[qmapshack] 01/06: Imported Upstream version 1.3.0

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Tue Jun 30 19:20:24 UTC 2015


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository qmapshack.

commit 2cc8299350d7bd0356418b825bdc5721788114b7
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Mon Jun 29 22:44:25 2015 +0200

    Imported Upstream version 1.3.0
---
 .hgsub                                             |    1 +
 .hgsubstate                                        |    1 +
 3rdparty/Routino/FILES                             |   18 +
 3rdparty/Routino/INSTALL.txt                       |    1 +
 3rdparty/Routino/Makefile                          |   67 +
 3rdparty/Routino/Makefile.conf                     |   90 +
 3rdparty/Routino/NEWS.txt                          |    1 +
 3rdparty/Routino/README.txt                        |    1 +
 3rdparty/Routino/agpl-3.0.txt                      |  661 ++++++
 3rdparty/Routino/doc/ALGORITHM.txt                 |  371 ++++
 3rdparty/Routino/doc/CONFIGURATION.txt             |  219 ++
 3rdparty/Routino/doc/DATA.txt                      |  116 +
 3rdparty/Routino/doc/DATALIFE.txt                  |  106 +
 3rdparty/Routino/doc/INSTALL-MS-WIN.txt            |  138 ++
 3rdparty/Routino/doc/INSTALL.txt                   |  312 +++
 3rdparty/Routino/doc/LIMITS.txt                    |  167 ++
 3rdparty/Routino/doc/Makefile                      |   75 +
 3rdparty/Routino/doc/NEWS.txt                      |  824 +++++++
 3rdparty/Routino/doc/OUTPUT.txt                    |  293 +++
 3rdparty/Routino/doc/README.txt                    |  188 ++
 3rdparty/Routino/doc/TAGGING.txt                   |  556 +++++
 3rdparty/Routino/doc/USAGE.txt                     |  648 ++++++
 3rdparty/Routino/doc/html/algorithm.html           |  413 ++++
 3rdparty/Routino/doc/html/configuration.html       |  314 +++
 3rdparty/Routino/doc/html/data.html                |  166 ++
 3rdparty/Routino/doc/html/example0.png             |  Bin 0 -> 119726 bytes
 3rdparty/Routino/doc/html/example1.png             |  Bin 0 -> 136817 bytes
 3rdparty/Routino/doc/html/example2.png             |  Bin 0 -> 95408 bytes
 3rdparty/Routino/doc/html/example3.png             |  Bin 0 -> 82532 bytes
 3rdparty/Routino/doc/html/example4.png             |  Bin 0 -> 67635 bytes
 3rdparty/Routino/doc/html/index.html               |  139 ++
 .../Routino/doc/html/installation-ms-windows.html  |  229 ++
 3rdparty/Routino/doc/html/installation.html        |  433 ++++
 3rdparty/Routino/doc/html/limits.html              |  243 +++
 3rdparty/Routino/doc/html/output.html              |  409 ++++
 3rdparty/Routino/doc/html/readme.html              |  425 ++++
 3rdparty/Routino/doc/html/style.css                |  435 ++++
 3rdparty/Routino/doc/html/tagging.html             |  988 +++++++++
 3rdparty/Routino/doc/html/usage.html               |  625 ++++++
 3rdparty/Routino/extras/Makefile                   |   67 +
 3rdparty/Routino/extras/README.txt                 |   27 +
 3rdparty/Routino/extras/errorlog/README.txt        |   29 +
 3rdparty/Routino/extras/errorlog/summarise-log.pl  |  295 +++
 3rdparty/Routino/extras/find-fixme/Makefile        |  191 ++
 3rdparty/Routino/extras/find-fixme/README.txt      |   97 +
 3rdparty/Routino/extras/find-fixme/fixme-dumper.c  |  345 +++
 3rdparty/Routino/extras/find-fixme/fixme-finder.c  |  369 ++++
 3rdparty/Routino/extras/find-fixme/fixme.xml       |   74 +
 3rdparty/Routino/extras/find-fixme/osmparser.c     |  306 +++
 .../Routino/extras/find-fixme/web/www/fixme.cgi    |  147 ++
 .../Routino/extras/find-fixme/web/www/fixme.css    |   86 +
 .../Routino/extras/find-fixme/web/www/fixme.html   |  162 ++
 .../extras/find-fixme/web/www/fixme.leaflet.js     |  563 +++++
 .../extras/find-fixme/web/www/fixme.openlayers.js  |  623 ++++++
 .../Routino/extras/find-fixme/web/www/index.html   |   71 +
 .../Routino/extras/find-fixme/web/www/paths.pl     |   34 +
 3rdparty/Routino/extras/plot-time/README.txt       |   18 +
 .../extras/plot-time/plot-planetsplitter-time.pl   |  108 +
 3rdparty/Routino/extras/tagmodifier/Makefile       |   88 +
 3rdparty/Routino/extras/tagmodifier/README.txt     |   45 +
 3rdparty/Routino/extras/tagmodifier/tagmodifier.c  |  723 +++++++
 3rdparty/Routino/src/Makefile                      |  274 +++
 3rdparty/Routino/src/cache.h                       |  179 ++
 3rdparty/Routino/src/errorlog.c                    |  178 ++
 3rdparty/Routino/src/errorlog.h                    |  195 ++
 3rdparty/Routino/src/errorlogx.c                   |  981 +++++++++
 3rdparty/Routino/src/errorlogx.h                   |   70 +
 3rdparty/Routino/src/fakes.c                       |  415 ++++
 3rdparty/Routino/src/fakes.h                       |   58 +
 3rdparty/Routino/src/filedumper.c                  | 1278 +++++++++++
 3rdparty/Routino/src/filedumperx.c                 |  330 +++
 3rdparty/Routino/src/files.c                       | 1081 ++++++++++
 3rdparty/Routino/src/files.h                       |  173 ++
 3rdparty/Routino/src/functions.h                   |   52 +
 3rdparty/Routino/src/logerror.c                    |  223 ++
 3rdparty/Routino/src/logging.c                     |  607 ++++++
 3rdparty/Routino/src/logging.h                     |  114 +
 3rdparty/Routino/src/mman-win32.c                  |  206 ++
 3rdparty/Routino/src/mman-win32.h                  |   77 +
 3rdparty/Routino/src/nodes.c                       |  624 ++++++
 3rdparty/Routino/src/nodes.h                       |  175 ++
 3rdparty/Routino/src/nodesx.c                      |  900 ++++++++
 3rdparty/Routino/src/nodesx.h                      |  186 ++
 3rdparty/Routino/src/optimiser.c                   | 1815 ++++++++++++++++
 3rdparty/Routino/src/osmo5mparse.c                 |  861 ++++++++
 3rdparty/Routino/src/osmparser.c                   | 1192 ++++++++++
 3rdparty/Routino/src/osmparser.h                   |   73 +
 3rdparty/Routino/src/osmpbfparse.c                 | 1243 +++++++++++
 3rdparty/Routino/src/osmxmlparse.c                 |  711 ++++++
 3rdparty/Routino/src/output.c                      |  954 ++++++++
 3rdparty/Routino/src/planetsplitter.c              |  731 +++++++
 3rdparty/Routino/src/profiles.c                    | 1119 ++++++++++
 3rdparty/Routino/src/profiles.h                    |   80 +
 3rdparty/Routino/src/prunex.c                      | 1497 +++++++++++++
 3rdparty/Routino/src/prunex.h                      |   43 +
 3rdparty/Routino/src/queue.c                       |  225 ++
 3rdparty/Routino/src/relations.c                   |  405 ++++
 3rdparty/Routino/src/relations.h                   |  151 ++
 3rdparty/Routino/src/relationsx.c                  | 1460 +++++++++++++
 3rdparty/Routino/src/relationsx.h                  |  120 ++
 3rdparty/Routino/src/results.c                     |  334 +++
 3rdparty/Routino/src/results.h                     |  122 ++
 3rdparty/Routino/src/router.c                      |  955 ++++++++
 3rdparty/Routino/src/routino.c                     |   26 +
 3rdparty/Routino/src/routino.h                     |   74 +
 3rdparty/Routino/src/segments.c                    |  437 ++++
 3rdparty/Routino/src/segments.h                    |  279 +++
 3rdparty/Routino/src/segmentsx.c                   | 1003 +++++++++
 3rdparty/Routino/src/segmentsx.h                   |  228 ++
 3rdparty/Routino/src/sorting.c                     | 1078 ++++++++++
 3rdparty/Routino/src/sorting.h                     |   59 +
 3rdparty/Routino/src/superx.c                      |  588 +++++
 3rdparty/Routino/src/superx.h                      |   38 +
 3rdparty/Routino/src/tagging.c                     |  980 +++++++++
 3rdparty/Routino/src/tagging.h                     |   85 +
 3rdparty/Routino/src/test/Makefile                 |  121 ++
 3rdparty/Routino/src/test/a-b-c-d.sh               |  105 +
 3rdparty/Routino/src/test/a-b-c.sh                 |  104 +
 3rdparty/Routino/src/test/a-b.sh                   |  103 +
 3rdparty/Routino/src/test/coincident-waypoint.osm  |  101 +
 3rdparty/Routino/src/test/coincident-waypoint.sh   |    1 +
 3rdparty/Routino/src/test/copyright.xml            |   30 +
 3rdparty/Routino/src/test/cycle-both-ways.osm      |  107 +
 3rdparty/Routino/src/test/cycle-both-ways.sh       |    1 +
 3rdparty/Routino/src/test/cycle-drive.sh           |  105 +
 3rdparty/Routino/src/test/dead-ends.osm            |  176 ++
 3rdparty/Routino/src/test/dead-ends.sh             |    1 +
 .../src/test/expected/coincident-waypoint-WP01.txt |   12 +
 .../src/test/expected/coincident-waypoint-WP02.txt |   11 +
 .../src/test/expected/coincident-waypoint-WP03.txt |   12 +
 .../src/test/expected/coincident-waypoint-WP04.txt |   10 +
 .../src/test/expected/cycle-both-ways-WP01.txt     |   16 +
 .../src/test/expected/cycle-both-ways-WP02.txt     |   16 +
 .../Routino/src/test/expected/dead-ends-WP01.txt   |   17 +
 .../Routino/src/test/expected/dead-ends-WP02.txt   |   19 +
 .../Routino/src/test/expected/dead-ends-WP03.txt   |   21 +
 .../Routino/src/test/expected/dead-ends-WP04.txt   |   23 +
 .../Routino/src/test/expected/dead-ends-WP05.txt   |   17 +
 .../Routino/src/test/expected/dead-ends-WP06.txt   |   19 +
 .../Routino/src/test/expected/dead-ends-WP07.txt   |   21 +
 .../Routino/src/test/expected/dead-ends-WP08.txt   |   17 +
 .../Routino/src/test/expected/dead-ends-WP09.txt   |   19 +
 .../Routino/src/test/expected/dead-ends-WP10.txt   |   21 +
 .../Routino/src/test/expected/dead-ends-WP11.txt   |   23 +
 .../src/test/expected/fake-node-with-loop-WP01.txt |   19 +
 .../src/test/expected/fake-node-with-loop-WP02.txt |   18 +
 3rdparty/Routino/src/test/expected/loops-WP01.txt  |   24 +
 3rdparty/Routino/src/test/expected/loops-WP02.txt  |   24 +
 3rdparty/Routino/src/test/expected/loops-WP03.txt  |   25 +
 3rdparty/Routino/src/test/expected/loops-WP04.txt  |   25 +
 3rdparty/Routino/src/test/expected/loops-WP05.txt  |   24 +
 3rdparty/Routino/src/test/expected/loops-WP06.txt  |   24 +
 3rdparty/Routino/src/test/expected/loops-WP07.txt  |   24 +
 3rdparty/Routino/src/test/expected/loops-WP08.txt  |   25 +
 3rdparty/Routino/src/test/expected/loops-WP09.txt  |   25 +
 3rdparty/Routino/src/test/expected/loops-WP10.txt  |   24 +
 3rdparty/Routino/src/test/expected/loops-WP11.txt  |   24 +
 .../Routino/src/test/expected/no-super-WP01.txt    |   16 +
 .../Routino/src/test/expected/no-super-WP02.txt    |    9 +
 .../Routino/src/test/expected/no-super-WP03.txt    |   13 +
 .../Routino/src/test/expected/no-super-WP04.txt    |   17 +
 .../src/test/expected/node-restrictions-WP01.txt   |   24 +
 .../src/test/expected/node-restrictions-WP02.txt   |   24 +
 .../src/test/expected/node-restrictions-WP03.txt   |   24 +
 .../src/test/expected/node-restrictions-WP04.txt   |   24 +
 .../src/test/expected/node-restrictions-WP05.txt   |   24 +
 .../src/test/expected/node-restrictions-WP06.txt   |   24 +
 .../src/test/expected/node-restrictions-WP07.txt   |   22 +
 .../src/test/expected/node-restrictions-WP08.txt   |   22 +
 .../Routino/src/test/expected/oneway-loop-WP01.txt |   17 +
 .../test/expected/roundabout-waypoints-WP01.txt    |   12 +
 .../test/expected/roundabout-waypoints-WP02.txt    |   13 +
 .../test/expected/roundabout-waypoints-WP03.txt    |   12 +
 .../test/expected/roundabout-waypoints-WP04.txt    |   13 +
 .../test/expected/roundabout-waypoints-WP05.txt    |   12 +
 .../test/expected/roundabout-waypoints-WP06.txt    |   13 +
 .../test/expected/roundabout-waypoints-WP07.txt    |   12 +
 .../src/test/expected/super-or-not-WP01.txt        |   13 +
 .../src/test/expected/super-or-not-WP02.txt        |   10 +
 .../src/test/expected/super-or-not-WP03.txt        |   10 +
 3rdparty/Routino/src/test/expected/turns-WP01.txt  |   19 +
 3rdparty/Routino/src/test/expected/turns-WP02.txt  |   18 +
 3rdparty/Routino/src/test/expected/turns-WP03.txt  |   18 +
 3rdparty/Routino/src/test/expected/turns-WP04.txt  |   27 +
 3rdparty/Routino/src/test/expected/turns-WP05.txt  |   26 +
 3rdparty/Routino/src/test/expected/turns-WP06.txt  |   26 +
 3rdparty/Routino/src/test/expected/turns-WP07.txt  |   34 +
 3rdparty/Routino/src/test/expected/turns-WP08.txt  |   31 +
 3rdparty/Routino/src/test/expected/turns-WP09.txt  |   31 +
 3rdparty/Routino/src/test/expected/turns-WP10.txt  |   35 +
 3rdparty/Routino/src/test/expected/turns-WP11.txt  |   32 +
 3rdparty/Routino/src/test/expected/turns-WP12.txt  |   32 +
 3rdparty/Routino/src/test/expected/turns-WP13.txt  |   45 +
 3rdparty/Routino/src/test/expected/turns-WP14.txt  |   44 +
 3rdparty/Routino/src/test/expected/turns-WP15.txt  |   44 +
 3rdparty/Routino/src/test/expected/turns-WP16.txt  |   16 +
 3rdparty/Routino/src/test/fake-node-with-loop.osm  |  102 +
 3rdparty/Routino/src/test/fake-node-with-loop.sh   |    1 +
 .../Routino/src/test/invalid-turn-relations.osm    |  230 ++
 .../Routino/src/test/invalid-turn-relations.sh     |    1 +
 3rdparty/Routino/src/test/is-fast-math.c           |   20 +
 3rdparty/Routino/src/test/loops.osm                |  168 ++
 3rdparty/Routino/src/test/loops.sh                 |    1 +
 3rdparty/Routino/src/test/no-super.osm             |  105 +
 3rdparty/Routino/src/test/no-super.sh              |    1 +
 3rdparty/Routino/src/test/node-restrictions.osm    |  176 ++
 3rdparty/Routino/src/test/node-restrictions.sh     |    1 +
 3rdparty/Routino/src/test/oneway-loop.osm          |   99 +
 3rdparty/Routino/src/test/oneway-loop.sh           |    1 +
 3rdparty/Routino/src/test/only-split.sh            |   75 +
 3rdparty/Routino/src/test/prune-short.osm          |  629 ++++++
 3rdparty/Routino/src/test/prune-short.sh           |    1 +
 3rdparty/Routino/src/test/prune-straight.osm       |  167 ++
 3rdparty/Routino/src/test/prune-straight.sh        |    1 +
 3rdparty/Routino/src/test/roundabout-waypoints.osm |  105 +
 3rdparty/Routino/src/test/roundabout-waypoints.sh  |    1 +
 3rdparty/Routino/src/test/start-1-finish.sh        |  103 +
 3rdparty/Routino/src/test/super-or-not.osm         |   55 +
 3rdparty/Routino/src/test/super-or-not.sh          |    1 +
 3rdparty/Routino/src/test/turns.osm                |  456 ++++
 3rdparty/Routino/src/test/turns.sh                 |    1 +
 3rdparty/Routino/src/test/waypoints.pl             |   78 +
 3rdparty/Routino/src/translations.c                | 1351 ++++++++++++
 3rdparty/Routino/src/translations.h                |   87 +
 3rdparty/Routino/src/types.c                       |  616 ++++++
 3rdparty/Routino/src/types.h                       |  460 ++++
 3rdparty/Routino/src/typesx.h                      |  125 ++
 3rdparty/Routino/src/uncompress.c                  |  473 ++++
 3rdparty/Routino/src/uncompress.h                  |   32 +
 3rdparty/Routino/src/visualiser.c                  | 1154 ++++++++++
 3rdparty/Routino/src/visualiser.h                  |   59 +
 3rdparty/Routino/src/ways.c                        |  148 ++
 3rdparty/Routino/src/ways.h                        |  196 ++
 3rdparty/Routino/src/waysx.c                       |  898 ++++++++
 3rdparty/Routino/src/waysx.h                       |  183 ++
 3rdparty/Routino/src/xml/Makefile                  |  119 +
 .../Routino/src/xml/test/bad-attr-entity-ref.xml   |   12 +
 .../src/xml/test/bad-comment-ends-triple-dash.xml  |   12 +
 .../src/xml/test/bad-comment-extra-double-dash.xml |   12 +
 .../src/xml/test/bad-double-quote-attr-amp.xml     |   12 +
 .../test/bad-double-quote-attr-invalid-ascii.xml   |   12 +
 .../test/bad-double-quote-attr-invalid-utf8.xml    |   12 +
 .../xml/test/bad-double-quote-attr-left-angle.xml  |   12 +
 .../xml/test/bad-double-quote-attr-right-angle.xml |   12 +
 .../Routino/src/xml/test/bad-early-end-of-file.xml |   11 +
 .../src/xml/test/bad-end-tag-space-at-begin1.xml   |   12 +
 .../src/xml/test/bad-end-tag-space-at-begin2.xml   |   12 +
 .../src/xml/test/bad-end-tag-space-at-end.xml      |   12 +
 .../Routino/src/xml/test/bad-end-tag-with-attr.xml |   12 +
 .../src/xml/test/bad-single-quote-attr-amp.xml     |   12 +
 .../test/bad-single-quote-attr-invalid-ascii.xml   |   12 +
 .../test/bad-single-quote-attr-invalid-utf8.xml    |   12 +
 .../xml/test/bad-single-quote-attr-left-angle.xml  |   12 +
 .../xml/test/bad-single-quote-attr-right-angle.xml |   12 +
 .../src/xml/test/bad-start-tag-space-at-begin.xml  |   12 +
 .../src/xml/test/bad-tag-attr-no-quotes.xml        |   12 +
 .../xml/test/bad-tag-attr-space-after-equal.xml    |   12 +
 .../xml/test/bad-tag-attr-space-before-equal.xml   |   12 +
 .../Routino/src/xml/test/bad-tag-level-nesting.xml |   12 +
 3rdparty/Routino/src/xml/test/bad-text-outside.xml |   13 +
 .../src/xml/test/bad-unbalanced-tag-start-end.xml  |   12 +
 .../src/xml/test/bad-unexpected-attribute-name.xml |   12 +
 .../src/xml/test/bad-unexpected-end-tag.xml        |   12 +
 .../src/xml/test/bad-unexpected-left-angle.xml     |   13 +
 .../src/xml/test/bad-unexpected-right-angle.xml    |   13 +
 .../src/xml/test/bad-xml-header-at-begin.xml       |   12 +
 .../Routino/src/xml/test/bad-xml-header-at-end.xml |   12 +
 .../src/xml/test/bad-xml-header-not-first.xml      |   12 +
 3rdparty/Routino/src/xml/test/good.xml             |   12 +
 3rdparty/Routino/src/xml/test/test.xsd             |   39 +
 3rdparty/Routino/src/xml/xsd-to-xmlparser.c        |  515 +++++
 3rdparty/Routino/src/xmlparse.c                    | 1788 +++++++++++++++
 3rdparty/Routino/src/xmlparse.h                    |  138 ++
 3rdparty/Routino/web/INSTALL.txt                   |    1 +
 3rdparty/Routino/web/Makefile                      |  232 ++
 3rdparty/Routino/web/data/create.sh                |   20 +
 3rdparty/Routino/web/translations/router.html      |  390 ++++
 3rdparty/Routino/web/translations/translate.pl     |  404 ++++
 .../Routino/web/translations/translation.de.txt    |  359 +++
 .../Routino/web/translations/translation.en.txt    |  477 ++++
 .../Routino/web/translations/translation.fr.txt    |  324 +++
 .../Routino/web/translations/translation.hu.txt    |  276 +++
 .../Routino/web/translations/translation.nl.txt    |  309 +++
 .../Routino/web/translations/translation.ru.txt    |  168 ++
 .../Routino/web/translations/translations-body.xml |   93 +
 .../Routino/web/translations/translations-head.xml |   18 +
 .../Routino/web/translations/translations-tail.xml |    1 +
 3rdparty/Routino/web/translations/visualiser.html  |  430 ++++
 3rdparty/Routino/web/www/leaflet/install.sh        |   11 +
 3rdparty/Routino/web/www/openlayers/install.sh     |   25 +
 3rdparty/Routino/web/www/openlayers/routino.cfg    |   45 +
 3rdparty/Routino/web/www/routino/.htaccess         |   40 +
 .../Routino/web/www/routino/icons/create-icons.pl  |  179 ++
 3rdparty/Routino/web/www/routino/icons/home.png    |  Bin 0 -> 233 bytes
 .../Routino/web/www/routino/icons/waypoint-add.png |  Bin 0 -> 177 bytes
 .../web/www/routino/icons/waypoint-centre.png      |  Bin 0 -> 142 bytes
 .../web/www/routino/icons/waypoint-coords.png      |  Bin 0 -> 162 bytes
 .../web/www/routino/icons/waypoint-down.png        |  Bin 0 -> 200 bytes
 .../web/www/routino/icons/waypoint-home.png        |  Bin 0 -> 185 bytes
 .../web/www/routino/icons/waypoint-left.png        |  Bin 0 -> 164 bytes
 .../web/www/routino/icons/waypoint-locate.png      |  Bin 0 -> 541 bytes
 .../web/www/routino/icons/waypoint-recentre.png    |  Bin 0 -> 146 bytes
 .../web/www/routino/icons/waypoint-remove.png      |  Bin 0 -> 229 bytes
 .../web/www/routino/icons/waypoint-right.png       |  Bin 0 -> 153 bytes
 .../web/www/routino/icons/waypoint-search.png      |  Bin 0 -> 249 bytes
 .../Routino/web/www/routino/icons/waypoint-up.png  |  Bin 0 -> 241 bytes
 3rdparty/Routino/web/www/routino/index.html        |   71 +
 3rdparty/Routino/web/www/routino/maplayout.css     |  111 +
 3rdparty/Routino/web/www/routino/maploader.js      |   63 +
 3rdparty/Routino/web/www/routino/mapprops.js       |   83 +
 3rdparty/Routino/web/www/routino/page-elements.css |  152 ++
 3rdparty/Routino/web/www/routino/page-elements.js  |   94 +
 3rdparty/Routino/web/www/routino/paths.pl          |   43 +
 3rdparty/Routino/web/www/routino/results.cgi       |   76 +
 3rdparty/Routino/web/www/routino/router.cgi        |  118 +
 3rdparty/Routino/web/www/routino/router.css        |  237 ++
 3rdparty/Routino/web/www/routino/router.leaflet.js | 2230 +++++++++++++++++++
 .../Routino/web/www/routino/router.openlayers.js   | 2275 ++++++++++++++++++++
 3rdparty/Routino/web/www/routino/router.pl         |  211 ++
 3rdparty/Routino/web/www/routino/search.cgi        |   96 +
 3rdparty/Routino/web/www/routino/search.pl         |  123 ++
 3rdparty/Routino/web/www/routino/statistics.cgi    |   44 +
 .../Routino/web/www/routino/update-profiles.pl     |   79 +
 3rdparty/Routino/web/www/routino/visualiser.cgi    |  157 ++
 3rdparty/Routino/web/www/routino/visualiser.css    |   86 +
 .../Routino/web/www/routino/visualiser.leaflet.js  | 1232 +++++++++++
 .../web/www/routino/visualiser.openlayers.js       | 1315 +++++++++++
 3rdparty/Routino/xml/Makefile                      |   79 +
 3rdparty/Routino/xml/osc.xsd                       |  133 ++
 3rdparty/Routino/xml/osm.xsd                       |  131 ++
 3rdparty/Routino/xml/routino-osc.xsd               |  142 ++
 3rdparty/Routino/xml/routino-osm.xsd               |  143 ++
 3rdparty/Routino/xml/routino-profiles.xml          |  509 +++++
 3rdparty/Routino/xml/routino-profiles.xsd          |  111 +
 3rdparty/Routino/xml/routino-tagging-nomodify.xml  |   57 +
 3rdparty/Routino/xml/routino-tagging.xml           | 1025 +++++++++
 3rdparty/Routino/xml/routino-tagging.xsd           |  101 +
 3rdparty/Routino/xml/routino-translations.xml      |  577 +++++
 3rdparty/Routino/xml/routino-translations.xsd      |  181 ++
 3rdparty/Routino/xml/scripts/drive.pl              |   60 +
 3rdparty/Routino/xml/scripts/ride.pl               |   62 +
 3rdparty/Routino/xml/scripts/walk.pl               |   67 +
 3rdparty/Routino/xml/xsd.xsd                       |   65 +
 3rdparty/RoutinoLib/CMakeLists.txt                 |  186 ++
 3rdparty/RoutinoLib/binout.c                       |  570 +++++
 src/gis/IGisLine.h => 3rdparty/RoutinoLib/binout.h |   23 +-
 3rdparty/RoutinoLib/routino.c                      |  426 ++++
 3rdparty/RoutinoLib/routino.h                      |  130 ++
 CMakeLists.txt                                     |   20 +-
 CMakeLists.txt.user                                |  108 +-
 CMakeLists.txt.user.3.3-pre1                       |  188 --
 changelog.txt                                      |   20 +
 mkfile                                             |    2 +
 src/CMainWindow.cpp                                |   77 +-
 src/CMainWindow.h                                  |    4 +
 src/CMakeLists.txt                                 |  102 +-
 src/GeoMath.cpp                                    |   32 +-
 src/IMainWindow.ui                                 |   64 +
 src/canvas/CCanvas.cpp                             |   33 +-
 src/canvas/CCanvas.h                               |   16 +-
 src/canvas/IDrawContext.cpp                        |   10 +-
 src/cursors/cursorDelete.png                       |  Bin 0 -> 1322 bytes
 src/cursors/cursorMovePoint.png                    |  Bin 0 -> 1335 bytes
 src/dem/CDemDraw.cpp                               |    5 +
 src/dem/CDemDraw.h                                 |    1 +
 src/dem/CDemPathSetup.cpp                          |    7 +-
 src/dem/CDemVRT.cpp                                |    1 +
 src/device/IDevice.cpp                             |    2 +
 src/device/IDeviceWatcher.cpp                      |    3 +
 src/gis/CGisListWks.cpp                            |  319 ++-
 src/gis/CGisListWks.h                              |    8 +
 src/gis/CGisWidget.cpp                             |   70 +-
 src/gis/CGisWidget.h                               |    8 +
 src/gis/CSelDevices.cpp                            |    3 +
 src/gis/IGisItem.cpp                               |    6 +-
 src/gis/IGisLine.cpp                               |   65 +-
 src/gis/IGisLine.h                                 |   36 +-
 src/gis/db/CDBItem.cpp                             |    2 +-
 src/gis/db/CDBProject.cpp                          |   10 +-
 src/gis/db/CSelectDBFolder.cpp                     |    3 +
 src/gis/db/CSelectSaveAction.cpp                   |    3 +
 src/gis/db/CSetupFolder.cpp                        |    3 +
 src/gis/db/IDB.cpp                                 |    7 +-
 src/gis/db/macros.h                                |    8 +-
 src/gis/gpx/CGpxProject.cpp                        |   22 +-
 src/gis/ovl/CGisItemOvlArea.cpp                    |   39 +-
 src/gis/ovl/CGisItemOvlArea.h                      |    8 +-
 src/gis/ovl/CScrOptOvlArea.cpp                     |    2 +-
 src/gis/ovl/IScrOptOvlArea.ui                      |    9 +
 src/gis/prj/CDetailsPrj.cpp                        |   13 +
 src/gis/prj/IGisProject.cpp                        |  113 +-
 src/gis/prj/IGisProject.h                          |   42 +-
 src/gis/qms/CQmsProject.cpp                        |    1 +
 src/gis/qms/serialization.cpp                      |   20 +-
 src/gis/rte/CCreateRouteFromWpt.cpp                |  138 ++
 .../rte/{CScrOptRte.h => CCreateRouteFromWpt.h}    |   35 +-
 src/gis/rte/CGisItemRte.cpp                        |  304 ++-
 src/gis/rte/CGisItemRte.h                          |   53 +-
 src/gis/rte/CScrOptRte.cpp                         |   25 +-
 src/gis/rte/CScrOptRte.h                           |    3 +
 src/gis/rte/ICreateRouteFromWpt.ui                 |  130 ++
 src/gis/rte/IScrOptRte.ui                          |   55 +-
 .../rte/router/CRouterMapQuest.cpp}                |   21 +-
 .../rte/router/CRouterMapQuest.h}                  |   22 +-
 src/gis/rte/router/CRouterRoutino.cpp              |  238 ++
 .../rte/{CScrOptRte.h => router/CRouterRoutino.h}  |   40 +-
 .../rte/router/CRouterRoutinoPathSetup.cpp}        |   21 +-
 .../CRouterRoutinoPathSetup.h}                     |   36 +-
 src/gis/rte/router/CRouterSetup.cpp                |   87 +
 .../rte/{CScrOptRte.h => router/CRouterSetup.h}    |   36 +-
 src/gis/{IGisLine.cpp => rte/router/IRouter.cpp}   |    8 +-
 src/gis/rte/{CScrOptRte.h => router/IRouter.h}     |   32 +-
 src/gis/rte/router/IRouterMapQuest.ui              |   31 +
 src/gis/rte/router/IRouterRoutino.ui               |  142 ++
 .../rte/router/IRouterRoutinoPathSetup.ui}         |  111 +-
 src/gis/rte/router/IRouterSetup.ui                 |   42 +
 src/gis/tnv/serialization.cpp                      |   24 +-
 src/gis/trk/CCombineTrk.cpp                        |   29 +-
 src/gis/trk/CCombineTrk.h                          |    2 +-
 src/gis/trk/CDetailsTrk.cpp                        |    2 -
 src/gis/trk/CGisItemTrk.cpp                        |   81 +-
 src/gis/trk/CGisItemTrk.h                          |   21 +-
 src/gis/trk/CScrOptTrk.cpp                         |    3 +-
 src/gis/trk/IScrOptTrk.ui                          |    4 +-
 src/gis/trk/filter/CFilterNewDate.cpp              |    1 +
 src/gis/trk/filter/IFilterNewDate.ui               |   10 +
 src/gis/trk/filter/filter.cpp                      |    4 +-
 src/gis/wpt/CScrOptWpt.cpp                         |    2 +-
 src/gis/wpt/IScrOptWpt.ui                          |   11 +-
 src/grid/CGrid.cpp                                 |    2 +
 src/helpers/CSelectCopyAction.cpp                  |    5 +
 src/helpers/CSelectProjectDialog.cpp               |    3 +
 src/icons/32x32/A.png                              |  Bin 0 -> 730 bytes
 src/icons/32x32/AddArea.png                        |  Bin 1288 -> 1385 bytes
 src/icons/32x32/AddRte.png                         |  Bin 0 -> 786 bytes
 src/icons/32x32/AddTrk.png                         |  Bin 979 -> 1029 bytes
 src/icons/32x32/AddWpt.png                         |  Bin 852 -> 831 bytes
 src/icons/32x32/CloneMapWorkspace.png              |  Bin 0 -> 1635 bytes
 src/icons/32x32/O.png                              |  Bin 0 -> 839 bytes
 src/icons/32x32/Route.png                          |  Bin 2379 -> 887 bytes
 src/icons/32x32/RouteSetup.png                     |  Bin 0 -> 842 bytes
 src/icons/32x32/V.png                              |  Bin 0 -> 693 bytes
 src/icons/48x48/A.png                              |  Bin 0 -> 1029 bytes
 src/icons/48x48/AddArea.png                        |  Bin 2044 -> 2198 bytes
 src/icons/48x48/AddRte.png                         |  Bin 0 -> 1032 bytes
 src/icons/48x48/AddTrk.png                         |  Bin 1235 -> 1519 bytes
 src/icons/48x48/AddWpt.png                         |  Bin 1228 -> 1189 bytes
 src/icons/48x48/CloneMapWorkspace.png              |  Bin 0 -> 2521 bytes
 src/icons/48x48/O.png                              |  Bin 0 -> 1234 bytes
 src/icons/48x48/Route.png                          |  Bin 4379 -> 1246 bytes
 src/icons/48x48/RouteSetup.png                     |  Bin 0 -> 1261 bytes
 src/icons/48x48/V.png                              |  Bin 0 -> 1071 bytes
 src/icons/A.svg                                    |   67 +
 src/icons/AddArea.svg                              |   14 +-
 src/icons/AddRte.svg                               |  112 +
 src/icons/AddTrk.svg                               |    8 +-
 src/icons/AddWpt.svg                               |   55 +-
 src/icons/CloneMapWorkspace.svg                    |  135 ++
 src/icons/O.svg                                    |   67 +
 src/icons/Route.svg                                |  185 +-
 src/icons/RouteSetup.svg                           |  118 +
 src/icons/V.svg                                    |   67 +
 src/locale/qmapshack_cs.ts                         | 1298 ++++++++---
 src/locale/qmapshack_de.ts                         | 1361 ++++++++----
 src/locale/qmapshack_es.ts                         | 1298 ++++++++---
 src/locale/qmapshack_fr.ts                         | 1506 +++++++++----
 src/map/CMapDraw.cpp                               |   14 +-
 src/map/CMapDraw.h                                 |    5 +-
 src/map/CMapIMG.cpp                                |   16 +-
 src/map/CMapIMG.h                                  |    2 +-
 src/map/CMapList.cpp                               |    2 +-
 src/map/CMapPathSetup.cpp                          |    7 +-
 src/map/CMapRMAP.h                                 |    4 +-
 src/map/CMapVRT.cpp                                |    1 +
 src/map/CMapWMTS.cpp                               |   18 +-
 src/map/IMap.cpp                                   |    2 +-
 src/map/IMap.h                                     |    2 +-
 src/map/IMapPathSetup.ui                           |   40 +-
 templates/source.cpp => src/mouse/CMouseDummy.cpp  |   12 +-
 src/mouse/{CScrOptEditLine.h => CMouseDummy.h}     |   33 +-
 src/mouse/CMouseEditArea.cpp                       |   23 +-
 src/mouse/CMouseEditArea.h                         |    8 +-
 src/mouse/{CMouseEditTrk.cpp => CMouseEditRte.cpp} |   65 +-
 src/mouse/{CMouseEditTrk.h => CMouseEditRte.h}     |   23 +-
 src/mouse/CMouseEditTrk.cpp                        |   31 +-
 src/mouse/CMouseEditTrk.h                          |    7 +-
 src/mouse/CMouseMoveWpt.cpp                        |    2 +-
 src/mouse/CMouseMoveWpt.h                          |    2 +-
 src/mouse/CMouseNormal.cpp                         |   19 +-
 src/mouse/CMouseNormal.h                           |    3 +-
 src/mouse/CMouseRangeTrk.cpp                       |    4 +-
 src/mouse/CMouseRangeTrk.h                         |    2 +-
 src/mouse/CMouseWptBubble.cpp                      |    2 +-
 src/mouse/CMouseWptBubble.h                        |    2 +-
 src/mouse/CScrOptPoint.cpp                         |    4 +-
 src/mouse/CScrOptPoint.h                           |    2 +-
 src/mouse/CScrOptRange.cpp                         |    4 +-
 src/mouse/CScrOptRange.h                           |    2 +-
 src/mouse/CScrOptRangeTrk.cpp                      |    8 +-
 src/mouse/CScrOptRangeTrk.h                        |    2 +-
 src/mouse/CScrOptUnclutter.cpp                     |    8 +-
 src/mouse/CScrOptUnclutter.h                       |    2 +-
 src/mouse/IMouse.h                                 |    8 +-
 src/mouse/IMouseEditLine.cpp                       |  903 --------
 src/mouse/IScrOpt.cpp                              |   28 +-
 src/mouse/IScrOpt.h                                |   12 +-
 src/mouse/IScrOptEditLine.ui                       |   97 -
 src/mouse/line/CLineOpAddPoint.cpp                 |  243 +++
 .../line/CLineOpAddPoint.h}                        |   39 +-
 src/mouse/line/CLineOpDeletePoint.cpp              |   73 +
 .../CLineOpDeletePoint.h}                          |   26 +-
 src/mouse/line/CLineOpMovePoint.cpp                |  150 ++
 .../line/CLineOpMovePoint.h}                       |   36 +-
 src/mouse/line/CLineOpSelectRange.cpp              |  211 ++
 .../line/CLineOpSelectRange.h}                     |   48 +-
 src/mouse/{ => line}/CScrOptEditLine.cpp           |    6 +-
 src/mouse/{ => line}/CScrOptEditLine.h             |    2 +-
 .../CScrOptRangeLine.cpp}                          |   22 +-
 .../{CScrOptRangeTrk.h => line/CScrOptRangeLine.h} |   19 +-
 src/mouse/line/ILineOp.cpp                         |  377 ++++
 src/mouse/line/ILineOp.h                           |  111 +
 src/mouse/line/IMouseEditLine.cpp                  |  402 ++++
 src/mouse/{ => line}/IMouseEditLine.h              |  115 +-
 src/mouse/line/IScrOptEditLine.ui                  |  338 +++
 src/mouse/line/IScrOptRangeLine.ui                 |   51 +
 src/plot/IPlot.cpp                                 |    6 +-
 src/plot/IPlot.h                                   |    3 +
 src/qlgt/CQlgtDb.cpp                               |   27 +-
 src/qlgt/CQmsDb.cpp                                |    2 +-
 src/resources.qrc                                  |   19 +
 src/{qlgt => tool}/CImportDatabase.cpp             |    2 +-
 src/{qlgt => tool}/CImportDatabase.h               |    0
 src/{map => tool}/CMapVrtBuilder.cpp               |   82 +-
 src/{map => tool}/CMapVrtBuilder.h                 |   20 +-
 src/tool/CRoutinoDatabaseBuilder.cpp               |  193 ++
 .../CRoutinoDatabaseBuilder.h}                     |   44 +-
 src/{qlgt => tool}/IImportDatabase.ui              |    0
 src/{map => tool}/IMapVrtBuilder.ui                |    0
 .../IRoutinoDatabaseBuilder.ui}                    |   49 +-
 src/tool/IToolShell.cpp                            |  134 ++
 src/{map/CMapVrtBuilder.h => tool/IToolShell.h}    |   38 +-
 src/xml/routino/routino-profiles.xml               |  509 +++++
 src/xml/routino/routino-tagging-nomodify.xml       |   57 +
 src/xml/routino/routino-tagging.xml                | 1025 +++++++++
 src/xml/routino/routino-translations.xml           |  577 +++++
 templates/header.h                                 |    2 +-
 templates/{source.cpp => source.c}                 |   12 +-
 templates/source.cpp                               |    2 +-
 548 files changed, 84959 insertions(+), 3893 deletions(-)

diff --git a/.hgsub b/.hgsub
new file mode 100644
index 0000000..46dee84
--- /dev/null
+++ b/.hgsub
@@ -0,0 +1 @@
+3rdparty/Routino = [svn]http://routino.org/svn/branches/libroutino/
diff --git a/.hgsubstate b/.hgsubstate
new file mode 100644
index 0000000..ef70257
--- /dev/null
+++ b/.hgsubstate
@@ -0,0 +1 @@
+1723 3rdparty/Routino
diff --git a/3rdparty/Routino/FILES b/3rdparty/Routino/FILES
new file mode 100644
index 0000000..49608ca
--- /dev/null
+++ b/3rdparty/Routino/FILES
@@ -0,0 +1,18 @@
+routino-2.7.3/src
+!routino-2.7.3/src/CXREF
+!routino-2.7.3/src/SPLINT
+routino-2.7.3/doc
+!routino-2.7.3/doc/auto
+routino-2.7.3/web
+routino-2.7.3/xml
+routino-2.7.3/ChangeLog
+!routino-2.7.3/FILES
+routino-2.7.3/Makefile
+routino-2.7.3/Makefile.conf
+routino-2.7.3/INSTALL.txt
+routino-2.7.3/README.txt
+routino-2.7.3/NEWS.txt
+routino-2.7.3/agpl-3.0.txt
+routino-2.7.3/extras
+!routino-2.7.3/test
+!routino-2.7.3/.svn
diff --git a/3rdparty/Routino/INSTALL.txt b/3rdparty/Routino/INSTALL.txt
new file mode 120000
index 0000000..b0385da
--- /dev/null
+++ b/3rdparty/Routino/INSTALL.txt
@@ -0,0 +1 @@
+doc/INSTALL.txt
\ No newline at end of file
diff --git a/3rdparty/Routino/Makefile b/3rdparty/Routino/Makefile
new file mode 100644
index 0000000..1c1cbd3
--- /dev/null
+++ b/3rdparty/Routino/Makefile
@@ -0,0 +1,67 @@
+# Top level Makefile
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2009-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# All configuration is in the top-level Makefile.conf
+
+include Makefile.conf
+
+# Sub-directories and sub-makefiles
+
+SUBFILES=$(wildcard */Makefile)
+SUBDIRS=$(foreach f,$(SUBFILES),$(dir $f))
+
+########
+
+all:
+	for dir in $(SUBDIRS); do \
+	   ( cd $$dir && $(MAKE) $@ ); \
+	done
+
+########
+
+test:
+	for dir in $(SUBDIRS); do \
+	   ( cd $$dir && $(MAKE) $@ ); \
+	done
+
+########
+
+install:
+	for dir in $(SUBDIRS); do \
+	   ( cd $$dir && $(MAKE) $@ ); \
+	done
+
+########
+
+clean:
+	for dir in $(SUBDIRS); do \
+	   ( cd $$dir && $(MAKE) $@ ); \
+	done
+
+########
+
+distclean:
+	for dir in $(SUBDIRS); do \
+	   ( cd $$dir && $(MAKE) $@ ); \
+	done
+
+########
+
+.PHONY:: all test install clean distclean
diff --git a/3rdparty/Routino/Makefile.conf b/3rdparty/Routino/Makefile.conf
new file mode 100644
index 0000000..82461dd
--- /dev/null
+++ b/3rdparty/Routino/Makefile.conf
@@ -0,0 +1,90 @@
+# Configuration Makefile
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2013-2015 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# Installation locations (edit if required)
+
+prefix=/usr/local
+bindir=$(prefix)/bin
+docdir=$(prefix)/doc/routino
+datadir=$(prefix)/share/routino
+
+
+# Compilation programs
+
+CC=gcc
+LD=gcc
+
+
+# Language dialect selection
+CFLAGS=-std=c99
+
+# Warning options
+CFLAGS+=-Wall -Wmissing-prototypes -Wextra -Wno-unused-parameter -pedantic
+
+# Optimisation options
+CFLAGS+=-O3
+CFLAGS+=-ffast-math
+
+# Optimisation option (only works if compilation and execution use exactly the same CPU architecture).
+#CFLAGS+=-march=native
+
+# Debugging symbols
+#CFLAGS+=-g
+
+
+# Maths library
+LDFLAGS=-lm
+
+
+# Extra flags for compiling libroutino shared library
+CFLAGS_LIB=-fPIC -fvisibility=hidden
+LDFLAGS_LIB=-fPIC -shared
+
+
+# Required for multi-threaded support (comment these two lines out if not required)
+CFLAGS+=-pthread -DUSE_PTHREADS
+LDFLAGS+=-pthread -lpthread
+
+
+ifndef MINGW
+# Required for bzip2 support (comment these two lines out if not required)
+CFLAGS+=-DUSE_BZIP2
+LDFLAGS+=-lbz2
+endif
+
+
+# Required for gzip support (comment these two lines out if not required)
+CFLAGS+=-DUSE_GZIP
+LDFLAGS+=-lz
+
+
+# Required for xz support (uncomment these two lines if required)
+#CFLAGS+=-DUSE_XZ
+#LDFLAGS+=-llzma
+
+
+# Required to use stdio with files > 2GiB on 32-bit system.
+CFLAGS+=-D_FILE_OFFSET_BITS=64
+
+
+ifndef MINGW
+# Required to compile on Linux without a warning about pread() and pwrite() functions.
+CFLAGS+=-D_POSIX_C_SOURCE=200809L
+endif
diff --git a/3rdparty/Routino/NEWS.txt b/3rdparty/Routino/NEWS.txt
new file mode 120000
index 0000000..7a887e7
--- /dev/null
+++ b/3rdparty/Routino/NEWS.txt
@@ -0,0 +1 @@
+doc/NEWS.txt
\ No newline at end of file
diff --git a/3rdparty/Routino/README.txt b/3rdparty/Routino/README.txt
new file mode 120000
index 0000000..253de0c
--- /dev/null
+++ b/3rdparty/Routino/README.txt
@@ -0,0 +1 @@
+doc/README.txt
\ No newline at end of file
diff --git a/3rdparty/Routino/agpl-3.0.txt b/3rdparty/Routino/agpl-3.0.txt
new file mode 100644
index 0000000..dba13ed
--- /dev/null
+++ b/3rdparty/Routino/agpl-3.0.txt
@@ -0,0 +1,661 @@
+                    GNU AFFERO GENERAL PUBLIC LICENSE
+                       Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+  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
+them 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.
+
+  Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+  A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate.  Many developers of free software are heartened and
+encouraged by the resulting cooperation.  However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+  The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community.  It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server.  Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+  An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals.  This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU Affero General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Remote Network Interaction; Use with the GNU General Public License.
+
+  Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software.  This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero 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 that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  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.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     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
+state 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 Affero General Public License as published by
+    the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source.  For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code.  There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
diff --git a/3rdparty/Routino/doc/ALGORITHM.txt b/3rdparty/Routino/doc/ALGORITHM.txt
new file mode 100644
index 0000000..569281b
--- /dev/null
+++ b/3rdparty/Routino/doc/ALGORITHM.txt
@@ -0,0 +1,371 @@
+                             Routino : Algorithm
+                             ===================
+
+
+   This page describes the development of the algorithm that is used in
+   Routino for finding routes.
+
+
+Simplest Algorithm
+------------------
+
+   The algorithm to find a route is fundamentally simple: Start at the
+   beginning, follow all possible routes and keep going until you reach
+   the end.
+
+   While this method does work, it isn't fast. To be able to find a route
+   quickly needs a different algorithm, one that can find the correct
+   answer without wasting time on routes that lead nowhere.
+
+
+Improved Algorithm
+------------------
+
+   The simplest way to do this is to follow all possible segments from the
+   starting node to the next nearest node (an intermediate node in the
+   complete journey). For each node that is reached store the shortest
+   route from the starting node and the length of that route. The list of
+   intermediate nodes needs to be maintained in order of shortest overall
+   route on the assumption that there is a straight line route from here
+   to the end node.
+   At each point the intermediate node that has the shortest potential
+   overall journey time is processed before any other node. From the first
+   node in the list follow all possible segments and place the newly
+   discovered nodes into the same list ordered in the same way. This will
+   tend to constrain the list of nodes examined to be the ones that are
+   between the start and end nodes. If at any point you reach a node that
+   has already been reached by a longer route then you can discard that
+   route since the newly discovered route is shorter. Conversely if the
+   previously discovered route is shorter then discard the new route.
+   At some point the end node will be reached and then any routes with
+   potential lengths longer than this actual route can be immediately
+   discarded. The few remaining potential routes must be continued until
+   they are found to be shorter or have no possibility of being shorter.
+   The shortest possible route is then found.
+
+   At all times when looking at a node only those segments that are
+   possible by the chosen means of transport are followed. This allows the
+   type of transport to be handled easily. When finding the quickest route
+   the same rules apply except that the criterion for sorting is the
+   shortest potential route (assuming that from each node to the end is
+   the fastest possible type of highway).
+
+   This method also works, but again it isn't very fast. The problem is
+   that the complexity is proportional to the number of nodes or segments
+   in all routes examined between the start and end nodes. Maintaining the
+   list of intermediate nodes in order is the most complex part.
+
+
+Final Algorithm
+---------------
+
+   The final algorithm that is implemented in the router is basically the
+   one above but with an important difference. Instead of finding a long
+   route among a data set of 8,000,000 nodes (number of highway nodes in
+   UK at beginning of 2010) it finds one long route in a data set of
+   1,000,000 nodes and a few hundred very short routes in the full data
+   set. Since the time taken to find a route is proportional to the number
+   of nodes that need to be considered the main route takes 1/10th of the
+   time and the very short routes take almost no time at all.
+
+   The solution to making the algorithm fast is therefore to discard most
+   of the nodes and only keep the interesting ones. In this case a node is
+   deemed to be interesting if it is the junction of three or more
+   segments or the junction of two segments with different properties or
+   has a routing restriction different from the connecting segments. In
+   the algorithm and following description these are classed as
+   super-nodes. Starting at each super-node a super-segment is generated
+   that finishes on another super-node and contains the shortest path
+   along segments with identical properties (and these properties are
+   inherited by the super-segment). The point of choosing the shortest
+   route is that since all segments considered have identical properties
+   they will be treated identically when properties are taken into
+   account. This decision making process can be repeated until the only
+   the most important and interesting nodes remain.
+
+   To find a route between a start and finish point now comprises the
+   following steps (assuming a shortest route is required):
+
+    1. Find all shortest routes from the start point along normal segments
+       and stopping when super-nodes are reached.
+    2. Find all shortest routes from the end point backwards along normal
+       segments and stopping when super-nodes are reached.
+    3. Find the shortest route along super-segments from the set of
+       super-nodes in step 1 to the set of super-nodes in step 2 (taking
+       into account the lengths found in steps 1 and 2 between the
+       start/finish super-nodes and the ultimate start/finish point).
+    4. For each super-segment in step 3 find the shortest route between
+       the two end-point super-nodes.
+
+   This multi-step process is considerably quicker than using all nodes
+   but gives a result that still contains the full list of nodes that are
+   visited. There are some special cases though, for example very short
+   routes that do not pass through any super-nodes, or routes that start
+   or finish on a super-node. In these cases one or more of the steps
+   listed can be removed or simplified.
+
+   When the first route reaches the final node the length of that route is
+   retained as a benchmark. Any shorter complete route that is calculated
+   later would replace this benchmark. As routes are tested any partial
+   routes that are longer than the benchmark can be immediately discarded.
+   Other partial routes have the length of a perfect straight highway to
+   the final node added to them and if the total exceeds the benchmark
+   they can also be discarded. Very quickly the number of possible routes
+   is reduced until the absolute shortest is found.
+
+   For routes that do not start or finish on a node in the original data
+   set a fake node is added to an existing segment. This requires special
+   handling in the algorithm but it gives mode flexibility for the start,
+   finish and intermediate points in a route.
+
+Algorithm Evolution
+- - - - - - - - - -
+
+   In Routino versions 1.0 to 1.4 the algorithm used to select a
+   super-node was the same as above except that node properties were not
+   included. Routino versions 1.4.1 to 1.5.1 used a slightly different
+   algorithm which only chose nodes that were junctions between segments
+   with different properties (or has a routing restriction that is
+   different from connecting segments in versions 1.5 and 1.5.1). The
+   addition of turn restrictions (described in more detail below) requires
+   the original algorithm since the super-segments more accurately reflect
+   the underlying topology.
+
+Algorithm Implementation
+- - - - - - - - - - - -
+
+   The algorithm that is used for finding the route between the
+   super-nodes using super-segments is the A* algorithm (or a slight
+   variation of it). This was not a deliberate design decision, but
+   evolved into it during development. This algorithm relies on
+   calculating the lowest score (shortest distance or quickest time) to
+   each node from the starting node. The remaining score for the path to
+   the destination node is estimated (based on a straight line using the
+   fastest type of highway) and added to the current score and the result
+   recorded. At each step the unvisited node that has the lowest current
+   score is examined and all nodes connected to it have their scores
+   calculated. When the destination node has been reached all remaining
+   unvisited nodes with scores higher than the destination node's score
+   can be discarded and the few remaining nodes examined.
+
+   The algorithm used to find the route between super-nodes using normal
+   segments is Dijkstra's algorithm (although it is implemented as the
+   same algorithm as above but with no estimated cost). Since these routes
+   tend to be short and the CPU time for calculating the heuristic cost
+   function is relatively large this tends to give a quicker solution.
+
+
+Routing Preferences
+-------------------
+
+   One of the important features of Routino is the ability to select a
+   route that is optimum for a set of criteria such as preferences for
+   each type of highway, speed limits and other restrictions and highway
+   properties.
+
+   All of these features are handled by assigning a score to each segment
+   while calculating the route and trying to minimise the score rather
+   than simply minimising the length.
+
+   Segment length
+          When calculating the shortest route the length of the segment is
+          the starting point for the score.
+
+   Speed preference
+          When calculating the quickest route the time taken calculated
+          from the length of the segment and the lower of the highway's
+          own speed limit and the user's speed preference for the type of
+          highway is the starting point for the score.
+
+   One-way restriction
+          If a highway has the one-way property in the opposite direction
+          to the desired travel and the user's preference is to obey
+          one-way restrictions then the segment is ignored.
+
+   Weight, height, width & length limits
+          If a highway has one of these limits and its value is less than
+          the user's specified requirement then the segment is ignored.
+
+   Highway preference
+          The highway preference specified by the user is a percentage,
+          these are scaled so that the most preferred highway type has a
+          weighted preference of 1.0 (0% always has a weighted preference
+          of 0.0). The calculated score for a segment is divided by this
+          weighted preference.
+
+   Highway properties
+          The other highway properties are specified by the user as a
+          percentage and each highway either has that property or not. The
+          user's property preference is scaled into the range 0.0 (for 0%)
+          to 1.0 (for 100%) to give a weighted preference, a second
+          "non-property" weighted preference is calculated in the same way
+          after subtracting the user's preference from 100%. If a segment
+          has a particular property then the calculated score is divided
+          by the weighted preference for that property, if not then it is
+          divided by the non-property weighted preference. A non-linear
+          transformation is applied so that changing property preferences
+          close to 50% do not cause large variations in routes.
+
+
+Data Pruning
+------------
+
+   From version 2.2 there are options to "prune" nodes and segments from
+   the input data which means to remove nodes and/or segments without
+   significantly changing the routing results.
+
+   The pruning options must meet a number of conditions to be useful:
+     * The topology relevant to routing must remain unchanged. The
+       instructions that are produced from the reduced set of nodes and
+       segments must be sufficiently accurate for anybody trying to follow
+       them on the ground.
+     * Any restrictions belonging to nodes or segments that stop certain
+       types of traffic from following a particular highway must be
+       preserved.
+     * The total length must be calculated using the original data and not
+       the simplified data which by its nature will typically be shorter.
+     * The location of the remaining nodes and segments must be a good
+       representation of the original nodes and segments. Since the
+       calculated route may be displayed on a map the remaining nodes and
+       segments must clearly indicate the route to take.
+
+   The prune options all have user-controllable parameters which allow the
+   geographical accuracy to be controlled. This means that although the
+   topology is the same the geographical accuracy can be sacrificed
+   slightly to minimise the number of nodes and segments.
+
+   The pruning options that are available are:
+     * Removing the access permissions for a transport type from segments
+       if it is not possible to route that transport type from those
+       segments to a significant number of other places. The limit on the
+       pruning is set by the total length of the isolated group of
+       segments. This significantly increases the chance that a route will
+       be found by not putting waypoints in inaccessible places.
+     * Removing short segments, the limit is set by the length of the
+       segment. This removes a number of redundant segments (and
+       associated nodes) but rules are applied to ensure that removing the
+       segments does not alter junction topology or remove node access
+       permissions or changes in way properties.
+     * Removing nodes from almost straight highways, the limit is set by
+       the distance between the remaining segments and the original nodes.
+       This removes a large number of redundant nodes (and therefore
+       segments) but again care is taken not to remove node access
+       permissions or changes in way properties.
+
+
+Turn Restrictions
+-----------------
+
+   The addition of turn restrictions in version 2.0 adds a set of further
+   complications because it introduces a set of constraints that are far
+   more complex than one-way streets.
+
+   A turn restriction in the simplest case is a combination of a segment,
+   node and segment such that routes are not allowed to go from the first
+   segment to the second one through the specified node. Exceptions for
+   certain types of traffic can also be specified. Currently only this
+   simplest type of turn restriction is handled by the algorithm.
+
+   The first complication of turn restrictions is that the algorithm above
+   requires that super-segments are composed of segments with identical
+   properties. A turn restriction is not the same in both directions so a
+   super-segment cannot include any route through that turn restriction.
+   The node at the centre of the turn restriction must therefore be a
+   super-node to avoid this. In addition to this all nodes connected to
+   the turn restriction node by a single segment must also be super-nodes
+   to avoid any long-distance super-segments starting at the restricted
+   node.
+
+   The second complication of a turn restriction is that the optimum route
+   may require passing through the same node more than once. This can
+   happen where the route needs to work around a turn restriction by
+   driving past it, turning round (on a roundabout perhaps) and coming
+   back along the same highway. Without turn restrictions a route could be
+   defined purely by the set of nodes that were passed; no node would
+   exist more than once along a route between two points. With turn
+   restrictions the route is defined by a node and the segment used to get
+   there; no route between two points will ever need to follow the same
+   segment in the same direction more than once. This means that the
+   optimisation algorithm calculates scores for directed segments (indexed
+   by segment and end node) rather than for nodes.
+
+   A side-effect of this is that a route that works around a turn
+   restriction must be calculable using the super-segments that are stored
+   in the database. This puts a limit on the amount of database
+   optimisation that can be performed because if too many super-segments
+   are removed the optimum work-around may also be removed. The solution
+   to this is to ensure that the database preserves all loops that can be
+   used to turn around and reverse direction, previously super-segments
+   that started and finished on the same super-node were disallowed.
+
+   Another side-effect of having the route composed of a set of locations
+   (nodes) as well as the direction of travel (segments used to reach
+   them) is that via points in the route can be forced to continue in the
+   original direction. If the chosen method of transport obeys turn
+   restrictions then it will not reverse direction at a via point but will
+   find an optimum route continuing in the same direction. The only
+   exception to this is when the route ahead at a waypoint is into a
+   dead-end and an immediate U-turn is allowed.
+
+   A side-effect of having the starting direction at a via point defined
+   by the previous part of the route is that overall non-optimal routes
+   may be found even though each section between via points is optimal.
+   For a route with a start, middle and end point defined it can be the
+   case that the shortest route from the start to the middle arrives in
+   the opposite direction to that required for the optimal route from the
+   middle to the end. The calculation of the route in separate sections
+   therefore may give a non-optimum result even though each section is
+   itself optimum based on the start conditions.
+
+   Overall the presence of turn restrictions in the database makes the
+   routing slower even for regions of the map that have no turn
+   restrictions.
+
+
+Data Implementation
+-------------------
+
+   The hardest part of implementing this router is the data organisation.
+   The arrangement of the data to minimise the number of operations
+   required to follow a route from one node to another is much harder than
+   designing the algorithm itself.
+
+   The final implementation uses a separate table for nodes, segments and
+   ways. Each table individually is implemented as a C-language data
+   structure that is written to disk by a program which parses the
+   OpenStreetMap XML data file. In the router these data structures are
+   memory mapped so that the operating system handles the problems of
+   loading the needed data blocks from disk.
+
+   Each node contains a latitude and longitude and they are sorted
+   geographically so that converting a latitude and longitude coordinate
+   to a node is fast as well as looking up the coordinate of a node. The
+   node also contains the location in the array of segments for the first
+   segment that uses that node.
+   Each segment contains the location of the two nodes as well as the way
+   that the segment came from. The location of the next segment that uses
+   one of the two nodes is also stored; the next segment for the other
+   node is the following one in the array. The length of the segment is
+   also pre-computed and stored.
+   Each way has a name, a highway type, a list of allowed types of
+   traffic, a speed limit, any weight, height, width or length
+   restrictions and the highway properties.
+
+   The super-nodes are mixed in with the nodes and the super-segments are
+   mixed in with the segments. For the nodes they are the same as the
+   normal nodes, so just a flag is needed to indicate that they are super.
+   The super-segments are in addition to the normal segments so they
+   increase the database size (by about 10%) and are also marked with a
+   flag. Some segments are therefore flagged as both normal segments and
+   super-segments if they both have the same end nodes.
+
+   The relations are stored separately from the nodes, segments and ways.
+   For the turn restriction relations the initial and final segments are
+   stored along with the restricted node itself. Each node that has a turn
+   restriction is marked in the main node storage with a flag to indicate
+   this information.
+
+
+--------
+
+Copyright 2008-2013 Andrew M. Bishop.
diff --git a/3rdparty/Routino/doc/CONFIGURATION.txt b/3rdparty/Routino/doc/CONFIGURATION.txt
new file mode 100644
index 0000000..14aaf46
--- /dev/null
+++ b/3rdparty/Routino/doc/CONFIGURATION.txt
@@ -0,0 +1,219 @@
+                           Routino : Configuration
+                           =======================
+
+
+   New in version 1.4 of Routino is the use of configuration files to
+   allow more information to be provided to the programs at run-time. The
+   configuration files that are used are:
+     * Tagging transformation rules for the planetsplitter program.
+     * Routing profiles for the router program.
+     * Output translations for the router program.
+
+   In keeping with the nature of the input and output files the
+   configuration files are also XML files. Each of the files uses a custom
+   defined XML schema and an XSD file is provided for each of them.
+
+
+Tag Transformation Rules
+------------------------
+
+   The default name of the tagging transformation rules XML configuration
+   file is tagging.xml in the same directory as the generated database
+   files. Other filenames can be specified on the command line using the
+   --tagging option. When processing the input it is possible to have a
+   different set of tagging rules for each file; for example different
+   rules for different countries.
+
+   The tagging rules allow modifying the highway tags in the source file
+   so that the routing can be performed on a simpler set of tags. This
+   removes the special case tagging rules from the source code into the
+   configuration file where they can be easily modified. Part of the
+   provided tagging.xml file showing the rules for motorway_link and
+   motorway highway types.
+
+<?xml version="1.0" encoding="utf-8"?>
+<routino-tagging>
+
+  <way>
+
+    <if k="highway" v="motorway_link">
+      <set v="motorway"/>
+    </if>
+
+    <if k="highway" v="motorway">
+      <output k="highway"/>
+
+      <output k="motorcycle" v="yes"/>
+      <output k="motorcar"   v="yes"/>
+      <output k="goods"      v="yes"/>
+      <output k="hgv"        v="yes"/>
+      <output k="psv"        v="yes"/>
+
+      <output k="paved"      v="yes"/>
+      <output k="multilane"  v="yes"/>
+      <output k="oneway"     v="yes"/>
+
+      <unset k="highway"/>
+    </if>
+...
+  <way>
+
+</routino-tagging>
+
+   The rules all have the same format; an if or ifnot element at the top
+   level for matching the input and some other elements inside to be used
+   if there was a match.
+
+   Within the if and ifnot rules any of the rules can be used. These are
+   if, ifnot, set, unset, output or logerror elements.
+
+   The rules for matching the if or ifnot elements are the following:
+     * An if rule that has both k and v specified is only matched if a tag
+       exists in the input that matches both.
+     * An if rule that has only the k attribute is matched if a tag with
+       that key exists.
+     * An if rule that has only the v attribute is matched for each tag
+       with that value (i.e. the contents may be used more than once).
+     * An if rule that has neither attribute specified always matches.
+     * An ifnot rule that has both k and v specified is only matched if no
+       tag exists in the input that matches both.
+     * An ifnot rule that has only the k attribute is matched only if no
+       tag with that key exists.
+     * An ifnot rule that has only the v attribute is only matched if no
+       tag with that value exists.
+     * An ifnot rule that has neither attribute specified never matches.
+
+   For set, unset, output or logerror elements inside of an if rule an
+   unspecified value for the k or v attribute is replaced by the values
+   from the tag that matched the outer if rule. This makes it simple to
+   delete tags that match a particular rule without having to specify the
+   parameters more than once. For elements inside of an ifnot element an
+   unspecified value for the k or v attribute is replaced by the values
+   from the outer ifnot rule. This means that either the outer ifnot
+   element or the inner element must specify both k and v attributes
+   between them. For nested if or ifnot elements the outer k and v
+   attributes are not inherited by the inner elements.
+
+   The set and unset elements either create or delete a tag from the input
+   data that was read from the file. If the set element is used and the
+   tag already exists then it is modified. The output element adds a tag
+   to the set that will be used by Routino to determine the data
+   properties.
+
+   The logerror element will cause an error message to be added to the
+   error log file that reports that the key and attribute combination are
+   not recognised. If the k attribute is specified but not the v attribute
+   then the tag value that matches the specified key is looked up and
+   used. An additional message attribute can be specified to be printed at
+   the end of the logged error.
+
+   The default logged error message is:
+
+   Node XXX has an unrecognised tag 'key' = 'value' (in tagging rules); ignoring it.
+
+   The specified message attribute will replace the final part of the
+   logged error.
+
+
+Routing Profiles
+----------------
+
+   The default name of the routing profiles XML configuration file is
+   profiles.xml in the same directory as the database files. Other
+   filenames can be specified on the command line using the --tagging
+   option.
+
+   The purpose of this configuration file is to allow easy modification of
+   the routing parameters so that they do not all need to be specified on
+   the command line. In versions of Routino before version 1.4 the default
+   routing parameters (preferred highways, preferred speeds etc) were
+   contained in the source code, now they are in a configuration file.
+   When calculating a route the --profile option selects the named profile
+   from the configuration file.
+
+   Part of the provided profiles.xml file showing the parameters for
+   transport on foot is shown below:
+
+<?xml version="1.0" encoding="UTF-8" ?>
+<routino-profiles>
+
+  <profile name="foot" transport="foot">
+    <speeds>
+...
+      <speed highway="cycleway"      kph="4" />
+      <speed highway="path"          kph="4" />
+      <speed highway="steps"         kph="4" />
+    </speeds>
+    <preferences>
+...
+      <preference highway="cycleway"      percent="95" />
+      <preference highway="path"          percent="100" />
+      <preference highway="steps"         percent="80" />
+    </preferences>
+    <properties>
+      <property type="paved"        percent="50" />
+      <property type="multilane"    percent="25" />
+      <property type="bridge"       percent="50" />
+      <property type="tunnel"       percent="50" />
+...
+    </properties>
+    <restrictions>
+      <oneway obey="0" />
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+  <profile name="horse" transport="horse">
+...
+  </profile>
+...
+</routino-profiles>
+
+
+Output Translations
+-------------------
+
+   The default name of the output translations XML configuration file is
+   translations.xml in the same directory as the database files. Other
+   filenames can be specified on the command line using the --translations
+   option.
+
+   The generated HTML and GPX output files (described in the next section)
+   are created using the fragments of text that are defined in this file.
+   Additional languages can be added to the file and are selected using
+   the --language option to the router. If no language is specified the
+   first one in the file is used.
+
+   Part of the provided translations.xml file showing some of the English
+   language (en) translations is shown below:
+
+<?xml version="1.0" encoding="utf-8"?>
+<routino-translations>
+
+  <language lang="en">
+...
+    <turn direction="-4" string="Very sharp left" />
+    <turn direction="-3" string="Sharp left" />
+    <turn direction="-2" string="Left" />
+...
+    <heading direction="-4" string="South" />
+    <heading direction="-3" string="South-West" />
+    <heading direction="-2" string="West" />
+...
+    <route type="shortest" string="Shortest" />
+    <route type="quickest" string="Quickest" />
+    <output-html>
+...
+    </output-html>
+    <output-gpx>
+...
+    </output-gpx>
+  </language>
+</routino-translations>
+
+
+--------
+
+Copyright 2010-2013 Andrew M. Bishop.
diff --git a/3rdparty/Routino/doc/DATA.txt b/3rdparty/Routino/doc/DATA.txt
new file mode 100644
index 0000000..aeb84a6
--- /dev/null
+++ b/3rdparty/Routino/doc/DATA.txt
@@ -0,0 +1,116 @@
+                               Routino : Data
+                               ==============
+
+
+   A router relies on data to be able to find a route.
+
+
+OpenStreetMap Data
+------------------
+
+   The data that is collected by the OpenStreetMap project consists of
+   nodes, ways and relations.
+
+   Node
+          A node is a point that has a latitude and longitude and
+          attributes that describe what type of point it is (part of a way
+          or a place of interest for example).
+
+   Way
+          A way is a collection of nodes that when joined together define
+          something (for example a road, a railway, a boundary, a
+          building, a lake etc). The ways also have attributes that define
+          them (speed limits, type of road and restrictions for example).
+
+   Relation
+          A relation is a collection of items (usually ways) that are
+          related to each other for some reason (highways that make up a
+          route for example).
+
+   The OpenStreetMap Wiki explains the data much better than I can.
+
+
+Router Data
+-----------
+
+   The information that is needed by a routing algorithm is only a subset
+   of the information that is collected by the OpenStreetMap project. For
+   routing what is required is information about the location of roads (or
+   other highways), the connections between the highways and the
+   properties of those highways.
+
+   Location of highways (nodes)
+          The locations of things is provided by the nodes from the
+          OpenStreetMap data. The nodes are the only things that have
+          coordinates in OpenStreetMap and everything else is made up by
+          reference to them. Not all of the nodes are useful, only the
+          ones that are part of highways. The location of the nodes is
+          stored but none of the other attributes are currently used by
+          the router.
+
+   Location of highways (ways)
+          The location of the highways is defined in the OpenStreetMap
+          data by the ways. Only the highway ways are useful and the other
+          ways are discarded. What remains is lists of nodes that join
+          together to form a section of highway. This is further split
+          into segments which are individual parts of a way connected by
+          two nodes.
+
+   Properties of highways (tags)
+          The ways that belong to highways are extracted from the data in
+          the previous step and for each way the useful information for
+          routing is stored. For the router the useful information is the
+          type of highway, the speed limit, the allowed types of transport
+          and other restrictions (one-way, minimum height, maximum weight
+          etc).
+
+   Connections between highways
+          The connections between highways are defined in the
+          OpenStreetMap data by ways that share nodes. Since the ways may
+          join in the middle and not just the ends it is the segments
+          defined above that are not part of the OpenStreetMap data that
+          are most important.
+
+   The information that is extracted from the OpenStreetMap data is stored
+   in an optimised way that allows the routing to be performed quickly.
+
+
+Interpreting Data Tags
+----------------------
+
+   The tags are the information that is attached to the nodes and ways in
+   OpenStreetMap. The router needs to interpret these tags and use them
+   when deciding what type of traffic can use a highway (for example).
+
+   There are no well defined rules in OpenStreetMap about tagging, but
+   there is guidance on the OpenStreetMap Wiki "Map_Features" page. This
+   describes a set of recommended tags but these are not universally used
+   so it is up to each application how to interpret them.
+
+   The tagging rules that the router uses are very important in
+   controlling how the router works. With Routino the data tags can be
+   modified when the data is imported to allow customisation of the
+   information used for routing.
+
+
+Problems With OpenStreetMap Data
+--------------------------------
+
+   The route that can be found is only as good as the data that is
+   available. This is not intended as a criticism of the OpenStreetMap
+   data; it is generally good.
+
+   There are some problems that are well known and which affect the
+   router. For example highways might be missing because nobody has mapped
+   them. A highway may be wrongly tagged with incorrect properties, or a
+   highway might be missing important tags for routing (e.g. speed
+   limits). There can also be problems with highways that should join but
+   don't because they do not share nodes.
+
+   A lot of these problems can be found using the interactive data
+   visualiser that uses the same Routino routing database.
+
+
+--------
+
+Copyright 2008-2010 Andrew M. Bishop.
diff --git a/3rdparty/Routino/doc/DATALIFE.txt b/3rdparty/Routino/doc/DATALIFE.txt
new file mode 100644
index 0000000..85447a7
--- /dev/null
+++ b/3rdparty/Routino/doc/DATALIFE.txt
@@ -0,0 +1,106 @@
+                                Planetsplitter Data Lifetime
+                                ============================
+
+Key (memory mapping):
+  nswr = Mapped into memory read-only
+  NSWR = Mapped into memory read/write
+
+Key (structure parameter usage):
+  C = Created   (allocated then written; write-only)
+  D = Destroyed (read then de-allocated; read-only)
+  U = Used      (read; read-only)
+  W = Written   (written; write-only)
+  M = Modified  (read then written; read/write)
+  T = Temporary (written then read; read/write)
+  | = Preserved unmodified for later
+  * = In this loop the current iteration of (super-)segments are in uppercase, the next iteration are in lowercase.
+
+                              .............................
+                              : Nodes        \
+                              : |Segments     | Mapped into
+                              : ||Ways        | memory
+                              : |||Relations /
+                              : |||| ...........................
+                              : vvvv : nodesx->idata
+                              :      : | . nodesx->gdata
+                              :      : | . | . nodesx->pdata
+                              :      : | . | . | . nodesx->super
+                              :      : | . | . | . | . nodex->id
+                              :      : | . | . | . | . | ...................................
+                              :      : v . v . v . v . v : segmentsx->firstnode
+                              :      :   .   .   .   .   : | . segmentsx->next1
+                              :      :   .   .   .   .   : | . | . segmentsx->usedway
+                              :      :   .   .   .   .   : | . | . | . segmentx->node1,2
+                              :      :   .   .   .   .   : | . | . | . | . segmentx->next2
+                              :      :   .   .   .   .   : | . | . | . | . | . segmentx->way
+                              :      :   .   .   .   .   : | . | . | . | . | . | ..................
+                              :      :   .   .   .   .   : v . v . v . v . v . v : waysx->idata
+                              :      :   .   .   .   .   :   .   .   .   .   .   : | . waysx->cdata
+                              :      :   .   .   .   .   :   .   .   .   .   .   : | . | . wayx->id
+                              :      :   .   .   .   .   :   .   .   .   .   .   : | . | . | ...............
+Function name (in order)      :      :   .   .   .   .   :   .   .   .   .   .   : v . v . v : relationx->id
+|                             :      :   .   .   .   .   :   .   .   .   .   .   :   .   .   : | ...........
+v                             :      :   .   .   .   .   :   .   .   .   .   .   :   .   .   : v :
+                              :......:...................:.......................:...........:...:
+(Parse XML etc)               :      :   .   .   .   . W :   .   .   .   .   .   :   .   . W : W :
+                              :......:...................:.......................:...........:...:
+SortNodeList                  :      : C .   .   .   . U :   .   .   .   .   .   :   .   . | : | :
+SortWayList                   :      : | .   .   .   . | :   .   .   .   .   .   : C .   . U : | :
+SortRelationList              :      : | .   .   .   . | :   .   .   .   .   .   : | .   .   : U :
+RemoveNonHighwayNodes         :      : M .   .   .   . U :   .   .   .   .   .   : | .   .   : | :
+SplitWays                     :      : U .   .   .   .   :   .   .   . W .   . W : U .   .   : | :
+SortWayNames                  :   W  : | .   .   .   .   :   .   .   . | .   . | : | .   .   : | :
+SortSegmentList               :      : | .   .   .   .   :   .   .   . U .   . | : | .   .   : | :
+ProcessSegments               : n    : U .   .   .   .   :   .   . C . U .   . U : U .   .   : | :
+IndexSegments                 :  S   : | .   .   .   .   : C .   . | . U . W . | : | .   .   : | :
+ProcessRouteRelations         :   W  : | .   .   .   .   : | .   . | . | . | . | : U .   .   : U :
+ProcessTurnRelations          : Nsw  : D .   .   .   .   : D .   . | . U . U . | : D .   .   : U :
+CompactWayList                :      :   .   .   .   .   :   .   . D . | .   . | :   . C . T :   :
+                              :......:...................:.......................:...........:...:
+SortNodeListGeographically    :      :   . C .   .   . T :   .   .   . | .   . | :   . | .   :   :
+SortSegmentListGeographically :      :   . U .   .   .   :   .   .   . M .   . | :   . | .   :   :
+IndexSegments                 :  S   :   . | .   .   .   : C .   .   . U . W . | :   . D .   :   :
+SortTurnRelationListGeogra... :  s   :   . D .   .   .   : U .   .   . U . U . | :   .   .   :   :
+                              :......:...................:.......................:...........:...:
+StartPruning                  :      :   .   .   .   .   : | . C .   . U . U . | :   .   .   :   : <---+
+PruneStraightHighwayNodes     : nSw  :   .   .   .   .   : U . U .   . U . U . | :   .   .   :   : \ o |
+PruneIsolatedRegions          : nSw  :   .   .   .   .   : U . U .   . U . U . | :   .   .   :   : | n |
+PruneShortSegments            : NSw  :   .   .   .   .   : U . U .   . U . U . | :   .   .   :   : / e | L
+FinishPruning                 :      :   .   .   .   .   : | . D .   . | .   . | :   .   .   :   :     | o
+RemovePrunedNodes             :      :   .   . C .   .   : D .   .   . | .   . | :   .   .   :   :     | o
+RemovePrunedSegments          :      :   .   . | .   .   :   .   . C . U .   . | :   .   .   :   :     | p
+CompactWayList                :      :   .   . | .   .   :   .   . D . | .   . | :   . C . T :   :     |
+RemovePrunedTurnRelations     :      :   .   . U .   .   :   .   .   . | .   . | :   . | .   :   :     |
+IndexSegments                 :  S   :   .   . D .   .   : C .   .   . M . W . | :   . D .   :   :     |
+                              :......:...................:.......................:...........:...: ----+
+ChooseSuperNodes              :  sw  :   .   .   . M .   : U .   .   . | . U . | :   .   .   :   :
+CreateSuperSegments           : nsw  :   .   .   . U .   : D .   .   .*Uw. U . | :   .   .   :   :
+DeduplicateSuperSegments      :   w  :   .   .   . | .   :   .   .   .*Uu.   . | :   .   .   :   :
+                              :......:...................:.......................:...........:...:
+IndexSegments                 :  S   :   .   .   . | .   : C .   .   . U . W . | :   .   .   :   : <-+
+ChooseSuperNodes              :  sw  :   .   .   . M .   : U .   .   . | . U . | :   .   .   :   :   | L
+CreateSuperSegments           : nsw  :   .   .   . U .   : D .   .   .*Uw. U . | :   .   .   :   :   | o
+DeduplicateSuperSegments      :   w  :   .   .   . | .   :   .   .   .*Uu.   . | :   .   .   :   :   | o
+                              :......:...................:.......................:...........:...: --+ p
+MergeSuperSegments            :      :   .   .   . | .   :   .   .   . U .   . | :   .   .   :   :
+                              :......:...................:.......................:...........:...:
+SortNodeListGeographically    :      :   . C .   . D . T :   .   .   . | .   . | :   .   .   :   :
+SortSegmentListGeographically :      :   . U .   .   .   :   .   .   . M .   . | :   .   .   :   :
+IndexSegments                 :  S   :   . | .   .   .   : C .   .   . U . W . | :   .   .   :   :
+SortTurnRelationListGeogra... :  s   :   . D .   .   .   : U .   .   . U . U . | :   .   .   :   :
+                              :......:...................:.......................:...........:...:
+SaveNodeList                  :      :   .   .   .   .   : D .   .   . | . | . | :   .   .   :   :
+SaveSegmentList               :      :   .   .   .   .   :   .   .   . U . U . U :   .   .   :   :
+SaveWayList                   :      :   .   .   .   .   :   .   .   .   .   .   :   .   .   :   :
+SaveRelationList              :      :   .   .   .   .   :   .   .   .   .   .   :   .   .   :   :
+                              :......:...................:.......................:...........:...:
+                                     : m . m . m . m . m : m . m . m . m . m . m : m . m . m : m :
+                                     : a . a . a . a . m : a . a . a . m . m . m : a . a . m : m :
+                                     : l . l . l . l . a : l . l . l . a . a . a : l . l . a : a :
+                                     : l . l . l . l . p : l . l . l . p . p . p : l . l . p : p :
+                                     : o . o . o . o .   : o . o . o .   .   .   : o . o .   :   :
+                                     : c . c . c . c .   : c . c . c .   .   .   : c . c .   :   :
+
+
+Note: waysx->odata, relationsx->rridata, relationsx->rrodata and relationsx->tridata are only used
+by the error log creation functions which are optional (all use malloc and not mmap).
diff --git a/3rdparty/Routino/doc/INSTALL-MS-WIN.txt b/3rdparty/Routino/doc/INSTALL-MS-WIN.txt
new file mode 100644
index 0000000..8a5e667
--- /dev/null
+++ b/3rdparty/Routino/doc/INSTALL-MS-WIN.txt
@@ -0,0 +1,138 @@
+                   Routino : Installation on MS Windows
+                   ====================================
+
+
+Using Cygwin
+------------
+
+   Cygwin is a large collection of GNU and Open Source tools which provide
+   functionality similar to a Linux distribution on Windows. A Cygwin DLL
+   provides substantial POSIX API functionality therefore providing direct
+   compatibility for most UNIX source code.
+
+   Since Cygwin aims to replicate a Linux-like system on Windows it is the
+   simplest method of compiling Routino. The disadvantage is that all
+   programs compiled with Cygwin require a number of runtime Cygwin
+   libraries which may introduce a runtime speed penalty.
+
+   The installer for Cygwin can be downloaded from http://cygwin.org/;
+   there are 32-bit and 64-bit versions available. For compiling Routino
+   the Cygwin installer should be run and the following packages selected
+   (any dependencies will be automatically be selected at the next step):
+
+     * base packages
+     * gcc-core (in 'Devel' menu)
+     * make (in 'Devel' menu)
+     * libbz2-devel (in 'Libs' menu)
+     * zlib-devel (in 'Libs' menu)
+     * perl (in 'Perl' menu)
+
+   To compile Routino open the "Cygwin Terminal" change to the Routino
+   source directory and compile using the make command.
+
+
+Native Compilation
+------------------
+
+   Routino has limited support in the source code for compiling on
+   Microsoft Windows. This includes a set of functions that can replace
+   the mmap() and munmap() UNIX functions which are not available on
+   Microsoft Windows.
+
+   The source code should be downloaded, either as a release version file
+   or from subversion - no instructions are provided for this step. The
+   release versions include some files (mainly the web icons) which are
+   not included in the subversion source (and which may be difficult to
+   create on Windows).
+
+Using Microsoft Visual C
+- - - - - - - - - - - -
+
+   The Routino source code (for the router at least) has been modified so
+   that it will compile with the Microsoft Visual C compiler.
+
+   The files that need to be compiled for the Routino router can be found
+   from the Makefile in the 'src' directory listed in the 'ROUTER_OBJ'
+   variable.
+
+   To compile the router in slim mode the pre-processor definition 'SLIM=0'
+   must be set and for non-slim mode 'SLIM=1' must be set.
+
+   The default directory for the Routino data files must be set in the
+   'ROUTINO_DATADIR' pre-processor variable. If the router command line
+   '--data' option is going to be used then this variable can be set to
+   any value.
+
+   Since Microsoft Visual C does not fully support the C99 standard it is
+   necessary to tell the compiler how to handle the inline functions. This
+   can be done by passing in the command line option '-Dinline=__inline' to
+   the C compiler.
+
+Using MinGW
+- - - - - -
+
+   MinGW is the "Minimalist GNU for Windows" which includes some of the
+   common GNU programs; principally gcc and related programs for software
+   development.
+
+   The installer for MinGW can be downloaded from 'http://mingw.org/'. For
+   compiling Routino the MinGW installer should be run and the following
+   packages selected:
+     * mingw-base
+     * msys-base
+     * mingw32-pthreads-w32
+     * mingw32-libz (dev package)
+     * msys-perl
+
+   To compile Routino open a DOS command window and set the path to the
+   installed MinGW and MSYS software. For example if MinGW was installed
+   in the 'C:/MinGW' directory then the path needs to be set to
+   'C:\MinGW\bin;C:\MinGW\MSYS\1.0\bin'.
+
+   From within this DOS command window change to the Routino source
+   directory and compile using the MinGW version of make with this command
+   'mingw32-make MINGW=1'.
+
+Using MinGW-W64
+- - - - - - - -
+
+   MinGW-w64 is an alernative implementation of the same concept as MinGW
+   but allows for compilation to 32-bit or 64-bit executables.
+
+   The website for MinGW-w64 is 'http://mingw-w64.org/' but the downloads
+   are available from 'http://win-builds.org/'.
+
+   The compilation method for MinGW-w64 should be the same as for MinGW.
+
+Limitations
+- - - - - -
+
+   A native Microsoft Windows compilation of Routino is more complicated
+   than compiling on Linux, other UNIX system or Cygwin. This is probably
+   not an option if you are unfamiliar with software development on
+   Microsoft Windows.
+
+   The size of files that can be accessed with an MSVC or MinGW compiled
+   version of Routino is limited to 32-bits (about 2 GB). The MinGW-w64
+   compiler on 64-bit windows might be able to handle larger files but has
+   not been tested.
+
+   The Windows operating system does not have a function equivalent to the
+   'fork()' function on UNIX. This means that it is not possible to use the
+   planetsplitter program's built-in file decompression with an MSVC or
+   MinGW compiled version of Routino.
+
+
+Example Web Pages
+-----------------
+
+   No instructions are available for using the Routino example web pages
+   with the Microsoft Web server (IIS).
+
+   For information on setting up Apache see the "Example Web Pages"
+   section of the main installation instructions.
+
+
+--------
+
+Copyright 2008-2015 Andrew M. Bishop.
diff --git a/3rdparty/Routino/doc/INSTALL.txt b/3rdparty/Routino/doc/INSTALL.txt
new file mode 100644
index 0000000..0ee8b48
--- /dev/null
+++ b/3rdparty/Routino/doc/INSTALL.txt
@@ -0,0 +1,312 @@
+                           Routino : Installation
+                           ======================
+
+
+Quick Start Guide
+-----------------
+
+   The instructions below are a complete list of the minimum required to
+   get Routino installed and running under Apache on Debian Linux. Other
+   Linux versions will be similar and other UNIX based systems will also
+   be similar although may have distinct differences. There is some
+   support in Routino for compiling on Microsoft Windows which has its own
+   installation instructions.
+
+   ***********************************************************************
+   *** These instructions should not be considered as complete or a    ***
+   *** secure installation for the reasons given in more detail below. ***
+   ***********************************************************************
+
+   The starting point for the installation is in the Routino source code
+   directory after it has been uncompressed. Most of the steps will need
+   to be run as the root user.
+
+   The first thing to do is to install the packages which are required for
+   compilation of Routino as described in the Pre-Requisites section
+   below.
+
+        apt-get install gcc make libc6-dev libz-dev libbz2-dev
+
+   After this the programs can be compiled:
+
+        make
+
+   The files for the web interface can now be copied to the web server
+   directory. On Debian this is '/var/www' and the files changed to be
+   owned by the user Apache runs as.
+
+        cp -a web /var/www/routino
+        chown -R www-data:www-data /var/www/routino
+
+   To be able to use Routino some data will need to be processed and a
+   script is provided for this. This will download the data for the UK
+   which may take a while and then process it.
+
+        cd /var/www/routino/data
+        sh -x create.sh
+
+   The routino web pages also requires either the OpenLayers or Leaflet
+   Javascript library to be downloaded and installed and scripts are
+   provided for this.
+
+        cd /var/www/routino/www/openlayers
+        sh -x install.sh
+
+        cd /var/www/routino/www/leaflet
+        sh -x install.sh
+
+   To make full use of the location search feature on the Routino web page
+   you will need to install some extra perl packages.
+
+       apt-get install libwww-perl liburi-perl libjson-pp-perl
+
+   Finally to make the web pages work you will need to add the extra lines
+   to the Apache configuration file as described in the Configuration of
+   Web Server section below.  You don't have to use 'vi' and can use any
+   text editor.
+
+        vi /etc/apache2/sites-enabled/000-default
+        apache2ctl restart
+
+   Now everything should be set up and the web page should work if
+   accessed at 'http://localhost/routino/www/routino/router.html'.
+
+   When everything is working you should read the rest of this document
+   carefully and make the following changes:
+     * Download your choice of OSM data - edit the file data/create.sh and
+       run it again.
+     * Edit the www/routino/mapprops.js file to match the downloaded data
+       and personal map preferences.
+     * Move the files in the web server directory so that only the
+       contents of the www directory are accessible by the web server.
+     * Edit the file www/routino/paths.pl to reference the new file
+       locations.
+
+
+Pre-Requisites
+--------------
+
+   The programs are written in standard C language with minimal external
+   requirements so only a small set of development tools are required
+   (gcc, make). The compilation tools to use and the command line options
+   are defined in the file 'Makefile.conf'.
+
+   There is some support for multi-threading that uses pthreads and
+   additional development libraries for this may be required (on Linux
+   this might be part of the standard C language development files). The
+   multi-threading is enabled by default but can be disabled at compile
+   time by commenting out two lines in the file 'Makefile.conf'.
+
+   To use the built-in gzip file decompression function and to process all
+   PBF format files the zlib (or libz) development library is required (on
+   Linux this might be in a package called libz-dev). The gzip function is
+   enabled by default but can be disabled by commenting out two lines in
+   the file 'Makefile.conf'.
+
+   To use the built-in bzip2 file decompression functions the bzip2 (or
+   libbz2) development library is required (on Linux this might be in a
+   package called libbz2-dev). The bzip2 function is enabled by default
+   but can be disabled by commenting out two lines in the file
+   'Makefile.conf'.
+
+   To use the built-in xz file decompression functions the liblzma
+   development library is required (on Linux this might be in a package
+   called liblzma-dev). The xz function is not enabled by default but can
+   be enabled by uncommenting two lines in the file 'Makefile.conf'.
+
+   To compile the source code from subversion requires the Perl
+   Graphics::Magick module to generate the web page icons (on Linux this
+   might be in a package called libgraphics-magick-perl). The released
+   source code packages contains the icons so this package is not required
+   for compilation.
+
+   To use the web page interface an http server is required. Instructions
+   below are for Apache but any server that supports CGIs should work.
+
+   The web pages use the Perl scripting language and a number of the
+   default Perl modules. To use the search function on the router web page
+   the Perl module JSON::PP must be installed (on Linux this might be in a
+   package called libjson-pp-perl if not part of the standard Perl
+   installation).
+
+Compilation
+-----------
+
+   To compile the programs just type 'make' at the top level of the source
+   tree.
+
+   This program has been written to run on Linux, no cross-platform
+   compatibility has been specifically included but on the other hand
+   other platforms have not knowingly been excluded either.
+
+   Any information on improving the compilation process on anything other
+   than x86 Linux is welcome.
+
+
+Installation
+------------
+
+   After compilation the executable files are copied into the directory
+   web/bin and the default XML configuration files are copied into the
+   directory web/data. This is in preparation for using the supplied
+   example web pages but is also a useful location to copy the files from
+   for normal use.
+
+   The required executable files are 'planetsplitter', 'router' and
+   'filedumper' and the '*-slim' versions of the same files. They can be
+   copied to any location and need no special installation environment.
+   The 'filedumperx' executable is for debugging and not required.
+
+   The configuration files are called 'profiles.xml', 'tagging.xml' and
+   'translations.xml'. The names of the configuration files can be
+   specified on the command line but by default are also looked for in the
+   directory that contains the routing database with these names.
+
+
+Example Web Page
+----------------
+
+   The directory 'web' contains a set of files that can be used to create
+   a working set of web pages with interfaces to the routing algorithm.
+
+   The files in the 'web' directory will require copying to a location
+   that is accessible by a web server. After copying the files some of
+   them need to be edited; search through the files for lines that contain
+   the words "EDIT THIS" and make appropriate edits. The files that need
+   editing are 'paths.pl' (to set the directory paths) and 'mapprops.js' (to
+   set the map properties).
+
+
+Configuration of web files
+--------------------------
+
+   The assumption in this description is that the whole of the directory
+   called web is copied into a directory that is accessible by an Apache
+   web server.
+
+    **************************************************************************
+    **** This is not a secure configuration but an easy one to configure. ****
+    **** Only the directory 'www' should be accessible by the web server. ****
+    **** Do not use this configuration unmodified in a public web server. ****
+    **************************************************************************
+
+   The directory structure is as follows:
+
+   web/
+    |
+    + /bin/                    <- The Routino executable files (when compiled).
+    |
+    + /data/                   <- The Routino database and default configuration
+    |                             files.
+    |
+    + /results/                <- An empty directory to store the results.
+    |
+    + /www/                    <- The files that must be available to the web
+        |                         server are below this level.
+        |
+        + /openlayers/         <- A directory to hold the OpenLayers library
+        |                         (optional; leaflet can be used instead).
+        |
+        + /leaflet/            <- A directory to hold the Leaflet library.
+        |                         (optional; openlayers can be used instead).
+        |
+        + /routino/            <- The main HTML, Javascript, CSS and CGI files.
+            |
+            + /documentation/  <- The HTML version of the Routino documentation.
+
+   The directory 'bin' will be filled by running the compilation process.
+   For a secure installation the 'bin' directory should be outside of the
+   web server, the file 'www/routino/paths.pl' contains the path to the
+   'bin' directory.
+
+   The directory 'data' must contain the Routino database and is also the
+   default location for the configuration files. The routing database is
+   created by downloading the OSM files for the region of interest and
+   running the 'planetsplitter' program. There is a script in the
+   directory that will download the OSM files and create the required
+   database. The script should be edited to set the names of the files to
+   be downloaded.  For a secure installation the 'data' directory should
+   be outside of the web server, the file 'www/routino/paths.pl' contains
+   the path to the 'data' directory.
+
+   The directory 'results' is a temporary directory that it used to hold
+   the GPX and text files generated by the Routino router. The directory
+   must be writable by the web server process since it is the CGI scripts
+   that are run by the web server that writes the results here. For a
+   secure installation the results directory should be outside of the web
+   server, the file 'www/routino/paths.pl' contains the path to the
+   results directory.
+
+   The directory 'www' and its sub-directories are the only ones that need
+   to be within the web server accessible directory.
+
+   A Javascript map drawing library is required and either OpenLayers or
+   Leaflet can be used. The library is loaded dynamically when the HTML is
+   opened based on the value that is selected in 'mapprops.js'.
+
+   The directory 'www/openlayers' is for the OpenLayers Javascript library
+   that can be downloaded from 'http://www.openlayers.org/'.  (This version
+   of Routino has been tested with OpenLayers library versions 2.12 and
+   2.13.1). The file 'www/openlayers/OpenLayers.js' and the directories
+   'www/openlayers/img/' and 'www/openlayers/theme/' must all exist. There
+   is a script in the 'www/openlayers' directory that will automatically
+   download the files, create an optimised 'OpenLayers.js' and copy the
+   files to the required locations.
+
+   The directory 'www/leaflet' is for the Leaflet Javascript library that
+   can be downloaded from 'http://leafletjs.com/'. (This version of Routino
+   has been tested with Leaflet library versions 0.7.1 and 0.7.2). The files
+   'www/leaflet/leaflet.js' and 'www/leaflet/leaflet.css' and the directory
+   'www/leaflet/images/' must all exist. There is a script in the
+   'www/leaflet' directory that will automatically download the files.
+
+   The directory 'www/routino' contains the main HTML, Javascript and CSS
+   files as well as the CGI scripts that perform the server-side routing
+   functions. The description below lists all of the files that contain
+   editable information.
+
+   paths.pl
+          This contains the names of the directories that contain the
+          executable files, router database and temporary results; the
+          prefix for the routing database; and the names of the
+          executables.
+
+   mapprops.js
+          The parameters in this file control the Javascript map library
+          (defaults to OpenLayers), the boundary of the visible map
+          (defaults to UK), the minimum and maximum zoom levels (defaults
+          to between 4 and 15 inclusive), the source of map tiles
+          (defaults to the main OpenStreetMap tile server), the data
+          editing and browsing URLs (default to the OpenStreetMap website)
+          and the number of waypoints allowed (defaults to 9).
+
+   The directory www/routino/documentation contains the HTML version of
+   the Routino documentation.
+
+
+Configuration of Web Server
+---------------------------
+
+   The file 'www/routino/.htaccess' contains all of the Apache
+   configuration options that are required to get the example web pages
+   running. The only problem is that because of the way that the
+   "AllowOverride" option works one of the configuration options has been
+   commented out. This must be enabled in the main Apache server
+   configuration file.
+
+   If you have copied the routino 'web' directory into '/var/www' and named
+   it 'routino' then the entry that you need in your Apache configuration
+   file is this one:
+  
+     <Directory /var/www/routino>
+         AllowOverride All
+         Options +ExecCGI
+     </Directory>
+
+   This can be placed anywhere between the <VirtualHost *:80> and
+   </VirtualHost> tags which should be at the start and end of the file.
+
+
+--------
+
+Copyright 2008-2015 Andrew M. Bishop.
diff --git a/3rdparty/Routino/doc/LIMITS.txt b/3rdparty/Routino/doc/LIMITS.txt
new file mode 100644
index 0000000..a434ea4
--- /dev/null
+++ b/3rdparty/Routino/doc/LIMITS.txt
@@ -0,0 +1,167 @@
+                         Routino : Numerical Limits
+                         ==========================
+
+
+32/64-bit Data IDs
+------------------
+
+   The OpenStreetMap data uses a numerical identifier for each node, way
+   and relation. These identifiers started at 1 and increase for every new
+   item of each type that is added. When an object is deleted the
+   identifier is not re-used so the highest identifier will always be
+   higher than the number of objects.
+
+   The identifier needs to be handled carefully to ensure that it does not
+   overflow the data type allocated for it. Depending on the data type
+   used to store the identifier there are are a number of numerical limits
+   as described below:
+
+    1. If a signed 32-bit integer is used to store the identifier then the
+       maximum value that can be handled is 2147483647 (2^31-1) before
+       overflow.
+    2. If an unsigned 32-bit integer is used to store the identifier then
+       the maximum value that can be handled is 4294967295 (2^32-1) before
+       overflow.
+    3. If a signed 64-bit integer is used to store the identifier then the
+       maximum value that can be handled is 9223372036854775807 (2^63-1)
+       before overflow.
+
+   For the purposes of this document the possibility of overflow of a
+   64-bit integer is ignored.
+
+   The part of Routino that handles the node, way and relation identifiers
+   is the planetsplitter program.
+
+
+ID Above 31-bits
+- - - - - - - -
+
+   The first identifier exceeding 31-bits (for a node) is predicted to be
+   created in the OpenStreetMap database in February 2013.
+
+   All versions of Routino use unsigned 32-bit integers to store the
+   identifier. Therefore all versions of Routino will continue working
+   correctly when node number 2147483648 (2^31) or higher is present.
+
+
+ID Above 32-bits
+- - - - - - - -
+
+   The ability of Routino to handle identifiers larger than 32-bits does
+   not depend on having a 64-bit operating system.
+
+   Before version 2.0.1 of Routino there was no check that the identifier
+   read from the input data would fit within an unsigned 32-bit integer.
+   Earlier versions of Routino will therefore fail to report an error and
+   will process data incorrectly when node number 4294967296 (2^32) or
+   higher is present.
+
+   From version 2.0.2 the code is written to allow the node, way and
+   relation identifier data type to be changed to 64-bits. This means that
+   a consistent data type is used for handling identifiers and the format
+   used for printing them is consistent with the variable type.
+
+   From version 2.0.2 onwards it is possible to make a simple change to
+   the code to process data with node identifiers above 4294967296 (2^32)
+   without error. The binary format of the database will be unchanged by
+   the use of 64-bit identifiers (since the identifiers are not stored in
+   the database).
+
+   To recompile with 64-bit node identifiers the file src/typesx.h should
+   be edited and the two lines below changed from:
+
+typedef uint32_t node_t;
+
+#define Pnode_t PRIu32
+
+   to:
+
+typedef uint64_t node_t;
+
+#define Pnode_t PRIu64
+
+   A similar change can also be made for way or relation identifiers
+   although since there are currently fewer of these the limit is not as
+   close to being reached.
+
+   Between version 2.0.2 and version 2.4 a bug means that route relations
+   will ignore the way or relation identifier if it is equal to 4294967295
+   (2^32-1).
+
+   From version 2.4 onwards when a numerical limit is reached the
+   planetsplitter program will exit with an error message that describes
+   which limit was reached and which data type needs to be changed.
+
+
+Database Format
+---------------
+
+   The other limitation in Routino is the number of objects stored in the
+   database that is generated by the planetsplitter data processing. This
+   number may be significantly different from the highest identifier in
+   the input data set for two reasons. Firstly any nodes, ways or
+   relations that have been deleted will not be present in the data.
+   Secondly when a partial planet database (continent, country or smaller)
+   is processed there will be only a fraction of the total number of
+   nodes, ways and relations.
+
+   The limiting factor is the largest of the following.
+
+    1. The number of nodes in the input data files.
+    2. The number of segments in the input data files.
+    3. The number of highways in the input data files.
+    4. The number of relations in the input data files.
+
+   Normally the number of nodes will be the limiting factor.
+
+
+32-bit Indexes
+- - - - - - -
+
+   Before version 1.2 the database could hold up to 4294967295 (2^32-1)
+   items of each type (node, segment, way) since an unsigned 32-bit
+   integer is used.
+
+   Versions 1.3 to 1.4.1 have a limit of 2147483647 (2^31-1) items since
+   half of the 32-bit integer range is reserved for fake nodes and
+   segments that are inserted if a waypoint is not close to a node.
+
+   From version 1.5 the limit is 4294901760 (2^32-2^16) for the number of
+   items of each type that can be stored. The small remaining part of the
+   32-bit unsigned integer range is reserved for fake nodes and segments.
+
+
+64-bit Indexes
+- - - - - - -
+
+   When using a 32-bit operating system it is not possible to create a
+   database that exceeds about 2GB in total. This will be fewer than 2^32
+   objects in the database in total. The use of 64-bit indexes will
+   require a 64-bit operating system.
+
+   From version 2.0.2 onwards it is possible to make a simple change to
+   the code to index the database objects with 64-bit integers insted of
+   32-bit integers.
+
+   To recompile with 64-bit index integers the file src/types.h should be
+   edited and the two lines below changed from:
+
+typedef uint32_t index_t;
+
+#define Pindex_t PRIu32
+
+   to:
+
+typedef uint64_t index_t;
+
+#define Pindex_t PRIu64
+
+   This change will affect nodes, segments, ways and relations together.
+   The database that is generated will no longer be compatible with
+   Routino that has been compiled with 32-bit indexes. The size of the
+   database will also grow by about 50% when this change is made.
+
+
+--------
+
+Copyright 2013 Andrew M. Bishop.
diff --git a/3rdparty/Routino/doc/Makefile b/3rdparty/Routino/doc/Makefile
new file mode 100644
index 0000000..f094b9d
--- /dev/null
+++ b/3rdparty/Routino/doc/Makefile
@@ -0,0 +1,75 @@
+# Documentation directory Makefile
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2010-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# All configuration is in the top-level Makefile.conf
+
+include ../Makefile.conf
+
+# Files to install
+
+HTML_FILES=$(notdir $(wildcard html/*.html)) $(notdir $(wildcard html/*.css))
+TXT_FILES=*.txt
+TOP_FILES=../agpl-3.0.txt
+
+########
+
+all:
+
+########
+
+test:
+
+########
+
+install: install-txt install-html
+
+install-txt:
+	@[ -d $(DESTDIR)$(docdir) ] || mkdir -p $(DESTDIR)$(docdir)
+	@for file in $(TOP_FILES); do \
+	    echo cp $$file $(DESTDIR)$(docdir) ;\
+	    cp -f $$file $(DESTDIR)$(docdir) ;\
+	 done
+	@for file in $(TXT_FILES); do \
+	    echo cp $$file $(DESTDIR)$(docdir) ;\
+	    cp -f $$file $(DESTDIR)$(docdir) ;\
+	 done
+
+install-html:
+	@[ -d $(DESTDIR)$(docdir)/html ] || mkdir -p $(DESTDIR)$(docdir)/html
+	@for file in $(HTML_FILES); do \
+	    echo cp html/$$file $(DESTDIR)$(docdir)/html ;\
+	    cp -f html/$$file $(DESTDIR)$(docdir)/html ;\
+	 done
+
+########
+
+clean:
+	rm -f *~
+	rm -f html/*~
+
+########
+
+distclean: clean
+
+########
+
+.PHONY:: all test install clean distclean
+
+.PHONY:: install-txt install-html
diff --git a/3rdparty/Routino/doc/NEWS.txt b/3rdparty/Routino/doc/NEWS.txt
new file mode 100644
index 0000000..2c50b7d
--- /dev/null
+++ b/3rdparty/Routino/doc/NEWS.txt
@@ -0,0 +1,824 @@
+Version 2.7.3 of Routino released : Sat Nov 8 2014
+--------------------------------------------------
+
+Bug fixes:
+  Limit the property preference ratio to 100 instead of 10000.
+  Don't allocate memory for sorting that won't be used.
+
+planetsplitter:
+  Added an option to print out the allocated/mapped memory at each step.
+  Speed up database generation by compacting results after each pruning step.
+  Speed up database generation by sorting nodes geographically before pruning.
+  Reduce memory use while generating the database.  
+
+router:
+  Added the options to print out time and allocated/mapped memory at each step.
+
+Translations:
+  Updated German translations.
+
+
+Note: This version is compatible with databases from version 2.7.1 & 2.7.2.
+
+
+Version 2.7.2 of Routino released : Thu June 26 2014
+----------------------------------------------------
+
+Bug fixes:
+  Make the visualiser display all segments including those crossing the border.
+  Fix two errors that cause crashes only on 64-bit systems.
+
+planetsplitter / router:
+  Increase the size of the caches for the slim programs by a factor of four.
+
+Translations:
+  Updated Russian translations.
+  Updated German translations.
+
+
+Note: This version is compatible with databases from version 2.7.1.
+
+
+Version 2.7.1 of Routino released : Sat May 17 2014
+---------------------------------------------------
+
+Bug fixes:
+  Fix typo in documentation for command to get SVN version.
+  Fix router crash when waypoint is on roundabout.
+  Don't duplicate super-segments when merging them with normal segments.
+  Change routing instructions for bicycle if highways allow cycling both ways.
+  Make translation script work with older versions of Perl.
+  Fix router crash if fewer than two waypoints are specified.
+  Revert router speed decrease with special-case tagging rules.
+  Fix web page search function when it returns non-ASCII text.
+  Fix router failure due to invalid assumption about allowed U-turn.
+  Fix bug with updating XML files in web/data directory (Makefile error).
+  Fix router web page error due to absence of cyclebothways property entry.
+  Fix results error if a waypoint node was passed again on way to next waypoint.
+  Fix router crash when route contains consecutive coincident waypoints.
+  Fix bug with slightly incorrect distances when pruning short segments.
+
+Test cases:
+  Create new test case for roundabout waypoint bug fixed in this version.
+  Create new test case for invalid U-turn assumption bug fixed in this version.
+  Create new test case for cycling both ways.
+  Create new test case for consecutive coincident waypoints.
+
+router:
+  Remove cyclebothways as a property that can be used as a routing preference.
+
+Web pages:
+  Disallow route calculation if fewer than two waypoints are selected.
+  Update visualiser for change of cyclebothways handling.
+
+Translations:
+  Updated Russian translations.
+  Updated German translations.
+
+
+Note: This version is not compatible with databases from previous versions.
+
+
+Version 2.7 of Routino released : Sat Mar 22 2014
+-------------------------------------------------
+
+Bug fixes:
+  Fix web-page CGI bug that did not allow more than 9 waypoints to be routed.
+  Fix typo in documentation strings in filedumper program.
+  Fix error in function prototype that stopped 64-bit node type being used.
+  Don't lose super-segments when merging them with normal segments.
+  Don't exceed the database lat/long limits when searching for visualiser data.
+
+planetsplitter:
+  Don't overflow (and wrap-around) conversions of lengths, weights etc.
+  Add some new formats of length, weight and speed parsing.
+  Add .xz uncompression as a compile-time option (default is disabled).
+
+router:
+  Remove ancient undocumented option to specify lat/lon without --lat/--lon.
+  Add a '--output-stdout' option to output the route in a selected format.
+  Add a '--reverse' option to calculate a route in the reverse order.
+  Add a '--loop' option to calculate a route that returns to the first waypoint.
+  Output valid HTML4 (use strict DTD and use numeric entity for apostrophe).
+
+OSM tagging:
+  Allow bicycles both ways on certain oneway roads if tagging allows.
+  Handle "access=bus" like "access=psv".
+
+Configuration Files:
+  Updated Dutch translations.
+  Updates to the XML parser tagging rules.
+  Added French translations for the routing output.
+
+Documentation:
+  Update the algorithm documentation for finding the shortest path.
+  Update documentation HTML to strict 4.01 DTD.
+
+Web pages:
+  Some changes to HTML, CSS formatting and Javascript to improve usability.
+  Added a French translation of the router web page.
+  Add the option to choose between OpenLayers and Leaflet for map rendering.
+  Check compatible with OpenLayers v2.13.1 and make this the default.
+  Create the router and visualiser pages from templates and translated phrases.
+
+
+Note: This version has removed specific support for IE6 and IE7 browsers.
+
+Note: This version is compatible with databases from version 2.6 (although
+      cycling both ways on one-way highways requires a database update).
+
+
+Version 2.6 of Routino released : Sat Jul 6 2013
+------------------------------------------------
+
+Bug fixes:
+  Force '<if>...</if>' in tagging rules to match even with no input tags.
+  Built-in translations for GPX-route file gave nonsense durations.
+  Handle some cases that potentially caused divide by zero (not crashes).
+
+Compilation:
+  All configuration is now contained in the top level file Makefile.conf.
+  Default to using -ffast-math option for faster maths and glibc workaround.
+
+Code improvements:
+  Improve router internal data structures to increase performance.
+  Add another layer of caching to significantly speed up slim mode operation.
+  Add a layer of file buffering to significantly speed up reading/writing.
+  Enable more compile-time warnings and fix them.
+
+planetsplitter:
+  Create a binary log file to allow searching for errors geographically.
+  Simplify processing for changes (segment files not kept).
+  Don't prune isolated regions for transport types we don't have.
+
+Web pages (visualiser):
+  Allow displaying the error logs on the map.
+  Allow selecting any item displayed and showing more information about it.
+
+Extras:
+  Create a separate directory to put extra (non-essential) programs and scripts.
+  * tagmodifier - a tagging rule testing program.
+  * errorlog - a script to summarise the planetsplitter error log.
+  * plot-time - a script to plot a graph of the planetsplitter execution time.
+  * find-fixme - search an OSM file for "fixme" tags and display them on a map.
+
+
+Note: This version is not compatible with databases from previous versions.
+
+
+Version 2.5.1 of Routino released : Sat Apr 20 2013
+---------------------------------------------------
+
+Bug fixes:
+  Stop contradictory log error messages about 'access=foot' etc.
+  Move the HTML charset definition to within the first 1024 bytes of file.
+  Don't prune short segments in some cases that would change routing.
+  Fix bug with pruning straight highways around loops.
+  Fix some bugs with installation documents and scripts.
+  Fix Javascript to work with OpenLayers v2.11 again.
+  Fix XML character quoting for special characters in 7-bit ASCII range.
+  Fix bug with parsing XML containing UTF-8 characters four bytes long.
+  Fix two bugs for simple routes with the option of not passing a super-node.
+
+planetsplitter:
+  Improve the pruning of straight highways (detect larger straight sections).
+
+Configuration Files:
+  Accept some more tag values for OSM file parsing.
+  Handle alternate forms of mini roundabouts (junction=roundabout).
+
+
+Note: This version is compatible with databases from version 2.4 / 2.4.1 / 2.5.
+
+
+Version 2.5 of Routino released : Sun Feb 9 2013
+------------------------------------------------
+
+General:
+  Replace 'motorbike' with 'motorcycle' everywhere.
+
+planetsplitter/tagmodifier:
+  Major changes to file reading:
+    Faster XML parser.
+    Reads PBF files natively (not for changes, not tagmodifier).
+    Reads o5m/o5c files natively (not tagmodifier).
+    Reads bzip2 or gzip compressed files natively (if compiled for them).
+    Data can no longer be read from standard input.
+
+planetsplitter:
+  Report errors with self-intersecting ways, clarify some other error messages.
+
+Configuration Files:
+  Tagging configuration can now use an <ifnot> rule.
+  The tagging configuration <if> and <ifnot> rules can be nested.
+  Change the way that the multilane property is derived from the lanes tag.
+  Accept some more tag values for OSM file parsing.
+  German translation now supports roundabouts.
+
+Documentation:
+  Describe numerical limits (OSM identifiers and maximum database size).
+
+Web pages:
+  Allow different data and tile attributions for each map source.
+  Include MapQuest as an optional tile source.
+
+Web pages (visualiser):
+  Allow plotting segments of highways that have a particular property.
+
+
+Note: Starting with this version the planetsplitter and tagmodifier programs
+      will no longer read data from standard input.
+
+Note: Existing mapprops.js files need to be updated for this version.
+
+Note: This version is compatible with databases from version 2.4 / 2.4.1.
+
+
+Version 2.4.1 of Routino released : Mon Dec 17 2012
+---------------------------------------------------
+
+Bug fixes:
+  Fix error with finding routes with low preference values (router).
+  Fix error when searching for default profiles.xml (router).
+  Fix bug with printing log messages when output is not stdout (tagmodifier).
+  Stop various crashes if trying to process file with no data (planetsplitter).
+
+
+Note: This version is compatible with databases from version 2.4.
+
+
+Version 2.4 of Routino released : Sat Dec 8 2012
+------------------------------------------------
+
+Bug fixes:
+  Fix pruning short segments in slim mode (gave different results to non-slim).
+  Fix error with segment lengths for some segments from ways that are areas.
+  Fix latent bug with route relations when compiled for 64-bit way/relation IDs.
+
+router/planetsplitter:
+  Replace all debugging "assert" statements with fatal error messages.
+
+planetsplitter:
+  Delete ways that are not used from the output files (names remain though).
+  Delete turn relations that are not used from the output files.
+  Speed up the processing, mainly by reducing the number of I/O operations.
+  Change the pruning of isolated regions to look at each transport type.
+  Slim and normal mode now give identical results (sorting preserves order).
+  Log some more error cases, clarify some existing ones.
+  Added a --append option which must be used to append files to existing data.
+  Added a --keep option which can be used to keep parsed, sorted data.
+  Added a --changes option to allow appending OSM change files (.osc files).
+
+Configuration Files:
+  Accept some more tag values for OSM file parsing.
+
+summarise-log.pl
+  Can now generate an HTML version with links to OSM information for each item.
+
+Deleted obsoleted files:
+  The CGI scripts customrouter.cgi and customvisualiser.cgi have been removed.
+  The noscript.cgi and noscript.html web pages have been removed.
+
+
+Note: Files deprecated in version 2.3 have been removed in version 2.4.
+
+Note: This version is not compatible with databases from previous versions.
+
+
+Version 2.3.2 of Routino released : Sat Oct 6 2012
+--------------------------------------------------
+
+Bug fixes:
+  Fix for highway type visualiser (was missing one-way segments).
+  Fix a real-life routing problem with oneway streets and super-segments.
+  Find a route even if an end waypoint forbids the specified transport.
+  Include the final junction in the HTML output (was missed in some cases).
+
+Test cases:
+  Create new test cases for two bugs fixed in this version.
+
+router:
+  Improve the error message for some cases of failing to route.
+
+planetsplitter:
+  Log an error if a foot/bicycle way doesn't allow foot/bicycle transport.
+  Do not mark nodes as super-nodes if they allow no transport types through.
+
+Web pages (visualiser):
+  Allow plotting nodes that block each transport type.
+
+Configuration Files:
+  Change the default license/copyright notice in the translations.xml file.
+
+
+Note: This version is compatible with databases from versions 2.2 or 2.3/2.3.1.
+
+
+Version 2.3.1 of Routino released : Sat Aug 11 2012
+---------------------------------------------------
+
+Bug fixes:
+  Create marker-XXX-grey.png icon which gets used before Javascript removes it.
+  Provide full set of 99 marker icons instead of just 19.
+  Add more limit icons (0.0-0.9, 20.0-40.0 and 161-200).
+  Fix router web page problem with placing initial marker (coords not updated).
+  Hide waypoints so that they are not visible when Javascript adds them to HTML.
+  Fix web page font problems by choosing an explicit font pixel-size in the CSS.
+  Fix potential crash in XML files containing lots of key/value pairs in a tag.
+
+Web pages (router):
+  Unused waypoints show as blank rather than 0,0.
+  Add a button to insert a waypoint to close the loop.
+  Write the command line and execution time to the log file.
+
+
+Note: This version is compatible with databases from versions 2.2 or 2.3.
+
+
+Version 2.3 of Routino released : Sat Jul 21 2012
+-------------------------------------------------
+
+Bug fixes:
+  Handle OSM files that contain changesets (don't raise an error).
+  Force bicyle/foot routes to allow bicycle/foot transport.
+  Fix problem running CGIs on Macs (md5 program name).
+  Fix bug with pruning straight highways (uninitialised data).
+  Fix bug with XML parsing error log (could miss some unrecognised tags).
+
+Web pages (all):
+  Make compatible with OpenLayers v2.12 (but don't change the install script).
+  Make all HTML files standards compliant.
+  Allow the HTML files to parse the query string instead of using a CGI.
+  Move all user-editable parameters to paths.pl and mapprops.js.
+
+Web pages (router):
+  Add a button to put a marker at the current location (Javascript geolocation).
+  Add a button to centre the map on a given marker.
+  Automatically insert the waypoints in the HTML from the JavaScript.
+  Added a German language router web page translation.
+  Add buttons to switch between lat/long and placename with Nominatim lookups.
+
+Web pages (visualiser):
+  Allow plotting segments of each highway type.
+  Allow plotting segments accessible to each transport type.
+
+planetsplitter:
+  Add a new '--logtime' option that prints the elapsed time of each step.
+  Make the sort functions multi-threaded (run-time option).
+  Improve the XML parsing speed slightly.
+
+
+Note: This version is compatible with databases from versions 2.2.
+
+Note: Existing mapprops.js and paths.pl files need to be updated to include new
+      items for this version.
+
+Note: Existing OpenLayers installations must be updated if they were installed
+      with older Routino provided script (the old OpenLayers.js will not work).
+
+Note: The CGI scripts customrouter.cgi and customvisualiser.cgi are deprecated
+      and will be removed in version 2.4
+
+Note: The noscript.cgi and noscript.html web pages are deprecated and will be
+      removed in version 2.4
+
+
+Version 2.2 of Routino released : Sat Mar 3 2012
+------------------------------------------------
+
+Bug fixes:
+  Fix some Makefile bugs.
+  Fix XML parsing (previously it allowed invalid XML comments).
+  Fix errors in HTML and GPX output files (highway names and bearings).
+  Fix errors in visualiser CGI related to oneway streets and in slim mode.
+  Ensure that no non-initialised memory is written to disk.
+
+OSM tagging:
+  Parse information about roundabouts and store it in the database.
+
+Documentation:
+  Update documentation to reflect changes in program usage and function.
+
+Web pages:
+  Change to OpenLayers v2.11.
+  Move the map preferences (ranges and URLs) to a separate file.
+  Prepare the visualiser.html web page for translation.
+  The customrouter script should now pick up the preferred language.
+
+planetsplitter:
+  When discarding duplicate segments prefer to discard those that are areas.
+  Ensure that XML file is OSM version 0.6 format.
+  Add a new option to prune nodes and/or segments (enabled by default)
+   - that form a small isolated sub-network.
+   - that are very short.
+   - that are not needed to represent a straight highway.
+
+router:
+  Change the format of the text file output (not the all points text file).
+  Output better HTML directions for roundabouts (e.g. take second exit).
+  Describe mini-roundabouts as "roundabout" rather than "junction".
+
+filedumper:
+  Ensure that all nodes needed for segments are included when dumping a region.
+  Include a bounding box when dumping a region.
+
+
+*** Important Note: The tagging.xml files from Routino v2.1.1 or earlier   ***
+*** contain invalid XML that will not be allowed by Routino v2.2 or later. ***
+
+Note: The format of the text file output has changed in this version.
+
+Note: This version is not compatible with databases from earlier versions.
+
+
+Version 2.1.2 of Routino released : Sat Nov 12 2011
+---------------------------------------------------
+
+Bug fixes:
+  Speed up the routing by a factor of 3 for slim mode by copying data to RAM.
+  Speed up routing & reduce memory use by a factor of 2.5 by stopping earlier.
+  Delete profiles.js and profiles.pl when cleaning up (make clean).
+  Improve output for translated versions (highway type names and text files).
+  Fix the summarise-log.pl script for segments which are loops.
+  Fix invalid XML syntax in tagging.xml file.
+
+Configuration Files:
+  Add extra tagging rules to handle problems found in the error log for UK.
+  Added Russian translations for output files.
+
+Documentation:
+  Improve the documentation for the tagging rule configuration file.
+
+
+Note: This version is compatible with databases from version 2.1 or 2.1.1.
+
+
+Version 2.1.1 of Routino released : Sun Oct 23 2011
+---------------------------------------------------
+
+Bug fixes:
+  Speed up the routing by a factor of 5 by improving data handling functions.
+  Speed up database generation by reducing the default number of iterations.
+  Fix the handling of the 'except' tag on turn restrictions.
+  Fix the 'make install' option for the XML files.
+  Add some more typecasts when printing data from filedumper program.
+  Make the CGI script more robust if shortest/fastest is not passed in.
+
+
+Note: This version is compatible with databases from version 2.1.
+
+
+Version 2.1 of Routino released : Mon Oct 3 2011
+------------------------------------------------
+
+Bug fixes:
+  Fix bug in pathological cases with binary search (don't crash).
+  Make stricter checks for closest nodes just like in v2.0.3 for segments.
+  Fix routing bug where start node is a super-node and finish is close by.
+
+OSM tagging:
+  More testing of turn relations; invalid or useless ones are discarded.
+  An error log file can be generated to record parsing and processing errors.
+
+Configuration Files:
+  Add new options in the tagging rules XML file.
+  Add extra tagging rules to handle many problems found in the error log for UK.
+  Create special-use tagging rule files for walking, riding and driving.
+
+Test cases:
+  Create new test case for bug fixed in v2.0.3.
+  Save expected results to allow future regressions to be found.
+
+
+Note: This version is not compatible with databases from earlier versions.
+
+
+Version 2.0.3 of Routino released : Thu Aug 4 2011
+--------------------------------------------------
+
+Bug fixes:
+  Handle start node being a super-node with no previous segment (don't crash).
+  Make stricter checks against the profile when finding the closest segment.
+  Find a valid route if the start and end point are the same location.
+  Choose the better route if one with and one without super-nodes are available.
+
+
+Note: This version is compatible with databases from versions 2.0, 2.0.x.
+
+
+Version 2.0.2 of Routino released : Sun June 26 2011
+----------------------------------------------------
+
+Bug fixes:
+  Fix error with handling ferry routes (were ignored).
+  Force roundabouts to be one-way (was present in v1.5.1).
+  Handle super-nodes with no segments when processing (don't crash).
+
+Code improvements:
+  Use C99 standard by default and fix related warnings.
+  More code tidy-up for 32/64 bit node and index types.
+  Free some memory in various places (not serious leaks).
+
+
+Note: This version is compatible with databases from versions 2.0, 2.0.1.
+
+
+Version 2.0.1 of Routino released : Tue June 7 2011
+---------------------------------------------------
+
+Bug fixes:
+  Turn relations that specify missing nodes/ways are deleted (don't crash).
+  Shorten the messages printed by planetsplitter to keep below 80 characters.
+
+Code improvements:
+  Various code tidy-ups and 32/64 bit node and index improvements.
+
+OSM Tagging:
+  Check whether node/way/relation IDs fit in 32-bits (code ready for 64-bits).
+
+
+Note: This version is compatible with databases from version 2.0.
+
+
+Version 2.0 of Routino released : Mon May 30 2011
+-------------------------------------------------
+
+Bug fixes:
+  Fix mis-spelling with surface=asphalt tag
+  Routes between two waypoints on the same segment now work.
+  Fix reading of numeric entities from XML files (store as UTF-8 internally).
+  Fix turn description in HTML file (angles were biased to the right).
+  Fix possibility of occasionally missing turn information from output files.
+
+Test cases:
+  Added test cases for routing in slim and non-slim modes.
+
+Documentation:
+  Update documentation to reflect changes in program usage and function.
+  Install the license file in the documentation directory.
+
+OSM tagging:
+  Process the tags associated with turn restriction relations.
+  Remove the roundabout type from the parsing.
+  Add parsing of mini-roundabouts.
+
+Configuration Files:
+  Update profiles with new options related to turn restrictions.
+
+Web pages:
+  Change to OpenLayers v2.10.
+  Visualiser can display turn restrictions.
+  Put the profile information into separate files and auto-generate them.
+
+planetsplitter:
+  Store information about turn restriction relations.
+  Quite a large code re-organisation - now faster and uses less memory.
+
+router:
+  Take turn restriction relations into account when routing.
+  Continue same direction of travel at each waypoint (unless dead-end).
+  Add a new option to specify an initial direction to start travel.
+
+filedumper:
+  Print out statistics about what highways are included in the database.
+
+
+Version 1.5.1 of Routino released : Sat Nov 13 2010
+---------------------------------------------------
+
+Bug fixes:
+  Ensure that enough memory is allocated for filenames.
+  Fix bug that sometimes causes crash when processing route relations.
+
+Documentation:
+  Update documentation to reflect changes in program usage and function.
+
+Programs:
+  Add an option to make the output more suitable for a log file.
+
+Documentation:
+  Update documentation to reflect changes in program usage.
+
+
+Version 1.5 of Routino released : Sat Oct 30 2010
+-------------------------------------------------
+
+Bug fixes:
+  Check that number of nodes/segments/ways doesn't exceed numerical limits.
+  Allow 32-bit systems to seek within files larger than 4GB.
+  Allow nearly 4G nodes to be stored instead of 2G before.
+  Added rules to makefile for installation (paths specified in top-level).
+  Stricter checking of UTF-8 in XML files and better UTF-8 output.
+  Improve error message if parsing of command line options fail.
+  Fix bugs in router's --help-profile-json and --help-profile-perl options.
+  Rename heapsort function to allow compilation on Mac OS with no change.
+  Reduce impact of property preferences close to 50% by using sqrt().
+
+Documentation:
+  Update documentation to reflect changes in program usage and function.
+
+OSM tagging:
+  Traffic restrictions on nodes are now included in default tagging file.
+  Added processing for ferry routes (as pseudo-highway type 'ferry').
+  Process foot and bicycle route relations to create new properties.
+
+Configuration Files:
+  Added Dutch output translations.
+  Added ferry information to profiles.
+  Added foot and bicycle route relation processing.
+
+planetsplitter:
+  The slim mode now includes the output data as well as the temporary data.
+  The slim mode is now a separate executable and not a command line option.
+  Traffic restrictions on nodes are now understood when parsing OSM files.
+  Falls back to installed tagging.xml configuration file as last resort.
+
+router:
+  Added a slim mode (as a separate executable and not a command line option).
+  Traffic will not be routed through a node that does not allow it.
+  Falls back to installed profiles.xml & translations.xml files as last resort.
+
+filedumper:
+  Added a slim mode (as a separate executable and not a command line option).
+
+Web pages:
+  Added Dutch translation of router.html.
+
+
+Version 1.4.1 of Routino released : Sat Jul 10 2010
+---------------------------------------------------
+
+Bug fixes:
+  Don't crash if start and finish are the same point.
+  Don't crash if several translations but --language option not used.
+  Don't crash if middle part of route cannot be found.
+  Don't allocate so much memory for intermediate nodes; routes much faster.
+  Fix problem with finding closest segment to the specified point.
+
+Documentation:
+  Provide HTML versions of the documentation (copy to web directory at install).
+  Change URL for website to http://www.routino.org/.
+
+Configuration Files:
+  Added German output translations.
+
+planetsplitter
+  Slight change to algorithm for finding super-nodes.
+
+Web pages:
+  Provide HTML versions of the documentation.
+  Change URL for website to http://www.routino.org/.
+  Provide updated HTML files, the same as on the website.
+  Change to OpenLayers v2.9.1 and build custom version if Python available.
+
+
+Version 1.4 of Routino released : Mon May 31 2010
+-------------------------------------------------
+
+Bug fixes:
+  Speed up start/via/stop point within segment search algorithm.
+  If no segment is found don't try routing but exit with error.
+  Improve the error messages by adding operating system error info to them.
+  Rewrite of tagging rules fixes bug with wheelchair access allow/deny.
+  Files greater than 2GB can be read/written on 32-bit systems.
+  Fix bug with profile preferences when optimising a route.
+  Stricter check on profile validity before starting routing.
+
+planetsplitter:
+  Add --parse-only and --process-only options (for incremental parsing).
+  Allow filenames to be specified on command line (default is still stdin).
+  Improved the '--help' information to describe all options.
+  Remove --transport, --not-highway, --not-property options (use config file).
+  Use tag transformation rules in configuration file not hard-coded.
+
+router:
+  Removed compiled-in profiles and use profiles loaded from XML file.
+  Improved the '--help' information to describe all options.
+  Change the name of the --profile-json and --profile-perl options.
+  Allow selection of the outputs to generate (or none).
+  Added HTML route instructions output.
+  GPX route file contains instructions at each waypoint.
+  Read in XML file of translated words/phrases for outputs.
+  Added options to specify file of translations and language to use.
+  Remove copyright.txt file and put information into translations file.
+
+filedumper:
+  Improved the '--help' information to describe all options.
+  Added the option to dump an OSM file containing database contents.
+
+Web Pages:
+  Combined generic map CSS into one file (not copied in two).
+  Much better support for IE6/7/8 with browser detection but not perfect.
+  Re-organised and tidied up the Javascript.
+  Added button next to waypoints to centre it on map.
+  Added button next to waypoints to set as home location (uses browsser cookie).
+  Create shorter URLs for custom map (ignore default values).
+  Reduced and clarified the amount of editing to customise the Javascript.
+  Made it easier to translate by moving text out of Javascript (not visualiser).
+  Prepared for translated versions of web page (Apache Multiviews).
+  Added option to select language of output.
+  Use HTML output from router to get translated instructions.
+
+
+Version 1.3 of Routino released : Thu Jan 21 2010
+-------------------------------------------------
+
+Bug fixes:
+  Ensure output even if the distance between two adjacent route points is small.
+  Correct the determination of waypoints for abbreviated output.
+  Check the command line values for filedumper --dump options.
+  Made the verbose output consistent between different places.
+
+OSM tagging:
+  Recognise "designation" tag to determine designated paths.
+  Recognise "steps" tag to determine the highway type.
+  Recognise "wheelchair" tag to determine if wheelchairs are allowed on highway.
+  Recognise "moped" tag to determine if mopeds are allowed on a highway.
+  Recognise "surface" and "paved" tags to determine if a highway is paved.
+  Recognise "lanes" tag to determine if a highway has multiple lanes.
+  Recognise "bridge" tag to determine if a highway is a bridge.
+  Recognise "tunnel" tag to determine if a highway is a tunnel.
+
+New Features:
+  Remove "bridleway" and "footway" highway types and use "path" highway instead.
+  Added "steps" as a new highway type separate from the "path" type.
+  Added "wheelchair" and "moped" to the list of possible transports.
+  Added "paved", "multilane", "bridge", "tunnel" to list of highway properties.
+
+Web Pages:
+  Updated for new features listed above.
+  Added popup to display instructions for each step in route on mouse-over.
+  Added buttons next to waypoints for: add / remove / move up / move down.
+  Highlight user selectable parts of form in yellow on mouse-over.
+  A few small changes, improved CSS, improved Javascript.
+
+router:
+  For each waypoint choose closest point on a segment and not just closest node.
+  Added the ability to set preferences based on highway properties.
+  Changed the text output formats to include bearing and turn information.
+
+
+Version 1.2 of Routino released : Wed Oct 21 2009
+-------------------------------------------------
+
+OSM tagging:
+  Recognise tags "vehicle" and "motor_vehicle".
+  Handle duplicate ways in the input OSM file (e.g. concatenation of 2 files).
+
+Database:
+  Identical ways are combined to reduce database size (~80% fewer ways stored).
+
+Routing:
+  Fix weight, height, width, length restriction routing.
+  Allow up to 99 waypoints to be specified instead of 9.
+
+Visualiser:
+  Don't display speed limits for tracks and paths unless a value is set.
+  Draw all super-segments that cross the selected boundary.
+
+Web Pages:
+  A few small changes, improved CSS, improved Javascript.
+  Changed marker colour when waypoint not selected.
+
+planetsplitter:
+  Optional slim mode uses minimal memory at the expense of temporary files.
+
+router:
+  Less CPU time for routing (~30% less).
+
+filedumper:
+  Allow dumping individual nodes, segments and ways (for debug).
+
+
+Version 1.1 of Routino released : Sat Jun 13 2009
+-------------------------------------------------
+
+Inputs:
+  Improve parsing of OSM file (imperial units).
+  Ignore nodes that are missing from the input OSM file.
+
+Outputs:
+  Create GPX route files as well as GPX track files.
+  Read in an optional copyright.txt file and include contents in output.
+  Make better choices about what to output in the abbreviated text file.
+
+Routing:
+  Allow generating a route with intermediate waypoints.
+  Use preferences for highway types instead of yes/no choice.
+  Choice of closest node to start/finish points ensures transport allowed.
+
+Visualiser:
+  Added data extraction function for viewing routing database data.
+
+Web Pages:
+  Include full set of web pages for creating customised online router.
+
+Documentation:
+  Included NEWS.txt file.
+  Included documentation for installation of web pages.
+
+
+Version 1.0 of Routino released : Wed Apr 08 2009
+-------------------------------------------------
+
+First version.
diff --git a/3rdparty/Routino/doc/OUTPUT.txt b/3rdparty/Routino/doc/OUTPUT.txt
new file mode 100644
index 0000000..497192a
--- /dev/null
+++ b/3rdparty/Routino/doc/OUTPUT.txt
@@ -0,0 +1,293 @@
+                              Routino : Output
+                              ================
+
+
+   There are three different formats of output from the router, HTML, GPX
+   (GPS eXchange) XML format and plain text with a total of five possible
+   output files:
+     * HTML route instructions for each interesting junction.
+     * GPX track file containing every node.
+     * GPX route file with waypoints at interesting junctions.
+     * Plain text description with the interesting junctions.
+     * Plain text file with every node.
+
+   The "interesting junctions" referred to above are junctions where the
+   route changes to a different type of highway, more than two highways of
+   the same type meet, or where the route meets but does not take a more
+   major highway. When the route follows a major road this definition
+   eliminates all junctions with minor roads.
+
+   The output files are written to the current directory and are named
+   depending on the selection of shortest or quickest route. For the
+   shortest route the file names are "shortest.html",
+   "shortest-track.gpx", "shortest-route.gpx", "shortest.txt" and
+   "shortest-all.txt", for the quickest route the names are
+   "quickest.html", "quickest-track.gpx", "quickest-route.gpx",
+   "quickest.txt" and "quickest-all.txt".
+
+   The HTML file and GPX files are written out according to the selected
+   language using the translations contained in the translations.xml
+   configuration file. The text files contains untranslated header lines
+   (in English) but the data is translated.
+
+
+HTML Route Instructions
+-----------------------
+
+   The HTML route instructions file contains one line for the description
+   of each of the interesting junctions in the route and one line for each
+   of the highways that connect them. The coordinates are also included in
+   the file but are not visible because of the style definitions.
+
+   An example HTML file output is below (some parts are missing, for
+   example the style definitions):
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<!-- Creator : Routino - http://www.routino.org/ -->
+<!-- Source : Based on OpenStreetMap data from http://www.openstreetmap.org/ -->
+<!-- License : http://www.openstreetmap.org/copyright -->
+<HEAD>
+<TITLE>Shortest Route</TITLE>
+...
+</HEAD>
+<BODY>
+<H1>Shortest Route</H1>
+<table>
+<tr class='c'><td class='l'>1:<td class='r'>51.524658 -0.127877
+<tr class='n'><td class='l'>Start:<td class='r'>At <span class='w'>Waypoint</span>, head <span class='b'>South-East</span>
+<tr class='s'><td class='l'>Follow:<td class='r'><span class='h'>Woburn Place (A4200)</span> for <span class='d'>0.251 km, 0.3 min</span> [<span class='j'>0.3 km, 0 minutes</span>]
+<tr class='c'><td class='l'>2:<td class='r'>51.522811 -0.125781
+<tr class='n'><td class='l'>At:<td class='r'>Junction, go <span class='t'>Straight on</span> heading <span class='b'>South-East</span>
+<tr class='s'><td class='l'>Follow:<td class='r'><span class='h'>Russell Square (A4200)</span> for <span class='d'>0.186 km, 0.2 min</span> [<span class='j'>0.4 km, 1 minutes</span>]
+<tr class='c'><td class='l'>3:<td class='r'>51.521482 -0.124123
+<tr class='n'><td class='l'>At:<td class='r'>Junction, go <span class='t'>Straig
+ht on</span> heading <span class='b'>South-East</span>
+<tr class='s'><td class='l'>Follow:<td class='r'><span class='h'>Southampton Row
+ (A4200)</span> for <span class='d'>0.351 km, 0.4 min</span> [<span class='j'>0.
+8 km, 1 minutes</span>]
+...
+<tr class='c'><td class='l'>21:<td class='r'>51.477678 -0.106792
+<tr class='n'><td class='l'>At:<td class='r'>Junction, go <span class='t'>Slight left</span> heading <span class='b'>South-East</span>
+<tr class='s'><td class='l'>Follow:<td class='r'><span class='h'>Vassall Road</span> for <span class='d'>0.138 km, 0.2 min</span> [<span class='j'>6.3 km, 6 minutes</span>]
+<tr class='c'><td class='l'>22:<td class='r'>51.478015 -0.104870
+<tr class='n'><td class='l'>At:<td class='r'>Junction, go <span class='t'>Straight on</span> heading <span class='b'>East</span>
+<tr class='s'><td class='l'>Follow:<td class='r'><span class='h'>Vassall Road</span> for <span class='d'>0.087 km, 0.1 min</span> [<span class='j'>6.4 km, 6 minutes</span>]
+<tr class='c'><td class='l'>23:<td class='r'>51.478244 -0.103651
+<tr class='n'><td class='l'>Stop:<td class='r'>At <span class='w'>Waypoint</span>
+<tr class='t'><td class='l'>Total:<td class='r'><span class='j'>6.4 km, 6 minutes</span>
+</table>
+</BODY>
+</HTML>
+
+
+GPX Track File
+--------------
+
+   The GPX track file contains a track with all of the individual nodes
+   that the route passes through.
+
+   An example GPX track file output is below:
+
+<?xml version="1.0" encoding="UTF-8"?>
+<gpx version="1.1" creator="Routino" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                                     xmlns="http://www.topografix.com/GPX/1/1"
+                                     xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
+<metadata>
+<desc>Creator : Routino - http://www.routino.org/</desc>
+<copyright author="Based on OpenStreetMap data from http://www.openstreetmap.org/">
+<license>http://www.openstreetmap.org/copyright</license>
+</copyright>
+</metadata>
+<trk>
+<name>Shortest route</name>
+<desc>Shortest route between 'start' and 'finish' waypoints</desc>
+<trkpt lat="51.524658" lon="-0.127877"/>
+<trkpt lat="51.523768" lon="-0.126918"/>
+<trkpt lat="51.522811" lon="-0.125781"/>
+...
+<trkpt lat="51.478015" lon="-0.104870"/>
+<trkpt lat="51.478127" lon="-0.104174"/>
+<trkpt lat="51.478244" lon="-0.103651"/>
+</trkseg>
+</trk>
+</gpx>
+
+
+GPX Route File
+--------------
+
+   The GPX route file contains a route (ordered set of waypoints) with all
+   of the interesting junctions that the route passes through and a
+   description of the route to take from that point.
+
+   An example GPX route file output is below:
+
+<?xml version="1.0" encoding="UTF-8"?>
+<gpx version="1.1" creator="Routino" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                                     xmlns="http://www.topografix.com/GPX/1/1"
+                                     xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
+<metadata>
+<desc>Creator : Routino - http://www.routino.org/</desc>
+<copyright author="Based on OpenStreetMap data from http://www.openstreetmap.org/">
+<license>http://www.openstreetmap.org/copyright</license>
+</copyright>
+</metadata>
+<rte>
+<name>Shortest route</name>
+<desc>Shortest route between 'start' and 'finish' waypoints</desc>
+<rtept lat="51.524658" lon="-0.127877">
+  <name>START</name>
+  <desc>South-East on 'Woburn Place (A4200)' for 0.251 km, 0.3 min</desc>
+</rtept>
+<rtept lat="51.522811" lon="-0.125781">
+  <name>TRIP001</name>
+  <desc>South-East on 'Russell Square (A4200)' for 0.186 km, 0.2 min</desc>
+</rtept>
+<rtept lat="51.521482" lon="-0.124123">
+  <name>TRIP002</name>
+  <desc>South-East on 'Southampton Row (A4200)' for 0.351 km, 0.4 min</desc>
+</rtept>
+...
+<rtept lat="51.477678" lon="-0.106792">
+  <name>TRIP020</name>
+  <desc>South-East on 'Vassall Road' for 0.138 km, 0.2 min</desc>
+</rtept>
+<rtept lat="51.478015" lon="-0.104870">
+  <name>TRIP021</name>
+  <desc>East on 'Vassall Road' for 0.087 km, 0.1 min</desc>
+</rtept>
+<rtept lat="51.478244" lon="-0.103651">
+  <name>FINISH</name>
+  <desc>Total Journey 6.4 km, 6 minutes</desc>
+</rtept>
+</rte>
+</gpx>
+
+
+Text File
+---------
+
+   The text file format contains one entry for all of the interesting
+   junctions in the route and is intended to be easy to interpret, for
+   example for creating other output formats.
+
+   An example text file output is below:
+
+# Creator : Routino - http://www.routino.org/
+# Source : Based on OpenStreetMap data from http://www.openstreetmap.org/
+# License : http://www.openstreetmap.org/copyright
+#
+#Latitude   Longitude  Section   Section  Total    Total    Point Turn Bearing Highway
+#                      Distance  Duration Distance Duration Type
+ 51.524658  -0.127877  0.000 km  0.0 min  0.0 km   0 min    Waypt  +3          Woburn Place (A4200)
+ 51.522811  -0.125781  0.251 km  0.3 min  0.3 km   0 min    Junct  +0  +3      Russell Square (A4200)
+ 51.521482  -0.124123  0.186 km  0.2 min  0.4 km   1 min    Junct  +0  +3      Southampton Row (A4200)
+...
+ 51.477678  -0.106792  0.204 km  0.2 min  6.1 km   5 min    Junct  +0  +3      Vassall Road
+ 51.478015  -0.104870  0.138 km  0.2 min  6.3 km   6 min    Junct  +0  +2      Vassall Road
+ 51.478244  -0.103651  0.087 km  0.1 min  6.4 km   6 min    Waypt
+
+   The text file output contains a header (indicated by the lines starting
+   with '#') and then one line for each waypoint or junction. Each line
+   contains the information for the current node and the next segment to
+   be followed. For each of the lines the individual fields contain the
+   following:
+
+   Latitude - Location of the node (degrees)
+
+   Longitude - Location of the node (degrees)
+
+   Section Distance - The distance travelled on the section of the journey
+   that ends at this node.
+
+   Section Duration - The duration of travel on the section of the journey
+   that ends at this node.
+
+   Total Distance - The total distance travelled up to this point.
+
+   Total Duration - The total duration of travel up to this point.
+
+   Point Type - The type of point; either a waypoint Waypt or junction
+   Junct.
+
+   Turn - The direction to turn at this point (missing for the first line
+   since the journey has not started yet and for the last line because it
+   has finished). This can take one of nine values between -4 and +4
+   defined by: 0 = Straight, +2 = Right, -2 = Left and +/-4 = Reverse.
+
+   Bearing - The direction to head from this point (missing for the last
+   line since the journey has finished). This can take one of nine values
+   between -4 and +4 defined by: 0 = North, +2 = East, -2 = West and +/-4
+   = South.
+
+   Highway - The name (or description) of the highway to follow from this
+   point (missing on the last line since the journey has finished).
+
+   The individual items are separated by tabs but some of the items
+   contain spaces as well.
+
+
+All Nodes Text File
+-------------------
+
+   The all nodes text file format contains one entry for each of the nodes
+   on the route.
+
+   An example all nodes text file output is below:
+
+# Creator : Routino - http://www.routino.org/
+# Source : Based on OpenStreetMap data from http://www.openstreetmap.org/
+# License : http://www.openstreetmap.org/copyright
+#
+#Latitude   Longitude  Node      Type   Segment Segment Total Total   Speed Bearing Highway
+#                                       Dist    Durat'n Dist  Durat'n
+ 51.524658  -0.127877  8439703*  Waypt   0.000  0.00    0.00   0.0
+ 51.523768  -0.126918  8439948*  Junct-  0.119  0.15    0.12   0.1     96    146    Woburn Place (A4200)
+ 51.522811  -0.125781  8440207*  Junct   0.132  0.17    0.25   0.3     96    143    Woburn Place (A4200)
+...
+ 51.478015  -0.104870  8529638*  Change  0.138  0.17    6.26   5.6     48     74    Vassall Road
+ 51.478127  -0.104174  8529849*  Junct-  0.049  0.04    6.31   5.7     64     75    Vassall Road
+ 51.478244  -0.103651  8530008   Waypt   0.038  0.04    6.35   5.7     64     70    Vassall Road
+
+   The all nodes text file output contains a header (indicated by the
+   lines starting with '#') and then one line for each node and the
+   segment that was used to reach it. This file therefore contains exactly
+   the same model as is used internally to define a route (a series of
+   results each of which is a node and the segment leading to it). For
+   each of the lines the individual fields contain the following:
+
+   Latitude - Location of the node in degrees.
+
+   Longitude - Location of the node in degrees.
+
+   Node - The internal node number and an indicator "*" if the node is a
+   super-node.
+
+   Type - The type of point; a waypoint Waypt, important junction Junct,
+   unimportant junction Junct-, change of highway Change or intermediate node
+   Inter.
+
+   Segment Distance - The distance travelled on the segment defined on this
+   line.
+
+   Segment Duration - The duration of travel on the segment defined on this
+   line.
+
+   Total Distance - The total distance travelled up to this point.
+
+   Total Duration - The total duration of travel up to this point.
+
+   Speed - The speed of travel on the segment defined on this line (missing
+   on the first line).
+
+   Bearing - The direction that the segment defined on this line travels in
+   degrees (missing on the first line).
+
+   Highway - The name (or description) of the highway segment (missing on
+   the first line).
+
+
+--------
+
+Copyright 2008-2011 Andrew M. Bishop.
diff --git a/3rdparty/Routino/doc/README.txt b/3rdparty/Routino/doc/README.txt
new file mode 100644
index 0000000..c401e49
--- /dev/null
+++ b/3rdparty/Routino/doc/README.txt
@@ -0,0 +1,188 @@
+                  Routino : OpenStreetMap Routing Software
+                  ========================================
+
+
+   Routino is an application for finding a route between two points using
+   the dataset of topographical information collected by
+   http://www.OpenStreetMap.org.
+
+   Starting from the raw OpenStreetMap data (in the form of the '.osm' XML
+   files available on the internet) a custom database is generated that
+   contains the information useful for routing. With this database and two
+   points specified by latitude and longitude an optimum route (either
+   shortest or quickest) is determined. The route is calculated for
+   OpenStreetMap highways (roads, paths etc) using one of the common forms
+   of transport defined in OpenStreetMap (foot, bicycle, horse, motorcar,
+   motorcycle etc).
+
+   When processing the OpenStreetMap data the types of highways are
+   recorded and these set default limits on the types of traffic allowed.
+   More specific information about permissions for different types of
+   transport are also recorded as are maximum speed limits. Further
+   restrictions like one-way streets, weight, height, width and length
+   limits are also included where specified. Additionally a set of
+   properties of each highway are also recorded. The processing of the
+   input file is controlled by a configuration file which determines the
+   information that is used.
+
+   When calculating a route the type of transport to be used is taken into
+   account to ensure that the known restrictions are followed. Each of the
+   different highway types can further be allowed or disallowed depending
+   on preferences. For each type of highway a default speed limit is
+   defined (although the actual speed used will be the lowest of the
+   default and any specified in the original data). To make use of the
+   information about restrictions the weight, height, width and length of
+   the transport can also be specified. Further preferences about road
+   properties (e.g. paved or not) can also be selected. The simplest type
+   of turn restrictions (those formed from an initial way, a node and a
+   second way) are also obeyed.
+
+   The result of calculating the route can be presented in several
+   different ways. An HTML file can be produced that contains a
+   description of the route to take with instructions for each of the
+   important junctions. The contents of the file are created based on a
+   set of translations specified in a configuration file. The route is
+   also available in a GPX (GPS eXchange) XML format. format file
+   containing either every point and highway segment (a track file) or
+   just a waypoint and translated instructions for the important junctions
+   (a route file). Additionally there are two plain text files that
+   contain all data points or just the important ones (intended for
+   debugging and further processing).
+
+   One of the design aims of Routino was to make the software are flexible
+   as possible in selecting routing preferences but also have a sensible
+   set of default values. Another design aim was that finding the optimum
+   route should be very fast and most of the speed increases come from the
+   carefully chosen and optimised data format.
+
+
+Disclaimer
+----------
+
+   The route that is calculated by this software is only as good as the
+   input data.
+
+   Routino comes with ABSOLUTELY NO WARRANTY for the software itself or
+   the route that is calculated by it.
+
+
+Demonstration
+-------------
+
+   A live demonstration of the router for the UK is available on the
+   internet in both OpenLayers and Leaflet versions:
+
+   http://www.routino.org/uk-leaflet/
+   http://www.routino.org/uk-openlayers/
+
+   The source code download available below also includes a set of files
+   that can be used to create your own interactive map.
+
+   The interactive map is made possible by use of the OpenLayers or
+   Leaflet Javascript library from http://www.openlayers.org/ or
+   http://leafletjs.com/.
+
+
+Documentation
+-------------
+
+   The algorithm used is described in the file ALGORITHM.txt with some notes
+   about the input data in DATA.txt and numerical limitations in LIMITS.txt.
+
+   The configuration files and in particular the default set of rules for
+   processing the OpenStreetMap data tags are described in detail in
+   CONFIGURATION.txt and TAGGING.txt.  The format of the output files
+   generated are described in OUTPUT.txt.
+
+   Detailed information about how to use the programs is available in the
+   file USAGE.txt and how to install it is in INSTALL.txt.
+
+
+Status
+------
+
+   Version 1.0 of Routino was released on 8th April 2009.
+   Version 1.1 of Routino was released on 13th June 2009.
+   Version 1.2 of Routino was released on 21st October 2009.
+   Version 1.3 of Routino was released on 21st January 2010.
+   Version 1.4 of Routino was released on 31st May 2010.
+   Version 1.4.1 of Routino was released on 10th July 2010.
+   Version 1.5 of Routino was released on 30th October 2010.
+   Version 1.5.1 of Routino was released on 13th November 2010.
+   Version 2.0 of Routino was released on 30th May 2011.
+   Version 2.0.1 of Routino was released on 7th June 2011.
+   Version 2.0.2 of Routino was released on 26th June 2011.
+   Version 2.0.3 of Routino was released on 4th August 2011.
+   Version 2.1 of Routino was released on 3rd October 2011.
+   Version 2.1.1 of Routino was released on 23rd October 2011.
+   Version 2.1.2 of Routino was released on 12th November 2011.
+   Version 2.2 of Routino was released on 3rd March 2012.
+   Version 2.3 of Routino was released on 21st July 2012.
+   Version 2.3.1 of Routino was released on 11th August 2012.
+   Version 2.3.2 of Routino was released on 6th October 2012.
+   Version 2.4 of Routino was released on 8th December 2012.
+   Version 2.4.1 of Routino was released on 17th December 2012.
+   Version 2.5 of Routino was released on 9th February 2013.
+   Version 2.5.1 of Routino was released on 20th April 2013.
+   Version 2.6 of Routino was released on 6th July 2013.
+   Version 2.7 of Routino was released on 22nd March 2014.
+   Version 2.7.1 of Routino was released on 17th May 2014.
+   Version 2.7.2 of Routino was released on 26th June 2014.
+   Version 2.7.3 of Routino was released on 8th November 2014.
+
+   The full version history is available in the NEWS.txt file.
+
+
+License
+-------
+
+   This program is free software: you can redistribute it and/or modify it
+   under the terms of the GNU Affero General Public License as published
+   by the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   It is important to note that for this program I have decided to use the
+   Affero GPLv3 instead of just using the GPL. This license adds
+   additional requirements to anybody who provides a networked service
+   using this software.
+
+
+Copyright
+---------
+
+   Routino is copyright Andrew M. Bishop 2008-2014.
+
+
+Homepage
+--------
+
+   The Routino homepage has the latest news about the program:
+
+   http://www.routino.org/
+
+
+Download
+--------
+
+   The program can be downloaded from:
+
+   http://www.routino.org/download/
+
+Subversion
+- - - - -
+
+   The source code can also be downloaded from the Subversion repository
+   with a command like the following:
+
+   svn co http://routino.org/svn/trunk routino
+
+   The source code can also be browsed in the Subversion viewer which also
+   has a list of the latest changes:
+
+   http://www.routino.org/viewvc/trunk/
+   http://www.routino.org/viewvc/trunk/?view=log
+
+
+--------
+
+Copyright 2008-2014 Andrew M. Bishop.
diff --git a/3rdparty/Routino/doc/TAGGING.txt b/3rdparty/Routino/doc/TAGGING.txt
new file mode 100644
index 0000000..dd53f91
--- /dev/null
+++ b/3rdparty/Routino/doc/TAGGING.txt
@@ -0,0 +1,556 @@
+                           Routino : Tagging Rules
+                           =======================
+
+
+   The different tags and attributes in the OSM format XML that are used
+   by Routino are described below.
+
+   Routino handles the tags in the input file after they have been
+   processed according to a set of rules defined in a configuration file.
+   The first half of this file describes the tags that are recognised by
+   Routino after being processed; the second half of the file describes
+   the transformations that are in the default tagging configuration file.
+
+
+Tags Recognised After Processing
+--------------------------------
+
+   This section describes the tags that are recognised by Routino after
+   the tag transformations have been applied. This is therefore a much
+   reduced set of tags compared to the original OSM data and also includes
+   tags which are specific to Routino.
+
+   In all cases of tag processing values of true, yes, 1 are recognised as
+   being affirmative and any other value is negative.
+
+
+Node Tags And Attributes
+------------------------
+
+   The node attributes id, latitude and longitude are used. The id
+   attribute is required to associate the node with the ways and the
+   position attributes are required to locate the node.
+
+Transport Specific Tags
+- - - - - - - - - - - -
+
+   One tag is recognised for each of the different modes of transport:
+   foot, horse, bicycle, wheelchair, moped, motorcycle, motorcar, goods,
+   hgv and psv. These indicate whether the specific type of transport is
+   allowed to pass through the node or not.
+
+   By default for nodes all types of transport are allowed to pass through
+   a node and specific tags must be used to remove the permissions for the
+   transport.
+
+The roundabout Tag
+- - - - - - - - -
+
+   The roundabout tag for mini-roundabouts is recognised and used to
+   improve the description of the route.
+
+
+Way Tags And Attributes
+-----------------------
+
+   The tags from the ways in the data are the ones that provide most of
+   the information for routing. The id attribute is used only so that the
+   many segments associated with a way can share a set of tags taken from
+   the way. The nd information is used to identify the nodes that make up
+   the way.
+
+The highway Tag
+- - - - - - - -
+
+   The most important tag that is used from a way is the highway tag. This
+   defines the type of highway that the way represents. Any way that does
+   not have a highway tag is discarded.
+
+   There are more highway types defined than are used by the router. The
+   subset that the router uses are:
+     * motorway
+     * trunk
+     * primary
+     * secondary
+     * tertiary
+     * unclassified
+     * residential
+     * service
+     * track
+     * cycleway
+     * path (1)
+     * steps (2)
+
+   Note 1: This changed in version 1.3 of Routino - the bridleway and
+   footway types were included within the path highway type.
+   Note 2: This changed in version 1.3 of Routino - the steps type was
+   separated from the footway type.
+
+Transport Specific Tags
+- - - - - - - - - - - -
+
+   One tag is recognised for each of the different modes of transport:
+   foot, horse, bicycle, wheelchair, moped, motorcycle, motorcar, goods,
+   hgv and psv. These indicate whether the specific type of transport is
+   allowed on the highway or not.
+
+   By default for ways no types of transport are allowed to pass along a
+   highway and specific tags must be used to add the permissions for the
+   transport.
+
+The name Tag
+- - - - - -
+
+   The name tag is used to provide the label for the highway when printing
+   the results.
+
+The ref Tag
+- - - - - -
+
+   The ref tag is used to provide the label for the highway when printing
+   the results.
+
+The lanes Tag
+- - - - - - -
+
+   The lanes tag is used to identify whether a highway has multiple lanes
+   for traffic and this is used to derive the multilane highway
+   properties.
+
+The paved Tag
+- - - - - - -
+
+   The paved tag is used to identify whether a highway is paved or not,
+   this is one of the available highway properties. A paved tag may exist
+   in the original data but normally the surface tag needs to be
+   transformed into the paved tag.
+
+The multilane Tag
+- - - - - - - - -
+
+   The multilane tag is used to indicate that a highway has multiple lanes
+   for traffic.
+
+The bridge Tag
+- - - - - - -
+
+   The bridge tag is used to identify whether a highway is a bridge and
+   therefore set one of the available properties.
+
+The tunnel Tag
+- - - - - - -
+
+   The tunnel tag is used to identify whether a highway is a tunnel and
+   therefore set one of the available properties.
+
+The footroute Tag
+- - - - - - - - -
+
+   The footroute tag is used to identify whether a highway is part of a
+   walking route and therefore set one of the available properties. This
+   is not a standard OSM tag and is normally added to the individual
+   highways by looking for route relations that are designated for foot
+   access.
+
+The bicycleroute Tag
+- - - - - - - - - -
+
+   The bicycleroute tag is used to identify whether a highway is part of a
+   bicycle route and therefore set one of the available properties. This
+   is not a standard OSM tag and is normally added to the individual
+   highways by looking for route relations that are designated for bicycle
+   access.
+
+The cyclebothways Tag
+- - - - - - - - - - -
+
+   The cyclebothways tag is used to identify whether a highway allows
+   cycling in the opposite direction to a signposted oneway restriction.
+
+The oneway Tag
+- - - - - - -
+
+   The oneway tag is used to specify that traffic is only allowed to
+   travel in one direction.
+
+The roundabout Tag
+- - - - - - - - -
+
+   The roundabout tag is used to specify that a highway is part of a
+   roundabout to improve the description of the calculated route.
+
+The maxspeed Tag
+- - - - - - - -
+
+   The maxspeed tag is used to specify the maximum speed limit on the
+   highway; this is always measured in km/hr in OpenStreetMap data. If the
+   tag value contains "mph" then it is assumed to be a value in those
+   units and converted to km/hr.
+
+The maxweight Tag
+- - - - - - - - -
+
+   The maxweight tag is used to specify the maximum weight of any traffic
+   on the highway. In other words this must be set to the heaviest weight
+   allowed on the highway (for example a bridge) in tonnes. If the tag
+   value contains "kg" then it is assumed that the value is in these units
+   and converted to tonnes.
+
+The maxheight Tag
+- - - - - - - - -
+
+   The maxheight tag is used to specify the maximum height of any traffic
+   on the highway. In other words this must be set to the lowest height of
+   anything above the highway (like a bridge) in metres. If the tag value
+   contains a measurement in feet or feet and inches then attempts are
+   made to convert this to metres.
+
+The maxwidth Tag
+- - - - - - - -
+
+   The maxwidth tag is used to specify the maximum width of any traffic on
+   the highway. This must be set to the minimum width of the constraints
+   at the wayside in metres. If the tag value contains a measurement in
+   feet or feet and inches then attempts are made to convert this to
+   metres.
+
+The maxlength Tag
+- - - - - - - - -
+
+   The maxlength tag is used to specify the maximum length of any traffic
+   on the highway (usually from a traffic sign) in metres. If the tag
+   value contains a measurement in feet or feet and inches then attempts
+   are made to convert this to metres.
+
+The area Tag
+- - - - - -
+
+   The area tag is used to specify that a way defines an area. This is
+   used only so that in the case of duplicated segments those belonging to
+   an area can be discarded in preference to those that are not.
+
+
+Relation Tags And Attributes
+----------------------------
+
+   The tags from the relations are used to associate more properties with
+   the highways that are part of that relation. The id attribute is used
+   so that relations that are members of other relations can be
+   identified. The member information is used to identify the nodes and
+   ways that make up the relation.
+
+The footroute Tag
+- - - - - - - - -
+
+   The footroute tag is used to identify whether a relation defines a
+   walking route and therefore should be applied to the individual member
+   highways.
+
+The bicycleroute Tag
+- - - - - - - - - -
+
+   The bicycleroute tag is used to identify whether a relation defines a
+   bicycle route and therefore should be applied to the individual member
+   highways.
+
+The type, restriction & except Tags
+- - - - - - - - - - - - - - - - - -
+
+   For turn relations the information about the allowed or disallowed
+   turns are stored in the type, restriction and except tags. For a turn
+   restriction the type must be equal to "restriction", the restriction
+   must define the type of turn relation and except defines transport
+   types which are exempt from the restriction.
+
+
+Tag Transformations
+-------------------
+
+   This section describes the set of tag transformations that are
+   contained in the default configuration file. The configuration file
+   tagging rules are applied in sequence and this section of the document
+   is arranged in the same order.
+
+
+Node Tag Transformations
+------------------------
+
+Barrier Defaults
+- - - - - - - -
+
+   The first part of the tag transformations is to decide on defaults for
+   each type of node. This uses the barrier tag in the OSM file and
+   converts it into a default set of disallowed transport types.
+
+   Barrier       foot horse wheelchair bicycle moped motorcycle motorcar goods hgv psv
+   -------       ---- ----- ---------- ------- ----- ---------- -------- ----- --- ---
+   kissing_gate, footgate, stile, v_stile, turnstile, squeeze,  squeeze_stile,
+   cycle_barrier, bicycle_barrier
+                 yes  no    no         no      no    no         no       no    no  no
+   horse_stile, horse_jump, step_over
+                 yes  yes   no         no      no    no         no       no    no  no
+   horse_barrier, cattle_grid
+                 yes  no    yes        yes     yes   yes        yes      yes   yes yes
+   motorcyle_barrier
+                 yes  yes   yes        yes     no    no         no       no    no  no
+   bollard, car_barrier, car_trap
+                 yes  yes   yes        yes     yes   yes        no       no    no  no
+
+Generic Access Permissions
+- - - - - - - - - - - - -
+
+   The access tag is used to specify the default access restrictions
+   through the node. If the tag value is no or private or a selection of
+   other values then all transport types are denied access (later tag
+   transformation rules may add specific transport types back again).
+
+Other Access Permissions
+- - - - - - - - - - - -
+
+   A tag named vehicle means any of the bicycle, moped, motorcycle,
+   motorcar, goods, hgv and psv transport types. A tag named motor_vehicle
+   is transformed to mean any vehicle except a bicycle.
+
+Specific Access Permissions
+- - - - - - - - - - - - - -
+
+   The final part of the access permissions is to use the specific
+   transport type tags.
+
+   One tag is recognised for each of the different modes of transport:
+   foot, horse, bicycle, wheelchair, moped, motorcycle, motorcar, goods,
+   hgv and psv. These indicate whether the specific type of transport is
+   allowed through the node or not; the values listed for the access tag
+   are also accepted here.
+
+Mini-roundabouts
+- - - - - - - -
+
+   If the highway tag has the value mini_roundabout or the junction tag
+   has the value roundabout then a junction tag with value roundaboutis
+   passed through.
+
+
+Way Tag Transformations
+-----------------------
+
+Highway Defaults
+- - - - - - - -
+
+   The first part of the tag transformations is to decide on defaults for
+   each type of highway. This uses the highway tag in the OSM file and
+   maps it into one of the highway tags that are recognised by Routino,
+   defining the default allowed transport types and adding a number of
+   properties.
+
+   The first part of the highway tag checking is to ignore the highway tag
+   if it has a value that indicates a non-highway. These are the proposed
+   and construction values for future highways, the no, abandoned and
+   disused values for previous highways and a small number of other
+   values.
+
+   The second part of the highway transformation is to convert the highway
+   tag into one that is recognised by Routino.
+
+   Original tag                            Transformed tag
+   ------------                            ---------------
+   motorway_link                           motorway
+   trunk_link                              trunk
+   primary_link                            primary
+   secondary_link                          secondary
+   tertiary_link                           tertiary
+   minor, road                             unclassified
+   living_street                           residential
+   access, services, layby                 service
+   byway, unsurfaced, unpaved              track
+   footway, bridleway, pedestrian, walkway path
+   route=ferry                             ferry (1)
+
+   Note 1: A ferry route is converted into a highway of type "ferry" so
+   that routes using a ferry can be calculated.
+
+   The type of highway also determines the defaults for the types of
+   transport allowed on the highway. The default assumptions are as shown
+   in the table below.
+
+   Highway      foot  horse  wheelchair bicycle moped motorcycle motorcar goods hgv psv
+   -------      ----  -----  ---------- ------- ----- ---------  -------- ----- --- ---
+   motorway     no    no     no         no      no    yes        yes      yes   yes yes
+   trunk        no(1) no(1)  no(1)      yes     yes   yes        yes      yes   yes yes
+   primary      yes   yes    yes        yes     yes   yes        yes      yes   yes yes
+   secondary    yes   yes    yes        yes     yes   yes        yes      yes   yes yes
+   tertiary     yes   yes    yes        yes     yes   yes        yes      yes   yes yes
+   unclassified yes   yes    yes        yes     yes   yes        yes      yes   yes yes
+   residential  yes   yes    yes        yes     yes   yes        yes      yes   yes yes
+   service      yes   yes    yes        yes     yes   yes        yes      yes   yes yes
+   track        yes   yes    yes        yes     no    no         no       no    no  no
+   cycleway     yes   no     yes        yes     no    no         no       no    no  no
+   path         yes   yes(2) yes        yes(2)  no    no         no       no    no  no
+   steps        yes   no     no         no      no    no         no       no    no  no
+   ferry (3)    no    no     no         no      no    no         no       no    no  no
+
+   Note 1: A trunk road may legally allow foot, horse or wheelchair access
+   but in the absence of other tags is considered to be too dangerous.
+   Note 2: A path allows bicycle or horse access by default only if
+   actually labelled as a highway of type "bridleway".
+   Note 3: Ferry routes must be explicitly tagged with the allowed
+   transport types, it is not sensible to try to guess.
+
+   Finally for the highway tag a number of default properties are added
+   depending on the highway type.
+
+   Highway      Properties
+   -------      ----------
+   motorway     paved, oneway, multilane
+   trunk        paved, multilane (1)
+   primary      paved, multilane (1)
+   secondary    paved
+   tertiary     paved
+   unclassified paved
+   residential  paved
+   service      paved
+   track        paved (2)
+   cycleway     paved
+   path         paved (3)
+   steps
+   ferry
+
+   Note 1: A highway of this type has the multilane property by default if
+   it is oneway.
+   Note 2: A track is paved only if it is tagged as tracktype=grade1.
+   Note 3: A path is paved only if it was originally tagged as
+   highway=walkway or highway=pedestrian.
+
+Generic Access Permissions
+- - - - - - - - - - - - -
+
+   The access tag is used to specify the default access restrictions on
+   the highway. If the tag value is no or private or a selection of other
+   values then all transport types are denied access (later tag
+   transformation rules may add specific transport types back again).
+
+Other Access Permissions
+- - - - - - - - - - - -
+
+   A tag named vehicle means any of the bicycle, moped, motorcycle,
+   motorcar, goods, hgv and psv transport types. A tag named motor_vehicle
+   is transformed to mean any vehicle except a bicycle.
+
+   The designation tag is used as an alternative method of identifying the
+   legal right of way on a path (in the UK at least). The tag
+   transformations convert these tags into a set of allowed transport
+   types as shown below.
+
+   Designation tag           Equivalent access permissions
+   ---------------           -----------------------------
+   restricted_byway          foot=yes, wheelchair=yes, horse=yes, bicycle=yes
+   public_byway, byway,
+   byway_open_to_all_traffic foot=yes, wheelchair=yes, horse=yes, bicycle=yes,
+                             moped=yes, motorcycle=yes, motorcar=yes
+   permissive_bridleway,
+   public_bridleway,
+   bridleway                 foot=yes, wheelchair=yes, horse=yes, bicycle=yes
+   public_cycleway           foot=yes, wheelchair=yes, bicycle=yes
+   permissive_footpath,
+   public_footpath,
+   footpath                  foot=yes, wheelchair=yes
+
+   In addition to these there are some other tags and values that will
+   modify the transport permissions on the highway.
+
+   A highway that is tagged as motorroad with a value of yes will deny
+   access to foot, horse, wheelchair, bicycle and moped transport.
+
+   A highway that is tagged with footway or sidewalk and one of a set of
+   popular values will allow foot and wheelchair access even if the road
+   type would not normally do so.
+
+   A highway that is tagged as cycleway with one of several values will
+   allow bicycle access. If the value of the cycleway tag is
+   opposite_lane, opposite_track or opposite then the cyclebothways tag is
+   set.
+
+   A highway that is tagged as oneway:bicycle with the value no will also
+   cause the cyclebothways tag to be set.
+
+Specific Access Permissions
+- - - - - - - - - - - - - -
+
+   The final part of the access permissions is to use the specific
+   transport type tags.
+
+   One tag is recognised for each of the different modes of transport:
+   foot, horse, bicycle, wheelchair, moped, motorcycle, motorcar, goods,
+   hgv and psv. These indicate whether the specific type of transport is
+   allowed on the highway or not.
+
+Highway Properties
+- - - - - - - - -
+
+   If there is a surface tag then the highway is assumed to be unpaved
+   unless the tag value matches one of the following: paved, asphalt,
+   concrete or many other values listed in the configuration file.
+
+   Support for the obsolete paved tag is also provided and the highway is
+   paved if this is set to a true value.
+
+   The lanes tag is passed through to be used to set the multilane highway
+   property.
+
+   The bridge and tunnel tags are copied directly from the input to the
+   output.
+
+Highway Restrictions
+- - - - - - - - - -
+
+   The oneway, maxspeed, maxweight, maxheight, maxwidth and maxlength are
+   copied directly from the input to the output without modification.
+
+Roundabouts
+- - - - - -
+
+   If a highway is tagged as junction=roundabout then a roundabout=yes tag
+   created on the output.
+
+Highway Names and References
+- - - - - - - - - - - - - -
+
+   The name and ref tags are copied directly from the input to the output.
+
+Highway Areas
+- - - - - - -
+
+   The area tag is copied directly from the input to the output.
+
+
+Relation Tag Transformations
+----------------------------
+
+   The type tag is passed through without change.
+
+Routes
+- - -
+
+   The route tag can be used to determine whether a relation is part of a
+   walking or bicycle route so that the footroute or bicycleroute
+   properties can be applied to the highways that make up that relation.
+
+   The tag transformations that are applied for route relations are
+   defined in the table below.
+
+   Relation Tag                 footroute Property bicycleroute Property
+   ------------                 ------------------ ---------------------
+   foot, walking, hiking        yes                no
+   bicycle                      no                 yes
+   bicycle;foot, foot;bicycle   yes                yes
+
+Turn Restrictions
+- - - - - - - - -
+
+   No tag transformations are defined for turn restriction relations but
+   the restriction and except tags are passed through without change.
+
+
+--------
+
+Copyright 2008-2015 Andrew M. Bishop.
diff --git a/3rdparty/Routino/doc/USAGE.txt b/3rdparty/Routino/doc/USAGE.txt
new file mode 100644
index 0000000..6405cf7
--- /dev/null
+++ b/3rdparty/Routino/doc/USAGE.txt
@@ -0,0 +1,648 @@
+                               Routino : Usage
+                               ===============
+
+
+   There are five programs that make up this software. The first one takes
+   the planet.osm datafile from OpenStreetMap (or other source of data
+   using the same formats) and converts it into a local database. The
+   second program uses the database to determine an optimum route between
+   two points. The third program allows visualisation of the data and
+   statistics to be extracted. The fourth program allows dumping the raw
+   parsed data for test purposes and the fifth is a test program for the
+   tag transformations.
+
+
+planetsplitter
+--------------
+
+   This program reads in the OSM format XML file and splits it up to
+   create the database that is used for routing.
+
+   Usage: planetsplitter [--help]
+                         [--dir=<dirname>] [--prefix=<name>]
+                         [--sort-ram-size=<size>] [--sort-threads=<number>]
+                         [--tmpdir=<dirname>]
+                         [--tagging=<filename>]
+                         [--loggable] [--logtime] [--logmemory]
+                         [--errorlog[=<name>]]
+                         [--parse-only | --process-only]
+                         [--append] [--keep] [--changes]
+                         [--max-iterations=<number>]
+                         [--prune-none]
+                         [--prune-isolated=<len>]
+                         [--prune-short=<len>]
+                         [--prune-straight=<len>]
+                         [<filename.osm> ... | <filename.osc> ...
+                          | <filename.pbf> ...
+                          | <filename.o5m> ... | <filename.o5c> ...
+                          | <filename.(osm|osc|o5m|o5c).bz2> ...
+                          | <filename.(osm|osc|o5m|o5c).gz> ...
+                          | <filename.(osm|osc|o5m|o5c).xz> ...]
+
+   --help
+          Prints out the help information.
+
+   --dir=<dirname>
+          Sets the directory name in which to save the results. Defaults
+          to the current directory.
+
+   --prefix=<name>
+          Sets the filename prefix for the files that are created.
+          Defaults to no prefix.
+
+   --sort-ram-size=<size>
+          Specifies the amount of RAM (in MB) to use for sorting the data.
+          If not specified then 64 MB will be used in slim mode or 256 MB
+          otherwise.
+
+   --sort-threads=<number>
+          The number of threads to use for data sorting (the sorting
+          memory is shared between the threads - too many threads and not
+          enough memory will reduce the performance).
+
+   --tmpdir=<dirname>
+          Specifies the name of the directory to store the temporary disk
+          files. If not specified then it defaults to either the value of
+          the --dir option or the current directory.
+
+   --tagging=<filename>
+          Sets the filename containing the list of tagging rules in XML
+          format for the parsing the input files. If the file doesn't
+          exist then dirname, prefix and "profiles.xml" will be combined
+          and used, if that doesn't exist then the file
+          '/usr/local/share/routino/profiles.xml' (or custom installation
+          location) will be used.
+
+   --loggable
+          Print progress messages that are suitable for logging to a file;
+          normally an incrementing counter is printed which is more
+          suitable for real-time display than logging.
+
+   --logtime
+          Print the elapsed time for each processing step (minutes,
+          seconds and milliseconds).
+
+   --logmemory
+          Print the maximum allocated and mapped memory for each
+          processing step (MBytes).
+
+   --errorlog[=<name>]
+          Log OSM parsing and processing errors to 'error.log' or the
+          specified file name (the '--dir' and '--prefix' options are
+          applied). If the --append option is used then the existing log
+          file will be appended, otherwise a new one will be created. If
+          the --keep option is also used a geographically searchable
+          database of error logs is created for use in the visualiser.
+
+   --parse-only
+          Parse the input files and store the data in intermediate files
+          but don't process the data into a routing database. This option
+          must be used with the --append option for all except the first
+          file.
+
+   --process-only
+          Don't read in any files but process the existing intermediate
+          files created by using the --parse-only option.
+
+   --append
+          Parse the input file and append the result to the existing
+          intermediate files; the appended file can be either an OSM file
+          or an OSC change file.
+
+   --keep
+          Store a set of intermediate files after parsing the OSM files,
+          sorting and removing duplicates; this allows appending an OSC
+          file and re-processing later.
+
+   --changes
+          This option indicates that the data being processed contains one
+          or more OSC (OSM changes) files, they must be applied in time
+          sequence if more than one is used. This option implies --append
+          when parsing data files and --keep when processing data.
+
+   --max-iterations=<number>
+          The maximum number of iterations to use when generating
+          super-nodes and super-segments. Defaults to 5 which is normally
+          enough.
+
+   --prune-none
+          Disable the prune options below, they can be re-enabled by
+          adding them to the command line after this option.
+
+   --prune-isolated=<length>
+          Remove the access permissions for a transport type from small
+          disconnected groups of segments and remove the segments if they
+          end up with no access permission (defaults to removing groups
+          under 500m).
+
+   --prune-short=<length>
+          Remove short segments (defaults to removing segments up to a
+          maximum length of 5m).
+
+   --prune-straight=<length>
+          Remove nodes in almost straight highways (defaults to removing
+          nodes up to 3m offset from a straight line).
+
+   <filename.osm>, <filename.osc>, <filename.pbf>, <filename.o5m>,
+          <filename.o5c>
+          Specifies the filename(s) to read data from. Filenames ending
+          '.pbf' will be read as PBF, filenames ending in '.o5m' or '.o5c'
+          will be read as O5M/O5C, otherwise as XML. Filenames ending
+          '.bz2' will be bzip2 uncompressed (if bzip2 support compiled
+          in). Filenames ending '.gz' will be gzip uncompressed (if gzip
+          support compiled in). Filenames ending '.xz' will be xz
+          uncompressed (if xz support compiled in).
+
+   Note: In version 2.5 of Routino the ability to read data from the
+   standard input has been removed. This is because there is now the
+   ability to read compressed files (bzip2, gzip, xz) and PBF files
+   directly. Also using standard input the file type cannot be
+   auto-detected from the filename.
+
+   Example usage 1:
+
+   planetsplitter --dir=data --prefix=gb great_britain.osm
+
+   This will generate the output files 'data/gb-nodes.mem',
+   'data/gb-segments.mem' and 'data/gb-ways.mem'. Multiple filenames can
+   be specified on the command line and they will all be read in, combined
+   and processed together.
+
+   Example usage 2:
+
+   planetsplitter --dir=data --prefix=gb --parse-only          great_britain_part1.osm
+   planetsplitter --dir=data --prefix=gb --parse-only --append great_britain_part2.osm
+   planetsplitter --dir=data --prefix=gb --parse-only --append ...
+   planetsplitter --dir=data --prefix=gb --process-only
+
+   This will generate the same output files as the first example but
+   parsing the input files is performed separately from the data
+   processing. The first file read in must not use the --append option but
+   the later ones must.
+
+   Example usage 3:
+
+   planetsplitter --dir=data --prefix=gb --keep    great_britain.osm
+
+   planetsplitter --dir=data --prefix=gb --changes great_britain.osc
+
+   This will generate the same output files as the first example. The
+   first command will process the complete file and keep some intermediate
+   data for later. The second command will apply a set of changes to the
+   stored intermediate data and keep the updated intermediate files for
+   repeating this step later with more change data.
+
+   The parsing and processing can be split into multiple commands as it
+   was in example 2 with the --keep option used with --process-only for
+   the initial OSM file(s) and the --changes option used with --parse-only
+   or --process-only for every OSC file.
+
+
+router
+------
+
+   This program performs the calculation of the optimum routes using the
+   database generated by the planetsplitter program.
+
+   Usage: router [--help | --help-profile | --help-profile-xml |
+                           --help-profile-json | --help-profile-perl ]
+                 [--dir=<dirname>] [--prefix=<name>]
+                 [--profiles=<filename>] [--translations=<filename>]
+                 [--exact-nodes-only]
+                 [--quiet | [--loggable] [--logtime] [--logmemory]]
+                 [--output-html]
+                 [--output-gpx-track] [--output-gpx-route]
+                 [--output-text] [--output-text-all]
+                 [--output-none] [--output-stdout]
+                 [--profile=<name>]
+                 [--transport=<transport>]
+                 [--shortest | --quickest]
+                 --lon1=<longitude> --lat1=<latitude>
+                 --lon2=<longitude> --lon2=<latitude>
+                 [ ... --lon99=<longitude> --lon99=<latitude>]
+                 [--reverse] [--loop]
+                 [--heading=<bearing>]
+                 [--highway-<highway>=<preference> ...]
+                 [--speed-<highway>=<speed> ...]
+                 [--property-<property>=<preference> ...]
+                 [--oneway=(0|1)] [--turns=(0|1)]
+                 [--weight=<weight>]
+                 [--height=<height>] [--width=<width>] [--length=<length>]
+
+   --help
+          Prints out the help information.
+
+   --help-profile
+          Prints out the selected transport profile (type, speed limits,
+          highway preferences etc.)
+
+   --help-profile-xml
+          Prints out all the loaded profiles as an XML file in the same
+          format that can be loaded in.
+
+   --help-profile-json
+          Prints out all the loaded profiles in JavaScript Object Notation
+          (JSON) format for use in the interactive webpage.
+
+   --help-profile-perl
+          Prints out all the loaded profiles as a Perl object for use in
+          the router CGI.
+
+   --dir=<dirname>
+          Sets the directory name in which to read the local database.
+          Defaults to the current directory.
+
+   --prefix=<name>
+          Sets the filename prefix for the files in the local database.
+          Defaults to no prefix.
+
+   --profiles=<filename>
+          Sets the filename containing the list of routing profiles in XML
+          format. If the file doesn't exist then dirname, prefix and
+          "profiles.xml" will be combined and used, if that doesn't exist
+          then the file '/usr/local/share/routino/profiles.xml' (or custom
+          installation location) will be used.
+
+   --translations=<filename>
+          Sets the filename containing the list of translations in XML
+          format for the output files. If the file doesn't exist then
+          dirname, prefix and "translations.xml" will be combined and
+          used, if that doesn't exist then the file
+          '/usr/local/share/routino/translations.xml' (or custom
+          installation location) will be used.
+
+   --exact-nodes-only
+          When processing the specified latitude and longitude points only
+          select the nearest node instead of finding the nearest point
+          within a segment (quicker but less accurate unless the points
+          are already near nodes).
+
+   --quiet
+          Don't generate any screen output while running (useful for
+          running in a script).
+
+   --loggable
+          Print progress messages that are suitable for logging to a file;
+          normally an incrementing counter is printed which is more
+          suitable for real-time display than logging.
+
+   --logtime
+          Print the elapsed time for each processing step (minutes,
+          seconds and milliseconds).
+
+   --logmemory
+          Print the maximum allocated and mapped memory for each
+          processing step (MBytes).
+
+   --language=<lang>
+          Select the language specified from the file of translations. If
+          this option is not given and the file exists then the first
+          language in the file will be used. If this option is not given
+          and no file exists the compiled-in default language (English)
+          will be used.
+
+   --output-html
+   --output-gpx-track
+   --output-gpx-route
+   --output-text
+   --output-text-all
+          Generate the selected output file formats (HTML, GPX track file,
+          GPX route file, plain text route and/or plain text with all
+          nodes). If no output is specified then all are generated,
+          specifying any automatically disables those not specified.
+
+   --output-none
+          Do not generate any output or read in any translations files.
+
+   --output-stdout
+          Write to stdout instead of a file (requires exactly one output
+          format option, implies '--quiet').
+
+   --profile=<name>
+          Specifies the name of the profile to use.
+
+   --transport=<transport>
+          Select the type of transport to use, <transport> can be set to:
+
+          + foot = Foot
+          + horse = Horse
+          + wheelchair = Wheelchair
+          + bicycle = Bicycle
+          + moped = Moped (Small motorcycle, limited speed)
+          + motorcycle = Motorcycle
+          + motorcar = Motorcar
+          + goods = Goods (Small lorry, van)
+          + hgv = HGV (Heavy Goods Vehicle - large lorry)
+          + psv = PSV (Public Service Vehicle - bus, coach)
+
+          Defaults to 'motorcar', this option also selects the default
+          profile information if the '--profile' option is not given and a
+          profile matching the transport name is found.
+
+   --shortest
+          Find the shortest route between the waypoints.
+
+   --quickest
+          Find the quickest route between the waypoints.
+
+   --lon1=<longitude>, --lat1=<latitude>
+   --lon2=<longitude>, --lat2=<latitude>
+   ... --lon99=<longitude>, --lat99=<latitude>
+          The location of the waypoints that make up the start, middle and
+          end points of the route. Up to 99 waypoints can be specified and
+          the route will pass through each of the specified ones in
+          sequence. The algorithm will use the closest node or point
+          within a segment that allows the specified traffic type.
+
+   --reverse
+          Find a route between the waypoints in reverse order.
+
+   --loop
+          Find a route that returns to the first waypoint after the last
+          one.
+
+   --heading=<bearing>
+          Specifies the initial direction of travel at the start of the
+          route (from the lowest numbered waypoint) as a compass bearing
+          from 0 to 360 degrees.
+
+   --highway-<highway>=<preference>
+          Selects the percentage preference for using each particular type
+          of highway. The value of <highway> can be selected from:
+
+          + motorway = Motorway
+          + trunk = Trunk
+          + primary = Primary
+          + secondary = Secondary
+          + tertiary = Tertiary
+          + unclassified = Unclassified
+          + residential = Residential
+          + service = Service
+          + track = Track
+          + cycleway = Cycleway
+          + path = Path
+          + steps = Steps
+          + ferry = Ferry
+
+          Default value depends on the profile selected by the --transport
+          option.
+
+   --speed-<highway>=<speed>
+          Selects the speed limit in km/hour for each type of highway.
+          Default value depends on the profile selected by the --transport
+          option.
+
+   --property-<property>=<preference>
+          Selects the percentage preference for using each particular
+          highway property The value of <property> can be selected from:
+
+          + paved = Paved (suitable for normal wheels)
+          + multilane = Multiple lanes
+          + bridge = Bridge
+          + tunnel = Tunnel
+          + footroute = A route marked for foot travel
+          + bicycleroute = A route marked for bicycle travel
+
+          Default value depends on the profile selected by the --transport
+          option.
+
+   --oneway=[0|1]
+          Selects if the direction of oneway streets are to be obeyed
+          (useful to not obey them when walking). Default value depends on
+          the profile selected by the --transport option.
+
+   --turns=[0|1]
+          Selects if turn restrictions are to be obeyed (useful to not
+          obey them when walking). Default value depends on the profile
+          selected by the --transport option.
+
+   --weight=<weight>
+          Specifies the weight of the mode of transport in tonnes; ensures
+          that the weight limit on the highway is not exceeded. Default
+          value depends on the profile selected by the --transport option.
+
+   --height=<height>
+          Specifies the height of the mode of transport in metres; ensures
+          that the height limit on the highway is not exceeded. Default
+          value depends on the profile selected by the --transport option.
+
+   --width=<width>
+          Specifies the width of the mode of transport in metres; ensures
+          that the width limit on the highway is not exceeded. Default
+          value depends on the profile selected by the --transport option.
+
+   --length=<length>
+          Specifies the length of the mode of transport in metres; ensures
+          that the length limit on the highway is not exceeded. Default
+          value depends on the profile selected by the --transport option.
+
+   The meaning of the <preference> parameter in the command line options
+   is slightly different for the highway preferences and the property
+   preferences. For the highway preference consider the choice between two
+   possible highways between the start and finish when looking for the
+   shortest route. If highway A has a preference of 100% and highway B has
+   a preference of 90% then highway A will be chosen even if it is up to
+   11% longer (100/90 = 111%). For the highway properties each highway
+   either has a particular property or not. If the preference for the
+   property is 60% then a highway with the property has a preference of
+   77% (sqrt(60%)) and one without has a preference of 63%
+   (sqrt(100-60%)). A highway with the property will be chosen even if it
+   is up to 22% longer than one without the property (77/63 = 122%). The
+   overall preference for each highway segment is the product of the
+   preference for the highway type and all of the preferences for the
+   highway properties.
+
+   Example usage (motorcycle journey, scenic route, not very fast):
+
+   router --dir=data --prefix=gb --transport=motorcycle --highway-motorway=0 \
+          --highway-trunk=0 --speed-primary=80 --speed-secondary=80 --quickest
+
+   This will use the files 'data/gb-nodes.mem', 'data/gb-segments.mem' and
+   'data/gb-ways.mem' to find the quickest route by motorcycle not using
+   motorways or trunk roads and not exceeding 80 km/hr.
+
+
+filedumper
+----------
+
+   This program is used to extract statistics from the database, extract
+   particular information for visualisation purposes or for dumping the
+   database contents.
+
+   Usage: filedumper [--help]
+                     [--dir=<dirname>] [--prefix=<name>]
+                     [--statistics]
+                     [--visualiser --latmin=<latmin> --latmax=<latmax>
+                                   --lonmin=<lonmin> --lonmax=<lonmax>
+                                   --data=<data-type>]
+                     [--dump [--node=<node> ...]
+                             [--segment=<segment> ...]
+                             [--way=<way> ...]
+                             [--turn-relation=<relation> ...]
+                             [--errorlog=<number> ...]]
+                     [--dump-osm [--no-super]
+                                 [--latmin=<latmin> --latmax=<latmax>
+                                  --lonmin=<lonmin> --lonmax=<lonmax>]]
+                     [--dump-visualiser [--data=node<node>]
+                                        [--data=segment<segment>]
+                                        [--data=turn-relation<rel>]
+                                        [--data=errorlog<number>]]
+
+   --help
+          Prints out the help information.
+
+   --dir=<dirname>
+          Sets the directory name in which to read the local database.
+          Defaults to the current directory.
+
+   --prefix=<name>
+          Sets the filename prefix for the files in the local database.
+
+   --statistics
+          Prints out statistics about the database files.
+
+   --visualiser
+          Selects a data visualiser mode which will output a set of data
+          according to the other parameters below.
+
+        --latmin=<latmin> --latmax=<latmax>
+                The range of latitudes to print the data for.
+
+        --lonmin=<lonmin> --lonmax=<lonmax>
+                The range of longitudes to print the data for.
+
+        --data=<data-type>
+                The type of data to output, <data-type> can be selected
+                from:
+
+               o junctions = segment count at each junction.
+               o super = super-node and super-segments.
+               o waytype-* = segments of oneway, cyclebothways or
+                 roundabout type.
+               o highway-* = segments of the specified highway type (e.g.
+                 highway-primary to display segments ofprimary roads).
+               o transport-* = segments allowing the specified transport
+                 type (e.g. transport-foot to display segments accessible
+                 on foot).
+               o turns = turn restrictions.
+               o speed = speed limits.
+               o weight = weight limits.
+               o height = height limits.
+               o width = width limits.
+               o length = length limits.
+               o property-* = segments having the specified property (e.g.
+                 property-paved to display segments of paved highway).
+               o errorlogs = errors logged during parsing.
+
+   --dump
+          Selects a data dumping mode which allows looking at individual
+          items in the databases (specifying 'all' instead of a number
+          dumps all of them). More than one of the following parameters
+          can be specified on the command line.
+
+        --node=<node>
+                Prints the information about the selected node number
+                (internal number, not the node id number in the original
+                source file).
+
+        --segment=<segment>
+                Prints the information about the selected segment number.
+
+        --way=<way>
+                Prints the information about the selected way number
+                (internal number, not the way id number in the original
+                source file).
+
+        --turn-relation=<relation>
+                Prints the information about the selected turn relation
+                number (internal number, not the relation id number in the
+                original source file).
+
+        --errorlog=<number>
+                Prints the information about the selected error log that
+                was stored when the data was parsed.
+
+   --osm-dump
+          Dumps the contents of the database as an OSM format XML file,
+          the whole database will be dumped unless the latitude and
+          longitude ranges are specified.
+
+        --no-super
+                The super segments will not be output.
+
+        --latmin=<latmin> --latmax=<latmax>
+                The range of latitudes to dump the data for.
+
+        --lonmin=<lonmin> --lonmax=<lonmax>
+                The range of longitudes to dump the data for.
+
+   --dump-visualiser
+          Dumps the contents of the database as HTML formatted items for
+          display in the visualiser web page.
+
+        --data=node<node>
+                Prints the information about the selected node number
+                (internal node number, not from the original source file).
+
+        --data=segment<segment>
+                Prints the information about the selected segment number
+                as if it was a way (internal segment number, unrelated to
+                original source file).
+
+        --data=turn-relation<relation>
+                Prints the information about the selected turn relation
+                number (internal turn relation number, not from the
+                original source file).
+
+        --data=errorlog<number>
+                Prints the information about the selected error log that
+                was stored when the data was parsed.
+
+
+filedumperx
+-----------
+
+   This program is a modified version of filedumper that will dump out the
+   contents of the intermediate data that is saved by planetsplitter after
+   processing using the --keep or --changes option. This is intended
+   for test purposes only and gives no useful information about the
+   routing database.
+
+   Usage: filedumperx [--help]
+                      [--dir=<dirname>] [--prefix=<name>]
+                      [--dump [--nodes]
+                              [--ways]
+                              [--route-relations]
+                              [--turn-relations]]
+
+   --help
+          Prints out the help information.
+
+   --dir=<dirname>
+          Sets the directory name in which to read the local database.
+          Defaults to the current directory.
+
+   --prefix=<name>
+          Sets the filename prefix for the files in the local database.
+
+   --dump
+          Dumps the complete set of data in the intermediate files that
+          are written by planetsplitter using the --keep or --changes
+          options.
+
+        --nodes
+                Dumps the node data.
+
+        --ways
+                Dumps the way data.
+
+        --route-relations
+                Dumps the route relation data.
+
+        --turn-relations
+                Dumps the turn relation data.
+
+
+--------
+
+Copyright 2008-2014 Andrew M. Bishop.
diff --git a/3rdparty/Routino/doc/html/algorithm.html b/3rdparty/Routino/doc/html/algorithm.html
new file mode 100644
index 0000000..84b56bb
--- /dev/null
+++ b/3rdparty/Routino/doc/html/algorithm.html
@@ -0,0 +1,413 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<title>Routino : Algorithm</title>
+
+<!--
+ Routino documentation - algorithm
+
+ Part of the Routino routing software.
+
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see http://www.gnu.org/licenses/.
+-->
+
+<link href="style.css" type="text/css" rel="stylesheet">
+</head>
+
+<body>
+
+<!-- Header Start -->
+
+<div class="header">
+
+<h1>Routino : Algorithm</h1>
+
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2 id="H_1_1">Algorithms</h2>
+
+This page describes the development of the algorithm that is used in Routino for
+finding routes.
+
+<h3 id="H_1_1_1">Simplest Algorithm</h3>
+
+The algorithm to find a route is fundamentally simple: Start at the beginning,
+follow all possible routes and keep going until you reach the end.
+<p>
+While this method does work, it isn't fast.  To be able to find a route quickly
+needs a different algorithm, one that can find the correct answer without
+wasting time on routes that lead nowhere.
+
+<h3 id="H_1_1_2">Improved Algorithm</h3>
+
+The simplest way to do this is to follow all possible segments from the starting
+node to the next nearest node (an intermediate node in the complete journey).
+For each node that is reached store the shortest route from the starting node
+and the length of that route.  The list of intermediate nodes needs to be
+maintained in order of shortest overall route on the assumption that there is a
+straight line route from here to the end node.
+<br>
+At each point the intermediate node that has the shortest potential overall
+journey time is processed before any other node.  From the first node in the
+list follow all possible segments and place the newly discovered nodes into the
+same list ordered in the same way.  This will tend to constrain the list of
+nodes examined to be the ones that are between the start and end nodes.  If at
+any point you reach a node that has already been reached by a longer route then
+you can discard that route since the newly discovered route is shorter.
+Conversely if the previously discovered route is shorter then discard the new
+route.
+<br>
+At some point the end node will be reached and then any routes with potential
+lengths longer than this actual route can be immediately discarded.  The few
+remaining potential routes must be continued until they are found to be shorter
+or have no possibility of being shorter.  The shortest possible route is then
+found.
+<p>
+At all times when looking at a node only those segments that are possible by the
+chosen means of transport are followed.  This allows the type of transport to be
+handled easily.  When finding the quickest route the same rules apply except
+that the criterion for sorting is the shortest potential route (assuming that
+from each node to the end is the fastest possible type of highway).
+<p>
+This method also works, but again it isn't very fast.  The problem is that the
+complexity is proportional to the number of nodes or segments in all routes
+examined between the start and end nodes.  Maintaining the list of intermediate
+nodes in order is the most complex part.
+
+<h3 id="H_1_1_3">Final Algorithm</h3>
+
+The final algorithm that is implemented in the router is basically the one above
+but with an important difference.  Instead of finding a long route among a data
+set of 8,000,000 nodes (number of highway nodes in UK at beginning of 2010) it
+finds one long route in a data set of 1,000,000 nodes and a few hundred very
+short routes in the full data set.  Since the time taken to find a route is
+proportional to the number of nodes that need to be considered the main route
+takes 1/10th of the time and the very short routes take almost no time at all.
+<p>
+The solution to making the algorithm fast is therefore to discard most of the
+nodes and only keep the interesting ones.  In this case a node is deemed to be
+interesting if it is the junction of three or more segments or the junction of
+two segments with different properties or has a routing restriction different
+from the connecting segments.  In the algorithm and following description these
+are classed as <em>super-nodes</em>.  Starting at each super-node a
+<em>super-segment</em> is generated that finishes on another super-node and
+contains the <em>shortest</em> path along segments with identical properties
+(and these properties are inherited by the super-segment).  The point of
+choosing the shortest route is that since all segments considered have identical
+properties they will be treated identically when properties are taken into
+account.  This decision making process can be repeated until the only the most
+important and interesting nodes remain.
+<p class="center">
+<img alt="Original data" src="example0.png">
+<br>
+Original Highways
+<p class="center">
+<img alt="Iteration 1" src="example1.png">
+<br>
+First Iteration
+<p class="center">
+<img alt="Iteration 2" src="example2.png">
+<br>
+Second Iteration
+<p class="center">
+<img alt="Iteration 3" src="example3.png">
+<br>
+Third Iteration
+<p class="center">
+<img alt="Iteration 4" src="example4.png">
+<br>
+Fourth Iteration
+<p>
+To find a route between a start and finish point now comprises the following
+steps (assuming a shortest route is required):
+<ol>
+  <li>Find all shortest routes from the start point along normal segments and
+  stopping when super-nodes are reached.
+  <li>Find all shortest routes from the end point backwards along normal
+  segments and stopping when super-nodes are reached.
+  <li>Find the shortest route along super-segments from the set of super-nodes
+  in step 1 to the set of super-nodes in step 2 (taking into account the lengths
+  found in steps 1 and 2 between the start/finish super-nodes and the ultimate
+  start/finish point).
+  <li>For each super-segment in step 3 find the shortest route between the two
+  end-point super-nodes.
+</ol>
+This multi-step process is considerably quicker than using all nodes but gives a
+result that still contains the full list of nodes that are visited.  There are
+some special cases though, for example very short routes that do not pass
+through any super-nodes, or routes that start or finish on a super-node.  In
+these cases one or more of the steps listed can be removed or simplified.
+<p>
+When the first route reaches the final node the length of that route is retained
+as a benchmark.  Any shorter complete route that is calculated later would
+replace this benchmark.  As routes are tested any partial routes that are longer
+than the benchmark can be immediately discarded.  Other partial routes have the
+length of a perfect straight highway to the final node added to them and if the
+total exceeds the benchmark they can also be discarded.  Very quickly the number
+of possible routes is reduced until the absolute shortest is found.
+<p>
+For routes that do not start or finish on a node in the original data set a fake
+node is added to an existing segment.  This requires special handling in the
+algorithm but it gives mode flexibility for the start, finish and intermediate
+points in a route.
+
+<h4 id="H_1_1_3_1">Algorithm Evolution</h4>
+
+In Routino versions 1.0 to 1.4 the algorithm used to select a super-node was the
+same as above except that node properties were not included.  Routino versions
+1.4.1 to 1.5.1 used a slightly different algorithm which only chose nodes that
+were junctions between segments with different properties (or has a routing
+restriction that is different from connecting segments in versions 1.5 and
+1.5.1).  The addition of turn restrictions (described in more detail below)
+requires the original algorithm since the super-segments more accurately reflect
+the underlying topology.
+
+<h4 id="H_1_1_3_2">Algorithm Implementation</h4>
+
+The algorithm that is used for finding the route between the super-nodes using
+super-segments is the A* algorithm (or a slight variation of it).  This was not
+a deliberate design decision, but evolved into it during development.  This
+algorithm relies on calculating the lowest score (shortest distance or quickest
+time) to each node from the starting node.  The remaining score for the path to
+the destination node is estimated (based on a straight line using the fastest
+type of highway) and added to the current score and the result recorded.  At
+each step the unvisited node that has the lowest current score is examined and
+all nodes connected to it have their scores calculated.  When the destination
+node has been reached all remaining unvisited nodes with scores higher than the
+destination node's score can be discarded and the few remaining nodes examined.
+<p>
+The algorithm used to find the route between super-nodes using normal segments
+is Dijkstra's algorithm (although it is implemented as the same algorithm as
+above but with no estimated cost).  Since these routes tend to be short and the
+CPU time for calculating the heuristic cost function is relatively large this
+tends to give a quicker solution.
+
+
+<h3 id="H_1_1_4">Routing Preferences</h3>
+
+One of the important features of Routino is the ability to select a route that
+is optimum for a set of criteria such as preferences for each type of highway,
+speed limits and other restrictions and highway properties.
+<p>
+All of these features are handled by assigning a score to each segment while
+calculating the route and trying to minimise the score rather than simply
+minimising the length.
+<dl>
+  <dt>Segment length
+  <dd>When calculating the shortest route the length of the segment is the
+  starting point for the score.
+  <dt>Speed preference
+  <dd>When calculating the quickest route the time taken calculated from the
+  length of the segment and the lower of the highway's own speed limit and the
+  user's speed preference for the type of highway is the starting point for the
+  score.
+  <dt>One-way restriction
+  <dd>If a highway has the one-way property in the opposite direction to the
+  desired travel and the user's preference is to obey one-way restrictions then
+  the segment is ignored.
+  <dt>Weight, height, width & length limits
+  <dd>If a highway has one of these limits and its value is less than the user's
+  specified requirement then the segment is ignored.
+  <dt>Highway preference
+  <dd>The highway preference specified by the user is a percentage, these are
+  scaled so that the most preferred highway type has a weighted preference of
+  1.0 (0% always has a weighted preference of 0.0).  The calculated score for a
+  segment is divided by this weighted preference.
+  <dt>Highway properties
+  <dd>The other highway properties are specified by the user as a percentage and
+  each highway either has that property or not.  The user's property preference
+  is scaled into the range 0.0 (for 0%) to 1.0 (for 100%) to give a weighted
+  preference, a second "non-property" weighted preference is calculated in the
+  same way after subtracting the user's preference from 100%.  If a segment has
+  a particular property then the calculated score is divided by the weighted
+  preference for that property, if not then it is divided by the non-property
+  weighted preference.  A non-linear transformation is applied so that changing
+  property preferences close to 50% do not cause large variations in routes.
+</dl>
+
+<h3 id="H_1_1_5">Data Pruning</h3>
+
+From version 2.2 there are options to "prune" nodes and segments from the input
+data which means to remove nodes and/or segments without significantly changing
+the routing results.
+<p>
+The pruning options must meet a number of conditions to be useful:
+<ul>
+  <li>The topology relevant to routing must remain unchanged.  The instructions
+    that are produced from the reduced set of nodes and segments must be
+    sufficiently accurate for anybody trying to follow them on the ground.
+  <li>Any restrictions belonging to nodes or segments that stop certain types of
+    traffic from following a particular highway must be preserved.
+  <li>The total length must be calculated using the original data and not the
+    simplified data which by its nature will typically be shorter.
+  <li>The location of the remaining nodes and segments must be a good
+    representation of the original nodes and segments.  Since the calculated
+    route may be displayed on a map the remaining nodes and segments must
+    clearly indicate the route to take.
+</ul>
+<p>
+The prune options all have user-controllable parameters which allow the
+geographical accuracy to be controlled.  This means that although the topology
+is the same the geographical accuracy can be sacrificed slightly to minimise the
+number of nodes and segments.
+<p>
+The pruning options that are available are:
+<ul>
+  <li>Removing the access permissions for a transport type from segments if it
+  is not possible to route that transport type from those segments to a
+  significant number of other places.  The limit on the pruning is set by the
+  total length of the isolated group of segments.  This significantly increases
+  the chance that a route will be found by not putting waypoints in inaccessible
+  places.
+  <li>Removing short segments, the limit is set by the length of the segment.
+  This removes a number of redundant segments (and associated nodes) but rules
+  are applied to ensure that removing the segments does not alter junction
+  topology or remove node access permissions or changes in way properties.
+  <li>Removing nodes from almost straight highways, the limit is set by the
+  distance between the remaining segments and the original nodes.  This removes
+  a large number of redundant nodes (and therefore segments) but again care is
+  taken not to remove node access permissions or changes in way properties.
+</ul>
+
+<h3 id="H_1_1_6">Turn Restrictions</h3>
+
+The addition of turn restrictions in version 2.0 adds a set of further
+complications because it introduces a set of constraints that are far more
+complex than one-way streets.
+<p>
+A turn restriction in the simplest case is a combination of a segment, node and
+segment such that routes are not allowed to go from the first segment to the
+second one through the specified node.  Exceptions for certain types of traffic
+can also be specified.  Currently only this simplest type of turn restriction is
+handled by the algorithm.
+<p>
+The first complication of turn restrictions is that the algorithm above requires
+that super-segments are composed of segments with identical properties.  A turn
+restriction is not the same in both directions so a super-segment cannot include
+any route through that turn restriction.  The node at the centre of the turn
+restriction must therefore be a super-node to avoid this.  In addition to this
+all nodes connected to the turn restriction node by a single segment must also
+be super-nodes to avoid any long-distance super-segments starting at the
+restricted node.
+<p>
+The second complication of a turn restriction is that the optimum route may
+require passing through the same node more than once.  This can happen where the
+route needs to work around a turn restriction by driving past it, turning round
+(on a roundabout perhaps) and coming back along the same highway.  Without turn
+restrictions a route could be defined purely by the set of nodes that were
+passed; no node would exist more than once along a route between two points.
+With turn restrictions the route is defined by a node and the segment used to
+get there; no route between two points will ever need to follow the same segment
+in the same direction more than once.  This means that the optimisation
+algorithm calculates scores for directed segments (indexed by segment and end
+node) rather than for nodes.
+<p>
+A side-effect of this is that a route that works around a turn restriction must
+be calculable using the super-segments that are stored in the database.  This
+puts a limit on the amount of database optimisation that can be performed
+because if too many super-segments are removed the optimum work-around may also
+be removed.  The solution to this is to ensure that the database preserves all
+loops that can be used to turn around and reverse direction, previously
+super-segments that started and finished on the same super-node were disallowed.
+<p>
+Another side-effect of having the route composed of a set of locations (nodes)
+as well as the direction of travel (segments used to reach them) is that via
+points in the route can be forced to continue in the original direction.  If the
+chosen method of transport obeys turn restrictions then it will not reverse
+direction at a via point but will find an optimum route continuing in the same
+direction.  The only exception to this is when the route ahead at a waypoint is
+into a dead-end and an immediate U-turn is allowed.
+<p>
+A side-effect of having the starting direction at a via point defined by the
+previous part of the route is that overall non-optimal routes may be found even
+though each section between via points is optimal.  For a route with a start,
+middle and end point defined it can be the case that the shortest route from the
+start to the middle arrives in the opposite direction to that required for the
+optimal route from the middle to the end.  The calculation of the route in
+separate sections therefore may give a non-optimum result even though each
+section is itself optimum based on the start conditions.
+<p>
+Overall the presence of turn restrictions in the database makes the routing
+slower even for regions of the map that have no turn restrictions.
+
+<h3 id="H_1_1_7">Data Implementation</h3>
+
+The hardest part of implementing this router is the data organisation.  The
+arrangement of the data to minimise the number of operations required to follow
+a route from one node to another is much harder than designing the algorithm
+itself.
+<p>
+The final implementation uses a separate table for nodes, segments and ways.
+Each table individually is implemented as a C-language data structure that is
+written to disk by a program which parses the OpenStreetMap XML data file.  In
+the router these data structures are memory mapped so that the operating system
+handles the problems of loading the needed data blocks from disk.
+<p>
+Each node contains a latitude and longitude and they are sorted geographically
+so that converting a latitude and longitude coordinate to a node is fast as well
+as looking up the coordinate of a node.  The node also contains the location in
+the array of segments for the first segment that uses that node.
+<br>
+Each segment contains the location of the two nodes as well as the way that the
+segment came from.  The location of the next segment that uses one of the two
+nodes is also stored; the next segment for the other node is the following one
+in the array.  The length of the segment is also pre-computed and stored.
+<br>
+Each way has a name, a highway type, a list of allowed types of traffic, a speed
+limit, any weight, height, width or length restrictions and the highway
+properties.
+<p>
+The super-nodes are mixed in with the nodes and the super-segments are mixed in
+with the segments.  For the nodes they are the same as the normal nodes, so just
+a flag is needed to indicate that they are super.  The super-segments are in
+addition to the normal segments so they increase the database size (by about
+10%) and are also marked with a flag.  Some segments are therefore flagged as
+both normal segments and super-segments if they both have the same end nodes.
+<p>
+The relations are stored separately from the nodes, segments and ways.  For the
+turn restriction relations the initial and final segments are stored along with
+the restricted node itself.  Each node that has a turn restriction is marked in
+the main node storage with a flag to indicate this information.
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer">
+
+<address>
+© Andrew M. Bishop - <a href="http://www.routino.org/">http://www.routino.org/</a>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</body>
+
+</html>
diff --git a/3rdparty/Routino/doc/html/configuration.html b/3rdparty/Routino/doc/html/configuration.html
new file mode 100644
index 0000000..1d3ebc3
--- /dev/null
+++ b/3rdparty/Routino/doc/html/configuration.html
@@ -0,0 +1,314 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<title>Routino : Configuration</title>
+
+<!--
+ Routino documentation - configuration
+
+ Part of the Routino routing software.
+
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see http://www.gnu.org/licenses/.
+-->
+
+<link href="style.css" type="text/css" rel="stylesheet">
+</head>
+
+<body>
+
+<!-- Header Start -->
+
+<div class="header">
+
+<h1>Routino : Configuration</h1>
+
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2 id="H_1_1">XML Configuration Files</h2>
+
+New in version 1.4 of Routino is the use of configuration files to allow more
+information to be provided to the programs at run-time.  The configuration files
+that are used are:
+<ul>
+  <li>Tagging transformation rules for the <em>planetsplitter</em> program.
+  <li>Routing profiles for the <em>router</em> program.
+  <li>Output translations for the <em>router</em> program.
+</ul>
+
+In keeping with the nature of the input and output files the configuration files
+are also XML files.  Each of the files uses a custom defined XML schema and an
+XSD file is provided for each of them.
+
+<h3 id="H_1_1_1" title="Tagging rules">Tag Transformation Rules</h3>
+
+The default name of the tagging transformation rules XML configuration file
+is <em>tagging.xml</em> in the same directory as the generated database files.
+Other filenames can be specified on the command line using
+the <tt>--tagging</tt> option.  When processing the input it is possible to have
+a different set of tagging rules for each file; for example different rules for
+different countries.
+
+<p>
+
+The tagging rules allow modifying the highway tags in the source file so that
+the routing can be performed on a simpler set of tags.  This removes the special
+case tagging rules from the source code into the configuration file where they
+can be easily modified.  Part of the provided tagging.xml file showing the rules
+for motorway_link and motorway highway types.
+
+<pre class="boxed">
+<?xml version="1.0" encoding="utf-8"?>
+<routino-tagging>
+
+  <way>
+
+    <if k="highway" v="motorway_link">
+      <set v="motorway"/>
+    </if>
+
+    <if k="highway" v="motorway">
+      <output k="highway"/>
+
+      <output k="motorcycle" v="yes"/>
+      <output k="motorcar"   v="yes"/>
+      <output k="goods"      v="yes"/>
+      <output k="hgv"        v="yes"/>
+      <output k="psv"        v="yes"/>
+
+      <output k="paved"      v="yes"/>
+      <output k="multilane"  v="yes"/>
+      <output k="oneway"     v="yes"/>
+
+      <unset k="highway"/>
+    </if>
+...
+  <way>
+
+</routino-tagging>
+</pre>
+
+The rules all have the same format; an <em>if</em> or <em>ifnot</em> element at
+the top level for matching the input and some other elements inside to be used
+if there was a match.
+
+<p>
+
+Within the <em>if</em> and <em>ifnot</em> rules any of the rules can be used.
+These are <em>if</em>, <em>ifnot</em>, <em>set</em>, <em>unset</em>,
+<em>output</em> or <em>logerror</em> elements.
+
+<p>
+
+The rules for matching the <em>if</em> or <em>ifnot</em> elements are the
+following:
+
+<ul>
+  <li>An <em>if</em> rule that has both <em>k</em> and <em>v</em> specified is
+    only matched if a tag exists in the input that matches both.
+  <li>An <em>if</em> rule that has only the <em>k</em> attribute is matched if a
+    tag with that key exists.
+  <li>An <em>if</em> rule that has only the <em>v</em> attribute is matched for
+    each tag with that value (i.e. the contents may be used more than once).
+  <li>An <em>if</em> rule that has neither attribute specified always matches.
+  <li>An <em>ifnot</em> rule that has both <em>k</em> and <em>v</em> specified
+    is only matched if no tag exists in the input that matches both.
+  <li>An <em>ifnot</em> rule that has only the <em>k</em> attribute is matched
+    only if no tag with that key exists.
+  <li>An <em>ifnot</em> rule that has only the <em>v</em> attribute is only
+    matched if no tag with that value exists.
+  <li>An <em>ifnot</em> rule that has neither attribute specified never matches.
+</ul>
+
+<p>
+
+For <em>set</em>, <em>unset</em>, <em>output</em> or <em>logerror</em> elements
+inside of an <em>if</em> rule an unspecified value for the <em>k</em>
+or <em>v</em> attribute is replaced by the values from the tag that matched the
+outer <em>if</em> rule.  This makes it simple to delete tags that match a
+particular rule without having to specify the parameters more than once.  For
+elements inside of an <em>ifnot</em> element an unspecified value for
+the <em>k</em> or <em>v</em> attribute is replaced by the values from the
+outer <em>ifnot</em> rule.  This means that either the outer <em>ifnot</em>
+element or the inner element must specify both <em>k</em> and <em>v</em>
+attributes between them.  For nested <em>if</em> or <em>ifnot</em> elements the
+outer <em>k</em> and <em>v</em> attributes are not inherited by the inner
+elements.
+
+<p>
+
+The <em>set</em> and <em>unset</em> elements either create or delete a tag from
+the input data that was read from the file.  If the <em>set</em> element is used
+and the tag already exists then it is modified.  The <em>output</em> element
+adds a tag to the set that will be used by Routino to determine the data
+properties.
+
+<p>
+
+The <em>logerror</em> element will cause an error message to be added to the
+error log file that reports that the key and attribute combination are not
+recognised.  If the <em>k</em> attribute is specified but not the <em>v</em>
+attribute then the tag value that matches the specified key is looked up and
+used.  An additional <em>message</em> attribute can be specified to be printed
+at the end of the logged error.
+
+<p>
+The default logged error message is:
+<pre class="boxed">
+Node XXX has an unrecognised tag 'key' = 'value' (in tagging rules); ignoring it.
+</pre>
+
+<p>
+The specified <em>message</em> attribute will replace the final part of the
+logged error.
+
+
+<h3 id="H_1_1_2" title="Profiles">Routing Profiles</h3>
+
+The default name of the routing profiles XML configuration file
+is <em>profiles.xml</em> in the same directory as the database files.  Other
+filenames can be specified on the command line using the <tt>--tagging</tt>
+option.
+
+<p>
+
+The purpose of this configuration file is to allow easy modification of the
+routing parameters so that they do not all need to be specified on the command
+line.  In versions of Routino before version 1.4 the default routing parameters
+(preferred highways, preferred speeds etc) were contained in the source code,
+now they are in a configuration file.  When calculating a route
+the <tt>--profile</tt> option selects the named profile from the configuration
+file.
+
+<p>
+
+Part of the provided profiles.xml file showing the parameters for transport on
+foot is shown below:
+
+<pre class="boxed">
+<?xml version="1.0" encoding="UTF-8" ?>
+<routino-profiles>
+
+  <profile name="foot" transport="foot">
+    <speeds>
+...
+      <speed highway="cycleway"      kph="4" />
+      <speed highway="path"          kph="4" />
+      <speed highway="steps"         kph="4" />
+    </speeds>
+    <preferences>
+...
+      <preference highway="cycleway"      percent="95" />
+      <preference highway="path"          percent="100" />
+      <preference highway="steps"         percent="80" />
+    </preferences>
+    <properties>
+      <property type="paved"        percent="50" />
+      <property type="multilane"    percent="25" />
+      <property type="bridge"       percent="50" />
+      <property type="tunnel"       percent="50" />
+...
+    </properties>
+    <restrictions>
+      <oneway obey="0" /> 
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+  <profile name="horse" transport="horse">
+...
+  </profile>
+...
+</routino-profiles>
+</pre>
+
+
+<h3 id="H_1_1_3" title="Translations">Output Translations</h3>
+
+The default name of the output translations XML configuration file
+is <em>translations.xml</em> in the same directory as the database files.  Other
+filenames can be specified on the command line using the <tt>--translations</tt>
+option.
+
+<p>
+
+The generated HTML and GPX output files (described in the next section) are
+created using the fragments of text that are defined in this file.  Additional
+languages can be added to the file and are selected using
+the <tt>--language</tt> option to the router.  If no language is specified the
+first one in the file is used.
+
+<p>
+
+Part of the provided translations.xml file showing some of the English language
+(en) translations is shown below:
+
+<pre class="boxed">
+<?xml version="1.0" encoding="utf-8"?>
+<routino-translations>
+
+  <language lang="en">
+...
+    <turn direction="-4" string="Very sharp left" />
+    <turn direction="-3" string="Sharp left" />
+    <turn direction="-2" string="Left" />
+...
+    <heading direction="-4" string="South" />
+    <heading direction="-3" string="South-West" />
+    <heading direction="-2" string="West" />
+...
+    <route type="shortest" string="Shortest" />
+    <route type="quickest" string="Quickest" />
+    <output-html>
+...
+    </output-html>
+    <output-gpx>
+...
+    </output-gpx>
+  </language>
+</routino-translations>
+</pre>
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer">
+
+<address>
+© Andrew M. Bishop - <a href="http://www.routino.org/">http://www.routino.org/</a>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</body>
+
+</html>
diff --git a/3rdparty/Routino/doc/html/data.html b/3rdparty/Routino/doc/html/data.html
new file mode 100644
index 0000000..62895b8
--- /dev/null
+++ b/3rdparty/Routino/doc/html/data.html
@@ -0,0 +1,166 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<title>Routino : Data</title>
+
+<!--
+ Routino documentation - data
+
+ Part of the Routino routing software.
+
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see http://www.gnu.org/licenses/.
+-->
+
+<link href="style.css" type="text/css" rel="stylesheet">
+</head>
+
+<body>
+
+<!-- Header Start -->
+
+<div class="header">
+
+<h1>Routino : Data</h1>
+
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2 id="H_1_1">Data</h2>
+
+A router relies on data to be able to find a route.
+
+<h3 id="H_1_1_1">OpenStreetMap Data</h3>
+
+The data that is collected by the OpenStreetMap project consists of
+<em>nodes</em>, <em>ways</em> and <em>relations</em>.
+<dl>
+  <dt>Node
+  <dd>A node is a point that has a latitude and longitude and attributes that
+      describe what type of point it is (part of a way or a place of interest for
+      example).
+  <dt>Way
+  <dd>A way is a collection of nodes that when joined together define something
+      (for example a road, a railway, a boundary, a building, a lake etc).  The
+      ways also have attributes that define them (speed limits, type of road and
+      restrictions for example).
+  <dt>Relation
+  <dd>A relation is a collection of items (usually ways) that are related to
+      each other for some reason (highways that make up a route for example).
+</dl>
+
+The
+<a class="ext" title="OpenStreetMap Wiki" href="http://wiki.openstreetmap.org/wiki/Main_Page">OpenStreetMap Wiki</a>
+explains the data much better than I can.
+
+<h3 id="H_1_1_2">Router Data</h3>
+
+The information that is needed by a routing algorithm is only a subset of the
+information that is collected by the OpenStreetMap project.  For routing what is
+required is information about the location of roads (or other highways), the
+connections between the highways and the properties of those highways.
+<dl>
+  <dt>Location of highways (nodes)
+  <dd>The locations of things is provided by the nodes from the OpenStreetMap
+      data.  The nodes are the only things that have coordinates in
+      OpenStreetMap and everything else is made up by reference to them.  Not
+      all of the nodes are useful, only the ones that are part of highways.  The
+      location of the nodes is stored but none of the other attributes are
+      currently used by the router.
+  <dt>Location of highways (ways)
+  <dd>The location of the highways is defined in the OpenStreetMap data by the
+      ways.  Only the highway ways are useful and the other ways are discarded.
+      What remains is lists of nodes that join together to form a section of
+      highway.  This is further split into <em>segments</em> which are
+      individual parts of a way connected by two nodes.
+  <dt>Properties of highways (tags)
+  <dd>The ways that belong to highways are extracted from the data in the
+      previous step and for each way the useful information for routing is
+      stored.  For the router the useful information is the type of highway, the
+      speed limit, the allowed types of transport and other restrictions
+      (one-way, minimum height, maximum weight etc).
+  <dt>Connections between highways
+  <dd>The connections between highways are defined in the OpenStreetMap data by
+      ways that share nodes.  Since the ways may join in the middle and not just
+      the ends it is the segments defined above that are not part of the
+      OpenStreetMap data that are most important.
+</dl>
+
+The information that is extracted from the OpenStreetMap data is stored in an
+optimised way that allows the routing to be performed quickly.
+
+<h3 id="H_1_1_3" title="Data Tags">Interpreting Data Tags</h3>
+
+The <em>tags</em> are the information that is attached to the nodes and ways in
+OpenStreetMap.  The router needs to interpret these tags and use them when
+deciding what type of traffic can use a highway (for example).
+<p>
+
+There are no well defined rules in OpenStreetMap about tagging, but there is
+guidance on the
+<a class="ext" title="Map Features" href="http://wiki.openstreetmap.org/wiki/Map_Features">OpenStreetMap Wiki "Map_Features"</a>
+page.  This describes a set of recommended tags but these are not universally used
+so it is up to each application how to interpret them.
+<p>
+
+The <a title="Tagging" href="tagging.html">tagging rules</a> that the router
+uses are very important in controlling how the router works.  With Routino the
+data tags can be modified when the data is imported to allow customisation of
+the information used for routing.
+
+
+<h3 id="H_1_1_4" title="Problems With Data">Problems With OpenStreetMap Data</h3>
+
+The route that can be found is only as good as the data that is available.  This
+is not intended as a criticism of the OpenStreetMap data; it is generally good.
+<p>
+There are some problems that are well known and which affect the router.  For
+example highways might be missing because nobody has mapped them.  A highway may
+be wrongly tagged with incorrect properties, or a highway might be missing
+important tags for routing (e.g.  speed limits).  There can also be problems
+with highways that should join but don't because they do not share nodes.
+<p>
+A lot of these problems can be found using the interactive data visualiser that
+uses the same Routino routing database.
+
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer">
+
+<address>
+© Andrew M. Bishop - <a href="http://www.routino.org/">http://www.routino.org/</a>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</body>
+
+</html>
diff --git a/3rdparty/Routino/doc/html/example0.png b/3rdparty/Routino/doc/html/example0.png
new file mode 100644
index 0000000..1766a44
Binary files /dev/null and b/3rdparty/Routino/doc/html/example0.png differ
diff --git a/3rdparty/Routino/doc/html/example1.png b/3rdparty/Routino/doc/html/example1.png
new file mode 100644
index 0000000..8c5b085
Binary files /dev/null and b/3rdparty/Routino/doc/html/example1.png differ
diff --git a/3rdparty/Routino/doc/html/example2.png b/3rdparty/Routino/doc/html/example2.png
new file mode 100644
index 0000000..bd6608a
Binary files /dev/null and b/3rdparty/Routino/doc/html/example2.png differ
diff --git a/3rdparty/Routino/doc/html/example3.png b/3rdparty/Routino/doc/html/example3.png
new file mode 100644
index 0000000..6828842
Binary files /dev/null and b/3rdparty/Routino/doc/html/example3.png differ
diff --git a/3rdparty/Routino/doc/html/example4.png b/3rdparty/Routino/doc/html/example4.png
new file mode 100644
index 0000000..b0c196e
Binary files /dev/null and b/3rdparty/Routino/doc/html/example4.png differ
diff --git a/3rdparty/Routino/doc/html/index.html b/3rdparty/Routino/doc/html/index.html
new file mode 100644
index 0000000..56edbb3
--- /dev/null
+++ b/3rdparty/Routino/doc/html/index.html
@@ -0,0 +1,139 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<title>Routino : Documentation</title>
+
+<!--
+ Routino documentation - index
+
+ Part of the Routino routing software.
+
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see http://www.gnu.org/licenses/.
+-->
+
+<link href="style.css" type="text/css" rel="stylesheet">
+</head>
+
+<body>
+
+<!-- Header Start -->
+
+<div class="header">
+
+<h1>Routino : Documentation</h1>
+
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+
+<h2 id="H_1_1">Data</h2>
+
+A good router relies on good data and the
+<a class="ext" title="OpenStreetMap" href="http://www.openstreetmap.org/">OpenStreetMap</a>
+data is a good source.  There are however a number of things that need to be
+considered about
+<a href="data.html" title="Data considerations">the data used</a>.
+
+
+<h2 id="H_1_2">Tagging</h2>
+
+In addition to the raw data the way that are tags are used is also important.
+With Routino the
+<a title="Tagging" href="tagging.html">tagging rules</a>
+are contained in a configuration file and can easily be customised to change the
+interpretation of each tag.
+
+
+<h2 id="H_1_3">Program Usage</h2>
+
+There are four programs that make up this software, two create the routing
+database and use the information in it and the other two perform additional functions.
+<a href="usage.html" title="Program Usage">Full instructions</a>
+for using the four programs are provided.
+
+
+<h2 id="H_1_4">Configuration Files</h2>
+
+When the programs are run they read in one or more
+<a href="configuration.html" title="Configuration Files">configuration files</a>.
+These files contain information about the routing preferences (types of highways,
+preferred speeds etc), tagging rules and translation information for the outputs.
+
+
+<h2 id="H_1_5">Output Files</h2>
+
+The final result of running the router is one or more
+<a href="output.html" title="Output Files">output files</a>
+that contain the calculated route.
+
+
+<h2 id="H_1_6">Numerical Limits</h2>
+
+When processing data there are 
+<a href="limits.html" title="Numerical Limits">numerical limits</a> for the
+range of data identifiers that can be handled and the size of the database.
+
+
+<h2 id="H_1_7">Algorithm</h2>
+
+The <a title="Algorithm" href="algorithm.html">algorithm</a> that is used by
+Routino takes the OpenStreetMap data and creates a local database of the
+important information for rapid routing.
+
+
+<h2 id="H_1_8">Installation</h2>
+
+The Routino source code comes with a set of files that can be used to create
+a working server very easily.  The full information about
+<a href="installation.html" title="Installation">installation</a> describes how
+to compile the programs and install them on UNIX-like systems such as Linux.
+
+<p>
+
+Routino can also be compiled and used on Microsoft Windows systems (with some
+limitations).  There are specific
+<a href="installation-ms-windows.html" title="MS Windows Installation">MS Windows installation</a>
+instructions describing how to compile the programs.
+
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer">
+
+<address>
+© Andrew M. Bishop - <a href="http://www.routino.org/">http://www.routino.org/</a>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</body>
+
+</html>
diff --git a/3rdparty/Routino/doc/html/installation-ms-windows.html b/3rdparty/Routino/doc/html/installation-ms-windows.html
new file mode 100644
index 0000000..d8133be
--- /dev/null
+++ b/3rdparty/Routino/doc/html/installation-ms-windows.html
@@ -0,0 +1,229 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<title>Routino : Installation on MS Windows</title>
+
+<!--
+ Routino documentation - installation on MS Windows
+
+ Part of the Routino routing software.
+
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see http://www.gnu.org/licenses/.
+-->
+
+<link href="style.css" type="text/css" rel="stylesheet">
+</head>
+
+<body>
+
+<!-- Header Start -->
+
+<div class="header">
+
+<h1>Routino : Installation on MS Windows</h1>
+
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+
+<h2 id="H_1_1">Using Cygwin</h2>
+
+Cygwin is a large collection of GNU and Open Source tools which provide
+functionality similar to a Linux distribution on Windows.  A Cygwin DLL
+provides substantial POSIX API functionality therefore providing direct
+compatibility for most UNIX source code.
+
+<p>
+
+Since Cygwin aims to replicate a Linux-like system on Windows it is the simplest
+method of compiling Routino.  The disadvantage is that all programs compiled
+with Cygwin require a number of runtime Cygwin libraries which may introduce a
+runtime speed penalty.
+
+<p>
+
+The installer for Cygwin can be downloaded from <tt>http://cygwin.org/</tt>;
+there are 32-bit and 64-bit versions available.  For compiling Routino the
+Cygwin installer should be run and the following packages selected (any
+dependencies will be automatically be selected at the next step):
+
+<ul>
+  <li><i>base packages</i>
+  <li>gcc-core (in 'Devel' menu)
+  <li>make (in 'Devel' menu)
+  <li>libbz2-devel (in 'Libs' menu)
+  <li>zlib-devel (in 'Libs' menu)
+  <li>perl (in 'Perl' menu)
+</ul>
+
+<p>
+
+To compile Routino open the "Cygwin Terminal" change to the Routino source
+directory and compile using the <tt>make</tt> command.
+
+
+<h2 id="H_1_2">Native Compilation</h2>
+
+Routino has limited support in the source code for compiling on Microsoft
+Windows.  This includes a set of functions that can replace the <tt>mmap()</tt>
+and <tt>munmap()</tt> UNIX functions which are not available on Microsoft
+Windows.
+
+<p>
+
+The source code should be downloaded, either as a release version file or from
+subversion - no instructions are provided for this step.  The release versions
+include some files (mainly the web icons) which are not included in the
+subversion source (and which may be difficult to create on Windows).
+
+
+<h3 id="H_1_2_1">Using Microsoft Visual C</h3>
+
+The Routino source code (for the router at least) has been modified so that it
+will compile with the Microsoft Visual C compiler.
+
+<p>
+
+The files that need to be compiled for the Routino router can be found from the
+Makefile in the <tt>src</tt> directory listed in the <tt>ROUTER_OBJ</tt>
+variable.
+
+<p>
+
+To compile the router in slim mode the pre-processor definition <tt>SLIM=0</tt>
+must be set and for non-slim mode <tt>SLIM=1</tt> must be set.
+
+<p>
+
+The default directory for the Routino data files must be set in the
+<tt>ROUTINO_DATADIR</tt> pre-processor variable.  If the router command line
+<tt>--data</tt> option is going to be used then this variable can be set to any
+value.
+
+<p>
+
+Since Microsoft Visual C does not fully support the C99 standard it is necessary
+to tell the compiler how to handle the <tt>inline</tt> functions.  This can be
+done by passing in the command line option <tt>-Dinline=__inline</tt> to the C
+compiler.
+
+
+<h3 id="H_1_2_2">Using MinGW</h3>
+
+MinGW is the "Minimalist GNU for Windows" which includes some of the common GNU
+programs; principally gcc and related programs for software development.
+
+<p>
+
+The installer for MinGW can be downloaded from <tt>http://mingw.org/</tt>.  For
+compiling Routino the MinGW installer should be run and the following packages
+selected:
+
+<ul>
+  <li>mingw-base
+  <li>msys-base
+  <li>mingw32-pthreads-w32
+  <li>mingw32-libz (dev package)
+  <li>msys-perl
+</ul>
+
+<p>
+
+To compile Routino open a DOS command window and set the path to the installed
+MinGW and MSYS software.  For example if MinGW was installed in the
+<tt>C:/MinGW</tt> directory then the path needs to be set to
+<tt>C:\MinGW\bin;C:\MinGW\MSYS\1.0\bin</tt>.
+
+<p>
+
+From within this DOS command window change to the Routino source directory and
+compile using the MinGW version of <tt>make</tt> with this command
+<tt>mingw32-make MINGW=1</tt>.
+
+
+<h3 id="H_1_2_3">Using MinGW-W64</h3>
+
+MinGW-w64 is an alernative implementation of the same concept as MinGW but
+allows for compilation to 32-bit or 64-bit executables.
+
+<p>
+
+The website for MinGW-w64 is <tt>http://mingw-w64.org/</tt> but the downloads
+are available from <tt>http://win-builds.org/</tt>.
+
+<p>
+
+The compilation method for MinGW-w64 should be the same as for MinGW.
+
+
+<h3 id="H_1_2_4">Limitations</h3>
+
+A native Microsoft Windows compilation of Routino is more complicated than
+compiling on Linux, other UNIX system or Cygwin.  This is probably not an option
+if you are unfamiliar with software development on Microsoft Windows.
+
+<p>
+
+The size of files that can be accessed with an MSVC or MinGW compiled version of
+Routino is limited to 32-bits (about 2 GB).  The MinGW-w64 compiler on 64-bit
+windows might be able to handle larger files but has not been tested.
+
+<p>
+
+The Windows operating system does not have a function equivalent to the
+<tt>fork()</tt> function on UNIX.  This means that it is not possible to use
+the <tt>planetsplitter</tt> program's built-in file decompression with an MSVC
+or MinGW compiled version of Routino.
+
+
+<h2 id="H_1_3">Example Web Pages</h2>
+
+No instructions are available for using the Routino example web pages with the
+Microsoft Web server (IIS).
+
+<p>
+
+For information on setting up Apache see the "Example Web Pages" section of the
+main <a href="installation.html">installation instructions</a>.
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer">
+
+<address>
+© Andrew M. Bishop - <a href="http://www.routino.org/">http://www.routino.org/</a>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</body>
+
+</html>
diff --git a/3rdparty/Routino/doc/html/installation.html b/3rdparty/Routino/doc/html/installation.html
new file mode 100644
index 0000000..547f8a1
--- /dev/null
+++ b/3rdparty/Routino/doc/html/installation.html
@@ -0,0 +1,433 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<title>Routino : Installation</title>
+
+<!--
+ Routino documentation - installation
+
+ Part of the Routino routing software.
+
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see http://www.gnu.org/licenses/.
+-->
+
+<link href="style.css" type="text/css" rel="stylesheet">
+</head>
+
+<body>
+
+<!-- Header Start -->
+
+<div class="header">
+
+<h1>Routino : Installation</h1>
+
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+
+<h2 id="H_1_1">Quick Start Guide</h2>
+
+The instructions below are a complete list of the minimum required to get
+Routino installed and running under Apache on Debian Linux.  Other Linux
+versions will be similar and other UNIX based systems will also be similar
+although may have distinct differences.  There is some support in Routino for
+compiling on Microsoft Windows which has its own
+<a href="installation-ms-windows.html">installation instructions</a>.
+
+<p>
+
+<em>These instructions should not be considered as complete or a secure
+installation for the reasons given in more detail in
+the <a href="#H_1_5_1">Configuration of Web Files</a> section below.</em>
+
+<p>
+
+The starting point for the installation is in the Routino source code directory
+after it has been uncompressed.  Most of the steps will need to be run as the
+root user.
+
+<p>
+
+The first thing to do is to install the packages which are required for
+compilation of Routino as described in the <a href="#H_1_2">Pre-Requisites</a>
+section below.
+
+<pre class="boxed">
+apt-get install gcc make libc6-dev libz-dev libbz2-dev
+</pre>
+
+After this the programs can be compiled:
+
+<pre class="boxed">
+make
+</pre>
+
+The files for the web interface can now be copied to the web server directory.
+On Debian this is <tt>/var/www</tt> and the files changed to be owned by the
+user Apache runs as.
+
+<pre class="boxed">
+cp -a web /var/www/routino
+chown -R www-data:www-data /var/www/routino
+</pre>
+
+To be able to use Routino some data will need to be processed and a script is
+provided for this.  This will download the data for the UK which may take a
+while and then process it.
+
+<pre class="boxed">
+cd /var/www/routino/data
+sh -x create.sh
+</pre>
+
+The routino web pages also requires either the OpenLayers or Leaflet Javascript
+library to be downloaded and installed and scripts are provided for this.
+
+<pre class="boxed">
+cd /var/www/routino/www/openlayers
+sh -x install.sh
+</pre>
+
+<pre class="boxed">
+cd /var/www/routino/www/leaflet
+sh -x install.sh
+</pre>
+
+To make full use of the location search feature on the Routino web page you will
+need to install some extra perl packages.
+
+<pre class="boxed">
+apt-get install libwww-perl liburi-perl libjson-pp-perl
+</pre>
+
+Finally to make the web pages work you will need to add the extra lines to the
+Apache configuration file as described in the <a href="#H_1_5_2">Configuration of
+Web Server</a> section below.  You don't have to use <tt>vi</tt> and can use any
+text editor.
+
+<pre class="boxed">
+vi /etc/apache2/sites-enabled/000-default
+apache2ctl restart
+</pre>
+
+Now everything should be set up and the web page should work if accessed at
+http://localhost/routino/www/routino/router.html.
+
+<p>
+
+When everything is working you should read the rest of this document carefully
+and make the following changes:
+
+<ul>
+  <li>Download your choice of OSM data - edit the file <tt>data/create.sh</tt>
+    and run it again.
+  <li>Edit the <tt>www/routino/mapprops.js</tt> file to match the downloaded
+    data and personal map preferences.
+  <li>Move the files in the web server directory so that only the contents of
+    the <tt>www</tt> directory are accessible by the web server.
+  <li>Edit the file <tt>www/routino/paths.pl</tt> to reference the new file
+    locations.
+</ul>
+
+
+<h2 id="H_1_2">Pre-Requisites</h2>
+
+The programs are written in standard C language with minimal external
+requirements so only a small set of development tools are required (gcc, make).
+The compilation tools to use and the command line options are defined in the
+file <tt>Makefile.conf</tt>.
+
+<p>
+
+There is some support for multi-threading that uses pthreads and additional
+development libraries for this may be required (on Linux this might be part of
+the standard C language development files).  The multi-threading is enabled by
+default but can be disabled at compile time by commenting out two lines in the
+file <tt>Makefile.conf</tt>.
+
+<p>
+
+To use the built-in gzip file decompression function and to process all PBF
+format files the zlib (or libz) development library is required (on Linux this
+might be in a package called libz-dev).  The gzip function is enabled by default
+but can be disabled by commenting out two lines in the
+file <tt>Makefile.conf</tt>.
+
+<p>
+
+To use the built-in bzip2 file decompression functions the bzip2 (or libbz2)
+development library is required (on Linux this might be in a package called
+libbz2-dev).  The bzip2 function is enabled by default but can be disabled by
+commenting out two lines in the file <tt>Makefile.conf</tt>.
+
+<p>
+
+To use the built-in xz file decompression functions the liblzma development
+library is required (on Linux this might be in a package called liblzma-dev).
+The xz function is not enabled by default but can be enabled by uncommenting
+two lines in the file <tt>Makefile.conf</tt>.
+
+<p>
+
+To compile the source code from subversion requires the Perl Graphics::Magick
+module to generate the web page icons (on Linux this might be in a package
+called libgraphics-magick-perl).  The released source code packages contains the
+icons so this package is not required for compilation.
+
+<p>
+
+To use the web page interface an http server is required.  Instructions below
+are for Apache but any server that supports CGIs should work.
+
+<p>
+
+The web pages use the Perl scripting language and a number of the default Perl
+modules.  To use the search function on the router web page the Perl module
+JSON::PP must be installed (on Linux this might be in a package called
+libjson-pp-perl if not part of the standard Perl installation).
+
+
+<h2 id="H_1_3">Compilation</h2>
+
+To compile the programs just type <tt>make</tt> at the top level of the source
+tree.
+
+<p>
+
+This program has been written to run on Linux, no cross-platform compatibility
+has been specifically included but on the other hand other platforms have not
+knowingly been excluded either.
+
+<p>
+
+Any information on improving the compilation process on anything other than x86
+Linux is welcome.
+
+
+<h2 id="H_1_4">Installation</h2>
+
+After compilation the executable files are copied into the directory
+<tt>web/bin</tt> and the default XML configuration files are copied into the
+directory <tt>web/data</tt>.  This is in preparation for using the supplied
+example web pages but is also a useful location to copy the files from for
+normal use.
+
+<p>
+
+The required executable files are <tt>planetsplitter</tt>, <tt>router</tt> and
+<tt>filedumper</tt> and the <tt>*-slim</tt> versions of the same files.  They
+can be copied to any location and need no special installation environment.
+The <tt>filedumperx</tt> executable is for debugging and not required.
+
+<p>
+
+The configuration files are called <tt>profiles.xml</tt>, <tt>tagging.xml</tt>
+and <tt>translations.xml</tt>.  The names of the configuration files can be
+specified on the command line but by default are also looked for in the
+directory that contains the routing database with these names.
+
+
+<h2 id="H_1_5">Example Web Page</h2>
+
+The directory <tt>web</tt> contains a set of files that can be used to create a
+working set of web pages with interfaces to the routing algorithm.
+
+<p>
+
+The files in the <tt>web</tt> directory will require copying to a location that
+is accessible by a web server.  After copying the files some of them need to be
+edited; search through the files for lines that contain the words "EDIT THIS"
+and make appropriate edits (more details below).
+
+
+<h3 id="H_1_5_1">Configuration of Web Files</h3>
+
+The assumption in this description is that the whole of the directory called
+<tt>web</tt> is copied into a directory that is accessible by an Apache web
+server.
+
+<p>
+
+<em>This is not a secure configuration but an easy one to configure.</em>
+<br>
+<em>Only the directory <tt>www</tt> should be accessible by the web server.</em>
+<em>Do not use this configuration unmodified in a public web server.</em>
+
+<p>
+
+The directory structure is as follows:
+
+<pre>
+   web/
+    |
+    + /bin/                    <- The Routino executable files (when compiled).
+    |
+    + /data/                   <- The Routino database and default configuration
+    |                             files.
+    |
+    + /results/                <- An empty directory to store the results.
+    |
+    + /www/                    <- The files that must be available to the web
+        |                         server are below this level.
+        |
+        + /openlayers/         <- A directory to hold the OpenLayers library
+        |                         (optional; leaflet can be used instead).
+        |
+        + /leaflet/            <- A directory to hold the Leaflet library.
+        |                         (optional; openlayers can be used instead).
+        |
+        + /routino/            <- The main HTML, Javascript, CSS and CGI files.
+            |
+            + /documentation/  <- The HTML version of the Routino documentation.
+</pre>
+
+The directory <tt>bin</tt> will be filled by running the compilation process.
+For a secure installation the <tt>bin</tt> directory should be outside of the
+web server, the file <tt>www/routino/paths.pl</tt> contains the path to
+the <tt>bin</tt> directory.
+
+<p>
+
+The directory <tt>data</tt> must contain the Routino database and is also the
+default location for the configuration files.  The routing database is created
+by downloading the OSM files for the region of interest and running the
+planetsplitter program.  There is a script in the directory that will download
+the OSM files and create the required database.  The script should be edited to
+set the names of the files to be downloaded.  For a secure installation
+the <tt>data</tt> directory should be outside of the web server, the
+file <tt>www/routino/paths.pl</tt> contains the path to the <tt>data</tt>
+directory.
+
+<p>
+
+The directory <tt>results</tt> is a temporary directory that it used to hold the
+GPX and text files generated by the Routino router.  The directory must be
+writable by the web server process since it is the CGI scripts that are run by
+the web server that writes the results here.  For a secure installation
+the <tt>results</tt> directory should be outside of the web server, the file
+<tt>www/routino/paths.pl</tt> contains the path to the <tt>results</tt> directory.
+
+<p>
+
+The directory <tt>www</tt> and its sub-directories are the only ones that need
+to be within the web server accessible directory.
+
+<p>
+
+A Javascript map drawing library is required and either OpenLayers or Leaflet
+can be used.  The library is loaded dynamically when the HTML is opened based on
+the value that is selected in <tt>mapprops.js</tt>.
+
+<p>
+
+The directory <tt>www/openlayers</tt> is for the OpenLayers Javascript library
+that can be downloaded from http://www.openlayers.org/.  (This version of
+Routino has been tested with OpenLayers library versions 2.12 and 2.13.1).  The
+file <tt>www/openlayers/OpenLayers.js</tt> and the directories
+<tt>www/openlayers/img/</tt> and <tt>www/openlayers/theme/</tt> must all exist.
+There is a script in the <tt>www/openlayers</tt> directory that will
+automatically download the files, create an optimised <tt>OpenLayers.js</tt> and
+copy the files to the required locations.
+
+<p>
+
+The directory <tt>www/leaflet</tt> is for the Leaflet Javascript library that
+can be downloaded from http://leafletjs.com/.  (This version of Routino has been
+tested with Leaflet library versions 0.7.1 and 0.7.2).  The files
+<tt>www/leaflet/leaflet.js</tt> and <tt>www/leaflet/leaflet.css</tt> and the
+directory <tt>www/leaflet/images/</tt> must all exist.  There is a script in the
+<tt>www/leaflet</tt> directory that will automatically download the files.
+
+<p>
+
+The directory <tt>www/routino</tt> contains the main HTML, Javascript and CSS
+files as well as the CGI scripts that perform the server-side routing functions.
+The description below lists all of the files that contain editable information.
+
+<dl>
+  <dt><tt>paths.pl</tt>
+  <dd>This contains the names of the directories that contain the executable
+      files, router database and temporary results; the prefix for the routing
+      database; and the names of the executables.
+  <dt><tt>mapprops.js</tt>
+  <dd>The parameters in this file control the Javascript map library (defaults
+      to OpenLayers), the boundary of the visible map (defaults to UK), the
+      minimum and maximum zoom levels (defaults to between 4 and 15 inclusive),
+      the source of map tiles (defaults to the main OpenStreetMap tile server),
+      the data editing and browsing URLs (default to the OpenStreetMap website)
+      and the number of waypoints allowed (defaults to 9).
+</dl>
+
+<p>
+
+The directory <tt>www/routino/documentation</tt> contains the HTML version of
+the Routino documentation.
+
+
+<h3 id="H_1_5_2">Configuration of Web Server</h3>
+
+The file <tt>www/routino/.htaccess</tt> contains all of the Apache configuration
+options that are required to get the example web pages running.  The only
+problem is that because of the way that the <tt>AllowOverride</tt> option works
+one of the configuration options has been commented out.  This must be enabled
+in the main Apache server configuration file.
+
+<p>
+
+If you have copied the routino <tt>web</tt> directory into <tt>/var/www</tt> and
+named it <tt>routino</tt> then the entry that you need in your Apache
+configuration file is this one:
+
+<pre>
+     <Directory /var/www/routino>
+         AllowOverride All
+         Options +ExecCGI
+     </Directory>
+</pre>
+
+This can be placed anywhere between the <tt><VirtualHost *:80></tt>
+and <tt></VirtualHost></tt> tags which should be at the start and end of
+the file.
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer">
+
+<address>
+© Andrew M. Bishop - <a href="http://www.routino.org/">http://www.routino.org/</a>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</body>
+
+</html>
diff --git a/3rdparty/Routino/doc/html/limits.html b/3rdparty/Routino/doc/html/limits.html
new file mode 100644
index 0000000..eb100bf
--- /dev/null
+++ b/3rdparty/Routino/doc/html/limits.html
@@ -0,0 +1,243 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<title>Routino : Numerical Limits</title>
+
+<!--
+ Routino documentation - ID limits
+
+ Part of the Routino routing software.
+
+ This file Copyright 2013-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see http://www.gnu.org/licenses/.
+-->
+
+<link href="style.css" type="text/css" rel="stylesheet">
+</head>
+
+<body>
+
+<!-- Header Start -->
+
+<div class="header">
+
+<h1>Routino : Numerical Limits</h1>
+
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2 id="H_1_1">32/64-bit Data IDs</h2>
+
+The
+<a class="ext" title="OpenStreetMap" href="http://www.openstreetmap.org/">OpenStreetMap</a>
+data uses a numerical identifier for each node, way and relation.  These
+identifiers started at 1 and increase for every new item of each type that is
+added.  When an object is deleted the identifier is not re-used so the highest
+identifier will always be higher than the number of objects.
+
+<p>
+The identifier needs to be handled carefully to ensure that it does not overflow
+the data type allocated for it.  Depending on the data type used to store the
+identifier there are are a number of numerical limits as described below:
+
+<ol>
+  <li>If a signed 32-bit integer is used to store the identifier then the
+    maximum value that can be handled is 2147483647 (2<sup>31</sup>-1) before
+    overflow.
+  <li>If an unsigned 32-bit integer is used to store the identifier then the
+    maximum value that can be handled is 4294967295 (2<sup>32</sup>-1) before
+    overflow.
+  <li>If a signed 64-bit integer is used to store the identifier then the
+    maximum value that can be handled is 9223372036854775807 (2<sup>63</sup>-1)
+    before overflow.
+</ol>
+
+For the purposes of this document the possibility of overflow of a 64-bit
+integer is ignored.
+
+<p>
+The part of Routino that handles the node, way and relation identifiers is the
+<tt>planetsplitter</tt> program.
+
+
+<h3 id="H_1_1_1">ID Above 31-bits</h3>
+
+The first identifier exceeding 31-bits (for a node) is predicted to be created
+in the OpenStreetMap database in February 2013.
+
+<p>
+All versions of Routino use unsigned 32-bit integers to store the identifier.
+Therefore all versions of Routino will continue working correctly when node
+number 2147483648 (2<sup>31</sup>) or higher is present.
+
+
+<h3 id="H_1_1_2">ID Above 32-bits</h3>
+
+The ability of Routino to handle identifiers larger than 32-bits does not depend
+on having a 64-bit operating system.
+
+<p>
+Before version 2.0.1 of Routino there was no check that the identifier read from
+the input data would fit within an unsigned 32-bit integer.  Earlier versions of
+Routino will therefore fail to report an error and will process data incorrectly
+when node number 4294967296 (2<sup>32</sup>) or higher is present.
+
+<p>
+From version 2.0.2 the code is written to allow the node, way and relation
+identifier data type to be changed to 64-bits.  This means that a consistent
+data type is used for handling identifiers and the format used for printing them
+is consistent with the variable type.
+
+<p>
+From version 2.0.2 onwards it is possible to make a simple change to the code to
+process data with node identifiers above 4294967296 (2<sup>32</sup>) without
+error.  The binary format of the database will be unchanged by the use of 64-bit
+identifiers (since the identifiers are not stored in the database).
+
+<p>
+To recompile with 64-bit node identifiers the file <tt>src/typesx.h</tt> should
+be edited and the two lines below changed from:
+
+<pre class="boxed">
+typedef uint32_t node_t;
+
+#define Pnode_t PRIu32
+</pre>
+
+to:
+
+<pre class="boxed">
+typedef uint64_t node_t;
+
+#define Pnode_t PRIu64
+</pre>
+
+<p>
+A similar change can also be made for way or relation identifiers although since
+there are currently fewer of these the limit is not as close to being reached.
+
+<p>
+Between version 2.0.2 and version 2.4 a bug means that route relations will
+ignore the way or relation identifier if it is equal to 4294967295
+(2<sup>32</sup>-1).
+
+<p>
+From version 2.4 onwards when a numerical limit is reached the
+<tt>planetsplitter</tt> program will exit with an error message that describes
+which limit was reached and which data type needs to be changed.
+
+
+<h2 id="H_1_2">Database Format</h2>
+
+The other limitation in Routino is the number of objects stored in the database
+that is generated by the <tt>planetsplitter</tt> data processing.  This number
+may be significantly different from the highest identifier in the input data set
+for two reasons.  Firstly any nodes, ways or relations that have been deleted
+will not be present in the data.  Secondly when a partial planet database
+(continent, country or smaller) is processed there will be only a fraction of
+the total number of nodes, ways and relations.
+
+<p>
+The limiting factor is the largest of the following.
+<ol>
+  <li>The number of nodes in the input data files.
+  <li>The number of segments in the input data files.
+  <li>The number of highways in the input data files.
+  <li>The number of relations in the input data files.
+</ol>
+
+Normally the number of nodes will be the limiting factor.
+
+
+<h3 id="H_1_2_1">32-bit Indexes</h3>
+
+Before version 1.2 the database could hold up to 4294967295 (2<sup>32</sup>-1)
+items of each type (node, segment, way) since an unsigned 32-bit integer is
+used.
+
+<p>
+Versions 1.3 to 1.4.1 have a limit of 2147483647 (2<sup>31</sup>-1) items since
+half of the 32-bit integer range is reserved for fake nodes and segments that
+are inserted if a waypoint is not close to a node.
+
+<p>
+From version 1.5 the limit is 4294901760 (2<sup>32</sup>-2<sup>16</sup>) for the
+number of items of each type that can be stored.  The small remaining part of
+the 32-bit unsigned integer range is reserved for fake nodes and segments.
+
+
+<h3 id="H_1_2_2">64-bit Indexes</h3>
+
+When using a 32-bit operating system it is not possible to create a database
+that exceeds about 2GB in total.  This will be fewer than 2<sup>32</sup> objects
+in the database in total.  The use of 64-bit indexes will require a 64-bit
+operating system.
+
+<p>
+From version 2.0.2 onwards it is possible to make a simple change to the code to
+index the database objects with 64-bit integers insted of 32-bit integers.
+
+<p>
+To recompile with 64-bit index integers the file <tt>src/types.h</tt> should be
+edited and the two lines below changed from:
+
+<pre class="boxed">
+typedef uint32_t index_t;
+
+#define Pindex_t PRIu32
+</pre>
+
+to:
+
+<pre class="boxed">
+typedef uint64_t index_t;
+
+#define Pindex_t PRIu64
+</pre>
+
+This change will affect nodes, segments, ways and relations together.  The
+database that is generated will no longer be compatible with Routino that has
+been compiled with 32-bit indexes.  The size of the database will also grow by
+about 50% when this change is made.
+
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer">
+
+<address>
+© Andrew M. Bishop - <a href="http://www.routino.org/">http://www.routino.org/</a>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</body>
+
+</html>
diff --git a/3rdparty/Routino/doc/html/output.html b/3rdparty/Routino/doc/html/output.html
new file mode 100644
index 0000000..467bf4e
--- /dev/null
+++ b/3rdparty/Routino/doc/html/output.html
@@ -0,0 +1,409 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<title>Routino : Output</title>
+
+<!--
+ Routino documentation - output
+
+ Part of the Routino routing software.
+
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see http://www.gnu.org/licenses/.
+-->
+
+<link href="style.css" type="text/css" rel="stylesheet">
+</head>
+
+<body>
+
+<!-- Header Start -->
+
+<div class="header">
+
+<h1>Routino : Output</h1>
+
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2 id="H_1_1">Router Output</h2>
+
+There are three different formats of output from the router, HTML,
+<a class="ext" title="GPX format" href="http://www.topografix.com/gpx.asp">GPX (GPS eXchange) XML format</a>
+and plain text with a total of five possible output files:
+<ul>
+  <li>HTML route instructions for each interesting junction.
+  <li>GPX track file containing every node.
+  <li>GPX route file with waypoints at interesting junctions.
+  <li>Plain text description with the interesting junctions.
+  <li>Plain text file with every node.
+</ul>
+
+The "interesting junctions" referred to above are junctions where the route
+changes to a different type of highway, more than two highways of the same type
+meet, or where the route meets but does not take a more major highway.  When the
+route follows a major road this definition eliminates all junctions with minor
+roads.
+
+<p>
+
+The output files are written to the current directory and are named depending on
+the selection of shortest or quickest route. For the shortest route the file
+names are "shortest.html", "shortest-track.gpx", "shortest-route.gpx",
+"shortest.txt" and "shortest-all.txt", for the quickest route the names are
+"quickest.html", "quickest-track.gpx", "quickest-route.gpx", "quickest.txt" and
+"quickest-all.txt".
+
+<p>
+
+The HTML file and GPX files are written out according to the selected language
+using the translations contained in the translations.xml configuration file.
+The text files contains untranslated header lines (in English) but the data is
+translated.
+
+<!-- For reference the examples were produced from the following URL:
+     http://www.routino.org/uk/router.html?transport=motorcar;lon1=-0.12790;lat1=51.52468;lon2=-0.10365;lat2=51.47824 -->
+
+<h3 id="H_1_1_1" title="HTML file">HTML Route Instructions</h3>
+
+The HTML route instructions file contains one line for the description of each
+of the interesting junctions in the route and one line for each of the highways
+that connect them.  The coordinates are also included in the file but are not
+visible because of the style definitions.
+
+<p>
+
+An example HTML file output is below (some parts are missing, for example the
+style definitions):
+
+<pre class="boxed">
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<!-- Creator : Routino - http://www.routino.org/ -->
+<!-- Source : Based on OpenStreetMap data from http://www.openstreetmap.org/ -->
+<!-- License : http://www.openstreetmap.org/copyright -->
+<HEAD>
+<TITLE>Shortest Route</TITLE>
+...
+</HEAD>
+<BODY>
+<H1>Shortest Route</H1>
+<table>
+<tr class='c'><td class='l'>1:<td class='r'>51.524658 -0.127877
+<tr class='n'><td class='l'>Start:<td class='r'>At <span class='w'>Waypoint</span>, head <span class='b'>South-East</span>
+<tr class='s'><td class='l'>Follow:<td class='r'><span class='h'>Woburn Place (A4200)</span> for <span class='d'>0.251 km, 0.3 min</span> [<span class='j'>0.3 km, 0 minutes</span>]
+<tr class='c'><td class='l'>2:<td class='r'>51.522811 -0.125781
+<tr class='n'><td class='l'>At:<td class='r'>Junction, go <span class='t'>Straight on</span> heading <span class='b'>South-East</span>
+<tr class='s'><td class='l'>Follow:<td class='r'><span class='h'>Russell Square (A4200)</span> for <span class='d'>0.186 km, 0.2 min</span> [<span class='j'>0.4 km, 1 minutes</span>]
+<tr class='c'><td class='l'>3:<td class='r'>51.521482 -0.124123
+<tr class='n'><td class='l'>At:<td class='r'>Junction, go <span class='t'>Straight on</span> heading <span class='b'>South-East</span>
+<tr class='s'><td class='l'>Follow:<td class='r'><span class='h'>Southampton Row (A4200)</span> for <span class='d'>0.351 km, 0.4 min</span> [<span class='j'>0.8 km, 1 minutes</span>]
+...
+<tr class='c'><td class='l'>21:<td class='r'>51.477678 -0.106792
+<tr class='n'><td class='l'>At:<td class='r'>Junction, go <span class='t'>Slight left</span> heading <span class='b'>South-East</span>
+<tr class='s'><td class='l'>Follow:<td class='r'><span class='h'>Vassall Road</span> for <span class='d'>0.138 km, 0.2 min</span> [<span class='j'>6.3 km, 6 minutes</span>]
+<tr class='c'><td class='l'>22:<td class='r'>51.478015 -0.104870
+<tr class='n'><td class='l'>At:<td class='r'>Junction, go <span class='t'>Straight on</span> heading <span class='b'>East</span>
+<tr class='s'><td class='l'>Follow:<td class='r'><span class='h'>Vassall Road</span> for <span class='d'>0.087 km, 0.1 min</span> [<span class='j'>6.4 km, 6 minutes</span>]
+<tr class='c'><td class='l'>23:<td class='r'>51.478244 -0.103651
+<tr class='n'><td class='l'>Stop:<td class='r'>At <span class='w'>Waypoint</span>
+<tr class='t'><td class='l'>Total:<td class='r'><span class='j'>6.4 km, 6 minutes</span>
+</table>
+</BODY>
+</HTML>
+</pre>
+
+
+<h3 id="H_1_1_2" title="GPX track file">GPX Track File</h3>
+
+The GPX track file contains a track with all of the individual nodes that the
+route passes through.
+
+<p>
+
+An example GPX track file output is below:
+
+<pre class="boxed">
+<?xml version="1.0" encoding="UTF-8"?>
+<gpx version="1.1" creator="Routino" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/1" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
+<metadata>
+<desc>Creator : Routino - http://www.routino.org/</desc>
+<copyright author="Based on OpenStreetMap data from http://www.openstreetmap.org/">
+<license>http://www.openstreetmap.org/copyright</license>
+</copyright>
+</metadata>
+<trk>
+<name>Shortest route</name>
+<desc>Shortest route between 'start' and 'finish' waypoints</desc>
+<trkpt lat="51.524658" lon="-0.127877"/>
+<trkpt lat="51.523768" lon="-0.126918"/>
+<trkpt lat="51.522811" lon="-0.125781"/>
+...
+<trkpt lat="51.478015" lon="-0.104870"/>
+<trkpt lat="51.478127" lon="-0.104174"/>
+<trkpt lat="51.478244" lon="-0.103651"/>
+</trkseg>
+</trk>
+</gpx>
+</pre>
+
+
+<h3 id="H_1_1_3" title="GPX route file">GPX Route File</h3>
+
+The GPX route file contains a route (ordered set of waypoints) with all of the
+interesting junctions that the route passes through and a description of the
+route to take from that point.
+
+<p>
+
+An example GPX route file output is below:
+
+<pre class="boxed">
+<?xml version="1.0" encoding="UTF-8"?>
+<gpx version="1.1" creator="Routino" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/1" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
+<metadata>
+<desc>Creator : Routino - http://www.routino.org/</desc>
+<copyright author="Based on OpenStreetMap data from http://www.openstreetmap.org/">
+<license>http://www.openstreetmap.org/copyright</license>
+</copyright>
+</metadata>
+<rte>
+<name>Shortest route</name>
+<desc>Shortest route between 'start' and 'finish' waypoints</desc>
+<rtept lat="51.524658" lon="-0.127877">
+  <name>START</name>
+  <desc>South-East on 'Woburn Place (A4200)' for 0.251 km, 0.3 min</desc>
+</rtept>
+<rtept lat="51.522811" lon="-0.125781">
+  <name>TRIP001</name>
+  <desc>South-East on 'Russell Square (A4200)' for 0.186 km, 0.2 min</desc>
+</rtept>
+<rtept lat="51.521482" lon="-0.124123">
+  <name>TRIP002</name>
+  <desc>South-East on 'Southampton Row (A4200)' for 0.351 km, 0.4 min</desc>
+</rtept>
+...
+<rtept lat="51.477678" lon="-0.106792">
+  <name>TRIP020</name>
+  <desc>South-East on 'Vassall Road' for 0.138 km, 0.2 min</desc>
+</rtept>
+<rtept lat="51.478015" lon="-0.104870">
+  <name>TRIP021</name>
+  <desc>East on 'Vassall Road' for 0.087 km, 0.1 min</desc>
+</rtept>
+<rtept lat="51.478244" lon="-0.103651">
+  <name>FINISH</name>
+  <desc>Total Journey 6.4 km, 6 minutes</desc>
+</rtept>
+</rte>
+</gpx>
+</pre>
+
+
+<h3 id="H_1_1_4" title="Text file">Text File</h3>
+
+The text file format contains one entry for all of the interesting junctions in
+the route and is intended to be easy to interpret, for example for creating
+other output formats.
+
+<p>
+
+An example text file output is below:
+
+<pre class="boxed">
+# Creator : Routino - http://www.routino.org/
+# Source : Based on OpenStreetMap data from http://www.openstreetmap.org/
+# License : http://www.openstreetmap.org/copyright
+#
+#Latitude   Longitude  Section   Section  Total    Total    Point Turn Bearing Highway
+#                      Distance  Duration Distance Duration Type
+ 51.524658  -0.127877  0.000 km  0.0 min  0.0 km   0 min    Waypt  +3          Woburn Place (A4200)
+ 51.522811  -0.125781  0.251 km  0.3 min  0.3 km   0 min    Junct  +0  +3      Russell Square (A4200)
+ 51.521482  -0.124123  0.186 km  0.2 min  0.4 km   1 min    Junct  +0  +3      Southampton Row (A4200)
+...
+ 51.477678  -0.106792  0.204 km  0.2 min  6.1 km   5 min    Junct  +0  +3      Vassall Road
+ 51.478015  -0.104870  0.138 km  0.2 min  6.3 km   6 min    Junct  +0  +2      Vassall Road
+ 51.478244  -0.103651  0.087 km  0.1 min  6.4 km   6 min    Waypt
+</pre>
+
+<p>
+
+The text file output contains a header (indicated by the lines starting with
+'#') and then one line for each waypoint or junction.  Each line contains the
+information for the current node and the next segment to be followed.
+
+For each of the lines the individual fields contain the following:
+
+<table>
+  <tr>
+    <th>Item
+    <th class=left>Description
+  <tr>
+    <td>Latitude
+    <td>Location of the node (degrees)
+  <tr>
+    <td>Longitude
+    <td>Location of the node (degrees)
+  <tr>
+    <td>Section Distance
+    <td>The distance travelled on the section of the journey that ends at this
+      node.
+  <tr>
+    <td>Section Duration
+    <td>The duration of travel on the section of the journey that ends at this
+      node.
+  <tr>
+    <td>Total Distance
+    <td>The total distance travelled up to this point.
+  <tr>
+    <td>Total Duration
+    <td>The total duration of travel up to this point.
+  <tr>
+    <td>Point Type
+    <td>The type of point; either a waypoint <em>Waypt</em> or junction
+      <em>Junct</em>.
+  <tr>
+    <td>Turn
+    <td>The direction to turn at this point (missing for the first line since
+      the journey has not started yet and for the last line because it has
+      finished).  This can take one of nine values between -4 and +4 defined by:
+      0 = <em>Straight</em>, +2 = <em>Right</em>, -2 = <em>Left</em> and +/-4
+      = <em>Reverse</em>.
+  <tr>
+    <td>Bearing
+    <td>The direction to head from this point (missing for the last line since
+      the journey has finished).  This can take one of nine values between -4
+      and +4 defined by: 0 = <em>North</em>, +2 = <em>East</em>, -2
+      = <em>West</em> and +/-4 = <em>South</em>.
+  <tr>
+    <td>Highway
+    <td>The name (or description) of the highway to follow from this point
+      (missing on the last line since the journey has finished).
+</table>
+
+<p>
+
+The individual items are separated by tabs but some of the items contain spaces
+as well.
+
+
+<h3 id="H_1_1_5" title="All nodes text file">All Nodes Text File</h3>
+
+The all nodes text file format contains one entry for each of the nodes on the
+route.
+
+<p>
+
+An example all nodes text file output is below:
+
+<pre class="boxed">
+# Creator : Routino - http://www.routino.org/
+# Source : Based on OpenStreetMap data from http://www.openstreetmap.org/
+# License : http://www.openstreetmap.org/copyright
+#
+#Latitude   Longitude  Node      Type   Segment Segment Total Total   Speed Bearing Highway
+#                                       Dist    Durat'n Dist  Durat'n
+ 51.524658  -0.127877  8439703*  Waypt   0.000  0.00    0.00   0.0   
+ 51.523768  -0.126918  8439948*  Junct-  0.119  0.15    0.12   0.1     96    146    Woburn Place (A4200)
+ 51.522811  -0.125781  8440207*  Junct   0.132  0.17    0.25   0.3     96    143    Woburn Place (A4200)
+...
+ 51.478015  -0.104870  8529638*  Change  0.138  0.17    6.26   5.6     48     74    Vassall Road
+ 51.478127  -0.104174  8529849*  Junct-  0.049  0.04    6.31   5.7     64     75    Vassall Road
+ 51.478244  -0.103651  8530008   Waypt   0.038  0.04    6.35   5.7     64     70    Vassall Road
+</pre>
+
+<p>
+
+The all nodes text file output contains a header (indicated by the lines
+starting with '#') and then one line for each node and the segment that was used
+to reach it.  This file therefore contains exactly the same model as is used
+internally to define a route (a series of results each of which is a node and
+the segment leading to it).
+
+For each of the lines the individual fields contain the following:
+
+<table>
+  <tr>
+    <th>Item
+    <th class=left>Description
+  <tr>
+    <td>Latitude
+    <td>Location of the node in degrees.
+  <tr>
+    <td>Longitude
+    <td>Location of the node in degrees.
+  <tr>
+    <td>Node
+    <td>The internal node number and an indicator "*" if the node is a super-node.
+  <tr>
+    <td>Type
+    <td>The type of point; a waypoint <em>Waypt</em>, important
+      junction <em>Junct</em>, unimportant junction <em>Junct-</em>, change of
+      highway <em>Change</em> or intermediate node <em>Inter</em>.
+  <tr>
+    <td>Segment Distance
+    <td>The distance travelled on the segment defined on this line.
+  <tr>
+    <td>Segment Duration
+    <td>The duration of travel on the segment defined on this line.
+  <tr>
+    <td>Total Distance
+    <td>The total distance travelled up to this point.
+  <tr>
+    <td>Total Duration
+    <td>The total duration of travel up to this point.
+  <tr>
+    <td>Speed
+    <td>The speed of travel on the segment defined on this line (missing on the
+      first line).
+  <tr>
+    <td>Bearing
+    <td>The direction that the segment defined on this line travels in degrees
+      (missing on the first line).
+  <tr>
+    <td>Highway
+    <td>The name (or description) of the highway segment (missing on the first
+      line).
+</table>
+
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer">
+
+<address>
+© Andrew M. Bishop - <a href="http://www.routino.org/">http://www.routino.org/</a>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</body>
+
+</html>
diff --git a/3rdparty/Routino/doc/html/readme.html b/3rdparty/Routino/doc/html/readme.html
new file mode 100644
index 0000000..ddc390f
--- /dev/null
+++ b/3rdparty/Routino/doc/html/readme.html
@@ -0,0 +1,425 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<title>Routino : Software</title>
+
+<!--
+ Routino documentation - readme
+
+ Part of the Routino routing software.
+
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see http://www.gnu.org/licenses/.
+-->
+
+<link href="style.css" type="text/css" rel="stylesheet">
+</head>
+
+<body>
+
+<!-- Header Start -->
+
+<div class="header">
+
+<h1>Routino : Software</h1>
+
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2 id="H_1_1" title="Introduction">Routino Introduction</h2>
+
+Routino is an application for finding a route between two points using the
+dataset of topographical information collected by
+<a class="ext" title="OpenStreetMap" href="http://www.openstreetmap.org/">http://www.OpenStreetMap.org</a>.
+
+<p>
+
+Starting from the raw OpenStreetMap data (in the form of the '.osm' XML files
+available on the internet) a custom database is generated that contains the
+information useful for routing.  With this database and two points specified by
+latitude and longitude an optimum route (either shortest or quickest) is
+determined.  The route is calculated for OpenStreetMap highways (roads, paths
+etc) using one of the common forms of transport defined in OpenStreetMap (foot,
+bicycle, horse, motorcar, motorcycle etc).
+
+<p>
+
+When processing the OpenStreetMap data the types of highways are recorded and
+these set default limits on the types of traffic allowed.  More specific
+information about permissions for different types of transport are also recorded
+as are maximum speed limits.  Further restrictions like one-way streets, weight,
+height, width and length limits are also included where specified. Additionally
+a set of properties of each highway are also recorded.  The processing of the
+input file is controlled by a configuration file which determines the
+information that is used.
+
+<p>
+
+When calculating a route the type of transport to be used is taken into account
+to ensure that the known restrictions are followed.  Each of the different
+highway types can further be allowed or disallowed depending on preferences.
+For each type of highway a default speed limit is defined (although the actual
+speed used will be the lowest of the default and any specified in the original
+data).  To make use of the information about restrictions the weight, height,
+width and length of the transport can also be specified.  Further preferences
+about road properties (e.g. paved or not) can also be selected.  The simplest
+type of turn restrictions (those formed from an initial way, a node and a second
+way) are also obeyed.
+
+<p>
+
+The result of calculating the route can be presented in several different ways.
+An HTML file can be produced that contains a description of the route to take
+with instructions for each of the important junctions.  The contents of the file
+are created based on a set of translations specified in a configuration file.
+The route is also available in a
+<a class="ext" title="GPX format" href="http://www.topografix.com/gpx.asp">GPX (GPS eXchange) XML format</a>.
+format file containing either every point and highway segment (a track file) or
+just a waypoint and translated instructions for the important junctions (a route
+file).
+Additionally there are two plain text files that contain all data points or just
+the important ones (intended for debugging and further processing).
+
+<p>
+
+One of the design aims of Routino was to make the software are flexible as
+possible in selecting routing preferences but also have a sensible set of
+default values.  Another design aim was that finding the optimum route should be
+very fast and most of the speed increases come from the carefully chosen and
+optimised data format.
+
+
+<h2 id="H_1_2">Disclaimer</h2>
+
+The route that is calculated by this software is only as good as the input data.
+
+<p>
+
+Routino comes with ABSOLUTELY NO WARRANTY for the software itself or the route
+that is calculated by it.
+
+
+<h2 id="H_1_3">Demonstration</h2>
+
+A live demonstration of the router for the UK is available on the internet in
+both OpenLayers and Leaflet versions:
+<br>
+<a href="http://www.routino.org/uk-leaflet/" title="Leaflet Router">http://www.routino.org/uk-leaflet/</a>
+<br>
+<a href="http://www.routino.org/uk-openlayers/" title="OpenLayers Router">http://www.routino.org/uk-openlayers/</a>
+
+<p>
+
+The source code download available below also includes a set of files that can
+be used to create your own interactive map.
+
+<p>
+
+The interactive map is made possible by use of the OpenLayers or Leaflet
+Javascript library from
+<a class="ext" href="http://www.openlayers.org" title="OpenLayers">http://www.openlayers.org/</a>
+or
+<a class="ext" href="http://leafletjs.com" title="Leaflet">http://leafletjs.com/</a>.
+
+
+<h2 id="H_1_4">Documentation</h2>
+
+A full set of
+<a href="index.html" title="Documentation">documentation</a>
+is available that describes how to install and use the programs as well as
+what should go in the configuration files and how it works.
+
+
+<h2 id="H_1_5">Status</h2>
+
+Version 1.0 of Routino was released on 8th April 2009.
+<br>
+Version 1.1 of Routino was released on 13th June 2009.
+<br>
+Version 1.2 of Routino was released on 21st October 2009.
+<br>
+Version 1.3 of Routino was released on 21st January 2010.
+<br>
+Version 1.4 of Routino was released on 31st May 2010.
+<br>
+Version 1.4.1 of Routino was released on 10th July 2010.
+<br>
+Version 1.5 of Routino was released on 30th October 2010.
+<br>
+Version 1.5.1 of Routino was released on 13th November 2010.
+<br>
+Version 2.0 of Routino was released on 30th May 2011.
+<br>
+Version 2.0.1 of Routino was released on 7th June 2011.
+<br>
+Version 2.0.2 of Routino was released on 26th June 2011.
+<br>
+Version 2.0.3 of Routino was released on 4th August 2011.
+<br>
+Version 2.1 of Routino was released on 3rd October 2011.
+<br>
+Version 2.1.1 of Routino was released on 23rd October 2011.
+<br>
+Version 2.1.2 of Routino was released on 12th November 2011.
+<br>
+Version 2.2 of Routino was released on 3rd March 2012.
+<br>
+Version 2.3 of Routino was released on 21st July 2012.
+<br>
+Version 2.3.1 of Routino was released on 11th August 2012.
+<br>
+Version 2.3.2 of Routino was released on 6th October 2012.
+<br>
+Version 2.4 of Routino was released on 8th December 2012.
+<br>
+Version 2.4.1 of Routino was released on 17th December 2012.
+<br>
+Version 2.5 of Routino was released on 9th February 2013.
+<br>
+Version 2.5.1 of Routino was released on 20th April 2013.
+<br>
+Version 2.6 of Routino was released on 6th July 2013.
+<br>
+Version 2.7 of Routino was released on 22nd March 2014.
+<br>
+Version 2.7.1 of Routino was released on 17th May 2014.
+<br>
+Version 2.7.2 of Routino was released on 26th June 2014.
+<br>
+Version 2.7.3 of Routino was released on 8th November 2014.
+
+<p>
+
+The full version history is available in the NEWS.txt file.
+
+
+<h3 id="H_1_5_1" title="Changes 2.7">Changes in Versions 2.7</h3>
+
+Version 2.7 - mostly web page usability improvements.
+
+<dl>
+  <dt>Bug fixes:
+    <dd>Fix web-page CGI bug that did not allow more than 9 waypoints to be routed.
+    <br>Fix typo in documentation strings in filedumper program.
+    <br>Fix error in function prototype that stopped 64-bit node type being used.
+    <br>Don't lose super-segments when merging them with normal segments.
+    <br>Don't exceed the database lat/long limits when searching for visualiser data.
+
+  <dt>planetsplitter:
+    <dd>Don't overflow (and wrap-around) conversions of lengths, weights etc.
+    <br>Add some new formats of length, weight and speed parsing.
+    <br>Add .xz uncompression as a compile-time option (default is disabled).
+
+  <dt>router:
+    <dd>Remove ancient undocumented option to specify lat/lon without --lat/--lon.
+    <br>Add a '--output-stdout' option to output the route in a selected format.
+    <br>Add a '--reverse' option to calculate a route in the reverse order.
+    <br>Add a '--loop' option to calculate a route that returns to the first waypoint.
+    <br>Output valid HTML4 (use strict DTD and use numeric entity for apostrophe).
+
+  <dt>OSM tagging:
+    <dd>Allow bicycles both ways on certain oneway roads if tagging allows.
+    <br>Handle "access=bus" like "access=psv".
+
+  <dt>Configuration Files:
+    <dd>Updated Dutch translations.
+    <br>Updates to the XML parser tagging rules.
+    <br>Added French translations for the routing output.
+
+  <dt>Documentation:
+    <dd>Update the algorithm documentation for finding the shortest path.
+    <br>Update documentation HTML to strict 4.01 DTD.
+
+  <dt>Web pages:
+    <dd>Some changes to HTML, CSS formatting and Javascript to improve usability.
+    <br>Added a French translation of the router web page.
+    <br>Add the option to choose between OpenLayers and Leaflet for map rendering.
+    <br>Check compatible with OpenLayers v2.13.1 and make this the default.
+    <br>Create the router and visualiser pages from templates and translated phrases.
+</dl>
+
+<p>
+<b>Note:</b> This version has removed specific support for IE6 and IE7 browsers.
+<p>
+<b>Note:</b> Note: This version is compatible with databases from version 2.6.
+
+<h3 id="H_1_5_2" title="Changes 2.7.1">Changes in Versions 2.7.1</h3>
+
+Version 2.7.1 - mostly bug fixes (some from version 2.7, but mostly older ones).
+
+<dl>
+  <dt>Bug fixes:
+    <dd>Fix typo in documentation for command to get SVN version.
+    <br>Fix router crash when waypoint is on roundabout.
+    <br>Don't duplicate super-segments when merging them with normal segments.
+    <br>Change routing instructions for bicycle if highways allow cycling both ways.
+    <br>Make translation script work with older versions of Perl.
+    <br>Fix router crash if fewer than two waypoints are specified.
+    <br>Revert router speed decrease with special-case tagging rules.
+    <br>Fix web page search function when it returns non-ASCII text.
+    <br>Fix router failure due to invalid assumption about allowed U-turn.
+    <br>Fix bug with updating XML files in web/data directory (Makefile error).
+    <br>Fix router web page error due to absence of cyclebothways property entry.
+    <br>Fix results error if a waypoint node was passed again on way to next waypoint.
+    <br>Fix router crash when route contains consecutive coincident waypoints.
+    <br>Fix bug with slightly incorrect distances when pruning short segments.
+
+  <dt>Test cases:
+    <dd>Create new test case for roundabout waypoint bug fixed in this version.
+    <br>Create new test case for invalid U-turn assumption bug fixed in this version.
+    <br>Create new test case for cycling both ways.
+    <br>Create new test case for consecutive coincident waypoints.
+
+  <dt>router:
+    <dd>Remove cyclebothways as a property that can be used as a routing preference.
+
+  <dt>Web pages:
+    <dd>Disallow route calculation if fewer than two waypoints are selected.
+    <br>Update visualiser for change of cyclebothways handling.
+
+  <dt>Translations:
+    <dd>Updated Russian translations.
+    <br>Updated German translations.
+</dl>
+
+<p>
+<b>Note:</b> This version is not compatible with databases from previous versions.
+
+
+<h3 id="H_1_5_3" title="Changes 2.7.2">Changes in Versions 2.7.2</h3>
+
+Version 2.7.2 - mostly bug fixes introduced in version 2.7.1 on 64-bit systems.
+
+<dl>
+  <dt>Bug fixes:
+    <dd>Make the visualiser display all segments including those crossing the border.
+    <br>Fix two errors that cause crashes only on 64-bit systems.
+
+  <dt>planetsplitter / router:
+    <dd>Increase the size of the caches for the slim programs by a factor of four.
+
+  <dt>Translations:
+    <dd>Updated Russian translations.
+    <br>Updated German translations.
+</dl>
+
+<p>
+<b>Note:</b> This version is compatible with databases from version 2.7.1.
+
+
+<h3 id="H_1_5_4" title="Changes 2.7.3">Changes in Versions 2.7.3</h3>
+
+Version 2.7.3 - Slightly reduced memory usage and large reduction in time to generate routing database on low memory systems.
+
+<dl>
+  <dt>Bug fixes:
+    <dd>Limit the property preference ratio to 100 instead of 10000.
+    <br>Don't allocate memory for sorting that won't be used.
+
+  <dt>planetsplitter:
+    <dd>Added an option to print out the allocated/mapped memory at each step.
+    <br>Speed up database generation by compacting results after each pruning step.
+    <br>Speed up database generation by sorting nodes geographically before pruning.
+    <br>Reduce memory use while generating the database.  
+
+  <dt>router:
+    <dd>Added the options to print out time and allocated/mapped memory at each step.
+
+  <dt>Translations:
+    <dd>Updated German translations.
+</dl>
+
+<p>
+<b>Note:</b> This version is compatible with databases from version 2.7.1 & 2.7.2.
+
+
+
+<h2 id="H_1_6">License</h2>
+
+This program is free software: you can redistribute it and/or modify it under
+the terms of the
+<a class="ext" title="Affero GPLv3" href="http://www.gnu.org/licenses/agpl-3.0.html">GNU Affero General Public License</a>
+as published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+<p>
+
+It is important to note that for this program I have decided to use the
+<em>Affero GPLv3</em> instead of just using the GPL.  This license adds
+additional requirements to anybody who provides a networked service using this
+software.
+
+
+<h3 id="H_1_6_1">Copyright</h3>
+
+Routino is copyright Andrew M. Bishop 2008-2014.
+
+
+<h2 id="H_1_7">Homepage</h2>
+
+The <a title="Homepage" href="http://www.routino.org/">Routino homepage</a>
+has the latest news about the program.
+
+
+<h2 id="H_1_8">Download</h2>
+
+The <a title="Download directory" href="http://www.routino.org/download/">download directory</a>
+contains the latest version of the source code.
+
+<h3 id="H_1_8_1">Subversion</h3>
+
+The source code can also be downloaded from the
+<a title="SVN Repository" href="http://routino.org/svn/trunk/">Subversion repository</a>
+with a command like the following:
+
+<pre class="boxed">
+svn co http://routino.org/svn/trunk routino
+</pre>
+
+<p>
+The source code can also be browsed in the
+<a title="SVN Viewer" href="http://www.routino.org/viewvc/trunk/">Subversion viewer</a>
+which also has a list of the
+<a title="SVN Changes" href="http://www.routino.org/viewvc/trunk/?view=log">latest changes</a>.
+
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer">
+
+<address>
+© Andrew M. Bishop - <a href="http://www.routino.org/">http://www.routino.org/</a>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</body>
+
+</html>
diff --git a/3rdparty/Routino/doc/html/style.css b/3rdparty/Routino/doc/html/style.css
new file mode 100644
index 0000000..213879e
--- /dev/null
+++ b/3rdparty/Routino/doc/html/style.css
@@ -0,0 +1,435 @@
+/*
+// Routino web page style sheet.
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2015 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*----------------------------------*/
+/* Body HTML formatting             */
+/*----------------------------------*/
+
+BODY
+{
+ /* fonts and text styles */
+
+ font-family: sans-serif;
+ font-size:   medium;
+
+ /* margins, borders, padding and sizes */
+
+ padding: 0;
+
+ margin: 0;
+}
+
+A.ext
+{
+ /* fonts and text styles */
+
+ text-decoration: underline;
+}
+
+PRE
+{
+ /* fonts and text styles */
+
+ font-family: monospace;
+}
+
+PRE.boxed
+{
+ /* margins, borders, padding and sizes */
+
+ padding:      0.5em;
+
+ border:       solid;
+ border-width: thin;
+}
+
+
+/*-----------------------------------*/
+/* Header HTML formatting            */
+/*-----------------------------------*/
+
+DIV.header
+{
+ /* margins, borders, padding and sizes */
+
+ padding:        0;
+ padding-top:    0.5em;
+ padding-bottom: 0.5em;
+
+ border-width:        0;
+ border-bottom:       solid;
+ border-bottom-width: thin;
+
+ margin: 0;
+
+ /* text alignment */
+
+ text-align: center;
+
+ /* floats */
+
+ clear: left;
+}
+
+DIV.header H1
+{
+ /* fonts and text styles */
+
+ font-size: 150%;
+
+ font-weight: bold;
+
+ text-decoration: underline;
+
+ /* margins, borders, padding and sizes */
+
+ padding: 0.25em;
+
+ border: 0;
+
+ margin: 0;
+}
+
+
+/*-----------------------------------*/
+/* Footer HTML formatting            */
+/*-----------------------------------*/
+
+DIV.footer
+{
+ /* fonts and text styles */
+
+ font-size: 80%;
+
+ /* margins, borders, padding and sizes */
+
+ padding:        0;
+ padding-top:    0.5em;
+ padding-bottom: 0.5em;
+
+ border-width:      0;
+ border-top:        solid;
+ border-top-width:  thin;
+
+ margin: 0;
+
+ /* text alignment */
+
+ text-align: center;
+
+ /* floats */
+
+ clear: left;
+}
+
+
+/*-----------------------------------*/
+/* Content HTML formatting           */
+/*-----------------------------------*/
+
+DIV.content
+{
+ /* margins, borders, padding and sizes */
+
+ padding: 0.5em;
+
+ border-width:  0;
+}
+
+DIV.content H1
+{
+ /* fonts and text styles */
+
+ font-size:   150%;
+ font-weight: bold;
+
+ /* margins, borders, padding and sizes */
+
+ padding: 0;
+
+ margin-top:    1em;
+ margin-bottom: 0.25em;
+}
+
+DIV.content H2
+{
+ /* fonts and text styles */
+
+ font-size:   140%;
+ font-weight: bold;
+
+ /* margins, borders, padding and sizes */
+
+ padding: 0;
+
+ margin-top:    0.75em;
+ margin-bottom: 0.25em;
+}
+
+DIV.content H3
+{
+ /* fonts and text styles */
+
+ font-size:   120%;
+ font-weight: bold;
+
+ /* margins, borders, padding and sizes */
+
+ padding: 0;
+
+ margin-top:    0.75em;
+ margin-bottom: 0.25em;
+}
+
+DIV.content H4
+{
+ /* fonts and text styles */
+
+ font-size:   110%;
+ font-weight: bold;
+
+ /* margins, borders, padding and sizes */
+
+ padding: 0;
+
+ margin-top:    0.5em;
+ margin-bottom: 0.125em;
+}
+
+DIV.content P.center
+{
+ /* text alignment */
+
+ text-align: center;
+}
+
+DIV.content OL, DIV.content UL, DIV.content DIR, DIV.content MENU, DIV.content DL
+{
+ /* margins, borders, padding and sizes */
+
+ padding-top:    0;
+ padding-bottom: 0;
+
+ margin-top:    0.25em;
+ margin-bottom: 0.25em;
+}
+
+DIV.content UL UL, DIV.content UL OL, DIV.content UL DL, DIV.content OL UL, DIV.content OL OL, DIV.content OL DL, DIV.content DL UL, DIV.content DL OL, DIV.content DL DL
+{
+ /* margins, borders, padding and sizes */
+
+ padding-top:    0;
+ padding-bottom: 0;
+
+ margin-top:    0;
+ margin-bottom: 0;
+}
+
+DIV.content FORM
+{
+ /* margins, borders, padding and sizes */
+
+ padding: 0.5em;
+
+ margin: 0.5em;
+}
+
+DIV.content INPUT
+{
+ /* margins, borders, padding and sizes */
+
+ padding: 0;
+
+ border:  1px solid;
+
+ margin:  1px;
+}
+
+DIV.content BUTTON
+{
+ /* margins, borders, padding and sizes */
+
+ padding: 0;
+
+ border:  1px solid;
+
+ margin:  1px;
+}
+
+DIV.content INPUT.left
+{
+ /* text alignment */
+
+ text-align: left;
+}
+
+DIV.content INPUT.center
+{
+ /* text alignment */
+
+ text-align: center;
+}
+
+DIV.content INPUT.right
+{
+ /* text alignment */
+
+ text-align: right;
+}
+
+DIV.content TABLE
+{
+ /* margins, borders, padding and sizes */
+
+ padding: 0;
+
+ border:  2px solid;
+
+ margin:  0;
+ margin-left: auto;
+ margin-right: auto;
+
+ border-collapse: collapse;
+}
+
+DIV.content TABLE.center
+{
+ /* text alignment */
+
+ text-align: center;
+}
+
+DIV.content TABLE.noborder
+{
+ /* margins, borders, padding and sizes */
+
+ margin-left: auto;
+ margin-right: auto;
+
+ border:  0;
+}
+
+DIV.content TABLE.noborder-left
+{
+ /* margins, borders, padding and sizes */
+
+ margin-left: 0;
+ margin-right: auto;
+
+ border:  0;
+}
+
+DIV.content CAPTION
+{
+ /* position */
+
+ caption-side: bottom;
+
+ /* text alignment */
+
+ text-align: center;
+
+ /* fonts and text styles */
+
+ font-weight: bold;
+}
+
+DIV.content TD, DIV.content TH
+{
+ /* margins, borders, padding and sizes */
+
+ border:  1px solid;
+}
+
+DIV.content TABLE.noborder TD, DIV.content TABLE.noborder TH
+{
+ /* margins, borders, padding and sizes */
+
+ border:  0;
+}
+
+DIV.content TABLE.noborder-left TD, DIV.content TABLE.noborder-left TH
+{
+ /* margins, borders, padding and sizes */
+
+ border:  0;
+}
+
+DIV.content TD.left, DIV.content TH.left, DIV.content TR.left
+{
+ /* text alignment */
+
+ text-align: left;
+}
+
+DIV.content TD.center, DIV.content TH.center, DIV.content TR.center
+{
+ /* text alignment */
+
+ text-align: center;
+}
+
+DIV.content TD.right, DIV.content TH.right, DIV.content TR.right
+{
+ /* text alignment */
+
+ text-align: right;
+}
+
+DIV.content IMG.center
+{
+ display: block;
+
+ /* margins, borders, padding and sizes */
+
+ margin-left:  auto;
+ margin-right: auto;
+}
+
+DIV.content IMG
+{
+ /* margins, borders, padding and sizes */
+
+ border: 0px;
+}
+
+
+/*------------------------------------------------*/
+/*                                                */
+/* Special case layout for narrow screens         */
+/*                                                */
+/*------------------------------------------------*/
+
+ at media screen and (max-width:640px) {
+
+  /*----------------------------------*/
+  /* Body HTML formatting             */
+  /*----------------------------------*/
+
+  BODY
+  {
+   /* fonts and text styles */
+
+   font-size: small;
+  }
+
+}
diff --git a/3rdparty/Routino/doc/html/tagging.html b/3rdparty/Routino/doc/html/tagging.html
new file mode 100644
index 0000000..f6c8173
--- /dev/null
+++ b/3rdparty/Routino/doc/html/tagging.html
@@ -0,0 +1,988 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<title>Routino : Tagging Rules</title>
+
+<!--
+ Routino documentation - tagging
+
+ Part of the Routino routing software.
+
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see http://www.gnu.org/licenses/.
+-->
+
+<link href="style.css" type="text/css" rel="stylesheet">
+</head>
+
+<body>
+
+<!-- Header Start -->
+
+<div class="header">
+
+<h1>Routino : Tagging Rules</h1>
+
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2 id="H_1_1">Tags And Attributes</h2>
+
+The different tags and attributes in the 
+<a class="ext" title="OpenStreetMap" href="http://www.openstreetmap.org/">OSM</a>
+format XML that are used by Routino are described below.
+
+<p>
+
+Routino handles the tags in the input file after they have been processed
+according to a set of rules defined in a configuration file.  The first half of
+this file describes the tags that are recognised by Routino after being
+processed; the second half of the file describes the transformations that are in
+the default tagging configuration file.
+
+
+<!-- ==================== Tags Recognised After Processing ==================== -->
+
+
+<h2 id="H_1_2" title="After Processing">Tags Recognised After Processing</h2>
+
+This section describes the tags that are recognised by Routino after the tag
+transformations have been applied.  This is therefore a much reduced set of tags
+compared to the original OSM data and also includes tags which are specific to
+Routino.
+
+<p>
+
+In all cases of tag processing values of <em>true</em>, <em>yes</em>, <em>1</em>
+are recognised as being affirmative and any other value is negative.
+
+
+<!-- ========================= Routino Node Tags ========================= -->
+
+<h3 id="H_1_2_1" title="Nodes">Node Tags And Attributes</h3>
+
+The node attributes <em>id</em>, <em>latitude</em> and <em>longitude</em> are
+used.  The id attribute is required to associate the node with the ways and the
+position attributes are required to locate the node.
+
+
+<h4 id="H_1_2_1_1" title="transport tags">Transport Specific Tags</h4>
+
+One tag is recognised for each of the different modes of transport: <em>foot</em>,
+<em>horse</em>, <em>bicycle</em>, <em>wheelchair</em>, <em>moped</em>,
+<em>motorcycle</em>, <em>motorcar</em>, <em>goods</em>, <em>hgv</em>
+and <em>psv</em>.  These indicate whether the specific type of transport is
+allowed to pass through the node or not.
+
+<p>
+
+By default for nodes all types of transport are allowed to pass through a node
+and specific tags must be used to remove the permissions for the transport.
+
+
+<h4 id="H_1_2_1_2" title="roundabout (node)">The roundabout Tag</h4>
+
+The <em>roundabout</em> tag for mini-roundabouts is recognised and used to
+improve the description of the route.
+
+
+<!-- ========================= Routino Way Tags ========================= -->
+
+<h3 id="H_1_2_2" title="Ways">Way Tags And Attributes</h3>
+
+The tags from the ways in the data are the ones that provide most of the
+information for routing.  The <em>id</em> attribute is used only so that the
+many segments associated with a way can share a set of tags taken from the way.
+The <em>nd</em> information is used to identify the nodes that make up the way.
+
+
+<h4 id="H_1_2_2_1" title="highway (way)">The highway Tag</h4>
+
+The most important tag that is used from a way is the <em>highway</em> tag.
+This defines the type of highway that the way represents.  Any way that does not
+have a highway tag is discarded.
+
+<p>
+
+There are more highway types defined than are used by the router.  The subset
+that the router uses are:
+
+<ul>
+  <li>motorway
+  <li>trunk
+  <li>primary
+  <li>secondary
+  <li>tertiary
+  <li>unclassified
+  <li>residential
+  <li>service
+  <li>track
+  <li>cycleway
+  <li>path (1)
+  <li>steps (2)
+</ul>
+
+<p>
+
+<i>
+  Note 1: This changed in version 1.3 of Routino - the bridleway and footway
+  types were included within the path highway type.
+  <br>
+  Note 2: This changed in version 1.3 of Routino - the steps type was separated
+  from the footway type.
+</i>
+
+
+<h4 id="H_1_2_2_2" title="transport tags">Transport Specific Tags</h4>
+
+One tag is recognised for each of the different modes of transport: <em>foot</em>,
+<em>horse</em>, <em>bicycle</em>, <em>wheelchair</em>, <em>moped</em>,
+<em>motorcycle</em>, <em>motorcar</em>, <em>goods</em>, <em>hgv</em>
+and <em>psv</em>.  These indicate whether the specific type of transport is
+allowed on the highway or not.
+
+<p>
+
+By default for ways no types of transport are allowed to pass along a highway
+and specific tags must be used to add the permissions for the transport.
+
+
+<h4 id="H_1_2_2_3" title="name">The name Tag</h4>
+
+The <em>name</em> tag is used to provide the label for the highway when printing
+the results.
+
+
+<h4 id="H_1_2_2_4" title="ref">The ref Tag</h4>
+
+The <em>ref</em> tag is used to provide the label for the highway when printing
+the results.
+
+
+<h4 id="H_1_2_2_5" title="lanes">The lanes Tag</h4>
+
+The <em>lanes</em> tag is used to identify whether a highway has multiple lanes
+for traffic and this is used to derive the <em>multilane</em> highway
+properties.
+
+
+<h4 id="H_1_2_2_6" title="paved">The paved Tag</h4>
+
+The <em>paved</em> tag is used to identify whether a highway is paved or not,
+this is one of the available highway properties.  A <em>paved</em> tag may exist
+in the original data but normally the <em>surface</em> tag needs to be
+transformed into the <em>paved</em> tag.
+
+
+<h4 id="H_1_2_2_7" title="multilane">The multilane Tag</h4>
+
+The <em>multilane</em> tag is used to indicate that a highway has multiple lanes
+for traffic.
+
+
+<h4 id="H_1_2_2_8" title="bridge">The bridge Tag</h4>
+
+The <em>bridge</em> tag is used to identify whether a highway is a bridge and
+therefore set one of the available properties.
+
+
+<h4 id="H_1_2_2_9" title="tunnel">The tunnel Tag</h4>
+
+The <em>tunnel</em> tag is used to identify whether a highway is a tunnel and
+therefore set one of the available properties.
+
+
+<h4 id="H_1_2_2_10" title="footroute">The footroute Tag</h4>
+
+The <em>footroute</em> tag is used to identify whether a highway is part of a
+walking route and therefore set one of the available properties.  This is not a
+standard OSM tag and is normally added to the individual highways by looking for
+route relations that are designated for foot access.
+
+
+<h4 id="H_1_2_2_11" title="bicycleroute">The bicycleroute Tag</h4>
+
+The <em>bicycleroute</em> tag is used to identify whether a highway is part of a
+bicycle route and therefore set one of the available properties.  This is not a
+standard OSM tag and is normally added to the individual highways by looking for
+route relations that are designated for bicycle access.
+
+
+<h4 id="H_1_2_2_12" title="cyclebothways">The cyclebothways Tag</h4>
+
+The <em>cyclebothways</em> tag is used to identify whether a highway allows
+cycling in the opposite direction to a signposted oneway restriction.
+
+
+<h4 id="H_1_2_2_13" title="oneway">The oneway Tag</h4>
+
+The <em>oneway</em> tag is used to specify that traffic is only allowed to
+travel in one direction.
+
+
+<h4 id="H_1_2_2_14" title="roundabout (way)">The roundabout Tag</h4>
+
+The <em>roundabout</em> tag is used to specify that a highway is part of a
+roundabout to improve the description of the calculated route.
+
+
+<h4 id="H_1_2_2_15" title="maxspeed">The maxspeed Tag</h4>
+
+The <em>maxspeed</em> tag is used to specify the maximum speed limit on the
+highway; this is always measured in km/hr in OpenStreetMap data.  If the tag
+value contains "mph" then it is assumed to be a value in those units and
+converted to km/hr.
+
+
+<h4 id="H_1_2_2_16" title="maxweight">The maxweight Tag</h4>
+
+The <em>maxweight</em> tag is used to specify the maximum weight of any traffic
+on the highway.  In other words this must be set to the heaviest weight allowed
+on the highway (for example a bridge) in tonnes.  If the tag value contains "kg"
+then it is assumed that the value is in these units and converted to tonnes.
+
+
+<h4 id="H_1_2_2_17" title="maxheight">The maxheight Tag</h4>
+
+The <em>maxheight</em> tag is used to specify the maximum height of any traffic
+on the highway.  In other words this must be set to the lowest height of
+anything above the highway (like a bridge) in metres.  If the tag value contains
+a measurement in feet or feet and inches then attempts are made to convert this
+to metres.
+
+
+<h4 id="H_1_2_2_18" title="maxwidth">The maxwidth Tag</h4>
+
+The <em>maxwidth</em> tag is used to specify the maximum width of any traffic on
+the highway.  This must be set to the minimum width of the constraints at the
+wayside in metres.  If the tag value contains a measurement in feet or feet and
+inches then attempts are made to convert this to metres.
+
+
+<h4 id="H_1_2_2_19" title="maxlength">The maxlength Tag</h4>
+
+The <em>maxlength</em> tag is used to specify the maximum length of any traffic
+on the highway (usually from a traffic sign) in metres.  If the tag value
+contains a measurement in feet or feet and inches then attempts are made to
+convert this to metres.
+
+
+<h4 id="H_1_2_2_20" title="area">The area Tag</h4>
+
+The <em>area</em> tag is used to specify that a way defines an area.  This is
+used only so that in the case of duplicated segments those belonging to an area
+can be discarded in preference to those that are not.
+
+
+<!-- ========================= Routino Relation Tags ========================= -->
+
+<h3 id="H_1_2_3" title="Relations">Relation Tags And Attributes</h3>
+
+The tags from the relations are used to associate more properties with the
+highways that are part of that relation.  The <em>id</em> attribute is used so
+that relations that are members of other relations can be identified.
+The <em>member</em> information is used to identify the nodes and ways that make
+up the relation.
+
+
+<h4 id="H_1_2_3_1" title="footroute">The footroute Tag</h4>
+
+The <em>footroute</em> tag is used to identify whether a relation defines a
+walking route and therefore should be applied to the individual member highways.
+
+
+<h4 id="H_1_2_3_2" title="bicycleroute">The bicycleroute Tag</h4>
+
+The <em>bicycleroute</em> tag is used to identify whether a relation defines a
+bicycle route and therefore should be applied to the individual member highways.
+
+
+<h4 id="H_1_2_3_3" title="type, restriction, except">The type, restriction & except Tags</h4>
+
+For turn relations the information about the allowed or disallowed turns are
+stored in the <em>type</em>, <em>restriction</em> and <em>except</em> tags.  For
+a turn restriction the <em>type</em> must be equal to "restriction",
+the <em>restriction</em> must define the type of turn relation
+and <em>except</em> defines transport types which are exempt from the
+restriction.
+
+
+<!-- ==================== Tag Transformations ==================== -->
+
+<h2 id="H_1_3">Tag Transformations</h2>
+
+This section describes the set of tag transformations that are contained in the
+default configuration file.  The configuration file tagging rules are applied in
+sequence and this section of the document is arranged in the same order.
+
+
+<!-- ==================== Node Tag Transformations ==================== -->
+
+<h3 id="H_1_3_1" title="Nodes">Node Tag Transformations</h3>
+
+<h4 id="H_1_3_1_1">Barrier Defaults</h4>
+
+The first part of the tag transformations is to decide on defaults for each type
+of node.  This uses the <em>barrier</em> tag in the OSM file and converts it into
+a default set of disallowed transport types.
+
+<p>
+
+<table>
+  <caption>Transport types through different barrier types</caption>
+  <tr>
+    <th class="left">Barrier
+    <th class="center">foot
+    <th class="center">horse
+    <th class="center">wheelchair
+    <th class="center">bicycle
+    <th class="center">moped
+    <th class="center">motorcycle
+    <th class="center">motorcar
+    <th class="center">goods
+    <th class="center">hgv
+    <th class="center">psv
+  <tr>
+    <td class="left">kissing_gate, footgate, stile, v_stile, turnstile, squeeze, squeeze_stile, cycle_barrier, bicycle_barrier
+    <td class="center">yes
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+  <tr>
+    <td class="left">horse_stile, horse_jump, step_over
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+  <tr>
+    <td class="left">horse_barrier, cattle_grid
+    <td class="center">yes
+    <td class="center">no
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+  <tr>
+    <td class="left">motorcyle_barrier
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+  <tr>
+    <td class="left">bollard, car_barrier, car_trap
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+</table>
+
+<h4 id="H_1_3_1_2" title="Generic access">Generic Access Permissions</h4>
+
+The <em>access</em> tag is used to specify the default access restrictions
+through the node.  If the tag value is <em>no</em> or <em>private</em> or a
+selection of other values then all transport types are denied access (later tag
+transformation rules may add specific transport types back again).
+
+
+<h4 id="H_1_3_1_3" title="Other access">Other Access Permissions</h4>
+
+A tag named <em>vehicle</em> means any of the <em>bicycle</em>, <em>moped</em>,
+<em>motorcycle</em>, <em>motorcar</em>, <em>goods</em>, <em>hgv</em>
+and <em>psv</em> transport types.  A tag named <em>motor_vehicle</em> is
+transformed to mean any vehicle except a <em>bicycle</em>.
+
+
+<h4 id="H_1_3_1_4" title="Specific access">Specific Access Permissions</h4>
+
+The final part of the access permissions is to use the specific transport type
+tags.
+
+<p>
+
+One tag is recognised for each of the different modes of transport: <em>foot</em>,
+<em>horse</em>, <em>bicycle</em>, <em>wheelchair</em>, <em>moped</em>,
+<em>motorcycle</em>, <em>motorcar</em>, <em>goods</em>, <em>hgv</em>
+and <em>psv</em>.  These indicate whether the specific type of transport is
+allowed through the node or not; the values listed for the <em>access</em> tag
+are also accepted here.
+
+
+<h4 id="H_1_3_1_5">Mini-roundabouts</h4>
+
+If the <em>highway</em> tag has the value <em>mini_roundabout</em> or
+the <em>junction</em> tag has the value <em>roundabout</em> then
+a <em>junction</em> tag with value <em>roundabout</em>is passed through.
+
+
+<!-- ==================== Way Tag Transformations ==================== -->
+
+<h3 id="H_1_3_2" title="Ways">Way Tag Transformations</h3>
+
+
+<h4 id="H_1_3_2_1">Highway Defaults</h4>
+
+The first part of the tag transformations is to decide on defaults for each type
+of highway.  This uses the <em>highway</em> tag in the OSM file and maps it into
+one of the <em>highway</em> tags that are recognised by Routino, defining the
+default allowed transport types and adding a number of properties.
+
+<p>
+The first part of the highway tag checking is to ignore the <em>highway</em> tag
+if it has a value that indicates a non-highway.  These are the <em>proposed</em>
+and <em>construction</em> values for future highways, the <em>no</em>,
+<em>abandoned</em> and <em>disused</em> values for previous highways and a small
+number of other values.
+
+<p>
+The second part of the highway transformation is to convert the <em>highway</em>
+tag into one that is recognised by Routino.
+
+<p>
+
+<table>
+  <caption>Mapping of equivalent highway types</caption>
+  <tr>
+    <th class="left">Original tag
+    <th class="left">Transformed tag
+  <tr>
+    <td class="left">motorway_link
+    <td class="left">motorway
+  <tr>
+    <td class="left">trunk_link
+    <td class="left">trunk
+  <tr>
+    <td class="left">primary_link
+    <td class="left">primary
+  <tr>
+    <td class="left">secondary_link
+    <td class="left">secondary
+  <tr>
+    <td class="left">tertiary_link
+    <td class="left">tertiary
+  <tr>
+    <td class="left">minor, road
+    <td class="left">unclassified
+  <tr>
+    <td class="left">living_street
+    <td class="left">residential
+  <tr>
+    <td class="left">access, services, layby
+    <td class="left">service
+  <tr>
+    <td class="left">byway, unsurfaced, unpaved
+    <td class="left">track
+  <tr>
+    <td class="left">footway, bridleway, pedestrian, walkway
+    <td class="left">path
+  <tr>
+    <td class="left">route=ferry
+    <td class="left">ferry (1)
+</table>
+
+<i>
+  Note 1: A ferry route is converted into a highway of type "ferry" so that
+  routes using a ferry can be calculated.
+</i>
+
+<p>
+The type of highway also determines the defaults for the types of transport
+allowed on the highway.  The default assumptions are as shown in the table
+below.
+
+<p>
+
+<table>
+  <caption>Transport types on different highway types</caption>
+  <tr>
+    <th class="left">Highway
+    <th class="center">foot
+    <th class="center">horse
+    <th class="center">wheelchair
+    <th class="center">bicycle
+    <th class="center">moped
+    <th class="center">motorcycle
+    <th class="center">motorcar
+    <th class="center">goods
+    <th class="center">hgv
+    <th class="center">psv
+  <tr>
+    <td class="left">motorway
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+  <tr>
+    <td class="left">trunk
+    <td class="center">no (1)
+    <td class="center">no (1)
+    <td class="center">no (1)
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+  <tr>
+    <td class="left">primary
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+  <tr>
+    <td class="left">secondary
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+  <tr>
+    <td class="left">tertiary
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+  <tr>
+    <td class="left">unclassified
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+  <tr>
+    <td class="left">residential
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+  <tr>
+    <td class="left">service
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+  <tr>
+    <td class="left">track
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+  <tr>
+    <td class="left">cycleway
+    <td class="center">yes
+    <td class="center">no
+    <td class="center">yes
+    <td class="center">yes
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+  <tr>
+    <td class="left">path
+    <td class="center">yes
+    <td class="center">yes (2)
+    <td class="center">yes
+    <td class="center">yes (2)
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+  <tr>
+    <td class="left">steps
+    <td class="center">yes
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+  <tr>
+    <td class="left">ferry (3)
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+    <td class="center">no
+</table>
+
+<p>
+
+<i>
+  Note 1: A trunk road may legally allow foot, horse or wheelchair access but in
+  the absence of other tags is considered to be too dangerous.
+  <br>
+  Note 2: A path allows bicycle or horse access by default only if actually
+  labelled as a highway of type "bridleway".
+  <br>
+  Note 3: Ferry routes must be explicitly tagged with the allowed transport
+  types, it is not sensible to try to guess.
+</i>
+
+<p>
+Finally for the highway tag a number of default properties are added depending
+on the highway type.
+
+<p>
+
+<table>
+  <caption>Default properties on different highway types</caption>
+  <tr>
+    <th class="center">Highway
+    <th class="center">Properties
+  <tr>
+    <td class="center">motorway
+    <td class="center">paved, oneway, multilane
+  <tr>
+    <td class="center">trunk
+    <td class="center">paved, multilane (1)
+  <tr>
+    <td class="center">primary
+    <td class="center">paved, multilane (1)
+  <tr>
+    <td class="center">secondary
+    <td class="center">paved
+  <tr>
+    <td class="center">tertiary
+    <td class="center">paved
+  <tr>
+    <td class="center">unclassified
+    <td class="center">paved
+  <tr>
+    <td class="center">residential
+    <td class="center">paved
+  <tr>
+    <td class="center">service
+    <td class="center">paved
+  <tr>
+    <td class="center">track
+    <td class="center">paved (2)
+  <tr>
+    <td class="center">cycleway
+    <td class="center">paved
+  <tr>
+    <td class="center">path
+    <td class="center">paved (3)
+  <tr>
+    <td class="center">steps
+    <td class="center">
+  <tr>
+    <td class="center">ferry
+    <td class="center">
+</table>
+
+<p>
+
+<i>
+  Note 1: A highway of this type has the multilane property by default if it is
+  oneway.
+  <br>
+  Note 2: A track is paved only if it is tagged as tracktype=grade1.
+  <br>
+  Note 3: A path is paved only if it was originally tagged as highway=walkway or
+  highway=pedestrian.
+</i>
+
+
+<h4 id="H_1_3_2_2" title="Generic access">Generic Access Permissions</h4>
+
+The <em>access</em> tag is used to specify the default access restrictions on
+the highway.  If the tag value is <em>no</em> or <em>private</em> or a selection
+of other values then all transport types are denied access (later tag
+transformation rules may add specific transport types back again).
+
+
+<h4 id="H_1_3_2_3" title="Other access">Other Access Permissions</h4>
+
+A tag named <em>vehicle</em> means any of the <em>bicycle</em>, <em>moped</em>,
+<em>motorcycle</em>, <em>motorcar</em>, <em>goods</em>, <em>hgv</em>
+and <em>psv</em> transport types.  A tag named <em>motor_vehicle</em> is
+transformed to mean any vehicle except a <em>bicycle</em>.
+
+<p>
+The <em>designation</em> tag is used as an alternative method of identifying the
+legal right of way on a path (in the UK at least).  The tag transformations
+convert these tags into a set of allowed transport types as shown below.
+
+<p>
+
+<table>
+  <caption>Aliasing of designation types</caption>
+  <tr>
+    <th class="left">Designation tag
+    <th class="left">Equivalent access permissions
+  <tr>
+    <td class="left">restricted_byway
+    <td class="left">foot=yes, wheelchair=yes, horse=yes, bicycle=yes
+  <tr>
+    <td class="left">public_byway, byway, byway_open_to_all_traffic
+    <td class="left">foot=yes, wheelchair=yes, horse=yes, bicycle=yes, moped=yes, motorcycle=yes, motorcar=yes
+  <tr>
+    <td class="left">permissive_bridleway, public_bridleway, bridleway
+    <td class="left">foot=yes, wheelchair=yes, horse=yes, bicycle=yes
+  <tr>
+    <td class="left">public_cycleway
+    <td class="left">foot=yes, wheelchair=yes, bicycle=yes
+  <tr>
+    <td class="left">permissive_footpath, public_footpath, footpath
+    <td class="left">foot=yes, wheelchair=yes
+</table>
+
+<p>
+In addition to these there are some other tags and values that will modify the
+transport permissions on the highway.
+
+<p>
+A highway that is tagged as <em>motorroad</em> with a value of <em>yes</em> will
+deny access to <em>foot</em>, <em>horse</em>, <em>wheelchair</em>,
+<em>bicycle</em> and <em>moped</em> transport.
+
+<p>
+A highway that is tagged with <em>footway</em> or <em>sidewalk</em> and one of a
+set of popular values will allow <em>foot</em> and <em>wheelchair</em> access
+even if the road type would not normally do so.
+
+<p>
+A highway that is tagged as <em>cycleway</em> with one of several values will
+allow bicycle access.  If the value of the <em>cycleway</em> tag
+is <em>opposite_lane</em>, <em>opposite_track</em> or <em>opposite</em> then
+the <em>cyclebothways</em> tag is set.
+
+<p>
+A highway that is tagged as <em>oneway:bicycle</em> with the value <em>no</em>
+will also cause the <em>cyclebothways</em> tag to be set.
+
+
+<h4 id="H_1_3_2_4" title="Specific access">Specific Access Permissions</h4>
+
+The final part of the access permissions is to use the specific transport type
+tags.
+
+<p>
+
+One tag is recognised for each of the different modes of transport: <em>foot</em>,
+<em>horse</em>, <em>bicycle</em>, <em>wheelchair</em>, <em>moped</em>,
+<em>motorcycle</em>, <em>motorcar</em>, <em>goods</em>, <em>hgv</em>
+and <em>psv</em>.  These indicate whether the specific type of transport is
+allowed on the highway or not.
+
+
+<h4 id="H_1_3_2_5" title="Properties">Highway Properties</h4>
+
+If there is a surface tag then the highway is assumed to be unpaved unless the
+tag value matches one of the following: <em>paved</em>, <em>asphalt</em>,
+<em>concrete</em> or many other values listed in the configuration file.
+
+<p>
+
+Support for the obsolete <em>paved</em> tag is also provided and the highway is
+paved if this is set to a true value.
+
+<p>
+
+The <em>lanes</em> tag is passed through to be used to set the
+<em>multilane</em> highway property.
+
+<p>
+
+The <em>bridge</em> and <em>tunnel</em> tags are copied directly from the input
+to the output.
+
+
+<h4 id="H_1_3_2_6" title="Restrictions">Highway Restrictions</h4>
+
+The <em>oneway</em>, <em>maxspeed</em>, <em>maxweight</em>, <em>maxheight</em>,
+<em>maxwidth</em> and <em>maxlength</em> are copied directly from the input to
+the output without modification.
+
+
+<h4 id="H_1_3_2_7">Roundabouts</h4>
+
+If a highway is tagged as <em>junction=roundabout</em> then a
+<em>roundabout=yes</em> tag created on the output.
+
+
+<h4 id="H_1_3_2_8" title="Names and Refs">Highway Names and References</h4>
+
+The <em>name</em> and <em>ref</em> tags are copied directly from the input to
+the output.
+
+
+<h4 id="H_1_3_2_9" title="Areas">Highway Areas</h4>
+
+The <em>area</em> tag is copied directly from the input to the output.
+
+
+<!-- ==================== Relation Tag Transformations ==================== -->
+
+<h3 id="H_1_3_3" title="Relations">Relation Tag Transformations</h3>
+
+The <em>type</em> tag is passed through without change.
+
+
+<h4 id="H_1_3_3_1">Routes</h4>
+
+The <em>route</em> tag can be used to determine whether a relation is part of a
+walking or bicycle route so that the <em>footroute</em> or <em>bicycleroute</em>
+properties can be applied to the highways that make up that relation.
+
+<p>
+
+The tag transformations that are applied for route relations are defined in the
+table below.
+
+<p>
+
+<table>
+  <caption>Route properties from different route types</caption>
+  <tr>
+    <th class="center">Relation Tag
+    <th class="center">footroute Property
+    <th class="center">bicycleroute Property
+  <tr>
+    <td class="center">foot, walking, hiking
+    <td class="center">yes
+    <td class="center">no
+  <tr>
+    <td class="center">bicycle
+    <td class="center">no
+    <td class="center">yes
+  <tr>
+    <td class="center">bicycle;foot, foot;bicycle
+    <td class="center">yes
+    <td class="center">yes
+</table>
+
+
+<h4 id="H_1_3_3_2">Turn Restrictions</h4>
+
+No tag transformations are defined for turn restriction relations but
+the <em>restriction</em> and <em>except</em> tags are passed through without
+change.
+
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer">
+
+<address>
+© Andrew M. Bishop - <a href="http://www.routino.org/">http://www.routino.org/</a>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</body>
+
+</html>
diff --git a/3rdparty/Routino/doc/html/usage.html b/3rdparty/Routino/doc/html/usage.html
new file mode 100644
index 0000000..9e21658
--- /dev/null
+++ b/3rdparty/Routino/doc/html/usage.html
@@ -0,0 +1,625 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<title>Routino : Usage</title>
+
+<!--
+ Routino documentation - usage
+
+ Part of the Routino routing software.
+
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see http://www.gnu.org/licenses/.
+-->
+
+<link href="style.css" type="text/css" rel="stylesheet">
+</head>
+
+<body>
+
+<!-- Header Start -->
+
+<div class="header">
+
+<h1>Routino : Usage</h1>
+
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2 id="H_1_1">Program Usage</h2>
+
+There are five programs that make up this software.  The first one takes the
+planet.osm datafile from OpenStreetMap (or other source of data using the same
+formats) and converts it into a local database.  The second program uses the
+database to determine an optimum route between two points.  The third program
+allows visualisation of the data and statistics to be extracted.  The fourth
+program allows dumping the raw parsed data for test purposes and the fifth is a
+test program for the tag transformations.
+
+<h3 id="H_1_1_1">planetsplitter</h3>
+
+This program reads in the OSM format XML file and splits it up to create the
+database that is used for routing.
+
+<pre class="boxed">
+Usage: planetsplitter [--help]
+                      [--dir=<dirname>] [--prefix=<name>]
+                      [--sort-ram-size=<size>] [--sort-threads=<number>]
+                      [--tmpdir=<dirname>]
+                      [--tagging=<filename>]
+                      [--loggable] [--logtime] [--logmemory]
+                      [--errorlog[=<name>]]
+                      [--parse-only | --process-only]
+                      [--append] [--keep] [--changes]
+                      [--max-iterations=<number>]
+                      [--prune-none]
+                      [--prune-isolated=<len>]
+                      [--prune-short=<len>]
+                      [--prune-straight=<len>]
+                      [<filename.osm> ... | <filename.osc> ...
+                       | <filename.pbf> ...
+                       | <filename.o5m> ... | <filename.o5c> ...
+                       | <filename.(osm|osc|o5m|o5c).bz2> ...
+                       | <filename.(osm|osc|o5m|o5c).gz> ...
+                       | <filename.(osm|osc|o5m|o5c).xz> ...]
+</pre>
+
+<dl>
+  <dt>--help
+  <dd>Prints out the help information.
+  <dt>--dir=<dirname>
+  <dd>Sets the directory name in which to save the results.
+    Defaults to the current directory.
+  <dt>--prefix=<name>
+  <dd>Sets the filename prefix for the files that are created.
+    Defaults to no prefix.
+  <dt>--sort-ram-size=<size>
+  <dd>Specifies the amount of RAM (in MB) to use for sorting the data.  If not
+    specified then 64 MB will be used in slim mode or 256 MB otherwise.
+  <dt>--sort-threads=<number>
+  <dd>The number of threads to use for data sorting (the sorting memory is
+    shared between the threads - too many threads and not enough memory will
+    reduce the performance).
+  <dt>--tmpdir=<dirname>
+  <dd>Specifies the name of the directory to store the temporary disk files.  If
+    not specified then it defaults to either the value of the --dir option or the
+    current directory.
+  <dt>--tagging=<filename>
+  <dd>Sets the filename containing the list of tagging rules in XML format for
+    the parsing the input files.  If the file doesn't exist then dirname, prefix
+    and "profiles.xml" will be combined and used, if that doesn't exist then the
+    file '/usr/local/share/routino/profiles.xml' (or custom installation
+    location) will be used.
+  <dt>--loggable
+  <dd>Print progress messages that are suitable for logging to a file; normally
+    an incrementing counter is printed which is more suitable for real-time
+    display than logging.
+  <dt>--logtime
+  <dd>Print the elapsed time for each processing step (minutes, seconds and milliseconds).
+  <dt>--logmemory
+  <dd>Print the maximum allocated and mapped memory for each processing step (MBytes).
+  <dt>--errorlog[=<name>]
+  <dd>Log OSM parsing and processing errors to 'error.log' or the specified file
+    name (the '--dir' and '--prefix' options are applied).  If the --append
+    option is used then the existing log file will be appended, otherwise a new
+    one will be created.  If the --keep option is also used a geographically
+    searchable database of error logs is created for use in the visualiser.
+  <dt>--parse-only
+  <dd>Parse the input files and store the data in intermediate files but don't
+    process the data into a routing database.  This option must be used with the
+    --append option for all except the first file.
+  <dt>--process-only
+  <dd>Don't read in any files but process the existing intermediate files
+    created by using the --parse-only option.
+  <dt>--append
+  <dd>Parse the input file and append the result to the existing intermediate
+    files; the appended file can be either an OSM file or an OSC change file.
+  <dt>--keep
+  <dd>Store a set of intermediate files after parsing the OSM files, sorting and
+    removing duplicates; this allows appending an OSC file and re-processing
+    later.
+  <dt>--changes
+  <dd>This option indicates that the data being processed contains one or more
+    OSC (OSM changes) files, they must be applied in time sequence if more than
+    one is used.  This option implies --append when parsing data files and
+    --keep when processing data.
+  <dt>--max-iterations=<number>
+  <dd>The maximum number of iterations to use when generating super-nodes and
+    super-segments.  Defaults to 5 which is normally enough.
+  <dt>--prune-none
+  <dd>Disable the prune options below, they can be re-enabled by adding them to
+    the command line after this option.
+  <dt>--prune-isolated=<length>
+  <dd>Remove the access permissions for a transport type from small disconnected
+    groups of segments and remove the segments if they end up with no access
+    permission (defaults to removing groups under 500m).
+  <dt>--prune-short=<length>
+  <dd>Remove short segments (defaults to removing segments up to a maximum
+    length of 5m).
+  <dt>--prune-straight=<length>
+  <dd>Remove nodes in almost straight highways (defaults to removing nodes up to
+    3m offset from a straight line).
+  <dt><filename.osm>, <filename.osc>, <filename.pbf>, <filename.o5m>, <filename.o5c>
+  <dd>Specifies the filename(s) to read data from.  Filenames ending '.pbf' will
+    be read as PBF, filenames ending in '.o5m' or '.o5c' will be read as
+    O5M/O5C, otherwise as XML.  Filenames ending '.bz2' will be bzip2
+    uncompressed (if bzip2 support compiled in).  Filenames ending '.gz' will be
+    gzip uncompressed (if gzip support compiled in).  Filenames ending '.xz'
+    will be xz uncompressed (if xz support compiled in).
+</dl>
+
+<p>
+<i>Note: In version 2.5 of Routino the ability to read data from the standard
+input has been removed.  This is because there is now the ability to read
+compressed files (bzip2, gzip, xz) and PBF files directly.  Also using standard
+input the file type cannot be auto-detected from the filename.</i>
+
+<p>
+Example usage 1:
+
+<pre class="boxed">
+planetsplitter --dir=data --prefix=gb great_britain.osm
+</pre>
+
+This will generate the output files 'data/gb-nodes.mem', 'data/gb-segments.mem'
+and 'data/gb-ways.mem'.  Multiple filenames can be specified on the command
+line and they will all be read in, combined and processed together.
+
+<p>
+Example usage 2:
+
+<pre class="boxed">
+planetsplitter --dir=data --prefix=gb --parse-only          great_britain_part1.osm
+planetsplitter --dir=data --prefix=gb --parse-only --append great_britain_part2.osm
+planetsplitter --dir=data --prefix=gb --parse-only --append ...
+planetsplitter --dir=data --prefix=gb --process-only
+</pre>
+
+This will generate the same output files as the first example but parsing the
+input files is performed separately from the data processing.  The first file
+read in must not use the --append option but the later ones must.
+
+<p>
+Example usage 3:
+
+<pre class="boxed">
+planetsplitter --dir=data --prefix=gb --keep    great_britain.osm
+
+planetsplitter --dir=data --prefix=gb --changes great_britain.osc
+</pre>
+
+This will generate the same output files as the first example.  The first
+command will process the complete file and keep some intermediate data for
+later.  The second command will apply a set of changes to the stored
+intermediate data and keep the updated intermediate files for repeating this
+step later with more change data.
+<p>
+The parsing and processing can be split into multiple commands as it was in
+example 2 with the --keep option used with --process-only for the initial OSM
+file(s) and the --changes option used with --parse-only or --process-only for
+every OSC file.
+
+
+<h3 id="H_1_1_2">router</h3>
+
+This program performs the calculation of the optimum routes using the database
+generated by the planetsplitter program.
+
+<pre class="boxed">
+Usage: router [--help | --help-profile | --help-profile-xml |
+                        --help-profile-json | --help-profile-perl ]
+              [--dir=<dirname>] [--prefix=<name>]
+              [--profiles=<filename>] [--translations=<filename>]
+              [--exact-nodes-only]
+              [--quiet | [--loggable] [--logtime] [--logmemory]]
+              [--output-html]
+              [--output-gpx-track] [--output-gpx-route]
+              [--output-text] [--output-text-all]
+              [--output-none] [--output-stdout]
+              [--profile=<name>]
+              [--transport=<transport>]
+              [--shortest | --quickest]
+              --lon1=<longitude> --lat1=<latitude>
+              --lon2=<longitude> --lon2=<latitude>
+              [ ... --lon99=<longitude> --lon99=<latitude>]
+              [--reverse] [--loop]
+              [--heading=<bearing>]
+              [--highway-<highway>=<preference> ...]
+              [--speed-<highway>=<speed> ...]
+              [--property-<property>=<preference> ...]
+              [--oneway=(0|1)] [--turns=(0|1)]
+              [--weight=<weight>]
+              [--height=<height>] [--width=<width>] [--length=<length>]
+</pre>
+
+<dl>
+  <dt>--help
+  <dd>Prints out the help information.
+  <dt>--help-profile
+  <dd>Prints out the selected transport profile (type, speed limits, highway
+    preferences etc.)
+  <dt>--help-profile-xml
+  <dd>Prints out all the loaded profiles as an XML file in the same format that
+    can be loaded in.
+  <dt>--help-profile-json
+  <dd>Prints out all the loaded profiles in JavaScript Object Notation (JSON)
+    format for use in the interactive webpage.
+  <dt>--help-profile-perl
+  <dd>Prints out all the loaded profiles as a Perl object for use in the router
+    CGI.
+  <dt>--dir=<dirname>
+  <dd>Sets the directory name in which to read the local database.
+    Defaults to the current directory.
+  <dt>--prefix=<name>
+  <dd>Sets the filename prefix for the files in the local database.
+    Defaults to no prefix.
+  <dt>--profiles=<filename>
+  <dd>Sets the filename containing the list of routing profiles in XML format.
+    If the file doesn't exist then dirname, prefix and "profiles.xml" will be
+    combined and used, if that doesn't exist then the file
+    '/usr/local/share/routino/profiles.xml' (or custom installation location)
+    will be used.
+  <dt>--translations=<filename>
+  <dd>Sets the filename containing the list of translations in XML format for
+    the output files.  If the file doesn't exist then dirname, prefix and
+    "translations.xml" will be combined and used, if that doesn't exist then the
+    file '/usr/local/share/routino/translations.xml' (or custom installation
+    location) will be used.
+  <dt>--exact-nodes-only
+  <dd>When processing the specified latitude and longitude points only select
+    the nearest node instead of finding the nearest point within a segment
+    (quicker but less accurate unless the points are already near nodes).
+  <dt>--quiet
+  <dd>Don't generate any screen output while running (useful for running in a script).
+  <dt>--loggable
+  <dd>Print progress messages that are suitable for logging to a file; normally
+    an incrementing counter is printed which is more suitable for real-time
+    display than logging.
+  <dt>--logtime
+  <dd>Print the elapsed time for each processing step (minutes, seconds and milliseconds).
+  <dt>--logmemory
+  <dd>Print the maximum allocated and mapped memory for each processing step (MBytes).
+  <dt>--language=<lang>
+  <dd>Select the language specified from the file of translations.  If this
+    option is not given and the file exists then the first language in the file
+    will be used.  If this option is not given and no file exists the
+    compiled-in default language (English) will be used.
+  <dt>--output-html
+  <dt>--output-gpx-track
+  <dt>--output-gpx-route
+  <dt>--output-text
+  <dt>--output-text-all
+  <dd>Generate the selected output file formats (HTML, GPX track file, GPX route
+  file, plain text route and/or plain text with all nodes).  If no output is
+  specified then all are generated, specifying any automatically disables those
+  not specified.
+  <dt>--output-none
+  <dd>Do not generate any output or read in any translations files.
+  <dt>--output-stdout
+  <dd>Write to stdout instead of a file (requires exactly one output format
+    option, implies '--quiet').
+  <dt>--profile=<name>
+  <dd>Specifies the name of the profile to use.
+  <dt>--transport=<transport>
+  <dd>Select the type of transport to use, <transport> can be set to:
+    <ul>
+      <li>foot       = Foot
+      <li>horse      = Horse
+      <li>wheelchair = Wheelchair
+      <li>bicycle    = Bicycle
+      <li>moped      = Moped     (Small motorcycle, limited speed)
+      <li>motorcycle = Motorcycle
+      <li>motorcar   = Motorcar
+      <li>goods      = Goods     (Small lorry, van)
+      <li>hgv        = HGV       (Heavy Goods Vehicle - large lorry)
+      <li>psv        = PSV       (Public Service Vehicle - bus, coach)
+    </ul>
+    Defaults to 'motorcar', this option also selects the default profile
+    information if the '--profile' option is not given and a profile matching
+    the transport name is found.
+  <dt>--shortest
+  <dd>Find the shortest route between the waypoints.
+  <dt>--quickest
+  <dd>Find the quickest route between the waypoints.
+  <dt>--lon1=<longitude>, --lat1=<latitude>
+  <dt>--lon2=<longitude>, --lat2=<latitude>
+  <dt>... --lon99=<longitude>, --lat99=<latitude>
+  <dd>The location of the waypoints that make up the start, middle and end
+  points of the route.  Up to 99 waypoints can be specified and the route will
+  pass through each of the specified ones in sequence.  The algorithm will use
+  the closest node or point within a segment that allows the specified traffic
+  type.
+  <dt>--reverse
+  <dd>Find a route between the waypoints in reverse order.
+  <dt>--loop
+  <dd>Find a route that returns to the first waypoint after the last one.
+  <dt>--heading=<bearing>
+  <dd>Specifies the initial direction of travel at the start of the route (from
+  the lowest numbered waypoint) as a compass bearing from 0 to 360 degrees.
+  <dt>--highway-<highway>=<preference>
+  <dd>Selects the percentage preference for using each particular type of
+      highway.  The value of <highway> can be selected from:
+    <ul>
+      <li>motorway     = Motorway
+      <li>trunk        = Trunk
+      <li>primary      = Primary
+      <li>secondary    = Secondary
+      <li>tertiary     = Tertiary
+      <li>unclassified = Unclassified
+      <li>residential  = Residential
+      <li>service      = Service
+      <li>track        = Track
+      <li>cycleway     = Cycleway
+      <li>path         = Path
+      <li>steps        = Steps
+      <li>ferry        = Ferry
+    </ul>
+    Default value depends on the profile selected by the --transport option.
+  <dt>--speed-<highway>=<speed>
+  <dd>Selects the speed limit in km/hour for each type of highway.  Default
+      value depends on the profile selected by the --transport option.
+  <dt>--property-<property>=<preference>
+  <dd>Selects the percentage preference for using each particular highway
+      property
+    The value of <property> can be selected from:
+    <ul>
+      <li>paved        = Paved (suitable for normal wheels)
+      <li>multilane    = Multiple lanes
+      <li>bridge       = Bridge
+      <li>tunnel       = Tunnel
+      <li>footroute    = A route marked for foot travel
+      <li>bicycleroute = A route marked for bicycle travel
+    </ul>
+    Default value depends on the profile selected by the --transport option.
+  <dt>--oneway=[0|1]
+  <dd>Selects if the direction of oneway streets are to be obeyed (useful to not
+      obey them when walking).  Default value depends on the profile selected by
+      the --transport option.
+  <dt>--turns=[0|1]
+  <dd>Selects if turn restrictions are to be obeyed (useful to not obey them
+      when walking).  Default value depends on the profile selected by the
+      --transport option.
+  <dt>--weight=<weight>
+  <dd>Specifies the weight of the mode of transport in tonnes; ensures that the
+      weight limit on the highway is not exceeded.  Default value depends on the
+      profile selected by the --transport option.
+  <dt>--height=<height>
+  <dd>Specifies the height of the mode of transport in metres; ensures that the
+      height limit on the highway is not exceeded.  Default value depends on the
+      profile selected by the --transport option.
+  <dt>--width=<width>
+  <dd>Specifies the width of the mode of transport in metres; ensures that the
+      width limit on the highway is not exceeded.  Default value depends on the
+      profile selected by the --transport option.
+  <dt>--length=<length>
+  <dd>Specifies the length of the mode of transport in metres; ensures that the
+      length limit on the highway is not exceeded.  Default value depends on the
+      profile selected by the --transport option.
+</dl>
+
+<p>
+The meaning of the <preference> parameter in the command line options is
+slightly different for the highway preferences and the property preferences.
+For the highway preference consider the choice between two possible highways
+between the start and finish when looking for the shortest route.  If highway A
+has a preference of 100% and highway B has a preference of 90% then highway A
+will be chosen even if it is up to 11% longer (100/90 = 111%).  For the highway
+properties each highway either has a particular property or not.  If the
+preference for the property is 60% then a highway with the property has a
+preference of 77% (sqrt(60%)) and one without has a preference of 63%
+(sqrt(100-60%)).  A highway with the property will be chosen even if it is up to
+22% longer than one without the property (77/63 = 122%).  The overall preference
+for each highway segment is the product of the preference for the highway type
+and all of the preferences for the highway properties.
+
+<p>
+Example usage (motorcycle journey, scenic route, not very fast):
+
+<pre class="boxed">
+router --dir=data --prefix=gb --transport=motorcycle --highway-motorway=0 \
+       --highway-trunk=0 --speed-primary=80 --speed-secondary=80 --quickest
+</pre>
+
+This will use the files 'data/gb-nodes.mem', 'data/gb-segments.mem' and
+'data/gb-ways.mem' to find the quickest route by motorcycle not using motorways
+or trunk roads and not exceeding 80 km/hr.
+
+
+<h3 id="H_1_1_3">filedumper</h3>
+
+This program is used to extract statistics from the database, extract particular
+information for visualisation purposes or for dumping the database contents.
+
+<pre class="boxed">
+Usage: filedumper [--help]
+                  [--dir=<dirname>] [--prefix=<name>]
+                  [--statistics]
+                  [--visualiser --latmin=<latmin> --latmax=<latmax>
+                                --lonmin=<lonmin> --lonmax=<lonmax>
+                                --data=<data-type>]
+                  [--dump [--node=<node> ...]
+                          [--segment=<segment> ...]
+                          [--way=<way> ...]
+                          [--turn-relation=<relation> ...]
+                          [--errorlog=<number> ...]]
+                  [--dump-osm [--no-super]
+                              [--latmin=<latmin> --latmax=<latmax>
+                               --lonmin=<lonmin> --lonmax=<lonmax>]]
+                  [--dump-visualiser [--data=node<node>]
+                                     [--data=segment<segment>]
+                                     [--data=turn-relation<rel>]
+                                     [--data=errorlog<number>]]
+</pre>
+
+<dl>
+  <dt>--help
+  <dd>Prints out the help information.
+  <dt>--dir=<dirname>
+  <dd>Sets the directory name in which to read the local database.
+    Defaults to the current directory.
+  <dt>--prefix=<name>
+  <dd>Sets the filename prefix for the files in the local database.
+  <dt>--statistics
+  <dd>Prints out statistics about the database files.
+  <dt>--visualiser
+  <dd>Selects a data visualiser mode which will output a set of data according
+    to the other parameters below.
+    <dl>
+      <dt>--latmin=<latmin> --latmax=<latmax>
+      <dd>The range of latitudes to print the data for.
+      <dt>--lonmin=<lonmin> --lonmax=<lonmax>
+      <dd>The range of longitudes to print the data for.
+      <dt>--data=<data-type>
+      <dd>The type of data to output, <data-type> can be selected from:
+        <ul>
+          <li>junctions   = segment count at each junction.
+          <li>super       = super-node and super-segments.
+          <li>waytype-*   = segments of oneway, cyclebothways or roundabout type.
+          <li>highway-*   = segments of the specified highway type
+          (e.g. highway-primary to display segments ofprimary roads).
+          <li>transport-* = segments allowing the specified transport type
+          (e.g. transport-foot to display segments accessible on foot).
+          <li>turns       = turn restrictions.
+          <li>speed       = speed limits.
+          <li>weight      = weight limits.
+          <li>height      = height limits.
+          <li>width       = width limits.
+          <li>length      = length limits.
+          <li>property-*  = segments having the specified property
+          (e.g. property-paved to display segments of paved highway).
+          <li>errorlogs   = errors logged during parsing.
+        </ul>
+    </dl>
+  <dt>--dump
+  <dd>Selects a data dumping mode which allows looking at individual items in
+    the databases (specifying 'all' instead of a number dumps all of them).
+    More than one of the following parameters can be specified on the command
+    line.
+    <dl>
+      <dt>--node=<node>
+      <dd>Prints the information about the selected node number (internal
+        number, not the node id number in the original source file).
+      <dt>--segment=<segment>
+      <dd>Prints the information about the selected segment number.
+      <dt>--way=<way>
+      <dd>Prints the information about the selected way number (internal
+        number, not the way id number in the original source file).
+      <dt>--turn-relation=<relation>
+      <dd>Prints the information about the selected turn relation number
+        (internal number, not the relation id number in the original source
+        file).
+      <dt>--errorlog=<number>
+      <dd>Prints the information about the selected error log that was stored
+        when the data was parsed.
+    </dl>
+  <dt>--osm-dump
+  <dd>Dumps the contents of the database as an OSM format XML file, the whole
+    database will be dumped unless the latitude and longitude ranges are
+    specified.
+    <dl>
+      <dt>--no-super
+      <dd>The super segments will not be output.
+      <dt>--latmin=<latmin> --latmax=<latmax>
+      <dd>The range of latitudes to dump the data for.
+      <dt>--lonmin=<lonmin> --lonmax=<lonmax>
+      <dd>The range of longitudes to dump the data for.
+    </dl>
+  <dt>--dump-visualiser
+  <dd>Dumps the contents of the database as HTML formatted items for display in
+    the visualiser web page.
+    <dl>
+      <dt>--data=node<node>
+      <dd>Prints the information about the selected node number (internal
+        node number, not from the original source file).
+      <dt>--data=segment<segment>
+      <dd>Prints the information about the selected segment number as if it was
+        a way (internal segment number, unrelated to original source file).
+      <dt>--data=turn-relation<relation>
+      <dd>Prints the information about the selected turn relation number
+        (internal turn relation number, not from the original source file).
+      <dt>--data=errorlog<number>
+      <dd>Prints the information about the selected error log that was stored
+        when the data was parsed.
+    </dl>
+</dl>
+
+
+<h3 id="H_1_1_4">filedumperx</h3>
+
+This program is a modified version of filedumper that will dump out the contents
+of the intermediate data that is saved by planetsplitter after processing using
+the --keep or --changes option.  This is intended for test purposes only and
+gives no useful information about the routing database.
+
+<pre class="boxed">
+Usage: filedumperx [--help]
+                   [--dir=<dirname>] [--prefix=<name>]
+                   [--dump [--nodes]
+                           [--ways]
+                           [--route-relations]
+                           [--turn-relations]]
+</pre>
+
+<dl>
+  <dt>--help
+  <dd>Prints out the help information.
+  <dt>--dir=<dirname>
+  <dd>Sets the directory name in which to read the local database.
+    Defaults to the current directory.
+  <dt>--prefix=<name>
+  <dd>Sets the filename prefix for the files in the local database.
+  <dt>--dump
+  <dd>Dumps the complete set of data in the intermediate files that are written
+    by planetsplitter using the --keep or --changes options.
+    <dl>
+      <dt>--nodes
+      <dd>Dumps the node data.
+      <dt>--ways
+      <dd>Dumps the way data.
+      <dt>--route-relations
+      <dd>Dumps the route relation data.
+      <dt>--turn-relations
+      <dd>Dumps the turn relation data.
+    </dl>
+</dl>
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer">
+
+<address>
+© Andrew M. Bishop - <a href="http://www.routino.org/">http://www.routino.org/</a>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</body>
+
+</html>
diff --git a/3rdparty/Routino/extras/Makefile b/3rdparty/Routino/extras/Makefile
new file mode 100644
index 0000000..f36a56d
--- /dev/null
+++ b/3rdparty/Routino/extras/Makefile
@@ -0,0 +1,67 @@
+# Extra files Makefile
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2013 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# All configuration is in the top-level Makefile.conf
+
+include ../Makefile.conf
+
+# Sub-directories and sub-makefiles
+
+SUBFILES=$(wildcard */Makefile)
+SUBDIRS=$(foreach f,$(SUBFILES),$(dir $f))
+
+########
+
+all:
+	for dir in $(SUBDIRS); do \
+	   ( cd $$dir && $(MAKE) $@ ); \
+	done
+
+########
+
+test:
+	for dir in $(SUBDIRS); do \
+	   ( cd $$dir && $(MAKE) $@ ); \
+	done
+
+########
+
+install:
+	for dir in $(SUBDIRS); do \
+	   ( cd $$dir && $(MAKE) $@ ); \
+	done
+
+########
+
+clean:
+	for dir in $(SUBDIRS); do \
+	   ( cd $$dir && $(MAKE) $@ ); \
+	done
+
+########
+
+distclean:
+	for dir in $(SUBDIRS); do \
+	   ( cd $$dir && $(MAKE) $@ ); \
+	done
+
+########
+
+.PHONY:: all test install clean distclean
diff --git a/3rdparty/Routino/extras/README.txt b/3rdparty/Routino/extras/README.txt
new file mode 100644
index 0000000..d5faff4
--- /dev/null
+++ b/3rdparty/Routino/extras/README.txt
@@ -0,0 +1,27 @@
+                                 ROUTINO EXTRAS
+                                 ==============
+
+This directory contains some programs and scripts that although distributed with
+Routino are not necessary components of a working OSM router.  They are
+generally either programs that use some components of Routino (i.e. they are
+compiled and linked with some of the Routino source code) or they are scripts to
+be used to process the outputs of Routino.
+
+Each program or script has its own directory which contains all of the necessary
+source code, documentation and/or web pages for that program or script.  None of
+them will be installed when Routino is installed.
+
+--------------------------------------------------------------------------------
+
+tagmodifier - A program to read an OSM XML file and process it using a Routino
+              tagging rules file to create a modified output XML file.
+
+errorlog    - Scripts for processing the error log file (created by running
+              planetsplitter with the --errorlog option).
+
+plot-time   - Plots the output of 'planetsplitter --loggable --logtime' to show
+              how long each part of the processing takes.
+
+find-fixme -  A modified version of the Routino planetsplitter and filedumper
+              programs to scan an OSM file for "fixme" tags and create a
+              database so that web pages provided can display them.
diff --git a/3rdparty/Routino/extras/errorlog/README.txt b/3rdparty/Routino/extras/errorlog/README.txt
new file mode 100644
index 0000000..2e2d065
--- /dev/null
+++ b/3rdparty/Routino/extras/errorlog/README.txt
@@ -0,0 +1,29 @@
+                              Error Log Summariser
+                              ====================
+
+This Perl script can be used to process the log file generated by runing
+'planetsplitter --errorlog' and generate a summary of the most common types of
+errors.
+
+summarise-log.pl
+----------------
+
+Example usage:
+
+summarise-log.pl < error.log
+
+          Generate a summary of the number of each type of error that appear in
+          the error log file as plain text.
+
+
+summarise-log.pl -v < error.log
+
+          Generate a verbose version of the plain text summary of errors with
+          each error item (node, way or relation) listed.
+
+
+summarise-log.pl -html < error.log
+
+          Generate an HTML file with a summary of the number of errors of each
+          type with links to each of the items (node, way or relation) on the
+          OSM website.
diff --git a/3rdparty/Routino/extras/errorlog/summarise-log.pl b/3rdparty/Routino/extras/errorlog/summarise-log.pl
new file mode 100755
index 0000000..6b89f99
--- /dev/null
+++ b/3rdparty/Routino/extras/errorlog/summarise-log.pl
@@ -0,0 +1,295 @@
+#!/usr/bin/perl
+#
+# Routino log summary tool.
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2011-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+
+# Command line
+
+my $verbose=0;
+$verbose=1 if($#ARGV==0 && $ARGV[0] eq "-v");
+
+my $html=0;
+$html=1 if($#ARGV==0 && $ARGV[0] eq "-html");
+
+die "Usage: $0 [-v | -html] < <error-log-file>\n" if($#ARGV>0 || ($#ARGV==0 && !$verbose && !$html));
+
+
+# Read in each line from the error log and store them
+
+my %errors=();
+my %errorids=();
+my %errortypes=();
+
+while(<STDIN>)
+  {
+   s%\r*\n%%;
+
+   my $errorid="";
+   my $errortype="";
+
+   if(m%nodes ([0-9]+) and ([0-9]+) in way ([0-9]+)%i) # Special case pair of nodes and a way
+     {
+      $errorid="($1 $2 $3)";
+      $errortype="N2W";
+      s%nodes [0-9]+ and [0-9]+ in way [0-9]+%nodes <node-id1> and <node-id2> in way <way-id>%;
+     }
+
+   elsif(m%node ([0-9]+) in way ([0-9]+)%i) # Special case node and a way
+     {
+      $errorid="($1 $2)";
+      $errortype="NW";
+      s%Node [0-9]+ in way [0-9]+%Node <node-id> in way <way-id>%;
+     }
+
+   elsif(m%way ([0-9]+) contains node ([0-9]+)%i) # Special case way and node
+     {
+      $errorid="($1 $2)";
+      $errortype="WN";
+      s%Way [0-9]+ contains node [0-9]+%Way <way-id> contains node <node-id>%;
+     }
+
+   elsif(m%nodes ([0-9]+) and ([0-9]+)%i) # Special case pair of nodes
+     {
+      $errorid="($1 $2)";
+      $errortype="N2";
+      s%nodes [0-9]+ and [0-9]+%nodes <node-id1> and <node-id2>%;
+     }
+
+   elsif(m%Segment (contains|connects) node ([0-9]+)%) # Special case node
+     {
+      $errorid=$2;
+      $errortype="N";
+      s%node [0-9]+%node <node-id>%;
+     }
+
+   elsif(m%Relation ([0-9]+).* contains Node ([0-9]+)%) # Special case relation/node
+     {
+      $errorid="($1 $2)";
+      $errortype="RN";
+      s%Relation [0-9]+%Relation <relation-id>%;
+      s%Node [0-9]+%node <node-id>%;
+     }
+
+   elsif(m%Relation ([0-9]+).* contains Way ([0-9]+)%) # Generic case relation/way
+     {
+      $errorid="($1 $2)";
+      $errortype="RW";
+      s%Relation [0-9]+%Relation <relation-id>%;
+      s%Way [0-9]+%way <way-id>%;
+     }
+
+   elsif(!m%Way ([0-9]+)% && !m%Relation ([0-9]+)% && m%Node ([0-9]+)%) # Generic node
+     {
+      $errorid=$1;
+      $errortype="N";
+      s%Node [0-9]+%Node <node-id>%;
+     }
+
+   elsif(!m%Node ([0-9]+)% && !m%Relation ([0-9]+)% && m%Way ([0-9]+)%) # Generic way
+     {
+      $errorid=$1;
+      $errortype="W";
+      s%Way [0-9]+%Way <way-id>%;
+     }
+
+   elsif(!m%Node ([0-9]+)% && !m%Way ([0-9]+)% && m%Relation ([0-9]+)%) # Generic relation
+     {
+      $errorid=$1;
+      $errortype="R";
+      s%Relation [0-9]+%Relation <relation-id>%;
+     }
+
+   else
+     {
+      $errorid="ERROR";
+      $errortype="E";
+      warn "Unrecognised error message '$_'\n";
+     }
+
+   $errors{$_}++;
+
+   if($verbose || $html)
+     {
+      if(defined $errorids{$_})
+        {
+         push(@{$errorids{$_}},$errorid);
+        }
+      else
+        {
+         $errorids{$_}=[$errorid];
+        }
+     }
+
+   if($html)
+     {
+      $errortypes{$_}=$errortype;
+     }
+  }
+
+
+# Print out the results as text
+
+if( ! $html )
+  {
+   foreach my $error (sort { if ( $errors{$b} == $errors{$a} ) { return $errors{$a} cmp $errors{$b} }
+                             else                              { return $errors{$b} <=> $errors{$a} } } (keys %errors))
+     {
+      printf "%9d : $error\n",$errors{$error};
+
+      if($verbose)
+        {
+         my @ids=sort({ return $a <=> $b } @{$errorids{$error}});
+
+         print "            ".join(",", at ids)."\n";
+        }
+     }
+  }
+
+# Print out the results as HTML
+
+else
+  {
+
+   print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n".
+         "<HTML>\n".
+         "\n".
+         "<HEAD>\n".
+         "<TITLE>Routino Error Log File Summary</TITLE>\n".
+         "<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n".
+         "<STYLE type=\"text/css\">\n".
+         "<!--\n".
+         "   body {font-family: sans-serif; font-size: 12px;}\n".
+         "   h1   {font-family: sans-serif; font-size: 14px; font-style: bold;}\n".
+         "   h2   {font-family: sans-serif; font-size: 13px; font-style: bold;}\n".
+         "   h3   {font-family: sans-serif; font-size: 12px; font-style: bold;}\n".
+         "-->\n".
+         "</STYLE>\n".
+         "</HEAD>\n".
+         "\n".
+         "<BODY>\n".
+         "\n".
+         "<h1>Routino Error Log File Summary</h1>\n".
+         "\n".
+         "This HTML file contains a summary of the Routino OSM parser error log file with\n".
+         "links to the OSM website that allow browsing each of the nodes, ways or relations\n".
+         "that are responsible for the error messages.\n".
+         "\n";
+
+   my %errortypeorder=(
+                       "N"   , 1,
+                       "NW"  , 2,
+                       "WN"  , 3,
+                       "N2W" , 4,
+                       "N2"  , 5,
+                       "W"   , 6,
+                       "R"   , 7,
+                       "RN"  , 8,
+                       "RW"  , 9,
+                       "E"   , 10
+                      );
+
+   my %errortypelabel=(
+                       "N"   , "Nodes",
+                       "NW"  , "Node in a Way",
+                       "WN"  , "Way contains Node",
+                       "N2W" , "Node Pairs in a Way",
+                       "N2"  , "Node Pairs",
+                       "W"   , "Ways",
+                       "R"   , "Relations",
+                       "RN"  , "Relations/Nodes",
+                       "RW"  , "Relations/Ways",
+                       "E"   , "ERROR"
+                      );
+
+   my $lasterrortype="";
+
+   foreach my $error (sort { if    ( $errortypes{$b} ne $errortypes{$a} ) { return $errortypeorder{$errortypes{$a}} <=> $errortypeorder{$errortypes{$b}} }
+                             elsif ( $errors{$b}     == $errors{$a} )     { return $errors{$a} cmp $errors{$b} }
+                             else                                         { return $errors{$b} <=> $errors{$a} } } (keys %errors))
+     {
+      my $errorhtml=$error;
+
+      $errorhtml =~ s/&/&/g;
+      $errorhtml =~ s/</</g;
+      $errorhtml =~ s/>/>/g;
+
+      if($errortypes{$error} ne $lasterrortype)
+        {
+         print "<h2>$errortypelabel{$errortypes{$error}}</h2>\n";
+         $lasterrortype=$errortypes{$error};
+        }
+
+      print "<h3>$errorhtml</h3>\n";
+
+      if($errors{$error}>100)
+        {
+         print "$errors{$error} occurences (not listed).\n";
+        }
+      else
+        {
+         my @ids=sort({ return $a <=> $b } @{$errorids{$error}});
+
+         my $first=1;
+
+         foreach my $id (@ids)
+           {
+            if($first)
+              {
+               print "$errortypelabel{$errortypes{$error}}:\n";
+              }
+            else
+              {
+               print ",";
+              }
+
+            $first=0;
+
+            print "<a href=\"http://www.openstreetmap.org/browse/node/$id\">$id</a>" if($errortypes{$error} eq "N");
+            print "<a href=\"http://www.openstreetmap.org/browse/way/$id\">$id</a>" if($errortypes{$error} eq "W");
+            print "<a href=\"http://www.openstreetmap.org/browse/relation/$id\">$id</a>" if($errortypes{$error} eq "R");
+
+            if($errortypes{$error} eq "NW" || $errortypes{$error} eq "WN" || $errortypes{$error} eq "N2" || $errortypes{$error} eq "RN" || $errortypes{$error} eq "RW")
+              {
+               $id =~ m%\(([0-9]+) ([0-9]+)\)%;
+               print "(<a href=\"http://www.openstreetmap.org/browse/node/$1\">$1</a> <a href=\"http://www.openstreetmap.org/browse/way/$2\">$2</a>)" if($errortypes{$error} eq "NW");
+               print "(<a href=\"http://www.openstreetmap.org/browse/way/$1\">$1</a> <a href=\"http://www.openstreetmap.org/browse/node/$2\">$2</a>)" if($errortypes{$error} eq "WN");
+               print "(<a href=\"http://www.openstreetmap.org/browse/node/$1\">$1</a> <a href=\"http://www.openstreetmap.org/browse/node/$2\">$2</a>)" if($errortypes{$error} eq "N2");
+               print "(<a href=\"http://www.openstreetmap.org/browse/relation/$1\">$1</a> <a href=\"http://www.openstreetmap.org/browse/node/$2\">$2</a>)" if($errortypes{$error} eq "RN");
+               print "(<a href=\"http://www.openstreetmap.org/browse/relation/$1\">$1</a> <a href=\"http://www.openstreetmap.org/browse/way/$2\">$2</a>)" if($errortypes{$error} eq "RW");
+              }
+
+            if($errortypes{$error} eq "N2W")
+              {
+               $id =~ m%\(([0-9]+) ([0-9]+) ([0-9]+)\)%;
+               print "(<a href=\"http://www.openstreetmap.org/browse/node/$1\">$1</a> <a href=\"http://www.openstreetmap.org/browse/node/$2\">$2</a> <a href=\"http://www.openstreetmap.org/browse/way/$3\">$3</a>)" if($errortypes{$error} eq "N2W");
+              }
+
+            print "\n";
+           }
+        }
+     }
+
+   print "\n".
+         "</BODY>\n".
+         "\n".
+         "</HTML>\n";
+}
diff --git a/3rdparty/Routino/extras/find-fixme/Makefile b/3rdparty/Routino/extras/find-fixme/Makefile
new file mode 100644
index 0000000..28337fd
--- /dev/null
+++ b/3rdparty/Routino/extras/find-fixme/Makefile
@@ -0,0 +1,191 @@
+# find-fixme Makefile
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2013-2015 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# All configuration is in the top-level Makefile.conf
+
+include ../../Makefile.conf
+
+# Web file paths
+
+WEBBINDIR=web/bin
+WEBDATADIR=web/data
+WEBWWWDIR=web/www
+
+# Compilation targets
+
+C=$(wildcard *.c)
+D=$(wildcard .deps/*.d)
+
+ROUTINO_SRC=../../src
+ROUTINO_WEBWWWDIR=../../web/www/routino
+ROUTINO_DOCDIR=../../doc/html
+
+EXE=fixme-finder fixme-finder-slim fixme-dumper fixme-dumper-slim
+DATA=fixme.xml
+WWW_COPY=page-elements.css page-elements.js maplayout.css mapprops.js maploader.js
+DOC_COPY=style.css
+
+########
+
+all: all-bin all-data all-www
+
+all-bin: $(EXE)
+	@[ -d $(WEBBINDIR) ] || mkdir -p $(WEBBINDIR)
+	@for file in $(EXE); do \
+	    if [ ! -f $(WEBBINDIR)/$$file ] || [ $$file -nt $(WEBBINDIR)/$$file ]; then \
+	       echo cp $$file $(WEBBINDIR) ;\
+	       cp -f $$file $(WEBBINDIR) ;\
+	    fi ;\
+	 done
+
+all-data:
+	@[ -d $(WEBDATADIR) ] || mkdir -p $(WEBDATADIR)
+	@for file in $(DATA); do \
+	    if [ ! -f $(WEBDATADIR)/$$file ] || [ $$file -nt $(WEBDATADIR)/$$file ]; then \
+	       echo cp $$file $(WEBDATADIR) ;\
+	       cp -f $$file $(WEBDATADIR) ;\
+	    fi ;\
+	 done
+
+all-www:
+	@for file in $(WWW_COPY); do \
+	    if [ ! -f $(WEBWWWDIR)/$$file ] || [ $(ROUTINO_WEBWWWDIR)/$$file -nt $(WEBWWWDIR)/$$file ]; then \
+	       echo cp $(ROUTINO_WEBWWWDIR)/$$file $(WEBWWWDIR) ;\
+	       cp -f $(ROUTINO_WEBWWWDIR)/$$file $(WEBWWWDIR) ;\
+	    fi ;\
+	 done
+	@for file in $(DOC_COPY); do \
+	    if [ ! -f $(WEBWWWDIR)/$$file ] || [ $(ROUTINO_DOCDIR)/$$file -nt $(WEBWWWDIR)/$$file ]; then \
+	       echo cp $(ROUTINO_DOCDIR)/$$file $(WEBWWWDIR) ;\
+	       cp -f $(ROUTINO_DOCDIR)/$$file $(WEBWWWDIR) ;\
+	    fi ;\
+	 done
+
+########
+
+FIXME_FINDER_OBJ=fixme-finder.o osmparser.o \
+	       	 $(ROUTINO_SRC)/nodesx.o $(ROUTINO_SRC)/segmentsx.o $(ROUTINO_SRC)/waysx.o $(ROUTINO_SRC)/relationsx.o \
+	       	 $(ROUTINO_SRC)/ways.o $(ROUTINO_SRC)/types.o \
+	       	 $(ROUTINO_SRC)/files.o $(ROUTINO_SRC)/logging.o $(ROUTINO_SRC)/logerror.o $(ROUTINO_SRC)/errorlogx.o \
+	       	 $(ROUTINO_SRC)/sorting.o \
+	       	 $(ROUTINO_SRC)/xmlparse.o $(ROUTINO_SRC)/tagging.o \
+	       	 $(ROUTINO_SRC)/uncompress.o $(ROUTINO_SRC)/osmxmlparse.o $(ROUTINO_SRC)/osmpbfparse.o $(ROUTINO_SRC)/osmo5mparse.o
+
+ifdef MINGW
+FIXME_FINDER_OBJ+=$(ROUTINO_SRC)/mman-win32.o
+endif
+
+fixme-finder : $(FIXME_FINDER_OBJ)
+	$(LD) $(FIXME_FINDER_OBJ) -o $@ $(LDFLAGS)
+
+########
+
+FIXME_FINDER_SLIM_OBJ=fixme-finder-slim.o osmparser.o \
+	       	      $(ROUTINO_SRC)/nodesx-slim.o $(ROUTINO_SRC)/segmentsx-slim.o $(ROUTINO_SRC)/waysx-slim.o $(ROUTINO_SRC)/relationsx-slim.o \
+	              $(ROUTINO_SRC)/ways.o $(ROUTINO_SRC)/types.o \
+	       	      $(ROUTINO_SRC)/files.o $(ROUTINO_SRC)/logging.o $(ROUTINO_SRC)/logerror-slim.o $(ROUTINO_SRC)/errorlogx-slim.o \
+	              $(ROUTINO_SRC)/sorting.o \
+	       	      $(ROUTINO_SRC)/xmlparse.o $(ROUTINO_SRC)/tagging.o \
+	       	      $(ROUTINO_SRC)/uncompress.o $(ROUTINO_SRC)/osmxmlparse.o $(ROUTINO_SRC)/osmpbfparse.o $(ROUTINO_SRC)/osmo5mparse.o
+
+ifdef MINGW
+FIXME_FINDER_SLIM_OBJ+=$(ROUTINO_SRC)/mman-win32.o
+endif
+
+fixme-finder-slim : $(FIXME_FINDER_SLIM_OBJ)
+	$(LD) $(FIXME_FINDER_SLIM_OBJ) -o $@ $(LDFLAGS)
+
+########
+
+FIXME_DUMPER_OBJ=fixme-dumper.o \
+	         $(ROUTINO_SRC)/errorlog.o \
+	         $(ROUTINO_SRC)/files.o $(ROUTINO_SRC)/logging.o $(ROUTINO_SRC)/xmlparse.o
+
+ifdef MINGW
+FIXME_DUMPER_OBJ+=$(ROUTINO_SRC)/mman-win32.o
+endif
+
+fixme-dumper : $(FIXME_DUMPER_OBJ)
+	$(LD) $(FIXME_DUMPER_OBJ) -o $@ $(LDFLAGS)
+
+########
+
+FIXME_DUMPER_SLIM_OBJ=fixme-dumper-slim.o \
+	              $(ROUTINO_SRC)/errorlog-slim.o \
+	              $(ROUTINO_SRC)/files.o $(ROUTINO_SRC)/logging.o $(ROUTINO_SRC)/xmlparse.o
+
+ifdef MINGW
+FIXME_DUMPER_SLIM_OBJ+=$(ROUTINO_SRC)/mman-win32.o
+endif
+
+fixme-dumper-slim : $(FIXME_DUMPER_SLIM_OBJ)
+	$(LD) $(FIXME_DUMPER_SLIM_OBJ) -o $@ $(LDFLAGS)
+
+########
+
+$(ROUTINO_SRC)/%.o :
+	cd $(ROUTINO_SRC) && $(MAKE) $(notdir $@)
+
+$(ROUTINO_SRC)/%-slim.o :
+	cd $(ROUTINO_SRC) && $(MAKE) $(notdir $@)
+
+%.o : %.c
+	@[ -d .deps ] || mkdir .deps
+	$(CC) -c $(CFLAGS) -DSLIM=0 -I$(ROUTINO_SRC) $< -o $@ -MMD -MP -MF $(addprefix .deps/,$(addsuffix .d,$(basename $@)))
+
+%-slim.o : %.c
+	@[ -d .deps ] || mkdir .deps
+	$(CC) -c $(CFLAGS) -DSLIM=1 -I$(ROUTINO_SRC) $< -o $@ -MMD -MP -MF $(addprefix .deps/,$(addsuffix .d,$(basename $@)))
+
+########
+
+test:
+
+########
+
+install:
+
+########
+
+clean:
+	rm -f *~
+	rm -f *.o
+	cd $(WEBBINDIR) && rm -f $(EXE) *.exe
+	cd $(WEBDATADIR) && rm -f $(DATA)
+	cd $(WEBWWWDIR) && rm -f $(WWW_COPY)
+	cd $(WEBWWWDIR) && rm -f $(DOC_COPY)
+	rm -f $(EXE) *.exe
+	rm -f $(D)
+	rm -fr .deps
+	rm -f core
+
+########
+
+distclean: clean
+
+########
+
+include $(D)
+
+########
+
+.PHONY:: all test install clean distclean
+
+.PHONY:: all-bin all-data all-www
diff --git a/3rdparty/Routino/extras/find-fixme/README.txt b/3rdparty/Routino/extras/find-fixme/README.txt
new file mode 100644
index 0000000..0286bab
--- /dev/null
+++ b/3rdparty/Routino/extras/find-fixme/README.txt
@@ -0,0 +1,97 @@
+                            Find and Display FIXME tags
+                            ===========================
+
+The "fixme" tag is often used in OSM data to mark an item whose details are not
+completely known - as a reminder or request for somebody to check it.  Since
+Routino can now generate a map of tagging problems that it finds it is easy to
+extend this to finding all "fixme" tags.  The files in this directory provide a
+complete set of executables and web pages for extracting and displaying all
+items with "fixme" tags on a map.
+
+Editing fixme.xml and changing the rules for selecting tags allows for creating
+custom databases to display items containing any desired tag(s).
+
+
+fixme-finder
+------------
+
+This program is a modified version of the Routino planetsplitter program and can
+be used on an OSM file to extract the fixme tags and generate a database of
+them.
+
+
+Usage: fixme-finder [--help]
+                    [--dir=<dirname>]
+                    [--sort-ram-size=<size>] [--sort-threads=<number>]
+                    [--tmpdir=<dirname>]
+                    [--tagging=<filename>]
+                    [--loggable] [--logtime] [--logmemory]
+                    [<filename.osm> ...
+                     | <filename.pbf> ...
+                     | <filename.o5m> ...
+                     | <filename.(osm|o5m).bz2> ...
+                     | <filename.(osm|o5m).gz> ...
+                     | <filename.(osm|o5m).xz> ...]
+
+--help                    Prints this information.
+
+--dir=<dirname>           The directory containing the fixme database.
+
+--sort-ram-size=<size>    The amount of RAM (in MB) to use for data sorting
+                          (defaults to 256MB otherwise.)
+--sort-threads=<number>   The number of threads to use for data sorting.
+
+--tmpdir=<dirname>        The directory name for temporary files.
+                          (defaults to the '--dir' option directory.)
+
+--tagging=<filename>      The name of the XML file containing the tagging rules
+                          (defaults to 'fixme.xml' with '--dir' option)
+
+--loggable                Print progress messages suitable for logging to file.
+--logtime                 Print the elapsed time for each processing step.
+--logmemory               Print the max allocated/mapped memory for each step.
+
+<filename.osm>, <filename.pbf>, <filename.o5m>
+                          The name(s) of the file(s) to read and parse.
+                          Filenames ending '.pbf' read as PBF, filenames ending
+                          '.o5m' read as O5M, others as XML.
+                          Filenames ending '.bz2' will be bzip2 uncompressed (if
+                          bzip2 support compiled in). Filenames ending '.gz'
+                          will be gzip uncompressed (if gzip  support compiled
+                          in). Filenames ending '.xz' will be xz uncompressed
+                          (if xz support compiled in).
+
+
+fixme-dumper
+------------
+
+This program is a modified version of the Routino filedumper program and is used
+by the web page CGI to display the information on a map.
+
+
+Usage: fixme-dumper [--help]
+                    [--dir=<dirname>]
+                    [--statistics]
+                    [--visualiser --latmin=<latmin> --latmax=<latmax>
+                                  --lonmin=<lonmin> --lonmax=<lonmax>
+                                  --data=<data-type>]
+                    [--dump--visualiser [--data=fixme<number>]]
+
+--help                    Prints this information.
+
+--dir=<dirname>           The directory containing the fixme database.
+
+--statistics              Print statistics about the fixme database.
+
+--visualiser              Extract selected data from the fixme database:
+  --latmin=<latmin>       * the minimum latitude (degrees N).
+  --latmax=<latmax>       * the maximum latitude (degrees N).
+  --lonmin=<lonmin>       * the minimum longitude (degrees E).
+  --lonmax=<lonmax>       * the maximum longitude (degrees E).
+  --data=<data-type>      * the type of data to select.
+
+  <data-type> can be selected from:
+      fixmes              = fixme tags extracted from the data.
+
+--dump-visualiser         Dump selected contents of the database in HTML.
+  --data=fixme<number>    * the fixme with the selected index.
diff --git a/3rdparty/Routino/extras/find-fixme/fixme-dumper.c b/3rdparty/Routino/extras/find-fixme/fixme-dumper.c
new file mode 100644
index 0000000..801fc73
--- /dev/null
+++ b/3rdparty/Routino/extras/find-fixme/fixme-dumper.c
@@ -0,0 +1,345 @@
+/***************************************
+ Fixme file dumper.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2013-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <math.h>
+
+#include "types.h"
+#include "errorlog.h"
+
+#include "files.h"
+#include "xmlparse.h"
+
+
+/* Local functions */
+
+static void OutputErrorLog(ErrorLogs *errorlogs,double latmin,double latmax,double lonmin,double lonmax);
+
+static void print_errorlog_visualiser(ErrorLogs *errorlogs,index_t item);
+
+static char *RFC822Date(time_t t);
+
+static void print_usage(int detail,const char *argerr,const char *err);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The main program for the fixme dumper.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int main(int argc,char** argv)
+{
+ ErrorLogs*OSMErrorLogs;
+ int       arg;
+ char     *dirname=NULL,*prefix=NULL;
+ char     *errorlogs_filename;
+ int       option_statistics=0;
+ int       option_visualiser=0,coordcount=0;
+ double    latmin=0,latmax=0,lonmin=0,lonmax=0;
+ char     *option_data=NULL;
+ int       option_dump_visualiser=0;
+
+ /* Parse the command line arguments */
+
+ for(arg=1;arg<argc;arg++)
+   {
+    if(!strcmp(argv[arg],"--help"))
+       print_usage(1,NULL,NULL);
+    else if(!strncmp(argv[arg],"--dir=",6))
+       dirname=&argv[arg][6];
+    else if(!strcmp(argv[arg],"--statistics"))
+       option_statistics=1;
+    else if(!strcmp(argv[arg],"--visualiser"))
+       option_visualiser=1;
+    else if(!strcmp(argv[arg],"--dump-visualiser"))
+       option_dump_visualiser=1;
+    else if(!strncmp(argv[arg],"--latmin",8) && argv[arg][8]=='=')
+      {latmin=degrees_to_radians(atof(&argv[arg][9]));coordcount++;}
+    else if(!strncmp(argv[arg],"--latmax",8) && argv[arg][8]=='=')
+      {latmax=degrees_to_radians(atof(&argv[arg][9]));coordcount++;}
+    else if(!strncmp(argv[arg],"--lonmin",8) && argv[arg][8]=='=')
+      {lonmin=degrees_to_radians(atof(&argv[arg][9]));coordcount++;}
+    else if(!strncmp(argv[arg],"--lonmax",8) && argv[arg][8]=='=')
+      {lonmax=degrees_to_radians(atof(&argv[arg][9]));coordcount++;}
+    else if(!strncmp(argv[arg],"--data",6) && argv[arg][6]=='=')
+       option_data=&argv[arg][7];
+    else if(!strncmp(argv[arg],"--fixme=",8))
+       ;
+    else
+       print_usage(0,argv[arg],NULL);
+   }
+
+ if((option_statistics + option_visualiser + option_dump_visualiser)!=1)
+    print_usage(0,NULL,"Must choose --visualiser, --statistics or --dump-visualiser.");
+
+ /* Load in the data - Note: No error checking because Load*List() will call exit() in case of an error. */
+
+ OSMErrorLogs=LoadErrorLogs(errorlogs_filename=FileName(dirname,prefix,"fixme.mem"));
+
+ /* Write out the visualiser data */
+
+ if(option_visualiser)
+   {
+    if(coordcount!=4)
+       print_usage(0,NULL,"The --visualiser option must have --latmin, --latmax, --lonmin, --lonmax.\n");
+
+    if(!option_data)
+       print_usage(0,NULL,"The --visualiser option must have --data.\n");
+
+    if(!strcmp(option_data,"fixmes"))
+       OutputErrorLog(OSMErrorLogs,latmin,latmax,lonmin,lonmax);
+    else
+       print_usage(0,option_data,NULL);
+   }
+
+ /* Print out statistics */
+
+ if(option_statistics)
+   {
+    struct stat buf;
+
+    /* Examine the files */
+
+    printf("Files\n");
+    printf("-----\n");
+    printf("\n");
+
+    stat(errorlogs_filename,&buf);
+
+    printf("'%s%sfixme.mem' - %9"PRIu64" Bytes\n",prefix?prefix:"",prefix?"-":"",(uint64_t)buf.st_size);
+    printf("%s\n",RFC822Date(buf.st_mtime));
+    printf("\n");
+
+    printf("\n");
+    printf("Error Logs\n");
+    printf("----------\n");
+    printf("\n");
+
+    printf("Number(total)           =%9"Pindex_t"\n",OSMErrorLogs->file.number);
+    printf("Number(geographical)    =%9"Pindex_t"\n",OSMErrorLogs->file.number_geo);
+    printf("Number(non-geographical)=%9"Pindex_t"\n",OSMErrorLogs->file.number_nongeo);
+
+    printf("\n");
+    stat(errorlogs_filename,&buf);
+#if !SLIM
+    printf("Total strings=%9zu Bytes\n",(size_t)buf.st_size-(OSMErrorLogs->strings-(char*)OSMErrorLogs->data));
+#else
+    printf("Total strings=%9zu Bytes\n",(size_t)buf.st_size-(size_t)OSMErrorLogs->stringsoffset);
+#endif
+   }
+
+ /* Print out internal data (in HTML format for the visualiser) */
+
+ if(option_dump_visualiser)
+   {
+    index_t item;
+
+    if(!option_data)
+       print_usage(0,NULL,"The --dump-visualiser option must have --data.\n");
+
+    for(arg=1;arg<argc;arg++)
+       if(!strncmp(argv[arg],"--data=fixme",12))
+         {
+          item=atoi(&argv[arg][12]);
+
+          if(item<OSMErrorLogs->file.number)
+             print_errorlog_visualiser(OSMErrorLogs,item);
+          else
+             printf("Invalid fixme number; minimum=0, maximum=%"Pindex_t".\n",OSMErrorLogs->file.number-1);
+         }
+   }
+
+ exit(EXIT_SUCCESS);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Output the data for error logs within the region.
+
+  ErrorLogs *errorlogs The set of error logs to use.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void OutputErrorLog(ErrorLogs *errorlogs,double latmin,double latmax,double lonmin,double lonmax)
+{
+ ll_bin_t latminbin=latlong_to_bin(radians_to_latlong(latmin))-errorlogs->file.latzero;
+ ll_bin_t latmaxbin=latlong_to_bin(radians_to_latlong(latmax))-errorlogs->file.latzero;
+ ll_bin_t lonminbin=latlong_to_bin(radians_to_latlong(lonmin))-errorlogs->file.lonzero;
+ ll_bin_t lonmaxbin=latlong_to_bin(radians_to_latlong(lonmax))-errorlogs->file.lonzero;
+ ll_bin_t latb,lonb;
+ index_t i,index1,index2;
+
+ /* Loop through all of the error logs. */
+
+ for(latb=latminbin;latb<=latmaxbin;latb++)
+    for(lonb=lonminbin;lonb<=lonmaxbin;lonb++)
+      {
+       ll_bin2_t llbin=lonb*errorlogs->file.latbins+latb;
+
+       if(llbin<0 || llbin>(errorlogs->file.latbins*errorlogs->file.lonbins))
+          continue;
+
+       index1=LookupErrorLogOffset(errorlogs,llbin);
+       index2=LookupErrorLogOffset(errorlogs,llbin+1);
+
+       if(index2>errorlogs->file.number_geo)
+          index2=errorlogs->file.number_geo;
+
+       for(i=index1;i<index2;i++)
+         {
+          ErrorLog *errorlogp=LookupErrorLog(errorlogs,i,1);
+
+          double lat=latlong_to_radians(bin_to_latlong(errorlogs->file.latzero+latb)+off_to_latlong(errorlogp->latoffset));
+          double lon=latlong_to_radians(bin_to_latlong(errorlogs->file.lonzero+lonb)+off_to_latlong(errorlogp->lonoffset));
+
+          if(lat>latmin && lat<latmax && lon>lonmin && lon<lonmax)
+             printf("fixme%"Pindex_t" %.6f %.6f\n",i,radians_to_degrees(lat),radians_to_degrees(lon));
+         }
+      }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out an error log entry from the database (in visualiser format).
+
+  ErrorLogs *errorlogs The set of error logs to use.
+
+  index_t item The error log index to print.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_errorlog_visualiser(ErrorLogs *errorlogs,index_t item)
+{
+ char *string=LookupErrorLogString(errorlogs,item);
+
+ printf("%s\n",ParseXML_Encode_Safe_XML(string));
+}
+
+
+/*+ Conversion from time_t to date string (day of week). +*/
+static const char* const weekdays[7]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
+
+/*+ Conversion from time_t to date string (month of year). +*/
+static const char* const months[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Convert the time into an RFC 822 compliant date.
+
+  char *RFC822Date Returns a pointer to a fixed string containing the date.
+
+  time_t t The time.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static char *RFC822Date(time_t t)
+{
+ static char value[32]; /* static allocation of return value */
+ char weekday[4];
+ char month[4];
+ struct tm *tim;
+
+ tim=gmtime(&t);
+
+ strcpy(weekday,weekdays[tim->tm_wday]);
+ strcpy(month,months[tim->tm_mon]);
+
+ /* Sun, 06 Nov 1994 08:49:37 GMT    ; RFC 822, updated by RFC 1123 */
+
+ sprintf(value,"%3s, %02d %3s %4d %02d:%02d:%02d %s",
+         weekday,
+         tim->tm_mday,
+         month,
+         tim->tm_year+1900,
+         tim->tm_hour,
+         tim->tm_min,
+         tim->tm_sec,
+         "GMT"
+         );
+
+ return(value);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the usage information.
+
+  int detail The level of detail to use - 0 = low, 1 = high.
+
+  const char *argerr The argument that gave the error (if there is one).
+
+  const char *err Other error message (if there is one).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_usage(int detail,const char *argerr,const char *err)
+{
+ fprintf(stderr,
+         "Usage: fixme-dumper [--help]\n"
+         "                    [--dir=<dirname>]\n"
+         "                    [--statistics]\n"
+         "                    [--visualiser --latmin=<latmin> --latmax=<latmax>\n"
+         "                                  --lonmin=<lonmin> --lonmax=<lonmax>\n"
+         "                                  --data=<data-type>]\n"
+         "                    [--dump--visualiser [--data=fixme<number>]]\n");
+
+ if(argerr)
+    fprintf(stderr,
+            "\n"
+            "Error with command line parameter: %s\n",argerr);
+
+ if(err)
+    fprintf(stderr,
+            "\n"
+            "Error: %s\n",err);
+
+ if(detail)
+    fprintf(stderr,
+            "\n"
+            "--help                    Prints this information.\n"
+            "\n"
+            "--dir=<dirname>           The directory containing the fixme database.\n"
+            "\n"
+            "--statistics              Print statistics about the fixme database.\n"
+            "\n"
+            "--visualiser              Extract selected data from the fixme database:\n"
+            "  --latmin=<latmin>       * the minimum latitude (degrees N).\n"
+            "  --latmax=<latmax>       * the maximum latitude (degrees N).\n"
+            "  --lonmin=<lonmin>       * the minimum longitude (degrees E).\n"
+            "  --lonmax=<lonmax>       * the maximum longitude (degrees E).\n"
+            "  --data=<data-type>      * the type of data to select.\n"
+            "\n"
+            "  <data-type> can be selected from:\n"
+            "      fixmes              = fixme tags extracted from the data.\n"
+            "\n"
+            "--dump-visualiser         Dump selected contents of the database in HTML.\n"
+            "  --data=fixme<number>    * the fixme with the selected index.\n");
+
+ exit(!detail);
+}
diff --git a/3rdparty/Routino/extras/find-fixme/fixme-finder.c b/3rdparty/Routino/extras/find-fixme/fixme-finder.c
new file mode 100644
index 0000000..9216b1d
--- /dev/null
+++ b/3rdparty/Routino/extras/find-fixme/fixme-finder.c
@@ -0,0 +1,369 @@
+/***************************************
+ OSM planet file fixme finder.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "types.h"
+#include "ways.h"
+
+#include "typesx.h"
+#include "nodesx.h"
+#include "waysx.h"
+#include "relationsx.h"
+
+#include "files.h"
+#include "logging.h"
+#include "errorlogx.h"
+#include "functions.h"
+#include "osmparser.h"
+#include "tagging.h"
+#include "uncompress.h"
+
+
+/* Global variables */
+
+/*+ The name of the temporary directory. +*/
+char *option_tmpdirname=NULL;
+
+/*+ The amount of RAM to use for filesorting. +*/
+size_t option_filesort_ramsize=0;
+
+/*+ The number of threads to use for filesorting. +*/
+int option_filesort_threads=1;
+
+
+/* Local functions */
+
+static void print_usage(int detail,const char *argerr,const char *err);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The main program for the find-fixme.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int main(int argc,char** argv)
+{
+ NodesX     *OSMNodes;
+ WaysX      *OSMWays;
+ RelationsX *OSMRelations;
+ ErrorLogsX *OSMErrorLogs;
+ char       *dirname=NULL,*prefix=NULL,*tagging=NULL;
+ int         option_keep=1;
+ int         option_filenames=0;
+ int         arg;
+
+ printf_program_start();
+
+ /* Parse the command line arguments */
+
+ for(arg=1;arg<argc;arg++)
+   {
+    if(!strcmp(argv[arg],"--help"))
+       print_usage(1,NULL,NULL);
+    else if(!strncmp(argv[arg],"--dir=",6))
+       dirname=&argv[arg][6];
+    else if(!strncmp(argv[arg],"--sort-ram-size=",16))
+       option_filesort_ramsize=atoi(&argv[arg][16]);
+#if defined(USE_PTHREADS) && USE_PTHREADS
+    else if(!strncmp(argv[arg],"--sort-threads=",15))
+       option_filesort_threads=atoi(&argv[arg][15]);
+#endif
+    else if(!strncmp(argv[arg],"--tmpdir=",9))
+       option_tmpdirname=&argv[arg][9];
+    else if(!strncmp(argv[arg],"--tagging=",10))
+       tagging=&argv[arg][10];
+    else if(!strcmp(argv[arg],"--loggable"))
+       option_loggable=1;
+    else if(!strcmp(argv[arg],"--logtime"))
+       option_logtime=1;
+    else if(!strcmp(argv[arg],"--logmemory"))
+       option_logmemory=1;
+    else if(argv[arg][0]=='-' && argv[arg][1]=='-')
+       print_usage(0,argv[arg],NULL);
+    else
+       option_filenames++;
+   }
+
+ /* Check the specified command line options */
+
+ if(!option_filesort_ramsize)
+   {
+#if SLIM
+    option_filesort_ramsize=64*1024*1024;
+#else
+    option_filesort_ramsize=256*1024*1024;
+#endif
+   }
+ else
+    option_filesort_ramsize*=1024*1024;
+
+ if(!option_tmpdirname)
+   {
+    if(!dirname)
+       option_tmpdirname=".";
+    else
+       option_tmpdirname=dirname;
+   }
+
+ if(tagging)
+   {
+    if(!ExistsFile(tagging))
+      {
+       fprintf(stderr,"Error: The '--tagging' option specifies a file that does not exist.\n");
+       exit(EXIT_FAILURE);
+      }
+   }
+ else
+   {
+    tagging=FileName(dirname,prefix,"fixme.xml");
+
+    if(!ExistsFile(tagging))
+      {
+       fprintf(stderr,"Error: The '--tagging' option was not used and the default 'fixme.xml' does not exist.\n");
+       exit(EXIT_FAILURE);
+      }
+   }
+
+ if(ParseXMLTaggingRules(tagging))
+   {
+    fprintf(stderr,"Error: Cannot read the tagging rules in the file '%s'.\n",tagging);
+    exit(EXIT_FAILURE);
+   }
+
+ /* Create new node, segment, way and relation variables */
+
+ OSMNodes=NewNodeList(0,0);
+
+ OSMWays=NewWayList(0,0);
+
+ OSMRelations=NewRelationList(0,0);
+
+ /* Create the error log file */
+
+ open_errorlog(FileName(dirname,prefix,"fixme.log"),0,option_keep);
+
+ /* Parse the file */
+
+ for(arg=1;arg<argc;arg++)
+   {
+    int fd;
+    char *filename,*p;
+
+    if(argv[arg][0]=='-' && argv[arg][1]=='-')
+       continue;
+
+    filename=strcpy(malloc(strlen(argv[arg])+1),argv[arg]);
+
+    fd=OpenFile(filename);
+
+    if((p=strstr(filename,".bz2")) && !strcmp(p,".bz2"))
+      {
+       fd=Uncompress_Bzip2(fd);
+       *p=0;
+      }
+
+    if((p=strstr(filename,".gz")) && !strcmp(p,".gz"))
+      {
+       fd=Uncompress_Gzip(fd);
+       *p=0;
+      }
+
+    if((p=strstr(filename,".xz")) && !strcmp(p,".xz"))
+      {
+       fd=Uncompress_Xz(fd);
+       *p=0;
+      }
+
+    printf("\nParse OSM Data [%s]\n==============\n\n",filename);
+    fflush(stdout);
+
+    if((p=strstr(filename,".pbf")) && !strcmp(p,".pbf"))
+      {
+       if(ParsePBFFile(fd,OSMNodes,OSMWays,OSMRelations))
+          exit(EXIT_FAILURE);
+      }
+    else if((p=strstr(filename,".o5m")) && !strcmp(p,".o5m"))
+      {
+       if(ParseO5MFile(fd,OSMNodes,OSMWays,OSMRelations))
+          exit(EXIT_FAILURE);
+      }
+    else
+      {
+       if(ParseOSMFile(fd,OSMNodes,OSMWays,OSMRelations))
+          exit(EXIT_FAILURE);
+      }
+
+    CloseFile(fd);
+
+    free(filename);
+   }
+
+ DeleteXMLTaggingRules();
+
+ FinishNodeList(OSMNodes);
+ FinishWayList(OSMWays);
+ FinishRelationList(OSMRelations);
+
+ /* Sort the data */
+
+ printf("\nSort OSM Data\n=============\n\n");
+ fflush(stdout);
+
+ /* Sort the nodes, ways and relations */
+
+ SortNodeList(OSMNodes);
+
+ SortWayList(OSMWays);
+
+ SortRelationList(OSMRelations);
+
+ /* Process the data */
+
+ RenameFile(OSMNodes->filename_tmp,OSMNodes->filename);
+ RenameFile(OSMWays->filename_tmp,OSMWays->filename);
+ RenameFile(OSMRelations->rrfilename_tmp,OSMRelations->rrfilename);
+ RenameFile(OSMRelations->trfilename_tmp,OSMRelations->trfilename);
+
+ close_errorlog();
+
+ printf("\nCreate Error Log\n================\n\n");
+ fflush(stdout);
+
+ OSMErrorLogs=NewErrorLogList();
+
+ ProcessErrorLogs(OSMErrorLogs,OSMNodes,OSMWays,OSMRelations);
+
+ SortErrorLogsGeographically(OSMErrorLogs);
+
+ SaveErrorLogs(OSMErrorLogs,FileName(dirname,prefix,"fixme.mem"));
+
+ FreeErrorLogList(OSMErrorLogs);
+
+ /* Free the memory (delete the temporary files) */
+
+ FreeNodeList(OSMNodes,0);
+ FreeWayList(OSMWays,0);
+ FreeRelationList(OSMRelations,0);
+
+ printf("\n");
+ fflush(stdout);
+
+ printf_program_end();
+
+ exit(EXIT_SUCCESS);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the usage information.
+
+  int detail The level of detail to use - 0 = low, 1 = high.
+
+  const char *argerr The argument that gave the error (if there is one).
+
+  const char *err Other error message (if there is one).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_usage(int detail,const char *argerr,const char *err)
+{
+ fprintf(stderr,
+         "Usage: fixme-finder [--help]\n"
+         "                    [--dir=<dirname>]\n"
+#if defined(USE_PTHREADS) && USE_PTHREADS
+         "                    [--sort-ram-size=<size>] [--sort-threads=<number>]\n"
+#else
+         "                    [--sort-ram-size=<size>]\n"
+#endif
+         "                    [--tmpdir=<dirname>]\n"
+         "                    [--tagging=<filename>]\n"
+         "                    [--loggable] [--logtime] [--logmemory]\n"
+         "                    [<filename.osm> ...\n"
+         "                     | <filename.pbf> ...\n"
+         "                     | <filename.o5m> ..."
+#if defined(USE_BZIP2) && USE_BZIP2
+         "\n                     | <filename.(osm|o5m).bz2> ..."
+#endif
+#if defined(USE_GZIP) && USE_GZIP
+         "\n                     | <filename.(osm|o5m).gz> ..."
+#endif
+#if defined(USE_XZ) && USE_XZ
+         "\n                     | <filename.(osm|o5m).xz> ..."
+#endif
+         "]\n");
+
+ if(argerr)
+    fprintf(stderr,
+            "\n"
+            "Error with command line parameter: %s\n",argerr);
+
+ if(err)
+    fprintf(stderr,
+            "\n"
+            "Error: %s\n",err);
+
+ if(detail)
+    fprintf(stderr,
+            "\n"
+            "--help                    Prints this information.\n"
+            "\n"
+            "--dir=<dirname>           The directory containing the fixme database.\n"
+            "\n"
+            "--sort-ram-size=<size>    The amount of RAM (in MB) to use for data sorting\n"
+#if SLIM
+            "                          (defaults to 64MB otherwise.)\n"
+#else
+            "                          (defaults to 256MB otherwise.)\n"
+#endif
+#if defined(USE_PTHREADS) && USE_PTHREADS
+            "--sort-threads=<number>   The number of threads to use for data sorting.\n"
+#endif
+            "\n"
+            "--tmpdir=<dirname>        The directory name for temporary files.\n"
+            "                          (defaults to the '--dir' option directory.)\n"
+            "\n"
+            "--tagging=<filename>      The name of the XML file containing the tagging rules\n"
+            "                          (defaults to 'fixme.xml' with '--dir' option)\n"
+            "\n"
+            "--loggable                Print progress messages suitable for logging to file.\n"
+            "--logtime                 Print the elapsed time for each processing step.\n"
+            "--logmemory               Print the max allocated/mapped memory for each step.\n"
+            "\n"
+            "<filename.osm>, <filename.pbf>, <filename.o5m>\n"
+            "                          The name(s) of the file(s) to read and parse.\n"
+            "                          Filenames ending '.pbf' read as PBF, filenames ending\n"
+            "                          '.o5m' read as O5M, others as XML.\n"
+#if defined(USE_BZIP2) && USE_BZIP2
+            "                          Filenames ending '.bz2' will be bzip2 uncompressed.\n"
+#endif
+#if defined(USE_GZIP) && USE_GZIP
+            "                          Filenames ending '.gz' will be gzip uncompressed.\n"
+#endif
+#if defined(USE_XZ) && USE_XZ
+            "                          Filenames ending '.xz' will be xz uncompressed.\n"
+#endif
+            );
+
+ exit(!detail);
+}
diff --git a/3rdparty/Routino/extras/find-fixme/fixme.xml b/3rdparty/Routino/extras/find-fixme/fixme.xml
new file mode 100644
index 0000000..ba45253
--- /dev/null
+++ b/3rdparty/Routino/extras/find-fixme/fixme.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!-- ============================================================
+     An XML format file containing Routino tagging rules - copy the input file
+     directly to the output with no modifications.
+
+     Part of the Routino routing software.
+     ============================================================
+     This file Copyright 2010-2013 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<routino-tagging xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xsi:noNamespaceSchemaLocation="http://www.routino.org/xml/routino-tagging.xsd">
+
+  <!-- - - - - - - - - - - Node rules - - - - - - - - - - -->
+
+  <node>
+
+    <!-- Add a marker for those nodes that match the wanted tag(s) -->
+
+    <if k="fixme">
+      <output k="fixme-finder:keep" v="yes" />
+    </if>
+
+    <!-- Copy all tags from input to output -->
+
+    <if>
+      <output />
+    </if>
+
+  </node>
+
+  <!-- - - - - - - - - - - Way rules - - - - - - - - - - -->
+
+  <way>
+
+    <!-- Add a marker for those ways that match the wanted tag(s) -->
+
+    <if k="fixme">
+      <output k="fixme-finder:keep" v="yes" />
+    </if>
+
+    <!-- Copy all tags from input to output -->
+
+    <if>
+      <output />
+    </if>
+
+  </way>
+
+  <!-- - - - - - - - - - - Relation rules - - - - - - - - - - -->
+
+  <relation>
+
+    <!-- Add a marker for those relations that match the wanted tag(s) -->
+
+    <if k="fixme">
+      <output k="fixme-finder:keep" v="yes" />
+    </if>
+
+    <!-- Copy all tags from input to output -->
+
+    <if>
+      <output />
+    </if>
+
+  </relation>
+
+</routino-tagging>
diff --git a/3rdparty/Routino/extras/find-fixme/osmparser.c b/3rdparty/Routino/extras/find-fixme/osmparser.c
new file mode 100644
index 0000000..f32e4f7
--- /dev/null
+++ b/3rdparty/Routino/extras/find-fixme/osmparser.c
@@ -0,0 +1,306 @@
+/***************************************
+ OSM file parser (either JOSM or planet)
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "types.h"
+#include "typesx.h"
+
+#include "nodesx.h"
+#include "waysx.h"
+#include "relationsx.h"
+
+#include "osmparser.h"
+#include "tagging.h"
+#include "logging.h"
+
+
+/* Local parsing variables (re-initialised for each file) */
+
+static NodesX     *nodes;
+static WaysX      *ways;
+static RelationsX *relations;
+
+static node_t     *way_nodes;
+static int         way_nnodes;
+
+static node_t     *relation_nodes;
+static int         relation_nnodes;
+static way_t      *relation_ways;
+static int         relation_nways;
+static relation_t *relation_relations;
+static int         relation_nrelations;
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Initialise the OSM parser by initialising the local variables.
+
+  NodesX *OSMNodes The data structure of nodes to fill in.
+
+  WaysX *OSMWays The data structure of ways to fill in.
+
+  RelationsX *OSMRelations The data structure of relations to fill in.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void InitialiseParser(NodesX *OSMNodes,WaysX *OSMWays,RelationsX *OSMRelations)
+{
+ /* Copy the function parameters and initialise the variables */
+
+ nodes=OSMNodes;
+ ways=OSMWays;
+ relations=OSMRelations;
+
+ way_nodes=(node_t*)malloc(256*sizeof(node_t));
+
+ relation_nodes    =(node_t    *)malloc(256*sizeof(node_t));
+ relation_ways     =(way_t     *)malloc(256*sizeof(way_t));
+ relation_relations=(relation_t*)malloc(256*sizeof(relation_t));
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Clean up the memory after parsing.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void CleanupParser(void)
+{
+ /* Free the variables */
+
+ free(way_nodes);
+
+ free(relation_nodes);
+ free(relation_ways);
+ free(relation_relations);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Add node references to a way.
+
+  int64_t node_id The node ID to add or zero to clear the list.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void AddWayRefs(int64_t node_id)
+{
+ if(node_id==0)
+    way_nnodes=0;
+ else
+   {
+    node_t id;
+
+    if(way_nnodes && (way_nnodes%256)==0)
+       way_nodes=(node_t*)realloc((void*)way_nodes,(way_nnodes+256)*sizeof(node_t));
+
+    id=(node_t)node_id;
+    logassert((int64_t)id==node_id,"Node ID too large (change node_t to 64-bits?)"); /* check node id can be stored in node_t data type. */
+
+    way_nodes[way_nnodes++]=id;
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Add node, way or relation references to a relation.
+
+  int64_t node_id The node ID to add or zero if it is not a node.
+
+  int64_t way_id The way ID to add or zero if it is not a way.
+
+  int64_t relation_id The relation ID to add or zero if it is not a relation.
+
+  const char *role The role played by this referenced item or NULL.
+
+  If all of node_id, way_id and relation_id are zero then the list is cleared.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void AddRelationRefs(int64_t node_id,int64_t way_id,int64_t relation_id,const char *role)
+{
+ if(node_id==0 && way_id==0 && relation_id==0)
+   {
+    relation_nnodes=0;
+    relation_nways=0;
+    relation_nrelations=0;
+   }
+ else if(node_id!=0)
+   {
+    node_t id;
+
+    id=(node_t)node_id;
+    logassert((int64_t)id==node_id,"Node ID too large (change node_t to 64-bits?)"); /* check node id can be stored in node_t data type. */
+
+    if(relation_nnodes && (relation_nnodes%256)==0)
+       relation_nodes=(node_t*)realloc((void*)relation_nodes,(relation_nnodes+256)*sizeof(node_t));
+
+    relation_nodes[relation_nnodes++]=id;
+   }
+ else if(way_id!=0)
+   {
+    way_t id;
+
+    id=(way_t)way_id;
+    logassert((int64_t)id==way_id,"Way ID too large (change way_t to 64-bits?)"); /* check way id can be stored in way_t data type. */
+
+    if(relation_nways && (relation_nways%256)==0)
+       relation_ways=(way_t*)realloc((void*)relation_ways,(relation_nways+256)*sizeof(way_t));
+
+    relation_ways[relation_nways++]=id;
+   }
+ else /* if(relation_id!=0) */
+   {
+    relation_t id;
+
+    id=(relation_t)relation_id;
+    logassert((int64_t)id==relation_id,"Relation ID too large (change relation_t to 64-bits?)"); /* check relation id can be stored in relation_t data type. */
+
+    if(relation_nrelations && (relation_nrelations%256)==0)
+       relation_relations=(relation_t*)realloc((void*)relation_relations,(relation_nrelations+256)*sizeof(relation_t));
+
+    relation_relations[relation_nrelations++]=relation_id;
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process the tags associated with a node.
+
+  TagList *tags The list of node tags.
+
+  int64_t node_id The id of the node.
+
+  double latitude The latitude of the node.
+
+  double longitude The longitude of the node.
+
+  int mode The mode of operation to take (create, modify, delete).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void ProcessNodeTags(TagList *tags,int64_t node_id,double latitude,double longitude,int mode)
+{
+ node_t id;
+ int i;
+
+ /* Convert id */
+
+ id=(node_t)node_id;
+ logassert((int64_t)id==node_id,"Node ID too large (change node_t to 64-bits?)"); /* check node id can be stored in node_t data type. */
+
+ /* Parse the tags */
+
+ for(i=0;i<tags->ntags;i++)
+   {
+    char *k=tags->k[i];
+
+    if(!strcmp(k,"fixme-finder:keep"))
+      {
+       DeleteTag(tags,"fixme-finder:keep");
+       logerror("<node id='%"Pnode_t"'>%s</node>\n",logerror_node(id),StringifyTag(tags));
+      }
+   }
+
+ /* Store the node */
+
+ AppendNodeList(nodes,id,degrees_to_radians(latitude),degrees_to_radians(longitude),0,0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process the tags associated with a way.
+
+  TagList *tags The list of way tags.
+
+  int64_t way_id The id of the way.
+
+  int mode The mode of operation to take (create, modify, delete).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void ProcessWayTags(TagList *tags,int64_t way_id,int mode)
+{
+ Way way={0};
+ way_t id;
+ int i;
+
+ /* Convert id */
+
+ id=(way_t)way_id;
+ logassert((int64_t)id==way_id,"Way ID too large (change way_t to 64-bits?)"); /* check way id can be stored in way_t data type. */
+
+ /* Parse the tags */
+
+ for(i=0;i<tags->ntags;i++)
+   {
+    char *k=tags->k[i];
+
+    if(!strcmp(k,"fixme-finder:keep"))
+      {
+       DeleteTag(tags,"fixme-finder:keep");
+       logerror("<way id='%"Pway_t"'>%s</way>\n",logerror_way(id),StringifyTag(tags));
+      }
+   }
+
+ /* Store the way */
+
+ AppendWayList(ways,id,&way,way_nodes,way_nnodes,"");
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process the tags associated with a relation.
+
+  TagList *tags The list of relation tags.
+
+  int64_t relation_id The id of the relation.
+
+  int mode The mode of operation to take (create, modify, delete).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void ProcessRelationTags(TagList *tags,int64_t relation_id,int mode)
+{
+ relation_t id;
+ int i;
+
+ /* Convert id */
+
+ id=(relation_t)relation_id;
+ logassert((int64_t)id==relation_id,"Relation ID too large (change relation_t to 64-bits?)"); /* check relation id can be stored in relation_t data type. */
+
+ /* Parse the tags */
+
+ for(i=0;i<tags->ntags;i++)
+   {
+    char *k=tags->k[i];
+
+    if(!strcmp(k,"fixme-finder:keep"))
+      {
+       DeleteTag(tags,"fixme-finder:keep");
+       logerror("<relation id='%"Prelation_t"'>%s</relation>\n",logerror_relation(id),StringifyTag(tags));
+      }
+   }
+
+ /* Store the relation */
+
+ AppendRouteRelationList(relations,id,0,
+                         relation_nodes,relation_nnodes,
+                         relation_ways,relation_nways,
+                         relation_relations,relation_nrelations);
+}
diff --git a/3rdparty/Routino/extras/find-fixme/web/www/fixme.cgi b/3rdparty/Routino/extras/find-fixme/web/www/fixme.cgi
new file mode 100755
index 0000000..19422cd
--- /dev/null
+++ b/3rdparty/Routino/extras/find-fixme/web/www/fixme.cgi
@@ -0,0 +1,147 @@
+#!/usr/bin/perl
+#
+# Routino data visualiser CGI
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+
+# Use the directory paths script
+require "paths.pl";
+
+# Use the perl CGI module
+use CGI ':cgi';
+
+
+# Create the query and get the parameters
+
+my $query=new CGI;
+
+my @rawparams=$query->param;
+
+# Legal CGI parameters with regexp validity check
+
+my %legalparams=(
+                 "latmin"     => "[-0-9.]+",
+                 "latmax"     => "[-0-9.]+",
+                 "lonmin"     => "[-0-9.]+",
+                 "lonmax"     => "[-0-9.]+",
+                 "data"       => "fixmes",
+                 "dump"       => "fixme[0-9]+",
+                 "statistics" => "yes"
+                );
+
+# Validate the CGI parameters, ignore invalid ones
+
+my %cgiparams=();
+
+foreach my $key (@rawparams)
+  {
+   foreach my $test (keys (%legalparams))
+     {
+      if($key =~ m%^$test$%)
+        {
+         my $value=$query->param($key);
+
+         if($value =~ m%^$legalparams{$test}$%)
+           {
+            $cgiparams{$key}=$value;
+            last;
+           }
+        }
+     }
+  }
+
+# Data, dump or statistics?
+
+my $params="";
+
+my $data      =$cgiparams{"data"};
+my $dump      =$cgiparams{"dump"};
+my $statistics=$cgiparams{"statistics"};
+
+if(!defined $data && !defined $dump && !defined $statistics)
+  {
+   print header(-status => '500 Invalid CGI parameters');
+   exit;
+  }
+
+if(defined $statistics)
+  {
+   # Print the output
+
+   print header('text/plain');
+
+   # Set the parameters
+
+   $params.=" --statistics";
+  }
+elsif(defined $data)
+  {
+   # Parameters to limit range selected
+
+   my $limits=0.5;
+
+   # Check the parameters
+
+   my $latmin=$cgiparams{"latmin"};
+   my $latmax=$cgiparams{"latmax"};
+   my $lonmin=$cgiparams{"lonmin"};
+   my $lonmax=$cgiparams{"lonmax"};
+
+   if($latmin eq "" || $latmax eq "" || $lonmin eq "" || $lonmax eq "" || $data eq "")
+     {
+      print header(-status => '500 Invalid CGI parameters');
+      exit;
+     }
+
+   if(($latmax-$latmin)>$limits || ($lonmax-$lonmin)>$limits)
+     {
+      print header(-status => '500 Selected area too large');
+      exit;
+     }
+
+   # Print the output
+
+   print header('text/plain');
+
+   print "$latmin $lonmin $latmax $lonmax\n";
+
+   # Set the parameters
+
+   $params.=" --visualiser --data=$data";
+   $params.=" --latmin=$latmin --latmax=$latmax --lonmin=$lonmin --lonmax=$lonmax";
+  }
+else
+  {
+   # Print the output
+
+   print header('text/plain');
+
+   # Set the parameters
+
+   $params.=" --dump-visualiser --data=$dump";
+  }
+
+# Run the filedumper
+
+$params.=" --dir=$main::data_dir" if($main::data_dir);
+$params.=" --prefix=$main::data_prefix" if($main::data_prefix);
+
+system "$main::bin_dir/$main::fixme_dumper_exe $params 2>&1";
diff --git a/3rdparty/Routino/extras/find-fixme/web/www/fixme.css b/3rdparty/Routino/extras/find-fixme/web/www/fixme.css
new file mode 100644
index 0000000..e1938d2
--- /dev/null
+++ b/3rdparty/Routino/extras/find-fixme/web/www/fixme.css
@@ -0,0 +1,86 @@
+/*
+// Routino (extras) fixme web page style sheet.
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2013 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*--------------------------------*/
+/* Left panel - override defaults */
+/*--------------------------------*/
+
+DIV.hideshow_box
+{
+ overflow-x: auto;
+}
+
+
+/*-----------------------------------*/
+/* Left panel - specific tab options */
+/*-----------------------------------*/
+
+DIV#tab_fixme_div INPUT
+{
+ padding: 0;
+ border:  1px solid;
+ margin:  0;
+
+ text-align: center;
+}
+
+DIV#tab_fixme_div INPUT:hover
+{
+ background: #F0F0C0;
+}
+
+DIV#tab_fixme_div DIV.center
+{
+ text-align: center;
+}
+
+DIV#tab_fixme_div TABLE
+{
+ padding: 0;
+ border:  0 hidden;
+ margin:  0;
+}
+
+DIV#tab_fixme_div TABLE TD
+{
+ padding: 0;
+ border:  0;
+ margin:  0;
+}
+
+DIV#tab_fixme_div INPUT
+{
+ padding: 0;
+ border:  1px solid;
+ margin:  0;
+}
+
+
+/*-------*/
+/* Popup */
+/*-------*/
+
+DIV.popup
+{
+ font-family: monospace;
+ font-size:   10px;
+}
diff --git a/3rdparty/Routino/extras/find-fixme/web/www/fixme.html b/3rdparty/Routino/extras/find-fixme/web/www/fixme.html
new file mode 100644
index 0000000..f221918
--- /dev/null
+++ b/3rdparty/Routino/extras/find-fixme/web/www/fixme.html
@@ -0,0 +1,162 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="keywords" content="openstreetmap routino fixme">
+<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, user-scalable=no">
+
+<title>Routino Extras : Viewer for OpenStreetMap "fixme" Tags</title>
+
+<!--
+ Routino (extras) fixme web page.
+
+ Part of the Routino routing software.
+
+ This file Copyright 2008-2014 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see http://www.gnu.org/licenses/.
+-->
+
+<!-- Page elements -->
+<script src="page-elements.js" type="text/javascript"></script>
+<link href="page-elements.css" type="text/css" rel="stylesheet">
+
+<!-- Router and visualiser shared features -->
+<link href="maplayout.css" type="text/css" rel="stylesheet">
+
+<!-- Fixme specific features -->
+<link href="fixme.css" type="text/css" rel="stylesheet">
+
+<!-- Map parameters -->
+<script src="mapprops.js" type="text/javascript"></script>
+
+<!-- Map loader -->
+<script src="maploader.js" type="text/javascript"></script>
+
+</head>
+<body onload="map_load('map_init();');">
+
+<!-- Left hand side of window - data panel -->
+
+<div class="left_panel">
+
+  <div class="tab_box">
+    <span id="tab_fixme" onclick="tab_select('fixme');" class="tab_selected"   title="View 'fixme' tags">Fixme</span>
+    <span id="tab_data"  onclick="tab_select('data');"  class="tab_unselected" title="View database information">Data</span>
+  </div>
+
+  <div class="tab_content" id="tab_fixme_div">
+
+    <div class="hideshow_box">
+      <span class="hideshow_title">OSM "fixme" Tags</span> This web page allows
+      viewing the "fixme" tags in OSM data.  It is generated using a modified
+      version of the Routino router data processor.
+      <div class="center">
+        <a target="other" href="http://www.routino.org/">Routino Website</a>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span class="hideshow_title">Instructions</span>
+      Zoom in and then use the button below to download the data.  The
+      server will only return data if the selected area is small enough.
+    </div>
+
+    <div class="hideshow_box">
+      <span class="hideshow_title">Status</span>
+      <div id="result_status">
+        <div id="result_status_no_data">
+          <b><i>No data displayed</i></b>
+        </div>
+        <div id="result_status_data"      style="display: none;">
+        </div>
+        <div id="result_status_failed"    style="display: none;">
+          <b>Failed to get fixme data!</b>
+        </div>
+        <div id="result_status_fixme"     style="display: none;">
+          <b>Processed # "fixme" tags</b>
+        </div>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span class="hideshow_title">Get Data</span>
+      <input type="button" id="fixme" onclick="displayData('fixmes');" value="Display "fixme" tags">
+      <input type="button" id="clear" onclick="displayData('');" value="Clear data">
+      <br>
+      The points displayed on the map are the location of items in the OSM data
+      that are tagged with "fixme" = "...".  Clicking on one of the points will
+      display the Node, Way or Relation identifier and the contents of the tag.
+    </div>
+
+    <div class="hideshow_box">
+      <span class="hideshow_title">Links</span>
+      <a id="permalink_url" href="fixme.html">Permanent link to this view</a>
+      <br>
+      <a id="edit_url" target="edit" style="display: none;">Edit OSM source data</a>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_help_options_show" onclick="hideshow_show('help_options');" class="hideshow_hide">+</span>
+      <span id="hideshow_help_options_hide" onclick="hideshow_hide('help_options');" class="hideshow_show">-</span>
+      <span class="hideshow_title">Help</span>
+      <div id="hideshow_help_options_div">
+        <div class="scrollable">
+          <b>Quick Start</b>
+          <br>
+          Zoom to an area and select one of the buttons to display the fixme data.
+          <p>
+          <b>Data Failure</b>
+          <br>
+          If the area selected is too large (depends on the data type) then the
+          status will say "Failed to get fixme data" - zoom in and try again.
+          <br>
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <div class="tab_content" id="tab_data_div" style="display: none;">
+    <div class="hideshow_box">
+      <span class="hideshow_title">Statistics</span>
+      <div id="statistics_data"></div>
+      <a id="statistics_link" href="statistics.cgi" onclick="displayStatistics();return(false);">Display data statistics</a>
+    </div>
+  </div>
+
+</div>
+
+<!-- Right hand side of window - map -->
+
+<div class="right_panel">
+  <div class="map" id="map">
+    <noscript>
+      <p>
+        Javascript is <em>required</em> to use this web page because of the
+        interactive map.
+    </noscript>
+  </div>
+  <div class="attribution">
+    Data Generator: <a href="http://www.routino.org/" target="routino">Routino</a>
+    |
+    Geo Data: <span id="attribution_data"></span>
+    |
+    Tiles: <span id="attribution_tile"></span>
+  </div>
+</div>
+
+</body>
+
+</html>
diff --git a/3rdparty/Routino/extras/find-fixme/web/www/fixme.leaflet.js b/3rdparty/Routino/extras/find-fixme/web/www/fixme.leaflet.js
new file mode 100644
index 0000000..d8e3515
--- /dev/null
+++ b/3rdparty/Routino/extras/find-fixme/web/www/fixme.leaflet.js
@@ -0,0 +1,563 @@
+//
+// Routino (extras) fixme web page Javascript
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2014 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Initialisation /////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+// Process the URL query string and extract the arguments
+
+var legal={"^lon"  : "^[-0-9.]+$",
+           "^lat"  : "^[-0-9.]+$",
+           "^zoom" : "^[0-9]+$"};
+
+var args={};
+
+if(location.search.length>1)
+  {
+   var query,queries;
+
+   query=location.search.replace(/^\?/,"");
+   query=query.replace(/;/g,"&");
+   queries=query.split("&");
+
+   for(var i=0;i<queries.length;i++)
+     {
+      queries[i].match(/^([^=]+)(=(.*))?$/);
+
+      var k=RegExp.$1;
+      var v=decodeURIComponent(RegExp.$3);
+
+      for(var l in legal)
+        {
+         if(k.match(RegExp(l)) && v.match(RegExp(legal[l])))
+            args[k]=v;
+        }
+     }
+  }
+
+
+////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////// Map handling /////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+var map;
+var layerMap=[], layerHighlights, layerVectors, layerBoxes;
+
+var box;
+
+//
+// Initialise the 'map' object
+//
+
+function map_init()             // called from fixme.html
+{
+ // Create the map (Map URLs and limits are in mapprops.js)
+
+ map = L.map("map",
+             {
+              attributionControl: false,
+              zoomControl: false,
+
+              minZoom: mapprops.zoomout,
+              maxZoom: mapprops.zoomin,
+
+              maxBounds: L.latLngBounds(L.latLng(mapprops.southedge,mapprops.westedge),L.latLng(mapprops.northedge,mapprops.eastedge))
+              });
+
+ // Add map tile layers
+
+ var baselayers={};
+
+ for(var l=0; l<mapprops.mapdata.length; l++)
+   {
+    var urls=mapprops.mapdata[l].tiles.url.replace(/\${/g,"{");
+
+    if(mapprops.mapdata[l].tiles.subdomains===undefined)
+       layerMap[l] = L.tileLayer(urls);
+    else
+       layerMap[l] = L.tileLayer(urls, {subdomains: mapprops.mapdata[l].tiles.subdomains});
+
+    baselayers[mapprops.mapdata[l].label]=layerMap[l];
+
+    if(l===0)
+       map.addLayer(layerMap[l]);
+   }
+
+ // Add the controls
+
+ map.addControl(L.control.zoom());
+ map.addControl(L.control.scale());
+ map.addControl(L.control.layers(baselayers));
+
+ // Update the attribution if the layer changes
+
+ function change_attribution_event(event)
+ {
+  for(var l=0; l<mapprops.mapdata.length; l++)
+     if(layerMap[l] == event.layer)
+        change_attribution(l);
+ }
+
+ map.on("baselayerchange",change_attribution_event);
+
+ function change_attribution(l)
+ {
+  var data_url =mapprops.mapdata[l].attribution.data_url;
+  var data_text=mapprops.mapdata[l].attribution.data_text;
+  var tile_url =mapprops.mapdata[l].attribution.tile_url;
+  var tile_text=mapprops.mapdata[l].attribution.tile_text;
+
+  document.getElementById("attribution_data").innerHTML="<a href=\"" + data_url + "\" target=\"data_attribution\">" + data_text + "</a>";
+  document.getElementById("attribution_tile").innerHTML="<a href=\"" + tile_url + "\" target=\"tile_attribution\">" + tile_text + "</a>";
+ }
+
+ change_attribution(0);
+
+ // Add two vectors layers (one for highlights that display behind the vectors)
+
+ layerVectors = L.layerGroup();
+ map.addLayer(layerVectors);
+
+ layerHighlights = L.layerGroup();
+ map.addLayer(layerHighlights);
+
+ // Handle popup
+
+ createPopup();
+
+ // Add a boxes layer
+
+ layerBoxes = L.rectangle(map.options.maxBounds,{stroke: false, color: "#f00", weight: 1, opacity: 1.0,
+                                                 fill: false});
+
+ map.addLayer(layerBoxes);
+
+ box=false;
+
+ // Move the map
+
+ map.on("moveend", updateURLs);
+
+ var lon =args["lon"];
+ var lat =args["lat"];
+ var zoom=args["zoom"];
+
+ if(lon !== undefined && lat !== undefined && zoom !== undefined)
+   {
+    if(lon<mapprops.westedge) lon=mapprops.westedge;
+    if(lon>mapprops.eastedge) lon=mapprops.eastedge;
+
+    if(lat<mapprops.southedge) lat=mapprops.southedge;
+    if(lat>mapprops.northedge) lat=mapprops.northedge;
+
+    if(zoom<mapprops.zoomout) zoom=mapprops.zoomout;
+    if(zoom>mapprops.zoomin)  zoom=mapprops.zoomin;
+
+    map.setView(L.latLng(lat,lon),zoom);
+   }
+ else
+    map.fitBounds(map.options.maxBounds);
+
+ // Unhide editing URL if variable set
+
+ if(mapprops.editurl !== undefined && mapprops.editurl !== "")
+   {
+    var edit_url=document.getElementById("edit_url");
+
+    edit_url.style.display="";
+    edit_url.href=mapprops.editurl;
+   }
+
+ updateURLs();
+}
+
+
+//
+// Format a number in printf("%.5f") format.
+//
+
+function format5f(number)
+{
+ var newnumber=Math.floor(number*100000+0.5);
+ var delta=0;
+
+ if(newnumber>=0 && newnumber<100000) delta= 100000;
+ if(newnumber<0 && newnumber>-100000) delta=-100000;
+
+ var string=String(newnumber+delta);
+
+ var intpart =string.substring(0,string.length-5);
+ var fracpart=string.substring(string.length-5,string.length);
+
+ if(delta>0) intpart="0";
+ if(delta<0) intpart="-0";
+
+ return(intpart + "." + fracpart);
+}
+
+
+//
+// Build a set of URL arguments for the map location
+//
+
+function buildMapArguments()
+{
+ var lonlat = map.getCenter();
+
+ var zoom = map.getZoom();
+
+ return "lat=" + format5f(lonlat.lat) + ";lon=" + format5f(lonlat.lng) + ";zoom=" + zoom;
+}
+
+
+//
+// Update the URLs
+//
+
+function updateURLs()
+{
+ var mapargs=buildMapArguments();
+
+ var links=document.getElementsByTagName("a");
+
+ for(var i=0; i<links.length; i++)
+   {
+    var element=links[i];
+
+    if(element.id == "permalink_url")
+       element.href=location.pathname + "?" + mapargs;
+
+    if(element.id == "edit_url")
+       element.href=mapprops.editurl + "?" + mapargs;
+   }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+///////////////////////// Popup and selection handling /////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+var popup=null;
+
+//
+// Create a popup - independent of map because want it fixed on screen not fixed on map.
+//
+
+function createPopup()
+{
+ popup=document.createElement("div");
+
+ popup.className = "popup";
+
+ popup.innerHTML = "<span></span>";
+
+ popup.style.display = "none";
+
+ popup.style.position = "fixed";
+ popup.style.top = "-4000px";
+ popup.style.left = "-4000px";
+ popup.style.zIndex = "100";
+
+ popup.style.padding = "5px";
+
+ popup.style.opacity=0.85;
+ popup.style.backgroundColor="#C0C0C0";
+ popup.style.border="4px solid #404040";
+
+ document.body.appendChild(popup);
+}
+
+
+//
+// Draw a popup - independent of map because want it fixed on screen not fixed on map.
+//
+
+function drawPopup(html)
+{
+ if(html===null)
+   {
+    popup.style.display="none";
+    return;
+   }
+
+ if(popup.style.display=="none")
+   {
+    var map_div=document.getElementById("map");
+
+    popup.style.left  =map_div.offsetParent.offsetLeft+map_div.offsetLeft+60 + "px";
+    popup.style.top   =                                map_div.offsetTop +30 + "px";
+    popup.style.width =map_div.clientWidth-120 + "px";
+
+    popup.style.display="";
+   }
+
+ var close="<span style='float: right; cursor: pointer;' onclick='drawPopup(null)'>X</span>";
+
+ popup.innerHTML=close+html;
+}
+
+
+//
+// Select a feature
+//
+
+function selectCircleMarkerFeature(feature,dump,event)
+{
+ if(dump)
+    ajaxGET("fixme.cgi?dump=" + dump, runDumpSuccess);
+
+ layerHighlights.clearLayers();
+
+ var highlight = L.circleMarker(feature.getLatLng(),{radius: 2*feature.getRadius(), fill: true, fillColor: "#F0F000", fillOpacity: 1.0,
+                                                     stroke: false});
+
+ layerHighlights.addLayer(highlight);
+
+ highlight.bringToBack();
+}
+
+
+//
+// Un-select a feature
+//
+
+function unselectFeature(feature)
+{
+ layerHighlights.clearLayers();
+
+ drawPopup(null);
+}
+
+
+//
+// Display the dump data
+//
+
+function runDumpSuccess(response)
+{
+ var string=response.responseText;
+
+ if(mapprops.editurl !== undefined && mapprops.editurl !== "")
+   {
+    var types=["node", "way", "relation"];
+
+    for(var t in types)
+      {
+       var type=types[t];
+
+       var regexp=RegExp(type + " id='[0-9]+'");
+
+       var match=string.match(regexp);
+
+       if(match !== null)
+         {
+          match=String(match);
+
+          var id=match.slice(10+type.length,match.length-6);
+
+          string=string.replace(regexp,type + " id='<a href='" + mapprops.browseurl + "/" + type + "/" + id + "' target='" + type + id + "'>" + id + "</a>'");
+         }
+      }
+   }
+
+ drawPopup(string.split("><").join("><br><").split("<br><tag").join("<br>  <tag"));
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Server handling ////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+//
+// Define an AJAX request object
+//
+
+function ajaxGET(url,success,failure,state)
+{
+ var ajaxRequest=new XMLHttpRequest();
+
+ function ajaxGOT(options) {
+  if(this.readyState==4)
+     if(this.status==200)
+       { if(typeof(options.success)=="function") options.success(this,options.state); }
+     else
+       { if(typeof(options.failure)=="function") options.failure(this,options.state); }
+ }
+
+ ajaxRequest.onreadystatechange = function(){ ajaxGOT.call(ajaxRequest,{success: success, failure: failure, state: state}); };
+ ajaxRequest.open("GET", url, true);
+ ajaxRequest.send(null);
+}
+
+
+//
+// Display the status
+//
+
+function displayStatus(type,subtype,content)
+{
+ var child=document.getElementById("result_status").firstChild;
+
+ do
+   {
+    if(child.id !== undefined)
+       child.style.display="none";
+
+    child=child.nextSibling;
+   }
+ while(child !== null);
+
+ var chosen_status=document.getElementById("result_status_" + type);
+
+ chosen_status.style.display="";
+
+ if(subtype !== undefined)
+   {
+    var format_status=document.getElementById("result_status_" + subtype).innerHTML;
+
+    chosen_status.innerHTML=format_status.replace("#",String(content));
+   }
+}
+
+
+//
+// Display data statistics
+//
+
+function displayStatistics()
+{
+ // Use AJAX to get the statistics
+
+ ajaxGET("fixme.cgi?statistics=yes", runStatisticsSuccess);
+}
+
+
+//
+// Success in running data statistics generation.
+//
+
+function runStatisticsSuccess(response)
+{
+ document.getElementById("statistics_data").innerHTML="<pre>" + response.responseText + "</pre>";
+ document.getElementById("statistics_link").style.display="none";
+}
+
+
+//
+// Get the requested data
+//
+
+function displayData(datatype)  // called from fixme.html
+{
+ // Delete the old data
+
+ unselectFeature();
+
+ layerVectors.clearLayers();
+ layerHighlights.clearLayers();
+
+ layerBoxes.setStyle({stroke:false});
+ box=false;
+
+ // Print the status
+
+ displayStatus("no_data");
+
+ // Return if just here to clear the data
+
+ if(datatype === "")
+    return;
+
+ // Get the new data
+
+ var mapbounds=map.getBounds();
+
+ var url="fixme.cgi";
+
+ url=url + "?lonmin=" + format5f(mapbounds.getWest());
+ url=url + ";latmin=" + format5f(mapbounds.getSouth());
+ url=url + ";lonmax=" + format5f(mapbounds.getEast());
+ url=url + ";latmax=" + format5f(mapbounds.getNorth());
+ url=url + ";data=" + datatype;
+
+ // Use AJAX to get the data
+
+ ajaxGET(url, runFixmeSuccess, runFailure);
+}
+
+
+//
+// Success in getting the error log data
+//
+
+function runFixmeSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = L.latLngBounds(L.latLng(lat1,lon1),L.latLng(lat2,lon2));
+
+       layerBoxes.setBounds(bounds);
+
+       layerBoxes.setStyle({stroke: true});
+       box=true;
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat=words[1];
+       var lon=words[2];
+
+       var lonlat = L.latLng(lat,lon);
+
+       var feature = L.circleMarker(lonlat,{radius: 3, fill: true, fillColor: "#FF0000", fillOpacity: 1.0,
+                                            stroke: false});
+
+       feature.on("click", (function(f,d) { return function(evt) { selectCircleMarkerFeature(f,d,evt); }; }(feature,dump)));
+
+       layerVectors.addLayer(feature);
+      }
+   }
+
+ displayStatus("data","fixme",lines.length-2);
+}
+
+
+//
+// Failure in getting data.
+//
+
+function runFailure(response)
+{
+ displayStatus("failed");
+}
diff --git a/3rdparty/Routino/extras/find-fixme/web/www/fixme.openlayers.js b/3rdparty/Routino/extras/find-fixme/web/www/fixme.openlayers.js
new file mode 100644
index 0000000..c525ab9
--- /dev/null
+++ b/3rdparty/Routino/extras/find-fixme/web/www/fixme.openlayers.js
@@ -0,0 +1,623 @@
+//
+// Routino (extras) fixme web page Javascript
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2014 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Initialisation /////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+// Process the URL query string and extract the arguments
+
+var legal={"^lon"  : "^[-0-9.]+$",
+           "^lat"  : "^[-0-9.]+$",
+           "^zoom" : "^[0-9]+$"};
+
+var args={};
+
+if(location.search.length>1)
+  {
+   var query,queries;
+
+   query=location.search.replace(/^\?/,"");
+   query=query.replace(/;/g,"&");
+   queries=query.split("&");
+
+   for(var i=0;i<queries.length;i++)
+     {
+      queries[i].match(/^([^=]+)(=(.*))?$/);
+
+      var k=RegExp.$1;
+      var v=decodeURIComponent(RegExp.$3);
+
+      for(var l in legal)
+        {
+         if(k.match(RegExp(l)) && v.match(RegExp(legal[l])))
+            args[k]=v;
+        }
+     }
+  }
+
+
+////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////// Map handling /////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+var map;
+var layerMap=[], layerHighlights, layerVectors, layerBoxes;
+var epsg4326, epsg900913;
+
+var box;
+var select;
+
+//
+// Initialise the 'map' object
+//
+
+function map_init()             // called from fixme.html
+{
+ // Create the map (Map URLs and limits are in mapprops.js)
+
+ epsg4326=new OpenLayers.Projection("EPSG:4326");
+ epsg900913=new OpenLayers.Projection("EPSG:900913");
+
+ map = new OpenLayers.Map ("map",
+                           {
+                            controls:[
+                                      new OpenLayers.Control.Navigation(),
+                                      new OpenLayers.Control.PanZoomBar(),
+                                      new OpenLayers.Control.ScaleLine(),
+                                      new OpenLayers.Control.LayerSwitcher()
+                                      ],
+
+                            projection: epsg900913,
+                            displayProjection: epsg4326,
+
+                            minZoomLevel: mapprops.zoomout,
+                            numZoomLevels: mapprops.zoomin-mapprops.zoomout+1,
+                            maxResolution: 156543.03390625 / Math.pow(2,mapprops.zoomout),
+
+                            restrictedExtent: new OpenLayers.Bounds(mapprops.westedge,mapprops.southedge,mapprops.eastedge,mapprops.northedge).transform(epsg4326,epsg900913)
+                           });
+
+ // Get a URL for the tile (mostly copied from OpenLayers/Layer/XYZ.js).
+
+ function limitedUrl(bounds)
+ {
+  var res = this.map.getResolution();
+
+  var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
+  var y = Math.round((this.maxExtent.top - bounds.top) / (res * this.tileSize.h));
+  var z = this.map.getZoom() + this.map.minZoomLevel;
+
+  var limit = Math.pow(2, z);
+  x = ((x % limit) + limit) % limit;
+
+  var xyz = {"x": x, "y": y, "z": z};
+  var url = this.url;
+
+  if (OpenLayers.Util.isArray(url))
+    {
+     var s = "" + xyz.x + xyz.y + xyz.z;
+     url = this.selectUrl(s, url);
+    }
+
+  return OpenLayers.String.format(url, xyz);
+ }
+
+ // Add map tile layers
+
+ for(var l=0; l<mapprops.mapdata.length; l++)
+   {
+    var urls;
+
+    if(OpenLayers.Util.isArray(mapprops.mapdata[l].tiles.subdomains))
+      {
+       urls=[];
+
+       for(var s=0; s<mapprops.mapdata[l].tiles.subdomains.length; s++)
+          urls.push(mapprops.mapdata[l].tiles.url.replace(/\${s}/,mapprops.mapdata[l].tiles.subdomains[s]));
+      }
+    else
+       urls=mapprops.mapdata[l].tiles.url;
+
+    layerMap[l] = new OpenLayers.Layer.TMS(mapprops.mapdata[l].label,
+                                           urls,
+                                           {
+                                            getURL: limitedUrl,
+                                            displayOutsideMaxExtent: true,
+                                            buffer: 1
+                                           });
+    map.addLayer(layerMap[l]);
+   }
+
+ // Update the attribution if the layer changes
+
+ function change_attribution_event(event)
+ {
+  for(var l=0; l<mapprops.mapdata.length; l++)
+     if(layerMap[l] == event.layer)
+        change_attribution(l);
+ }
+
+ map.events.register("changelayer",layerMap,change_attribution_event);
+
+ function change_attribution(l)
+ {
+  var data_url =mapprops.mapdata[l].attribution.data_url;
+  var data_text=mapprops.mapdata[l].attribution.data_text;
+  var tile_url =mapprops.mapdata[l].attribution.tile_url;
+  var tile_text=mapprops.mapdata[l].attribution.tile_text;
+
+  document.getElementById("attribution_data").innerHTML="<a href=\"" + data_url + "\" target=\"data_attribution\">" + data_text + "</a>";
+  document.getElementById("attribution_tile").innerHTML="<a href=\"" + tile_url + "\" target=\"tile_attribution\">" + tile_text + "</a>";
+ }
+
+ change_attribution(0);
+
+ // Add two vectors layers (one for highlights that display behind the vectors)
+
+ layerHighlights = new OpenLayers.Layer.Vector("Highlights",{displayInLayerSwitcher: false});
+ map.addLayer(layerHighlights);
+
+ layerVectors = new OpenLayers.Layer.Vector("Markers",{displayInLayerSwitcher: false});
+ map.addLayer(layerVectors);
+
+ // Handle feature selection and popup
+
+ select = new OpenLayers.Control.SelectFeature(layerVectors,
+                                               {onSelect: selectFeature, onUnselect: unselectFeature});
+
+ map.addControl(select);
+ select.activate();
+
+ createPopup();
+
+ // Add a boxes layer
+
+ layerBoxes = new OpenLayers.Layer.Boxes("Boundary",{displayInLayerSwitcher: false});
+ map.addLayer(layerBoxes);
+
+ box=null;
+
+ // Move the map
+
+ map.events.register("moveend", map, updateURLs);
+
+ var lon =args["lon"];
+ var lat =args["lat"];
+ var zoom=args["zoom"];
+
+ if(lon !== undefined && lat !== undefined && zoom !== undefined)
+   {
+    if(lon<mapprops.westedge) lon=mapprops.westedge;
+    if(lon>mapprops.eastedge) lon=mapprops.eastedge;
+
+    if(lat<mapprops.southedge) lat=mapprops.southedge;
+    if(lat>mapprops.northedge) lat=mapprops.northedge;
+
+    if(zoom<mapprops.zoomout) zoom=mapprops.zoomout;
+    if(zoom>mapprops.zoomin)  zoom=mapprops.zoomin;
+
+    var lonlat = new OpenLayers.LonLat(lon,lat);
+    lonlat.transform(epsg4326,epsg900913);
+
+    map.moveTo(lonlat,zoom-map.minZoomLevel);
+   }
+ else
+   {
+    map.setCenter(map.restrictedExtent.getCenterLonLat(), map.getZoomForExtent(map.restrictedExtent,true));
+    map.maxResolution = map.getResolution();
+   }
+
+ // Unhide editing URL if variable set
+
+ if(mapprops.editurl !== undefined && mapprops.editurl !== "")
+   {
+    var edit_url=document.getElementById("edit_url");
+
+    edit_url.style.display="";
+    edit_url.href=mapprops.editurl;
+   }
+
+ updateURLs();
+}
+
+
+//
+// Format a number in printf("%.5f") format.
+//
+
+function format5f(number)
+{
+ var newnumber=Math.floor(number*100000+0.5);
+ var delta=0;
+
+ if(newnumber>=0 && newnumber<100000) delta= 100000;
+ if(newnumber<0 && newnumber>-100000) delta=-100000;
+
+ var string=String(newnumber+delta);
+
+ var intpart =string.substring(0,string.length-5);
+ var fracpart=string.substring(string.length-5,string.length);
+
+ if(delta>0) intpart="0";
+ if(delta<0) intpart="-0";
+
+ return(intpart + "." + fracpart);
+}
+
+
+//
+// Build a set of URL arguments for the map location
+//
+
+function buildMapArguments()
+{
+ var lonlat = map.getCenter().clone();
+ lonlat.transform(epsg900913,epsg4326);
+
+ var zoom = map.getZoom() + map.minZoomLevel;
+
+ return "lat=" + format5f(lonlat.lat) + ";lon=" + format5f(lonlat.lon) + ";zoom=" + zoom;
+}
+
+
+//
+// Update the URLs
+//
+
+function updateURLs()
+{
+ var mapargs=buildMapArguments();
+
+ var links=document.getElementsByTagName("a");
+
+ for(var i=0; i<links.length; i++)
+   {
+    var element=links[i];
+
+    if(element.id == "permalink_url")
+       element.href=location.pathname + "?" + mapargs;
+
+    if(element.id == "edit_url")
+       element.href=mapprops.editurl + "?" + mapargs;
+   }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+///////////////////////// Popup and selection handling /////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+var popup=null;
+
+//
+// Create a popup - independent of map because want it fixed on screen not fixed on map.
+//
+
+function createPopup()
+{
+ popup=document.createElement("div");
+
+ popup.className = "popup";
+
+ popup.innerHTML = "<span></span>";
+
+ popup.style.display = "none";
+
+ popup.style.position = "fixed";
+ popup.style.top = "-4000px";
+ popup.style.left = "-4000px";
+ popup.style.zIndex = "100";
+
+ popup.style.padding = "5px";
+
+ popup.style.opacity=0.85;
+ popup.style.backgroundColor="#C0C0C0";
+ popup.style.border="4px solid #404040";
+
+ document.body.appendChild(popup);
+}
+
+
+//
+// Draw a popup - independent of map because want it fixed on screen not fixed on map.
+//
+
+function drawPopup(html)
+{
+ if(html===null)
+   {
+    popup.style.display="none";
+    return;
+   }
+
+ if(popup.style.display=="none")
+   {
+    var map_div=document.getElementById("map");
+
+    popup.style.left  =map_div.offsetParent.offsetLeft+map_div.offsetLeft+60 + "px";
+    popup.style.top   =                                map_div.offsetTop +30 + "px";
+    popup.style.width =map_div.clientWidth-120 + "px";
+
+    popup.style.display="";
+   }
+
+ var close="<span style='float: right; cursor: pointer;' onclick='drawPopup(null)'>X</span>";
+
+ popup.innerHTML=close+html;
+}
+
+
+//
+// Select a feature
+//
+
+function selectFeature(feature)
+{
+ if(feature.attributes.dump)
+    ajaxGET("fixme.cgi?dump=" + feature.attributes.dump, runDumpSuccess);
+
+ layerHighlights.destroyFeatures();
+
+ var highlight_style = new OpenLayers.Style({},{strokeColor: "#F0F000",strokeWidth: 8,
+                                                fillColor: "#F0F000",pointRadius: 4});
+
+ var highlight = new OpenLayers.Feature.Vector(feature.geometry.clone(),{},highlight_style);
+
+ layerHighlights.addFeatures([highlight]);
+}
+
+
+//
+// Un-select a feature
+//
+
+function unselectFeature(feature)
+{
+ layerHighlights.destroyFeatures();
+
+ drawPopup(null);
+}
+
+
+//
+// Display the dump data
+//
+
+function runDumpSuccess(response)
+{
+ var string=response.responseText;
+
+ if(mapprops.editurl !== undefined && mapprops.editurl !== "")
+   {
+    var types=["node", "way", "relation"];
+
+    for(var t in types)
+      {
+       var type=types[t];
+
+       var regexp=RegExp(type + " id='[0-9]+'");
+
+       var match=string.match(regexp);
+
+       if(match !== null)
+         {
+          match=String(match);
+
+          var id=match.slice(10+type.length,match.length-6);
+
+          string=string.replace(regexp,type + " id='<a href='" + mapprops.browseurl + "/" + type + "/" + id + "' target='" + type + id + "'>" + id + "</a>'");
+         }
+      }
+   }
+
+ drawPopup(string.split("><").join("><br><").split("<br><tag").join("<br>  <tag"));
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Server handling ////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+//
+// Define an AJAX request object
+//
+
+function ajaxGET(url,success,failure,state)
+{
+ var ajaxRequest=new XMLHttpRequest();
+
+ function ajaxGOT(options) {
+  if(this.readyState==4)
+     if(this.status==200)
+       { if(typeof(options.success)=="function") options.success(this,options.state); }
+     else
+       { if(typeof(options.failure)=="function") options.failure(this,options.state); }
+ }
+
+ ajaxRequest.onreadystatechange = function(){ ajaxGOT.call(ajaxRequest,{success: success, failure: failure, state: state}); };
+ ajaxRequest.open("GET", url, true);
+ ajaxRequest.send(null);
+}
+
+
+//
+// Display the status
+//
+
+function displayStatus(type,subtype,content)
+{
+ var child=document.getElementById("result_status").firstChild;
+
+ do
+   {
+    if(child.id !== undefined)
+       child.style.display="none";
+
+    child=child.nextSibling;
+   }
+ while(child !== null);
+
+ var chosen_status=document.getElementById("result_status_" + type);
+
+ chosen_status.style.display="";
+
+ if(subtype !== undefined)
+   {
+    var format_status=document.getElementById("result_status_" + subtype).innerHTML;
+
+    chosen_status.innerHTML=format_status.replace("#",String(content));
+   }
+}
+
+
+//
+// Display data statistics
+//
+
+function displayStatistics()
+{
+ // Use AJAX to get the statistics
+
+ ajaxGET("fixme.cgi?statistics=yes", runStatisticsSuccess);
+}
+
+
+//
+// Success in running data statistics generation.
+//
+
+function runStatisticsSuccess(response)
+{
+ document.getElementById("statistics_data").innerHTML="<pre>" + response.responseText + "</pre>";
+ document.getElementById("statistics_link").style.display="none";
+}
+
+
+//
+// Get the requested data
+//
+
+function displayData(datatype)  // called from fixme.html
+{
+ // Delete the old data
+
+ unselectFeature();
+
+ select.deactivate();
+
+ layerVectors.destroyFeatures();
+ layerHighlights.destroyFeatures();
+
+ if(box !== null)
+    layerBoxes.removeMarker(box);
+ box=null;
+
+ // Print the status
+
+ displayStatus("no_data");
+
+ // Return if just here to clear the data
+
+ if(datatype === "")
+    return;
+
+ // Get the new data
+
+ var mapbounds=map.getExtent().clone();
+ mapbounds.transform(epsg900913,epsg4326);
+
+ var url="fixme.cgi";
+
+ url=url + "?lonmin=" + format5f(mapbounds.left);
+ url=url + ";latmin=" + format5f(mapbounds.bottom);
+ url=url + ";lonmax=" + format5f(mapbounds.right);
+ url=url + ";latmax=" + format5f(mapbounds.top);
+ url=url + ";data=" + datatype;
+
+ // Use AJAX to get the data
+
+ ajaxGET(url, runFixmeSuccess, runFailure);
+}
+
+
+//
+// Success in getting the error log data
+//
+
+function runFixmeSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var style = new OpenLayers.Style({},{stroke: false,
+                                      pointRadius: 3,fillColor: "#FF0000",
+                                      cursor: "pointer"});
+
+ var features=[];
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,epsg900913);
+
+       box = new OpenLayers.Marker.Box(bounds);
+
+       layerBoxes.addMarker(box);
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat=words[1];
+       var lon=words[2];
+
+       var lonlat = new OpenLayers.LonLat(lon,lat).transform(epsg4326,epsg900913);
+
+       var point = new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);
+
+       features.push(new OpenLayers.Feature.Vector(point,{dump: dump},style));
+      }
+   }
+
+ select.activate();
+
+ layerVectors.addFeatures(features);
+
+ displayStatus("data","fixme",lines.length-2);
+}
+
+
+//
+// Failure in getting data.
+//
+
+function runFailure(response)
+{
+ displayStatus("failed");
+}
diff --git a/3rdparty/Routino/extras/find-fixme/web/www/index.html b/3rdparty/Routino/extras/find-fixme/web/www/index.html
new file mode 100644
index 0000000..dd8c3a4
--- /dev/null
+++ b/3rdparty/Routino/extras/find-fixme/web/www/index.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<meta http-equiv="refresh" content="1; URL=fixme.html">
+
+<title>Routino Extras : Viewer for OpenStreetMap "fixme" Tags</title>
+
+<!--
+ Routino extras fixme redirect web page.
+
+ Part of the Routino routing software.
+
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see http://www.gnu.org/licenses/.
+-->
+
+<link href="style.css" type="text/css" rel="stylesheet">
+</head>
+
+<body>
+
+<!-- Header Start -->
+
+<div class="header">
+
+<h1>Routino Extras : Viewer for OpenStreetMap "fixme" Tags</h1>
+
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2><a href="fixme.html" title="Page Moved">Page Moved</a></h2>
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer">
+
+<address>
+© Andrew M. Bishop - <a href="http://www.routino.org/">http://www.routino.org/</a>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</body>
+
+</html>
diff --git a/3rdparty/Routino/extras/find-fixme/web/www/paths.pl b/3rdparty/Routino/extras/find-fixme/web/www/paths.pl
new file mode 100644
index 0000000..0791efd
--- /dev/null
+++ b/3rdparty/Routino/extras/find-fixme/web/www/paths.pl
@@ -0,0 +1,34 @@
+#
+# Routino CGI paths Perl script
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2013 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# Directory path parameters
+
+# EDIT THIS to set the root directory for the non-web data files.
+$root_dir="..";
+
+# EDIT THIS to change the location of the individual directories.
+$bin_dir="$root_dir/bin";
+$data_dir="$root_dir/data";
+
+# EDIT THIS to change the name of the executable (enables easy selection of slim mode).
+$fixme_dumper_exe="fixme-dumper";
+
+1;
diff --git a/3rdparty/Routino/extras/plot-time/README.txt b/3rdparty/Routino/extras/plot-time/README.txt
new file mode 100644
index 0000000..2e002f2
--- /dev/null
+++ b/3rdparty/Routino/extras/plot-time/README.txt
@@ -0,0 +1,18 @@
+                      Planetsplitter Execution Time Analysis
+                      ======================================
+
+A Perl script that uses Gnuplot to plot a graph of the time taken by the
+planetsplitter program to run.
+
+
+plot-planetsplitter-time.pl
+---------------------------
+
+Example usage:
+
+planetsplitter --loggable --logtime ... > planetsplitter.log
+
+plot-planetsplitter-time.pl < planetsplitter.log
+
+This will generate a file called planetsplitter.png that contains the graph of
+the execution time.
diff --git a/3rdparty/Routino/extras/plot-time/plot-planetsplitter-time.pl b/3rdparty/Routino/extras/plot-time/plot-planetsplitter-time.pl
new file mode 100755
index 0000000..e5fd92d
--- /dev/null
+++ b/3rdparty/Routino/extras/plot-time/plot-planetsplitter-time.pl
@@ -0,0 +1,108 @@
+#!/usr/bin/perl
+#
+# Routino execution log plotter.
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2013-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+
+# Read the planetsplitter log file
+
+open(SECTION   ,">gnuplot.section.tmp");
+open(SUBSECTION,">gnuplot.subsection.tmp");
+
+my $count=1;
+my $startcount=0;
+my $totaltime=0;
+
+while(<STDIN>)
+  {
+   s%\r*\n%%;
+
+   next if(! $_);
+
+   next if(m%^=%);
+
+   if( m%^\[ *([0-9]+):([0-9.]+)\] ([^:]+)% && ! m%Complete$% )
+     {
+      my $time=(60.0*$1)+$2;
+      my $description=$3;
+
+      print SUBSECTION "$count $time \"$description\"\n";
+
+      $totaltime+=$time;
+     }
+   else
+     {
+      if($startcount>0)
+        {
+         my $boxcentre=($count+$startcount+0.5)/2;
+         my $boxwidth=$count-$startcount-1;
+
+         print SECTION "$boxcentre $totaltime $boxwidth\n";
+        }
+
+      $startcount=$count-0.5;
+      $totaltime=0;
+     }
+
+   $count++;
+  }
+
+close(SECTION);
+close(SUBSECTION);
+
+# Plot using gnuplot
+
+open(GNUPLOT,"|gnuplot");
+
+print GNUPLOT <<EOF
+
+set title "Planetsplitter Execution Time"
+
+set noxtics
+
+set ylabel "Sub-section Time (seconds)"
+set logscale y
+set yrange [0.001:]
+
+set style fill solid 1.0
+set boxwidth 0.8
+
+set nokey
+
+set style line 1 lt rgb "#FFC0C0" lw 1
+set style line 2 lt rgb "#FF0000" lw 1
+
+set term png size 1000,750
+set output "planetsplitter.png"
+
+plot "gnuplot.section.tmp" using 1:2:3 with boxes linestyle 1, \\
+     "gnuplot.section.tmp" using 1:(\$2*1.1):(sprintf("%.1f",\$2)) with labels font "Sans,9" center textcolor rgbcolor "#000000", \\
+     "gnuplot.subsection.tmp" using 1:2 with boxes linestyle 2, \\
+     "gnuplot.subsection.tmp" using (\$1+0.1):(0.0013):3 with labels font "Sans,8" left rotate textcolor rgbcolor "#000000"
+
+exit
+EOF
+;
+
+close(GNUPLOT);
+
+unlink "gnuplot.section.tmp";
+unlink "gnuplot.subsection.tmp";
diff --git a/3rdparty/Routino/extras/tagmodifier/Makefile b/3rdparty/Routino/extras/tagmodifier/Makefile
new file mode 100644
index 0000000..1eb9860
--- /dev/null
+++ b/3rdparty/Routino/extras/tagmodifier/Makefile
@@ -0,0 +1,88 @@
+# tagmodifier Makefile
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2013-2015 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# All configuration is in the top-level Makefile.conf
+
+include ../../Makefile.conf
+
+# Compilation targets
+
+C=$(wildcard *.c)
+D=$(wildcard .deps/*.d)
+
+ROUTINO_SRC=../../src
+
+EXE=tagmodifier
+
+########
+
+all: $(EXE)
+
+########
+
+TAGMODIFIER_OBJ=tagmodifier.o \
+	        $(ROUTINO_SRC)/files.o $(ROUTINO_SRC)/logging.o $(ROUTINO_SRC)/logerror.o \
+	        $(ROUTINO_SRC)/uncompress.o $(ROUTINO_SRC)/xmlparse.o $(ROUTINO_SRC)/tagging.o
+
+ifdef MINGW
+TAGMODIFIER_OBJ+=$(ROUTINO_SRC)/mman-win32.o
+endif
+
+tagmodifier : $(TAGMODIFIER_OBJ)
+	$(LD) $(TAGMODIFIER_OBJ) -o $@ $(LDFLAGS)
+
+########
+
+$(ROUTINO_SRC)/%.o :
+	cd $(ROUTINO_SRC) && $(MAKE) $(notdir $@)
+
+%.o : %.c
+	@[ -d .deps ] || mkdir .deps
+	$(CC) -c $(CFLAGS) -DSLIM=0 -I$(ROUTINO_SRC) $< -o $@ -MMD -MP -MF $(addprefix .deps/,$(addsuffix .d,$(basename $@)))
+
+########
+
+test:
+
+########
+
+install:
+
+########
+
+clean:
+	rm -f *~
+	rm -f *.o
+	rm -f $(EXE) *.exe
+	rm -f $(D)
+	rm -fr .deps
+	rm -f core
+
+########
+
+distclean: clean
+
+########
+
+include $(D)
+
+########
+
+.PHONY:: all test install clean distclean
diff --git a/3rdparty/Routino/extras/tagmodifier/README.txt b/3rdparty/Routino/extras/tagmodifier/README.txt
new file mode 100644
index 0000000..a4c30f8
--- /dev/null
+++ b/3rdparty/Routino/extras/tagmodifier/README.txt
@@ -0,0 +1,45 @@
+                        Tagging Rule Tester / Tag Modifier
+                        ==================================
+
+This program is used to run the tag transformation process on an OSM XML file
+for test purposes.  This allows it to be used to test new tagging rules or to
+make automatic rule-based modifications to tags within an XML file.
+
+
+tagmodifier
+-----------
+
+Usage: tagmodifier [--help]
+                   [--tagging=<filename>]
+                   [--loggable] [--logtime] [--logmemory]
+                   [--errorlog[<name>]]
+                   [<filename.osm> | <filename.osm.bz2> |
+                    <filename.osm.gz> | <filename.osm.xz>]
+
+--help
+       Prints out the help information.
+
+--tagging=<filename>
+       The name of the XML file containing the tagging rules (defaults
+       to 'tagging.xml' in the current directory).
+
+--loggable
+       Print progress messages that are suitable for logging to a file;
+       normally an incrementing counter is printed which is more
+       suitable for real-time display than logging.
+
+--logtime
+       Print the elapsed time for the processing.
+
+--logmemory
+       Print the used memory for the processing.
+
+--errorlog[=<name>]
+       Log parsing errors to 'error.log' or the specified file name.
+
+<filename.osm>
+       Specifies the filename(s) to read data from. Filenames ending
+       '.bz2' will be bzip2 uncompressed (if bzip2 support compiled
+       in). Filenames ending '.gz' will be gzip uncompressed (if gzip
+       support compiled in). Filenames ending '.xz' will be xz
+       uncompressed (if xz support compiled in).
diff --git a/3rdparty/Routino/extras/tagmodifier/tagmodifier.c b/3rdparty/Routino/extras/tagmodifier/tagmodifier.c
new file mode 100644
index 0000000..bb4a2d0
--- /dev/null
+++ b/3rdparty/Routino/extras/tagmodifier/tagmodifier.c
@@ -0,0 +1,723 @@
+/***************************************
+ Test application for OSM XML file parser / tagging rule testing.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#include "xmlparse.h"
+#include "tagging.h"
+
+#include "files.h"
+#include "uncompress.h"
+
+
+/* Local variables (re-initialised for each file) */
+
+static uint64_t nnodes,nways,nrelations;
+
+TagList *current_tags;
+
+
+/* Local functions */
+
+static void print_usage(int detail,const char *argerr,const char *err);
+
+
+/* The XML tag processing function prototypes */
+
+static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding);
+static int osmType_function(const char *_tag_,int _type_,const char *version,const char *generator);
+static int relationType_function(const char *_tag_,int _type_,const char *id,const char *timestamp,const char *uid,const char *user,const char *visible,const char *version,const char *action);
+static int wayType_function(const char *_tag_,int _type_,const char *id,const char *timestamp,const char *uid,const char *user,const char *visible,const char *version,const char *action);
+static int memberType_function(const char *_tag_,int _type_,const char *type,const char *ref,const char *role);
+static int ndType_function(const char *_tag_,int _type_,const char *ref);
+static int nodeType_function(const char *_tag_,int _type_,const char *id,const char *lat,const char *lon,const char *timestamp,const char *uid,const char *user,const char *visible,const char *version,const char *action);
+static int tagType_function(const char *_tag_,int _type_,const char *k,const char *v);
+static int boundType_function(const char *_tag_,int _type_,const char *box,const char *origin);
+static int boundsType_function(const char *_tag_,int _type_,const char *minlat,const char *minlon,const char *maxlat,const char *maxlon,const char *origin);
+
+
+/* The XML tag definitions */
+
+/*+ The boundsType type tag. +*/
+static const xmltag boundsType_tag=
+              {"bounds",
+               5, {"minlat","minlon","maxlat","maxlon","origin"},
+               boundsType_function,
+               {NULL}};
+
+/*+ The boundType type tag. +*/
+static const xmltag boundType_tag=
+              {"bound",
+               2, {"box","origin"},
+               boundType_function,
+               {NULL}};
+
+/*+ The tagType type tag. +*/
+static const xmltag tagType_tag=
+              {"tag",
+               2, {"k","v"},
+               tagType_function,
+               {NULL}};
+
+/*+ The nodeType type tag. +*/
+static const xmltag nodeType_tag=
+              {"node",
+               9, {"id","lat","lon","timestamp","uid","user","visible","version","action"},
+               nodeType_function,
+               {&tagType_tag,NULL}};
+
+/*+ The ndType type tag. +*/
+static const xmltag ndType_tag=
+              {"nd",
+               1, {"ref"},
+               ndType_function,
+               {NULL}};
+
+/*+ The memberType type tag. +*/
+static const xmltag memberType_tag=
+              {"member",
+               3, {"type","ref","role"},
+               memberType_function,
+               {NULL}};
+
+/*+ The wayType type tag. +*/
+static const xmltag wayType_tag=
+              {"way",
+               7, {"id","timestamp","uid","user","visible","version","action"},
+               wayType_function,
+               {&ndType_tag,&tagType_tag,NULL}};
+
+/*+ The relationType type tag. +*/
+static const xmltag relationType_tag=
+              {"relation",
+               7, {"id","timestamp","uid","user","visible","version","action"},
+               relationType_function,
+               {&memberType_tag,&tagType_tag,NULL}};
+
+/*+ The osmType type tag. +*/
+static const xmltag osmType_tag=
+              {"osm",
+               2, {"version","generator"},
+               osmType_function,
+               {&boundsType_tag,&boundType_tag,&nodeType_tag,&wayType_tag,&relationType_tag,NULL}};
+
+/*+ The xmlDeclaration type tag. +*/
+static const xmltag xmlDeclaration_tag=
+              {"xml",
+               2, {"version","encoding"},
+               xmlDeclaration_function,
+               {NULL}};
+
+
+/*+ The complete set of tags at the top level. +*/
+static const xmltag *const xml_toplevel_tags[]={&xmlDeclaration_tag,&osmType_tag,NULL};
+
+
+/* The XML tag processing functions */
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the boundsType XSD type is seen
+
+  int boundsType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *minlat The contents of the 'minlat' attribute (or NULL if not defined).
+
+  const char *minlon The contents of the 'minlon' attribute (or NULL if not defined).
+
+  const char *maxlat The contents of the 'maxlat' attribute (or NULL if not defined).
+
+  const char *maxlon The contents of the 'maxlon' attribute (or NULL if not defined).
+
+  const char *origin The contents of the 'origin' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int boundsType_function(const char *_tag_,int _type_,const char *minlat,const char *minlon,const char *maxlat,const char *maxlon,const char *origin)
+{
+ printf("  <%s%s",(_type_==XMLPARSE_TAG_END)?"/":"",_tag_);
+ if(minlat) printf(" minlat='%s'",ParseXML_Encode_Safe_XML(minlat));
+ if(minlon) printf(" minlon='%s'",ParseXML_Encode_Safe_XML(minlon));
+ if(maxlat) printf(" maxlat='%s'",ParseXML_Encode_Safe_XML(maxlat));
+ if(maxlon) printf(" maxlon='%s'",ParseXML_Encode_Safe_XML(maxlon));
+ if(origin) printf(" origin='%s'",ParseXML_Encode_Safe_XML(origin));
+ printf("%s>\n",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?" /":"");
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the boundType XSD type is seen
+
+  int boundType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *box The contents of the 'box' attribute (or NULL if not defined).
+
+  const char *origin The contents of the 'origin' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int boundType_function(const char *_tag_,int _type_,const char *box,const char *origin)
+{
+ printf("  <%s%s",(_type_==XMLPARSE_TAG_END)?"/":"",_tag_);
+ if(box) printf(" box='%s'",ParseXML_Encode_Safe_XML(box));
+ if(origin) printf(" origin='%s'",ParseXML_Encode_Safe_XML(origin));
+ printf("%s>\n",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?" /":"");
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the tagType XSD type is seen
+
+  int tagType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *k The contents of the 'k' attribute (or NULL if not defined).
+
+  const char *v The contents of the 'v' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int tagType_function(const char *_tag_,int _type_,const char *k,const char *v)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    XMLPARSE_ASSERT_STRING(_tag_,k);
+    XMLPARSE_ASSERT_STRING(_tag_,v);
+
+    AppendTag(current_tags,k,v);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the nodeType XSD type is seen
+
+  int nodeType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *id The contents of the 'id' attribute (or NULL if not defined).
+
+  const char *lat The contents of the 'lat' attribute (or NULL if not defined).
+
+  const char *lon The contents of the 'lon' attribute (or NULL if not defined).
+
+  const char *timestamp The contents of the 'timestamp' attribute (or NULL if not defined).
+
+  const char *uid The contents of the 'uid' attribute (or NULL if not defined).
+
+  const char *user The contents of the 'user' attribute (or NULL if not defined).
+
+  const char *visible The contents of the 'visible' attribute (or NULL if not defined).
+
+  const char *version The contents of the 'version' attribute (or NULL if not defined).
+
+  const char *action The contents of the 'action' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int nodeType_function(const char *_tag_,int _type_,const char *id,const char *lat,const char *lon,const char *timestamp,const char *uid,const char *user,const char *visible,const char *version,const char *action)
+{
+ static int64_t llid; /* static variable to store attributes from <node> tag until </node> tag */
+
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    nnodes++;
+
+    if(!(nnodes%10000))
+       fprintf_middle(stderr,"Reading: Lines=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,ParseXML_LineNumber(),nnodes,nways,nrelations);
+
+    current_tags=NewTagList();
+
+    /* Handle the node information */
+
+    XMLPARSE_ASSERT_INTEGER(_tag_,id); llid=atoll(id); /* need int64_t conversion */
+   }
+
+ if(_type_&XMLPARSE_TAG_END)
+   {
+    TagList *result=ApplyNodeTaggingRules(current_tags,llid);
+    int i;
+
+    for(i=0;i<result->ntags;i++)
+      {
+       printf("    <tag");
+       printf(" k='%s'",ParseXML_Encode_Safe_XML(result->k[i]));
+       printf(" v='%s'",ParseXML_Encode_Safe_XML(result->v[i]));
+       printf(" />\n");
+      }
+
+    DeleteTagList(current_tags);
+    DeleteTagList(result);
+   }
+
+ printf("  <%s%s",(_type_==XMLPARSE_TAG_END)?"/":"",_tag_);
+ if(id) printf(" id='%s'",ParseXML_Encode_Safe_XML(id));
+ if(lat) printf(" lat='%s'",ParseXML_Encode_Safe_XML(lat));
+ if(lon) printf(" lon='%s'",ParseXML_Encode_Safe_XML(lon));
+ if(timestamp) printf(" timestamp='%s'",ParseXML_Encode_Safe_XML(timestamp));
+ if(uid) printf(" uid='%s'",ParseXML_Encode_Safe_XML(uid));
+ if(user) printf(" user='%s'",ParseXML_Encode_Safe_XML(user));
+ if(visible) printf(" visible='%s'",ParseXML_Encode_Safe_XML(visible));
+ if(version) printf(" version='%s'",ParseXML_Encode_Safe_XML(version));
+ if(action) printf(" action='%s'",ParseXML_Encode_Safe_XML(action));
+ printf("%s>\n",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?" /":"");
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the ndType XSD type is seen
+
+  int ndType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *ref The contents of the 'ref' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int ndType_function(const char *_tag_,int _type_,const char *ref)
+{
+ printf("    <%s%s",(_type_==XMLPARSE_TAG_END)?"/":"",_tag_);
+ if(ref) printf(" ref='%s'",ParseXML_Encode_Safe_XML(ref));
+ printf("%s>\n",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?" /":"");
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the memberType XSD type is seen
+
+  int memberType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *type The contents of the 'type' attribute (or NULL if not defined).
+
+  const char *ref The contents of the 'ref' attribute (or NULL if not defined).
+
+  const char *role The contents of the 'role' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int memberType_function(const char *_tag_,int _type_,const char *type,const char *ref,const char *role)
+{
+ printf("    <%s%s",(_type_==XMLPARSE_TAG_END)?"/":"",_tag_);
+ if(type) printf(" type='%s'",ParseXML_Encode_Safe_XML(type));
+ if(ref) printf(" ref='%s'",ParseXML_Encode_Safe_XML(ref));
+ if(role) printf(" role='%s'",ParseXML_Encode_Safe_XML(role));
+ printf("%s>\n",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?" /":"");
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the wayType XSD type is seen
+
+  int wayType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *id The contents of the 'id' attribute (or NULL if not defined).
+
+  const char *timestamp The contents of the 'timestamp' attribute (or NULL if not defined).
+
+  const char *uid The contents of the 'uid' attribute (or NULL if not defined).
+
+  const char *user The contents of the 'user' attribute (or NULL if not defined).
+
+  const char *visible The contents of the 'visible' attribute (or NULL if not defined).
+
+  const char *version The contents of the 'version' attribute (or NULL if not defined).
+
+  const char *action The contents of the 'action' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int wayType_function(const char *_tag_,int _type_,const char *id,const char *timestamp,const char *uid,const char *user,const char *visible,const char *version,const char *action)
+{
+ static int64_t llid; /* static variable to store attributes from <way> tag until </way> tag */
+
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    nways++;
+
+    if(!(nways%1000))
+       fprintf_middle(stderr,"Reading: Lines=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,ParseXML_LineNumber(),nnodes,nways,nrelations);
+
+    current_tags=NewTagList();
+
+    /* Handle the way information */
+
+    XMLPARSE_ASSERT_INTEGER(_tag_,id); llid=atoll(id); /* need int64_t conversion */
+   }
+
+ if(_type_&XMLPARSE_TAG_END)
+   {
+    TagList *result=ApplyWayTaggingRules(current_tags,llid);
+    int i;
+
+    for(i=0;i<result->ntags;i++)
+      {
+       printf("    <tag");
+       printf(" k='%s'",ParseXML_Encode_Safe_XML(result->k[i]));
+       printf(" v='%s'",ParseXML_Encode_Safe_XML(result->v[i]));
+       printf(" />\n");
+      }
+
+    DeleteTagList(current_tags);
+    DeleteTagList(result);
+   }
+
+ printf("  <%s%s",(_type_==XMLPARSE_TAG_END)?"/":"",_tag_);
+ if(id) printf(" id='%s'",ParseXML_Encode_Safe_XML(id));
+ if(timestamp) printf(" timestamp='%s'",ParseXML_Encode_Safe_XML(timestamp));
+ if(uid) printf(" uid='%s'",ParseXML_Encode_Safe_XML(uid));
+ if(user) printf(" user='%s'",ParseXML_Encode_Safe_XML(user));
+ if(visible) printf(" visible='%s'",ParseXML_Encode_Safe_XML(visible));
+ if(version) printf(" version='%s'",ParseXML_Encode_Safe_XML(version));
+ if(action) printf(" action='%s'",ParseXML_Encode_Safe_XML(action));
+ printf("%s>\n",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?" /":"");
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the relationType XSD type is seen
+
+  int relationType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *id The contents of the 'id' attribute (or NULL if not defined).
+
+  const char *timestamp The contents of the 'timestamp' attribute (or NULL if not defined).
+
+  const char *uid The contents of the 'uid' attribute (or NULL if not defined).
+
+  const char *user The contents of the 'user' attribute (or NULL if not defined).
+
+  const char *visible The contents of the 'visible' attribute (or NULL if not defined).
+
+  const char *version The contents of the 'version' attribute (or NULL if not defined).
+
+  const char *action The contents of the 'action' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int relationType_function(const char *_tag_,int _type_,const char *id,const char *timestamp,const char *uid,const char *user,const char *visible,const char *version,const char *action)
+{
+ static int64_t llid; /* static variable to store attributes from <relation> tag until </relation> tag */
+
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    nrelations++;
+
+    if(!(nrelations%1000))
+       fprintf_middle(stderr,"Reading: Lines=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,ParseXML_LineNumber(),nnodes,nways,nrelations);
+
+    current_tags=NewTagList();
+
+    /* Handle the relation information */
+
+    XMLPARSE_ASSERT_INTEGER(_tag_,id); llid=atoll(id); /* need int64_t conversion */
+   }
+
+ if(_type_&XMLPARSE_TAG_END)
+   {
+    TagList *result=ApplyRelationTaggingRules(current_tags,llid);
+    int i;
+
+    for(i=0;i<result->ntags;i++)
+      {
+       printf("    <tag");
+       printf(" k='%s'",ParseXML_Encode_Safe_XML(result->k[i]));
+       printf(" v='%s'",ParseXML_Encode_Safe_XML(result->v[i]));
+       printf(" />\n");
+      }
+
+    DeleteTagList(current_tags);
+    DeleteTagList(result);
+   }
+
+ printf("  <%s%s",(_type_==XMLPARSE_TAG_END)?"/":"",_tag_);
+ if(id) printf(" id='%s'",ParseXML_Encode_Safe_XML(id));
+ if(timestamp) printf(" timestamp='%s'",ParseXML_Encode_Safe_XML(timestamp));
+ if(uid) printf(" uid='%s'",ParseXML_Encode_Safe_XML(uid));
+ if(user) printf(" user='%s'",ParseXML_Encode_Safe_XML(user));
+ if(visible) printf(" visible='%s'",ParseXML_Encode_Safe_XML(visible));
+ if(version) printf(" version='%s'",ParseXML_Encode_Safe_XML(version));
+ if(action) printf(" action='%s'",ParseXML_Encode_Safe_XML(action));
+ printf("%s>\n",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?" /":"");
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the osmType XSD type is seen
+
+  int osmType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *version The contents of the 'version' attribute (or NULL if not defined).
+
+  const char *generator The contents of the 'generator' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int osmType_function(const char *_tag_,int _type_,const char *version,const char *generator)
+{
+ printf("<%s%s",(_type_==XMLPARSE_TAG_END)?"/":"",_tag_);
+ if(version) printf(" version='%s'",ParseXML_Encode_Safe_XML(version));
+ if(generator) printf(" generator='%s'",ParseXML_Encode_Safe_XML(generator));
+ printf("%s>\n",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?" /":"");
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the XML declaration is seen
+
+  int xmlDeclaration_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *version The contents of the 'version' attribute (or NULL if not defined).
+
+  const char *encoding The contents of the 'encoding' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding)
+{
+ printf("<?%s",_tag_);
+ if(version) printf(" version='%s'",ParseXML_Encode_Safe_XML(version));
+ if(encoding) printf(" encoding='%s'",ParseXML_Encode_Safe_XML(encoding));
+ printf(" ?>\n");
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The main program for the tagmodifier.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int main(int argc,char **argv)
+{
+ char *tagging=NULL,*filename=NULL,*errorlog=NULL;
+ char *p;
+ int fd;
+ int arg,retval;
+
+ /* Parse the command line arguments */
+
+ for(arg=1;arg<argc;arg++)
+   {
+    if(!strcmp(argv[arg],"--help"))
+       print_usage(1,NULL,NULL);
+    else if(!strncmp(argv[arg],"--tagging=",10))
+       tagging=&argv[arg][10];
+    else if(!strcmp(argv[arg],"--loggable"))
+       option_loggable=1;
+    else if(!strcmp(argv[arg],"--logtime"))
+       option_logtime=1;
+    else if(!strcmp(argv[arg],"--logmemory"))
+       option_logmemory=1;
+    else if(!strcmp(argv[arg],"--errorlog"))
+       errorlog="error.log";
+    else if(!strncmp(argv[arg],"--errorlog=",11))
+       errorlog=&argv[arg][11];
+    else if(argv[arg][0]=='-' && argv[arg][1]=='-')
+       print_usage(0,argv[arg],NULL);
+    else if(filename)
+       print_usage(0,argv[arg],"Only one file name can be specified on the command line.");
+    else
+       filename=argv[arg];
+   }
+
+ /* Check the specified command line options */
+
+ if(!filename)
+    print_usage(0,NULL,"A single file name must be specified on the command line.");
+
+ if(tagging)
+   {
+    if(!ExistsFile(tagging))
+      {
+       fprintf(stderr,"Error: The '--tagging' option specifies a file that does not exist.\n");
+       exit(EXIT_FAILURE);
+      }
+   }
+ else
+   {
+    if(ExistsFile("tagging.xml"))
+       tagging="tagging.xml";
+    else
+      {
+       fprintf(stderr,"Error: The '--tagging' option was not used and the default 'tagging.xml' does not exist.\n");
+       exit(EXIT_FAILURE);
+      }
+   }
+
+ if(ParseXMLTaggingRules(tagging))
+   {
+    fprintf(stderr,"Error: Cannot read the tagging rules in the file '%s'.\n",tagging);
+    exit(EXIT_FAILURE);
+   }
+
+ /* Open the input file */
+
+ fd=OpenFile(filename);
+
+ if((p=strstr(filename,".bz2")) && !strcmp(p,".bz2"))
+    fd=Uncompress_Bzip2(fd);
+
+ if((p=strstr(filename,".gz")) && !strcmp(p,".gz"))
+    fd=Uncompress_Gzip(fd);
+
+ if((p=strstr(filename,".xz")) && !strcmp(p,".xz"))
+    fd=Uncompress_Xz(fd);
+
+ /* Create the error log file */
+
+ if(errorlog)
+    open_errorlog(errorlog,0,0);
+
+ /* Parse the file */
+
+ nnodes=0;
+ nways=0;
+ nrelations=0;
+
+ current_tags=NULL;
+
+ fprintf_first(stderr,"Reading: Lines=0 Nodes=0 Ways=0 Relations=0");
+
+ retval=ParseXML(fd,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_IGNORE);
+
+ fprintf_last(stderr,"Read: Lines=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,ParseXML_LineNumber(),nnodes,nways,nrelations);
+
+ /* Close the error log file */
+
+ if(errorlog)
+    close_errorlog();
+
+ /* Tidy up */
+
+ CloseFile(fd);
+
+ return(retval);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the usage information.
+
+  int detail The level of detail to use - 0 = low, 1 = high.
+
+  const char *argerr The argument that gave the error (if there is one).
+
+  const char *err Other error message (if there is one).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_usage(int detail,const char *argerr,const char *err)
+{
+ fprintf(stderr,
+         "Usage: tagmodifier [--help]\n"
+         "                   [--tagging=<filename>]\n"
+         "                   [--loggable] [--logtime] [--logmemory]\n"
+         "                   [--errorlog[=<name>]]\n"
+         "                   <filename.osm>"
+#if defined(USE_BZIP2) && USE_BZIP2
+         " | <filename.osm.bz2>"
+#endif
+#if defined(USE_GZIP) && USE_GZIP
+         " | <filename.osm.gz>"
+#endif
+#if defined(USE_XZ) && USE_XZ
+         " | <filename.osm.xz>"
+#endif
+         "\n");
+
+ if(argerr)
+    fprintf(stderr,
+            "\n"
+            "Error with command line parameter: %s\n",argerr);
+
+ if(err)
+    fprintf(stderr,
+            "\n"
+            "Error: %s\n",err);
+
+ if(detail)
+    fprintf(stderr,
+            "\n"
+            "--help                    Prints this information.\n"
+            "\n"
+            "--tagging=<filename>      The name of the XML file containing the tagging rules\n"
+            "                          (defaults to 'tagging.xml' in current directory).\n"
+            "\n"
+            "--loggable                Print progress messages suitable for logging to file.\n"
+            "--logtime                 Print the elapsed time for the processing.\n"
+            "--logmemory               Print the max allocated/mapped memory for each step.\n"
+            "--errorlog[=<name>]       Log parsing errors to 'error.log' or the given name.\n"
+            "\n"
+            "<filename.osm>            The name of the file to process.\n"
+#if defined(USE_BZIP2) && USE_BZIP2
+            "                          Filenames ending '.bz2' will be bzip2 uncompressed.\n"
+#endif
+#if defined(USE_GZIP) && USE_GZIP
+            "                          Filenames ending '.gz' will be gzip uncompressed.\n"
+#endif
+#if defined(USE_XZ) && USE_XZ
+            "                          Filenames ending '.xz' will be xz uncompressed.\n"
+#endif
+            );
+
+ exit(!detail);
+}
diff --git a/3rdparty/Routino/src/Makefile b/3rdparty/Routino/src/Makefile
new file mode 100644
index 0000000..f6be89e
--- /dev/null
+++ b/3rdparty/Routino/src/Makefile
@@ -0,0 +1,274 @@
+# Source code Makefile
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2015 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# All configuration is in the top-level Makefile.conf
+
+include ../Makefile.conf
+
+# Debugging options
+
+#CFLAGS+=-O0 -g
+#CFLAGS+=-pg
+#CFLAGS+=-fprofile-arcs -ftest-coverage
+
+#LDFLAGS+=-pg -static
+#LDFLAGS+=-fprofile-arcs -ftest-coverage
+
+# Sub-directories and sub-makefiles
+
+SUBFILES=$(wildcard */Makefile)
+SUBDIRS=$(foreach f,$(SUBFILES),$(dir $f))
+
+# Compilation targets
+
+C=$(wildcard *.c)
+D=$(wildcard .deps/*.d)
+
+EXE=planetsplitter planetsplitter-slim router router-slim filedumperx filedumper filedumper-slim
+
+LIB=libroutino.so libroutino-slim.so
+
+########
+
+all: all-local
+	for dir in $(SUBDIRS); do \
+	   ( cd $$dir && $(MAKE) $@ ); \
+	done
+
+all-local: $(EXE) $(LIB)
+
+########
+
+PLANETSPLITTER_OBJ=planetsplitter.o \
+	           nodesx.o segmentsx.o waysx.o relationsx.o superx.o prunex.o \
+	           ways.o types.o \
+	           files.o logging.o logerror.o errorlogx.o \
+	           results.o queue.o sorting.o \
+	           xmlparse.o tagging.o \
+	           uncompress.o osmxmlparse.o osmpbfparse.o osmo5mparse.o osmparser.o
+
+ifdef MINGW
+PLANETSPLITTER_OBJ+=mman-win32.o
+endif
+
+planetsplitter : $(PLANETSPLITTER_OBJ)
+	$(LD) $(PLANETSPLITTER_OBJ) -o $@ $(LDFLAGS)
+
+########
+
+PLANETSPLITTER_SLIM_OBJ=planetsplitter-slim.o \
+	                nodesx-slim.o segmentsx-slim.o waysx-slim.o relationsx-slim.o superx-slim.o prunex-slim.o \
+	                ways.o types.o \
+	                files.o logging.o logerror-slim.o errorlogx-slim.o \
+	                results.o queue.o sorting.o \
+	                xmlparse.o tagging.o \
+	                uncompress.o osmxmlparse.o osmpbfparse.o osmo5mparse.o osmparser.o
+
+ifdef MINGW
+PLANETSPLITTER_SLIM_OBJ+=mman-win32.o
+endif
+
+planetsplitter-slim : $(PLANETSPLITTER_SLIM_OBJ)
+	$(LD) $(PLANETSPLITTER_SLIM_OBJ) -o $@ $(LDFLAGS)
+
+########
+
+ROUTER_OBJ=router.o \
+	   nodes.o segments.o ways.o relations.o types.o fakes.o \
+	   optimiser.o output.o \
+	   files.o logging.o profiles.o xmlparse.o \
+	   results.o queue.o translations.o
+
+ifdef MINGW
+ROUTER_OBJ+=mman-win32.o
+endif
+
+router : $(ROUTER_OBJ)
+	$(LD) $(ROUTER_OBJ) -o $@ $(LDFLAGS)
+
+########
+
+ROUTER_SLIM_OBJ=router-slim.o \
+	        nodes-slim.o segments-slim.o ways-slim.o relations-slim.o types.o fakes-slim.o \
+	        optimiser-slim.o output-slim.o \
+	        files.o logging.o profiles.o xmlparse.o \
+	        results.o queue.o translations.o
+
+ifdef MINGW
+ROUTER_SLIM_OBJ+=mman-win32.o
+endif
+
+router-slim : $(ROUTER_SLIM_OBJ)
+	$(LD) $(ROUTER_SLIM_OBJ) -o $@ $(LDFLAGS)
+
+########
+
+FILEDUMPERX_OBJ=filedumperx.o \
+	        files.o logging.o
+
+ifdef MINGW
+FILEDUMPERX_OBJ+=mman-win32.o
+endif
+
+filedumperx : $(FILEDUMPERX_OBJ)
+	$(LD) $(FILEDUMPERX_OBJ) -o $@ $(LDFLAGS)
+
+########
+
+FILEDUMPER_OBJ=filedumper.o \
+	       nodes.o segments.o ways.o relations.o types.o fakes.o errorlog.o \
+               visualiser.o \
+	       files.o logging.o xmlparse.o
+
+ifdef MINGW
+FILEDUMPER_OBJ+=mman-win32.o
+endif
+
+filedumper : $(FILEDUMPER_OBJ)
+	$(LD) $(FILEDUMPER_OBJ) -o $@ $(LDFLAGS)
+
+########
+
+FILEDUMPER_SLIM_OBJ=filedumper-slim.o \
+	       nodes-slim.o segments-slim.o ways-slim.o relations-slim.o types.o fakes-slim.o errorlog-slim.o \
+	       visualiser-slim.o \
+	       files.o logging.o xmlparse.o
+
+ifdef MINGW
+FILEDUMPER_SLIM_OBJ+=mman-win32.o
+endif
+
+filedumper-slim : $(FILEDUMPER_SLIM_OBJ)
+	$(LD) $(FILEDUMPER_SLIM_OBJ) -o $@ $(LDFLAGS)
+
+########
+
+%.o : %.c
+	@[ -d .deps ] || mkdir .deps
+	$(CC) -c $(CFLAGS) -DSLIM=0 -DROUTINO_DATADIR=\"$(datadir)\" $< -o $@ -MMD -MP -MF $(addprefix .deps/,$(addsuffix .d,$(basename $@)))
+
+%-slim.o : %.c
+	@[ -d .deps ] || mkdir .deps
+	$(CC) -c $(CFLAGS) -DSLIM=1 -DROUTINO_DATADIR=\"$(datadir)\" $< -o $@ -MMD -MP -MF $(addprefix .deps/,$(addsuffix .d,$(basename $@)))
+
+########
+
+LIBROUTINO_OBJ=routino-lib.o \
+	        nodes-lib.o segments-lib.o ways-lib.o relations-lib.o types-lib.o fakes-lib.o \
+	        optimiser-lib.o output-lib.o \
+	        files-lib.o profiles-lib.o xmlparse-lib.o \
+	        results-lib.o queue-lib.o translations-lib.o
+
+ifdef MINGW
+LIBROUTINO_OBJ+=mman-win32.o
+endif
+
+libroutino.so : $(LIBROUTINO_OBJ)
+	$(LD) $(LIBROUTINO_OBJ) -o $@ $(LDFLAGS) $(LDFLAGS_LIB)
+
+########
+
+LIBROUTINO_SLIM_OBJ=routino-slim-lib.o \
+	        nodes-slim-lib.o segments-slim-lib.o ways-slim-lib.o relations-slim-lib.o types-lib.o fakes-slim-lib.o \
+	        optimiser-slim-lib.o output-slim-lib.o \
+	        files-lib.o profiles-lib.o xmlparse-lib.o \
+	        results-lib.o queue-lib.o translations-lib.o
+
+ifdef MINGW
+LIBROUTINO_SLIM_OBJ+=mman-win32.o
+endif
+
+libroutino-slim.so : $(LIBROUTINO_SLIM_OBJ)
+	$(LD) $(LIBROUTINO_SLIM_OBJ) -o $@ $(LDFLAGS) $(LDFLAGS_LIB)
+
+########
+
+%-lib.o : %.c
+	@[ -d .deps ] || mkdir .deps
+	$(CC) -c $(CFLAGS) $(CFLAGS_LIB) -DSLIM=0 -DLIBROUTINO $< -o $@ -MMD -MP -MF $(addprefix .deps/,$(addsuffix .d,$(basename $@)))
+
+%-slim-lib.o : %.c
+	@[ -d .deps ] || mkdir .deps
+	$(CC) -c $(CFLAGS) $(CFLAGS_LIB) -DSLIM=1 -DLIBROUTINO $< -o $@ -MMD -MP -MF $(addprefix .deps/,$(addsuffix .d,$(basename $@)))
+
+########
+
+test: test-local
+	for dir in $(SUBDIRS); do \
+	   ( cd $$dir && $(MAKE) $@ ); \
+	done
+
+test-local:
+
+########
+
+install: install-local
+	for dir in $(SUBDIRS); do \
+	   ( cd $$dir && $(MAKE) $@ ); \
+	done
+
+install-local: all-local
+	@[ -d $(DESTDIR)$(bindir) ] || mkdir -p $(DESTDIR)$(bindir)
+	@for file in $(EXE); do \
+	    if [ -f $$file ]; then \
+	       echo cp $$file $(DESTDIR)$(bindir) ;\
+	       cp -f $$file $(DESTDIR)$(bindir) ;\
+	    fi ;\
+	    if [ -f $$file.exe ]; then \
+	       echo cp $$file.exe $(DESTDIR)$(bindir) ;\
+	       cp -f $$file.exe $(DESTDIR)$(bindir) ;\
+	    fi ;\
+	 done
+
+########
+
+clean: clean-local
+	for dir in $(SUBDIRS); do \
+	   ( cd $$dir && $(MAKE) $@ ); \
+	done
+
+clean-local:
+	rm -f *~
+	rm -f *.o
+	rm -f $(EXE) *.exe
+	rm -f $(LIB)
+	rm -f $(D)
+	rm -fr .deps
+	rm -f core
+	rm -f *.gcda *.gcno *.gcov gmon.out
+
+########
+
+distclean: distclean-local
+	for dir in $(SUBDIRS); do \
+	   ( cd $$dir && $(MAKE) $@ ); \
+	done
+
+distclean-local: clean-local
+
+########
+
+include $(D)
+
+########
+
+.PHONY:: all test install clean distclean
+
+.PHONY:: all-local test-local install-local clean-local distclean-local
diff --git a/3rdparty/Routino/src/cache.h b/3rdparty/Routino/src/cache.h
new file mode 100644
index 0000000..bd33cb5
--- /dev/null
+++ b/3rdparty/Routino/src/cache.h
@@ -0,0 +1,179 @@
+/***************************************
+ Functions to maintain an in-RAM cache of on-disk data for slim mode.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2013-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#if SLIM
+
+#ifndef CACHE_H
+#define CACHE_H    /*+ To stop multiple inclusions. +*/
+
+#include <stdlib.h>
+
+#include "types.h"
+
+
+/* Macros for constants */
+
+#define CACHEWIDTH 8192         /*+ The width of the cache. +*/
+#define CACHEDEPTH   16         /*+ The depth of the cache. +*/
+
+
+/* Macro for structure forward declaration */
+
+#define CACHE_STRUCTURE_FWD(type) typedef struct _##type##Cache type##Cache;
+
+
+/* Macro for structure declaration */
+
+/*+ A macro to create a cache structure. +*/
+#define CACHE_STRUCTURE(type) \
+                              \
+struct _##type##Cache                                                     \
+{                                                                         \
+ int     first  [CACHEWIDTH];             /*+ The first entry to fill +*/ \
+                                                                          \
+ type    data   [CACHEWIDTH][CACHEDEPTH]; /*+ The array of type##s. +*/   \
+ index_t indices[CACHEWIDTH][CACHEDEPTH]; /*+ The array of indexes. +*/   \
+};
+
+
+/* Macros for function prototypes */
+
+#define CACHE_NEWCACHE_PROTO(type) static inline type##Cache *New##type##Cache(void);
+
+#define CACHE_DELETECACHE_PROTO(type) static inline void Delete##type##Cache(type##Cache *cache);
+
+#define CACHE_FETCHCACHE_PROTO(type) static inline type *FetchCached##type(type##Cache *cache,index_t index,int fd,off_t offset);
+
+#define CACHE_REPLACECACHE_PROTO(type) static inline void ReplaceCached##type(type##Cache *cache,type *value,index_t index,int fd,off_t offset);
+
+#define CACHE_INVALIDATECACHE_PROTO(type) static inline void Invalidate##type##Cache(type##Cache *cache);
+
+
+/* Macros for function definitions */
+
+/*+ A macro to create a function that creates a new cache data structure. +*/
+#define CACHE_NEWCACHE(type) \
+                             \
+static inline type##Cache *New##type##Cache(void)       \
+{                                                       \
+ type##Cache *cache;                                    \
+                                                        \
+ cache=(type##Cache*)malloc(sizeof(type##Cache));       \
+                                                        \
+ Invalidate##type##Cache(cache);                        \
+                                                        \
+ return(cache);                                         \
+}
+
+
+/*+ A macro to create a function that deletes a cache data structure. +*/
+#define CACHE_DELETECACHE(type) \
+                                \
+static inline void Delete##type##Cache(type##Cache *cache)      \
+{                                                               \
+ free(cache);                                                   \
+}
+
+
+/*+ A macro to create a function that fetches an item from a cache data structure or reads from file. +*/
+#define CACHE_FETCHCACHE(type) \
+                               \
+static inline type *FetchCached##type(type##Cache *cache,index_t index,int fd,off_t offset) \
+{                                                                                           \
+ int row=index%CACHEWIDTH;                                                                  \
+ int col;                                                                                   \
+                                                                                            \
+ for(col=0;col<CACHEDEPTH;col++)                                                            \
+    if(cache->indices[row][col]==index)                                                     \
+       return(&cache->data[row][col]);                                                      \
+                                                                                            \
+ col=cache->first[row];                                                                     \
+                                                                                            \
+ cache->first[row]=(cache->first[row]+1)%CACHEDEPTH;                                        \
+                                                                                            \
+ SlimFetch(fd,&cache->data[row][col],sizeof(type),offset+(off_t)index*sizeof(type));        \
+                                                                                            \
+ cache->indices[row][col]=index;                                                            \
+                                                                                            \
+ return(&cache->data[row][col]);                                                            \
+}
+
+
+/*+ A macro to create a function that replaces an item in a cache data structure and writes to file. +*/
+#define CACHE_REPLACECACHE(type) \
+                                 \
+static inline void ReplaceCached##type(type##Cache *cache,type *value,index_t index,int fd,off_t offset) \
+{                                                                                                        \
+ int row=index%CACHEWIDTH;                                                                               \
+ int col;                                                                                                \
+                                                                                                         \
+ for(col=0;col<CACHEDEPTH;col++)                                                                         \
+    if(cache->indices[row][col]==index)                                                                  \
+       break;                                                                                            \
+                                                                                                         \
+ if(col==CACHEDEPTH)                                                                                     \
+   {                                                                                                     \
+    col=cache->first[row];                                                                               \
+                                                                                                         \
+    cache->first[row]=(cache->first[row]+1)%CACHEDEPTH;                                                  \
+   }                                                                                                     \
+                                                                                                         \
+ cache->indices[row][col]=index;                                                                         \
+                                                                                                         \
+ cache->data[row][col]=*value;                                                                           \
+                                                                                                         \
+ SlimReplace(fd,&cache->data[row][col],sizeof(type),offset+(off_t)index*sizeof(type));                   \
+}
+
+
+/*+ A macro to create a function that invalidates the contents of a cache data structure. +*/
+#define CACHE_INVALIDATECACHE(type) \
+                                    \
+static inline void Invalidate##type##Cache(type##Cache *cache) \
+{                                                              \
+ int row,col;                                                  \
+                                                               \
+ for(row=0;row<CACHEWIDTH;row++)                               \
+   {                                                           \
+    cache->first[row]=0;                                       \
+                                                               \
+    for(col=0;col<CACHEDEPTH;col++)                            \
+       cache->indices[row][col]=NO_NODE;                       \
+   }                                                           \
+}
+
+
+/*+ Cache data structure forward declarations (for planetsplitter). +*/
+CACHE_STRUCTURE_FWD(NodeX)
+CACHE_STRUCTURE_FWD(SegmentX)
+CACHE_STRUCTURE_FWD(WayX)
+
+/*+ Cache data structure forward declarations (for router). +*/
+CACHE_STRUCTURE_FWD(Node)
+CACHE_STRUCTURE_FWD(Segment)
+CACHE_STRUCTURE_FWD(Way)
+CACHE_STRUCTURE_FWD(TurnRelation)
+
+
+#endif /* CACHE_H */
+
+#endif  /* SLIM */
diff --git a/3rdparty/Routino/src/errorlog.c b/3rdparty/Routino/src/errorlog.c
new file mode 100644
index 0000000..8c574dc
--- /dev/null
+++ b/3rdparty/Routino/src/errorlog.c
@@ -0,0 +1,178 @@
+/***************************************
+ Error log data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2013 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "types.h"
+#include "errorlog.h"
+
+#include "files.h"
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Load in an error log list from a file.
+
+  ErrorLogs *LoadErrorLogs Returns the error log list.
+
+  const char *filename The name of the file to load.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+ErrorLogs *LoadErrorLogs(const char *filename)
+{
+ ErrorLogs *errorlogs;
+
+ errorlogs=(ErrorLogs*)malloc(sizeof(ErrorLogs));
+
+#if !SLIM
+
+ errorlogs->data=MapFile(filename);
+
+ /* Copy the ErrorLogsFile header structure from the loaded data */
+
+ errorlogs->file=*((ErrorLogsFile*)errorlogs->data);
+
+ /* Set the pointers in the ErrorLogs structure. */
+
+ errorlogs->offsets         =(index_t* )(errorlogs->data+sizeof(ErrorLogsFile));
+ errorlogs->errorlogs_geo   =(ErrorLog*)(errorlogs->data+sizeof(ErrorLogsFile)+(errorlogs->file.latbins*errorlogs->file.lonbins+1)*sizeof(index_t));
+ errorlogs->errorlogs_nongeo=(ErrorLog*)(errorlogs->data+sizeof(ErrorLogsFile)+(errorlogs->file.latbins*errorlogs->file.lonbins+1)*sizeof(index_t)+errorlogs->file.number_geo*sizeof(ErrorLog));
+ errorlogs->strings         =(char*    )(errorlogs->data+sizeof(ErrorLogsFile)+(errorlogs->file.latbins*errorlogs->file.lonbins+1)*sizeof(index_t)+errorlogs->file.number*sizeof(ErrorLog));
+
+#else
+
+ errorlogs->fd=SlimMapFile(filename);
+
+ /* Copy the ErrorLogsFile header structure from the loaded data */
+
+ SlimFetch(errorlogs->fd,&errorlogs->file,sizeof(ErrorLogsFile),0);
+
+ errorlogs->offsetsoffset         =sizeof(ErrorLogsFile);
+ errorlogs->errorlogsoffset_geo   =sizeof(ErrorLogsFile)+(errorlogs->file.latbins*errorlogs->file.lonbins+1)*sizeof(index_t);
+ errorlogs->errorlogsoffset_nongeo=sizeof(ErrorLogsFile)+(errorlogs->file.latbins*errorlogs->file.lonbins+1)*sizeof(index_t)+errorlogs->file.number_geo*sizeof(ErrorLog);
+ errorlogs->stringsoffset         =sizeof(ErrorLogsFile)+(errorlogs->file.latbins*errorlogs->file.lonbins+1)*sizeof(index_t)+errorlogs->file.number*sizeof(ErrorLog);
+
+#endif
+
+ return(errorlogs);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Destroy the node list.
+
+  ErrorLogs *errorlogs The node list to destroy.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void DestroyErrorLogs(ErrorLogs *errorlogs)
+{
+#if !SLIM
+
+ errorlogs->data=UnmapFile(errorlogs->data);
+
+#else
+
+ errorlogs->fd=SlimUnmapFile(errorlogs->fd);
+
+#endif
+
+ free(errorlogs);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Get the latitude and longitude associated with an error log.
+
+  ErrorLogs *errorlogs The set of error logs to use.
+
+  index_t index The errorlog index.
+
+  ErrorLog *errorlogp A pointer to the error log.
+
+  double *latitude Returns the latitude.
+
+  double *longitude Returns the logitude.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void GetErrorLogLatLong(ErrorLogs *errorlogs,index_t index,ErrorLog *errorlogp,double *latitude,double *longitude)
+{
+ ll_bin_t latbin,lonbin;
+ ll_bin2_t bin=-1;
+ ll_bin2_t start,end,mid;
+ index_t offset;
+
+ /* Binary search - search key nearest match below is required.
+  *
+  *  # <- start  |  Check mid and move start or end if it doesn't match
+  *  #           |
+  *  #           |  A lower bound match is wanted we can set end=mid-1 or
+  *  # <- mid    |  start=mid because we know that mid doesn't match.
+  *  #           |
+  *  #           |  Eventually either end=start or end=start+1 and one of
+  *  # <- end    |  start or end is the wanted one.
+  */
+
+ /* Search for offset */
+
+ start=0;
+ end=errorlogs->file.lonbins*errorlogs->file.latbins;
+
+ do
+   {
+    mid=(start+end)/2;                  /* Choose mid point */
+
+    offset=LookupErrorLogOffset(errorlogs,mid);
+
+    if(offset<index)                    /* Mid point is too low for an exact match but could be lower bound */
+       start=mid;
+    else if(offset>index)               /* Mid point is too high */
+       end=mid?(mid-1):mid;
+    else                                /* Mid point is correct */
+      {bin=mid;break;}
+   }
+ while((end-start)>1);
+
+ if(bin==-1)
+   {
+    offset=LookupErrorLogOffset(errorlogs,end);
+
+    if(offset>index)
+       bin=start;
+    else
+       bin=end;
+   }
+
+ while(bin<=(errorlogs->file.lonbins*errorlogs->file.latbins) && 
+       LookupErrorLogOffset(errorlogs,bin)==LookupErrorLogOffset(errorlogs,bin+1))
+    bin++;
+
+ latbin=bin%errorlogs->file.latbins;
+ lonbin=bin/errorlogs->file.latbins;
+
+ /* Return the values */
+
+ if(errorlogp==NULL)
+    errorlogp=LookupErrorLog(errorlogs,index,2);
+
+ *latitude =latlong_to_radians(bin_to_latlong(errorlogs->file.latzero+latbin)+off_to_latlong(errorlogp->latoffset));
+ *longitude=latlong_to_radians(bin_to_latlong(errorlogs->file.lonzero+lonbin)+off_to_latlong(errorlogp->lonoffset));
+}
diff --git a/3rdparty/Routino/src/errorlog.h b/3rdparty/Routino/src/errorlog.h
new file mode 100644
index 0000000..df32e63
--- /dev/null
+++ b/3rdparty/Routino/src/errorlog.h
@@ -0,0 +1,195 @@
+/***************************************
+ Header file for error log file data types and associated function prototypes.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2013-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef ERRORLOG_H
+#define ERRORLOG_H    /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "types.h"
+#include "typesx.h"
+
+#include "files.h"
+
+
+/*+ A structure containing information for an error message in the file. +*/
+typedef struct _ErrorLog
+{
+ ll_off_t  latoffset;        /*+ The error message latitude offset within its bin. +*/
+ ll_off_t  lonoffset;        /*+ The error message longitude offset within its bin. +*/
+
+ uint32_t  offset;           /*+ The offset of the error message from the beginning of the text section. +*/
+ uint32_t  length;           /*+ The length of the error message in the text section. +*/
+}
+ ErrorLog;
+
+
+/*+ A structure containing the header from the error log file. +*/
+typedef struct _ErrorLogsFile
+{
+ index_t  number;               /*+ The total number of error messages. +*/
+ index_t  number_geo;           /*+ The number of error messages with a geographical location. +*/
+ index_t  number_nongeo;        /*+ The number of error messages without a geographical location. +*/
+
+ ll_bin_t latbins;              /*+ The number of bins containing latitude. +*/
+ ll_bin_t lonbins;              /*+ The number of bins containing longitude. +*/
+
+ ll_bin_t latzero;              /*+ The bin number of the furthest south bin. +*/
+ ll_bin_t lonzero;              /*+ The bin number of the furthest west bin. +*/
+}
+ ErrorLogsFile;
+
+
+/*+ A structure containing a set of error log messages read from the file. +*/
+typedef struct _ErrorLogs
+{
+ ErrorLogsFile file;            /*+ The header data from the file. +*/
+
+#if !SLIM
+
+ char     *data;                /*+ The memory mapped data in the file. +*/
+
+ index_t  *offsets;             /*+ A pointer to the array of offsets in the file. +*/
+
+ ErrorLog *errorlogs_geo;       /*+ A pointer to the array of geographical error logs in the file. +*/
+ ErrorLog *errorlogs_nongeo;    /*+ A pointer to the array of non-geographical error logs in the file. +*/
+
+ char     *strings;             /*+ A pointer to the array of error strings in the file. +*/
+
+#else
+
+ int       fd;                  /*+ The file descriptor for the file. +*/
+
+ off_t     offsetsoffset;       /*+ An allocated array with a copy of the file offsets. +*/
+
+ off_t     errorlogsoffset_geo;    /*+ The offset of the geographical error logs within the file. +*/
+ off_t     errorlogsoffset_nongeo; /*+ The offset of the non-geographical error logs within the file. +*/
+
+ off_t     stringsoffset;       /*+ The offset of the error strings within the file. +*/
+
+ ErrorLog  cached[2];           /*+ Some cached error logs read from the file in slim mode. +*/
+
+ char      cachestring[1024];   /*+ A cached copy of the error string read from the file in slim mode. +*/
+
+#endif
+}
+ ErrorLogs;
+
+
+/* Error log functions in errorlog.c */
+
+ErrorLogs *LoadErrorLogs(const char *filename);
+
+void DestroyErrorLogs(ErrorLogs *errorlogs);
+
+void GetErrorLogLatLong(ErrorLogs *errorlogs,index_t index,ErrorLog *errorlogp,double *latitude,double *longitude);
+
+
+/* Macros and inline functions */
+
+#if !SLIM
+
+/*+ Return an ErrorLog pointer given a set of errorlogs and an index. +*/
+#define LookupErrorLog(xxx,yyy,ppp)     (&(xxx)->errorlogs_geo[yyy])
+
+/*+ Return the offset of a geographical region given a set of errorlogs. +*/
+#define LookupErrorLogOffset(xxx,yyy)   ((xxx)->offsets[yyy])
+
+/*+ Return the string for an error log. +*/
+#define LookupErrorLogString(xxx,yyy)   (&(xxx)->strings[(xxx)->errorlogs_geo[yyy].offset])
+
+#else
+
+/* Prototypes */
+
+static inline ErrorLog *LookupErrorLog(ErrorLogs *errorlogs,index_t index,int position);
+
+static inline index_t LookupErrorLogOffset(ErrorLogs *errorlogs,index_t index);
+
+static inline char *LookupErrorLogString(ErrorLogs *errorlogs,index_t index);
+
+/* Inline functions */
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the ErrorLog information for a particular error log.
+
+  ErrorLog *LookupErrorLog Returns a pointer to the cached error log information.
+
+  ErrorLogs *errorlogs The set of errorlogs to use.
+
+  index_t index The index of the error log.
+
+  int position The position in the cache to store the value.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline ErrorLog *LookupErrorLog(ErrorLogs *errorlogs,index_t index,int position)
+{
+ SlimFetch(errorlogs->fd,&errorlogs->cached[position-1],sizeof(ErrorLog),errorlogs->errorlogsoffset_geo+(off_t)index*sizeof(ErrorLog));
+
+ return(&errorlogs->cached[position-1]);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the offset of error logs in a geographical region.
+
+  index_t LookupErrorLogOffset Returns the index offset.
+
+  ErrorLogs *errorlogs The set of error logs to use.
+
+  index_t index The index of the offset.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline index_t LookupErrorLogOffset(ErrorLogs *errorlogs,index_t index)
+{
+ index_t offset;
+
+ SlimFetch(errorlogs->fd,&offset,sizeof(index_t),errorlogs->offsetsoffset+(off_t)index*sizeof(index_t));
+
+ return(offset);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the string associated with a particular error log.
+
+  char *LookupErrorLogString Returns the error string.
+
+  ErrorLogs *errorlogs The set of error logs to use.
+
+  index_t index The index of the string.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline char *LookupErrorLogString(ErrorLogs *errorlogs,index_t index)
+{
+ ErrorLog *errorlog=LookupErrorLog(errorlogs,index,2);
+
+ SlimFetch(errorlogs->fd,errorlogs->cachestring,errorlog->length,errorlogs->stringsoffset+errorlog->offset);
+
+ return(errorlogs->cachestring);
+}
+
+#endif
+
+
+#endif /* ERRORLOG_H */
diff --git a/3rdparty/Routino/src/errorlogx.c b/3rdparty/Routino/src/errorlogx.c
new file mode 100644
index 0000000..7842a26
--- /dev/null
+++ b/3rdparty/Routino/src/errorlogx.c
@@ -0,0 +1,981 @@
+/***************************************
+ Error log processing functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2013-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include "typesx.h"
+#include "nodesx.h"
+#include "waysx.h"
+#include "relationsx.h"
+
+#include "errorlogx.h"
+#include "errorlog.h"
+
+#include "files.h"
+#include "sorting.h"
+
+
+/* Global variables */
+
+/*+ The name of the error log file. +*/
+extern char *errorlogfilename;
+
+/*+ The name of the binary error log file. +*/
+extern char *errorbinfilename;
+
+/* Local variables */
+
+/*+ Temporary file-local variables for use by the sort functions (re-initialised for each sort). +*/
+static latlong_t lat_min,lat_max,lon_min,lon_max;
+
+/* Local functions */
+
+static void reindex_nodes(NodesX *nodesx);
+static void reindex_ways(WaysX *waysx);
+static void reindex_relations(RelationsX *relationsx);
+
+static int lookup_lat_long_node(NodesX *nodesx,node_t node,latlong_t *latitude,latlong_t *longitude);
+static int lookup_lat_long_way(WaysX *waysx,NodesX *nodesx,way_t way,latlong_t *latitude,latlong_t *longitude,index_t error);
+static int lookup_lat_long_relation(RelationsX *relationsx,WaysX *waysx,NodesX *nodesx,relation_t relation,latlong_t *latitude,latlong_t *longitude,index_t error);
+
+static int sort_by_lat_long(ErrorLogX *a,ErrorLogX *b);
+static int measure_lat_long(ErrorLogX *errorlogx,index_t index);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Allocate a new error log list (create a new file).
+
+  ErrorLogsX *NewErrorLogList Returns a pointer to the error log list.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+ErrorLogsX *NewErrorLogList(void)
+{
+ ErrorLogsX *errorlogsx;
+
+ errorlogsx=(ErrorLogsX*)calloc(1,sizeof(ErrorLogsX));
+
+ logassert(errorlogsx,"Failed to allocate memory (try using slim mode?)"); /* Check calloc() worked */
+
+ return(errorlogsx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Free an error log list.
+
+  ErrorLogsX *errorlogsx The set of error logs to be freed.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FreeErrorLogList(ErrorLogsX *errorlogsx)
+{
+ free(errorlogsx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process the binary error log.
+
+  ErrorLogsX *errorlogsx The set of error logs to update.
+
+  NodesX *nodesx The set of nodes.
+
+  WaysX *waysx The set of ways.
+
+  RelationsX *relationsx The set of relations.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void ProcessErrorLogs(ErrorLogsX *errorlogsx,NodesX *nodesx,WaysX *waysx,RelationsX *relationsx)
+{
+ int oldfd,newfd;
+ uint32_t offset=0;
+ int nerrorlogobjects=0;
+ int finished;
+ ErrorLogObject errorlogobjects[8];
+
+ /* Re-index the nodes, ways and relations */
+
+ printf_first("Re-indexing the Data: Nodes=0 Ways=0 Route-Relations=0 Turn-Relations=0");
+
+ reindex_nodes(nodesx);
+
+ printf_middle("Re-indexing the Data: Nodes=%"Pindex_t" Ways=0 Route-Relations=0 Turn-Relations=0",nodesx->number);
+
+ reindex_ways(waysx);
+
+ printf_middle("Re-indexing the Data: Nodes=%"Pindex_t" Ways=%"Pindex_t" Route-Relations=0 Turn-Relations=0",nodesx->number,waysx->number);
+
+ reindex_relations(relationsx);
+
+ printf_last("Re-indexed the Data: Nodes=%"Pindex_t" Ways=%"Pindex_t" Route-Relations=%"Pindex_t" Turn-Relations=%"Pindex_t,nodesx->number,waysx->number,relationsx->rrnumber,relationsx->trnumber);
+
+
+ /* Print the start message */
+
+ printf_first("Calculating Coordinates: Errors=0");
+
+ /* Map into memory / open the files */
+
+#if !SLIM
+ nodesx->data=MapFile(nodesx->filename);
+#else
+ nodesx->fd=SlimMapFile(nodesx->filename);
+
+ InvalidateNodeXCache(nodesx->cache);
+#endif
+
+ waysx->fd=ReOpenFileBuffered(waysx->filename);
+ relationsx->rrfd=ReOpenFileBuffered(relationsx->rrfilename);
+ relationsx->trfd=ReOpenFileBuffered(relationsx->trfilename);
+
+ /* Open the binary log file read-only and a new file writeable */
+
+ newfd=ReplaceFileBuffered(errorbinfilename,&oldfd);
+
+ /* Loop through the file and merge the raw data into coordinates */
+
+ errorlogsx->number=0;
+
+ do
+   {
+    ErrorLogObject errorlogobject;
+
+    finished=ReadFileBuffered(oldfd,&errorlogobject,sizeof(ErrorLogObject));
+
+    if(finished)
+       errorlogobject.offset=SizeFile(errorlogfilename);
+
+    if(offset!=errorlogobject.offset)
+      {
+       ErrorLogX errorlogx;
+       latlong_t errorlat=NO_LATLONG,errorlon=NO_LATLONG;
+
+       /* Calculate suitable coordinates */
+
+       if(nerrorlogobjects==1)
+         {
+          if(errorlogobjects[0].type=='N')
+            {
+             node_t node=(node_t)errorlogobjects[0].id;
+
+             lookup_lat_long_node(nodesx,node,&errorlat,&errorlon);
+            }
+          else if(errorlogobjects[0].type=='W')
+            {
+             way_t way=(way_t)errorlogobjects[0].id;
+
+             lookup_lat_long_way(waysx,nodesx,way,&errorlat,&errorlon,errorlogsx->number);
+            }
+          else if(errorlogobjects[0].type=='R')
+            {
+             relation_t relation=(relation_t)errorlogobjects[0].type;
+
+             lookup_lat_long_relation(relationsx,waysx,nodesx,relation,&errorlat,&errorlon,errorlogsx->number);
+            }
+         }
+       else
+         {
+          latlong_t latitude[8],longitude[8];
+          int i;
+          int ncoords=0,nnodes=0,nways=0,nrelations=0;
+
+          for(i=0;i<nerrorlogobjects;i++)
+            {
+             if(errorlogobjects[i].type=='N')
+               {
+                node_t node=(node_t)errorlogobjects[i].id;
+
+                if(lookup_lat_long_node(nodesx,node,&latitude[ncoords],&longitude[ncoords]))
+                   ncoords++;
+
+                nnodes++;
+               }
+             else if(errorlogobjects[i].type=='W')
+                nways++;
+             else if(errorlogobjects[i].type=='R')
+                nrelations++;
+            }
+
+          if(nways==0 && nrelations==0) /* only nodes */
+             ;
+          else if(ncoords)      /* some good nodes, possibly ways and/or relations */
+             ;
+          else if(nways)        /* no good nodes, possibly some good ways */
+            {
+             for(i=0;i<nerrorlogobjects;i++)
+                if(errorlogobjects[i].type=='W')
+                  {
+                   way_t way=(way_t)errorlogobjects[i].id;
+
+                   if(lookup_lat_long_way(waysx,nodesx,way,&latitude[ncoords],&longitude[ncoords],errorlogsx->number))
+                      ncoords++;
+                  }
+            }
+
+          if(nrelations==0) /* only nodes and/or ways */
+             ;
+          else if(ncoords)  /* some good nodes and/or ways, possibly relations */
+             ;
+          else /* if(nrelations) */
+            {
+             for(i=0;i<nerrorlogobjects;i++)
+                if(errorlogobjects[i].type=='R')
+                  {
+                   relation_t relation=(relation_t)errorlogobjects[i].id;
+
+                   if(lookup_lat_long_relation(relationsx,waysx,nodesx,relation,&latitude[ncoords],&longitude[ncoords],errorlogsx->number))
+                      ncoords++;
+                  }
+            }
+
+          if(ncoords)
+            {
+             errorlat=0;
+             errorlon=0;
+
+             for(i=0;i<ncoords;i++)
+               {
+                errorlat+=latitude[i];
+                errorlon+=longitude[i];
+               }
+
+             errorlat/=ncoords;
+             errorlon/=ncoords;
+            }
+          else
+            {
+             errorlat=NO_LATLONG;
+             errorlon=NO_LATLONG;
+            }
+         }
+
+       /* Write to file */
+
+       errorlogx.offset=offset;
+       errorlogx.length=errorlogobject.offset-offset;
+
+       errorlogx.latitude =errorlat;
+       errorlogx.longitude=errorlon;
+
+       WriteFileBuffered(newfd,&errorlogx,sizeof(ErrorLogX));
+
+       errorlogsx->number++;
+
+       offset=errorlogobject.offset;
+       nerrorlogobjects=0;
+
+       if(!(errorlogsx->number%10000))
+          printf_middle("Calculating Coordinates: Errors=%"Pindex_t,errorlogsx->number);
+      }
+
+    /* Store for later */
+
+    logassert(nerrorlogobjects<8,"Too many error log objects for one error message."); /* Only a limited amount of information stored. */
+
+    errorlogobjects[nerrorlogobjects]=errorlogobject;
+
+    nerrorlogobjects++;
+   }
+ while(!finished);
+
+ /* Unmap from memory / close the files */
+
+#if !SLIM
+ nodesx->data=UnmapFile(nodesx->data);
+#else
+ nodesx->fd=SlimUnmapFile(nodesx->fd);
+#endif
+
+ waysx->fd=CloseFileBuffered(waysx->fd);
+ relationsx->rrfd=CloseFileBuffered(relationsx->rrfd);
+ relationsx->trfd=CloseFileBuffered(relationsx->trfd);
+
+ CloseFileBuffered(oldfd);
+ CloseFileBuffered(newfd);
+
+ /* Print the final message */
+
+ printf_last("Calculated Coordinates: Errors=%"Pindex_t,errorlogsx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Re-index the nodes that were kept.
+
+  NodesX *nodesx The set of nodes to process (contains the filename and number of nodes).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void reindex_nodes(NodesX *nodesx)
+{
+ int fd;
+ index_t index=0;
+ NodeX nodex;
+
+ nodesx->number=nodesx->knumber;
+
+ nodesx->idata=(node_t*)malloc(nodesx->number*sizeof(node_t));
+ log_malloc(nodesx->idata,nodesx->number*sizeof(node_t));
+
+ /* Get the node id for each node in the file. */
+
+ fd=ReOpenFileBuffered(nodesx->filename);
+
+ while(!ReadFileBuffered(fd,&nodex,sizeof(NodeX)))
+   {
+    nodesx->idata[index]=nodex.id;
+
+    index++;
+   }
+
+ CloseFileBuffered(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Re-index the ways that were kept.
+
+  WaysX *waysx The set of ways to process (contains the filename and number of ways).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void reindex_ways(WaysX *waysx)
+{
+ FILESORT_VARINT waysize;
+ int fd;
+ off_t position=0;
+ index_t index=0;
+
+ waysx->number=waysx->knumber;
+
+ waysx->idata=(way_t*)malloc(waysx->number*sizeof(way_t));
+ waysx->odata=(off_t*)malloc(waysx->number*sizeof(off_t));
+
+ log_malloc(waysx->idata,waysx->number*sizeof(way_t));
+ log_malloc(waysx->odata,waysx->number*sizeof(off_t));
+
+ /* Get the way id and the offset for each way in the file */
+
+ fd=ReOpenFileBuffered(waysx->filename);
+
+ while(!ReadFileBuffered(fd,&waysize,FILESORT_VARSIZE))
+   {
+    WayX wayx;
+
+    ReadFileBuffered(fd,&wayx,sizeof(WayX));
+
+    waysx->idata[index]=wayx.id;
+    waysx->odata[index]=position+FILESORT_VARSIZE+sizeof(WayX);
+
+    index++;
+
+    SkipFileBuffered(fd,waysize-sizeof(WayX));
+
+    position+=waysize+FILESORT_VARSIZE;
+   }
+
+ CloseFileBuffered(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Re-index the relations that were kept.
+
+  RelationsX *relationsx The set of relations to process (contains the filenames and numbers of relations).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void reindex_relations(RelationsX *relationsx)
+{
+ FILESORT_VARINT relationsize;
+ int fd;
+ off_t position=0;
+ index_t index;
+ TurnRelX turnrelx;
+
+ /* Route relations */
+
+ relationsx->rrnumber=relationsx->rrknumber;
+
+ relationsx->rridata=(relation_t*)malloc(relationsx->rrnumber*sizeof(relation_t));
+ relationsx->rrodata=(off_t*)malloc(relationsx->rrnumber*sizeof(off_t));
+
+ log_malloc(relationsx->rridata,relationsx->rrnumber*sizeof(relation_t));
+ log_malloc(relationsx->rrodata,relationsx->rrnumber*sizeof(off_t));
+
+ /* Get the relation id and the offset for each relation in the file */
+
+ fd=ReOpenFileBuffered(relationsx->rrfilename);
+
+ index=0;
+
+ while(!ReadFileBuffered(fd,&relationsize,FILESORT_VARSIZE))
+   {
+    RouteRelX routerelx;
+
+    ReadFileBuffered(fd,&routerelx,sizeof(RouteRelX));
+
+    relationsx->rridata[index]=routerelx.id;
+    relationsx->rrodata[index]=position+FILESORT_VARSIZE+sizeof(RouteRelX);
+
+    index++;
+
+    SkipFileBuffered(fd,relationsize-sizeof(RouteRelX));
+
+    position+=relationsize+FILESORT_VARSIZE;
+   }
+
+ CloseFileBuffered(fd);
+
+
+ /* Turn relations */
+
+ relationsx->trnumber=relationsx->trknumber;
+
+ relationsx->tridata=(relation_t*)malloc(relationsx->trnumber*sizeof(relation_t));
+
+ log_malloc(relationsx->tridata,relationsx->trnumber*sizeof(relation_t));
+
+ /* Get the relation id and the offset for each relation in the file */
+
+ fd=ReOpenFileBuffered(relationsx->trfilename);
+
+ index=0;
+
+ while(!ReadFileBuffered(fd,&turnrelx,sizeof(TurnRelX)))
+   {
+    relationsx->tridata[index]=turnrelx.id;
+
+    index++;
+   }
+
+ CloseFileBuffered(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Lookup a node's latitude and longitude.
+
+  int lookup_lat_long_node Returns 1 if a node was found.
+
+  NodesX *nodesx The set of nodes to use.
+
+  node_t node The node number.
+
+  latlong_t *latitude Returns the latitude.
+
+  latlong_t *longitude Returns the longitude.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int lookup_lat_long_node(NodesX *nodesx,node_t node,latlong_t *latitude,latlong_t *longitude)
+{
+ index_t index=IndexNodeX(nodesx,node);
+
+ if(index==NO_NODE)
+    return 0;
+ else
+   {
+    NodeX *nodex=LookupNodeX(nodesx,index,1);
+
+    *latitude =nodex->latitude;
+    *longitude=nodex->longitude;
+
+    return 1;
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Lookup a way's latitude and longitude.
+
+  int lookup_lat_long_way Returns 1 if a way was found.
+
+  WaysX *waysx The set of ways to use.
+
+  NodesX *nodesx The set of nodes to use.
+
+  way_t way The way number.
+
+  latlong_t *latitude Returns the latitude.
+
+  latlong_t *longitude Returns the longitude.
+
+  index_t error The index of the error in the complete set of errors.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int lookup_lat_long_way(WaysX *waysx,NodesX *nodesx,way_t way,latlong_t *latitude,latlong_t *longitude,index_t error)
+{
+ index_t index=IndexWayX(waysx,way);
+
+ if(index==NO_WAY)
+    return 0;
+ else
+   {
+    int count=1;
+    off_t offset=waysx->odata[index];
+    node_t node1,node2,prevnode,node;
+    latlong_t latitude1,longitude1,latitude2,longitude2;
+
+    SeekFileBuffered(waysx->fd,offset);
+
+    /* Choose a random pair of adjacent nodes */
+
+    if(ReadFileBuffered(waysx->fd,&node1,sizeof(node_t)) || node1==NO_NODE_ID)
+       return 0;
+
+    if(ReadFileBuffered(waysx->fd,&node2,sizeof(node_t)) || node2==NO_NODE_ID)
+       return lookup_lat_long_node(nodesx,node1,latitude,longitude);
+
+    prevnode=node2;
+
+    while(!ReadFileBuffered(waysx->fd,&node,sizeof(node_t)) && node!=NO_NODE_ID)
+      {
+       count++;
+
+       if((error%count)==0)     /* A 1/count chance */
+         {
+          node1=prevnode;
+          node2=node;
+         }
+
+       prevnode=node;
+      }
+
+    if(!lookup_lat_long_node(nodesx,node1,&latitude1,&longitude1))
+       return lookup_lat_long_node(nodesx,node2,latitude,longitude);
+
+    if(!lookup_lat_long_node(nodesx,node2,&latitude2,&longitude2))
+       return lookup_lat_long_node(nodesx,node1,latitude,longitude);
+
+    *latitude =(latitude1 +latitude2 )/2;
+    *longitude=(longitude1+longitude2)/2;
+
+    return 1;
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Lookup a relation's latitude and longitude.
+
+  int lookup_lat_long_relation Returns 1 if a relation was found.
+
+  RelationsX *relationsx The set of relations to use.
+
+  WaysX *waysx The set of ways to use.
+
+  NodesX *nodesx The set of nodes to use.
+
+  relation_t relation The relation number.
+
+  latlong_t *latitude Returns the latitude.
+
+  latlong_t *longitude Returns the longitude.
+
+  index_t error The index of the error in the complete set of errors.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int lookup_lat_long_relation(RelationsX *relationsx,WaysX *waysx,NodesX *nodesx,relation_t relation,latlong_t *latitude,latlong_t *longitude,index_t error)
+{
+ index_t index=IndexRouteRelX(relationsx,relation);
+
+ if(index==NO_RELATION)
+   {
+    index=IndexTurnRelX(relationsx,relation);
+
+    if(index==NO_RELATION)
+       return 0;
+    else
+      {
+       TurnRelX turnrelx;
+
+       SeekFileBuffered(relationsx->trfd,index*sizeof(TurnRelX));
+       ReadFileBuffered(relationsx->trfd,&turnrelx,sizeof(TurnRelX));
+
+       if(lookup_lat_long_node(nodesx,turnrelx.via,latitude,longitude))
+          return 1;
+
+       if(lookup_lat_long_way(waysx,nodesx,turnrelx.from,latitude,longitude,error))
+          return 1;
+
+       if(lookup_lat_long_way(waysx,nodesx,turnrelx.to,latitude,longitude,error))
+          return 1;
+
+       return 0;
+      }
+   }
+ else
+   {
+    int count;
+    off_t offset=relationsx->rrodata[index];
+    node_t node=NO_NODE_ID,tempnode;
+    way_t way=NO_WAY_ID,tempway;
+    relation_t relation=NO_RELATION_ID,temprelation;
+
+    SeekFileBuffered(relationsx->rrfd,offset);
+
+    /* Choose a random node */
+
+    count=0;
+
+    while(!ReadFileBuffered(relationsx->rrfd,&tempnode,sizeof(node_t)) && tempnode!=NO_NODE_ID)
+      {
+       count++;
+
+       if((error%count)==0)     /* A 1/count chance */
+          node=tempnode;
+      }
+
+    if(lookup_lat_long_node(nodesx,node,latitude,longitude))
+       return 1;
+
+    /* Choose a random way */
+
+    count=0;
+
+    while(!ReadFileBuffered(relationsx->rrfd,&tempway,sizeof(way_t)) && tempway!=NO_WAY_ID)
+      {
+       count++;
+
+       if((error%count)==0)     /* A 1/count chance */
+          way=tempway;
+      }
+
+    if(lookup_lat_long_way(waysx,nodesx,way,latitude,longitude,error))
+       return 1;
+
+    /* Choose a random relation */
+
+    count=0;
+
+    while(!ReadFileBuffered(relationsx->rrfd,&temprelation,sizeof(relation_t)) && temprelation!=NO_RELATION_ID)
+      {
+       count++;
+
+       if((error%count)==0)     /* A 1/count chance */
+          relation=temprelation;
+      }
+
+    return lookup_lat_long_relation(relationsx,waysx,nodesx,relation,latitude,longitude,error);
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the error logs geographically.
+
+  ErrorLogsX *errorlogsx The set of error logs to sort.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SortErrorLogsGeographically(ErrorLogsX *errorlogsx)
+{
+ int oldfd,newfd;
+ ll_bin_t lat_min_bin,lat_max_bin,lon_min_bin,lon_max_bin;
+
+ /* Print the start message */
+
+ printf_first("Sorting Errors Geographically");
+
+ /* Work out the range of data */
+
+ lat_min=radians_to_latlong( 2);
+ lat_max=radians_to_latlong(-2);
+ lon_min=radians_to_latlong( 4);
+ lon_max=radians_to_latlong(-4);
+
+ /* Re-open the file read-only and a new file writeable */
+
+ newfd=ReplaceFileBuffered(errorbinfilename,&oldfd);
+
+ /* Sort errors geographically */
+
+ filesort_fixed(oldfd,newfd,sizeof(ErrorLogX),NULL,
+                                              (int (*)(const void*,const void*))sort_by_lat_long,
+                                              (int (*)(void*,index_t))measure_lat_long);
+
+ /* Close the files */
+
+ CloseFileBuffered(oldfd);
+ CloseFileBuffered(newfd);
+
+ /* Work out the number of bins */
+
+ lat_min_bin=latlong_to_bin(lat_min);
+ lon_min_bin=latlong_to_bin(lon_min);
+ lat_max_bin=latlong_to_bin(lat_max);
+ lon_max_bin=latlong_to_bin(lon_max);
+
+ errorlogsx->latzero=lat_min_bin;
+ errorlogsx->lonzero=lon_min_bin;
+
+ errorlogsx->latbins=(lat_max_bin-lat_min_bin)+1;
+ errorlogsx->lonbins=(lon_max_bin-lon_min_bin)+1;
+
+ /* Print the final message */
+
+ printf_last("Sorted Errors Geographically: Errors=%"Pindex_t,errorlogsx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the errors into latitude and longitude order (first by longitude bin
+  number, then by latitude bin number and then by exact longitude and then by
+  exact latitude).
+
+  int sort_by_lat_long Returns the comparison of the latitude and longitude fields.
+
+  ErrorLogX *a The first error location.
+
+  ErrorLogX *b The second error location.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int sort_by_lat_long(ErrorLogX *a,ErrorLogX *b)
+{
+ ll_bin_t a_lon=latlong_to_bin(a->longitude);
+ ll_bin_t b_lon=latlong_to_bin(b->longitude);
+
+ if(a_lon<b_lon)
+    return(-1);
+ else if(a_lon>b_lon)
+    return(1);
+ else
+   {
+    ll_bin_t a_lat=latlong_to_bin(a->latitude);
+    ll_bin_t b_lat=latlong_to_bin(b->latitude);
+
+    if(a_lat<b_lat)
+       return(-1);
+    else if(a_lat>b_lat)
+       return(1);
+    else
+      {
+       if(a->longitude<b->longitude)
+          return(-1);
+       else if(a->longitude>b->longitude)
+          return(1);
+       else
+         {
+          if(a->latitude<b->latitude)
+             return(-1);
+          else if(a->latitude>b->latitude)
+             return(1);
+         }
+
+       return(FILESORT_PRESERVE_ORDER(a,b));
+      }
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Measure the extent of the data.
+
+  int measure_lat_long Return 1 if the value is to be kept, otherwise 0.
+
+  ErrorLogX *errorlogx The error location.
+
+  index_t index The number of sorted error locations that have already been written to the output file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int measure_lat_long(ErrorLogX *errorlogx,index_t index)
+{
+ if(errorlogx->latitude!=NO_LATLONG)
+   {
+    if(errorlogx->latitude<lat_min)
+       lat_min=errorlogx->latitude;
+    if(errorlogx->latitude>lat_max)
+       lat_max=errorlogx->latitude;
+    if(errorlogx->longitude<lon_min)
+       lon_min=errorlogx->longitude;
+    if(errorlogx->longitude>lon_max)
+       lon_max=errorlogx->longitude;
+   }
+
+ return(1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Save the binary error log.
+
+  ErrorLogsX *errorlogsx The set of error logs to write.
+
+  char *filename The name of the final file to write.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SaveErrorLogs(ErrorLogsX *errorlogsx,char *filename)
+{
+ ErrorLogsFile errorlogsfile;
+ ErrorLogX errorlogx;
+ int oldfd,newfd;
+ ll_bin2_t latlonbin=0,maxlatlonbins;
+ index_t *offsets;
+ index_t number=0,number_geo=0,number_nongeo=0;
+ off_t size;
+
+ /* Print the start message */
+
+ printf_first("Writing Errors: Geographical=0 Non-geographical=0");
+
+ /* Allocate the memory for the geographical offsets array */
+
+ offsets=(index_t*)malloc((errorlogsx->latbins*errorlogsx->lonbins+1)*sizeof(index_t));
+
+ logassert(offsets,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
+
+ latlonbin=0;
+
+ /* Re-open the file */
+
+ oldfd=ReOpenFileBuffered(errorbinfilename);
+
+ newfd=OpenFileBufferedNew(filename);
+
+ /* Write out the geographical errors */
+
+ SeekFileBuffered(newfd,sizeof(ErrorLogsFile)+(errorlogsx->latbins*errorlogsx->lonbins+1)*sizeof(index_t));
+
+ while(!ReadFileBuffered(oldfd,&errorlogx,sizeof(ErrorLogX)))
+   {
+    ErrorLog errorlog={0};
+    ll_bin_t latbin,lonbin;
+    ll_bin2_t llbin;
+
+    if(errorlogx.latitude==NO_LATLONG)
+       continue;
+
+    /* Create the ErrorLog */
+
+    errorlog.latoffset=latlong_to_off(errorlogx.latitude);
+    errorlog.lonoffset=latlong_to_off(errorlogx.longitude);
+
+    errorlog.offset=errorlogx.offset;
+    errorlog.length=errorlogx.length;
+
+    /* Work out the offsets */
+
+    latbin=latlong_to_bin(errorlogx.latitude )-errorlogsx->latzero;
+    lonbin=latlong_to_bin(errorlogx.longitude)-errorlogsx->lonzero;
+    llbin=lonbin*errorlogsx->latbins+latbin;
+
+    for(;latlonbin<=llbin;latlonbin++)
+       offsets[latlonbin]=number_geo;
+
+    /* Write the data */
+
+    WriteFileBuffered(newfd,&errorlog,sizeof(ErrorLog));
+
+    number_geo++;
+    number++;
+
+    if(!(number%10000))
+       printf_middle("Writing Errors: Geographical=%"Pindex_t" Non-geographical=%"Pindex_t,number_geo,number_nongeo);
+   }
+
+ /* Write out the non-geographical errors */
+
+ SeekFileBuffered(oldfd,0);
+
+ while(!ReadFileBuffered(oldfd,&errorlogx,sizeof(ErrorLogX)))
+   {
+    ErrorLog errorlog={0};
+
+    if(errorlogx.latitude!=NO_LATLONG)
+       continue;
+
+    /* Create the ErrorLog */
+
+    errorlog.latoffset=0;
+    errorlog.lonoffset=0;
+
+    errorlog.offset=errorlogx.offset;
+    errorlog.length=errorlogx.length;
+
+    /* Write the data */
+
+    WriteFileBuffered(newfd,&errorlog,sizeof(ErrorLog));
+
+    number_nongeo++;
+    number++;
+
+    if(!(number%10000))
+       printf_middle("Writing Errors: Geographical=%"Pindex_t" Non-geographical=%"Pindex_t,number_geo,number_nongeo);
+   }
+
+ /* Close the input file */
+
+ CloseFileBuffered(oldfd);
+
+ DeleteFile(errorbinfilename);
+
+ /* Append the text from the log file */
+
+ size=SizeFile(errorlogfilename);
+
+ oldfd=ReOpenFileBuffered(errorlogfilename);
+
+ while(size)
+   {
+    int i;
+    char buffer[4096];
+    off_t chunksize=(size>(off_t)sizeof(buffer)?(off_t)sizeof(buffer):size);
+
+    ReadFileBuffered(oldfd,buffer,chunksize);
+
+    for(i=0;i<chunksize;i++)
+       if(buffer[i]=='\n')
+          buffer[i]=0;
+
+    WriteFileBuffered(newfd,buffer,chunksize);
+
+    size-=chunksize;
+   }
+
+ CloseFileBuffered(oldfd);
+
+ /* Finish off the offset indexing and write them out */
+
+ maxlatlonbins=errorlogsx->latbins*errorlogsx->lonbins;
+
+ for(;latlonbin<=maxlatlonbins;latlonbin++)
+    offsets[latlonbin]=number_geo;
+
+ SeekFileBuffered(newfd,sizeof(ErrorLogsFile));
+ WriteFileBuffered(newfd,offsets,(errorlogsx->latbins*errorlogsx->lonbins+1)*sizeof(index_t));
+
+ free(offsets);
+
+ /* Write out the header structure */
+
+ errorlogsfile.number       =number;
+ errorlogsfile.number_geo   =number_geo;
+ errorlogsfile.number_nongeo=number_nongeo;
+
+ errorlogsfile.latbins=errorlogsx->latbins;
+ errorlogsfile.lonbins=errorlogsx->lonbins;
+
+ errorlogsfile.latzero=errorlogsx->latzero;
+ errorlogsfile.lonzero=errorlogsx->lonzero;
+
+ SeekFileBuffered(newfd,0);
+ WriteFileBuffered(newfd,&errorlogsfile,sizeof(ErrorLogsFile));
+
+ CloseFileBuffered(newfd);
+
+ /* Print the final message */
+
+ printf_last("Wrote Errors: Geographical=%"Pindex_t" Non-geographical=%"Pindex_t,number_geo,number_nongeo);
+}
diff --git a/3rdparty/Routino/src/errorlogx.h b/3rdparty/Routino/src/errorlogx.h
new file mode 100644
index 0000000..21bbf6e
--- /dev/null
+++ b/3rdparty/Routino/src/errorlogx.h
@@ -0,0 +1,70 @@
+/***************************************
+ Header file for error log file data types and processing function prototypes.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2013 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef ERRORLOGX_H
+#define ERRORLOGX_H    /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+
+#include "types.h"
+#include "typesx.h"
+
+
+/*+ A structure containing information for an error message during processing. +*/
+typedef struct _ErrorLogX
+{
+ latlong_t latitude;         /*+ The error message latitude. +*/
+ latlong_t longitude;        /*+ The error message longitude. +*/
+
+ uint32_t  offset;           /*+ The offset of the error message from the beginning of the text file. +*/
+ uint32_t  length;           /*+ The length of the error message in the text file. +*/
+}
+ ErrorLogX;
+
+
+/*+ A structure containing a set of error logs (memory format). +*/
+typedef struct _ErrorLogsX
+{
+ index_t   number;              /*+ The number of error logs. +*/
+
+ index_t   latbins;             /*+ The number of bins containing latitude. +*/
+ index_t   lonbins;             /*+ The number of bins containing longitude. +*/
+
+ ll_bin_t  latzero;             /*+ The bin number of the furthest south bin. +*/
+ ll_bin_t  lonzero;             /*+ The bin number of the furthest west bin. +*/
+}
+ ErrorLogsX;
+
+
+/* Error log processing functions in errorlogx.c */
+
+ErrorLogsX *NewErrorLogList(void);
+void FreeErrorLogList(ErrorLogsX *errorlogsx);
+
+void ProcessErrorLogs(ErrorLogsX *errorlogsx,NodesX *nodesx,WaysX *waysx,RelationsX *relationsx);
+
+void SortErrorLogsGeographically(ErrorLogsX *errorlogsx);
+
+void SaveErrorLogs(ErrorLogsX *errorlogsx,char *filename);
+
+
+#endif /* ERRORLOGX_H */
diff --git a/3rdparty/Routino/src/fakes.c b/3rdparty/Routino/src/fakes.c
new file mode 100644
index 0000000..625b445
--- /dev/null
+++ b/3rdparty/Routino/src/fakes.c
@@ -0,0 +1,415 @@
+/***************************************
+ Fake node and segment generation.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include "types.h"
+#include "nodes.h"
+#include "segments.h"
+
+#include "fakes.h"
+
+
+/*+ The minimum distance along a segment from a node to insert a fake node. (in km). +*/
+#define MINSEGMENT 0.005
+
+
+/* Local variables (re-initialised by DeleteFakeNodes() function) */
+
+/*+ A set of fake segments to allow start/finish in the middle of a segment. +*/
+static Segment fake_segments[4*NWAYPOINTS+1];
+
+/*+ A set of pointers to the real segments underlying the fake segments. +*/
+static index_t real_segments[4*NWAYPOINTS+1];
+
+/*+ A set of fake node latitudes and longitudes. +*/
+static double fake_lon[NWAYPOINTS+1],fake_lat[NWAYPOINTS+1];
+
+/*+ The previous waypoint. +*/
+static int prevpoint=0;
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create a pair of fake segments corresponding to the given segment split in two
+  (and will create an extra two fake segments if adjacent waypoints are on the
+  same segment).
+
+  index_t CreateFakes Returns the fake node index (or a real one in special cases).
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  int point Which of the waypoints this is.
+
+  Segment *segmentp The segment to split.
+
+  index_t node1 The first node at the end of this segment.
+
+  index_t node2 The second node at the end of this segment.
+
+  distance_t dist1 The distance to the first node.
+
+  distance_t dist2 The distance to the second node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t CreateFakes(Nodes *nodes,Segments *segments,int point,Segment *segmentp,index_t node1,index_t node2,distance_t dist1,distance_t dist2)
+{
+ index_t fakenode;
+ double lat1,lon1,lat2,lon2;
+
+ /* Initialise all the connecting segments to fake values */
+
+ fake_segments[4*point-4].node1=NO_NODE;
+ fake_segments[4*point-4].node2=NO_NODE;
+
+ fake_segments[4*point-3].node1=NO_NODE;
+ fake_segments[4*point-3].node2=NO_NODE;
+
+ fake_segments[4*point-2].node1=NO_NODE;
+ fake_segments[4*point-2].node2=NO_NODE;
+
+ fake_segments[4*point-1].node1=NO_NODE;
+ fake_segments[4*point-1].node2=NO_NODE;
+
+ /* Check if we are actually close enough to an existing node */
+
+ if(dist1<=km_to_distance(MINSEGMENT) && dist2>km_to_distance(MINSEGMENT))
+   {
+    prevpoint=point;
+    return(node1);
+   }
+
+ if(dist2<=km_to_distance(MINSEGMENT) && dist1>km_to_distance(MINSEGMENT))
+   {
+    prevpoint=point;
+    return(node2);
+   }
+
+ if(dist1<=km_to_distance(MINSEGMENT) && dist2<=km_to_distance(MINSEGMENT))
+   {
+    prevpoint=point;
+
+    if(dist1<dist2)
+       return(node1);
+    else
+       return(node2);
+   }
+
+ /* Create the fake node */
+
+ fakenode=NODE_FAKE+point;
+
+ GetLatLong(nodes,node1,NULL,&lat1,&lon1);
+ GetLatLong(nodes,node2,NULL,&lat2,&lon2);
+
+ if(lat1>3 && lat2<-3)
+    lat2+=2*M_PI;
+ else if(lat1<-3 && lat2>3)
+    lat1+=2*M_PI;
+
+ fake_lat[point]=lat1+(lat2-lat1)*(double)dist1/(double)(dist1+dist2); /* (dist1+dist2) must be > 0 */
+ fake_lon[point]=lon1+(lon2-lon1)*(double)dist1/(double)(dist1+dist2); /* (dist1+dist2) must be > 0 */
+
+ if(fake_lat[point]>M_PI) fake_lat[point]-=2*M_PI;
+
+ /*
+  *    node1  fakenode                         node2
+  *      #----------*----------------------------#     real_segments[4*point-{4,3}]
+  *   
+  *      #----------*                                  fake_segments[4*point-4]
+  *                 *----------------------------#     fake_segments[4*point-3]
+  *   
+  *   
+  *    node1  fakenode[prevpoint]              node2
+  *      #----------*------------------%---------#     real_segments[4*prevpoint-{4,3,1}], real_segments[4*point-{4,3,2}]
+  *                              fakenode[point]
+  *      #----------*                                  fake_segments[4*prevpoint-4]
+  *                 *----------------------------#     fake_segments[4*prevpoint-3]
+  *                 *------------------%               fake_segments[4*prevpoint-1]
+  *      #-----------------------------%               fake_segments[4*point-4]
+  *                                    %---------#     fake_segments[4*point-3]
+  *                 *------------------%               fake_segments[4*point-2]
+  */
+
+ /* Create the first fake segment */
+
+ fake_segments[4*point-4]=*segmentp;
+
+ fake_segments[4*point-4].node2=fakenode;
+
+ fake_segments[4*point-4].distance=DISTANCE(dist1)|DISTFLAG(segmentp->distance);
+
+ real_segments[4*point-4]=IndexSegment(segments,segmentp);
+
+ /* Create the second fake segment */
+
+ fake_segments[4*point-3]=*segmentp;
+
+ fake_segments[4*point-3].node1=fakenode;
+
+ fake_segments[4*point-3].distance=DISTANCE(dist2)|DISTFLAG(segmentp->distance);
+
+ real_segments[4*point-3]=IndexSegment(segments,segmentp);
+
+ /* Create a third fake segment to join adjacent points if both are fake and on the same real segment */
+
+ if(prevpoint>0 && fake_segments[4*prevpoint-4].node1==node1 && fake_segments[4*prevpoint-3].node2==node2)
+   {
+    if(DISTANCE(dist1)>DISTANCE(fake_segments[4*prevpoint-4].distance)) /* point is further from node1 than prevpoint */
+      {
+       fake_segments[4*point-2]=fake_segments[4*prevpoint-3];
+
+       fake_segments[4*point-2].node2=fakenode;
+
+       fake_segments[4*point-2].distance=(DISTANCE(dist1)-DISTANCE(fake_segments[4*prevpoint-4].distance))|DISTFLAG(segmentp->distance);
+      }
+    else
+      {
+       fake_segments[4*point-2]=fake_segments[4*prevpoint-4];
+
+       fake_segments[4*point-2].node1=fakenode;
+
+       fake_segments[4*point-2].distance=(DISTANCE(fake_segments[4*prevpoint-4].distance)-DISTANCE(dist1))|DISTFLAG(segmentp->distance);
+      }
+
+    real_segments[4*point-2]=IndexSegment(segments,segmentp);
+
+    fake_segments[4*prevpoint-1]=fake_segments[4*point-2];
+
+    real_segments[4*prevpoint-1]=real_segments[4*point-2];
+   }
+
+ /* Return the fake node */
+
+ prevpoint=point;
+
+ return(fakenode);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create a fake segment connecting a node to itself.
+
+  index_t CreateFakeNullSegment Returns the index of a fake segment.
+
+  Segments *segments The list of segments to use.
+
+  index_t node The node that is to be linked.
+
+  index_t segment The segment that is to be emulated.
+
+  int point The waypoint number.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t CreateFakeNullSegment(Segments *segments,index_t node,index_t segment,int point)
+{
+ Segment *segmentp=LookupSegment(segments,segment,1);
+
+ fake_segments[4*point-2].node1=node;
+ fake_segments[4*point-2].node2=node;
+ fake_segments[4*point-2].way=segmentp->way;
+ fake_segments[4*point-2].distance=0;
+
+ return(4*point-2+SEGMENT_FAKE);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Re-initialise the fake node data storage.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void DeleteFakeNodes(void)
+{
+ unsigned int i;
+
+ for(i=0;i<sizeof(fake_segments)/sizeof(fake_segments[0]);i++)
+   {
+    fake_segments[i].node1=NO_NODE;
+    fake_segments[i].node2=NO_NODE;
+   }
+
+ for(i=0;i<sizeof(real_segments)/sizeof(real_segments[0]);i++)
+    real_segments[i]=NO_SEGMENT;
+
+ prevpoint=0;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Lookup the latitude and longitude of a fake node.
+
+  index_t fakenode The fake node to lookup.
+
+  double *latitude Returns the latitude
+
+  double *longitude Returns the longitude.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void GetFakeLatLong(index_t fakenode, double *latitude,double *longitude)
+{
+ index_t whichnode=fakenode-NODE_FAKE;
+
+ *latitude =fake_lat[whichnode];
+ *longitude=fake_lon[whichnode];
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Finds the first fake segment associated to a fake node.
+
+  Segment *FirstFakeSegment Returns a pointer to the first fake segment.
+
+  index_t fakenode The fake node to lookup.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Segment *FirstFakeSegment(index_t fakenode)
+{
+ index_t whichnode=fakenode-NODE_FAKE;
+
+ return(&fake_segments[4*whichnode-4]);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Finds the next fake segment associated to a fake node.
+
+  Segment *NextFakeSegment Returns a pointer to the next fake segment.
+
+  Segment *fakesegmentp The first fake segment.
+
+  index_t fakenode The node to lookup.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Segment *NextFakeSegment(Segment *fakesegmentp,index_t fakenode)
+{
+ index_t whichnode=fakenode-NODE_FAKE;
+
+ if(fakesegmentp==&fake_segments[4*whichnode-4])
+    return(&fake_segments[4*whichnode-3]);
+
+ if(fakesegmentp==&fake_segments[4*whichnode-3] && fake_segments[4*whichnode-2].node1!=NO_NODE)
+    return(&fake_segments[4*whichnode-2]);
+
+ if(fakesegmentp==&fake_segments[4*whichnode-3] && fake_segments[4*whichnode-1].node1!=NO_NODE)
+    return(&fake_segments[4*whichnode-1]);
+
+ if(fakesegmentp==&fake_segments[4*whichnode-2] && fake_segments[4*whichnode-1].node1!=NO_NODE)
+    return(&fake_segments[4*whichnode-1]);
+
+ return(NULL);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Finds the fake segment between a real node and a fake node.
+
+  Segment *ExtraFakeSegment Returns a segment between the two specified nodes if it exists.
+
+  index_t realnode The real node.
+
+  index_t fakenode The fake node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Segment *ExtraFakeSegment(index_t realnode,index_t fakenode)
+{
+ index_t whichnode=fakenode-NODE_FAKE;
+
+ if(fake_segments[4*whichnode-4].node1==realnode || fake_segments[4*whichnode-4].node2==realnode)
+    return(&fake_segments[4*whichnode-4]);
+
+ if(fake_segments[4*whichnode-3].node1==realnode || fake_segments[4*whichnode-3].node2==realnode)
+    return(&fake_segments[4*whichnode-3]);
+
+ return(NULL);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Lookup a fake segment given its index.
+
+  Segment *LookupFakeSegment Returns a pointer to the fake segment.
+
+  index_t fakesegment The index of the fake segment.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Segment *LookupFakeSegment(index_t fakesegment)
+{
+ index_t whichsegment=fakesegment-SEGMENT_FAKE;
+
+ return(&fake_segments[whichsegment]);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the fake index of a fake segment.
+
+  index_t IndexFakeSegment Returns the fake segment.
+
+  Segment *fakesegmentp The fake segment to look for.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t IndexFakeSegment(Segment *fakesegmentp)
+{
+ index_t whichsegment=(index_t)(fakesegmentp-&fake_segments[0]);
+
+ return(whichsegment+SEGMENT_FAKE);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the real segment underlying a fake segment.
+
+  index_t IndexRealSegment Returns the index of the real segment.
+
+  index_t fakesegment The index of the fake segment.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t IndexRealSegment(index_t fakesegment)
+{
+ index_t whichsegment=fakesegment-SEGMENT_FAKE;
+
+ return(real_segments[whichsegment]);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Determine if a route between two fake segments is valid or a U-turn.
+
+  int IsFakeUTurn Returns true for a U-turn.
+
+  index_t fakesegment1 The first fake segment.
+
+  index_t fakesegment2 The second fake segment.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int IsFakeUTurn(index_t fakesegment1,index_t fakesegment2)
+{
+ index_t whichsegment1=fakesegment1-SEGMENT_FAKE;
+ index_t whichsegment2=fakesegment2-SEGMENT_FAKE;
+
+ if(fake_segments[whichsegment1].node1==fake_segments[whichsegment2].node1)
+    return(1);
+
+ if(fake_segments[whichsegment1].node2==fake_segments[whichsegment2].node2)
+    return(1);
+
+ return(0);
+}
diff --git a/3rdparty/Routino/src/fakes.h b/3rdparty/Routino/src/fakes.h
new file mode 100644
index 0000000..0bb73a3
--- /dev/null
+++ b/3rdparty/Routino/src/fakes.h
@@ -0,0 +1,58 @@
+/***************************************
+ Header file for fake node and segment function prototypes
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef FAKES_H
+#define FAKES_H    /*+ To stop multiple inclusions. +*/
+
+#include "types.h"
+
+
+/* Macros */
+
+/*+ Return true if this is a fake node. +*/
+#define IsFakeNode(xxx)    ((xxx)>=NODE_FAKE && (xxx)!=NO_NODE)
+
+/*+ Return true if this is a fake segment. +*/
+#define IsFakeSegment(xxx) ((xxx)>=SEGMENT_FAKE && (xxx)!=NO_SEGMENT)
+
+
+/* Functions in fakes.c */
+
+index_t CreateFakes(Nodes *nodes,Segments *segments,int point,Segment *segmentp,index_t node1,index_t node2,distance_t dist1,distance_t dist2);
+
+index_t CreateFakeNullSegment(Segments *segments,index_t node,index_t segment,int point);
+
+void DeleteFakeNodes(void);
+
+void GetFakeLatLong(index_t fakenode, double *latitude,double *longitude);
+
+Segment *FirstFakeSegment(index_t fakenode);
+Segment *NextFakeSegment(Segment *fakesegmentp,index_t fakenode);
+Segment *ExtraFakeSegment(index_t realnode,index_t fakenode);
+
+Segment *LookupFakeSegment(index_t index);
+index_t IndexFakeSegment(Segment *fakesegmentp);
+index_t IndexRealSegment(index_t fakesegment);
+
+int IsFakeUTurn(index_t fakesegment1,index_t fakesegment2);
+
+#endif /* FAKES_H */
diff --git a/3rdparty/Routino/src/filedumper.c b/3rdparty/Routino/src/filedumper.c
new file mode 100644
index 0000000..aa347bc
--- /dev/null
+++ b/3rdparty/Routino/src/filedumper.c
@@ -0,0 +1,1278 @@
+/***************************************
+ Memory file dumper.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <math.h>
+
+#include "types.h"
+#include "nodes.h"
+#include "segments.h"
+#include "ways.h"
+#include "relations.h"
+#include "errorlog.h"
+
+#include "files.h"
+#include "visualiser.h"
+#include "xmlparse.h"
+
+
+/* Local functions */
+
+static void print_node(Nodes *nodes,index_t item);
+static void print_segment(Segments *segments,index_t item);
+static void print_way(Ways *ways,index_t item);
+static void print_turn_relation(Relations *relations,index_t item,Segments *segments,Nodes *nodes);
+static void print_errorlog(ErrorLogs *errorlogs,index_t item);
+
+static void print_head_osm(int coordcount,double latmin,double latmax,double lonmin,double lonmax);
+static void print_region_osm(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,
+                             double latmin,double latmax,double lonmin,double lonmax,int option_no_super);
+static void print_node_osm(Nodes *nodes,index_t item);
+static void print_segment_osm(Segments *segments,index_t item,Ways *ways);
+static void print_turn_relation_osm(Relations *relations,index_t item,Segments *segments,Nodes *nodes);
+static void print_tail_osm(void);
+
+static void print_node_visualiser(Nodes *nodes,index_t item);
+static void print_segment_visualiser(Segments *segments,index_t item,Ways *ways);
+static void print_turn_relation_visualiser(Relations *relations,index_t item,Segments *segments,Nodes *nodes);
+static void print_errorlog_visualiser(ErrorLogs *errorlogs,index_t item);
+
+static char *RFC822Date(time_t t);
+
+static void print_usage(int detail,const char *argerr,const char *err);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The main program for the file dumper.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int main(int argc,char** argv)
+{
+ Nodes    *OSMNodes;
+ Segments *OSMSegments;
+ Ways     *OSMWays;
+ Relations*OSMRelations;
+ ErrorLogs*OSMErrorLogs=NULL;
+ int       arg;
+ char     *dirname=NULL,*prefix=NULL;
+ char     *nodes_filename,*segments_filename,*ways_filename,*relations_filename,*errorlogs_filename;
+ int       option_statistics=0;
+ int       option_visualiser=0,coordcount=0;
+ double    latmin=0,latmax=0,lonmin=0,lonmax=0;
+ char     *option_data=NULL;
+ int       option_dump=0;
+ int       option_dump_osm=0,option_no_super=0;
+ int       option_dump_visualiser=0;
+
+ /* Parse the command line arguments */
+
+ for(arg=1;arg<argc;arg++)
+   {
+    if(!strcmp(argv[arg],"--help"))
+       print_usage(1,NULL,NULL);
+    else if(!strncmp(argv[arg],"--dir=",6))
+       dirname=&argv[arg][6];
+    else if(!strncmp(argv[arg],"--prefix=",9))
+       prefix=&argv[arg][9];
+    else if(!strcmp(argv[arg],"--statistics"))
+       option_statistics=1;
+    else if(!strcmp(argv[arg],"--visualiser"))
+       option_visualiser=1;
+    else if(!strcmp(argv[arg],"--dump"))
+       option_dump=1;
+    else if(!strcmp(argv[arg],"--dump-osm"))
+       option_dump_osm=1;
+    else if(!strcmp(argv[arg],"--dump-visualiser"))
+       option_dump_visualiser=1;
+    else if(!strncmp(argv[arg],"--latmin",8) && argv[arg][8]=='=')
+      {latmin=degrees_to_radians(atof(&argv[arg][9]));coordcount++;}
+    else if(!strncmp(argv[arg],"--latmax",8) && argv[arg][8]=='=')
+      {latmax=degrees_to_radians(atof(&argv[arg][9]));coordcount++;}
+    else if(!strncmp(argv[arg],"--lonmin",8) && argv[arg][8]=='=')
+      {lonmin=degrees_to_radians(atof(&argv[arg][9]));coordcount++;}
+    else if(!strncmp(argv[arg],"--lonmax",8) && argv[arg][8]=='=')
+      {lonmax=degrees_to_radians(atof(&argv[arg][9]));coordcount++;}
+    else if(!strncmp(argv[arg],"--data",6) && argv[arg][6]=='=')
+       option_data=&argv[arg][7];
+    else if(!strcmp(argv[arg],"--no-super"))
+       option_no_super=1;
+    else if(!strncmp(argv[arg],"--node=",7))
+       ;
+    else if(!strncmp(argv[arg],"--segment=",10))
+       ;
+    else if(!strncmp(argv[arg],"--way=",6))
+       ;
+    else if(!strncmp(argv[arg],"--turn-relation=",16))
+       ;
+    else if(!strncmp(argv[arg],"--errorlog=",11))
+       ;
+    else
+       print_usage(0,argv[arg],NULL);
+   }
+
+ if((option_statistics + option_visualiser + option_dump + option_dump_osm + option_dump_visualiser)!=1)
+    print_usage(0,NULL,"Must choose --visualiser, --statistics, --dump, --dump-osm or --dump-visualiser.");
+
+ /* Load in the data - Note: No error checking because Load*List() will call exit() in case of an error. */
+
+ OSMNodes=LoadNodeList(nodes_filename=FileName(dirname,prefix,"nodes.mem"));
+
+ OSMSegments=LoadSegmentList(segments_filename=FileName(dirname,prefix,"segments.mem"));
+
+ OSMWays=LoadWayList(ways_filename=FileName(dirname,prefix,"ways.mem"));
+
+ OSMRelations=LoadRelationList(relations_filename=FileName(dirname,prefix,"relations.mem"));
+
+ if(ExistsFile(errorlogs_filename=FileName(dirname,prefix,"errorlogs.mem")))
+    OSMErrorLogs=LoadErrorLogs(errorlogs_filename);
+ else
+    errorlogs_filename=NULL;
+
+ /* Write out the visualiser data */
+
+ if(option_visualiser)
+   {
+    Highway highway;
+    Transport transport;
+    Property property;
+
+    if(coordcount!=4)
+       print_usage(0,NULL,"The --visualiser option must have --latmin, --latmax, --lonmin, --lonmax.\n");
+
+    if(!option_data)
+       print_usage(0,NULL,"The --visualiser option must have --data.\n");
+
+    if(!strcmp(option_data,"junctions"))
+       OutputJunctions(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax);
+    else if(!strcmp(option_data,"super"))
+       OutputSuper(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax);
+    else if(!strcmp(option_data,"waytype-oneway"))
+       OutputWaytype(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax,Highway_OneWay);
+    else if(!strcmp(option_data,"waytype-cyclebothways"))
+       OutputWaytype(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax,Highway_CycleBothWays);
+    else if(!strcmp(option_data,"waytype-roundabout"))
+       OutputWaytype(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax,Highway_Roundabout);
+    else if(!strncmp(option_data,"highway",7) && option_data[7]=='-' && (highway=HighwayType(option_data+8))!=Highway_None)
+       OutputHighway(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax,highway);
+    else if(!strncmp(option_data,"transport",9) && option_data[9]=='-' && (transport=TransportType(option_data+10))!=Transport_None)
+       OutputTransport(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax,transport);
+    else if(!strncmp(option_data,"barrier",7) && option_data[7]=='-' && (transport=TransportType(option_data+8))!=Transport_None)
+       OutputBarrier(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax,transport);
+    else if(!strcmp(option_data,"turns"))
+       OutputTurnRestrictions(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax);
+    else if(!strcmp(option_data,"speed"))
+       OutputSpeedLimits(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax);
+    else if(!strcmp(option_data,"weight"))
+       OutputWeightLimits(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax);
+    else if(!strcmp(option_data,"height"))
+       OutputHeightLimits(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax);
+    else if(!strcmp(option_data,"width"))
+       OutputWidthLimits(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax);
+    else if(!strcmp(option_data,"length"))
+       OutputLengthLimits(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax);
+    else if(!strncmp(option_data,"property",8) && option_data[8]=='-' && (property=PropertyType(option_data+9))!=Property_None)
+       OutputProperty(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax,property);
+    else if(!strcmp(option_data,"errorlogs"))
+       OutputErrorLog(OSMErrorLogs,latmin,latmax,lonmin,lonmax);
+    else
+       print_usage(0,option_data,NULL);
+   }
+
+ /* Print out statistics */
+
+ if(option_statistics)
+   {
+    struct stat buf;
+
+    /* Examine the files */
+
+    printf("Files\n");
+    printf("-----\n");
+    printf("\n");
+
+    stat(nodes_filename,&buf);
+
+    printf("'%s%snodes.mem'     - %9"PRIu64" Bytes\n",prefix?prefix:"",prefix?"-":"",(uint64_t)buf.st_size);
+    printf("%s\n",RFC822Date(buf.st_mtime));
+    printf("\n");
+
+    stat(segments_filename,&buf);
+
+    printf("'%s%ssegments.mem'  - %9"PRIu64" Bytes\n",prefix?prefix:"",prefix?"-":"",(uint64_t)buf.st_size);
+    printf("%s\n",RFC822Date(buf.st_mtime));
+    printf("\n");
+
+    stat(ways_filename,&buf);
+
+    printf("'%s%sways.mem'      - %9"PRIu64" Bytes\n",prefix?prefix:"",prefix?"-":"",(uint64_t)buf.st_size);
+    printf("%s\n",RFC822Date(buf.st_mtime));
+    printf("\n");
+
+    stat(relations_filename,&buf);
+
+    printf("'%s%srelations.mem' - %9"PRIu64" Bytes\n",prefix?prefix:"",prefix?"-":"",(uint64_t)buf.st_size);
+    printf("%s\n",RFC822Date(buf.st_mtime));
+    printf("\n");
+
+    if(errorlogs_filename)
+      {
+       stat(errorlogs_filename,&buf);
+
+       printf("'%s%serrorlogs.mem' - %9"PRIu64" Bytes\n",prefix?prefix:"",prefix?"-":"",(uint64_t)buf.st_size);
+       printf("%s\n",RFC822Date(buf.st_mtime));
+       printf("\n");
+      }
+
+    /* Examine the nodes */
+
+    printf("Nodes\n");
+    printf("-----\n");
+    printf("\n");
+
+    printf("sizeof(Node) =%9zu Bytes\n",sizeof(Node));
+    printf("Number       =%9"Pindex_t"\n",OSMNodes->file.number);
+    printf("Number(super)=%9"Pindex_t"\n",OSMNodes->file.snumber);
+    printf("\n");
+
+    printf("Lat bins= %4d\n",(int)OSMNodes->file.latbins);
+    printf("Lon bins= %4d\n",(int)OSMNodes->file.lonbins);
+    printf("\n");
+
+    printf("Lat zero=%5d (%8.4f deg)\n",(int)OSMNodes->file.latzero,radians_to_degrees(latlong_to_radians(bin_to_latlong(OSMNodes->file.latzero))));
+    printf("Lon zero=%5d (%8.4f deg)\n",(int)OSMNodes->file.lonzero,radians_to_degrees(latlong_to_radians(bin_to_latlong(OSMNodes->file.lonzero))));
+
+    /* Examine the segments */
+
+    printf("\n");
+    printf("Segments\n");
+    printf("--------\n");
+    printf("\n");
+
+    printf("sizeof(Segment)=%9zu Bytes\n",sizeof(Segment));
+    printf("Number(total)  =%9"Pindex_t"\n",OSMSegments->file.number);
+    printf("Number(super)  =%9"Pindex_t"\n",OSMSegments->file.snumber);
+    printf("Number(normal) =%9"Pindex_t"\n",OSMSegments->file.nnumber);
+
+    /* Examine the ways */
+
+    printf("\n");
+    printf("Ways\n");
+    printf("----\n");
+    printf("\n");
+
+    printf("sizeof(Way)=%9zu Bytes\n",sizeof(Way));
+    printf("Number     =%9"Pindex_t"\n",OSMWays->file.number);
+    printf("\n");
+
+    stat(ways_filename,&buf);
+    printf("Total names=%9zu Bytes\n",(size_t)buf.st_size-sizeof(Ways)-OSMWays->file.number*sizeof(Way));
+    printf("\n");
+
+    printf("Included highways  : %s\n",HighwaysNameList(OSMWays->file.highways));
+    printf("Included transports: %s\n",AllowedNameList(OSMWays->file.allow));
+    printf("Included properties: %s\n",PropertiesNameList(OSMWays->file.props));
+
+    /* Examine the relations */
+
+    printf("\n");
+    printf("Relations\n");
+    printf("---------\n");
+    printf("\n");
+
+    printf("sizeof(TurnRelation)=%9zu Bytes\n",sizeof(TurnRelation));
+    printf("Number              =%9"Pindex_t"\n",OSMRelations->file.trnumber);
+
+    if(errorlogs_filename)
+      {
+       printf("\n");
+       printf("Error Logs\n");
+       printf("----------\n");
+       printf("\n");
+
+       printf("Number(total)           =%9"Pindex_t"\n",OSMErrorLogs->file.number);
+       printf("Number(geographical)    =%9"Pindex_t"\n",OSMErrorLogs->file.number_geo);
+       printf("Number(non-geographical)=%9"Pindex_t"\n",OSMErrorLogs->file.number_nongeo);
+
+       printf("\n");
+       stat(errorlogs_filename,&buf);
+#if !SLIM
+       printf("Total strings=%9zu Bytes\n",(size_t)buf.st_size-(OSMErrorLogs->strings-(char*)OSMErrorLogs->data));
+#else
+       printf("Total strings=%9zu Bytes\n",(size_t)buf.st_size-(size_t)OSMErrorLogs->stringsoffset);
+#endif
+      }
+   }
+
+ /* Print out internal data (in plain text format) */
+
+ if(option_dump)
+   {
+    index_t item;
+
+    for(arg=1;arg<argc;arg++)
+       if(!strcmp(argv[arg],"--node=all"))
+         {
+          for(item=0;item<OSMNodes->file.number;item++)
+             print_node(OSMNodes,item);
+         }
+       else if(!strncmp(argv[arg],"--node=",7))
+         {
+          item=atoi(&argv[arg][7]);
+
+          if(item<OSMNodes->file.number)
+             print_node(OSMNodes,item);
+          else
+             printf("Invalid node number; minimum=0, maximum=%"Pindex_t".\n",OSMNodes->file.number-1);
+         }
+       else if(!strcmp(argv[arg],"--segment=all"))
+         {
+          for(item=0;item<OSMSegments->file.number;item++)
+             print_segment(OSMSegments,item);
+         }
+       else if(!strncmp(argv[arg],"--segment=",10))
+         {
+          item=atoi(&argv[arg][10]);
+
+          if(item<OSMSegments->file.number)
+             print_segment(OSMSegments,item);
+          else
+             printf("Invalid segment number; minimum=0, maximum=%"Pindex_t".\n",OSMSegments->file.number-1);
+         }
+       else if(!strcmp(argv[arg],"--way=all"))
+         {
+          for(item=0;item<OSMWays->file.number;item++)
+             print_way(OSMWays,item);
+         }
+       else if(!strncmp(argv[arg],"--way=",6))
+         {
+          item=atoi(&argv[arg][6]);
+
+          if(item<OSMWays->file.number)
+             print_way(OSMWays,item);
+          else
+             printf("Invalid way number; minimum=0, maximum=%"Pindex_t".\n",OSMWays->file.number-1);
+         }
+       else if(!strcmp(argv[arg],"--turn-relation=all"))
+         {
+          for(item=0;item<OSMRelations->file.trnumber;item++)
+             print_turn_relation(OSMRelations,item,OSMSegments,OSMNodes);
+         }
+       else if(!strncmp(argv[arg],"--turn-relation=",16))
+         {
+          item=atoi(&argv[arg][16]);
+
+          if(item<OSMRelations->file.trnumber)
+             print_turn_relation(OSMRelations,item,OSMSegments,OSMNodes);
+          else
+             printf("Invalid turn relation number; minimum=0, maximum=%"Pindex_t".\n",OSMRelations->file.trnumber-1);
+         }
+       else if(!strcmp(argv[arg],"--errorlog=all"))
+         {
+          for(item=0;item<OSMErrorLogs->file.number;item++)
+             print_errorlog(OSMErrorLogs,item);
+         }
+       else if(!strncmp(argv[arg],"--errorlog=",11))
+         {
+          item=atoi(&argv[arg][11]);
+
+          if(item<OSMErrorLogs->file.number)
+             print_errorlog(OSMErrorLogs,item);
+          else
+             printf("Invalid error log number; minimum=0, maximum=%"Pindex_t".\n",OSMErrorLogs->file.number-1);
+         }
+   }
+
+ /* Print out internal data (in OSM XML format) */
+
+ if(option_dump_osm)
+   {
+    if(coordcount>0 && coordcount!=4)
+       print_usage(0,NULL,"The --dump-osm option must have all of --latmin, --latmax, --lonmin, --lonmax or none.\n");
+
+    print_head_osm(coordcount,latmin,latmax,lonmin,lonmax);
+
+    if(coordcount)
+       print_region_osm(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax,option_no_super);
+    else
+      {
+       index_t item;
+
+       for(item=0;item<OSMNodes->file.number;item++)
+          print_node_osm(OSMNodes,item);
+
+       for(item=0;item<OSMSegments->file.number;item++)
+          if(!option_no_super || IsNormalSegment(LookupSegment(OSMSegments,item,1)))
+             print_segment_osm(OSMSegments,item,OSMWays);
+
+       for(item=0;item<OSMRelations->file.trnumber;item++)
+          print_turn_relation_osm(OSMRelations,item,OSMSegments,OSMNodes);
+      }
+
+    print_tail_osm();
+   }
+
+ /* Print out internal data (in HTML format for the visualiser) */
+
+ if(option_dump_visualiser)
+   {
+    index_t item;
+
+    if(!option_data)
+       print_usage(0,NULL,"The --dump-visualiser option must have --data.\n");
+
+    for(arg=1;arg<argc;arg++)
+       if(!strncmp(argv[arg],"--data=node",11))
+         {
+          item=atoi(&argv[arg][11]);
+
+          if(item<OSMNodes->file.number)
+             print_node_visualiser(OSMNodes,item);
+          else
+             printf("Invalid node number; minimum=0, maximum=%"Pindex_t".\n",OSMNodes->file.number-1);
+         }
+       else if(!strncmp(argv[arg],"--data=segment",14))
+         {
+          item=atoi(&argv[arg][14]);
+
+          if(item<OSMSegments->file.number)
+             print_segment_visualiser(OSMSegments,item,OSMWays);
+          else
+             printf("Invalid segment number; minimum=0, maximum=%"Pindex_t".\n",OSMSegments->file.number-1);
+         }
+       else if(!strncmp(argv[arg],"--data=turn-relation",20))
+         {
+          item=atoi(&argv[arg][20]);
+
+          if(item<OSMRelations->file.trnumber)
+             print_turn_relation_visualiser(OSMRelations,item,OSMSegments,OSMNodes);
+          else
+             printf("Invalid turn relation number; minimum=0, maximum=%"Pindex_t".\n",OSMRelations->file.trnumber-1);
+         }
+       else if(!strncmp(argv[arg],"--data=errorlog",15))
+         {
+          item=atoi(&argv[arg][15]);
+
+          if(item<OSMErrorLogs->file.number)
+             print_errorlog_visualiser(OSMErrorLogs,item);
+          else
+             printf("Invalid error log number; minimum=0, maximum=%"Pindex_t".\n",OSMErrorLogs->file.number-1);
+         }
+   }
+
+ exit(EXIT_SUCCESS);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the contents of a node from the routing database (as plain text).
+
+  Nodes *nodes The set of nodes to use.
+
+  index_t item The node index to print.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_node(Nodes *nodes,index_t item)
+{
+ Node *nodep=LookupNode(nodes,item,1);
+ double latitude,longitude;
+
+ GetLatLong(nodes,item,nodep,&latitude,&longitude);
+
+ printf("Node %"Pindex_t"\n",item);
+ printf("  firstseg=%"Pindex_t"\n",nodep->firstseg);
+ printf("  latoffset=%d lonoffset=%d (latitude=%.6f longitude=%.6f)\n",nodep->latoffset,nodep->lonoffset,radians_to_degrees(latitude),radians_to_degrees(longitude));
+ printf("  allow=%02x (%s)\n",nodep->allow,AllowedNameList(nodep->allow));
+ if(IsSuperNode(nodep))
+    printf("  Super-Node\n");
+ if(nodep->flags & NODE_MINIRNDBT)
+    printf("  Mini-roundabout\n");
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the contents of a segment from the routing database (as plain text).
+
+  Segments *segments The set of segments to use.
+
+  index_t item The segment index to print.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_segment(Segments *segments,index_t item)
+{
+ Segment *segmentp=LookupSegment(segments,item,1);
+
+ printf("Segment %"Pindex_t"\n",item);
+ printf("  node1=%"Pindex_t" node2=%"Pindex_t"\n",segmentp->node1,segmentp->node2);
+ printf("  next2=%"Pindex_t"\n",segmentp->next2);
+ printf("  way=%"Pindex_t"\n",segmentp->way);
+ printf("  distance=%d (%.3f km)\n",DISTANCE(segmentp->distance),distance_to_km(DISTANCE(segmentp->distance)));
+ if(IsSuperSegment(segmentp) && IsNormalSegment(segmentp))
+    printf("  Super-Segment AND normal Segment\n");
+ else if(IsSuperSegment(segmentp) && !IsNormalSegment(segmentp))
+    printf("  Super-Segment\n");
+ if(IsOnewayTo(segmentp,segmentp->node1))
+    printf("  One-Way from node2 to node1\n");
+ if(IsOnewayTo(segmentp,segmentp->node2))
+    printf("  One-Way from node1 to node2\n");
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the contents of a way from the routing database (as plain text).
+
+  Ways *ways The set of ways to use.
+
+  index_t item The way index to print.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_way(Ways *ways,index_t item)
+{
+ Way *wayp=LookupWay(ways,item,1);
+ char *name=WayName(ways,wayp);
+
+ printf("Way %"Pindex_t"\n",item);
+ if(*name)
+    printf("  name=%s\n",name);
+ printf("  type=%02x (%s%s%s%s)\n",wayp->type,
+                                   HighwayName(HIGHWAY(wayp->type)),
+                                   wayp->type&Highway_OneWay?",One-Way":"",
+                                   wayp->type&Highway_CycleBothWays?",Cycle-Both-Ways":"",
+                                   wayp->type&Highway_Roundabout?",Roundabout":"");
+ printf("  allow=%02x (%s)\n",wayp->allow,AllowedNameList(wayp->allow));
+ if(wayp->props)
+    printf("  props=%02x (%s)\n",wayp->props,PropertiesNameList(wayp->props));
+ if(wayp->speed)
+    printf("  speed=%d (%d km/hr)\n",wayp->speed,speed_to_kph(wayp->speed));
+ if(wayp->weight)
+    printf("  weight=%d (%.1f tonnes)\n",wayp->weight,weight_to_tonnes(wayp->weight));
+ if(wayp->height)
+    printf("  height=%d (%.1f m)\n",wayp->height,height_to_metres(wayp->height));
+ if(wayp->width)
+    printf("  width=%d (%.1f m)\n",wayp->width,width_to_metres(wayp->width));
+ if(wayp->length)
+    printf("  length=%d (%.1f m)\n",wayp->length,length_to_metres(wayp->length));
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the contents of a turn relation from the routing database (as plain text).
+
+  Relations *relations The set of relations to use.
+
+  index_t item The turn relation index to print.
+
+  Segments *segments The set of segments to use.
+
+  Nodes *nodes The set of nodes to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_turn_relation(Relations *relations,index_t item,Segments *segments,Nodes *nodes)
+{
+ Segment *segmentp;
+ TurnRelation *relationp=LookupTurnRelation(relations,item,1);
+ Node *nodep=LookupNode(nodes,relationp->via,1);
+ index_t from_way=NO_WAY,to_way=NO_WAY;
+ index_t from_node=NO_NODE,to_node=NO_NODE;
+
+ segmentp=FirstSegment(segments,nodep,1);
+
+ do
+   {
+    index_t seg=IndexSegment(segments,segmentp);
+
+    if(seg==relationp->from)
+      {
+       from_node=OtherNode(segmentp,relationp->from);
+       from_way=segmentp->way;
+      }
+
+    if(seg==relationp->to)
+      {
+       to_node=OtherNode(segmentp,relationp->to);
+       to_way=segmentp->way;
+      }
+
+    segmentp=NextSegment(segments,segmentp,relationp->via);
+   }
+ while(segmentp);
+
+ printf("Relation %"Pindex_t"\n",item);
+ printf("  from=%"Pindex_t" (segment) = %"Pindex_t" (way) = %"Pindex_t" (node)\n",relationp->from,from_way,from_node);
+ printf("  via=%"Pindex_t" (node)\n",relationp->via);
+ printf("  to=%"Pindex_t" (segment) = %"Pindex_t" (way) = %"Pindex_t" (node)\n",relationp->to,to_way,to_node);
+ if(relationp->except)
+    printf("  except=%02x (%s)\n",relationp->except,AllowedNameList(relationp->except));
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the contents of an error log from the routing database (as plain text).
+
+  ErrorLogs *errorlogs The set of error logs to use.
+
+  index_t item The error log index to print.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_errorlog(ErrorLogs *errorlogs,index_t item)
+{
+ ErrorLog *errorlogp=LookupErrorLog(errorlogs,item,1);
+
+ printf("Error Log %"Pindex_t"\n",item);
+
+ if(item<errorlogs->file.number_geo)
+   {
+    double latitude,longitude;
+
+    GetErrorLogLatLong(errorlogs,item,errorlogp,&latitude,&longitude);
+
+    printf("  latoffset=%d lonoffset=%d (latitude=%.6f longitude=%.6f)\n",errorlogp->latoffset,errorlogp->lonoffset,radians_to_degrees(latitude),radians_to_degrees(longitude));
+   }
+ else
+    printf("  No geographical information\n");
+
+ printf("  '%s'\n",LookupErrorLogString(errorlogs,item));
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out a header in OSM XML format.
+
+  int coordcount If true then include a bounding box.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_head_osm(int coordcount,double latmin,double latmax,double lonmin,double lonmax)
+{
+ printf("<?xml version='1.0' encoding='UTF-8'?>\n");
+ printf("<osm version='0.6' generator='Routino'>\n");
+
+ if(coordcount)
+    printf("  <bounds minlat='%.6f' maxlat='%.6f' minlon='%.6f' maxlon='%.6f' />\n",
+           radians_to_degrees(latmin),radians_to_degrees(latmax),radians_to_degrees(lonmin),radians_to_degrees(lonmax));
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print a region of the database in OSM XML format.
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+
+  int option_no_super The option to print no super-segments.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_region_osm(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,
+                             double latmin,double latmax,double lonmin,double lonmax,int option_no_super)
+{
+ ll_bin_t latminbin=latlong_to_bin(radians_to_latlong(latmin))-nodes->file.latzero;
+ ll_bin_t latmaxbin=latlong_to_bin(radians_to_latlong(latmax))-nodes->file.latzero;
+ ll_bin_t lonminbin=latlong_to_bin(radians_to_latlong(lonmin))-nodes->file.lonzero;
+ ll_bin_t lonmaxbin=latlong_to_bin(radians_to_latlong(lonmax))-nodes->file.lonzero;
+ ll_bin_t latb,lonb;
+ index_t item,index1,index2;
+
+ if(latminbin<0)                   latminbin=0;
+ if(latmaxbin>nodes->file.latbins) latmaxbin=nodes->file.latbins-1;
+ if(lonminbin<0)                   lonminbin=0;
+ if(lonmaxbin>nodes->file.lonbins) lonmaxbin=nodes->file.lonbins-1;
+
+ /* Loop through all of the nodes. */
+
+ for(latb=latminbin;latb<=latmaxbin;latb++)
+    for(lonb=lonminbin;lonb<=lonmaxbin;lonb++)
+      {
+       ll_bin2_t llbin=lonb*nodes->file.latbins+latb;
+
+       if(llbin<0 || llbin>(nodes->file.latbins*nodes->file.lonbins))
+          continue;
+
+       index1=LookupNodeOffset(nodes,llbin);
+       index2=LookupNodeOffset(nodes,llbin+1);
+
+       for(item=index1;item<index2;item++)
+         {
+          Node *nodep=LookupNode(nodes,item,1);
+          double lat=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb)+off_to_latlong(nodep->latoffset));
+          double lon=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb)+off_to_latlong(nodep->lonoffset));
+
+          if(lat>latmin && lat<latmax && lon>lonmin && lon<lonmax)
+            {
+             Segment *segmentp;
+
+             print_node_osm(nodes,item);
+
+             segmentp=FirstSegment(segments,nodep,1);
+
+             while(segmentp)
+               {
+                double olat,olon;
+                index_t oitem=OtherNode(segmentp,item);
+
+                GetLatLong(nodes,oitem,NULL,&olat,&olon);
+
+                if(olat>latmin && olat<latmax && olon>lonmin && olon<lonmax)
+                   if(item>oitem)
+                      if(!option_no_super || IsNormalSegment(segmentp))
+                         print_segment_osm(segments,IndexSegment(segments,segmentp),ways);
+
+                segmentp=NextSegment(segments,segmentp,item);
+               }
+
+             if(IsTurnRestrictedNode(nodep))
+               {
+                index_t relindex=FindFirstTurnRelation1(relations,item);
+
+                while(relindex!=NO_RELATION)
+                  {
+                   print_turn_relation_osm(relations,relindex,segments,nodes);
+
+                   relindex=FindNextTurnRelation1(relations,relindex);
+                  }
+               }
+            }
+         }
+      }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the contents of a node from the routing database (in OSM XML format).
+
+  Nodes *nodes The set of nodes to use.
+
+  index_t item The node index to print.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_node_osm(Nodes *nodes,index_t item)
+{
+ Node *nodep=LookupNode(nodes,item,1);
+ double latitude,longitude;
+ int i;
+
+ GetLatLong(nodes,item,nodep,&latitude,&longitude);
+
+ if(nodep->allow==Transports_ALL && nodep->flags==0)
+    printf("  <node id='%"Pindex_t"' lat='%.7f' lon='%.7f' version='1' />\n",item+1,radians_to_degrees(latitude),radians_to_degrees(longitude));
+ else
+   {
+    printf("  <node id='%"Pindex_t"' lat='%.7f' lon='%.7f' version='1'>\n",item+1,radians_to_degrees(latitude),radians_to_degrees(longitude));
+
+    if(nodep->flags & NODE_SUPER)
+       printf("    <tag k='routino:super' v='yes' />\n");
+
+    if(nodep->flags & NODE_UTURN)
+       printf("    <tag k='routino:uturn' v='yes' />\n");
+
+    if(nodep->flags & NODE_MINIRNDBT)
+       printf("    <tag k='junction' v='roundabout' />\n");
+
+    if(nodep->flags & NODE_TURNRSTRCT)
+       printf("    <tag k='routino:turnrestriction' v='yes' />\n");
+
+    for(i=1;i<Transport_Count;i++)
+       if(!(nodep->allow & TRANSPORTS(i)))
+          printf("    <tag k='%s' v='no' />\n",TransportName(i));
+
+    printf("  </node>\n");
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the contents of a segment from the routing database (as a way in OSM XML format).
+
+  Segments *segments The set of segments to use.
+
+  index_t item The segment index to print.
+
+  Ways *ways The set of ways to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_segment_osm(Segments *segments,index_t item,Ways *ways)
+{
+ Segment *segmentp=LookupSegment(segments,item,1);
+ Way *wayp=LookupWay(ways,segmentp->way,1);
+ char *name=WayName(ways,wayp);
+ int i;
+
+ printf("  <way id='%"Pindex_t"' version='1'>\n",item+1);
+
+ if(IsOnewayTo(segmentp,segmentp->node1))
+   {
+    printf("    <nd ref='%"Pindex_t"' />\n",segmentp->node2+1);
+    printf("    <nd ref='%"Pindex_t"' />\n",segmentp->node1+1);
+   }
+ else
+   {
+    printf("    <nd ref='%"Pindex_t"' />\n",segmentp->node1+1);
+    printf("    <nd ref='%"Pindex_t"' />\n",segmentp->node2+1);
+   }
+
+ if(IsSuperSegment(segmentp))
+    printf("    <tag k='routino:super' v='yes' />\n");
+ if(IsNormalSegment(segmentp))
+    printf("    <tag k='routino:normal' v='yes' />\n");
+
+ printf("    <tag k='routino:distance' v='%.3f' />\n",distance_to_km(DISTANCE(segmentp->distance)));
+
+ if(wayp->type & Highway_OneWay)
+    printf("    <tag k='oneway' v='yes' />\n");
+
+ if(wayp->type & Highway_CycleBothWays)
+    printf("    <tag k='cyclebothways' v='yes' />\n");
+
+ if(wayp->type & Highway_Roundabout)
+    printf("    <tag k='roundabout' v='yes' />\n");
+
+ printf("    <tag k='highway' v='%s' />\n",HighwayName(HIGHWAY(wayp->type)));
+
+ if(IsNormalSegment(segmentp) && *name)
+    printf("    <tag k='name' v='%s' />\n",ParseXML_Encode_Safe_XML(name));
+
+ for(i=1;i<Transport_Count;i++)
+    if(wayp->allow & TRANSPORTS(i))
+       printf("    <tag k='%s' v='yes' />\n",TransportName(i));
+
+ for(i=1;i<Property_Count;i++)
+    if(wayp->props & PROPERTIES(i))
+       printf("    <tag k='%s' v='yes' />\n",PropertyName(i));
+
+ if(wayp->speed)
+    printf("    <tag k='maxspeed' v='%d' />\n",speed_to_kph(wayp->speed));
+
+ if(wayp->weight)
+    printf("    <tag k='maxweight' v='%.1f' />\n",weight_to_tonnes(wayp->weight));
+ if(wayp->height)
+    printf("    <tag k='maxheight' v='%.1f' />\n",height_to_metres(wayp->height));
+ if(wayp->width)
+    printf("    <tag k='maxwidth' v='%.1f' />\n",width_to_metres(wayp->width));
+ if(wayp->length)
+    printf("    <tag k='maxlength' v='%.1f' />\n",length_to_metres(wayp->length));
+
+ printf("  </way>\n");
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the contents of a turn relation from the routing database (in OSM XML format).
+
+  Relations *relations The set of relations to use.
+
+  index_t item The relation index to print.
+
+  Segments *segments The set of segments to use.
+
+  Nodes *nodes The set of nodes to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_turn_relation_osm(Relations *relations,index_t item,Segments *segments,Nodes *nodes)
+{
+ TurnRelation *relationp=LookupTurnRelation(relations,item,1);
+
+ Segment *segmentp_from=LookupSegment(segments,relationp->from,1);
+ Segment *segmentp_to  =LookupSegment(segments,relationp->to  ,2);
+
+ double angle=TurnAngle(nodes,segmentp_from,segmentp_to,relationp->via);
+
+ char *restriction;
+
+ if(angle>150 || angle<-150)
+    restriction="no_u_turn";
+ else if(angle>30)
+    restriction="no_right_turn";
+ else if(angle<-30)
+    restriction="no_left_turn";
+ else
+    restriction="no_straight_on";
+
+ printf("  <relation id='%"Pindex_t"' version='1'>\n",item+1);
+ printf("    <tag k='type' v='restriction' />\n");
+ printf("    <tag k='restriction' v='%s'/>\n",restriction);
+
+ if(relationp->except)
+    printf("    <tag k='except' v='%s' />\n",AllowedNameList(relationp->except));
+
+ printf("    <member type='way' ref='%"Pindex_t"' role='from' />\n",relationp->from+1);
+ printf("    <member type='node' ref='%"Pindex_t"' role='via' />\n",relationp->via+1);
+ printf("    <member type='way' ref='%"Pindex_t"' role='to' />\n",relationp->to+1);
+
+ printf("  </relation>\n");
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out a tail in OSM XML format.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_tail_osm(void)
+{
+ printf("</osm>\n");
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the contents of a node from the routing database (in visualiser format).
+
+  Nodes *nodes The set of nodes to use.
+
+  index_t item The node index to print.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_node_visualiser(Nodes *nodes,index_t item)
+{
+ Node *nodep=LookupNode(nodes,item,1);
+ double latitude,longitude;
+ int i;
+
+ GetLatLong(nodes,item,nodep,&latitude,&longitude);
+
+ if(nodep->allow==Transports_ALL && nodep->flags==0)
+    printf("<routino:node id='%"Pindex_t"' lat='%.7f' lon='%.7f' />\n",item+1,radians_to_degrees(latitude),radians_to_degrees(longitude));
+ else
+   {
+    printf("<routino:node id='%"Pindex_t"' lat='%.7f' lon='%.7f'>\n",item+1,radians_to_degrees(latitude),radians_to_degrees(longitude));
+
+    if(nodep->flags & NODE_SUPER)
+       printf("   <tag k='routino:super' v='yes' />\n");
+
+    if(nodep->flags & NODE_UTURN)
+       printf("   <tag k='routino:uturn' v='yes' />\n");
+
+    if(nodep->flags & NODE_MINIRNDBT)
+       printf("   <tag k='junction' v='roundabout' />\n");
+
+    if(nodep->flags & NODE_TURNRSTRCT)
+       printf("   <tag k='routino:turnrestriction' v='yes' />\n");
+
+    for(i=1;i<Transport_Count;i++)
+       if(!(nodep->allow & TRANSPORTS(i)))
+          printf("   <tag k='%s' v='no' />\n",TransportName(i));
+
+    printf("</routino:node>\n");
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the contents of a segment from the routing database (as a way in visualiser format).
+
+  Segments *segments The set of segments to use.
+
+  index_t item The segment index to print.
+
+  Ways *ways The set of ways to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_segment_visualiser(Segments *segments,index_t item,Ways *ways)
+{
+ Segment *segmentp=LookupSegment(segments,item,1);
+ Way *wayp=LookupWay(ways,segmentp->way,1);
+ char *name=WayName(ways,wayp);
+ int i;
+
+ printf("<routino:way id='%"Pindex_t"'>\n",item+1);
+
+ if(IsOnewayTo(segmentp,segmentp->node1))
+   {
+    printf("   <nd ref='%"Pindex_t"' />\n",segmentp->node2+1);
+    printf("   <nd ref='%"Pindex_t"' />\n",segmentp->node1+1);
+   }
+ else
+   {
+    printf("   <nd ref='%"Pindex_t"' />\n",segmentp->node1+1);
+    printf("   <nd ref='%"Pindex_t"' />\n",segmentp->node2+1);
+   }
+
+ if(IsSuperSegment(segmentp))
+    printf("   <tag k='routino:super' v='yes' />\n");
+ if(IsNormalSegment(segmentp))
+    printf("   <tag k='routino:normal' v='yes' />\n");
+
+ printf("   <tag k='routino:distance' v='%.3f km' />\n",distance_to_km(DISTANCE(segmentp->distance)));
+
+ if(wayp->type & Highway_OneWay)
+    printf("   <tag k='oneway' v='yes' />\n");
+
+ if(wayp->type & Highway_CycleBothWays)
+    printf("   <tag k='cyclebothways' v='yes' />\n");
+
+ if(wayp->type & Highway_Roundabout)
+    printf("   <tag k='roundabout' v='yes' />\n");
+
+ printf("   <tag k='highway' v='%s' />\n",HighwayName(HIGHWAY(wayp->type)));
+
+ if(IsNormalSegment(segmentp) && *name)
+    printf("   <tag k='name' v='%s' />\n",ParseXML_Encode_Safe_XML(name));
+
+ for(i=1;i<Transport_Count;i++)
+    if(wayp->allow & TRANSPORTS(i))
+       printf("   <tag k='%s' v='yes' />\n",TransportName(i));
+
+ for(i=1;i<Property_Count;i++)
+    if(wayp->props & PROPERTIES(i))
+       printf("   <tag k='%s' v='yes' />\n",PropertyName(i));
+
+ if(wayp->speed)
+    printf("   <tag k='maxspeed' v='%d kph' />\n",speed_to_kph(wayp->speed));
+
+ if(wayp->weight)
+    printf("   <tag k='maxweight' v='%.1f t' />\n",weight_to_tonnes(wayp->weight));
+ if(wayp->height)
+    printf("   <tag k='maxheight' v='%.1f m' />\n",height_to_metres(wayp->height));
+ if(wayp->width)
+    printf("   <tag k='maxwidth' v='%.1f m' />\n",width_to_metres(wayp->width));
+ if(wayp->length)
+    printf("   <tag k='maxlength' v='%.1f m' />\n",length_to_metres(wayp->length));
+
+ printf("</routino:way>\n");
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the contents of a turn relation from the routing database (in visualiser format).
+
+  Relations *relations The set of relations to use.
+
+  index_t item The relation index to print.
+
+  Segments *segments The set of segments to use.
+
+  Nodes *nodes The set of nodes to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_turn_relation_visualiser(Relations *relations,index_t item,Segments *segments,Nodes *nodes)
+{
+ TurnRelation *relationp=LookupTurnRelation(relations,item,1);
+
+ Segment *segmentp_from=LookupSegment(segments,relationp->from,1);
+ Segment *segmentp_to  =LookupSegment(segments,relationp->to  ,2);
+
+ double angle=TurnAngle(nodes,segmentp_from,segmentp_to,relationp->via);
+
+ char *restriction;
+
+ if(angle>150 || angle<-150)
+    restriction="no_u_turn";
+ else if(angle>30)
+    restriction="no_right_turn";
+ else if(angle<-30)
+    restriction="no_left_turn";
+ else
+    restriction="no_straight_on";
+
+ printf("<routino:relation id='%"Pindex_t"'>\n",item+1);
+ printf("   <tag k='type' v='restriction' />\n");
+ printf("   <tag k='restriction' v='%s'/>\n",restriction);
+
+ if(relationp->except)
+    printf("   <tag k='except' v='%s' />\n",AllowedNameList(relationp->except));
+
+ printf("   <member type='way' ref='%"Pindex_t"' role='from' />\n",relationp->from+1);
+ printf("   <member type='node' ref='%"Pindex_t"' role='via' />\n",relationp->via+1);
+ printf("   <member type='way' ref='%"Pindex_t"' role='to' />\n",relationp->to+1);
+
+ printf("</routino:relation>\n");
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out an error log entry from the database (in visualiser format).
+
+  ErrorLogs *errorlogs The set of error logs to use.
+
+  index_t item The error log index to print.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_errorlog_visualiser(ErrorLogs *errorlogs,index_t item)
+{
+ char *string=LookupErrorLogString(errorlogs,item);
+
+ printf("%s\n",ParseXML_Encode_Safe_XML(string));
+}
+
+
+/*+ Conversion from time_t to date string (day of week). +*/
+static const char* const weekdays[7]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
+
+/*+ Conversion from time_t to date string (month of year). +*/
+static const char* const months[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Convert the time into an RFC 822 compliant date.
+
+  char *RFC822Date Returns a pointer to a fixed string containing the date.
+
+  time_t t The time.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static char *RFC822Date(time_t t)
+{
+ static char value[32]; /* static allocation of return value */
+ char weekday[4];
+ char month[4];
+ struct tm *tim;
+
+ tim=gmtime(&t);
+
+ strcpy(weekday,weekdays[tim->tm_wday]);
+ strcpy(month,months[tim->tm_mon]);
+
+ /* Sun, 06 Nov 1994 08:49:37 GMT    ; RFC 822, updated by RFC 1123 */
+
+ sprintf(value,"%3s, %02d %3s %4d %02d:%02d:%02d %s",
+         weekday,
+         tim->tm_mday,
+         month,
+         tim->tm_year+1900,
+         tim->tm_hour,
+         tim->tm_min,
+         tim->tm_sec,
+         "GMT"
+         );
+
+ return(value);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the usage information.
+
+  int detail The level of detail to use - 0 = low, 1 = high.
+
+  const char *argerr The argument that gave the error (if there is one).
+
+  const char *err Other error message (if there is one).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_usage(int detail,const char *argerr,const char *err)
+{
+ fprintf(stderr,
+         "Usage: filedumper [--help]\n"
+         "                  [--dir=<dirname>] [--prefix=<name>]\n"
+         "                  [--statistics]\n"
+         "                  [--visualiser --latmin=<latmin> --latmax=<latmax>\n"
+         "                                --lonmin=<lonmin> --lonmax=<lonmax>\n"
+         "                                --data=<data-type>]\n"
+         "                  [--dump [--node=<node> ...]\n"
+         "                          [--segment=<segment> ...]\n"
+         "                          [--way=<way> ...]\n"
+         "                          [--turn-relation=<rel> ...]\n"
+         "                          [--errorlog=<number> ...]]\n"
+         "                  [--dump-osm [--no-super]\n"
+         "                              [--latmin=<latmin> --latmax=<latmax>\n"
+         "                               --lonmin=<lonmin> --lonmax=<lonmax>]]\n"
+         "                  [--dump-visualiser [--data=node<node>]\n"
+         "                                     [--data=segment<segment>]\n"
+         "                                     [--data=turn-relation<rel>]\n"
+         "                                     [--data=errorlog<number>]]\n");
+
+ if(argerr)
+    fprintf(stderr,
+            "\n"
+            "Error with command line parameter: %s\n",argerr);
+
+ if(err)
+    fprintf(stderr,
+            "\n"
+            "Error: %s\n",err);
+
+ if(detail)
+    fprintf(stderr,
+            "\n"
+            "--help                    Prints this information.\n"
+            "\n"
+            "--dir=<dirname>           The directory containing the routing database.\n"
+            "--prefix=<name>           The filename prefix for the routing database.\n"
+            "\n"
+            "--statistics              Print statistics about the routing database.\n"
+            "\n"
+            "--visualiser              Extract selected data from the routing database:\n"
+            "  --latmin=<latmin>       * the minimum latitude (degrees N).\n"
+            "  --latmax=<latmax>       * the maximum latitude (degrees N).\n"
+            "  --lonmin=<lonmin>       * the minimum longitude (degrees E).\n"
+            "  --lonmax=<lonmax>       * the maximum longitude (degrees E).\n"
+            "  --data=<data-type>      * the type of data to select.\n"
+            "\n"
+            "  <data-type> can be selected from:\n"
+            "      junctions   = segment count at each junction.\n"
+            "      super       = super-node and super-segments.\n"
+            "      waytype-*   = segments of oneway, cyclebothways or roundabout type.\n"
+            "      highway-*   = segments of the specified highway type.\n"
+            "      transport-* = segments allowing the specified transport type.\n"
+            "      barrier-*   = nodes disallowing the specified transport type.\n"
+            "      turns       = turn restrictions.\n"
+            "      speed       = speed limits.\n"
+            "      weight      = weight limits.\n"
+            "      height      = height limits.\n"
+            "      width       = width limits.\n"
+            "      length      = length limits.\n"
+            "      property-*  = segments with the specified property.\n"
+            "      errorlogs   = errors logged during parsing.\n"
+            "\n"
+            "--dump                    Dump selected contents of the database.\n"
+            "  --node=<node>             * the node with the selected index.\n"
+            "  --segment=<segment>       * the segment with the selected index.\n"
+            "  --way=<way>               * the way with the selected index.\n"
+            "  --turn-relation=<rel>     * the turn relation with the selected index.\n"
+            "  --errorlog=<number>       * the error log with the selected index.\n"
+            "                          Use 'all' instead of a number to get all of them.\n"
+            "\n"
+            "--dump-osm                Dump all or part of the database as an XML file.\n"
+            "  --no-super                * exclude the super-segments.\n"
+            "  --latmin=<latmin>         * the minimum latitude (degrees N).\n"
+            "  --latmax=<latmax>         * the maximum latitude (degrees N).\n"
+            "  --lonmin=<lonmin>         * the minimum longitude (degrees E).\n"
+            "  --lonmax=<lonmax>         * the maximum longitude (degrees E).\n"
+            "\n"
+            "--dump-visualiser         Dump selected contents of the database in HTML.\n"
+            "  --data=node<node>         * the node with the selected index.\n"
+            "  --data=segment<segment>   * the segment with the selected index.\n"
+            "  --data=turn-relation<rel> * the turn relation with the selected index.\n"
+            "  --data=errorlog<number>   * the error log with the selected index.\n");
+
+ exit(!detail);
+}
diff --git a/3rdparty/Routino/src/filedumperx.c b/3rdparty/Routino/src/filedumperx.c
new file mode 100644
index 0000000..56c1789
--- /dev/null
+++ b/3rdparty/Routino/src/filedumperx.c
@@ -0,0 +1,330 @@
+/***************************************
+ Memory file dumper for the intermediate files containing parsed data.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "typesx.h"
+#include "nodesx.h"
+#include "waysx.h"
+#include "relationsx.h"
+
+#include "files.h"
+#include "sorting.h"
+
+
+/* Local functions */
+
+static void print_nodes(const char *filename);
+static void print_ways(const char *filename);
+static void print_route_relations(const char *filename);
+static void print_turn_relations(const char *filename);
+
+static void print_usage(int detail,const char *argerr,const char *err);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The main program for the file dumper.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int main(int argc,char** argv)
+{
+ int   arg;
+ char *dirname=NULL,*prefix=NULL;
+ char *nodes_filename,*ways_filename,*route_relations_filename,*turn_relations_filename;
+ int   option_dump;
+
+ /* Parse the command line arguments */
+
+ for(arg=1;arg<argc;arg++)
+   {
+    if(!strcmp(argv[arg],"--help"))
+       print_usage(1,NULL,NULL);
+    else if(!strncmp(argv[arg],"--dir=",6))
+       dirname=&argv[arg][6];
+    else if(!strncmp(argv[arg],"--prefix=",9))
+       prefix=&argv[arg][9];
+    else if(!strcmp(argv[arg],"--dump"))
+       option_dump=1;
+    else if(!strcmp(argv[arg],"--nodes"))
+       ;
+    else if(!strcmp(argv[arg],"--ways"))
+       ;
+    else if(!strcmp(argv[arg],"--route-relations"))
+       ;
+    else if(!strcmp(argv[arg],"--turn-relations"))
+       ;
+    else
+       print_usage(0,argv[arg],NULL);
+   }
+
+ if((option_dump)!=1)
+    print_usage(0,NULL,"Must choose --dump.");
+
+ /* Get the filenames. */
+
+ nodes_filename=FileName(dirname,prefix,"nodesx.parsed.mem");
+
+ ways_filename=FileName(dirname,prefix,"waysx.parsed.mem");
+
+ route_relations_filename=FileName(dirname,prefix,"relationsx.route.parsed.mem");
+
+ turn_relations_filename=FileName(dirname,prefix,"relationsx.turn.parsed.mem");
+
+ /* Print out internal data (in plain text format) */
+
+ if(option_dump)
+   {
+    for(arg=1;arg<argc;arg++)
+       if(!strcmp(argv[arg],"--nodes"))
+         {
+          print_nodes(nodes_filename);
+         }
+       else if(!strcmp(argv[arg],"--ways"))
+         {
+          print_ways(ways_filename);
+         }
+       else if(!strcmp(argv[arg],"--route-relations"))
+         {
+          print_route_relations(route_relations_filename);
+         }
+       else if(!strcmp(argv[arg],"--turn-relations"))
+         {
+          print_turn_relations(turn_relations_filename);
+         }
+   }
+
+ exit(EXIT_SUCCESS);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out all of the nodes.
+
+  const char *filename The name of the file containing the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_nodes(const char *filename)
+{
+ int fd;
+ NodeX nodex;
+
+ fd=ReOpenFileBuffered(filename);
+
+ while(!ReadFileBuffered(fd,&nodex,sizeof(NodeX)))
+   {
+    printf("Node %"Pnode_t"\n",nodex.id);
+    printf("  lat=%d lon=%d\n",nodex.latitude,nodex.longitude);
+    printf("  allow=%02x\n",nodex.allow);
+    printf("  flags=%02x\n",nodex.flags);
+   }
+
+ CloseFileBuffered(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out all of the ways.
+
+  const char *filename The name of the file containing the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_ways(const char *filename)
+{
+ FILESORT_VARINT waysize;
+ int fd;
+
+ fd=ReOpenFileBuffered(filename);
+
+ while(!ReadFileBuffered(fd,&waysize,FILESORT_VARSIZE))
+   {
+    WayX wayx;
+    node_t node;
+    char *name=NULL;
+    size_t malloced=0;
+    int first=1;
+
+    ReadFileBuffered(fd,&wayx,sizeof(WayX));
+
+    printf("Way %"Pway_t"\n",wayx.id);
+
+    while(!ReadFileBuffered(fd,&node,sizeof(node_t)) && node!=NO_NODE_ID)
+      {
+       if(first)
+          printf("  nodes=%"Pnode_t,node);
+       else
+          printf(",%"Pnode_t,node);
+
+       waysize-=sizeof(node_t);
+
+       first=0;
+      }
+
+    printf("\n");
+
+    waysize-=sizeof(node_t)+sizeof(WayX);
+
+    if(malloced<waysize)
+      {
+       malloced=waysize;
+       name=(char*)realloc((void*)name,malloced);
+      }
+
+    ReadFileBuffered(fd,name,waysize);
+
+    if(*name)
+       printf("  name=%s\n",name);
+    printf("  type=%02x\n",wayx.way.type);
+    printf("  allow=%02x\n",wayx.way.allow);
+    if(wayx.way.props)
+       printf("  props=%02x\n",wayx.way.props);
+    if(wayx.way.speed)
+       printf("  speed=%d\n",wayx.way.speed);
+    if(wayx.way.weight)
+       printf("  weight=%d\n",wayx.way.weight);
+    if(wayx.way.height)
+       printf("  height=%d\n",wayx.way.height);
+    if(wayx.way.width)
+       printf("  width=%d\n",wayx.way.width);
+    if(wayx.way.length)
+       printf("  length=%d\n",wayx.way.length);
+   }
+
+ CloseFileBuffered(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out all of the route relations.
+
+  const char *filename The name of the file containing the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_route_relations(const char *filename)
+{
+ FILESORT_VARINT relationsize;
+ int fd;
+
+ fd=ReOpenFileBuffered(filename);
+
+ while(!ReadFileBuffered(fd,&relationsize,FILESORT_VARSIZE))
+   {
+    RouteRelX relationx;
+    node_t nodeid;
+    way_t wayid;
+    relation_t relationid;
+
+    ReadFileBuffered(fd,&relationx,sizeof(RouteRelX));
+
+    printf("Relation %"Prelation_t"\n",relationx.id);
+    printf("  routes=%02x\n",relationx.routes);
+
+    while(!ReadFileBuffered(fd,&nodeid,sizeof(node_t)) && nodeid!=NO_NODE_ID)
+       printf("  node=%"Pnode_t"\n",nodeid);
+
+    while(!ReadFileBuffered(fd,&wayid,sizeof(way_t)) && wayid!=NO_WAY_ID);
+       printf("  way=%"Pway_t"\n",wayid);
+
+    while(!ReadFileBuffered(fd,&relationid,sizeof(relation_t)) && relationid!=NO_RELATION_ID);
+       printf("  relation=%"Prelation_t"\n",relationid);
+   }
+
+ CloseFileBuffered(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out all of the turn relations.
+
+  const char *filename The name of the file containing the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_turn_relations(const char *filename)
+{
+ int fd;
+ TurnRelX relationx;
+
+ fd=ReOpenFileBuffered(filename);
+
+ while(!ReadFileBuffered(fd,&relationx,sizeof(TurnRelX)))
+   {
+    printf("Relation %"Prelation_t"\n",relationx.id);
+    printf("  from=%"Pway_t"\n",relationx.from);
+    printf("  via=%"Pnode_t"\n",relationx.via);
+    printf("  to=%"Pway_t"\n",relationx.to);
+    printf("  type=%d\n",relationx.restriction);
+    if(relationx.except)
+       printf("  except=%02x\n",relationx.except);
+   }
+
+ CloseFileBuffered(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the usage information.
+
+  int detail The level of detail to use - 0 = low, 1 = high.
+
+  const char *argerr The argument that gave the error (if there is one).
+
+  const char *err Other error message (if there is one).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_usage(int detail,const char *argerr,const char *err)
+{
+ fprintf(stderr,
+         "Usage: filedumperx [--help]\n"
+         "                   [--dir=<dirname>] [--prefix=<name>]\n"
+         "                   [--dump [--nodes]\n"
+         "                           [--ways]\n"
+         "                           [--route-relations]\n"
+         "                           [--turn-relations]]\n");
+
+ if(argerr)
+    fprintf(stderr,
+            "\n"
+            "Error with command line parameter: %s\n",argerr);
+
+ if(err)
+    fprintf(stderr,
+            "\n"
+            "Error: %s\n",err);
+
+ if(detail)
+    fprintf(stderr,
+            "\n"
+            "--help                    Prints this information.\n"
+            "\n"
+            "--dir=<dirname>           The directory containing the routing database.\n"
+            "--prefix=<name>           The filename prefix for the routing database.\n"
+            "\n"
+            "--dump                    Dump the intermediate files after parsing.\n"
+            "  --nodes                 * all of the nodes.\n"
+            "  --ways                  * all of the ways.\n"
+            "  --route-relations       * all of the route relations.\n"
+            "  --turn-relations        * all of the turn relations.\n");
+
+ exit(!detail);
+}
diff --git a/3rdparty/Routino/src/files.c b/3rdparty/Routino/src/files.c
new file mode 100644
index 0000000..a1cc97a
--- /dev/null
+++ b/3rdparty/Routino/src/files.c
@@ -0,0 +1,1081 @@
+/***************************************
+ Functions to handle files.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#if defined(_MSC_VER)
+#include <io.h>
+typedef unsigned __int64  ssize_t;
+#define read(fd,address,length)  _read(fd,address,(unsigned int)(length))
+#define write(fd,address,length) _write(fd,address,(unsigned int)(length))
+#define lseek       _lseeki64
+#define open        _open
+#define close       _close
+#define unlink      _unlink
+#else
+#include <unistd.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#include "mman-win32.h"
+#else
+#include <sys/mman.h>
+#endif
+
+#include <sys/types.h>
+
+#include "files.h"
+
+
+/*+ A structure to contain the list of memory mapped files. +*/
+struct mmapinfo
+{
+ const char  *filename;         /*+ The name of the file (the index of the list). +*/
+       int    fd;               /*+ The file descriptor used when it was opened. +*/
+       char  *address;          /*+ The address the file was mapped to. +*/
+       size_t length;           /*+ The length of the file. +*/
+};
+
+/*+ The list of memory mapped files. +*/
+static struct mmapinfo *mappedfiles;
+
+/*+ The number of mapped files. +*/
+static int nmappedfiles=0;
+
+
+#define BUFFLEN 4096
+
+/*+ A structure to contain the list of file buffers. +*/
+struct filebuffer
+{
+ char   buffer[BUFFLEN];        /*+ The data buffer. +*/
+ size_t pointer;                /*+ The read/write pointer for the file buffer. +*/
+ size_t length;                 /*+ The read pointer for the file buffer. +*/
+ int    reading;                /*+ A flag to indicate if the file is for reading. +*/
+};
+
+/*+ The list of file buffers. +*/
+static struct filebuffer **filebuffers=NULL;
+
+/*+ The number of allocated file buffer pointers. +*/
+static int nfilebuffers=0;
+
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+
+/*+ A structure to contain the list of opened files to record which are to be deleted when closed. +*/
+struct openedfile
+{
+ const char *filename;          /*+ The name of the file. +*/
+       int   delete;            /*+ Set to non-zero value if the file is to be deleted when closed. +*/
+};
+
+/*+ The list of opened files. +*/
+static struct openedfile **openedfiles=NULL;
+
+/*+ The number of allocated opened file buffer pointers. +*/
+static int nopenedfiles=0;
+
+#endif
+
+
+/* Local functions */
+
+static void CreateFileBuffer(int fd,int read_write);
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+
+static void CreateOpenedFile(int fd,const char *filename);
+
+#endif
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Return a filename composed of the dirname, prefix and name.
+
+  char *FileName Returns a pointer to memory allocated to the filename.
+
+  const char *dirname The directory name.
+
+  const char *prefix The file prefix.
+
+  const char *name The main part of the name.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+char *FileName(const char *dirname,const char *prefix, const char *name)
+{
+ char *filename=(char*)malloc((dirname?strlen(dirname):0)+1+(prefix?strlen(prefix):0)+1+strlen(name)+1);
+
+ sprintf(filename,"%s%s%s%s%s",dirname?dirname:"",dirname?"/":"",prefix?prefix:"",prefix?"-":"",name);
+
+ return(filename);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Open a file read-only and map it into memory.
+
+  void *MapFile Returns the address of the file or exits in case of an error.
+
+  const char *filename The name of the file to open.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void *MapFile(const char *filename)
+{
+ int fd;
+ struct stat buf;
+ off_t size;
+ void *address;
+
+ /* Open the file */
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ fd=open(filename,O_RDONLY|O_BINARY);
+#else
+ fd=open(filename,O_RDONLY);
+#endif
+
+ if(fd<0)
+   {
+#ifdef LIBROUTINO
+    return(NULL);
+#else
+    fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",filename,strerror(errno));
+    exit(EXIT_FAILURE);
+#endif
+   }
+
+ /* Get its size */
+
+ if(stat(filename,&buf))
+   {
+#ifdef LIBROUTINO
+    return(NULL);
+#else
+    fprintf(stderr,"Cannot stat file '%s' [%s].\n",filename,strerror(errno));
+    exit(EXIT_FAILURE);
+#endif
+   }
+
+ size=buf.st_size;
+
+ /* Map the file */
+
+ address=mmap(NULL,size,PROT_READ,MAP_SHARED,fd,0);
+
+ if(address==MAP_FAILED)
+   {
+    close(fd);
+
+#ifdef LIBROUTINO
+    return(NULL);
+#else
+    fprintf(stderr,"Cannot mmap file '%s' for reading [%s].\n",filename,strerror(errno));
+    exit(EXIT_FAILURE);
+#endif
+   }
+
+#ifndef LIBROUTINO
+ log_mmap(size);
+#endif
+
+ /* Store the information about the mapped file */
+
+ mappedfiles=(struct mmapinfo*)realloc((void*)mappedfiles,(nmappedfiles+1)*sizeof(struct mmapinfo));
+
+ mappedfiles[nmappedfiles].filename=filename;
+ mappedfiles[nmappedfiles].fd=fd;
+ mappedfiles[nmappedfiles].address=address;
+ mappedfiles[nmappedfiles].length=size;
+
+ nmappedfiles++;
+
+ return(address);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Open a file read-write and map it into memory.
+
+  void *MapFileWriteable Returns the address of the file or exits in case of an error.
+
+  const char *filename The name of the file to open.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void *MapFileWriteable(const char *filename)
+{
+ int fd;
+ struct stat buf;
+ off_t size;
+ void *address;
+
+ /* Open the file */
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ fd=open(filename,O_RDWR|O_BINARY);
+#else
+ fd=open(filename,O_RDWR);
+#endif
+
+ if(fd<0)
+   {
+#ifdef LIBROUTINO
+    return(NULL);
+#else
+    fprintf(stderr,"Cannot open file '%s' for reading and writing [%s].\n",filename,strerror(errno));
+    exit(EXIT_FAILURE);
+#endif
+   }
+
+ /* Get its size */
+
+ if(stat(filename,&buf))
+   {
+#ifdef LIBROUTINO
+    return(NULL);
+#else
+    fprintf(stderr,"Cannot stat file '%s' [%s].\n",filename,strerror(errno));
+    exit(EXIT_FAILURE);
+#endif
+   }
+
+ size=buf.st_size;
+
+ /* Map the file */
+
+ address=mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
+
+ if(address==MAP_FAILED)
+   {
+    close(fd);
+
+#ifdef LIBROUTINO
+    return(NULL);
+#else
+    fprintf(stderr,"Cannot mmap file '%s' for reading and writing [%s].\n",filename,strerror(errno));
+    exit(EXIT_FAILURE);
+#endif
+   }
+
+#ifndef LIBROUTINO
+ log_mmap(size);
+#endif
+
+ /* Store the information about the mapped file */
+
+ mappedfiles=(struct mmapinfo*)realloc((void*)mappedfiles,(nmappedfiles+1)*sizeof(struct mmapinfo));
+
+ mappedfiles[nmappedfiles].filename=filename;
+ mappedfiles[nmappedfiles].fd=fd;
+ mappedfiles[nmappedfiles].address=address;
+ mappedfiles[nmappedfiles].length=size;
+
+ nmappedfiles++;
+
+ return(address);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Unmap a file and close it.
+
+  void *UnmapFile Returns NULL (for similarity to the MapFile function).
+
+  const void *address The address of the mapped file in memory.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void *UnmapFile(const void *address)
+{
+ int i;
+
+ for(i=0;i<nmappedfiles;i++)
+    if(mappedfiles[i].address==address)
+       break;
+
+ if(i==nmappedfiles)
+   {
+#ifdef LIBROUTINO
+    return(NULL);
+#else
+    fprintf(stderr,"The data at address %p was not mapped using MapFile().\n",address);
+    exit(EXIT_FAILURE);
+#endif
+   }
+
+ /* Close the file */
+
+ close(mappedfiles[i].fd);
+
+ /* Unmap the file */
+
+ munmap(mappedfiles[i].address,mappedfiles[i].length);
+
+#ifndef LIBROUTINO
+ log_munmap(mappedfiles[i].length);
+#endif
+
+ /* Shuffle the list of files */
+
+ nmappedfiles--;
+
+ if(nmappedfiles>i)
+    memmove(&mappedfiles[i],&mappedfiles[i+1],(nmappedfiles-i)*sizeof(struct mmapinfo));
+
+ return(NULL);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Open an existing file on disk for reading.
+
+  int SlimMapFile Returns the file descriptor if OK or exits in case of an error.
+
+  const char *filename The name of the file to open.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int SlimMapFile(const char *filename)
+{
+ int fd;
+
+ /* Open the file */
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ fd=open(filename,O_RDONLY|O_BINARY);
+#else
+ fd=open(filename,O_RDONLY);
+#endif
+
+ if(fd<0)
+   {
+#ifdef LIBROUTINO
+    return(-1);
+#else
+    fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",filename,strerror(errno));
+    exit(EXIT_FAILURE);
+#endif
+   }
+
+ CreateFileBuffer(fd,0);
+
+ return(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Open an existing file on disk for reading or writing.
+
+  int SlimMapFileWriteable Returns the file descriptor if OK or exits in case of an error.
+
+  const char *filename The name of the file to open.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int SlimMapFileWriteable(const char *filename)
+{
+ int fd;
+
+ /* Open the file */
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ fd=open(filename,O_RDWR|O_BINARY);
+#else
+ fd=open(filename,O_RDWR);
+#endif
+
+ if(fd<0)
+   {
+#ifdef LIBROUTINO
+    return(-1);
+#else
+    fprintf(stderr,"Cannot open file '%s' for reading and writing [%s].\n",filename,strerror(errno));
+    exit(EXIT_FAILURE);
+#endif
+   }
+
+ CreateFileBuffer(fd,0);
+
+ return(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Close a file on disk.
+
+  int SlimUnmapFile returns -1 (for similarity to the UnmapFile function).
+
+  int fd The file descriptor to close.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int SlimUnmapFile(int fd)
+{
+ close(fd);
+
+ return(-1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Open a new file on disk for writing (with buffering).
+
+  int OpenFileBufferedNew Returns the file descriptor if OK or exits in case of an error.
+
+  const char *filename The name of the file to create.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int OpenFileBufferedNew(const char *filename)
+{
+ int fd;
+
+ /* Open the file */
+
+#if defined(_MSC_VER)
+ fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY);
+#else
+#if defined(__MINGW32__)
+ fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,S_IRUSR|S_IWUSR);
+#else
+ fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC         ,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+#endif
+#endif
+
+ if(fd<0)
+   {
+#ifdef LIBROUTINO
+    return(-1);
+#else
+    fprintf(stderr,"Cannot open file '%s' for writing [%s].\n",filename,strerror(errno));
+    exit(EXIT_FAILURE);
+#endif
+   }
+
+ CreateFileBuffer(fd,-1);
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ CreateOpenedFile(fd,filename);
+#endif
+
+ return(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Open a new or existing file on disk for appending (with buffering).
+
+  int OpenFileBufferedAppend Returns the file descriptor if OK or exits in case of an error.
+
+  const char *filename The name of the file to create or open.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int OpenFileBufferedAppend(const char *filename)
+{
+ int fd;
+
+ /* Open the file */
+
+#if defined(_MSC_VER)
+ fd=open(filename,O_WRONLY|O_CREAT|O_APPEND|O_BINARY);
+#else
+#if defined(__MINGW32__)
+ fd=open(filename,O_WRONLY|O_CREAT|O_APPEND|O_BINARY,S_IRUSR|S_IWUSR);
+#else
+ fd=open(filename,O_WRONLY|O_CREAT|O_APPEND         ,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+#endif
+#endif
+
+ if(fd<0)
+   {
+#ifdef LIBROUTINO
+    return(-1);
+#else
+    fprintf(stderr,"Cannot open file '%s' for appending [%s].\n",filename,strerror(errno));
+    exit(EXIT_FAILURE);
+#endif
+   }
+
+ CreateFileBuffer(fd,-1);
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ CreateOpenedFile(fd,filename);
+#endif
+
+ return(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Open an existing file on disk for reading (with buffering).
+
+  int ReOpenFileBuffered Returns the file descriptor if OK or exits in case of an error.
+
+  const char *filename The name of the file to open.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int ReOpenFileBuffered(const char *filename)
+{
+ int fd;
+
+ /* Open the file */
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ fd=open(filename,O_RDONLY|O_BINARY);
+#else
+ fd=open(filename,O_RDONLY);
+#endif
+
+ if(fd<0)
+   {
+#ifdef LIBROUTINO
+    return(-1);
+#else
+    fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",filename,strerror(errno));
+    exit(EXIT_FAILURE);
+#endif
+   }
+
+ CreateFileBuffer(fd,1);
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ CreateOpenedFile(fd,filename);
+#endif
+
+ return(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Open an existing file on disk for reading (with buffering), delete
+  it and open a new file on disk for writing (with buffering).
+
+  int ReplaceFileBuffered Returns the file descriptor of the new writable file.
+
+  const char *filename The name of the file to open, delete and replace.
+
+  int *oldfd Returns the file descriptor of the old, readable file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int ReplaceFileBuffered(const char *filename,int *oldfd)
+{
+ int newfd;
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+
+ char *filename2;
+
+ filename2=strcpy(malloc(strlen(filename)+2),filename);
+ strcat(filename2,"2");
+
+ RenameFile(filename,filename2);
+
+ *oldfd=ReOpenFileBuffered(filename2);
+ 
+ DeleteFile(filename2);
+
+#else
+
+ *oldfd=ReOpenFileBuffered(filename);
+ 
+ DeleteFile(filename);
+
+#endif
+
+ newfd=OpenFileBufferedNew(filename);
+
+ return(newfd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Write data to a file descriptor (via a buffer).
+
+  int WriteFileBuffered Returns 0 if OK or something else in case of an error.
+
+  int fd The file descriptor to write to.
+
+  const void *address The address of the data to be written.
+
+  size_t length The length of data to write.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int WriteFileBuffered(int fd,const void *address,size_t length)
+{
+#ifndef LIBROUTINO
+ logassert(fd!=-1,"File descriptor is in error - report a bug");
+
+ logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
+
+ logassert(!filebuffers[fd]->reading,"File descriptor was not opened for writing - report a bug");
+#endif
+
+ /* Write the data */
+
+ if((filebuffers[fd]->pointer+length)>BUFFLEN)
+   {
+    if(write(fd,filebuffers[fd]->buffer,filebuffers[fd]->pointer)!=(ssize_t)filebuffers[fd]->pointer)
+       return(-1);
+
+    filebuffers[fd]->pointer=0;
+   }
+
+ if(length>=BUFFLEN)
+   {
+    if(write(fd,address,length)!=(ssize_t)length)
+       return(-1);
+
+    return(0);
+   }
+
+ memcpy(filebuffers[fd]->buffer+filebuffers[fd]->pointer,address,length);
+
+ filebuffers[fd]->pointer+=length;
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Read data from a file descriptor (via a buffer).
+
+  int ReadFileBuffered Returns 0 if OK or something else in case of an error.
+
+  int fd The file descriptor to read from.
+
+  void *address The address the data is to be read into.
+
+  size_t length The length of data to read.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int ReadFileBuffered(int fd,void *address,size_t length)
+{
+#ifndef LIBROUTINO
+ logassert(fd!=-1,"File descriptor is in error - report a bug");
+
+ logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
+
+ logassert(filebuffers[fd]->reading,"File descriptor was not opened for reading - report a bug");
+#endif
+
+ /* Read the data */
+
+ if((filebuffers[fd]->pointer+length)>filebuffers[fd]->length)
+    if(filebuffers[fd]->pointer<filebuffers[fd]->length)
+      {
+       memcpy(address,filebuffers[fd]->buffer+filebuffers[fd]->pointer,filebuffers[fd]->length-filebuffers[fd]->pointer);
+
+       address=(char*)address+filebuffers[fd]->length-filebuffers[fd]->pointer;
+       length-=filebuffers[fd]->length-filebuffers[fd]->pointer;
+
+       filebuffers[fd]->pointer=0;
+       filebuffers[fd]->length=0;
+      }
+
+ if(length>=BUFFLEN)
+   {
+    if(read(fd,address,length)!=(ssize_t)length)
+       return(-1);
+
+    return(0);
+   }
+
+ if(filebuffers[fd]->pointer==filebuffers[fd]->length)
+   {
+    ssize_t len=read(fd,filebuffers[fd]->buffer,BUFFLEN);
+
+    if(len<=0)
+       return(-1);
+
+    filebuffers[fd]->length=len;
+    filebuffers[fd]->pointer=0;
+   }
+
+ if(filebuffers[fd]->length==0)
+    return(-1);
+
+ memcpy(address,filebuffers[fd]->buffer+filebuffers[fd]->pointer,length);
+
+ filebuffers[fd]->pointer+=length;
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Seek to a position in a file descriptor that uses a buffer.
+
+  int SeekFileBuffered Returns 0 if OK or something else in case of an error.
+
+  int fd The file descriptor to seek within.
+
+  off_t position The position to seek to.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int SeekFileBuffered(int fd,off_t position)
+{
+#ifndef LIBROUTINO
+ logassert(fd!=-1,"File descriptor is in error - report a bug");
+
+ logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
+#endif
+
+ /* Seek the data - doesn't need to be highly optimised */
+
+ if(!filebuffers[fd]->reading)
+    if(write(fd,filebuffers[fd]->buffer,filebuffers[fd]->pointer)!=(ssize_t)filebuffers[fd]->pointer)
+       return(-1);
+
+ filebuffers[fd]->pointer=0;
+ filebuffers[fd]->length=0;
+
+ if(lseek(fd,position,SEEK_SET)!=position)
+    return(-1);
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Skip forward by an offset in a file descriptor that uses a buffer.
+
+  int SkipFileBuffered Returns 0 if OK or something else in case of an error.
+
+  int fd The file descriptor to skip within.
+
+  off_t skip The amount to skip forward.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int SkipFileBuffered(int fd,off_t skip)
+{
+#ifndef LIBROUTINO
+ logassert(fd!=-1,"File descriptor is in error - report a bug");
+
+ logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
+
+ logassert(filebuffers[fd]->reading,"File descriptor was not opened for reading - report a bug");
+#endif
+
+ /* Skip the data - needs to be optimised */
+
+ if((filebuffers[fd]->pointer+skip)>filebuffers[fd]->length)
+   {
+    skip-=(off_t)(filebuffers[fd]->length-filebuffers[fd]->pointer);
+
+    filebuffers[fd]->pointer=0;
+    filebuffers[fd]->length=0;
+
+    if(lseek(fd,skip,SEEK_CUR)==-1)
+       return(-1);
+   }
+ else
+    filebuffers[fd]->pointer+=skip;
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Get the size of a file.
+
+  off_t SizeFile Returns the file size if OK or exits in case of an error.
+
+  const char *filename The name of the file to check.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+off_t SizeFile(const char *filename)
+{
+ struct stat buf;
+
+ if(stat(filename,&buf))
+   {
+#ifdef LIBROUTINO
+    return(-1);
+#else
+    fprintf(stderr,"Cannot stat file '%s' [%s].\n",filename,strerror(errno));
+    exit(EXIT_FAILURE);
+#endif
+   }
+
+ return(buf.st_size);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Get the size of a file from a file descriptor.
+
+  off_t SizeFileFD Returns the file size if OK or exits in case of an error.
+
+  int fd The file descriptor to check.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+off_t SizeFileFD(int fd)
+{
+ struct stat buf;
+
+ if(fstat(fd,&buf))
+   {
+#ifdef LIBROUTINO
+    return(-1);
+#else
+    fprintf(stderr,"Cannot stat file descriptor '%d' [%s].\n",fd,strerror(errno));
+    exit(EXIT_FAILURE);
+#endif
+   }
+
+ return(buf.st_size);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Check if a file exists.
+
+  int ExistsFile Returns 1 if the file exists and 0 if not.
+
+  const char *filename The name of the file to check.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int ExistsFile(const char *filename)
+{
+ struct stat buf;
+
+ if(stat(filename,&buf))
+    return(0);
+ else
+    return(1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Close a file on disk (and flush the buffer).
+
+  int CloseFileBuffered returns -1 (for similarity to the *OpenFileBuffered* functions).
+
+  int fd The file descriptor to close.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int CloseFileBuffered(int fd)
+{
+#ifndef LIBROUTINO
+ logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
+#endif
+
+ if(!filebuffers[fd]->reading)
+    if(write(fd,filebuffers[fd]->buffer,filebuffers[fd]->pointer)!=(ssize_t)filebuffers[fd]->pointer)
+       return(-1);
+
+ close(fd);
+
+ free(filebuffers[fd]);
+ filebuffers[fd]=NULL;
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+
+#ifndef LIBROUTINO
+ logassert(fd<nopenedfiles && openedfiles[fd],"File descriptor has no record of opening - report a bug");
+#endif
+
+ if(openedfiles[fd]->delete)
+    unlink(openedfiles[fd]->filename);
+
+ free(openedfiles[fd]);
+ openedfiles[fd]=NULL;
+
+#endif
+
+ return(-1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Open an existing file on disk for reading (in a simple mode).
+
+  int OpenFile Returns the file descriptor if OK or exits in case of an error.
+
+  const char *filename The name of the file to open.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int OpenFile(const char *filename)
+{
+ int fd;
+
+ /* Open the file */
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ fd=open(filename,O_RDONLY|O_BINARY);
+#else
+ fd=open(filename,O_RDONLY);
+#endif
+
+ if(fd<0)
+   {
+#ifdef LIBROUTINO
+    return(-1);
+#else
+    fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",filename,strerror(errno));
+    exit(EXIT_FAILURE);
+#endif
+   }
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ CreateOpenedFile(fd,filename);
+#endif
+
+ return(fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Close a file on disk (that was opened in simple mode).
+
+  int fd The file descriptor to close.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void CloseFile(int fd)
+{
+ close(fd);
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+
+#ifndef LIBROUTINO
+ logassert(fd<nopenedfiles && openedfiles[fd],"File descriptor has no record of opening - report a bug");
+#endif
+
+ if(openedfiles[fd]->delete)
+    unlink(openedfiles[fd]->filename);
+
+ free(openedfiles[fd]);
+ openedfiles[fd]=NULL;
+
+#endif
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Delete a file from disk.
+
+  int DeleteFile Returns 0 if OK.
+
+  const char *filename The name of the file to delete.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int DeleteFile(const char *filename)
+{
+#if defined(_MSC_VER) || defined(__MINGW32__)
+
+ int fd;
+
+ for(fd=0;fd<nopenedfiles;fd++)
+    if(openedfiles[fd] && !strcmp(openedfiles[fd]->filename,filename))
+      {
+       openedfiles[fd]->delete=1;
+       return(0);
+      }
+
+#endif
+
+ unlink(filename);
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Rename a file on disk.
+
+  int RenameFile Returns 0 if OK.
+
+  const char *oldfilename The old name of the file before renaming.
+
+  const char *newfilename The new name of the file after renaming.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int RenameFile(const char *oldfilename,const char *newfilename)
+{
+ rename(oldfilename,newfilename);
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create a file buffer.
+
+  int fd The file descriptor.
+
+  int read_write A flag set to 1 for reading, -1 for writing and 0 for unbuffered.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void CreateFileBuffer(int fd,int read_write)
+{
+ if(nfilebuffers<=fd)
+   {
+    int i;
+
+    filebuffers=(struct filebuffer**)realloc((void*)filebuffers,(fd+1)*sizeof(struct filebuffer*));
+
+    for(i=nfilebuffers;i<=fd;i++)
+       filebuffers[i]=NULL;
+
+    nfilebuffers=fd+1;
+   }
+
+ if(read_write)
+   {
+    filebuffers[fd]=(struct filebuffer*)calloc(sizeof(struct filebuffer),1);
+
+    filebuffers[fd]->reading=(read_write==1);
+   }
+}
+
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create an opened file record.
+
+  int fd The file descriptor.
+
+  const char *filename The name of the file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void CreateOpenedFile(int fd,const char *filename)
+{
+ if(nopenedfiles<=fd)
+   {
+    int i;
+
+    openedfiles=(struct openedfile**)realloc((void*)openedfiles,(fd+1)*sizeof(struct openedfile*));
+
+    for(i=nopenedfiles;i<=fd;i++)
+       openedfiles[i]=NULL;
+
+    nopenedfiles=fd+1;
+   }
+
+ openedfiles[fd]=(struct openedfile*)calloc(sizeof(struct openedfile),1);
+
+ openedfiles[fd]->filename=strcpy(malloc(strlen(filename)+1),filename);
+ openedfiles[fd]->delete=0;
+}
+
+#endif
diff --git a/3rdparty/Routino/src/files.h b/3rdparty/Routino/src/files.h
new file mode 100644
index 0000000..6a397a4
--- /dev/null
+++ b/3rdparty/Routino/src/files.h
@@ -0,0 +1,173 @@
+/***************************************
+ Header file for file function prototypes
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef FILES_H
+#define FILES_H    /*+ To stop multiple inclusions. +*/
+
+/* If your system does not have the pread() and pwrite() system calls then you
+ * will need to change this line to the value 0 so that seek() and
+ * read()/write() are used instead of pread()/pwrite(). */
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define HAVE_PREAD_PWRITE 0
+#else
+#define HAVE_PREAD_PWRITE 1
+#endif
+
+#if defined(_MSC_VER)
+#include <io.h>
+#define read(fd,address,length)  _read(fd,address,(unsigned int)(length))
+#define write(fd,address,length) _write(fd,address,(unsigned int)(length))
+#define lseek       _lseeki64
+#else
+#include <unistd.h>
+#endif
+
+#include <sys/types.h>
+
+#include "logging.h"
+
+
+/* Functions in files.c */
+
+char *FileName(const char *dirname,const char *prefix, const char *name);
+
+void *MapFile(const char *filename);
+void *MapFileWriteable(const char *filename);
+
+void *UnmapFile(const void *address);
+
+int SlimMapFile(const char *filename);
+int SlimMapFileWriteable(const char *filename);
+
+int SlimUnmapFile(int fd);
+
+int OpenFileBufferedNew(const char *filename);
+int OpenFileBufferedAppend(const char *filename);
+
+int ReOpenFileBuffered(const char *filename);
+
+int ReplaceFileBuffered(const char *filename,int *oldfd);
+
+int WriteFileBuffered(int fd,const void *address,size_t length);
+int ReadFileBuffered(int fd,void *address,size_t length);
+
+int SeekFileBuffered(int fd,off_t position);
+int SkipFileBuffered(int fd,off_t skip);
+
+int CloseFileBuffered(int fd);
+
+int OpenFile(const char *filename);
+
+void CloseFile(int fd);
+
+off_t SizeFile(const char *filename);
+off_t SizeFileFD(int fd);
+int ExistsFile(const char *filename);
+
+int DeleteFile(const char *filename);
+
+int RenameFile(const char *oldfilename,const char *newfilename);
+
+/* Functions in files.h */
+
+static inline int SlimReplace(int fd,const void *address,size_t length,off_t position);
+static inline int SlimFetch(int fd,void *address,size_t length,off_t position);
+
+
+/* Inline the frequently called functions */
+
+/*++++++++++++++++++++++++++++++++++++++
+  Write data to a file that has been opened for slim mode access.
+
+  int SlimReplace Returns 0 if OK or something else in case of an error.
+
+  int fd The file descriptor to write to.
+
+  const void *address The address of the data to be written.
+
+  size_t length The length of data to write.
+
+  off_t position The position in the file to seek to.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline int SlimReplace(int fd,const void *address,size_t length,off_t position)
+{
+ /* Seek and write the data */
+
+#if HAVE_PREAD_PWRITE
+
+ if(pwrite(fd,address,length,position)!=(ssize_t)length)
+    return(-1);
+
+#else
+
+ if(lseek(fd,position,SEEK_SET)!=position)
+    return(-1);
+
+ if(write(fd,address,length)!=(ssize_t)length)
+    return(-1);
+
+#endif
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Read data from a file that has been opened for slim mode access.
+
+  int SlimFetch Returns 0 if OK or something else in case of an error.
+
+  int fd The file descriptor to read from.
+
+  void *address The address the data is to be read into.
+
+  size_t length The length of data to read.
+
+  off_t position The position in the file to seek to.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline int SlimFetch(int fd,void *address,size_t length,off_t position)
+{
+ /* Seek and read the data */
+
+#if HAVE_PREAD_PWRITE
+
+ if(pread(fd,address,length,position)!=(ssize_t)length)
+    return(-1);
+
+#else
+
+ if(lseek(fd,position,SEEK_SET)!=position)
+    return(-1);
+
+ if(read(fd,address,length)!=(ssize_t)length)
+    return(-1);
+
+#endif
+
+ return(0);
+}
+
+
+#endif /* FILES_H */
diff --git a/3rdparty/Routino/src/functions.h b/3rdparty/Routino/src/functions.h
new file mode 100644
index 0000000..f80d644
--- /dev/null
+++ b/3rdparty/Routino/src/functions.h
@@ -0,0 +1,52 @@
+/***************************************
+ Header file for miscellaneous function prototypes
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef FUNCTIONS_H
+#define FUNCTIONS_H    /*+ To stop multiple inclusions. +*/
+
+#include "types.h"
+
+#include "profiles.h"
+#include "results.h"
+
+
+/* Functions in optimiser.c */
+
+Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t prev_segment,index_t finish_node);
+
+Results *FindMiddleRoute(Nodes *supernodes,Segments *supersegments,Ways *superways,Relations *relations,Profile *profile,Results *begin,Results *end);
+
+Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t prev_segment,index_t finish_node);
+
+Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t finish_node);
+
+Results *CombineRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,Results *begin,Results *middle,Results *end);
+
+void FixForwardRoute(Results *results,Result *finish_result);
+
+
+/* Functions in output.c */
+
+void PrintRoute(Results **results,int nresults,Nodes *nodes,Segments *segments,Ways *ways,Profile *profile);
+
+
+#endif /* FUNCTIONS_H */
diff --git a/3rdparty/Routino/src/logerror.c b/3rdparty/Routino/src/logerror.c
new file mode 100644
index 0000000..a0d4c30
--- /dev/null
+++ b/3rdparty/Routino/src/logerror.c
@@ -0,0 +1,223 @@
+/***************************************
+ Error logging functions
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2013, 2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include "typesx.h"
+
+#include "files.h"
+#include "logging.h"
+
+
+/* Global variables */
+
+/*+ The name of the error log file. +*/
+char *errorlogfilename=NULL;
+
+/*+ The name of the binary error log file. +*/
+char *errorbinfilename=NULL;
+
+
+/* Local variables (re-initialised by open_errorlog() function) */
+
+/*+ The file handle for the error log file. +*/
+static FILE *errorlogfile=NULL;
+
+/*+ The file descriptor for the binary error log file. +*/
+static int errorbinfile=-1;
+
+/*+ The offset of the error message in the error log file. +*/
+static off_t errorfileoffset=0;
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create the error log file.
+
+  const char *filename The name of the file to create.
+
+  int append The option to append to an existing file.
+
+  int bin The option to enable a binary log file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void open_errorlog(const char *filename,int append,int bin)
+{
+ /* Text log file */
+
+ errorlogfilename=(char*)malloc(strlen(filename)+8);
+
+ strcpy(errorlogfilename,filename);
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ errorlogfile=fopen(errorlogfilename,append?"ab":"wb");
+#else
+ errorlogfile=fopen(errorlogfilename,append?"a" :"w" );
+#endif
+
+ if(!errorlogfile)
+   {
+    fprintf(stderr,"Cannot open file '%s' for writing [%s].\n",errorlogfilename,strerror(errno));
+    exit(EXIT_FAILURE);
+   }
+
+ /* Binary log file */
+
+ if(bin)
+   {
+    errorbinfilename=(char*)malloc(strlen(filename)+8);
+
+    sprintf(errorbinfilename,"%s.tmp",filename);
+
+    errorfileoffset=0;
+
+    if(append)
+      {
+       if(ExistsFile(filename))
+          errorfileoffset=SizeFile(filename);
+
+       errorbinfile=OpenFileBufferedAppend(errorbinfilename);
+      }
+    else
+       errorbinfile=OpenFileBufferedNew(errorbinfilename);
+   }
+ else
+    errorbinfile=-1;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Close the error log file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void close_errorlog(void)
+{
+ if(errorlogfile)
+   {
+    fclose(errorlogfile);
+
+    if(errorbinfile!=-1)
+       CloseFileBuffered(errorbinfile);
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Log a message to the error log file.
+
+  const char *format The format string.
+
+  ... The other arguments.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void logerror(const char *format, ...)
+{
+ va_list ap;
+
+ if(!errorlogfile)
+    return;
+
+ va_start(ap,format);
+
+ errorfileoffset+=vfprintf(errorlogfile,format,ap);
+
+ va_end(ap);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Store the node information in the binary log file for this message.
+
+  node_t logerror_node Returns the node identifier.
+
+  node_t id The node identifier.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+node_t logerror_node(node_t id)
+{
+ if(errorbinfile!=-1)
+   {
+    ErrorLogObject error={0};
+
+    error.id=id;
+    error.type='N';
+
+    error.offset=errorfileoffset;
+
+    WriteFileBuffered(errorbinfile,&error,sizeof(ErrorLogObject));
+   }
+
+ return(id);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Store the way information in the binary log file for this message.
+
+  way_t logerror_way Returns the way identifier.
+
+  way_t id The way identifier.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+way_t logerror_way(way_t id)
+{
+ if(errorbinfile!=-1)
+   {
+    ErrorLogObject error={0};
+
+    error.id=id;
+    error.type='W';
+
+    error.offset=errorfileoffset;
+
+    WriteFileBuffered(errorbinfile,&error,sizeof(ErrorLogObject));
+   }
+
+ return(id);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Store the relation information in the binary log file for this message.
+
+  relation_t logerror_relation Returns the relation identifier.
+
+  relation_t id The relation identifier.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+relation_t logerror_relation(relation_t id)
+{
+ if(errorbinfile!=-1)
+   {
+    ErrorLogObject error={0};
+
+    error.id=id;
+    error.type='R';
+
+    error.offset=errorfileoffset;
+
+    WriteFileBuffered(errorbinfile,&error,sizeof(ErrorLogObject));
+   }
+
+ return(id);
+}
diff --git a/3rdparty/Routino/src/logging.c b/3rdparty/Routino/src/logging.c
new file mode 100644
index 0000000..11cd399
--- /dev/null
+++ b/3rdparty/Routino/src/logging.c
@@ -0,0 +1,607 @@
+/***************************************
+ Functions to handle logging functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#if defined(_MSC_VER)
+
+#include <WinSock2.h>
+#include <stdint.h>
+
+static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
+
+int gettimeofday(struct timeval * tp, struct timezone * tzp)
+{
+ FILETIME    file_time;
+ SYSTEMTIME  system_time;
+ ULARGE_INTEGER ularge;
+
+ GetSystemTime(&system_time);
+ SystemTimeToFileTime(&system_time, &file_time);
+ ularge.LowPart = file_time.dwLowDateTime;
+ ularge.HighPart = file_time.dwHighDateTime;
+
+ tp->tv_sec = (long) ((ularge.QuadPart - EPOCH) / 10000000L);
+ tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
+ return 0;
+}
+
+#else
+
+#include <sys/time.h>
+
+#endif
+
+#include "logging.h"
+
+
+/* Global variables */
+
+/*+ The option to print the output in a way that allows logging to a file. +*/
+int option_loggable=0;
+
+/*+ The option to print elapsed time with the output. +*/
+int option_logtime=0;
+
+/*+ The option to print memory usage with the output. +*/
+int option_logmemory=0;
+
+
+/* Local data types */
+
+/*+ A structure to contain the list of allocated memory. +*/
+struct mallocinfo
+{
+ void  *address;            /*+ The address of the allocated memory. +*/
+ size_t size;               /*+ The size of the allocated memory. +*/
+};
+
+
+/* Local functions */
+
+static void vfprintf_first(FILE *file,const char *format,va_list ap);
+static void vfprintf_middle(FILE *file,const char *format,va_list ap);
+static void vfprintf_last(FILE *file,const char *format,va_list ap);
+
+static void fprintf_elapsed_time(FILE *file,struct timeval *start);
+static void fprintf_max_memory(FILE *file,size_t max_alloc,size_t max_mmap);
+
+
+/* Local variables */
+
+/*+ The time that program_start() was called. +*/
+static struct timeval program_start_time;
+
+/*+ The time that printf_first() was called. +*/
+static struct timeval function_start_time;
+
+/*+ The list of allocated memory. +*/
+static struct mallocinfo *mallocedmem;
+
+/*+ The number of allocated memory blocks. +*/
+static int nmallocedmem=0;
+
+/*+ The length of the string printed out last time. +*/
+static int printed_length=0;
+
+/*+ The maximum amount of memory allocated and memory mapped since starting the program. +*/
+static size_t program_max_alloc=0,program_max_mmap=0;
+
+/*+ The maximum amount of memory allocated and memory mapped since starting the function. +*/
+static size_t function_max_alloc=0,function_max_mmap=0;
+
+/*+ The current amount of memory allocated and memory mapped. +*/
+static size_t current_alloc=0,current_mmap=0;
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Record the time that the program started.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void printf_program_start(void)
+{
+ gettimeofday(&program_start_time,NULL);
+
+ program_max_alloc=program_max_mmap=0;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Record the time that the program started.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void printf_program_end(void)
+{
+ if(option_logtime || option_logmemory)
+   {
+    if(option_logtime)
+       fprintf_elapsed_time(stdout,&program_start_time);
+
+    if(option_logmemory)
+       fprintf_max_memory(stdout,program_max_alloc,program_max_mmap);
+
+    printf("Finish Program\n");
+
+    if(option_logtime==2)
+       printf("[ m:ss.micros] ");
+    else if(option_logtime==1)
+       printf("[ m:ss.mil] ");
+
+    if(option_logmemory)
+       printf("[RAM,FILE MB] ");
+
+    if(option_logtime)
+       printf("elapsed time");
+
+    if(option_logmemory)
+      {
+       if(option_logtime)
+          printf(", ");
+       printf("maximum memory");
+      }
+
+    printf("\n");
+
+    fflush(stdout);
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print the first message in an overwriting sequence (to stdout).
+
+  const char *format The format string.
+
+  ... The other arguments.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void printf_first(const char *format, ...)
+{
+ va_list ap;
+
+ if(option_logtime)
+    gettimeofday(&function_start_time,NULL);
+
+ if(option_logmemory)
+   {
+    function_max_alloc=current_alloc;
+    function_max_mmap=current_mmap;
+   }
+
+ if(option_loggable)
+    return;
+
+ va_start(ap,format);
+
+ vfprintf_first(stdout,format,ap);
+
+ va_end(ap);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print the middle message in an overwriting sequence (to stdout).
+
+  const char *format The format string.
+
+  ... The other arguments.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void printf_middle(const char *format, ...)
+{
+ va_list ap;
+
+ if(option_loggable)
+    return;
+
+ va_start(ap,format);
+
+ vfprintf_middle(stdout,format,ap);
+
+ va_end(ap);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print the last message in an overwriting sequence (to stdout).
+
+  const char *format The format string.
+
+  ... The other arguments.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void printf_last(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap,format);
+
+ vfprintf_last(stdout,format,ap);
+
+ va_end(ap);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print the first message in an overwriting sequence to a specified file.
+
+  FILE *file The file to write to.
+
+  const char *format The format string.
+
+  ... The other arguments.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void fprintf_first(FILE *file,const char *format, ...)
+{
+ va_list ap;
+
+ if(option_logtime)
+    gettimeofday(&function_start_time,NULL);
+
+ if(option_logmemory)
+   {
+    function_max_alloc=current_alloc;
+    function_max_mmap=current_mmap;
+   }
+
+ if(option_loggable)
+    return;
+
+ va_start(ap,format);
+
+ vfprintf_first(file,format,ap);
+
+ va_end(ap);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print the middle message in an overwriting sequence to a specified file.
+
+  FILE *file The file to write to.
+
+  const char *format The format string.
+
+  ... The other arguments.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void fprintf_middle(FILE *file,const char *format, ...)
+{
+ va_list ap;
+
+ if(option_loggable)
+    return;
+
+ va_start(ap,format);
+
+ vfprintf_middle(file,format,ap);
+
+ va_end(ap);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print the last message in an overwriting sequence to a specified file.
+
+  FILE *file The file to write to.
+
+  const char *format The format string.
+
+  ... The other arguments.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void fprintf_last(FILE *file,const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap,format);
+
+ vfprintf_last(file,format,ap);
+
+ va_end(ap);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Record the memory allocations (record the amount in use).
+
+  void *address The address that has been allocated.
+
+  size_t size The size of the memory that has been allocated.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void log_malloc(void *address,size_t size)
+{
+ int i;
+
+ if(!option_logmemory)
+    return;
+
+ /* Store the information about the allocated memory */
+
+ for(i=0;i<nmallocedmem;i++)
+    if(mallocedmem[i].address==address)
+      {
+       size=size-mallocedmem[i].size;
+       mallocedmem[i].size+=size;
+       break;
+      }
+
+ if(i==nmallocedmem)
+   {
+    mallocedmem=(struct mallocinfo*)realloc((void*)mallocedmem,(nmallocedmem+1)*sizeof(struct mallocinfo));
+
+    mallocedmem[nmallocedmem].address=address;
+    mallocedmem[nmallocedmem].size=size;
+
+    nmallocedmem++;
+   }
+
+ /* Increase the sum of allocated memory */
+
+ current_alloc+=size;
+
+ if(current_alloc>function_max_alloc)
+    function_max_alloc=current_alloc;
+
+ if(current_alloc>program_max_alloc)
+    program_max_alloc=current_alloc;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Record the memory de-allocations.
+
+  void *address The address that has been freed.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void log_free(void *address)
+{
+ size_t size=0;
+ int i;
+
+ if(!option_logmemory)
+    return;
+
+ /* Remove the information about the allocated memory */
+
+ for(i=0;i<nmallocedmem;i++)
+    if(mallocedmem[i].address==address)
+      {
+       size=mallocedmem[i].size;
+       break;
+      }
+
+ logassert(i!=nmallocedmem,"Memory freed with log_free() was not allocated with log_[cm]alloc()");
+
+ nmallocedmem--;
+
+ if(nmallocedmem>i)
+    memmove(&mallocedmem[i],&mallocedmem[i+1],(nmallocedmem-i)*sizeof(struct mallocinfo));
+
+ /* Reduce the sum of allocated memory */
+
+ current_alloc-=size;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Record the amount of memory that has been mapped into files.
+
+  size_t size The size of the file that has been mapped.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void log_mmap(size_t size)
+{
+ if(!option_logmemory)
+    return;
+
+ current_mmap+=size;
+
+ if(current_mmap>function_max_mmap)
+    function_max_mmap=current_mmap;
+
+ if(current_mmap>program_max_mmap)
+    program_max_mmap=current_mmap;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Record the amount of memory that has been unmapped from files.
+
+  size_t size The size of the file that has been unmapped.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void log_munmap(size_t size)
+{
+ if(!option_logmemory)
+    return;
+
+ current_mmap-=size;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Do the work to print the first message in an overwriting sequence.
+
+  FILE *file The file to write to.
+
+  const char *format The format string.
+
+  va_list ap The other arguments.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void vfprintf_first(FILE *file,const char *format,va_list ap)
+{
+ int retval;
+
+ if(option_logtime)
+    fprintf_elapsed_time(file,&function_start_time);
+
+ if(option_logmemory)
+    fprintf_max_memory(file,function_max_alloc,function_max_mmap);
+
+ retval=vfprintf(file,format,ap);
+ fflush(file);
+
+ if(retval>0)
+    printed_length=retval;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Do the work to print the middle message in an overwriting sequence.
+
+  FILE *file The file to write to.
+
+  const char *format The format string.
+
+  va_list ap The other arguments.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void vfprintf_middle(FILE *file,const char *format,va_list ap)
+{
+ int retval;
+
+ fputc('\r',file);
+
+ if(option_logtime)
+    fprintf_elapsed_time(file,&function_start_time);
+
+ if(option_logmemory)
+    fprintf_max_memory(file,function_max_alloc,function_max_mmap);
+
+ retval=vfprintf(file,format,ap);
+ fflush(file);
+
+ if(retval>0)
+   {
+    int new_printed_length=retval;
+
+    while(retval++<printed_length)
+       fputc(' ',file);
+
+    printed_length=new_printed_length;
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Do the work to print the last message in an overwriting sequence.
+
+  FILE *file The file to write to.
+
+  const char *format The format string.
+
+  va_list ap The other arguments.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void vfprintf_last(FILE *file,const char *format,va_list ap)
+{
+ int retval;
+
+ if(!option_loggable)
+    fputc('\r',file);
+
+ if(option_logtime)
+    fprintf_elapsed_time(file,&function_start_time);
+
+ if(option_logmemory)
+    fprintf_max_memory(file,function_max_alloc,function_max_mmap);
+
+ retval=vfprintf(file,format,ap);
+
+ if(retval>0)
+    while(retval++<printed_length)
+       fputc(' ',file);
+
+ fputc('\n',file);
+ fflush(file);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print the elapsed time without a following newline.
+
+  FILE *file The file to print to.
+
+  struct timeval *start The start time from which the elapsed time is to be printed.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void fprintf_elapsed_time(FILE *file,struct timeval *start)
+{
+ struct timeval finish,elapsed;
+
+ gettimeofday(&finish,NULL);
+
+ elapsed.tv_sec =finish.tv_sec -start->tv_sec;
+ elapsed.tv_usec=finish.tv_usec-start->tv_usec;
+ if(elapsed.tv_usec<0)
+   {
+    elapsed.tv_sec -=1;
+    elapsed.tv_usec+=1000000;
+   }
+
+ if(option_logtime==2)
+    fprintf(file,"[%2ld:%02ld.%06ld] ",elapsed.tv_sec/60,elapsed.tv_sec%60,elapsed.tv_usec);
+ else
+    fprintf(file,"[%2ld:%02ld.%03ld] ",elapsed.tv_sec/60,elapsed.tv_sec%60,elapsed.tv_usec/1000);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print the maximum used memory without a following newline.
+
+  FILE *file The file to print to.
+
+  size_t max_alloc The maximum amount of allocated memory.
+
+  size_t max_mmap The maximum amount of memory mapped memory.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void fprintf_max_memory(FILE *file,size_t max_alloc,size_t max_mmap)
+{
+ fprintf(file,"[%3zu, %3zu MB] ",max_alloc/(1024*1024),max_mmap/(1024*1024));
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Log a fatal error and exit
+
+  const char *message The error message.
+
+  const char *file The file in which the error occured.
+
+  int line The line number in the file at which the error occured.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void _logassert(const char *message,const char *file,int line)
+{
+ fprintf(stderr,"Routino Fatal Error (%s:%d): %s\n",file,line,message);
+
+ exit(EXIT_FAILURE);
+}
diff --git a/3rdparty/Routino/src/logging.h b/3rdparty/Routino/src/logging.h
new file mode 100644
index 0000000..3d5ca9a
--- /dev/null
+++ b/3rdparty/Routino/src/logging.h
@@ -0,0 +1,114 @@
+/***************************************
+ Header file for logging function prototypes
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef LOGGING_H
+#define LOGGING_H    /*+ To stop multiple inclusions. +*/
+
+#include <stdio.h>
+
+#include "typesx.h"
+
+
+/* Data structures */
+
+/*+ A structure containing a single object as written by the logerror_*() functions. +*/
+typedef struct _ErrorLogObject
+{
+ char      type;             /*+ The type of the object. +*/
+
+ uint64_t  id;               /*+ The id of the object. +*/
+
+ uint32_t  offset;           /*+ The offset of the error message from the beginning of the text file. +*/
+}
+ ErrorLogObject;
+
+
+/* Variables */
+
+extern int option_loggable;
+extern int option_logtime;
+extern int option_logmemory;
+
+
+/* Runtime progress logging functions in logging.c */
+
+void printf_program_start(void);
+void printf_program_end(void);
+
+
+#ifdef __GNUC__
+
+void printf_first(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
+void printf_middle(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
+void printf_last(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
+
+void fprintf_first(FILE *file,const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+void fprintf_middle(FILE *file,const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+void fprintf_last(FILE *file,const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+#else
+
+void printf_first(const char *format, ...);
+void printf_middle(const char *format, ...);
+void printf_last(const char *format, ...);
+
+void fprintf_first(FILE *file,const char *format, ...);
+void fprintf_middle(FILE *file,const char *format, ...);
+void fprintf_last(FILE *file,const char *format, ...);
+
+#endif
+
+void log_malloc(void *address,size_t size);
+void log_free(void *address);
+
+void log_mmap(size_t size);
+void log_munmap(size_t size);
+
+
+/* Error logging functions in logerror.c */
+
+void open_errorlog(const char *filename,int append,int bin);
+void close_errorlog(void);
+
+#ifdef __GNUC__
+
+void logerror(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
+
+#else
+
+void logerror(const char *format, ...);
+
+#endif
+
+node_t     logerror_node    (node_t     id);
+way_t      logerror_way     (way_t      id);
+relation_t logerror_relation(relation_t id);
+
+
+/* Runtime fatal error assertion in logging.c */
+
+#define logassert(xx,yy) do { if(!(xx)) _logassert(yy,__FILE__,__LINE__); } while(0)
+
+void _logassert(const char *message,const char *file,int line);
+
+
+#endif /* LOGGING_H */
diff --git a/3rdparty/Routino/src/mman-win32.c b/3rdparty/Routino/src/mman-win32.c
new file mode 100644
index 0000000..2fd5f63
--- /dev/null
+++ b/3rdparty/Routino/src/mman-win32.c
@@ -0,0 +1,206 @@
+/***************************************
+ Windows 32 memory management functions from https://code.google.com/p/mman-win32
+
+ File header comment created by Andrew M. Bishop, all source code unchanged from original.
+ ******************/ /******************
+ Copyright (c) 2010,2012 Viktor Kutuzov
+
+ 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.
+ ***************************************/
+
+
+#include <windows.h>
+#include <errno.h>
+#include <io.h>
+
+#include "mman-win32.h"
+
+#ifndef FILE_MAP_EXECUTE
+#define FILE_MAP_EXECUTE    0x0020
+#endif /* FILE_MAP_EXECUTE */
+
+static int __map_mman_error(const DWORD err, const int deferr)
+{
+    if (err == 0)
+        return 0;
+    //TODO: implement
+    return err;
+}
+
+static DWORD __map_mmap_prot_page(const int prot)
+{
+    DWORD protect = 0;
+    
+    if (prot == PROT_NONE)
+        return protect;
+        
+    if ((prot & PROT_EXEC) != 0)
+    {
+        protect = ((prot & PROT_WRITE) != 0) ? 
+                    PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
+    }
+    else
+    {
+        protect = ((prot & PROT_WRITE) != 0) ?
+                    PAGE_READWRITE : PAGE_READONLY;
+    }
+    
+    return protect;
+}
+
+static DWORD __map_mmap_prot_file(const int prot)
+{
+    DWORD desiredAccess = 0;
+    
+    if (prot == PROT_NONE)
+        return desiredAccess;
+        
+    if ((prot & PROT_READ) != 0)
+        desiredAccess |= FILE_MAP_READ;
+    if ((prot & PROT_WRITE) != 0)
+        desiredAccess |= FILE_MAP_WRITE;
+    if ((prot & PROT_EXEC) != 0)
+        desiredAccess |= FILE_MAP_EXECUTE;
+    
+    return desiredAccess;
+}
+
+void* mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
+{
+    HANDLE fm, h;
+    
+    void * map = MAP_FAILED;
+    
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4293)
+#endif
+
+    const DWORD dwFileOffsetLow = (sizeof(off_t) <= sizeof(DWORD)) ? 
+                    (DWORD)off : (DWORD)(off & 0xFFFFFFFFL);
+    const DWORD dwFileOffsetHigh = (sizeof(off_t) <= sizeof(DWORD)) ?
+                    (DWORD)0 : (DWORD)((off >> 32) & 0xFFFFFFFFL);
+    const DWORD protect = __map_mmap_prot_page(prot);
+    const DWORD desiredAccess = __map_mmap_prot_file(prot);
+
+    const off_t maxSize = off + (off_t)len;
+
+    const DWORD dwMaxSizeLow = (sizeof(off_t) <= sizeof(DWORD)) ? 
+                    (DWORD)maxSize : (DWORD)(maxSize & 0xFFFFFFFFL);
+    const DWORD dwMaxSizeHigh = (sizeof(off_t) <= sizeof(DWORD)) ?
+                    (DWORD)0 : (DWORD)((maxSize >> 32) & 0xFFFFFFFFL);
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+    errno = 0;
+    
+    if (len == 0 
+        /* Unsupported flag combinations */
+        || (flags & MAP_FIXED) != 0
+        /* Usupported protection combinations */
+        || prot == PROT_EXEC)
+    {
+        errno = EINVAL;
+        return MAP_FAILED;
+    }
+    
+    h = ((flags & MAP_ANONYMOUS) == 0) ? 
+                    (HANDLE)_get_osfhandle(fildes) : INVALID_HANDLE_VALUE;
+
+    if ((flags & MAP_ANONYMOUS) == 0 && h == INVALID_HANDLE_VALUE)
+    {
+        errno = EBADF;
+        return MAP_FAILED;
+    }
+
+    fm = CreateFileMapping(h, NULL, protect, dwMaxSizeHigh, dwMaxSizeLow, NULL);
+
+    if (fm == NULL)
+    {
+        errno = __map_mman_error(GetLastError(), EPERM);
+        return MAP_FAILED;
+    }
+  
+    map = MapViewOfFile(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len);
+
+    CloseHandle(fm);
+  
+    if (map == NULL)
+    {
+        errno = __map_mman_error(GetLastError(), EPERM);
+        return MAP_FAILED;
+    }
+
+    return map;
+}
+
+int munmap(void *addr, size_t len)
+{
+    if (UnmapViewOfFile(addr))
+        return 0;
+        
+    errno =  __map_mman_error(GetLastError(), EPERM);
+    
+    return -1;
+}
+
+int mprotect(void *addr, size_t len, int prot)
+{
+    DWORD newProtect = __map_mmap_prot_page(prot);
+    DWORD oldProtect = 0;
+    
+    if (VirtualProtect(addr, len, newProtect, &oldProtect))
+        return 0;
+    
+    errno =  __map_mman_error(GetLastError(), EPERM);
+    
+    return -1;
+}
+
+int msync(void *addr, size_t len, int flags)
+{
+    if (FlushViewOfFile(addr, len))
+        return 0;
+    
+    errno =  __map_mman_error(GetLastError(), EPERM);
+    
+    return -1;
+}
+
+int mlock(const void *addr, size_t len)
+{
+    if (VirtualLock((LPVOID)addr, len))
+        return 0;
+        
+    errno =  __map_mman_error(GetLastError(), EPERM);
+    
+    return -1;
+}
+
+int munlock(const void *addr, size_t len)
+{
+    if (VirtualUnlock((LPVOID)addr, len))
+        return 0;
+        
+    errno =  __map_mman_error(GetLastError(), EPERM);
+    
+    return -1;
+}
diff --git a/3rdparty/Routino/src/mman-win32.h b/3rdparty/Routino/src/mman-win32.h
new file mode 100644
index 0000000..3dca196
--- /dev/null
+++ b/3rdparty/Routino/src/mman-win32.h
@@ -0,0 +1,77 @@
+/***************************************
+ Windows 32 memory management functions from https://code.google.com/p/mman-win32
+
+ File header comment created by Andrew M. Bishop, all source code unchanged from original.
+ ******************/ /******************
+ Copyright (c) 2010,2012 Viktor Kutuzov
+
+ 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.
+ ***************************************/
+
+
+#ifndef _SYS_MMAN_H_
+#define _SYS_MMAN_H_
+
+#ifndef _WIN32_WINNT		// Allow use of features specific to Windows XP or later.                   
+#define _WIN32_WINNT 0x0501	// Change this to the appropriate value to target other versions of Windows.
+#endif						
+
+/* All the headers include this file. */
+#ifndef _MSC_VER
+#include <_mingw.h>
+#endif
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PROT_NONE       0
+#define PROT_READ       1
+#define PROT_WRITE      2
+#define PROT_EXEC       4
+
+#define MAP_FILE        0
+#define MAP_SHARED      1
+#define MAP_PRIVATE     2
+#define MAP_TYPE        0xf
+#define MAP_FIXED       0x10
+#define MAP_ANONYMOUS   0x20
+#define MAP_ANON        MAP_ANONYMOUS
+
+#define MAP_FAILED      ((void *)-1)
+
+/* Flags for msync. */
+#define MS_ASYNC        1
+#define MS_SYNC         2
+#define MS_INVALIDATE   4
+
+void*   mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);
+int     munmap(void *addr, size_t len);
+int     mprotect(void *addr, size_t len, int prot);
+int     msync(void *addr, size_t len, int flags);
+int     mlock(const void *addr, size_t len);
+int     munlock(const void *addr, size_t len);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /*  _SYS_MMAN_H_ */
diff --git a/3rdparty/Routino/src/nodes.c b/3rdparty/Routino/src/nodes.c
new file mode 100644
index 0000000..90f95c4
--- /dev/null
+++ b/3rdparty/Routino/src/nodes.c
@@ -0,0 +1,624 @@
+/***************************************
+ Node data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "types.h"
+#include "nodes.h"
+#include "segments.h"
+#include "ways.h"
+
+#include "files.h"
+#include "profiles.h"
+
+
+/* Local functions */
+
+static int valid_segment_for_profile(Ways *ways,Segment *segmentp,Profile *profile);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Load in a node list from a file.
+
+  Nodes *LoadNodeList Returns the node list.
+
+  const char *filename The name of the file to load.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Nodes *LoadNodeList(const char *filename)
+{
+ Nodes *nodes;
+#if SLIM
+ size_t sizeoffsets;
+#endif
+
+ nodes=(Nodes*)malloc(sizeof(Nodes));
+
+#if !SLIM
+
+ nodes->data=MapFile(filename);
+
+ /* Copy the NodesFile header structure from the loaded data */
+
+ nodes->file=*((NodesFile*)nodes->data);
+
+ /* Set the pointers in the Nodes structure. */
+
+ nodes->offsets=(index_t*)(nodes->data+sizeof(NodesFile));
+ nodes->nodes  =(Node*   )(nodes->data+sizeof(NodesFile)+(nodes->file.latbins*nodes->file.lonbins+1)*sizeof(index_t));
+
+#else
+
+ nodes->fd=SlimMapFile(filename);
+
+ /* Copy the NodesFile header structure from the loaded data */
+
+ SlimFetch(nodes->fd,&nodes->file,sizeof(NodesFile),0);
+
+ sizeoffsets=(nodes->file.latbins*nodes->file.lonbins+1)*sizeof(index_t);
+
+ nodes->offsets=(index_t*)malloc(sizeoffsets);
+#ifndef LIBROUTINO
+ log_malloc(nodes->offsets,sizeoffsets);
+#endif
+
+ SlimFetch(nodes->fd,nodes->offsets,sizeoffsets,sizeof(NodesFile));
+
+ nodes->nodesoffset=(off_t)(sizeof(NodesFile)+sizeoffsets);
+
+ nodes->cache=NewNodeCache();
+#ifndef LIBROUTINO
+ log_malloc(nodes->cache,sizeof(*nodes->cache));
+#endif
+
+#endif
+
+ return(nodes);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Destroy the node list.
+
+  Nodes *nodes The node list to destroy.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void DestroyNodeList(Nodes *nodes)
+{
+#if !SLIM
+
+ nodes->data=UnmapFile(nodes->data);
+
+#else
+
+ nodes->fd=SlimUnmapFile(nodes->fd);
+
+#ifndef LIBROUTINO
+ log_free(nodes->offsets);
+#endif
+ free(nodes->offsets);
+
+#ifndef LIBROUTINO
+ log_free(nodes->cache);
+#endif
+ DeleteNodeCache(nodes->cache);
+
+#endif
+
+ free(nodes);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the closest node given its latitude, longitude and the profile of the
+  mode of transport that must be able to move to/from this node.
+
+  index_t FindClosestNode Returns the closest node.
+
+  Nodes *nodes The set of nodes to search.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  double latitude The latitude to look for.
+
+  double longitude The longitude to look for.
+
+  distance_t distance The maximum distance to look from the specified coordinates.
+
+  Profile *profile The profile of the mode of transport.
+
+  distance_t *bestdist Returns the distance to the best node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t FindClosestNode(Nodes *nodes,Segments *segments,Ways *ways,double latitude,double longitude,
+                        distance_t distance,Profile *profile,distance_t *bestdist)
+{
+ ll_bin_t   latbin=latlong_to_bin(radians_to_latlong(latitude ))-nodes->file.latzero;
+ ll_bin_t   lonbin=latlong_to_bin(radians_to_latlong(longitude))-nodes->file.lonzero;
+ int        delta=0,count;
+ index_t    i,index1,index2;
+ index_t    bestn=NO_NODE;
+ distance_t bestd=INF_DISTANCE;
+
+ /* Find the maximum distance to search */
+
+ double dlat=DeltaLat(longitude,distance);
+ double dlon=DeltaLon(latitude ,distance);
+
+ double minlat=latitude -dlat;
+ double maxlat=latitude +dlat;
+ double minlon=longitude-dlon;
+ double maxlon=longitude+dlon;
+
+ ll_bin_t minlatbin=latlong_to_bin(radians_to_latlong(minlat))-nodes->file.latzero;
+ ll_bin_t maxlatbin=latlong_to_bin(radians_to_latlong(maxlat))-nodes->file.latzero;
+ ll_bin_t minlonbin=latlong_to_bin(radians_to_latlong(minlon))-nodes->file.lonzero;
+ ll_bin_t maxlonbin=latlong_to_bin(radians_to_latlong(maxlon))-nodes->file.lonzero;
+
+ ll_off_t minlatoff=latlong_to_off(radians_to_latlong(minlat));
+ ll_off_t maxlatoff=latlong_to_off(radians_to_latlong(maxlat));
+ ll_off_t minlonoff=latlong_to_off(radians_to_latlong(minlon));
+ ll_off_t maxlonoff=latlong_to_off(radians_to_latlong(maxlon));
+
+ /* Start with the bin containing the location, then spiral outwards. */
+
+ do
+   {
+    ll_bin_t latb,lonb;
+    ll_bin2_t llbin;
+
+    count=0;
+
+    for(latb=latbin-delta;latb<=latbin+delta;latb++)
+      {
+       if(latb<0 || latb>=nodes->file.latbins || latb<minlatbin || latb>maxlatbin)
+          continue;
+
+       for(lonb=lonbin-delta;lonb<=lonbin+delta;lonb++)
+         {
+          if(lonb<0 || lonb>=nodes->file.lonbins || lonb<minlonbin || lonb>maxlonbin)
+             continue;
+
+          if(abs(latb-latbin)<delta && abs(lonb-lonbin)<delta)
+             continue;
+
+          /* Check every node in this grid square. */
+
+          llbin=lonb*nodes->file.latbins+latb;
+
+          index1=LookupNodeOffset(nodes,llbin);
+          index2=LookupNodeOffset(nodes,llbin+1);
+
+          for(i=index1;i<index2;i++)
+            {
+             Node *nodep=LookupNode(nodes,i,3);
+             double lat,lon;
+             distance_t dist;
+
+             if(latb==minlatbin && nodep->latoffset<minlatoff)
+                continue;
+
+             if(latb==maxlatbin && nodep->latoffset>maxlatoff)
+                continue;
+
+             if(lonb==minlonbin && nodep->lonoffset<minlonoff)
+                continue;
+
+             if(lonb==maxlonbin && nodep->lonoffset>maxlonoff)
+                continue;
+
+             lat=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb)+off_to_latlong(nodep->latoffset));
+             lon=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb)+off_to_latlong(nodep->lonoffset));
+
+             dist=Distance(lat,lon,latitude,longitude);
+
+             if(dist<bestd)
+               {
+                Segment *segmentp;
+
+                /* Check that at least one segment is valid for the profile */
+
+                segmentp=FirstSegment(segments,nodep,1);
+
+                do
+                  {
+                   if(IsNormalSegment(segmentp) && valid_segment_for_profile(ways,segmentp,profile))
+                     {
+                      bestn=i;
+                      bestd=dist;
+
+                      break;
+                     }
+
+                   segmentp=NextSegment(segments,segmentp,i);
+                  }
+                while(segmentp);
+               }
+            }
+
+          count++;
+         }
+      }
+
+    delta++;
+   }
+ while(count);
+
+ *bestdist=bestd;
+
+ return(bestn);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the closest point on the closest segment given its latitude, longitude
+  and the profile of the mode of transport that must be able to move along this
+  segment.
+
+  index_t FindClosestSegment Returns the closest segment index.
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to search.
+
+  Ways *ways The set of ways to use.
+
+  double latitude The latitude to look for.
+
+  double longitude The longitude to look for.
+
+  distance_t distance The maximum distance to look from the specified coordinates.
+
+  Profile *profile The profile of the mode of transport.
+
+  distance_t *bestdist Returns the distance to the closest point on the best segment.
+
+  index_t *bestnode1 Returns the index of the node at one end of the closest segment.
+
+  index_t *bestnode2 Returns the index of the node at the other end of the closest segment.
+
+  distance_t *bestdist1 Returns the distance along the segment to the node at one end.
+
+  distance_t *bestdist2 Returns the distance along the segment to the node at the other end.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t FindClosestSegment(Nodes *nodes,Segments *segments,Ways *ways,double latitude,double longitude,
+                           distance_t distance,Profile *profile, distance_t *bestdist,
+                           index_t *bestnode1,index_t *bestnode2,distance_t *bestdist1,distance_t *bestdist2)
+{
+ ll_bin_t   latbin=latlong_to_bin(radians_to_latlong(latitude ))-nodes->file.latzero;
+ ll_bin_t   lonbin=latlong_to_bin(radians_to_latlong(longitude))-nodes->file.lonzero;
+ int        delta=0,count;
+ index_t    i,index1,index2;
+ index_t    bestn1=NO_NODE,bestn2=NO_NODE;
+ distance_t bestd=INF_DISTANCE,bestd1=INF_DISTANCE,bestd2=INF_DISTANCE;
+ index_t    bests=NO_SEGMENT;
+
+ /* Find the maximum distance to search */
+
+ double dlat=DeltaLat(longitude,distance);
+ double dlon=DeltaLon(latitude ,distance);
+
+ double minlat=latitude -dlat;
+ double maxlat=latitude +dlat;
+ double minlon=longitude-dlon;
+ double maxlon=longitude+dlon;
+
+ ll_bin_t minlatbin=latlong_to_bin(radians_to_latlong(minlat))-nodes->file.latzero;
+ ll_bin_t maxlatbin=latlong_to_bin(radians_to_latlong(maxlat))-nodes->file.latzero;
+ ll_bin_t minlonbin=latlong_to_bin(radians_to_latlong(minlon))-nodes->file.lonzero;
+ ll_bin_t maxlonbin=latlong_to_bin(radians_to_latlong(maxlon))-nodes->file.lonzero;
+
+ ll_off_t minlatoff=latlong_to_off(radians_to_latlong(minlat));
+ ll_off_t maxlatoff=latlong_to_off(radians_to_latlong(maxlat));
+ ll_off_t minlonoff=latlong_to_off(radians_to_latlong(minlon));
+ ll_off_t maxlonoff=latlong_to_off(radians_to_latlong(maxlon));
+
+ /* Start with the bin containing the location, then spiral outwards. */
+
+ do
+   {
+    ll_bin_t latb,lonb;
+    ll_bin2_t llbin;
+
+    count=0;
+
+    for(latb=latbin-delta;latb<=latbin+delta;latb++)
+      {
+       if(latb<0 || latb>=nodes->file.latbins || latb<minlatbin || latb>maxlatbin)
+          continue;
+
+       for(lonb=lonbin-delta;lonb<=lonbin+delta;lonb++)
+         {
+          if(lonb<0 || lonb>=nodes->file.lonbins || lonb<minlonbin || lonb>maxlonbin)
+             continue;
+
+          if(abs(latb-latbin)<delta && abs(lonb-lonbin)<delta)
+             continue;
+
+          /* Check every node in this grid square. */
+
+          llbin=lonb*nodes->file.latbins+latb;
+
+          index1=LookupNodeOffset(nodes,llbin);
+          index2=LookupNodeOffset(nodes,llbin+1);
+
+          for(i=index1;i<index2;i++)
+            {
+             Node *nodep=LookupNode(nodes,i,3);
+             double lat1,lon1;
+             distance_t dist1;
+
+             if(latb==minlatbin && nodep->latoffset<minlatoff)
+                continue;
+
+             if(latb==maxlatbin && nodep->latoffset>maxlatoff)
+                continue;
+
+             if(lonb==minlonbin && nodep->lonoffset<minlonoff)
+                continue;
+
+             if(lonb==maxlonbin && nodep->lonoffset>maxlonoff)
+                continue;
+
+             lat1=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb)+off_to_latlong(nodep->latoffset));
+             lon1=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb)+off_to_latlong(nodep->lonoffset));
+
+             dist1=Distance(lat1,lon1,latitude,longitude);
+
+             if(dist1<distance)
+               {
+                Segment *segmentp;
+
+                /* Check each segment for closeness and if valid for the profile */
+
+                segmentp=FirstSegment(segments,nodep,1);
+
+                do
+                  {
+                   if(IsNormalSegment(segmentp) && valid_segment_for_profile(ways,segmentp,profile))
+                     {
+                      distance_t dist2,dist3;
+                      double lat2,lon2,dist3a,dist3b,distp;
+
+                      GetLatLong(nodes,OtherNode(segmentp,i),NULL,&lat2,&lon2);
+
+                      dist2=Distance(lat2,lon2,latitude,longitude);
+
+                      dist3=Distance(lat1,lon1,lat2,lon2);
+
+                      /* Use law of cosines (assume flat Earth) */
+
+                      if(dist3==0)
+                        {
+                         distp=dist1;  /* == dist2 */
+                         dist3a=dist1; /* == dist2 */
+                         dist3b=dist2; /* == dist1 */
+                        }
+                      else if((dist1+dist2)<dist3)
+                        {
+                         distp=0;
+                         dist3a=dist1;
+                         dist3b=dist2;
+                        }
+                      else
+                        {
+                         dist3a=((double)dist1*(double)dist1-(double)dist2*(double)dist2+(double)dist3*(double)dist3)/(2.0*(double)dist3);
+                         dist3b=(double)dist3-dist3a;
+
+                         if(dist3a>=0 && dist3b>=0)
+                            distp=sqrt((double)dist1*(double)dist1-dist3a*dist3a);
+                         else if(dist3a>0)
+                           {
+                            distp=dist2;
+                            dist3a=dist3;
+                            dist3b=0;
+                           }
+                         else /* if(dist3b>0) */
+                           {
+                            distp=dist1;
+                            dist3a=0;
+                            dist3b=dist3;
+                           }
+                        }
+
+                      if(distp<(double)bestd)
+                        {
+                         bests=IndexSegment(segments,segmentp);
+
+                         if(segmentp->node1==i)
+                           {
+                            bestn1=i;
+                            bestn2=OtherNode(segmentp,i);
+                            bestd1=(distance_t)dist3a;
+                            bestd2=(distance_t)dist3b;
+                           }
+                         else
+                           {
+                            bestn1=OtherNode(segmentp,i);
+                            bestn2=i;
+                            bestd1=(distance_t)dist3b;
+                            bestd2=(distance_t)dist3a;
+                           }
+
+                         bestd=(distance_t)distp;
+                        }
+                     }
+
+                   segmentp=NextSegment(segments,segmentp,i);
+                  }
+                while(segmentp);
+
+               } /* dist1 < distance */
+            }
+
+          count++;
+         }
+      }
+
+    delta++;
+   }
+ while(count);
+
+ *bestdist=bestd;
+
+ *bestnode1=bestn1;
+ *bestnode2=bestn2;
+ *bestdist1=bestd1;
+ *bestdist2=bestd2;
+
+ return(bests);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Check if the transport defined by the profile is allowed on the segment.
+
+  int valid_segment_for_profile Return 1 if it is or 0 if not.
+
+  Ways *ways The set of ways to use.
+
+  Segment *segmentp The segment to check.
+
+  Profile *profile The profile to check.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int valid_segment_for_profile(Ways *ways,Segment *segmentp,Profile *profile)
+{
+ Way *wayp=LookupWay(ways,segmentp->way,1);
+ score_t segment_pref;
+ int i;
+
+ /* mode of transport must be allowed on the highway */
+ if(!(wayp->allow&profile->allow))
+    return(0);
+
+ /* must obey weight restriction (if exists) */
+ if(wayp->weight && wayp->weight<profile->weight)
+    return(0);
+
+ /* must obey height/width/length restriction (if exists) */
+ if((wayp->height && wayp->height<profile->height) ||
+    (wayp->width  && wayp->width <profile->width ) ||
+    (wayp->length && wayp->length<profile->length))
+    return(0);
+
+ segment_pref=profile->highway[HIGHWAY(wayp->type)];
+
+ for(i=1;i<Property_Count;i++)
+    if(ways->file.props & PROPERTIES(i))
+      {
+       if(wayp->props & PROPERTIES(i))
+          segment_pref*=profile->props_yes[i];
+       else
+          segment_pref*=profile->props_no[i];
+      }
+
+ /* profile preferences must allow this highway */
+ if(segment_pref==0)
+    return(0);
+
+ /* Must be OK */
+ return(1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Get the latitude and longitude associated with a node.
+
+  Nodes *nodes The set of nodes to use.
+
+  index_t index The node index.
+
+  Node *nodep A pointer to the node if already available.
+
+  double *latitude Returns the latitude.
+
+  double *longitude Returns the logitude.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void GetLatLong(Nodes *nodes,index_t index,Node *nodep,double *latitude,double *longitude)
+{
+ ll_bin_t latbin,lonbin;
+ ll_bin2_t bin=-1;
+ ll_bin2_t start,end,mid;
+ index_t offset;
+
+ /* Binary search - search key nearest match below is required.
+  *
+  *  # <- start  |  Check mid and move start or end if it doesn't match
+  *  #           |
+  *  #           |  A lower bound match is wanted we can set end=mid-1 or
+  *  # <- mid    |  start=mid because we know that mid doesn't match.
+  *  #           |
+  *  #           |  Eventually either end=start or end=start+1 and one of
+  *  # <- end    |  start or end is the wanted one.
+  */
+
+ /* Search for offset */
+
+ start=0;
+ end=nodes->file.lonbins*nodes->file.latbins;
+
+ do
+   {
+    mid=(start+end)/2;                  /* Choose mid point */
+
+    offset=LookupNodeOffset(nodes,mid);
+
+    if(offset<index)                    /* Mid point is too low for an exact match but could be lower bound */
+       start=mid;
+    else if(offset>index)               /* Mid point is too high */
+       end=mid?(mid-1):mid;
+    else                                /* Mid point is correct */
+      {bin=mid;break;}
+   }
+ while((end-start)>1);
+
+ if(bin==-1)
+   {
+    offset=LookupNodeOffset(nodes,end);
+
+    if(offset>index)
+       bin=start;
+    else
+       bin=end;
+   }
+
+ while(bin<=(nodes->file.lonbins*nodes->file.latbins) && 
+       LookupNodeOffset(nodes,bin)==LookupNodeOffset(nodes,bin+1))
+    bin++;
+
+ latbin=bin%nodes->file.latbins;
+ lonbin=bin/nodes->file.latbins;
+
+ /* Return the values */
+
+ if(nodep==NULL)
+    nodep=LookupNode(nodes,index,4);
+
+ *latitude =latlong_to_radians(bin_to_latlong(nodes->file.latzero+latbin)+off_to_latlong(nodep->latoffset));
+ *longitude=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonbin)+off_to_latlong(nodep->lonoffset));
+}
diff --git a/3rdparty/Routino/src/nodes.h b/3rdparty/Routino/src/nodes.h
new file mode 100644
index 0000000..b3dcfce
--- /dev/null
+++ b/3rdparty/Routino/src/nodes.h
@@ -0,0 +1,175 @@
+/***************************************
+ A header file for the nodes.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef NODES_H
+#define NODES_H    /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "types.h"
+
+#include "cache.h"
+#include "files.h"
+#include "profiles.h"
+
+
+/* Data structures */
+
+
+/*+ A structure containing a single node. +*/
+struct _Node
+{
+ index_t      firstseg;         /*+ The index of the first segment. +*/
+
+ ll_off_t     latoffset;        /*+ The node latitude offset within its bin. +*/
+ ll_off_t     lonoffset;        /*+ The node longitude offset within its bin. +*/
+
+ transports_t allow;            /*+ The types of transport that are allowed through the node. +*/
+ nodeflags_t  flags;            /*+ Flags containing extra information (e.g. super-node, turn restriction). +*/
+};
+
+
+/*+ A structure containing the header from the file. +*/
+typedef struct _NodesFile
+{
+ index_t  number;               /*+ The number of nodes in total. +*/
+ index_t  snumber;              /*+ The number of super-nodes. +*/
+
+ ll_bin_t latbins;              /*+ The number of bins containing latitude. +*/
+ ll_bin_t lonbins;              /*+ The number of bins containing longitude. +*/
+
+ ll_bin_t latzero;              /*+ The bin number of the furthest south bin. +*/
+ ll_bin_t lonzero;              /*+ The bin number of the furthest west bin. +*/
+}
+ NodesFile;
+
+
+/*+ A structure containing a set of nodes. +*/
+struct _Nodes
+{
+ NodesFile file;                /*+ The header data from the file. +*/
+
+#if !SLIM
+
+ char     *data;                /*+ The memory mapped data in the file. +*/
+
+ index_t  *offsets;             /*+ A pointer to the array of offsets in the file. +*/
+
+ Node     *nodes;               /*+ A pointer to the array of nodes in the file. +*/
+
+#else
+
+ int       fd;                  /*+ The file descriptor for the file. +*/
+
+ index_t  *offsets;             /*+ An allocated array with a copy of the file offsets. +*/
+
+ off_t     nodesoffset;         /*+ The offset of the nodes within the file. +*/
+
+ Node      cached[6];           /*+ Some cached nodes read from the file in slim mode. +*/
+
+ NodeCache *cache;              /*+ A RAM cache of nodes read from the file. +*/
+
+#endif
+};
+
+
+/* Functions in nodes.c */
+
+Nodes *LoadNodeList(const char *filename);
+
+void DestroyNodeList(Nodes *nodes);
+
+index_t FindClosestNode(Nodes *nodes,Segments *segments,Ways *ways,double latitude,double longitude,
+                        distance_t distance,Profile *profile,distance_t *bestdist);
+
+index_t FindClosestSegment(Nodes *nodes,Segments *segments,Ways *ways,double latitude,double longitude,
+                           distance_t distance,Profile *profile, distance_t *bestdist,
+                           index_t *bestnode1,index_t *bestnode2,distance_t *bestdist1,distance_t *bestdist2);
+
+void GetLatLong(Nodes *nodes,index_t index,Node *nodep,double *latitude,double *longitude);
+
+
+/* Macros and inline functions */
+
+/*+ Return true if this is a super-node. +*/
+#define IsSuperNode(xxx)            (((xxx)->flags)&NODE_SUPER)
+
+/*+ Return true if this is a turn restricted node. +*/
+#define IsTurnRestrictedNode(xxx)   (((xxx)->flags)&NODE_TURNRSTRCT)
+
+/*+ Return a Segment index given a Node pointer and a set of segments. +*/
+#define FirstSegment(xxx,yyy,ppp)   LookupSegment((xxx),(yyy)->firstseg,ppp)
+
+/*+ Return the offset of a geographical region given a set of nodes. +*/
+#define LookupNodeOffset(xxx,yyy)   ((xxx)->offsets[yyy])
+
+
+#if !SLIM
+
+/*+ Return a Node pointer given a set of nodes and an index. +*/
+#define LookupNode(xxx,yyy,ppp)     (&(xxx)->nodes[yyy])
+
+#else
+
+/* Prototypes */
+
+static inline Node *LookupNode(Nodes *nodes,index_t index,int position);
+
+CACHE_NEWCACHE_PROTO(Node)
+CACHE_DELETECACHE_PROTO(Node)
+CACHE_FETCHCACHE_PROTO(Node)
+CACHE_INVALIDATECACHE_PROTO(Node)
+
+
+/* Inline functions */
+
+CACHE_STRUCTURE(Node)
+CACHE_NEWCACHE(Node)
+CACHE_DELETECACHE(Node)
+CACHE_FETCHCACHE(Node)
+CACHE_INVALIDATECACHE(Node)
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the Node information for a particular node.
+
+  Node *LookupNode Returns a pointer to the cached node information.
+
+  Nodes *nodes The set of nodes to use.
+
+  index_t index The index of the node.
+
+  int position The position in the cache to store the value.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline Node *LookupNode(Nodes *nodes,index_t index,int position)
+{
+ nodes->cached[position-1]=*FetchCachedNode(nodes->cache,index,nodes->fd,nodes->nodesoffset);
+
+ return(&nodes->cached[position-1]);
+}
+
+#endif
+
+
+#endif /* NODES_H */
diff --git a/3rdparty/Routino/src/nodesx.c b/3rdparty/Routino/src/nodesx.c
new file mode 100644
index 0000000..741bc89
--- /dev/null
+++ b/3rdparty/Routino/src/nodesx.c
@@ -0,0 +1,900 @@
+/***************************************
+ Extented Node data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "types.h"
+#include "nodes.h"
+
+#include "typesx.h"
+#include "nodesx.h"
+#include "segmentsx.h"
+#include "waysx.h"
+
+#include "files.h"
+#include "logging.h"
+#include "sorting.h"
+
+
+/* Global variables */
+
+/*+ The command line '--tmpdir' option or its default value. +*/
+extern char *option_tmpdirname;
+
+/* Local variables */
+
+/*+ Temporary file-local variables for use by the sort functions (re-initialised for each sort). +*/
+static NodesX *sortnodesx;
+static latlong_t lat_min,lat_max,lon_min,lon_max;
+
+/* Local functions */
+
+static int sort_by_id(NodeX *a,NodeX *b);
+static int deduplicate_and_index_by_id(NodeX *nodex,index_t index);
+
+static int update_id(NodeX *nodex,index_t index);
+static int sort_by_lat_long(NodeX *a,NodeX *b);
+static int index_by_lat_long(NodeX *nodex,index_t index);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Allocate a new node list (create a new file or open an existing one).
+
+  NodesX *NewNodeList Returns a pointer to the node list.
+
+  int append Set to 1 if the file is to be opened for appending.
+
+  int readonly Set to 1 if the file is to be opened for reading.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+NodesX *NewNodeList(int append,int readonly)
+{
+ NodesX *nodesx;
+
+ nodesx=(NodesX*)calloc(1,sizeof(NodesX));
+
+ logassert(nodesx,"Failed to allocate memory (try using slim mode?)"); /* Check calloc() worked */
+
+ nodesx->filename    =(char*)malloc(strlen(option_tmpdirname)+32);
+ nodesx->filename_tmp=(char*)malloc(strlen(option_tmpdirname)+40); /* allow %p to be up to 20 bytes */
+
+ sprintf(nodesx->filename    ,"%s/nodesx.parsed.mem",option_tmpdirname);
+ sprintf(nodesx->filename_tmp,"%s/nodesx.%p.tmp"    ,option_tmpdirname,(void*)nodesx);
+
+ if(append || readonly)
+    if(ExistsFile(nodesx->filename))
+      {
+       off_t size;
+
+       size=SizeFile(nodesx->filename);
+
+       nodesx->number=size/sizeof(NodeX);
+
+       RenameFile(nodesx->filename,nodesx->filename_tmp);
+      }
+
+ if(append)
+    nodesx->fd=OpenFileBufferedAppend(nodesx->filename_tmp);
+ else if(!readonly)
+    nodesx->fd=OpenFileBufferedNew(nodesx->filename_tmp);
+ else
+    nodesx->fd=-1;
+
+#if SLIM
+ nodesx->cache=NewNodeXCache();
+ log_malloc(nodesx->cache,sizeof(*nodesx->cache));
+#endif
+
+ return(nodesx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Free a node list.
+
+  NodesX *nodesx The set of nodes to be freed.
+
+  int keep If set then the results file is to be kept.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FreeNodeList(NodesX *nodesx,int keep)
+{
+ if(keep)
+    RenameFile(nodesx->filename_tmp,nodesx->filename);
+ else
+    DeleteFile(nodesx->filename_tmp);
+
+ free(nodesx->filename);
+ free(nodesx->filename_tmp);
+
+ if(nodesx->idata)
+   {
+    log_free(nodesx->idata);
+    free(nodesx->idata);
+   }
+
+ if(nodesx->gdata)
+   {
+    log_free(nodesx->gdata);
+    free(nodesx->gdata);
+   }
+
+ if(nodesx->pdata)
+   {
+    log_free(nodesx->pdata);
+    free(nodesx->pdata);
+   }
+
+ if(nodesx->super)
+   {
+    log_free(nodesx->super);
+    free(nodesx->super);
+   }
+
+#if SLIM
+ log_free(nodesx->cache);
+ DeleteNodeXCache(nodesx->cache);
+#endif
+
+ free(nodesx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Append a single node to an unsorted node list.
+
+  NodesX *nodesx The set of nodes to modify.
+
+  node_t id The node identifier from the original OSM data.
+
+  double latitude The latitude of the node.
+
+  double longitude The longitude of the node.
+
+  transports_t allow The allowed traffic types through the node.
+
+  nodeflags_t flags The flags to set for this node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void AppendNodeList(NodesX *nodesx,node_t id,double latitude,double longitude,transports_t allow,nodeflags_t flags)
+{
+ NodeX nodex;
+
+ nodex.id=id;
+ nodex.latitude =radians_to_latlong(latitude);
+ nodex.longitude=radians_to_latlong(longitude);
+ nodex.allow=allow;
+ nodex.flags=flags;
+
+ WriteFileBuffered(nodesx->fd,&nodex,sizeof(NodeX));
+
+ nodesx->number++;
+
+ logassert(nodesx->number<NODE_FAKE,"Too many nodes (change index_t to 64-bits?)"); /* NODE_FAKE marks the high-water mark for real nodes. */
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Finish appending nodes and change the filename over.
+
+  NodesX *nodesx The nodes that have been appended.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FinishNodeList(NodesX *nodesx)
+{
+ if(nodesx->fd!=-1)
+    nodesx->fd=CloseFileBuffered(nodesx->fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find a particular node index.
+
+  index_t IndexNodeX Returns the index of the extended node with the specified id.
+
+  NodesX *nodesx The set of nodes to use.
+
+  node_t id The node id to look for.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t IndexNodeX(NodesX *nodesx,node_t id)
+{
+ index_t start=0;
+ index_t end=nodesx->number-1;
+ index_t mid;
+
+ if(nodesx->number==0)          /* No nodes */
+    return(NO_NODE);
+
+ if(id<nodesx->idata[start])    /* Key is before start */
+    return(NO_NODE);
+
+ if(id>nodesx->idata[end])      /* Key is after end */
+    return(NO_NODE);
+
+ /* Binary search - search key exact match only is required.
+  *
+  *  # <- start  |  Check mid and move start or end if it doesn't match
+  *  #           |
+  *  #           |  Since an exact match is wanted we can set end=mid-1
+  *  # <- mid    |  or start=mid+1 because we know that mid doesn't match.
+  *  #           |
+  *  #           |  Eventually either end=start or end=start+1 and one of
+  *  # <- end    |  start or end is the wanted one.
+  */
+
+ do
+   {
+    mid=(start+end)/2;             /* Choose mid point */
+
+    if(nodesx->idata[mid]<id)      /* Mid point is too low */
+       start=mid+1;
+    else if(nodesx->idata[mid]>id) /* Mid point is too high */
+       end=mid?(mid-1):mid;
+    else                           /* Mid point is correct */
+       return(mid);
+   }
+ while((end-start)>1);
+
+ if(nodesx->idata[start]==id)      /* Start is correct */
+    return(start);
+
+ if(nodesx->idata[end]==id)        /* End is correct */
+    return(end);
+
+ return(NO_NODE);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the node list.
+
+  NodesX *nodesx The set of nodes to modify.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SortNodeList(NodesX *nodesx)
+{
+ int fd;
+ index_t xnumber;
+
+ /* Print the start message */
+
+ printf_first("Sorting Nodes");
+
+ /* Re-open the file read-only and a new file writeable */
+
+ fd=ReplaceFileBuffered(nodesx->filename_tmp,&nodesx->fd);
+
+ /* Allocate the array of indexes */
+
+ nodesx->idata=(node_t*)malloc(nodesx->number*sizeof(node_t));
+ log_malloc(nodesx->idata,nodesx->number*sizeof(node_t));
+
+ logassert(nodesx->idata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
+
+ /* Sort the nodes by ID and index them */
+
+ xnumber=nodesx->number;
+
+ sortnodesx=nodesx;
+
+ nodesx->number=filesort_fixed(nodesx->fd,fd,sizeof(NodeX),NULL,
+                                                           (int (*)(const void*,const void*))sort_by_id,
+                                                           (int (*)(void*,index_t))deduplicate_and_index_by_id);
+
+ nodesx->knumber=nodesx->number;
+
+ /* Close the files */
+
+ nodesx->fd=CloseFileBuffered(nodesx->fd);
+ CloseFileBuffered(fd);
+
+ /* Print the final message */
+
+ printf_last("Sorted Nodes: Nodes=%"Pindex_t" Duplicates=%"Pindex_t,xnumber,xnumber-nodesx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the nodes into id order.
+
+  int sort_by_id Returns the comparison of the id fields.
+
+  NodeX *a The first extended node.
+
+  NodeX *b The second extended node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int sort_by_id(NodeX *a,NodeX *b)
+{
+ node_t a_id=a->id;
+ node_t b_id=b->id;
+
+ if(a_id<b_id)
+    return(-1);
+ else if(a_id>b_id)
+    return(1);
+ else
+    return(-FILESORT_PRESERVE_ORDER(a,b)); /* latest version first */
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create the index of identifiers and discard duplicate nodes.
+
+  int deduplicate_and_index_by_id Return 1 if the value is to be kept, otherwise 0.
+
+  NodeX *nodex The extended node.
+
+  index_t index The number of sorted nodes that have already been written to the output file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int deduplicate_and_index_by_id(NodeX *nodex,index_t index)
+{
+ static node_t previd; /* internal variable (reset by first call in each sort; index==0) */
+
+ if(index==0 || nodex->id!=previd)
+   {
+    previd=nodex->id;
+
+    if(nodex->flags&NODE_DELETED)
+       return(0);
+    else
+      {
+       sortnodesx->idata[index]=nodex->id;
+
+       return(1);
+      }
+   }
+ else
+    return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Remove any nodes that are not part of a highway.
+
+  NodesX *nodesx The set of nodes to modify.
+
+  WaysX *waysx The set of ways to use.
+
+  int keep If set to 1 then keep the old data file otherwise delete it.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void RemoveNonHighwayNodes(NodesX *nodesx,WaysX *waysx,int keep)
+{
+ BitMask *usednode;
+ NodeX nodex;
+ index_t i,total=0,highway=0,nothighway=0;
+ int fd;
+
+ /* Print the start message */
+
+ printf_first("Checking Ways for unused Nodes: Ways=0 Highway Nodes=0");
+
+ /* Allocate the node usage bitmask */
+
+ usednode=AllocBitMask(nodesx->number);
+ log_malloc(usednode,LengthBitMask(nodesx->number)*sizeof(BitMask));
+
+ logassert(usednode,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
+
+ /* Re-open the file read-only */
+
+ waysx->fd=ReOpenFileBuffered(waysx->filename_tmp);
+
+ /* Loop through the ways and mark the used nodes */
+
+ for(i=0;i<waysx->number;i++)
+   {
+    WayX wayx;
+    FILESORT_VARINT waysize;
+    node_t node;
+
+    ReadFileBuffered(waysx->fd,&waysize,FILESORT_VARSIZE);
+
+    ReadFileBuffered(waysx->fd,&wayx,sizeof(WayX));
+
+    while(!ReadFileBuffered(waysx->fd,&node,sizeof(node_t)) && node!=NO_NODE_ID)
+      {
+       index_t index=IndexNodeX(nodesx,node);
+
+       waysize-=sizeof(node_t);
+
+       if(index!=NO_NODE)
+         {
+          if(!IsBitSet(usednode,index))
+             highway++;
+
+          SetBit(usednode,index);
+         }
+      }
+
+    waysize-=sizeof(node_t)+sizeof(WayX);
+
+    SkipFileBuffered(waysx->fd,waysize);
+
+    if(!((i+1)%1000))
+       printf_middle("Checking Ways for unused Nodes: Ways=%"Pindex_t" Highway Nodes=%"Pindex_t,i+1,highway);
+   }
+
+ /* Free the now-unneeded index */
+
+ log_free(nodesx->idata);
+ free(nodesx->idata);
+ nodesx->idata=NULL;
+
+ /* Close the file */
+
+ waysx->fd=CloseFileBuffered(waysx->fd);
+
+ /* Print the final message */
+
+ printf_last("Checked Ways for unused Nodes: Ways=%"Pindex_t" Highway Nodes=%"Pindex_t,waysx->number,highway);
+
+
+ /* Print the start message */
+
+ printf_first("Removing unused Nodes: Nodes=0");
+
+ /* Allocate the array of indexes */
+
+ nodesx->idata=(node_t*)malloc(highway*sizeof(node_t));
+ log_malloc(nodesx->idata,highway*sizeof(node_t));
+
+ logassert(nodesx->idata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
+
+ highway=0;
+
+ /* Re-open the file read-only and a new file writeable */
+
+ if(keep)
+   {
+    RenameFile(nodesx->filename_tmp,nodesx->filename);
+
+    nodesx->fd=ReOpenFileBuffered(nodesx->filename);
+
+    fd=OpenFileBufferedNew(nodesx->filename_tmp);
+   }
+ else
+    fd=ReplaceFileBuffered(nodesx->filename_tmp,&nodesx->fd);
+
+ /* Modify the on-disk image */
+
+ while(!ReadFileBuffered(nodesx->fd,&nodex,sizeof(NodeX)))
+   {
+    if(!IsBitSet(usednode,total))
+       nothighway++;
+    else
+      {
+       nodesx->idata[highway]=nodex.id;
+
+       WriteFileBuffered(fd,&nodex,sizeof(NodeX));
+
+       highway++;
+      }
+
+    total++;
+
+    if(!(total%10000))
+       printf_middle("Removing unused Nodes: Nodes=%"Pindex_t" Highway=%"Pindex_t" not-Highway=%"Pindex_t,total,highway,nothighway);
+   }
+
+ nodesx->number=highway;
+
+ /* Close the files */
+
+ nodesx->fd=CloseFileBuffered(nodesx->fd);
+ CloseFileBuffered(fd);
+
+ /* Free the now-unneeded index */
+
+ log_free(usednode);
+ free(usednode);
+
+ /* Print the final message */
+
+ printf_last("Removed unused Nodes: Nodes=%"Pindex_t" Highway=%"Pindex_t" not-Highway=%"Pindex_t,total,highway,nothighway);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Remove any nodes that have been pruned.
+
+  NodesX *nodesx The set of nodes to prune.
+
+  SegmentsX *segmentsx The set of segments to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void RemovePrunedNodes(NodesX *nodesx,SegmentsX *segmentsx)
+{
+ NodeX nodex;
+ index_t total=0,pruned=0,notpruned=0;
+ int fd;
+
+ if(nodesx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Deleting Pruned Nodes: Nodes=0 Pruned=0");
+
+ /* Allocate the array of indexes */
+
+ nodesx->pdata=(index_t*)malloc(nodesx->number*sizeof(index_t));
+ log_malloc(nodesx->pdata,nodesx->number*sizeof(index_t));
+
+ logassert(nodesx->pdata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
+
+ /* Re-open the file read-only and a new file writeable */
+
+ fd=ReplaceFileBuffered(nodesx->filename_tmp,&nodesx->fd);
+
+ /* Modify the on-disk image */
+
+ while(!ReadFileBuffered(nodesx->fd,&nodex,sizeof(NodeX)))
+   {
+    if(segmentsx->firstnode[total]==NO_SEGMENT)
+      {
+       pruned++;
+
+       nodesx->pdata[total]=NO_NODE;
+      }
+    else
+      {
+       nodesx->pdata[total]=notpruned;
+
+       WriteFileBuffered(fd,&nodex,sizeof(NodeX));
+
+       notpruned++;
+      }
+
+    total++;
+
+    if(!(total%10000))
+       printf_middle("Deleting Pruned Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
+   }
+
+ nodesx->number=notpruned;
+
+ /* Close the files */
+
+ nodesx->fd=CloseFileBuffered(nodesx->fd);
+ CloseFileBuffered(fd);
+
+ /* Free the no-longer required memory */
+
+ if(segmentsx->firstnode)
+   {
+    log_free(segmentsx->firstnode);
+    free(segmentsx->firstnode);
+    segmentsx->firstnode=NULL;
+   }
+
+ /* Print the final message */
+
+ printf_last("Deleted Pruned Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the node list geographically.
+
+  NodesX *nodesx The set of nodes to modify.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SortNodeListGeographically(NodesX *nodesx)
+{
+ int fd;
+ ll_bin_t lat_min_bin,lat_max_bin,lon_min_bin,lon_max_bin;
+
+ if(nodesx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Sorting Nodes Geographically");
+
+ /* Work out the range of data */
+
+ lat_min=radians_to_latlong( 2);
+ lat_max=radians_to_latlong(-2);
+ lon_min=radians_to_latlong( 4);
+ lon_max=radians_to_latlong(-4);
+
+ /* Allocate the memory for the geographical index array */
+
+ nodesx->gdata=(index_t*)malloc(nodesx->number*sizeof(index_t));
+ log_malloc(nodesx->gdata,nodesx->number*sizeof(index_t));
+
+ logassert(nodesx->gdata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
+
+ /* Re-open the file read-only and a new file writeable */
+
+ fd=ReplaceFileBuffered(nodesx->filename_tmp,&nodesx->fd);
+
+ /* Sort nodes geographically and index them */
+
+ sortnodesx=nodesx;
+
+ filesort_fixed(nodesx->fd,fd,sizeof(NodeX),(int (*)(void*,index_t))update_id,
+                                            (int (*)(const void*,const void*))sort_by_lat_long,
+                                            (int (*)(void*,index_t))index_by_lat_long);
+
+ /* Close the files */
+
+ nodesx->fd=CloseFileBuffered(nodesx->fd);
+ CloseFileBuffered(fd);
+
+ /* Work out the number of bins */
+
+ if(nodesx->super)
+   {
+    lat_min_bin=latlong_to_bin(lat_min);
+    lon_min_bin=latlong_to_bin(lon_min);
+    lat_max_bin=latlong_to_bin(lat_max);
+    lon_max_bin=latlong_to_bin(lon_max);
+
+    nodesx->latzero=lat_min_bin;
+    nodesx->lonzero=lon_min_bin;
+
+    nodesx->latbins=(lat_max_bin-lat_min_bin)+1;
+    nodesx->lonbins=(lon_max_bin-lon_min_bin)+1;
+   }
+
+ /* Free the memory */
+
+ if(nodesx->super)
+   {
+    log_free(nodesx->super);
+    free(nodesx->super);
+    nodesx->super=NULL;
+   }
+
+ /* Print the final message */
+
+ printf_last("Sorted Nodes Geographically: Nodes=%"Pindex_t,nodesx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Update the node ids.
+
+  int update_id Return 1 if the value is to be kept, otherwise 0.
+
+  NodeX *nodex The extended node.
+
+  index_t index The number of unsorted nodes that have been read from the input file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int update_id(NodeX *nodex,index_t index)
+{
+ nodex->id=index;
+
+ if(sortnodesx->super && IsBitSet(sortnodesx->super,index))
+    nodex->flags|=NODE_SUPER;
+
+ return(1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the nodes into latitude and longitude order (first by longitude bin
+  number, then by latitude bin number and then by exact longitude and then by
+  exact latitude).
+
+  int sort_by_lat_long Returns the comparison of the latitude and longitude fields.
+
+  NodeX *a The first extended node.
+
+  NodeX *b The second extended node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int sort_by_lat_long(NodeX *a,NodeX *b)
+{
+ ll_bin_t a_lon=latlong_to_bin(a->longitude);
+ ll_bin_t b_lon=latlong_to_bin(b->longitude);
+
+ if(a_lon<b_lon)
+    return(-1);
+ else if(a_lon>b_lon)
+    return(1);
+ else
+   {
+    ll_bin_t a_lat=latlong_to_bin(a->latitude);
+    ll_bin_t b_lat=latlong_to_bin(b->latitude);
+
+    if(a_lat<b_lat)
+       return(-1);
+    else if(a_lat>b_lat)
+       return(1);
+    else
+      {
+       if(a->longitude<b->longitude)
+          return(-1);
+       else if(a->longitude>b->longitude)
+          return(1);
+       else
+         {
+          if(a->latitude<b->latitude)
+             return(-1);
+          else if(a->latitude>b->latitude)
+             return(1);
+         }
+
+       return(FILESORT_PRESERVE_ORDER(a,b));
+      }
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create the index between the sorted and unsorted nodes.
+
+  int index_by_lat_long Return 1 if the value is to be kept, otherwise 0.
+
+  NodeX *nodex The extended node.
+
+  index_t index The number of sorted nodes that have already been written to the output file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int index_by_lat_long(NodeX *nodex,index_t index)
+{
+ sortnodesx->gdata[nodex->id]=index;
+
+ if(sortnodesx->super)
+   {
+    if(nodex->latitude<lat_min)
+       lat_min=nodex->latitude;
+    if(nodex->latitude>lat_max)
+       lat_max=nodex->latitude;
+    if(nodex->longitude<lon_min)
+       lon_min=nodex->longitude;
+    if(nodex->longitude>lon_max)
+       lon_max=nodex->longitude;
+   }
+
+ return(1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Save the final node list database to a file.
+
+  NodesX *nodesx The set of nodes to save.
+
+  const char *filename The name of the file to save.
+
+  SegmentsX *segmentsx The set of segments to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SaveNodeList(NodesX *nodesx,const char *filename,SegmentsX *segmentsx)
+{
+ index_t i;
+ int fd;
+ NodesFile nodesfile={0};
+ index_t super_number=0;
+ ll_bin2_t latlonbin=0,maxlatlonbins;
+ index_t *offsets;
+
+ /* Print the start message */
+
+ printf_first("Writing Nodes: Nodes=0");
+
+ /* Allocate the memory for the geographical offsets array */
+
+ offsets=(index_t*)malloc((nodesx->latbins*nodesx->lonbins+1)*sizeof(index_t));
+
+ logassert(offsets,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
+
+ latlonbin=0;
+
+ /* Re-open the file */
+
+ nodesx->fd=ReOpenFileBuffered(nodesx->filename_tmp);
+
+ /* Write out the nodes data */
+
+ fd=OpenFileBufferedNew(filename);
+
+ SeekFileBuffered(fd,sizeof(NodesFile)+(nodesx->latbins*nodesx->lonbins+1)*sizeof(index_t));
+
+ for(i=0;i<nodesx->number;i++)
+   {
+    NodeX nodex;
+    Node node={0};
+    ll_bin_t latbin,lonbin;
+    ll_bin2_t llbin;
+
+    ReadFileBuffered(nodesx->fd,&nodex,sizeof(NodeX));
+
+    /* Create the Node */
+
+    node.latoffset=latlong_to_off(nodex.latitude);
+    node.lonoffset=latlong_to_off(nodex.longitude);
+    node.firstseg=segmentsx->firstnode[i];
+    node.allow=nodex.allow;
+    node.flags=nodex.flags;
+
+    if(node.flags&NODE_SUPER)
+       super_number++;
+
+    /* Work out the offsets */
+
+    latbin=latlong_to_bin(nodex.latitude )-nodesx->latzero;
+    lonbin=latlong_to_bin(nodex.longitude)-nodesx->lonzero;
+    llbin=lonbin*nodesx->latbins+latbin;
+
+    for(;latlonbin<=llbin;latlonbin++)
+       offsets[latlonbin]=i;
+
+    /* Write the data */
+
+    WriteFileBuffered(fd,&node,sizeof(Node));
+
+    if(!((i+1)%10000))
+       printf_middle("Writing Nodes: Nodes=%"Pindex_t,i+1);
+   }
+
+ /* Close the file */
+
+ nodesx->fd=CloseFileBuffered(nodesx->fd);
+
+ /* Finish off the offset indexing and write them out */
+
+ maxlatlonbins=nodesx->latbins*nodesx->lonbins;
+
+ for(;latlonbin<=maxlatlonbins;latlonbin++)
+    offsets[latlonbin]=nodesx->number;
+
+ SeekFileBuffered(fd,sizeof(NodesFile));
+ WriteFileBuffered(fd,offsets,(nodesx->latbins*nodesx->lonbins+1)*sizeof(index_t));
+
+ free(offsets);
+
+ /* Write out the header structure */
+
+ nodesfile.number=nodesx->number;
+ nodesfile.snumber=super_number;
+
+ nodesfile.latbins=nodesx->latbins;
+ nodesfile.lonbins=nodesx->lonbins;
+
+ nodesfile.latzero=nodesx->latzero;
+ nodesfile.lonzero=nodesx->lonzero;
+
+ SeekFileBuffered(fd,0);
+ WriteFileBuffered(fd,&nodesfile,sizeof(NodesFile));
+
+ CloseFileBuffered(fd);
+
+ /* Free the memory in the segments */
+
+ log_free(segmentsx->firstnode);
+ free(segmentsx->firstnode);
+ segmentsx->firstnode=NULL;
+
+ /* Print the final message */
+
+ printf_last("Wrote Nodes: Nodes=%"Pindex_t,nodesx->number);
+}
diff --git a/3rdparty/Routino/src/nodesx.h b/3rdparty/Routino/src/nodesx.h
new file mode 100644
index 0000000..84bd380
--- /dev/null
+++ b/3rdparty/Routino/src/nodesx.h
@@ -0,0 +1,186 @@
+/***************************************
+ A header file for the extended nodes.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2013 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef NODESX_H
+#define NODESX_H    /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+
+#include "types.h"
+#include "nodes.h"
+
+#include "typesx.h"
+
+#include "cache.h"
+#include "files.h"
+
+
+/* Data structures */
+
+
+/*+ An extended structure used for processing. +*/
+struct _NodeX
+{
+ node_t       id;               /*+ The node identifier; initially the OSM value, later the Node index, finally the first segment. +*/
+
+ latlong_t    latitude;         /*+ The node latitude. +*/
+ latlong_t    longitude;        /*+ The node longitude. +*/
+
+ transports_t allow;            /*+ The node allowed traffic. +*/
+ nodeflags_t  flags;            /*+ The node flags. +*/
+};
+
+/*+ A structure containing a set of nodes (memory format). +*/
+struct _NodesX
+{
+ char     *filename;            /*+ The name of the intermediate file (for the NodesX). +*/
+ char     *filename_tmp;        /*+ The name of the temporary file (for the NodesX). +*/
+
+ int       fd;                  /*+ The file descriptor of the open file (for the NodesX). +*/
+
+ index_t   number;              /*+ The number of extended nodes still being considered. +*/
+ index_t   knumber;             /*+ The number of extended nodes kept for next time. +*/
+
+#if !SLIM
+
+ NodeX    *data;                /*+ The extended node data (when mapped into memory). +*/
+
+#else
+
+ NodeX     cached[3];           /*+ Three cached extended nodes read from the file in slim mode. +*/
+ index_t   incache[3];          /*+ The indexes of the cached extended nodes. +*/
+
+ NodeXCache *cache;             /*+ A RAM cache of extended nodes read from the file. +*/
+
+#endif
+
+ node_t   *idata;               /*+ The extended node IDs (sorted by ID). +*/
+
+ index_t  *pdata;               /*+ The node indexes after pruning. +*/
+
+ index_t  *gdata;               /*+ The final node indexes (sorted geographically). +*/
+
+ BitMask  *super;               /*+ A bit-mask marker for super nodes (same order as sorted nodes). +*/
+
+ index_t   latbins;             /*+ The number of bins containing latitude. +*/
+ index_t   lonbins;             /*+ The number of bins containing longitude. +*/
+
+ ll_bin_t  latzero;             /*+ The bin number of the furthest south bin. +*/
+ ll_bin_t  lonzero;             /*+ The bin number of the furthest west bin. +*/
+};
+
+
+/* Functions in nodesx.c */
+
+NodesX *NewNodeList(int append,int readonly);
+void FreeNodeList(NodesX *nodesx,int keep);
+
+void AppendNodeList(NodesX *nodesx,node_t id,double latitude,double longitude,transports_t allow,nodeflags_t flags);
+void FinishNodeList(NodesX *nodesx);
+
+index_t IndexNodeX(NodesX *nodesx,node_t id);
+
+void SortNodeList(NodesX *nodesx);
+
+void RemoveNonHighwayNodes(NodesX *nodesx,WaysX *waysx,int keep);
+
+void RemovePrunedNodes(NodesX *nodesx,SegmentsX *segmentsx);
+
+void SortNodeListGeographically(NodesX *nodesx);
+
+void SaveNodeList(NodesX *nodesx,const char *filename,SegmentsX *segmentsx);
+
+
+/* Macros and inline functions */
+
+#if !SLIM
+
+#define LookupNodeX(nodesx,index,position)      &(nodesx)->data[index]
+  
+#define PutBackNodeX(nodesx,nodex)              while(0) { /* nop */ }
+
+#else
+
+/* Prototypes */
+
+static inline NodeX *LookupNodeX(NodesX *nodesx,index_t index,int position);
+
+static inline void PutBackNodeX(NodesX *nodesx,NodeX *nodex);
+
+CACHE_NEWCACHE_PROTO(NodeX)
+CACHE_DELETECACHE_PROTO(NodeX)
+CACHE_FETCHCACHE_PROTO(NodeX)
+CACHE_REPLACECACHE_PROTO(NodeX)
+CACHE_INVALIDATECACHE_PROTO(NodeX)
+
+
+/* Inline functions */
+
+CACHE_STRUCTURE(NodeX)
+CACHE_NEWCACHE(NodeX)
+CACHE_DELETECACHE(NodeX)
+CACHE_FETCHCACHE(NodeX)
+CACHE_REPLACECACHE(NodeX)
+CACHE_INVALIDATECACHE(NodeX)
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Lookup a particular extended node with the specified id from the file on disk.
+
+  NodeX *LookupNodeX Returns a pointer to a cached copy of the extended node.
+
+  NodesX *nodesx The set of nodes to use.
+
+  index_t index The node index to look for.
+
+  int position The position in the cache to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline NodeX *LookupNodeX(NodesX *nodesx,index_t index,int position)
+{
+ nodesx->cached[position-1]=*FetchCachedNodeX(nodesx->cache,index,nodesx->fd,0);
+
+ nodesx->incache[position-1]=index;
+
+ return(&nodesx->cached[position-1]);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Put back an extended node's data into the file on disk.
+
+  NodesX *nodesx The set of nodes to modify.
+
+  NodeX *nodex The extended node to be put back.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline void PutBackNodeX(NodesX *nodesx,NodeX *nodex)
+{
+ int position1=nodex-&nodesx->cached[0];
+
+ ReplaceCachedNodeX(nodesx->cache,nodex,nodesx->incache[position1],nodesx->fd,0);
+}
+
+#endif /* SLIM */
+
+
+#endif /* NODESX_H */
diff --git a/3rdparty/Routino/src/optimiser.c b/3rdparty/Routino/src/optimiser.c
new file mode 100644
index 0000000..d8dbe54
--- /dev/null
+++ b/3rdparty/Routino/src/optimiser.c
@@ -0,0 +1,1815 @@
+/***************************************
+ Routing optimiser.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include "types.h"
+#include "nodes.h"
+#include "segments.h"
+#include "ways.h"
+#include "relations.h"
+
+#include "logging.h"
+#include "functions.h"
+#include "fakes.h"
+#include "results.h"
+
+
+/*+ To help when debugging +*/
+#define DEBUG 0
+
+
+/* Global variables */
+
+/*+ The option not to print any progress information. +*/
+extern int option_quiet;
+
+/*+ The option to calculate the quickest route insted of the shortest. +*/
+extern int option_quickest;
+
+
+/* Local functions */
+
+static index_t FindSuperSegment(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t finish_node,index_t finish_segment);
+static Results *FindSuperRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t finish_node);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the optimum route between two nodes not passing through a super-node.
+
+  Results *FindNormalRoute Returns a set of results.
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  Profile *profile The profile containing the transport type, speeds and allowed highways.
+
+  index_t start_node The start node.
+
+  index_t prev_segment The previous segment before the start node.
+
+  index_t finish_node The finish node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t prev_segment,index_t finish_node)
+{
+ Results *results;
+ Queue   *queue;
+ score_t finish_score;
+ double  finish_lat,finish_lon;
+ Result  *finish_result;
+ Result  *result1,*result2;
+ int     force_uturn=0;
+
+#if DEBUG
+ printf("    FindNormalRoute(...,start_node=%"Pindex_t" prev_segment=%"Pindex_t" finish_node=%"Pindex_t")\n",start_node,prev_segment,finish_node);
+#endif
+
+ /* Set up the finish conditions */
+
+ finish_score=INF_SCORE;
+ finish_result=NULL;
+
+ if(IsFakeNode(finish_node))
+    GetFakeLatLong(finish_node,&finish_lat,&finish_lon);
+ else
+    GetLatLong(nodes,finish_node,NULL,&finish_lat,&finish_lon);
+
+ /* Create the list of results and insert the first node into the queue */
+
+ results=NewResultsList(8);
+ queue=NewQueueList(8);
+
+ results->start_node=start_node;
+ results->prev_segment=prev_segment;
+
+ result1=InsertResult(results,results->start_node,results->prev_segment);
+
+ InsertInQueue(queue,result1,0);
+
+ /* Check for barrier at start waypoint - must perform U-turn */
+
+ if(prev_segment!=NO_SEGMENT && !IsFakeNode(start_node))
+   {
+    Node *startp=LookupNode(nodes,start_node,1);
+
+    if(!(startp->allow&profile->allow))
+       force_uturn=1;
+   }
+
+ /* Loop across all nodes in the queue */
+
+ while((result1=PopFromQueue(queue)))
+   {
+    Node *node1p=NULL;
+    Segment *segmentp;
+    index_t node1,seg1,seg1r;
+    index_t turnrelation=NO_RELATION;
+
+    /* score must be better than current best score */
+    if(result1->score>=finish_score)
+       continue;
+
+    node1=result1->node;
+    seg1=result1->segment;
+
+    if(IsFakeSegment(seg1))
+       seg1r=IndexRealSegment(seg1);
+    else
+       seg1r=seg1;
+
+    if(!IsFakeNode(node1))
+       node1p=LookupNode(nodes,node1,1);
+
+    /* lookup if a turn restriction applies */
+    if(profile->turns && node1p && IsTurnRestrictedNode(node1p))
+       turnrelation=FindFirstTurnRelation2(relations,node1,seg1r);
+
+    /* Loop across all segments */
+
+    if(IsFakeNode(node1))
+       segmentp=FirstFakeSegment(node1);
+    else
+       segmentp=FirstSegment(segments,node1p,1);
+
+    while(segmentp)
+      {
+       Node *node2p=NULL;
+       Way *wayp;
+       index_t node2,seg2,seg2r;
+       score_t segment_pref,segment_score,cumulative_score;
+       int i;
+
+       node2=OtherNode(segmentp,node1); /* need this here because we use node2 at the end of the loop */
+
+       /* must be a normal segment */
+       if(!IsNormalSegment(segmentp))
+          goto endloop;
+
+       /* must obey one-way restrictions (unless profile allows) */
+       if(profile->oneway && IsOnewayTo(segmentp,node1))
+         {
+          if(profile->allow!=Transports_Bicycle)
+             goto endloop;
+
+          wayp=LookupWay(ways,segmentp->way,1);
+
+          if(!(wayp->type&Highway_CycleBothWays))
+             goto endloop;
+         }
+
+       if(IsFakeNode(node1) || IsFakeNode(node2))
+         {
+          seg2 =IndexFakeSegment(segmentp);
+          seg2r=IndexRealSegment(seg2);
+         }
+       else
+         {
+          seg2 =IndexSegment(segments,segmentp);
+          seg2r=seg2;
+         }
+
+       /* must perform U-turn in special cases */
+       if(force_uturn && node1==results->start_node)
+         {
+          if(seg2r!=result1->segment)
+             goto endloop;
+         }
+       else
+          /* must not perform U-turn (unless profile allows) */
+          if(profile->turns && (seg1==seg2 || seg1==seg2r || seg1r==seg2 || (seg1r==seg2r && IsFakeUTurn(seg1,seg2))))
+             goto endloop;
+
+       /* must obey turn relations */
+       if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1r,seg2r,profile->allow))
+          goto endloop;
+
+       if(!IsFakeNode(node2))
+          node2p=LookupNode(nodes,node2,2);
+
+       /* must not pass over super-node */
+       if(node2!=finish_node && node2p && IsSuperNode(node2p))
+          goto endloop;
+
+       wayp=LookupWay(ways,segmentp->way,1);
+
+       /* mode of transport must be allowed on the highway */
+       if(!(wayp->allow&profile->allow))
+          goto endloop;
+
+       /* must obey weight restriction (if exists) */
+       if(wayp->weight && wayp->weight<profile->weight)
+          goto endloop;
+
+       /* must obey height/width/length restriction (if exist) */
+       if((wayp->height && wayp->height<profile->height) ||
+          (wayp->width  && wayp->width <profile->width ) ||
+          (wayp->length && wayp->length<profile->length))
+          goto endloop;
+
+       segment_pref=profile->highway[HIGHWAY(wayp->type)];
+
+       /* highway preferences must allow this highway */
+       if(segment_pref==0)
+          goto endloop;
+
+       for(i=1;i<Property_Count;i++)
+          if(ways->file.props & PROPERTIES(i))
+            {
+             if(wayp->props & PROPERTIES(i))
+                segment_pref*=profile->props_yes[i];
+             else
+                segment_pref*=profile->props_no[i];
+            }
+
+       /* profile preferences must allow this highway */
+       if(segment_pref==0)
+          goto endloop;
+
+       /* mode of transport must be allowed through node2 unless it is the final node */
+       if(node2p && node2!=finish_node && !(node2p->allow&profile->allow))
+          goto endloop;
+
+       /* calculate the score for the segment and cumulative */
+       if(option_quickest==0)
+          segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref;
+       else
+          segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref;
+
+       cumulative_score=result1->score+segment_score;
+
+       /* score must be better than current best score */
+       if(cumulative_score>=finish_score)
+          goto endloop;
+
+       /* find whether the node/segment combination already exists */
+       result2=FindResult(results,node2,seg2);
+
+       if(!result2) /* New end node/segment combination */
+         {
+          result2=InsertResult(results,node2,seg2);
+          result2->prev=result1;
+          result2->score=cumulative_score;
+         }
+       else if(cumulative_score<result2->score) /* New score for end node/segment combination is better */
+         {
+          result2->prev=result1;
+          result2->score=cumulative_score;
+          result2->segment=seg2;
+         }
+       else
+          goto endloop;
+
+       if(node2==finish_node)
+         {
+          finish_score=cumulative_score;
+          finish_result=result2;
+
+          results->finish_node=node2;
+          results->last_segment=seg2;
+         }
+       else
+          InsertInQueue(queue,result2,result2->score);
+
+      endloop:
+
+       if(IsFakeNode(node1))
+          segmentp=NextFakeSegment(segmentp,node1);
+       else if(IsFakeNode(node2))
+          segmentp=NULL; /* cannot call NextSegment() with a fake segment */
+       else
+         {
+          segmentp=NextSegment(segments,segmentp,node1);
+
+          if(!segmentp && IsFakeNode(finish_node))
+             segmentp=ExtraFakeSegment(node1,finish_node);
+         }
+      }
+   }
+
+ FreeQueueList(queue);
+
+ /* Check it worked */
+
+ if(!finish_result)
+   {
+#if DEBUG
+    printf("      Failed\n");
+#endif
+
+    FreeResultsList(results);
+    return(NULL);
+   }
+
+ FixForwardRoute(results,finish_result);
+
+#if DEBUG
+ Result *r=FindResult(results,results->start_node,results->prev_segment);
+
+ printf("      -------- normal route (between super-nodes)\n");
+
+ while(r)
+   {
+    printf("      node=%"Pindex_t" segment=%"Pindex_t" score=%f%s%s%s\n",r->node,r->segment,r->score,
+                                                                         (IsSuperNode(LookupNode(nodes,r->node,1))?" (super)":""),
+                                                                         (r->node==results->start_node&&r->segment==results->prev_segment?" (start)":""),
+                                                                         (r->node==results->finish_node?" (finish)":""));
+
+    r=r->next;
+   }
+#endif
+
+ return(results);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the optimum route between two nodes where the start and end are a set of pre/post-routed super-nodes.
+
+  Results *FindMiddleRoute Returns a set of results.
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  Profile *profile The profile containing the transport type, speeds and allowed highways.
+
+  Results *begin The initial portion of the route.
+
+  Results *end The final portion of the route.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,Results *begin,Results *end)
+{
+ Results *results;
+ Queue   *queue;
+ Result  *finish_result;
+ score_t finish_score;
+ double  finish_lat,finish_lon;
+ Result  *result1,*result2,*result3,*result4;
+ int     force_uturn=0;
+
+#if DEBUG
+ printf("  FindMiddleRoute(...,[begin has %d nodes],[end has %d nodes])\n",begin->number,end->number);
+#endif
+
+#if !DEBUG && !defined(LIBROUTINO)
+ if(!option_quiet)
+    printf_first("Finding Middle Route: Super-Nodes checked = 0");
+#endif
+
+ /* Set up the finish conditions */
+
+ finish_score=INF_SCORE;
+ finish_result=NULL;
+
+ if(IsFakeNode(end->finish_node))
+    GetFakeLatLong(end->finish_node,&finish_lat,&finish_lon);
+ else
+    GetLatLong(nodes,end->finish_node,NULL,&finish_lat,&finish_lon);
+
+ /* Create the list of results and insert the first node into the queue */
+
+ results=NewResultsList(20);
+ queue=NewQueueList(12);
+
+ results->start_node=begin->start_node;
+ results->prev_segment=begin->prev_segment;
+
+ if(begin->number==1 && begin->prev_segment!=NO_SEGMENT)
+   {
+    index_t superseg=FindSuperSegment(nodes,segments,ways,relations,profile,begin->start_node,begin->prev_segment);
+
+    results->prev_segment=superseg;
+   }
+
+ result1=InsertResult(results,results->start_node,results->prev_segment);
+
+ /* Insert the finish points of the beginning part of the path into the queue,
+    translating the segments into super-segments. */
+
+ result3=FirstResult(begin);
+
+ while(result3)
+   {
+    if((results->start_node!=result3->node || results->prev_segment!=result3->segment) &&
+       !IsFakeNode(result3->node) && IsSuperNode(LookupNode(nodes,result3->node,3)))
+      {
+       Result *result5=result1;
+       index_t superseg=FindSuperSegment(nodes,segments,ways,relations,profile,result3->node,result3->segment);
+
+       if(superseg!=result3->segment)
+         {
+          result5=InsertResult(results,result3->node,result3->segment);
+
+          result5->score=result3->score;
+
+          result5->prev=result1;
+         }
+
+       if(!FindResult(results,result3->node,superseg))
+         {
+          result2=InsertResult(results,result3->node,superseg);
+          result2->prev=result5;
+
+          result2->score=result3->score;
+
+          InsertInQueue(queue,result2,result3->score);
+
+          if((result4=FindResult(end,result2->node,result2->segment)))
+            {
+             if((result2->score+result4->score)<finish_score)
+               {
+                finish_score=result2->score+result4->score;
+                finish_result=result2;
+               }
+            }
+         }
+      }
+
+    result3=NextResult(begin,result3);
+   }
+
+ if(begin->number==1)
+    InsertInQueue(queue,result1,0);
+
+ /* Check for barrier at start waypoint - must perform U-turn */
+
+ if(begin->number==1 && results->prev_segment!=NO_SEGMENT)
+   {
+    Node *startp=LookupNode(nodes,result1->node,1);
+
+    if(!(startp->allow&profile->allow))
+       force_uturn=1;
+   }
+
+ /* Loop across all nodes in the queue */
+
+ while((result1=PopFromQueue(queue)))
+   {
+    Node *node1p;
+    Segment *segmentp;
+    index_t node1,seg1;
+    index_t turnrelation=NO_RELATION;
+
+    /* score must be better than current best score */
+    if(result1->score>=finish_score)
+       continue;
+
+    node1=result1->node;
+    seg1=result1->segment;
+
+    node1p=LookupNode(nodes,node1,1); /* node1 cannot be a fake node (must be a super-node) */
+
+    /* lookup if a turn restriction applies */
+    if(profile->turns && IsTurnRestrictedNode(node1p)) /* node1 cannot be a fake node (must be a super-node) */
+       turnrelation=FindFirstTurnRelation2(relations,node1,seg1);
+
+    /* Loop across all segments */
+
+    segmentp=FirstSegment(segments,node1p,1); /* node1 cannot be a fake node (must be a super-node) */
+
+    while(segmentp)
+      {
+       Node *node2p;
+       Way *wayp;
+       index_t node2,seg2;
+       score_t segment_pref,segment_score,cumulative_score;
+       int i;
+
+       /* must be a super segment */
+       if(!IsSuperSegment(segmentp))
+          goto endloop;
+
+       /* must obey one-way restrictions (unless profile allows) */
+       if(profile->oneway && IsOnewayTo(segmentp,node1))
+         {
+          if(profile->allow!=Transports_Bicycle)
+             goto endloop;
+
+          wayp=LookupWay(ways,segmentp->way,1);
+
+          if(!(wayp->type&Highway_CycleBothWays))
+             goto endloop;
+         }
+
+       seg2=IndexSegment(segments,segmentp); /* segment cannot be a fake segment (must be a super-segment) */
+
+       /* must perform U-turn in special cases */
+       if(force_uturn && node1==results->start_node)
+         {
+          if(seg2!=result1->segment)
+             goto endloop;
+         }
+       else
+          /* must not perform U-turn */
+          if(seg1==seg2) /* No fake segments, applies to all profiles */
+             goto endloop;
+
+       /* must obey turn relations */
+       if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1,seg2,profile->allow))
+          goto endloop;
+
+       wayp=LookupWay(ways,segmentp->way,1);
+
+       /* mode of transport must be allowed on the highway */
+       if(!(wayp->allow&profile->allow))
+          goto endloop;
+
+       /* must obey weight restriction (if exists) */
+       if(wayp->weight && wayp->weight<profile->weight)
+          goto endloop;
+
+       /* must obey height/width/length restriction (if exist) */
+       if((wayp->height && wayp->height<profile->height) ||
+          (wayp->width  && wayp->width <profile->width ) ||
+          (wayp->length && wayp->length<profile->length))
+          goto endloop;
+
+       segment_pref=profile->highway[HIGHWAY(wayp->type)];
+
+       /* highway preferences must allow this highway */
+       if(segment_pref==0)
+          goto endloop;
+
+       for(i=1;i<Property_Count;i++)
+          if(ways->file.props & PROPERTIES(i))
+            {
+             if(wayp->props & PROPERTIES(i))
+                segment_pref*=profile->props_yes[i];
+             else
+                segment_pref*=profile->props_no[i];
+            }
+
+       /* profile preferences must allow this highway */
+       if(segment_pref==0)
+          goto endloop;
+
+       node2=OtherNode(segmentp,node1);
+
+       node2p=LookupNode(nodes,node2,2); /* node2 cannot be a fake node (must be a super-node) */
+
+       /* mode of transport must be allowed through node2 unless it is the final node */
+       if(node2!=end->finish_node && !(node2p->allow&profile->allow))
+          goto endloop;
+
+       /* calculate the score for the segment and cumulative */
+       if(option_quickest==0)
+          segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref;
+       else
+          segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref;
+
+       cumulative_score=result1->score+segment_score;
+
+       /* score must be better than current best score */
+       if(cumulative_score>=finish_score)
+          goto endloop;
+
+       /* find whether the node/segment combination already exists */
+       result2=FindResult(results,node2,seg2);
+
+       if(!result2) /* New end node/segment pair */
+         {
+          result2=InsertResult(results,node2,seg2);
+          result2->prev=result1;
+          result2->score=cumulative_score;
+         }
+       else if(cumulative_score<result2->score) /* New end node/segment pair is better */
+         {
+          result2->prev=result1;
+          result2->score=cumulative_score;
+         }
+       else
+          goto endloop;
+
+       if((result3=FindResult(end,node2,seg2)))
+         {
+          if((result2->score+result3->score)<finish_score)
+            {
+             finish_score=result2->score+result3->score;
+             finish_result=result2;
+
+             results->finish_node=node2;
+             results->last_segment=seg2;
+            }
+         }
+       else
+         {
+          double lat,lon;
+          distance_t direct;
+          score_t potential_score;
+
+          GetLatLong(nodes,node2,node2p,&lat,&lon); /* node2 cannot be a fake node (must be a super-node) */
+
+          direct=Distance(lat,lon,finish_lat,finish_lon);
+
+          if(option_quickest==0)
+             potential_score=result2->score+(score_t)direct/profile->max_pref;
+          else
+             potential_score=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref;
+
+          if(potential_score<finish_score)
+             InsertInQueue(queue,result2,potential_score);
+         }
+
+      endloop:
+
+       segmentp=NextSegment(segments,segmentp,node1); /* node1 cannot be a fake node (must be a super-node) */
+      }
+   }
+
+ FreeQueueList(queue);
+
+ /* Check it worked */
+
+ if(!finish_result)
+   {
+#if DEBUG
+    printf("    Failed\n");
+#endif
+
+#if !DEBUG && !defined(LIBROUTINO)
+    if(!option_quiet)
+       printf_last("Found Middle Route: Super-Nodes checked = %d - Fail",results->number);
+#endif
+
+    FreeResultsList(results);
+    return(NULL);
+   }
+
+ FixForwardRoute(results,finish_result);
+
+#if DEBUG
+ Result *r=FindResult(results,results->start_node,results->prev_segment);
+
+ printf("    -------- middle route (start route then via super-nodes/segments)\n");
+
+ while(r)
+   {
+    printf("    node=%"Pindex_t" segment=%"Pindex_t" score=%f%s%s%s\n",r->node,r->segment,r->score,
+                                                                       (IsSuperNode(LookupNode(nodes,r->node,1))?" (super)":""),
+                                                                       (r->node==results->start_node&&r->segment==results->prev_segment?" (start)":""),
+                                                                       (r->node==results->finish_node?" (finish)":""));
+
+    r=r->next;
+   }
+#endif
+
+#if !DEBUG && !defined(LIBROUTINO)
+ if(!option_quiet)
+    printf_last("Found Middle Route: Super-Nodes checked = %d",results->number);
+#endif
+
+ return(results);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the super-segment that represents the route that contains a particular segment.
+
+  index_t FindSuperSegment Returns the index of the super-segment.
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  Profile *profile The profile containing the transport type, speeds and allowed highways.
+
+  index_t finish_node The super-node that the route ends at.
+
+  index_t finish_segment The segment that the route ends with.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static index_t FindSuperSegment(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t finish_node,index_t finish_segment)
+{
+ Node *supernodep;
+ Segment *supersegmentp;
+
+ if(IsFakeSegment(finish_segment))
+    finish_segment=IndexRealSegment(finish_segment);
+
+ supernodep=LookupNode(nodes,finish_node,3); /* finish_node cannot be a fake node (must be a super-node) */
+ supersegmentp=LookupSegment(segments,finish_segment,4); /* finish_segment cannot be a fake segment. */
+
+ if(IsSuperSegment(supersegmentp))
+    return(finish_segment);
+
+ /* Loop across all segments */
+
+ supersegmentp=FirstSegment(segments,supernodep,4); /* supernode cannot be a fake node (must be a super-node) */
+
+ while(supersegmentp)
+   {
+    if(IsSuperSegment(supersegmentp))
+      {
+       Results *results;
+       Result *result;
+       index_t start_node;
+
+       start_node=OtherNode(supersegmentp,finish_node);
+
+       results=FindSuperRoute(nodes,segments,ways,relations,profile,start_node,finish_node);
+
+       if(!results)
+          continue;
+
+       result=FindResult(results,finish_node,finish_segment);
+
+       if(result && (distance_t)result->score==DISTANCE(supersegmentp->distance))
+         {
+          FreeResultsList(results);
+          return(IndexSegment(segments,supersegmentp));
+         }
+
+       if(results)
+          FreeResultsList(results);
+      }
+
+    supersegmentp=NextSegment(segments,supersegmentp,finish_node); /* finish_node cannot be a fake node (must be a super-node) */
+   }
+
+ return(finish_segment);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the shortest route between two super-nodes using only normal nodes.
+  This is effectively the same function as is used in superx.c when finding super-segments initially.
+
+  Results *FindSuperRoute Returns a set of results.
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  Profile *profile The profile containing the transport type, speeds and allowed highways.
+
+  index_t start_node The start node.
+
+  index_t finish_node The finish node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static Results *FindSuperRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t finish_node)
+{
+ Results *results;
+ Queue   *queue;
+ Result  *result1,*result2;
+
+#if DEBUG
+ printf("      FindSuperRoute(...,start_node=%"Pindex_t" finish_node=%"Pindex_t")\n",start_node,finish_node);
+#endif
+
+ /* Create the list of results and insert the first node into the queue */
+
+ results=NewResultsList(8);
+ queue=NewQueueList(8);
+
+ results->start_node=start_node;
+ results->prev_segment=NO_SEGMENT;
+
+ result1=InsertResult(results,results->start_node,results->prev_segment);
+
+ InsertInQueue(queue,result1,0);
+
+ /* Loop across all nodes in the queue */
+
+ while((result1=PopFromQueue(queue)))
+   {
+    Node *node1p=NULL;
+    Segment *segmentp;
+    index_t node1,seg1;
+
+    node1=result1->node;
+    seg1=result1->segment;
+
+    node1p=LookupNode(nodes,node1,3); /* node1 cannot be a fake node */
+
+    /* Loop across all segments */
+
+    segmentp=FirstSegment(segments,node1p,3); /* node1 cannot be a fake node */
+
+    while(segmentp)
+      {
+       Node *node2p=NULL;
+       index_t node2,seg2;
+       score_t cumulative_score;
+
+       /* must be a normal segment */
+       if(!IsNormalSegment(segmentp))
+          goto endloop;
+
+       /* must obey one-way restrictions */
+       if(IsOnewayTo(segmentp,node1))
+         {
+          Way *wayp;
+
+          if(profile->allow!=Transports_Bicycle)
+             goto endloop;
+
+          wayp=LookupWay(ways,segmentp->way,2);
+
+          if(!(wayp->type&Highway_CycleBothWays))
+             goto endloop;
+         }
+
+       seg2=IndexSegment(segments,segmentp);
+
+       /* must not perform U-turn */
+       if(seg1==seg2)
+          goto endloop;
+
+       node2=OtherNode(segmentp,node1);
+
+       node2p=LookupNode(nodes,node2,4); /* node2 cannot be a fake node */
+
+       /* must not pass over super-node */
+       if(node2!=finish_node && IsSuperNode(node2p))
+          goto endloop;
+
+       /* Specifically looking for the shortest route to emulate superx.c */
+       cumulative_score=result1->score+(score_t)DISTANCE(segmentp->distance);
+
+       result2=FindResult(results,node2,seg2);
+
+       if(!result2) /* New end node/segment combination */
+         {
+          result2=InsertResult(results,node2,seg2);
+          result2->prev=result1;
+          result2->score=cumulative_score;
+         }
+       else if(cumulative_score<result2->score) /* New score for end node/segment combination is better */
+         {
+          result2->prev=result1;
+          result2->segment=seg2;
+          result2->score=cumulative_score;
+         }
+       else goto endloop;
+
+       /* don't route beyond a super-node. */
+       if(!IsSuperNode(node2p))
+          InsertInQueue(queue,result2,result2->score);
+
+      endloop:
+
+       segmentp=NextSegment(segments,segmentp,node1);
+      }
+   }
+
+ FreeQueueList(queue);
+
+#if DEBUG
+ Result *s=FirstResult(results);
+
+ while(s)
+   {
+    if(s->node==finish_node)
+      {
+       Result *r=FindResult(results,s->node,s->segment);
+
+       printf("        -------- super-route\n");
+
+       while(r)
+         {
+          printf("        node=%"Pindex_t" segment=%"Pindex_t" score=%f%s%s%s\n",r->node,r->segment,r->score,
+                                                                                (IsSuperNode(LookupNode(nodes,r->node,1))?" (super)":""),
+                                                                                (r->node==start_node?" (start)":""),
+                                                                                (r->node==finish_node?" (finish)":""));
+
+          r=r->prev;
+         }
+      }
+
+    s=NextResult(results,s);
+   }
+#endif
+
+ return(results);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find all routes from a specified node to any super-node.
+
+  Results *FindStartRoutes Returns a set of results.
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  Profile *profile The profile containing the transport type, speeds and allowed highways.
+
+  index_t start_node The start node.
+
+  index_t prev_segment The previous segment before the start node.
+
+  index_t finish_node The finish node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t prev_segment,index_t finish_node)
+{
+ Results *results;
+ Queue   *queue,*superqueue;
+ Result  *result1,*result2;
+ Result  *finish_result=NULL;
+ score_t finish_score=INF_SCORE;
+ int     nsuper=0,force_uturn=0;
+
+#if DEBUG
+ printf("  FindStartRoutes(...,start_node=%"Pindex_t" prev_segment=%"Pindex_t" finish_node=%"Pindex_t")\n",start_node,prev_segment,finish_node);
+#endif
+
+#if !DEBUG && !defined(LIBROUTINO)
+ if(!option_quiet)
+    printf_first("Finding Start Route: Nodes checked = 0");
+#endif
+
+ /* Create the list of results and insert the first node into the queue */
+
+ results=NewResultsList(8);
+ queue=NewQueueList(8);
+ superqueue=NewQueueList(8);
+
+ results->start_node=start_node;
+ results->prev_segment=prev_segment;
+
+ result1=InsertResult(results,results->start_node,results->prev_segment);
+
+ InsertInQueue(queue,result1,0);
+
+ /* Check for barrier at start waypoint - must perform U-turn */
+
+ if(prev_segment!=NO_SEGMENT && !IsFakeNode(start_node))
+   {
+    Node *startp=LookupNode(nodes,start_node,1);
+
+    if(!(startp->allow&profile->allow))
+       force_uturn=1;
+   }
+
+ /* Loop across all nodes in the queue */
+
+ while((result1=PopFromQueue(queue)))
+   {
+    Node *node1p=NULL;
+    Segment *segmentp;
+    index_t node1,seg1,seg1r;
+    index_t turnrelation=NO_RELATION;
+
+    /* score must be better than current best score */
+    if(result1->score>=finish_score)
+       continue;
+
+    node1=result1->node;
+    seg1=result1->segment;
+
+    if(IsFakeSegment(seg1))
+       seg1r=IndexRealSegment(seg1);
+    else
+       seg1r=seg1;
+
+    if(!IsFakeNode(node1))
+       node1p=LookupNode(nodes,node1,1);
+
+    /* lookup if a turn restriction applies */
+    if(profile->turns && node1p && IsTurnRestrictedNode(node1p))
+       turnrelation=FindFirstTurnRelation2(relations,node1,seg1r);
+
+    /* Loop across all segments */
+
+    if(IsFakeNode(node1))
+       segmentp=FirstFakeSegment(node1);
+    else
+       segmentp=FirstSegment(segments,node1p,1);
+
+    while(segmentp)
+      {
+       Node *node2p=NULL;
+       Way *wayp;
+       index_t node2,seg2,seg2r;
+       score_t segment_pref,segment_score,cumulative_score;
+       int i;
+
+       node2=OtherNode(segmentp,node1); /* need this here because we use node2 at the end of the loop */
+
+       /* must be a normal segment */
+       if(!IsNormalSegment(segmentp))
+          goto endloop;
+
+       /* must obey one-way restrictions (unless profile allows) */
+       if(profile->oneway && IsOnewayTo(segmentp,node1))
+         {
+          if(profile->allow!=Transports_Bicycle)
+             goto endloop;
+
+          wayp=LookupWay(ways,segmentp->way,1);
+
+          if(!(wayp->type&Highway_CycleBothWays))
+             goto endloop;
+         }
+
+       if(IsFakeNode(node1) || IsFakeNode(node2))
+         {
+          seg2 =IndexFakeSegment(segmentp);
+          seg2r=IndexRealSegment(seg2);
+         }
+       else
+         {
+          seg2 =IndexSegment(segments,segmentp);
+          seg2r=seg2;
+         }
+
+       /* must perform U-turn in special cases */
+       if(node1==start_node && force_uturn)
+         {
+          if(seg2r!=result1->segment)
+             goto endloop;
+         }
+       else
+          /* must not perform U-turn (unless profile allows) */
+          if(profile->turns && (seg1==seg2 || seg1==seg2r || seg1r==seg2 || (seg1r==seg2r && IsFakeUTurn(seg1,seg2))))
+             goto endloop;
+
+       /* must obey turn relations */
+       if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1r,seg2r,profile->allow))
+          goto endloop;
+
+       wayp=LookupWay(ways,segmentp->way,1);
+
+       /* mode of transport must be allowed on the highway */
+       if(!(wayp->allow&profile->allow))
+          goto endloop;
+
+       /* must obey weight restriction (if exists) */
+       if(wayp->weight && wayp->weight<profile->weight)
+          goto endloop;
+
+       /* must obey height/width/length restriction (if exists) */
+       if((wayp->height && wayp->height<profile->height) ||
+          (wayp->width  && wayp->width <profile->width ) ||
+          (wayp->length && wayp->length<profile->length))
+          goto endloop;
+
+       segment_pref=profile->highway[HIGHWAY(wayp->type)];
+
+       /* highway preferences must allow this highway */
+       if(segment_pref==0)
+          goto endloop;
+
+       for(i=1;i<Property_Count;i++)
+          if(ways->file.props & PROPERTIES(i))
+            {
+             if(wayp->props & PROPERTIES(i))
+                segment_pref*=profile->props_yes[i];
+             else
+                segment_pref*=profile->props_no[i];
+            }
+
+       /* profile preferences must allow this highway */
+       if(segment_pref==0)
+          goto endloop;
+
+       if(!IsFakeNode(node2))
+          node2p=LookupNode(nodes,node2,2);
+
+       /* mode of transport must be allowed through node2 unless it is the final node */
+       if(node2p && node2!=finish_node && !(node2p->allow&profile->allow))
+          goto endloop;
+
+       /* calculate the score for the segment and cumulative */
+       if(option_quickest==0)
+          segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref;
+       else
+          segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref;
+
+       /* prefer not to follow two fake segments when one would do (special case) */
+       if(IsFakeSegment(seg2))
+          segment_score*=1.01f;
+
+       cumulative_score=result1->score+segment_score;
+
+       /* score must be better than current best score */
+       if(cumulative_score>=finish_score)
+          goto endloop;
+
+       /* find whether the node/segment combination already exists */
+       result2=FindResult(results,node2,seg2);
+
+       if(!result2) /* New end node/segment combination */
+         {
+          result2=InsertResult(results,node2,seg2);
+          result2->prev=result1;
+          result2->score=cumulative_score;
+
+          if(node2p && IsSuperNode(node2p))
+             nsuper++;
+         }
+       else if(cumulative_score<result2->score) /* New score for end node/segment combination is better */
+         {
+          result2->prev=result1;
+          result2->score=cumulative_score;
+         }
+       else
+          goto endloop;
+
+       if(node2==finish_node)
+         {
+          if(!finish_result)
+            {
+             Result *result3;
+
+             while((result3=PopFromQueue(superqueue)))
+                InsertInQueue(queue,result3,result3->score);
+            }
+
+          if(cumulative_score<finish_score)
+            {
+             finish_score=cumulative_score;
+             finish_result=result2;
+
+             results->finish_node=node2;
+             results->last_segment=seg2;
+            }
+         }
+
+       if(finish_result || (node2p && !IsSuperNode(node2p)))
+          InsertInQueue(queue,result2,result2->score);
+       else if(node2p && IsSuperNode(node2p))
+          InsertInQueue(superqueue,result2,result2->score);
+
+      endloop:
+
+       if(IsFakeNode(node1))
+          segmentp=NextFakeSegment(segmentp,node1);
+       else if(IsFakeNode(node2))
+          segmentp=NULL; /* cannot call NextSegment() with a fake segment */
+       else
+         {
+          segmentp=NextSegment(segments,segmentp,node1);
+
+          if(!segmentp && IsFakeNode(finish_node))
+             segmentp=ExtraFakeSegment(node1,finish_node);
+         }
+      }
+   }
+
+ FreeQueueList(queue);
+ FreeQueueList(superqueue);
+
+ /* Check it worked */
+
+ if(results->number==1 || (nsuper==0 && !finish_result))
+   {
+#if DEBUG
+    printf("    Failed (%d results, %d super)\n",results->number,nsuper);
+#endif
+
+#if !DEBUG && !defined(LIBROUTINO)
+    if(!option_quiet)
+       printf_last("Found Start Route: Nodes checked = %d - Fail",results->number);
+#endif
+
+    FreeResultsList(results);
+    return(NULL);
+   }
+
+ /* If we found the finish node then make a proper route */
+
+ if(finish_result)
+    FixForwardRoute(results,finish_result);
+
+#if DEBUG
+ Result *s=FirstResult(results);
+
+ while(s)
+   {
+    if(s->node==finish_node || (!IsFakeNode(s->node) && IsSuperNode(LookupNode(nodes,s->node,1))))
+      {
+       Result *r=FindResult(results,s->node,s->segment);
+
+       printf("    -------- possible start route\n");
+
+       while(r)
+         {
+          printf("    node=%"Pindex_t" segment=%"Pindex_t" score=%f%s%s%s\n",r->node,r->segment,r->score,
+                                                                            (IsSuperNode(LookupNode(nodes,r->node,1))?" (super)":""),
+                                                                            (r->node==start_node&&r->segment==prev_segment?" (start)":""),
+                                                                            (r->node==finish_node?" (finish)":""));
+
+          r=r->prev;
+         }
+      }
+
+    s=NextResult(results,s);
+   }
+#endif
+
+#if !DEBUG && !defined(LIBROUTINO)
+ if(!option_quiet)
+    printf_last("Found Start Route: Nodes checked = %d",results->number);
+#endif
+
+ return(results);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find all routes from any super-node to a specific node (by working backwards from the specific node to all super-nodes).
+
+  Results *FindFinishRoutes Returns a set of results.
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  Profile *profile The profile containing the transport type, speeds and allowed highways.
+
+  index_t finish_node The finishing node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t finish_node)
+{
+ Results *results,*results2;
+ Queue   *queue;
+ Result  *result1,*result2,*result3;
+
+#if DEBUG
+ printf("  FindFinishRoutes(...,finish_node=%"Pindex_t")\n",finish_node);
+#endif
+
+#if !DEBUG && !defined(LIBROUTINO)
+ if(!option_quiet)
+    printf_first("Finding Finish Route: Nodes checked = 0");
+#endif
+
+ /* Create the results and insert the finish node into the queue */
+
+ results=NewResultsList(8);
+ queue=NewQueueList(8);
+
+ results->finish_node=finish_node;
+
+ result1=InsertResult(results,finish_node,NO_SEGMENT);
+
+ InsertInQueue(queue,result1,0);
+
+ /* Loop across all nodes in the queue */
+
+ while((result1=PopFromQueue(queue)))
+   {
+    Node *node1p=NULL;
+    Segment *segmentp;
+    index_t node1,seg1,seg1r;
+    index_t turnrelation=NO_RELATION;
+
+    node1=result1->node;
+    seg1=result1->segment;
+
+    if(seg1!=NO_SEGMENT && IsFakeSegment(seg1))
+       seg1r=IndexRealSegment(seg1);
+    else
+       seg1r=seg1;
+
+    if(!IsFakeNode(node1))
+       node1p=LookupNode(nodes,node1,1);
+
+    /* lookup if a turn restriction applies */
+    if(profile->turns && node1p && IsTurnRestrictedNode(node1p))
+       turnrelation=FindFirstTurnRelation1(relations,node1); /* working backwards => turn relation sort order doesn't help */
+
+    /* Loop across all segments */
+
+    if(IsFakeNode(node1))
+       segmentp=FirstFakeSegment(node1);
+    else
+       segmentp=FirstSegment(segments,node1p,1);
+
+    while(segmentp)
+      {
+       Node *node2p=NULL;
+       Way *wayp;
+       index_t node2,seg2,seg2r;
+       score_t segment_pref,segment_score,cumulative_score;
+       int i;
+
+       /* must be a normal segment unless node1 is a super-node (see below). */
+       if((IsFakeNode(node1) || !IsSuperNode(node1p)) && !IsNormalSegment(segmentp))
+          goto endloop;
+
+       /* must be a super segment if node1 is a super-node to give starting super-segment for finding middle route. */
+       if((!IsFakeNode(node1) && IsSuperNode(node1p)) && !IsSuperSegment(segmentp))
+          goto endloop;
+
+       /* must obey one-way restrictions (unless profile allows) */
+       if(profile->oneway && IsOnewayFrom(segmentp,node1)) /* working backwards => disallow oneway *from* node1 */
+         {
+          if(profile->allow!=Transports_Bicycle)
+             goto endloop;
+
+          wayp=LookupWay(ways,segmentp->way,1);
+
+          if(!(wayp->type&Highway_CycleBothWays))
+             goto endloop;
+         }
+
+       node2=OtherNode(segmentp,node1);
+
+       if(IsFakeNode(node1) || IsFakeNode(node2))
+         {
+          seg2 =IndexFakeSegment(segmentp);
+          seg2r=IndexRealSegment(seg2);
+         }
+       else
+         {
+          seg2 =IndexSegment(segments,segmentp);
+          seg2r=seg2;
+         }
+
+       /* must not perform U-turn (unless profile allows) */
+       if(profile->turns && seg1!=NO_SEGMENT)
+         {
+          if(IsFakeNode(node1) || !IsSuperNode(node1p))
+            {
+             if(seg1==seg2 || seg1==seg2r || seg1r==seg2 || (seg1r==seg2r && IsFakeUTurn(seg1,seg2)))
+                goto endloop;
+            }
+          else
+            {
+             index_t superseg=FindSuperSegment(nodes,segments,ways,relations,profile,node1,seg1);
+
+             if(seg2==superseg)
+                goto endloop;
+            }
+         }
+
+       /* must obey turn relations */
+       if(turnrelation!=NO_RELATION && seg1!=NO_SEGMENT)
+         {
+          index_t turnrelation2=FindFirstTurnRelation2(relations,node1,seg2r); /* node2 -> node1 -> result1->next->node */
+
+          if(turnrelation2!=NO_RELATION && !IsTurnAllowed(relations,turnrelation2,node1,seg2r,seg1r,profile->allow))
+             goto endloop;
+         }
+
+       wayp=LookupWay(ways,segmentp->way,1);
+
+       /* mode of transport must be allowed on the highway */
+       if(!(wayp->allow&profile->allow))
+          goto endloop;
+
+       /* must obey weight restriction (if exists) */
+       if(wayp->weight && wayp->weight<profile->weight)
+          goto endloop;
+
+       /* must obey height/width/length restriction (if exist) */
+       if((wayp->height && wayp->height<profile->height) ||
+          (wayp->width  && wayp->width <profile->width ) ||
+          (wayp->length && wayp->length<profile->length))
+          goto endloop;
+
+       segment_pref=profile->highway[HIGHWAY(wayp->type)];
+
+       /* highway preferences must allow this highway */
+       if(segment_pref==0)
+          goto endloop;
+
+       for(i=1;i<Property_Count;i++)
+          if(ways->file.props & PROPERTIES(i))
+            {
+             if(wayp->props & PROPERTIES(i))
+                segment_pref*=profile->props_yes[i];
+             else
+                segment_pref*=profile->props_no[i];
+            }
+
+       /* profile preferences must allow this highway */
+       if(segment_pref==0)
+          goto endloop;
+
+       if(!IsFakeNode(node2))
+          node2p=LookupNode(nodes,node2,2);
+
+       /* mode of transport must be allowed through node2 */
+       if(node2p && !(node2p->allow&profile->allow))
+          goto endloop;
+
+       /* calculate the score for the segment and cumulative */
+       if(option_quickest==0)
+          segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref;
+       else
+          segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref;
+
+       /* prefer not to follow two fake segments when one would do (special case) */
+       if(IsFakeSegment(seg1))
+          segment_score*=1.01f;
+
+       cumulative_score=result1->score+segment_score;
+
+       /* find whether the node/segment combination already exists */
+       result2=FindResult(results,node2,seg2);
+
+       if(!result2) /* New end node */
+         {
+          result2=InsertResult(results,node2,seg2);
+          result2->next=result1;   /* working backwards */
+          result2->score=cumulative_score;
+         }
+       else if(cumulative_score<result2->score) /* New end node is better */
+         {
+          result2->next=result1; /* working backwards */
+          result2->score=cumulative_score;
+         }
+       else
+          goto endloop;
+
+       if(IsFakeNode(node1) || !IsSuperNode(node1p))
+          InsertInQueue(queue,result2,result2->score);
+
+      endloop:
+
+       if(IsFakeNode(node1))
+          segmentp=NextFakeSegment(segmentp,node1);
+       else
+          segmentp=NextSegment(segments,segmentp,node1);
+      }
+   }
+
+ FreeQueueList(queue);
+
+ /* Check it worked */
+
+ if(results->number==1)
+   {
+#if DEBUG
+    printf("    Failed\n");
+#endif
+
+#if !DEBUG && !defined(LIBROUTINO)
+ if(!option_quiet)
+    printf_last("Found Finish Route: Nodes checked = %d - Fail",results->number);
+#endif
+
+    FreeResultsList(results);
+    return(NULL);
+   }
+
+ /* Create a results structure with the node at the end of the segment opposite the start */
+
+ results2=NewResultsList(8);
+
+ results2->finish_node=results->finish_node;
+
+ result3=FirstResult(results);
+
+ while(result3)
+   {
+    if(result3->next)
+      {
+       result2=InsertResult(results2,result3->next->node,result3->segment);
+
+       result2->score=result3->next->score;
+      }
+
+    result3=NextResult(results,result3);
+   }
+
+ /* Fix up the result->next pointers */
+
+ result3=FirstResult(results);
+
+ while(result3)
+   {
+    if(result3->next && result3->next->next)
+      {
+       result1=FindResult(results2,result3->next->node,result3->segment);
+       result2=FindResult(results2,result3->next->next->node,result3->next->segment);
+
+       result1->next=result2;
+      }
+
+    result3=NextResult(results,result3);
+   }
+
+#if DEBUG
+ Result *s=FirstResult(results2);
+
+ while(s)
+   {
+    if(!IsFakeNode(s->node) && IsSuperNode(LookupNode(nodes,s->node,1)))
+      {
+       Result *r=FindResult(results2,s->node,s->segment);
+
+       printf("    -------- possible finish route\n");
+
+       while(r)
+         {
+          printf("    node=%"Pindex_t" segment=%"Pindex_t" score=%f%s%s\n",r->node,r->segment,r->score,
+                                                                           (IsSuperNode(LookupNode(nodes,r->node,1))?" (super)":""),
+                                                                           (r->node==finish_node?" (finish)":""));
+
+          r=r->next;
+         }
+      }
+
+    s=NextResult(results2,s);
+   }
+#endif
+
+#if !DEBUG && !defined(LIBROUTINO)
+ if(!option_quiet)
+    printf_last("Found Finish Route: Nodes checked = %d",results->number);
+#endif
+
+ FreeResultsList(results);
+
+ return(results2);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create an optimum route given the set of super-nodes to follow.
+
+  Results *CombineRoutes Returns the results from joining the super-nodes.
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  Profile *profile The profile containing the transport type, speeds and allowed highways.
+
+  Results *begin The set of results for the start of the route.
+
+  Results *middle The set of results from the super-node route.
+
+  Results *end The set of results for the end of the route.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Results *CombineRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,Results *begin,Results *middle,Results *end)
+{
+ Result *midres,*comres;
+ Results *combined;
+
+#if DEBUG
+ printf("  CombineRoutes(...,[begin has %d nodes],[middle has %d nodes],[end has %d nodes])\n",begin->number,middle->number,end->number);
+#endif
+
+#if !DEBUG && !defined(LIBROUTINO)
+ if(!option_quiet)
+    printf_first("Finding Combined Route: Nodes = 0");
+#endif
+
+ combined=NewResultsList(10);
+
+ combined->start_node=begin->start_node;
+ combined->prev_segment=begin->prev_segment;
+
+ /* Insert the start point */
+
+ midres=FindResult(middle,middle->start_node,middle->prev_segment);
+
+ comres=InsertResult(combined,combined->start_node,combined->prev_segment);
+
+ /* Insert the start of the route */
+
+ if(begin->number>1 && midres->next)
+   {
+    Result *begres;
+
+    midres=FindResult(middle,midres->next->node,midres->next->segment);
+
+    begres=FindResult(begin,midres->node,midres->segment);
+
+    FixForwardRoute(begin,begres);
+
+    if(midres->next && midres->next->node==midres->node)
+       midres=midres->next;
+
+    begres=FindResult(begin,begin->start_node,begin->prev_segment);
+
+    begres=begres->next;
+
+    do
+      {
+       Result *comres2;
+
+       comres2=InsertResult(combined,begres->node,begres->segment);
+
+       comres2->score=begres->score;
+       comres2->prev=comres;
+
+       begres=begres->next;
+
+       comres=comres2;
+      }
+    while(begres);
+   }
+
+ /* Sort out the combined route */
+
+ while(midres->next)
+   {
+    Results *results=FindNormalRoute(nodes,segments,ways,relations,profile,comres->node,comres->segment,midres->next->node);
+    Result *result;
+
+    if(!results)
+      {
+#if !DEBUG && !defined(LIBROUTINO)
+       if(!option_quiet)
+          printf_last("Found Combined Route: Nodes = %d - Fail",combined->number);
+#endif
+
+       FreeResultsList(combined);
+       return(NULL);
+      }
+
+    result=FindResult(results,midres->node,comres->segment);
+
+    result=result->next;
+
+    /*
+     *      midres                          midres->next
+     *         =                                  =
+     *      ---*----------------------------------*  = middle
+     *
+     *      ---*----.----.----.----.----.----.----*  = results
+     *              =
+     *             result
+     *
+     *      ---*----.----.----.----.----.----.----*  = combined
+     *         =    =
+     *     comres  comres2
+     */
+
+    do
+      {
+       Result *comres2;
+
+       comres2=InsertResult(combined,result->node,result->segment);
+
+       comres2->score=midres->score+result->score;
+       comres2->prev=comres;
+
+       result=result->next;
+
+       comres=comres2;
+      }
+    while(result);
+
+    FreeResultsList(results);
+
+    midres=midres->next;
+   }
+
+ /* Insert the end of the route */
+
+ if(end->number>1)
+   {
+    Result *endres=FindResult(end,midres->node,midres->segment);
+
+    while(endres->next)
+      {
+       Result *comres2;
+
+       comres2=InsertResult(combined,endres->next->node,endres->next->segment);
+
+       comres2->score=comres->score+(endres->score-endres->next->score);
+       comres2->prev=comres;
+
+       endres=endres->next;
+
+       comres=comres2;
+      }
+   }
+
+ /* Turn the route round */
+
+ combined->finish_node=comres->node;
+ combined->last_segment=comres->segment;
+
+ FixForwardRoute(combined,comres);
+
+#if DEBUG
+ Result *r=FindResult(combined,combined->start_node,combined->prev_segment);
+
+ printf("      -------- combined route (end-to-end)\n");
+
+ while(r)
+   {
+    printf("    node=%"Pindex_t" segment=%"Pindex_t" score=%f%s%s%s\n",r->node,r->segment,r->score,
+                                                                       (IsSuperNode(LookupNode(nodes,r->node,1))?" (super)":""),
+                                                                       (r->node==combined->start_node&&r->segment==combined->prev_segment?" (start)":""),
+                                                                       (r->node==combined->finish_node?" (finish)":""));
+
+    r=r->next;
+   }
+#endif
+
+#if !DEBUG && !defined(LIBROUTINO)
+ if(!option_quiet)
+    printf_last("Found Combined Route: Nodes = %d",combined->number);
+#endif
+
+ return(combined);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Fix the forward route (i.e. setup next pointers for forward path from prev nodes on reverse path).
+
+  Results *results The set of results to update.
+
+  Result *finish_result The result for the finish point.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FixForwardRoute(Results *results,Result *finish_result)
+{
+ Result *result2=finish_result;
+
+ /* Erase the old route if there is one */
+
+ if(results->finish_node!=NO_NODE)
+   {
+    Result *result1=FirstResult(results);
+
+    while(result1)
+      {
+       result1->next=NULL;
+
+       result1=NextResult(results,result1);
+      }
+   }
+
+ /* Create the forward links for the optimum path */
+
+ do
+   {
+    Result *result1;
+
+    if(result2->prev)
+      {
+       index_t node1=result2->prev->node;
+       index_t seg1=result2->prev->segment;
+
+       result1=FindResult(results,node1,seg1);
+
+#ifndef LIBROUTINO
+       logassert(!result1->next,"Unable to reverse route through results (report a bug)"); /* Bugs elsewhere can lead to infinite loop here. */
+#endif
+
+       result1->next=result2;
+
+       result2=result1;
+      }
+    else
+       result2=NULL;
+   }
+ while(result2);
+
+ results->finish_node=finish_result->node;
+ results->last_segment=finish_result->segment;
+}
diff --git a/3rdparty/Routino/src/osmo5mparse.c b/3rdparty/Routino/src/osmo5mparse.c
new file mode 100644
index 0000000..3e7c5c1
--- /dev/null
+++ b/3rdparty/Routino/src/osmo5mparse.c
@@ -0,0 +1,861 @@
+/***************************************
+ A simple o5m/o5c parser.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2012-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+
+#if defined(_MSC_VER)
+#include <io.h>
+#define read(fd,address,length) _read(fd,address,(unsigned int)(length))
+#else
+#include <unistd.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#include "osmparser.h"
+#include "tagging.h"
+#include "logging.h"
+
+
+/* At the top level */
+
+#define O5M_FILE_NODE           0x10
+#define O5M_FILE_WAY            0x11
+#define O5M_FILE_RELATION       0x12
+#define O5M_FILE_BOUNDING_BOX   0xdb
+#define O5M_FILE_TIMESTAMP      0xdc
+#define O5M_FILE_HEADER         0xe0
+#define O5M_FILE_SYNC           0xee
+#define O5M_FILE_JUMP           0xef
+#define O5M_FILE_END            0xfe
+#define O5M_FILE_RESET          0xff
+
+/* Errors */
+
+#define O5M_EOF                     0
+
+#define O5M_ERROR_UNEXP_EOF        100
+#define O5M_ERROR_RESET_NOT_FIRST  101
+#define O5M_ERROR_HEADER_NOT_FIRST 102
+#define O5M_ERROR_EXPECTED_O5M     103
+#define O5M_ERROR_EXPECTED_O5C     104
+#define O5M_ERROR_FILE_LEVEL       105
+
+/* Local parsing variables (re-initialised for each file) */
+
+static uint64_t byteno=0;
+static uint64_t nnodes=0,nways=0,nrelations=0;
+
+static int64_t id=0;
+static int32_t lat=0;
+static int32_t lon=0;
+static int64_t timestamp=0;
+static int64_t node_refid=0,way_refid=0,relation_refid=0;
+
+static int mode_change=MODE_NORMAL;
+
+static uint32_t buffer_allocated;
+static unsigned char *buffer=NULL;
+static unsigned char *buffer_ptr,*buffer_end;
+
+static int string_table_start=0;
+static unsigned char **string_table=NULL;
+
+#define STRING_TABLE_ALLOCATED 15000
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Refill the data buffer and set the pointers.
+
+  int buffer_refill Return 0 if everything is OK or 1 for EOF.
+
+  int fd The file descriptor to read from.
+
+  uint32_t bytes The number of bytes to read.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline int buffer_refill(int fd,uint32_t bytes)
+{
+ ssize_t n,m;
+ uint32_t totalbytes;
+
+ m=buffer_end-buffer_ptr;
+
+ if(m)
+    memmove(buffer,buffer_ptr,m);
+
+ totalbytes=bytes+m;
+
+ if(totalbytes>buffer_allocated)
+    buffer=(unsigned char *)realloc(buffer,buffer_allocated=totalbytes);
+
+ byteno+=bytes;
+
+ buffer_ptr=buffer;
+ buffer_end=buffer+m;
+
+ do
+   {
+    n=read(fd,buffer_end,bytes);
+
+    if(n<=0)
+       return(1);
+
+    buffer_end+=n;
+    bytes-=n;
+   }
+ while(bytes>0);
+
+ return(0);
+}
+
+static void process_node(void);
+static void process_way(void);
+static void process_relation(void);
+static void process_info(void);
+static unsigned char *process_string(int pair,unsigned char **buf_ptr,unsigned char **string1,unsigned char **string2);
+
+
+/* Macros to simplify the parser (and make it look more like the XML parser) */
+
+#define BEGIN(xx)            do{ state=(xx); goto finish_parsing; } while(0)
+
+#define BUFFER_CHARS(xx)     do{ if(buffer_refill(fd,(xx))) BEGIN(O5M_ERROR_UNEXP_EOF); } while(0)
+
+
+/* O5M decoding */
+
+#define O5M_LATITUDE(xx)  (double)(1E-7*(xx))
+#define O5M_LONGITUDE(xx) (double)(1E-7*(xx))
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse an O5M int32 data value.
+
+  uint32_t o5m_int32 Returns the integer value.
+
+  unsigned char **ptr The pointer to read the data from.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline uint32_t o5m_int32(unsigned char **ptr)
+{
+ uint32_t result=(**ptr)&0x7F;
+
+ if((**ptr)&0x80) result+=((*++(*ptr))&0x7F)<<7;
+ if((**ptr)&0x80) result+=((*++(*ptr))&0x7F)<<14;
+ if((**ptr)&0x80) result+=((*++(*ptr))&0x7F)<<21;
+ if((**ptr)&0x80) result+=((*++(*ptr))&0x7F)<<28;
+
+ (*ptr)++;
+
+ return(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse an O5M int32 data value.
+
+  int32_t o5m_sint32 Returns the integer value.
+
+  unsigned char **ptr The pointer to read the data from.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline int32_t o5m_sint32(unsigned char **ptr)
+{
+ int64_t result=((**ptr)&0x7E)>>1;
+ int sign=(**ptr)&0x01;
+
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<6;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<13;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<20;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<27;
+
+ (*ptr)++;
+
+ if(sign)
+    result=-result-1;
+
+ return(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse an O5M int64 data value.
+
+  int64_t o5m_int64 Returns the integer value.
+
+  unsigned char **ptr The pointer to read the data from.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline int64_t o5m_int64(unsigned char **ptr)
+{
+ uint64_t result=(**ptr)&0x7F;
+
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<7;
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<14;
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<21;
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<28;
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<35;
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<42;
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<49;
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<56;
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<63;
+
+ (*ptr)++;
+
+ return(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse an O5M sint64 data value.
+
+  int64_t o5m_sint64 Returns the integer value.
+
+  unsigned char **ptr The pointer to read the data from.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline int64_t o5m_sint64(unsigned char **ptr)
+{
+ int64_t result=((**ptr)&0x7E)>>1;
+ int sign=(**ptr)&0x01;
+
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<6;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<13;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<20;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<27;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<34;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<41;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<48;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<55;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<62;
+
+ (*ptr)++;
+
+ if(sign)
+    result=-result-1;
+
+ return(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse the O5M and call the functions for each OSM item as seen.
+
+  int ParseO5M Returns 0 if OK or something else in case of an error.
+
+  int fd The file descriptor of the file to parse.
+
+  int changes Set to 1 if this is expected to be a changes file, otherwise zero.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int ParseO5M(int fd,int changes)
+{
+ int i;
+ int state;
+ int number_reset=0;
+ int error;
+
+ /* Print the initial message */
+
+ printf_first("Reading: Bytes=0 Nodes=0 Ways=0 Relations=0");
+
+ /* The actual parser. */
+
+ nnodes=0,nways=0,nrelations=0;
+
+ if(changes)
+    mode_change=MODE_MODIFY;
+
+ string_table_start=0;
+ string_table=(unsigned char **)malloc(STRING_TABLE_ALLOCATED*sizeof(unsigned char *));
+ for(i=0;i<STRING_TABLE_ALLOCATED;i++)
+    string_table[i]=(unsigned char*)malloc(252);
+
+ buffer_allocated=4096;
+ buffer=(unsigned char*)malloc(buffer_allocated);
+
+ buffer_ptr=buffer_end=buffer;
+
+ while(1)
+   {
+    uint32_t dataset_length=0;
+
+    /* ================ Parsing states ================ */
+
+    BUFFER_CHARS(1);
+
+    state=*buffer_ptr++;
+
+    if(state!=O5M_FILE_END && state!=O5M_FILE_RESET)
+      {
+       uint32_t length;
+       unsigned char *ptr;
+
+       if(number_reset==0)
+          BEGIN(O5M_ERROR_RESET_NOT_FIRST);
+
+       BUFFER_CHARS(4);
+
+       ptr=buffer_ptr;
+       dataset_length=o5m_int32(&buffer_ptr);
+
+       length=dataset_length-4+(buffer_ptr-ptr);
+
+       BUFFER_CHARS(length);
+      }
+    else if(state==O5M_FILE_END)
+       ;
+    else if(state==O5M_FILE_RESET)
+       number_reset++;
+
+    switch(state)
+      {
+      case O5M_FILE_NODE:
+
+       process_node();
+
+       break;
+
+      case O5M_FILE_WAY:
+
+       process_way();
+
+       break;
+
+      case O5M_FILE_RELATION:
+
+       process_relation();
+
+       break;
+
+      case O5M_FILE_BOUNDING_BOX:
+
+       buffer_ptr+=dataset_length;
+
+       break;
+
+      case O5M_FILE_TIMESTAMP:
+
+       buffer_ptr+=dataset_length;
+
+       break;
+
+      case O5M_FILE_HEADER:
+
+       if(number_reset!=1)
+          BEGIN(O5M_ERROR_HEADER_NOT_FIRST);
+
+       if(!changes && strncmp((char*)buffer_ptr,"o5m2",4))
+          BEGIN(O5M_ERROR_EXPECTED_O5M);
+
+       if( changes && strncmp((char*)buffer_ptr,"o5c2",4))
+          BEGIN(O5M_ERROR_EXPECTED_O5C);
+
+       buffer_ptr+=dataset_length;
+
+       break;
+
+      case O5M_FILE_SYNC:
+
+       buffer_ptr+=dataset_length;
+
+       break;
+
+      case O5M_FILE_JUMP:
+
+       buffer_ptr+=dataset_length;
+
+       break;
+
+      case O5M_FILE_END:
+
+       BEGIN(O5M_EOF);
+
+       break;
+
+      case O5M_FILE_RESET:
+
+       string_table_start=0;
+       id=0;
+       lat=0;
+       lon=0;
+       timestamp=0;
+       node_refid=0,way_refid=0,relation_refid=0;
+
+       break;
+
+      default:
+
+       error=state;
+       BEGIN(O5M_ERROR_FILE_LEVEL);
+      }
+   }
+
+
+ finish_parsing:
+
+ switch(state)
+   {
+    /* End of file */
+
+   case O5M_EOF:
+    break;
+
+
+    /* ================ Error states ================ */
+
+
+   case O5M_ERROR_UNEXP_EOF:
+    fprintf(stderr,"O5M Parser: Error at byte %"PRIu64": unexpected end of file seen.\n",byteno);
+    break;
+
+   case O5M_ERROR_RESET_NOT_FIRST:
+    fprintf(stderr,"O5M Parser: Error at byte %"PRIu64": Reset was not the first byte.\n",byteno);
+    break;
+
+   case O5M_ERROR_HEADER_NOT_FIRST:
+    fprintf(stderr,"O5M Parser: Error at byte %"PRIu64": Header was not the first section.\n",byteno);
+    break;
+
+   case O5M_ERROR_EXPECTED_O5M:
+    fprintf(stderr,"O5M Parser: Error at byte %"PRIu64": Expected O5M format but header disagrees.\n",byteno);
+    break;
+
+   case O5M_ERROR_EXPECTED_O5C:
+    fprintf(stderr,"O5M Parser: Error at byte %"PRIu64": Expected O5C format but header disagrees.\n",byteno);
+    break;
+
+   case O5M_ERROR_FILE_LEVEL:
+    fprintf(stderr,"O5M Parser: Error at byte %"PRIu64": Unexpected dataset type %02x.\n",byteno,error);
+    break;
+   }
+
+ /* Free the parser variables */
+
+ for(i=0;i<STRING_TABLE_ALLOCATED;i++)
+    free(string_table[i]);
+ free(string_table);
+
+ free(buffer);
+
+ /* Print the final message */
+
+ printf_last("Read: Bytes=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,byteno,nnodes,nways,nrelations);
+
+ return(state);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process an O5M Node dataset.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void process_node(void)
+{
+ int64_t delta_id;
+ int32_t delta_lat;
+ int32_t delta_lon;
+ TagList *tags=NULL,*result=NULL;
+ int mode=mode_change;
+
+ delta_id=o5m_sint64(&buffer_ptr);
+ id+=delta_id;
+
+ if(buffer_ptr<buffer_end)
+   {
+    if(*buffer_ptr!=0)
+       process_info();
+    else
+       buffer_ptr++;
+   }
+
+ if(buffer_ptr<buffer_end)
+   {
+    delta_lon=o5m_sint32(&buffer_ptr);
+    lon+=delta_lon;
+
+    delta_lat=o5m_sint32(&buffer_ptr);
+    lat+=delta_lat;
+   }
+ else
+    mode=MODE_DELETE;
+
+ /* Mangle the data and send it to the OSM parser */
+
+ nnodes++;
+
+ if(!(nnodes%10000))
+    printf_middle("Reading: Bytes=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,byteno,nnodes,nways,nrelations);
+
+ tags=NewTagList();
+
+ while(buffer_ptr<buffer_end)
+   {
+    unsigned char *key,*val;
+
+    process_string(2,&buffer_ptr,&key,&val);
+
+    AppendTag(tags,(char*)key,(char*)val);
+   }
+
+ result=ApplyNodeTaggingRules(tags,id);
+
+ ProcessNodeTags(result,id,O5M_LATITUDE(lat),O5M_LONGITUDE(lon),mode);
+
+ DeleteTagList(tags);
+ DeleteTagList(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process an O5M Way dataset.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void process_way(void)
+{
+ int64_t delta_id;
+ TagList *tags=NULL,*result=NULL;
+ int mode=mode_change;
+ unsigned char *refs=NULL,*refs_end;
+
+ delta_id=o5m_sint64(&buffer_ptr);
+ id+=delta_id;
+
+ if(buffer_ptr<buffer_end)
+   {
+    if(*buffer_ptr!=0)
+       process_info();
+    else
+       buffer_ptr++;
+   }
+
+ if(buffer_ptr<buffer_end)
+   {
+    uint32_t length;
+
+    length=o5m_int32(&buffer_ptr);
+
+    if(length)
+      {
+       refs=buffer_ptr;
+       refs_end=buffer_ptr+length;
+
+       buffer_ptr=refs_end;
+      }
+   }
+ else
+    mode=MODE_DELETE;
+
+ /* Mangle the data and send it to the OSM parser */
+
+ nways++;
+
+ if(!(nways%1000))
+    printf_middle("Reading: Bytes=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,byteno,nnodes,nways,nrelations);
+
+ AddWayRefs(0);
+
+ if(refs)
+    while(refs<refs_end)
+      {
+       int64_t delta_ref;
+
+       delta_ref=o5m_sint64(&refs);
+       node_refid+=delta_ref;
+
+       AddWayRefs(node_refid);
+      }
+
+ tags=NewTagList();
+
+ while(buffer_ptr<buffer_end)
+   {
+    unsigned char *key,*val;
+
+    process_string(2,&buffer_ptr,&key,&val);
+
+    AppendTag(tags,(char*)key,(char*)val);
+   }
+
+ result=ApplyWayTaggingRules(tags,id);
+
+ ProcessWayTags(result,id,mode);
+
+ DeleteTagList(tags);
+ DeleteTagList(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process an O5M Relation dataset.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void process_relation()
+{
+ int64_t delta_id;
+ TagList *tags=NULL,*result=NULL;
+ int mode=mode_change;
+ unsigned char *refs=NULL,*refs_end;
+
+ delta_id=o5m_sint64(&buffer_ptr);
+ id+=delta_id;
+
+ if(buffer_ptr<buffer_end)
+   {
+    if(*buffer_ptr!=0)
+       process_info();
+    else
+       buffer_ptr++;
+   }
+
+ if(buffer_ptr<buffer_end)
+   {
+    uint32_t length;
+
+    length=o5m_int32(&buffer_ptr);
+
+    if(length)
+      {
+       refs=buffer_ptr;
+       refs_end=buffer_ptr+length;
+
+       buffer_ptr=refs_end;
+      }
+   }
+ else
+    mode=MODE_DELETE;
+
+ /* Mangle the data and send it to the OSM parser */
+
+ nrelations++;
+
+ if(!(nrelations%1000))
+    printf_middle("Reading: Bytes=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,byteno,nnodes,nways,nrelations);
+
+ AddRelationRefs(0,0,0,NULL);
+
+ if(refs)
+    while(refs<refs_end)
+      {
+       int64_t delta_ref;
+       unsigned char *typerole=NULL;
+
+       delta_ref=o5m_sint64(&refs);
+
+       typerole=process_string(1,&refs,NULL,NULL);
+
+       if(*typerole=='0')
+         {
+          node_refid+=delta_ref;
+
+          AddRelationRefs(node_refid,0,0,(char*)(typerole+1));
+         }
+       else if(*typerole=='1')
+         {
+          way_refid+=delta_ref;
+
+          AddRelationRefs(0,way_refid,0,(char*)(typerole+1));
+         }
+       else if(*typerole=='2')
+         {
+          relation_refid+=delta_ref;
+
+          AddRelationRefs(0,0,relation_refid,(char*)(typerole+1));
+         }
+      }
+
+ tags=NewTagList();
+
+ while(buffer_ptr<buffer_end)
+   {
+    unsigned char *key,*val;
+
+    process_string(2,&buffer_ptr,&key,&val);
+
+    AppendTag(tags,(char*)key,(char*)val);
+   }
+
+ result=ApplyRelationTaggingRules(tags,id);
+
+ ProcessRelationTags(result,id,mode);
+
+ DeleteTagList(tags);
+ DeleteTagList(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process an O5M info message.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void process_info(void)
+{
+ int64_t timestamp_delta;
+
+ o5m_int32(&buffer_ptr);        /* version */
+
+ timestamp_delta=o5m_sint64(&buffer_ptr);
+ timestamp+=timestamp_delta;
+
+ if(timestamp!=0)
+   {
+    o5m_sint32(&buffer_ptr);     /* changeset */
+
+    process_string(2,&buffer_ptr,NULL,NULL);  /* user */
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process an O5M string and take care of maintaining the string table.
+
+  unsigned char *process_string_pair Return a pointer to the concatenation of the two strings.
+
+  int pair Set to 2 for a pair or 1 for a single string.
+
+  unsigned char **buf_ptr The pointer to the buffer that is to be updated.
+
+  unsigned char **string1 Returns a pointer to the first of the strings in the pair.
+
+  unsigned char **string2 Returns a pointer to the second of the strings in the pair.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static unsigned char *process_string(int pair,unsigned char **buf_ptr,unsigned char **string1,unsigned char **string2)
+{
+ int lookup=0;
+ unsigned char *string;
+ unsigned char *p;
+
+ if(**buf_ptr==0)
+    string=*buf_ptr+1;
+ else
+   {
+    uint32_t position=o5m_int32(buf_ptr);
+
+    string=string_table[(string_table_start-position+STRING_TABLE_ALLOCATED)%STRING_TABLE_ALLOCATED];
+
+    lookup=1;
+   }
+
+ p=string;
+
+ if(pair==2)
+   {
+    if(string1)
+       *string1=p;
+
+    while(*p) p++;
+
+    p++;
+
+    if(string2)
+       *string2=p;
+   }
+
+ while(*p) p++;
+
+ if(!lookup)
+   {
+    if((p-string)<252)
+      {
+       memcpy(string_table[string_table_start],string,p-string+1);
+
+       string_table_start=(string_table_start+1)%STRING_TABLE_ALLOCATED;
+      }
+
+    *buf_ptr=p+1;
+   }
+
+ return(string);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse an O5M format OSM file (from planet download).
+
+  int ParseO5MFile Returns 0 if OK or something else in case of an error.
+
+  int fd The file descriptor of the file to read from.
+
+  NodesX *OSMNodes The data structure of nodes to fill in.
+
+  WaysX *OSMWays The data structure of ways to fill in.
+
+  RelationsX *OSMRelations The data structure of relations to fill in.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int ParseO5MFile(int fd,NodesX *OSMNodes,WaysX *OSMWays,RelationsX *OSMRelations)
+{
+ int retval;
+
+ /* Initialise the parser */
+
+ InitialiseParser(OSMNodes,OSMWays,OSMRelations);
+
+ /* Parse the file */
+
+ retval=ParseO5M(fd,0);
+
+ /* Cleanup the parser */
+
+ CleanupParser();
+
+ return(retval);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse an O5C format OSM file (from planet download).
+
+  int ParseO5CFile Returns 0 if OK or something else in case of an error.
+
+  int fd The file descriptor of the file to read from.
+
+  NodesX *OSMNodes The data structure of nodes to fill in.
+
+  WaysX *OSMWays The data structure of ways to fill in.
+
+  RelationsX *OSMRelations The data structure of relations to fill in.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int ParseO5CFile(int fd,NodesX *OSMNodes,WaysX *OSMWays,RelationsX *OSMRelations)
+{
+ int retval;
+
+ /* Initialise the parser */
+
+ InitialiseParser(OSMNodes,OSMWays,OSMRelations);
+
+ /* Parse the file */
+
+ retval=ParseO5M(fd,1);
+
+ /* Cleanup the parser */
+
+ CleanupParser();
+
+ return(retval);
+}
diff --git a/3rdparty/Routino/src/osmparser.c b/3rdparty/Routino/src/osmparser.c
new file mode 100644
index 0000000..88f6e22
--- /dev/null
+++ b/3rdparty/Routino/src/osmparser.c
@@ -0,0 +1,1192 @@
+/***************************************
+ OSM file parser (either JOSM or planet)
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <ctype.h>
+
+#include "types.h"
+#include "typesx.h"
+
+#include "nodesx.h"
+#include "waysx.h"
+#include "relationsx.h"
+
+#include "osmparser.h"
+#include "tagging.h"
+#include "logging.h"
+
+
+/* Macros */
+
+/*+ Checks if a value in the XML is one of the allowed values for true. +*/
+#define ISTRUE(xx)  (!strcmp(xx,"true") || !strcmp(xx,"yes") || !strcmp(xx,"1"))
+
+/*+ Checks if a value in the XML is one of the allowed values for false. +*/
+#define ISFALSE(xx) (!strcmp(xx,"false") || !strcmp(xx,"no") || !strcmp(xx,"0"))
+
+/* Local parsing variables (re-initialised for each file) */
+
+static NodesX     *nodes;
+static WaysX      *ways;
+static RelationsX *relations;
+
+static node_t     *way_nodes;
+static int         way_nnodes;
+
+static node_t     *relation_nodes;
+static int         relation_nnodes;
+static way_t      *relation_ways;
+static int         relation_nways;
+static relation_t *relation_relations;
+static int         relation_nrelations;
+static way_t       relation_from;
+static way_t       relation_to;
+static node_t      relation_via;
+
+/* Local parsing functions */
+
+static double parse_speed(way_t id,const char *k,const char *v);
+static double parse_weight(way_t id,const char *k,const char *v);
+static double parse_length(way_t id,const char *k,const char *v);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Initialise the OSM parser by initialising the local variables.
+
+  NodesX *OSMNodes The data structure of nodes to fill in.
+
+  WaysX *OSMWays The data structure of ways to fill in.
+
+  RelationsX *OSMRelations The data structure of relations to fill in.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void InitialiseParser(NodesX *OSMNodes,WaysX *OSMWays,RelationsX *OSMRelations)
+{
+ /* Copy the function parameters and initialise the variables */
+
+ nodes=OSMNodes;
+ ways=OSMWays;
+ relations=OSMRelations;
+
+ way_nodes=(node_t*)malloc(256*sizeof(node_t));
+
+ relation_nodes    =(node_t    *)malloc(256*sizeof(node_t));
+ relation_ways     =(way_t     *)malloc(256*sizeof(way_t));
+ relation_relations=(relation_t*)malloc(256*sizeof(relation_t));
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Clean up the memory after parsing.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void CleanupParser(void)
+{
+ /* Free the variables */
+
+ free(way_nodes);
+
+ free(relation_nodes);
+ free(relation_ways);
+ free(relation_relations);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Add node references to a way.
+
+  int64_t node_id The node ID to add or zero to clear the list.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void AddWayRefs(int64_t node_id)
+{
+ if(node_id==0)
+    way_nnodes=0;
+ else
+   {
+    node_t id;
+
+    if(way_nnodes && (way_nnodes%256)==0)
+       way_nodes=(node_t*)realloc((void*)way_nodes,(way_nnodes+256)*sizeof(node_t));
+
+    id=(node_t)node_id;
+    logassert((int64_t)id==node_id,"Node ID too large (change node_t to 64-bits?)"); /* check node id can be stored in node_t data type. */
+
+    way_nodes[way_nnodes++]=id;
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Add node, way or relation references to a relation.
+
+  int64_t node_id The node ID to add or zero if it is not a node.
+
+  int64_t way_id The way ID to add or zero if it is not a way.
+
+  int64_t relation_id The relation ID to add or zero if it is not a relation.
+
+  const char *role The role played by this referenced item or NULL.
+
+  If all of node_id, way_id and relation_id are zero then the list is cleared.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void AddRelationRefs(int64_t node_id,int64_t way_id,int64_t relation_id,const char *role)
+{
+ if(node_id==0 && way_id==0 && relation_id==0)
+   {
+    relation_nnodes=0;
+    relation_nways=0;
+    relation_nrelations=0;
+
+    relation_from=NO_WAY_ID;
+    relation_via=NO_NODE_ID;
+    relation_to=NO_WAY_ID;
+   }
+ else if(node_id!=0)
+   {
+    node_t id;
+
+    id=(node_t)node_id;
+    logassert((int64_t)id==node_id,"Node ID too large (change node_t to 64-bits?)"); /* check node id can be stored in node_t data type. */
+
+    if(relation_nnodes && (relation_nnodes%256)==0)
+       relation_nodes=(node_t*)realloc((void*)relation_nodes,(relation_nnodes+256)*sizeof(node_t));
+
+    relation_nodes[relation_nnodes++]=id;
+
+    if(role)
+      {
+       if(!strcmp(role,"via"))
+          relation_via=id;
+      }
+   }
+ else if(way_id!=0)
+   {
+    way_t id;
+
+    id=(way_t)way_id;
+    logassert((int64_t)id==way_id,"Way ID too large (change way_t to 64-bits?)"); /* check way id can be stored in way_t data type. */
+
+    if(relation_nways && (relation_nways%256)==0)
+       relation_ways=(way_t*)realloc((void*)relation_ways,(relation_nways+256)*sizeof(way_t));
+
+    relation_ways[relation_nways++]=id;
+
+    if(role)
+      {
+       if(!strcmp(role,"from"))
+          relation_from=id;
+       else if(!strcmp(role,"to"))
+          relation_to=id;
+      }
+   }
+ else /* if(relation_id!=0) */
+   {
+    relation_t id;
+
+    id=(relation_t)relation_id;
+    logassert((int64_t)id==relation_id,"Relation ID too large (change relation_t to 64-bits?)"); /* check relation id can be stored in relation_t data type. */
+
+    if(relation_nrelations && (relation_nrelations%256)==0)
+       relation_relations=(relation_t*)realloc((void*)relation_relations,(relation_nrelations+256)*sizeof(relation_t));
+
+    relation_relations[relation_nrelations++]=relation_id;
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process the tags associated with a node.
+
+  TagList *tags The list of node tags.
+
+  int64_t node_id The id of the node.
+
+  double latitude The latitude of the node.
+
+  double longitude The longitude of the node.
+
+  int mode The mode of operation to take (create, modify, delete).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void ProcessNodeTags(TagList *tags,int64_t node_id,double latitude,double longitude,int mode)
+{
+ transports_t allow=Transports_ALL;
+ nodeflags_t flags=0;
+ node_t id;
+ int i;
+
+ /* Convert id */
+
+ id=(node_t)node_id;
+ logassert((int64_t)id==node_id,"Node ID too large (change node_t to 64-bits?)"); /* check node id can be stored in node_t data type. */
+
+ /* Delete */
+
+ if(mode==MODE_DELETE)
+   {
+    AppendNodeList(nodes,id,degrees_to_radians(latitude),degrees_to_radians(longitude),allow,NODE_DELETED);
+
+    return;
+   }
+
+ /* Parse the tags */
+
+ for(i=0;i<tags->ntags;i++)
+   {
+    int recognised=0;
+    char *k=tags->k[i];
+    char *v=tags->v[i];
+
+    switch(*k)
+      {
+      case 'b':
+       if(!strcmp(k,"bicycle"))
+         {
+          if(ISFALSE(v))
+             allow&=~Transports_Bicycle;
+          else if(!ISTRUE(v))
+             logerror("Node %"Pnode_t" has an unrecognised tag 'bicycle' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'f':
+       if(!strcmp(k,"foot"))
+         {
+          if(ISFALSE(v))
+             allow&=~Transports_Foot;
+          else if(!ISTRUE(v))
+             logerror("Node %"Pnode_t" has an unrecognised tag 'foot' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'g':
+       if(!strcmp(k,"goods"))
+         {
+          if(ISFALSE(v))
+             allow&=~Transports_Goods;
+          else if(!ISTRUE(v))
+             logerror("Node %"Pnode_t" has an unrecognised tag 'goods' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'h':
+       if(!strcmp(k,"horse"))
+         {
+          if(ISFALSE(v))
+             allow&=~Transports_Horse;
+          else if(!ISTRUE(v))
+             logerror("Node %"Pnode_t" has an unrecognised tag 'horse' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
+          recognised=1; break;
+         }
+
+       if(!strcmp(k,"hgv"))
+         {
+          if(ISFALSE(v))
+             allow&=~Transports_HGV;
+          else if(!ISTRUE(v))
+             logerror("Node %"Pnode_t" has an unrecognised tag 'hgv' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'm':
+       if(!strcmp(k,"moped"))
+         {
+          if(ISFALSE(v))
+             allow&=~Transports_Moped;
+          else if(!ISTRUE(v))
+             logerror("Node %"Pnode_t" has an unrecognised tag 'moped' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
+          recognised=1; break;
+         }
+
+       if(!strcmp(k,"motorcycle"))
+         {
+          if(ISFALSE(v))
+             allow&=~Transports_Motorcycle;
+          else if(!ISTRUE(v))
+             logerror("Node %"Pnode_t" has an unrecognised tag 'motorcycle' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
+          recognised=1; break;
+         }
+
+       if(!strcmp(k,"motorcar"))
+         {
+          if(ISFALSE(v))
+             allow&=~Transports_Motorcar;
+          else if(!ISTRUE(v))
+             logerror("Node %"Pnode_t" has an unrecognised tag 'motorcar' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'p':
+       if(!strcmp(k,"psv"))
+         {
+          if(ISFALSE(v))
+             allow&=~Transports_PSV;
+          else if(!ISTRUE(v))
+             logerror("Node %"Pnode_t" has an unrecognised tag 'psv' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'r':
+       if(!strcmp(k,"roundabout"))
+         {
+          if(ISTRUE(v))
+             flags|=NODE_MINIRNDBT;
+          else
+             logerror("Node %"Pnode_t" has an unrecognised tag 'roundabout' = '%s' (after tagging rules); using 'no'.\n",id,v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'w':
+       if(!strcmp(k,"wheelchair"))
+         {
+          if(ISFALSE(v))
+             allow&=~Transports_Wheelchair;
+          else if(!ISTRUE(v))
+             logerror("Node %"Pnode_t" has an unrecognised tag 'wheelchair' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      default:
+       break;
+      }
+
+    if(!recognised)
+       logerror("Node %"Pnode_t" has an unrecognised tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_node(id),k,v);
+   }
+
+ /* Create the node */
+
+ AppendNodeList(nodes,id,degrees_to_radians(latitude),degrees_to_radians(longitude),allow,flags);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process the tags associated with a way.
+
+  TagList *tags The list of way tags.
+
+  int64_t way_id The id of the way.
+
+  int mode The mode of operation to take (create, modify, delete).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void ProcessWayTags(TagList *tags,int64_t way_id,int mode)
+{
+ Way way={0};
+ int oneway=0,area=0;
+ int roundabout=0,lanes=0,cyclebothways=0;
+ char *name=NULL,*ref=NULL,*refname=NULL;
+ way_t id;
+ int i;
+
+ /* Convert id */
+
+ id=(way_t)way_id;
+ logassert((int64_t)id==way_id,"Way ID too large (change way_t to 64-bits?)"); /* check way id can be stored in way_t data type. */
+
+ /* Delete */
+
+ if(mode==MODE_DELETE || mode==MODE_MODIFY)
+   {
+    way.type=WAY_DELETED;
+
+    AppendWayList(ways,id,&way,way_nodes,way_nnodes,"");
+   }
+
+ if(mode==MODE_DELETE)
+    return;
+
+ /* Sanity check */
+
+ if(way_nnodes==0)
+   {
+    logerror("Way %"Pway_t" has no nodes.\n",logerror_way(id));
+    return;
+   }
+
+ if(way_nnodes==1)
+   {
+    logerror_node(way_nodes[0]); /* Extra logerror information since way isn't stored */
+    logerror("Way %"Pway_t" has only one node.\n",logerror_way(id));
+    return;
+   }
+
+ /* Parse the tags - just look for highway */
+
+ for(i=0;i<tags->ntags;i++)
+   {
+    char *k=tags->k[i];
+    char *v=tags->v[i];
+
+    if(!strcmp(k,"highway"))
+      {
+       way.type=HighwayType(v);
+
+       if(way.type==Highway_None)
+          logerror("Way %"Pway_t" has an unrecognised highway type '%s' (after tagging rules); ignoring it.\n",logerror_way(id),v);
+
+       break;
+      }
+   }
+
+ /* Don't continue if this is not a highway (bypass error logging) */
+
+ if(way.type==Highway_None)
+    return;
+
+ /* Parse the tags - look for the others */
+
+ for(i=0;i<tags->ntags;i++)
+   {
+    int recognised=0;
+    char *k=tags->k[i];
+    char *v=tags->v[i];
+
+    switch(*k)
+      {
+      case 'a':
+       if(!strcmp(k,"area"))
+         {
+          if(ISTRUE(v))
+             area=1;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'area' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'b':
+       if(!strcmp(k,"bicycle"))
+         {
+          if(ISTRUE(v))
+             way.allow|=Transports_Bicycle;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'bicycle' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       if(!strcmp(k,"bicycleroute"))
+         {
+          if(ISTRUE(v))
+             way.props|=Properties_BicycleRoute;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'bicycleroute' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       if(!strcmp(k,"bridge"))
+         {
+          if(ISTRUE(v))
+             way.props|=Properties_Bridge;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'bridge' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'c':
+       if(!strcmp(k,"cyclebothways"))
+         {
+          if(ISTRUE(v))
+             cyclebothways=1;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'cyclebothways' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+       break;
+
+      case 'f':
+       if(!strcmp(k,"foot"))
+         {
+          if(ISTRUE(v))
+             way.allow|=Transports_Foot;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'foot' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       if(!strcmp(k,"footroute"))
+         {
+          if(ISTRUE(v))
+             way.props|=Properties_FootRoute;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'footroute' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'g':
+       if(!strcmp(k,"goods"))
+         {
+          if(ISTRUE(v))
+             way.allow|=Transports_Goods;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'goods' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'h':
+       if(!strcmp(k,"highway"))
+         {recognised=1; break;}
+
+       if(!strcmp(k,"horse"))
+         {
+          if(ISTRUE(v))
+             way.allow|=Transports_Horse;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'horse' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       if(!strcmp(k,"hgv"))
+         {
+          if(ISTRUE(v))
+             way.allow|=Transports_HGV;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'hgv' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'l':
+       if(!strcmp(k,"lanes"))
+         {
+          int en=0;
+          float lanesf;
+          if(sscanf(v,"%f%n",&lanesf,&en)==1 && en && !v[en])
+             lanes=(int)lanesf;
+          else
+             logerror("Way %"Pway_t" has an unrecognised tag 'lanes' = '%s' (after tagging rules); ignoring it.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'm':
+       if(!strncmp(k,"max",3))
+         {
+          if(!strcmp(k+3,"speed"))
+            {
+             way.speed=kph_to_speed(parse_speed(id,k,v));
+             recognised=1; break;
+            }
+
+          if(!strcmp(k+3,"weight"))
+            {
+             way.weight=tonnes_to_weight(parse_weight(id,k,v));
+             recognised=1; break;
+            }
+
+          if(!strcmp(k+3,"height"))
+            {
+             way.height=metres_to_height(parse_length(id,k,v));
+             recognised=1; break;
+            }
+
+          if(!strcmp(k+3,"width"))
+            {
+             way.width=metres_to_height(parse_length(id,k,v));
+             recognised=1; break;
+            }
+
+          if(!strcmp(k+3,"length"))
+            {
+             way.length=metres_to_height(parse_length(id,k,v));
+             recognised=1; break;
+            }
+         }
+
+       if(!strcmp(k,"moped"))
+         {
+          if(ISTRUE(v))
+             way.allow|=Transports_Moped;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'moped' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       if(!strcmp(k,"motorcycle"))
+         {
+          if(ISTRUE(v))
+             way.allow|=Transports_Motorcycle;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'motorcycle' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       if(!strcmp(k,"motorcar"))
+         {
+          if(ISTRUE(v))
+             way.allow|=Transports_Motorcar;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'motorcar' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       if(!strcmp(k,"multilane"))
+         {
+          if(ISTRUE(v))
+             way.props|=Properties_Multilane;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'multilane' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'n':
+       if(!strcmp(k,"name"))
+         {
+          name=v;
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'o':
+       if(!strcmp(k,"oneway"))
+         {
+          if(ISTRUE(v))
+             oneway=1;
+          else if(!strcmp(v,"-1"))
+             oneway=-1;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'oneway' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'p':
+       if(!strcmp(k,"paved"))
+         {
+          if(ISTRUE(v))
+             way.props|=Properties_Paved;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'paved' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       if(!strcmp(k,"psv"))
+         {
+          if(ISTRUE(v))
+             way.allow|=Transports_PSV;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'psv' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'r':
+       if(!strcmp(k,"ref"))
+         {
+          ref=v;
+          recognised=1; break;
+         }
+
+       if(!strcmp(k,"roundabout"))
+         {
+          if(ISTRUE(v))
+             roundabout=1;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'roundabout' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 't':
+       if(!strcmp(k,"tunnel"))
+         {
+          if(ISTRUE(v))
+             way.props|=Properties_Tunnel;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'tunnel' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'w':
+       if(!strcmp(k,"wheelchair"))
+         {
+          if(ISTRUE(v))
+             way.allow|=Transports_Wheelchair;
+          else if(!ISFALSE(v))
+             logerror("Way %"Pway_t" has an unrecognised tag 'wheelchair' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      default:
+       break;
+      }
+
+    if(!recognised)
+       logerror("Way %"Pway_t" has an unrecognised tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_way(id),k,v);
+   }
+
+ /* Create the way */
+
+ if(area && oneway)
+   {
+    logerror("Way %"Pway_t" is an area and oneway; ignoring area tag.\n",logerror_way(id));
+    area=0;
+   }
+
+ if(cyclebothways && !oneway)
+   {
+    logerror("Way %"Pway_t" is cyclebothways but not oneway; ignoring cyclebothways tag.\n",logerror_way(id));
+    cyclebothways=0;
+   }
+
+ if(roundabout && !oneway)
+   {
+    logerror("Way %"Pway_t" is roundabout but not oneway; adding oneway tag.\n",logerror_way(id));
+    oneway=1;
+   }
+
+ if(!way.allow)
+    return;
+
+ if(cyclebothways)
+    way.type|=Highway_CycleBothWays;
+
+ if(oneway)
+   {
+    way.type|=Highway_OneWay;
+
+    if(oneway==-1)
+       for(i=0;i<way_nnodes/2;i++)
+         {
+          node_t temp;
+
+          temp=way_nodes[i];
+          way_nodes[i]=way_nodes[way_nnodes-i-1];
+          way_nodes[way_nnodes-i-1]=temp;
+         }
+   }
+
+ if(roundabout)
+    way.type|=Highway_Roundabout;
+
+ if(area)
+   {
+    way.type|=Highway_Area;
+
+    if(way_nodes[0]!=way_nodes[way_nnodes-1])
+       logerror("Way %"Pway_t" is an area but not closed.\n",logerror_way(id));
+   }
+
+ if(lanes)
+   {
+    if(oneway || (lanes/2)>1)
+       way.props|=Properties_Multilane;
+
+    if(oneway && lanes==1)
+       way.props&=~Properties_Multilane;
+   }
+
+ if(ref && name)
+   {
+    refname=(char*)malloc(strlen(ref)+strlen(name)+4);
+    sprintf(refname,"%s (%s)",name,ref);
+   }
+ else if(ref && !name)
+    refname=ref;
+ else if(!ref && name)
+    refname=name;
+ else /* if(!ref && !name) */
+    refname="";
+
+ AppendWayList(ways,id,&way,way_nodes,way_nnodes,refname);
+
+ if(ref && name)
+    free(refname);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process the tags associated with a relation.
+
+  TagList *tags The list of relation tags.
+
+  int64_t relation_id The id of the relation.
+
+  int mode The mode of operation to take (create, modify, delete).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void ProcessRelationTags(TagList *tags,int64_t relation_id,int mode)
+{
+ transports_t routes=Transports_None;
+ transports_t except=Transports_None;
+ int relation_turn_restriction=0;
+ TurnRestriction restriction=TurnRestrict_None;
+ relation_t id;
+ int i;
+
+ /* Convert id */
+
+ id=(relation_t)relation_id;
+ logassert((int64_t)id==relation_id,"Relation ID too large (change relation_t to 64-bits?)"); /* check relation id can be stored in relation_t data type. */
+
+ /* Delete */
+
+ if(mode==MODE_DELETE || mode==MODE_MODIFY)
+   {
+    AppendRouteRelationList(relations,id,RELATION_DELETED,
+                            relation_nodes,relation_nnodes,
+                            relation_ways,relation_nways,
+                            relation_relations,relation_nrelations);
+
+    AppendTurnRelationList(relations,id,
+                           relation_from,relation_to,relation_via,
+                           restriction,RELATION_DELETED);
+   }
+
+ if(mode==MODE_DELETE)
+    return;
+
+ /* Sanity check */
+
+ if(relation_nnodes==0 && relation_nways==0 && relation_nrelations==0)
+   {
+    logerror("Relation %"Prelation_t" has no nodes, ways or relations.\n",logerror_relation(id));
+    return;
+   }
+
+ /* Parse the tags */
+
+ for(i=0;i<tags->ntags;i++)
+   {
+    int recognised=0;
+    char *k=tags->k[i];
+    char *v=tags->v[i];
+
+    switch(*k)
+      {
+      case 'b':
+       if(!strcmp(k,"bicycleroute"))
+         {
+          if(ISTRUE(v))
+             routes|=Transports_Bicycle;
+          else if(!ISFALSE(v))
+             logerror("Relation %"Prelation_t" has an unrecognised tag 'bicycleroute' = '%s' (after tagging rules); using 'no'.\n",logerror_relation(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'e':
+       if(!strcmp(k,"except"))
+         {
+          for(i=1;i<Transport_Count;i++)
+             if(strstr(v,TransportName(i)))
+                except|=TRANSPORTS(i);
+
+          if(except==Transports_None)
+             logerror("Relation %"Prelation_t" has an unrecognised tag 'except' = '%s' (after tagging rules); ignoring it.\n",logerror_relation(id),v);
+
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'f':
+       if(!strcmp(k,"footroute"))
+         {
+          if(ISTRUE(v))
+             routes|=Transports_Foot;
+          else if(!ISFALSE(v))
+             logerror("Relation %"Prelation_t" has an unrecognised tag 'footroute' = '%s' (after tagging rules); using 'no'.\n",logerror_relation(id),v);
+          recognised=1; break;
+         }
+
+       break;
+
+      case 'r':
+       if(!strcmp(k,"restriction"))
+         {
+          if(!strcmp(v,"no_right_turn"   )) restriction=TurnRestrict_no_right_turn;
+          if(!strcmp(v,"no_left_turn"    )) restriction=TurnRestrict_no_left_turn;
+          if(!strcmp(v,"no_u_turn"       )) restriction=TurnRestrict_no_u_turn;
+          if(!strcmp(v,"no_straight_on"  )) restriction=TurnRestrict_no_straight_on;
+          if(!strcmp(v,"only_right_turn" )) restriction=TurnRestrict_only_right_turn;
+          if(!strcmp(v,"only_left_turn"  )) restriction=TurnRestrict_only_left_turn;
+          if(!strcmp(v,"only_straight_on")) restriction=TurnRestrict_only_straight_on;
+
+          if(restriction==TurnRestrict_None)
+             logerror("Relation %"Prelation_t" has an unrecognised tag 'restriction' = '%s' (after tagging rules); ignoring it.\n",logerror_relation(id),v);
+
+          recognised=1; break;
+         }
+
+       break;
+
+      case 't':
+       if(!strcmp(k,"type"))
+         {
+          if(!strcmp(v,"restriction"))
+             relation_turn_restriction=1;
+
+          /* Don't log an error for relations of types that we don't handle - there are so many */
+          recognised=1; break;
+         }
+
+       break;
+
+      default:
+       break;
+      }
+
+    if(!recognised)
+       logerror("Relation %"Prelation_t" has an unrecognised tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_relation(id),k,v);
+   }
+
+ /* Create the route relation (must store all relations that have ways or
+    relations even if they are not routes because they might be referenced by
+    other relations that are routes) */
+
+ if((relation_nways || relation_nrelations) && !relation_turn_restriction)
+    AppendRouteRelationList(relations,id,routes,
+                            relation_nodes,relation_nnodes,
+                            relation_ways,relation_nways,
+                            relation_relations,relation_nrelations);
+
+ /* Create the turn restriction relation. */
+
+ if(relation_turn_restriction && restriction!=TurnRestrict_None)
+   {
+    if(relation_from==NO_WAY_ID)
+      {
+       /* Extra logerror information since relation isn't stored */
+       if(relation_to!=NO_WAY_ID) logerror_way(relation_to);
+       if(relation_via!=NO_NODE_ID) logerror_node(relation_via);
+       logerror("Relation %"Prelation_t" is a turn restriction but has no 'from' way.\n",logerror_relation(id));
+      }
+    if(relation_to==NO_WAY_ID)
+      {
+       /* Extra logerror information since relation isn't stored */
+       if(relation_via!=NO_NODE_ID) logerror_node(relation_via);
+       if(relation_from!=NO_WAY_ID) logerror_way(relation_from);
+       logerror("Relation %"Prelation_t" is a turn restriction but has no 'to' way.\n",logerror_relation(id));
+      }
+    if(relation_via==NO_NODE_ID)
+      {
+       /* Extra logerror information since relation isn't stored */
+       if(relation_to!=NO_WAY_ID) logerror_way(relation_to);
+       if(relation_from!=NO_WAY_ID) logerror_way(relation_from);
+       logerror("Relation %"Prelation_t" is a turn restriction but has no 'via' node.\n",logerror_relation(id));
+      }
+
+    if(relation_from!=NO_WAY_ID && relation_to!=NO_WAY_ID && relation_via!=NO_NODE_ID)
+       AppendTurnRelationList(relations,id,
+                              relation_from,relation_to,relation_via,
+                              restriction,except);
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Convert a string containing a speed into a double precision.
+
+  double parse_speed Returns the speed in km/h if it can be parsed.
+
+  way_t id The way being processed.
+
+  const char *k The tag key.
+
+  const char *v The tag value.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static double parse_speed(way_t id,const char *k,const char *v)
+{
+ char *ev;
+ double value=strtod(v,&ev);
+
+ if(v==ev)
+    logerror("Way %"Pway_t" has an unrecognised tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_way(id),k,v);
+ else
+   {
+    while(isspace(*ev)) ev++;
+
+    if(*ev==0)
+       return(value);
+
+    if(!strcmp(ev,"km/h") || !strcmp(ev,"kph") || !strcmp(ev,"kmph"))
+       return(value);
+
+    if(!strcmp(ev,"mph"))
+       return(1.609*value);
+
+    if(!strcmp(ev,"knots"))
+       return(1.852*value);
+
+    logerror("Way %"Pway_t" has an un-parseable tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_way(id),k,v);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Convert a string containing a weight into a double precision.
+
+  double parse_weight Returns the weight in tonnes if it can be parsed.
+
+  way_t id The way being processed.
+
+  const char *k The tag key.
+
+  const char *v The tag value.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static double parse_weight(way_t id,const char *k,const char *v)
+{
+ char *ev;
+ double value=strtod(v,&ev);
+
+ if(v==ev)
+    logerror("Way %"Pway_t" has an unrecognised tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_way(id),k,v);
+ else
+   {
+    while(isspace(*ev)) ev++;
+
+    if(*ev==0)
+       return(value);
+
+    if(!strcmp(ev,"kg"))
+       return(value/1000.0);
+
+    if(!strcmp(ev,"T") || !strcmp(ev,"t") ||
+       !strcmp(ev,"ton") || !strcmp(ev,"tons") ||
+       !strcmp(ev,"tonne") || !strcmp(ev,"tonnes"))
+       return(value);
+
+    logerror("Way %"Pway_t" has an un-parseable tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_way(id),k,v);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Convert a string containing a length into a double precision.
+
+  double parse_length Returns the length in metres if it can be parsed.
+
+  way_t id The way being processed.
+
+  const char *k The tag key.
+
+  const char *v The tag value.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static double parse_length(way_t id,const char *k,const char *v)
+{
+ char *ev;
+ double value=strtod(v,&ev);
+
+ if(v==ev)
+    logerror("Way %"Pway_t" has an unrecognised tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_way(id),k,v);
+ else
+   {
+    int en=0;
+    int feet=0,inches=0;
+
+    while(isspace(*ev)) ev++;
+
+    if(*ev==0)
+       return(value);
+
+    if(!strcmp(ev,"m") || !strcmp(ev,"metre") || !strcmp(ev,"metres") || !strcmp(ev,"meter") || !strcmp(ev,"meters"))
+       return(value);
+
+    if(!strcmp(ev,"'"))
+       return(value*0.254);
+
+    if(!strcmp(ev,"′"))
+       return(value*0.254);
+
+    if(!strcmp(ev,"ft") || !strcmp(ev,"feet"))
+       return(value*0.254);
+
+    if(sscanf(v,"%d' %d\"%n",&feet,&inches,&en)==2 && en && !v[en])
+       return((feet+(double)inches/12.0)*0.254);
+
+    if(sscanf(v,"%d'%d\"%n",&feet,&inches,&en)==2 && en && !v[en])
+       return((feet+(double)inches/12.0)*0.254);
+
+    if(sscanf(v,"%d'-%d\"%n",&feet,&inches,&en)==2 && en && !v[en])
+       return((feet+(double)inches/12.0)*0.254);
+
+    if(sscanf(v,"%d′ %d″%n",&feet,&inches,&en)==2 && en && !v[en])
+       return((feet+(double)inches/12.0)*0.254);
+
+    if(sscanf(v,"%d′%d″%n",&feet,&inches,&en)==2 && en && !v[en])
+       return((feet+(double)inches/12.0)*0.254);
+
+    if(sscanf(v,"%d′-%d″%n",&feet,&inches,&en)==2 && en && !v[en])
+       return((feet+(double)inches/12.0)*0.254);
+
+    if(sscanf(v,"%d - %d%n",&feet,&inches,&en)==2 && en && !v[en])
+       return((feet+(double)inches/12.0)*0.254);
+
+    if(sscanf(v,"%d ft %d in%n",&feet,&inches,&en)==2 && en && !v[en])
+       return((feet+(double)inches/12.0)*0.254);
+
+    if(sscanf(v,"%d feet %d inches%n",&feet,&inches,&en)==2 && en && !v[en])
+       return((feet+(double)inches/12.0)*0.254);
+
+    logerror("Way %"Pway_t" has an un-parseable tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_way(id),k,v);
+   }
+
+ return(0);
+}
diff --git a/3rdparty/Routino/src/osmparser.h b/3rdparty/Routino/src/osmparser.h
new file mode 100644
index 0000000..02d89e3
--- /dev/null
+++ b/3rdparty/Routino/src/osmparser.h
@@ -0,0 +1,73 @@
+/***************************************
+ Header file for OSM parser function prototype.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2014 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef OSMPARSER_H
+#define OSMPARSER_H    /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+
+#include "typesx.h"
+#include "xmlparse.h"
+#include "tagging.h"
+
+
+/* Constants */
+
+#define MODE_NORMAL  3
+#define MODE_CREATE  2
+#define MODE_MODIFY  1
+#define MODE_DELETE -1
+
+
+/* Functions in osmxmlparse.c */
+
+int ParseOSMFile(int fd,NodesX *OSMNodes,WaysX *OSMWays,RelationsX *OSMRelations);
+
+int ParseOSCFile(int fd,NodesX *OSMNodes,WaysX *OSMWays,RelationsX *OSMRelations);
+
+
+/* Functions in osmpbfparse.c */
+
+int ParsePBFFile(int fd,NodesX *OSMNodes,WaysX *OSMWays,RelationsX *OSMRelations);
+
+
+/* Functions in osmo5mparse.c */
+
+int ParseO5MFile(int fd,NodesX *OSMNodes,WaysX *OSMWays,RelationsX *OSMRelations);
+
+int ParseO5CFile(int fd,NodesX *OSMNodes,WaysX *OSMWays,RelationsX *OSMRelations);
+
+
+/* Functions in osmparser.c */
+
+void InitialiseParser(NodesX *OSMNodes,WaysX *OSMWays,RelationsX *OSMRelations);
+void CleanupParser(void);
+
+void AddWayRefs(int64_t node_id);
+void AddRelationRefs(int64_t node_id,int64_t way_id,int64_t relation_id,const char *role);
+
+void ProcessNodeTags(TagList *tags,int64_t node_id,double latitude,double longitude,int mode);
+void ProcessWayTags(TagList *tags,int64_t way_id, int mode);
+void ProcessRelationTags(TagList *tags,int64_t relation_id,int mode);
+
+
+#endif /* OSMPARSER_H */
diff --git a/3rdparty/Routino/src/osmpbfparse.c b/3rdparty/Routino/src/osmpbfparse.c
new file mode 100644
index 0000000..116fdca
--- /dev/null
+++ b/3rdparty/Routino/src/osmpbfparse.c
@@ -0,0 +1,1243 @@
+/***************************************
+ A simple osm-specific PBF parser where the structure is hard-coded.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2012-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+
+#if defined(_MSC_VER)
+#include <io.h>
+#define read(fd,address,length) _read(fd,address,(unsigned int)(length))
+#else
+#include <unistd.h>
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#if defined(USE_GZIP) && USE_GZIP
+#include <zlib.h>
+#endif
+
+#include "osmparser.h"
+#include "tagging.h"
+#include "logging.h"
+
+
+/* Inside a BlobHeader message */
+
+#define PBF_VAL_BLOBHEADER_TYPE    1
+#define PBF_VAL_BLOBHEADER_SIZE    3
+
+/* Inside a Blob message */
+
+#define PBF_VAL_BLOB_RAW_DATA      1
+#define PBF_VAL_BLOB_RAW_SIZE      2
+#define PBF_VAL_BLOB_ZLIB_DATA     3
+
+/* Inside a HeaderBlock message */
+
+#define PBF_VAL_REQUIRED_FEATURES  4
+#define PBF_VAL_OPTIONAL_FEATURES  5
+
+/* Inside a PrimitiveBlock message */
+
+#define PBF_VAL_STRING_TABLE       1
+#define PBF_VAL_PRIMITIVE_GROUP    2
+#define PBF_VAL_GRANULARITY       17
+#define PBF_VAL_LAT_OFFSET        19
+#define PBF_VAL_LON_OFFSET        20
+
+/* Inside a PrimitiveGroup message */
+
+#define PBF_VAL_NODES              1
+#define PBF_VAL_DENSE_NODES        2
+#define PBF_VAL_WAYS               3
+#define PBF_VAL_RELATIONS          4
+
+/* Inside a StringTable message */
+
+#define PBF_VAL_STRING             1
+
+/* Inside a Node message */
+
+#define PBF_VAL_NODE_ID            1
+#define PBF_VAL_NODE_KEYS          2
+#define PBF_VAL_NODE_VALS          3
+#define PBF_VAL_NODE_LAT           8
+#define PBF_VAL_NODE_LON           9
+
+/* Inside a DenseNode message */
+
+#define PBF_VAL_DENSE_NODE_ID         1
+#define PBF_VAL_DENSE_NODE_LAT        8
+#define PBF_VAL_DENSE_NODE_LON        9
+#define PBF_VAL_DENSE_NODE_KEYS_VALS 10
+
+/* Inside a Way message */
+
+#define PBF_VAL_WAY_ID             1
+#define PBF_VAL_WAY_KEYS           2
+#define PBF_VAL_WAY_VALS           3
+#define PBF_VAL_WAY_REFS           8
+
+/* Inside a Relation message */
+
+#define PBF_VAL_RELATION_ID        1
+#define PBF_VAL_RELATION_KEYS      2
+#define PBF_VAL_RELATION_VALS      3
+#define PBF_VAL_RELATION_ROLES     8
+#define PBF_VAL_RELATION_MEMIDS    9
+#define PBF_VAL_RELATION_TYPES    10
+
+/* Errors */
+
+#define PBF_EOF                     0
+
+#define PBF_ERROR_UNEXP_EOF       100
+#define PBF_ERROR_BLOB_HEADER_LEN 101
+#define PBF_ERROR_BLOB_LEN        102
+#define PBF_ERROR_NOT_OSM         103
+#define PBF_ERROR_BLOB_BOTH       104
+#define PBF_ERROR_BLOB_NEITHER    105
+#define PBF_ERROR_NO_GZIP         106
+#define PBF_ERROR_GZIP_INIT       107
+#define PBF_ERROR_GZIP_INFLATE    108
+#define PBF_ERROR_GZIP_WRONG_LEN  109
+#define PBF_ERROR_GZIP_END        110
+#define PBF_ERROR_UNSUPPORTED     111
+#define PBF_ERROR_TOO_MANY_GROUPS 112
+
+
+/* Local parsing variables (re-initialised for each file) */
+
+static uint64_t byteno;
+static uint64_t nnodes,nways,nrelations;
+
+static uint32_t buffer_allocated,zbuffer_allocated;
+static unsigned char *buffer=NULL,*zbuffer=NULL;
+static unsigned char *buffer_ptr,*buffer_end;
+
+static int string_table_length=0,string_table_allocated=0;
+static unsigned char **string_table=NULL;
+static uint32_t *string_table_string_lengths=NULL;
+
+static int32_t granularity=100;
+static int64_t lat_offset=0,lon_offset=0;
+
+#define LENGTH_32M (32*1024*1024)
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Refill the data buffer and set the pointers.
+
+  int buffer_refill Return 0 if everything is OK or 1 for EOF.
+
+  int fd The file descriptor to read from.
+
+  uint32_t bytes The number of bytes to read.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline int buffer_refill(int fd,uint32_t bytes)
+{
+ ssize_t n;
+
+ if(bytes>buffer_allocated)
+    buffer=(unsigned char *)realloc(buffer,buffer_allocated=bytes);
+
+ byteno+=bytes;
+
+ buffer_ptr=buffer;
+ buffer_end=buffer;
+
+ do
+   {
+    n=read(fd,buffer_end,bytes);
+
+    if(n<=0)
+       return(1);
+
+    buffer_end+=n;
+    bytes-=n;
+   }
+ while(bytes>0);
+
+ return(0);
+}
+
+#if defined(USE_GZIP) && USE_GZIP
+static int uncompress_pbf(unsigned char *data,uint32_t compressed,uint32_t uncompressed);
+#endif /* USE_GZIP */
+
+static void process_string_table(unsigned char *data,uint32_t length);
+static void process_primitive_group(unsigned char *data,uint32_t length);
+static void process_nodes(unsigned char *data,uint32_t length);
+static void process_dense_nodes(unsigned char *data,uint32_t length);
+static void process_ways(unsigned char *data,uint32_t length);
+static void process_relations(unsigned char *data,uint32_t length);
+
+
+/* Macros to simplify the parser (and make it look more like the XML parser) */
+
+#define BEGIN(xx)            do{ state=(xx); goto finish_parsing; } while(0)
+
+#define BUFFER_CHARS_EOF(xx) do{ if(buffer_refill(fd,(xx))) BEGIN(PBF_EOF); } while(0)
+
+#define BUFFER_CHARS(xx)     do{ if(buffer_refill(fd,(xx))) BEGIN(PBF_ERROR_UNEXP_EOF); } while(0)
+
+
+/* PBF decoding */
+
+#define PBF_FIELD(xx)   (int)(((xx)&0xFFF8)>>3)
+#define PBF_TYPE(xx)    (int)((xx)&0x0007)
+
+#define PBF_LATITUDE(xx)  (double)(1E-9*(granularity*(xx)+lat_offset))
+#define PBF_LONGITUDE(xx) (double)(1E-9*(granularity*(xx)+lon_offset))
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse a PBF int32 data value.
+
+  uint32_t pbf_int32 Returns the integer value.
+
+  unsigned char **ptr The pointer to read the data from.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline uint32_t pbf_int32(unsigned char **ptr)
+{
+ uint32_t result=(**ptr)&0x7F;
+
+ if((**ptr)&0x80) result+=((*++(*ptr))&0x7F)<<7;
+ if((**ptr)&0x80) result+=((*++(*ptr))&0x7F)<<14;
+ if((**ptr)&0x80) result+=((*++(*ptr))&0x7F)<<21;
+ if((**ptr)&0x80) result+=((*++(*ptr))&0x7F)<<28;
+
+ (*ptr)++;
+
+ return(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse a PBF int64 data value.
+
+  int64_t pbf_int64 Returns the integer value.
+
+  unsigned char **ptr The pointer to read the data from.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline int64_t pbf_int64(unsigned char **ptr)
+{
+ uint64_t result=(**ptr)&0x7F;
+
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<7;
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<14;
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<21;
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<28;
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<35;
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<42;
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<49;
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<56;
+ if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<63;
+
+ (*ptr)++;
+
+ return(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse a PBF sint64 data value.
+
+  int64_t pbf_sint64 Returns the integer value.
+
+  unsigned char **ptr The pointer to read the data from.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline int64_t pbf_sint64(unsigned char **ptr)
+{
+ int64_t result=((**ptr)&0x7E)>>1;
+ int sign=(**ptr)&0x01;
+
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<6;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<13;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<20;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<27;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<34;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<41;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<48;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<55;
+ if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<62;
+
+ (*ptr)++;
+
+ if(sign)
+    result=-result-1;
+
+ return(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse a PBF length delimited data value.
+
+  unsigned char *pbf_length_delimited Returns a pointer to the start of the data.
+
+  unsigned char **ptr The pointer to read the data from.
+
+  uint32_t *length Returns the length of the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline unsigned char *pbf_length_delimited(unsigned char **ptr,uint32_t *length)
+{
+ uint32_t len=pbf_int32(ptr);
+
+ if(length)
+    *length=len;
+
+ *ptr+=len;
+
+ return(*ptr-len);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Skip any pbf field from a message.
+
+  unsigned char **ptr The pointer to read the data from.
+
+  int type The type of the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline void pbf_skip(unsigned char **ptr,int type)
+{
+ uint32_t length;
+
+ switch(type)
+   {
+   case 0: /* varint */
+    while((**ptr)&0x80) (*ptr)++;
+    (*ptr)++;
+    break;
+   case 1: /* 64-bit */
+    *ptr+=8;
+    break;
+   case 2: /* length delimited */
+    length=pbf_int32(ptr);
+    *ptr+=length;
+    break;
+   case 3: /* deprecated */
+    break;
+   case 4: /* deprecated */
+    break;
+   case 5: /* 32-bit */
+    *ptr+=4;
+    break;
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse the PBF and call the functions for each OSM item as seen.
+
+  int ParsePBF Returns 0 if OK or something else in case of an error.
+
+  int fd The file descriptor of the file to parse.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int ParsePBF(int fd)
+{
+ int state;
+ unsigned char *error=NULL;
+
+ /* Print the initial message */
+
+ printf_first("Reading: Bytes=0 Nodes=0 Ways=0 Relations=0");
+
+ /* The actual parser. */
+
+ byteno=0;
+
+ nnodes=0,nways=0,nrelations=0;
+
+ string_table_allocated=16384;
+ string_table_length=0;
+ string_table=(unsigned char **)malloc(string_table_allocated*sizeof(unsigned char *));
+ string_table_string_lengths=(uint32_t *)malloc(string_table_allocated*sizeof(uint32_t));
+
+ zbuffer_allocated=0;
+ zbuffer=NULL;
+
+ buffer_allocated=65536;
+ buffer=(unsigned char*)malloc(buffer_allocated);
+
+ buffer_ptr=buffer_end=buffer;
+
+ while(1)
+   {
+    int32_t blob_header_length=0;
+    int osm_data=0,osm_header=0;
+    int32_t blob_length=0;
+    uint32_t raw_size=0,compressed_size=0,uncompressed_size=0;
+    unsigned char *raw_data=NULL,*zlib_data=NULL;
+    uint32_t length;
+    unsigned char *data;
+
+    /* ================ Parsing states ================ */
+
+
+    BUFFER_CHARS_EOF(4);
+
+    blob_header_length=(256*(256*(256*(int)buffer_ptr[0])+(int)buffer_ptr[1])+(int)buffer_ptr[2])+buffer_ptr[3];
+    buffer_ptr+=4;
+
+    if(blob_header_length==0 || blob_header_length>LENGTH_32M)
+       BEGIN(PBF_ERROR_BLOB_HEADER_LEN);
+
+
+    BUFFER_CHARS(blob_header_length);
+
+    osm_header=0;
+    osm_data=0;
+
+    while(buffer_ptr<buffer_end)
+      {
+       int fieldtype=pbf_int32(&buffer_ptr);
+       int field=PBF_FIELD(fieldtype);
+
+       switch(field)
+         {
+         case PBF_VAL_BLOBHEADER_TYPE: /* string */
+          {
+           uint32_t length=0;
+           unsigned char *type=NULL;
+
+           type=pbf_length_delimited(&buffer_ptr,&length);
+
+           if(length==9 && !strncmp((char*)type,"OSMHeader",9))
+              osm_header=1;
+
+           if(length==7 && !strncmp((char*)type,"OSMData",7))
+              osm_data=1;
+          }
+          break;
+
+         case PBF_VAL_BLOBHEADER_SIZE: /* int32 */
+          blob_length=pbf_int32(&buffer_ptr);
+          break;
+
+         default:
+          pbf_skip(&buffer_ptr,PBF_TYPE(fieldtype));
+         }
+      }
+
+    if(blob_length==0 || blob_length>LENGTH_32M)
+       BEGIN(PBF_ERROR_BLOB_LEN);
+
+    if(!osm_data && !osm_header)
+       BEGIN(PBF_ERROR_NOT_OSM);
+
+
+    BUFFER_CHARS(blob_length);
+
+    while(buffer_ptr<buffer_end)
+      {
+       int fieldtype=pbf_int32(&buffer_ptr);
+       int field=PBF_FIELD(fieldtype);
+
+       switch(field)
+         {
+         case PBF_VAL_BLOB_RAW_DATA: /* bytes */
+          raw_data=pbf_length_delimited(&buffer_ptr,&raw_size);
+          break;
+
+         case PBF_VAL_BLOB_RAW_SIZE: /* int32 */
+          uncompressed_size=pbf_int32(&buffer_ptr);
+          break;
+
+         case PBF_VAL_BLOB_ZLIB_DATA: /* bytes */
+          zlib_data=pbf_length_delimited(&buffer_ptr,&compressed_size);
+          break;
+
+         default:
+          pbf_skip(&buffer_ptr,PBF_TYPE(fieldtype));
+         }
+      }
+
+    if(raw_data && zlib_data)
+       BEGIN(PBF_ERROR_BLOB_BOTH);
+
+    if(!raw_data && !zlib_data)
+       BEGIN(PBF_ERROR_BLOB_NEITHER);
+
+    if(zlib_data)
+      {
+#if defined(USE_GZIP) && USE_GZIP
+       int newstate=uncompress_pbf(zlib_data,compressed_size,uncompressed_size);
+
+       if(newstate)
+          BEGIN(newstate);
+#else
+       BEGIN(PBF_ERROR_NO_GZIP);
+#endif
+      }
+    else
+      {
+       buffer_ptr=raw_data;
+       buffer_end=raw_data+raw_size;
+      }
+
+
+    if(osm_header)
+      {
+       while(buffer_ptr<buffer_end)
+         {
+          int fieldtype=pbf_int32(&buffer_ptr);
+          int field=PBF_FIELD(fieldtype);
+
+          switch(field)
+            {
+            case PBF_VAL_REQUIRED_FEATURES: /* string */
+             {
+              uint32_t length=0;
+              unsigned char *feature=NULL;
+
+              feature=pbf_length_delimited(&buffer_ptr,&length);
+
+              if(strncmp((char*)feature,"OsmSchema-V0.6",14) &&
+                 strncmp((char*)feature,"DenseNodes",10))
+                {
+                 feature[length]=0;
+                 error=feature;
+                 BEGIN(PBF_ERROR_UNSUPPORTED);
+                }
+             }
+             break;
+
+            case PBF_VAL_OPTIONAL_FEATURES: /* string */
+             pbf_length_delimited(&buffer_ptr,NULL);
+             break;
+
+            default:
+             pbf_skip(&buffer_ptr,PBF_TYPE(fieldtype));
+            }
+         }
+      }
+
+
+    if(osm_data)
+      {
+       unsigned char *primitive_group[8]={NULL};
+       uint32_t primitive_group_length[8]={0};
+       uint32_t nprimitive_groups=0,i;
+
+       granularity=100;
+       lat_offset=lon_offset=0;
+
+       while(buffer_ptr<buffer_end)
+         {
+          int fieldtype=pbf_int32(&buffer_ptr);
+          int field=PBF_FIELD(fieldtype);
+
+          switch(field)
+            {
+            case PBF_VAL_STRING_TABLE: /* bytes */
+             data=pbf_length_delimited(&buffer_ptr,&length);
+             process_string_table(data,length);
+             break;
+
+            case PBF_VAL_PRIMITIVE_GROUP: /* bytes */
+             primitive_group[nprimitive_groups]=pbf_length_delimited(&buffer_ptr,&primitive_group_length[nprimitive_groups]);
+
+             if(++nprimitive_groups>(sizeof(primitive_group)/sizeof(primitive_group[0])))
+                BEGIN(PBF_ERROR_TOO_MANY_GROUPS);
+             break;
+
+            case PBF_VAL_GRANULARITY: /* int32 */
+             granularity=pbf_int32(&buffer_ptr);
+             break;
+
+            case PBF_VAL_LAT_OFFSET: /* int64 */
+             lat_offset=pbf_int64(&buffer_ptr);
+             break;
+
+            case PBF_VAL_LON_OFFSET: /* int64 */
+             lon_offset=pbf_int64(&buffer_ptr);
+             break;
+
+            default:
+             pbf_skip(&buffer_ptr,PBF_TYPE(fieldtype));
+            }
+         }
+
+       if(nprimitive_groups)
+          for(i=0;i<nprimitive_groups;i++)
+             process_primitive_group(primitive_group[i],primitive_group_length[i]);
+      }
+   }
+
+
+ finish_parsing:
+
+ switch(state)
+   {
+    /* End of file */
+
+   case PBF_EOF:
+    break;
+
+
+    /* ================ Error states ================ */
+
+
+   case PBF_ERROR_UNEXP_EOF:
+    fprintf(stderr,"PBF Parser: Error at byte %"PRIu64": unexpected end of file seen.\n",byteno);
+    break;
+
+   case PBF_ERROR_BLOB_HEADER_LEN:
+    fprintf(stderr,"PBF Parser: Error at byte %"PRIu64": BlobHeader length is wrong (0<x<=32M).\n",byteno);
+    break;
+
+   case PBF_ERROR_BLOB_LEN:
+    fprintf(stderr,"PBF Parser: Error at byte %"PRIu64": Blob length is wrong (0<x<=32M).\n",byteno);
+    break;
+
+   case PBF_ERROR_NOT_OSM:
+    fprintf(stderr,"PBF Parser: Error at byte %"PRIu64": BlobHeader is neither 'OSMData' or 'OSMHeader'.\n",byteno);
+    break;
+
+   case PBF_ERROR_BLOB_BOTH:
+    fprintf(stderr,"PBF Parser: Error at byte %"PRIu64": Blob has both zlib compressed and raw uncompressed data.\n",byteno);
+    break;
+
+   case PBF_ERROR_BLOB_NEITHER:
+    fprintf(stderr,"PBF Parser: Error at byte %"PRIu64": Blob has neither zlib compressed or raw uncompressed data.\n",byteno);
+    break;
+
+   case PBF_ERROR_NO_GZIP:
+    fprintf(stderr,"PBF Parser: Error at byte %"PRIu64": Blob is compressed but no gzip support is available.\n",byteno);
+    break;
+
+   case PBF_ERROR_GZIP_INIT:
+    fprintf(stderr,"PBF Parser: Error at byte %"PRIu64": Blob is compressed but failed to initialise decompression.\n",byteno);
+    break;
+
+   case PBF_ERROR_GZIP_INFLATE:
+    fprintf(stderr,"PBF Parser: Error at byte %"PRIu64": Blob is compressed but failed to uncompress it.\n",byteno);
+    break;
+
+   case PBF_ERROR_GZIP_WRONG_LEN:
+    fprintf(stderr,"PBF Parser: Error at byte %"PRIu64": Blob is compressed and wrong size when uncompressed.\n",byteno);
+    break;
+
+   case PBF_ERROR_GZIP_END:
+    fprintf(stderr,"PBF Parser: Error at byte %"PRIu64": Blob is compressed but failed to finalise decompression.\n",byteno);
+    break;
+
+   case PBF_ERROR_UNSUPPORTED:
+    fprintf(stderr,"PBF Parser: Error at byte %"PRIu64": Unsupported required feature '%s'.\n",byteno,error);
+    break;
+
+   case PBF_ERROR_TOO_MANY_GROUPS:
+    fprintf(stderr,"PBF Parser: Error at byte %"PRIu64": OsmData message contains too many PrimitiveGroup messages.\n",byteno);
+    break;
+   }
+
+ /* Free the parser variables */
+
+ free(string_table);
+ free(string_table_string_lengths);
+
+ free(buffer);
+ if(zbuffer)
+    free(zbuffer);
+
+ /* Print the final message */
+
+ printf_last("Read: Bytes=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,byteno,nnodes,nways,nrelations);
+
+ return(state);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process a PBF StringTable message.
+
+  unsigned char *data The data to process.
+
+  uint32_t length The length of the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void process_string_table(unsigned char *data,uint32_t length)
+{
+ unsigned char *end=data+length;
+ unsigned char *string;
+ uint32_t string_length;
+
+ string_table_length=0;
+
+ while(data<end)
+   {
+    int fieldtype=pbf_int32(&data);
+    int field=PBF_FIELD(fieldtype);
+
+    switch(field)
+      {
+      case PBF_VAL_STRING:      /* string */
+       string=pbf_length_delimited(&data,&string_length);
+
+       if(string_table_length==string_table_allocated)
+         {
+          string_table_allocated+=8192;
+          string_table=(unsigned char **)realloc(string_table,string_table_allocated*sizeof(unsigned char *));
+          string_table_string_lengths=(uint32_t *)realloc(string_table_string_lengths,string_table_allocated*sizeof(uint32_t));
+         }
+
+       string_table[string_table_length]=string;
+       string_table_string_lengths[string_table_length]=string_length;
+
+       string_table_length++;
+       break;
+
+      default:
+       pbf_skip(&data,PBF_TYPE(fieldtype));
+      }
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process a PBF PrimitiveGroup message.
+
+  unsigned char *data The data to process.
+
+  uint32_t length The length of the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void process_primitive_group(unsigned char *data,uint32_t length)
+{
+ unsigned char *end=data+length;
+ unsigned char *subdata;
+ uint32_t sublength;
+ int i;
+
+ /* Fixup the strings (not null terminated in buffer) */
+
+ for(i=0;i<string_table_length;i++)
+    string_table[i][string_table_string_lengths[i]]=0;
+
+
+ while(data<end)
+   {
+    int fieldtype=pbf_int32(&data);
+    int field=PBF_FIELD(fieldtype);
+
+    switch(field)
+      {
+      case PBF_VAL_NODES:       /* message */
+       subdata=pbf_length_delimited(&data,&sublength);
+       process_nodes(subdata,sublength);
+       break;
+
+      case PBF_VAL_DENSE_NODES: /* message */
+       subdata=pbf_length_delimited(&data,&sublength);
+       process_dense_nodes(subdata,sublength);
+       break;
+
+      case PBF_VAL_WAYS:        /* message */
+       subdata=pbf_length_delimited(&data,&sublength);
+       process_ways(subdata,sublength);
+       break;
+
+      case PBF_VAL_RELATIONS:   /* message */
+       subdata=pbf_length_delimited(&data,&sublength);
+       process_relations(subdata,sublength);
+       break;
+
+      default:
+       pbf_skip(&data,PBF_TYPE(fieldtype));
+      }
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process a PBF Node message.
+
+  unsigned char *data The data to process.
+
+  uint32_t length The length of the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void process_nodes(unsigned char *data,uint32_t length)
+{
+ unsigned char *end=data+length;
+ int64_t id=0;
+ unsigned char *keys=NULL,*vals=NULL;
+ unsigned char *keys_end=NULL,*vals_end=NULL;
+ uint32_t keylen=0,vallen=0;
+ int64_t lat=0,lon=0;
+ TagList *tags=NULL,*result=NULL;
+
+ while(data<end)
+   {
+    int fieldtype=pbf_int32(&data);
+    int field=PBF_FIELD(fieldtype);
+
+    switch(field)
+      {
+      case PBF_VAL_NODE_ID:     /* sint64 */
+       id=pbf_sint64(&data);
+       break;
+
+      case PBF_VAL_NODE_KEYS:   /* packed int32 */
+       keys=pbf_length_delimited(&data,&keylen);
+       keys_end=keys+keylen;
+       break;
+
+      case PBF_VAL_NODE_VALS:   /* packed int32 */
+       vals=pbf_length_delimited(&data,&vallen);
+       vals_end=vals+vallen;
+       break;
+
+      case PBF_VAL_NODE_LAT:    /* sint64 */
+       lat=pbf_sint64(&data);
+       break;
+
+      case PBF_VAL_NODE_LON:    /* sint64 */
+       lon=pbf_sint64(&data);
+       break;
+
+      default:
+       pbf_skip(&data,PBF_TYPE(fieldtype));
+      }
+   }
+
+ /* Mangle the data and send it to the OSM parser */
+
+ nnodes++;
+
+ if(!(nnodes%10000))
+    printf_middle("Reading: Bytes=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,byteno,nnodes,nways,nrelations);
+
+ tags=NewTagList();
+
+ if(keys && vals)
+   {
+    while(keys<keys_end && vals<vals_end)
+      {
+       uint32_t key=pbf_int32(&keys);
+       uint32_t val=pbf_int32(&vals);
+
+       AppendTag(tags,(char*)string_table[key],(char*)string_table[val]);
+      }
+   }
+
+ result=ApplyNodeTaggingRules(tags,id);
+
+ ProcessNodeTags(result,id,PBF_LATITUDE(lat),PBF_LONGITUDE(lon),MODE_NORMAL);
+
+ DeleteTagList(tags);
+ DeleteTagList(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process a PBF DenseNode message.
+
+  unsigned char *data The data to process.
+
+  uint32_t length The length of the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void process_dense_nodes(unsigned char *data,uint32_t length)
+{
+ unsigned char *end=data+length;
+ unsigned char *ids=NULL,*keys_vals=NULL,*lats=NULL,*lons=NULL;
+ unsigned char *ids_end=NULL;
+ uint32_t idlen=0;
+ int64_t id=0;
+ int64_t lat=0,lon=0;
+ TagList *tags=NULL,*result;
+
+ while(data<end)
+   {
+    int fieldtype=pbf_int32(&data);
+    int field=PBF_FIELD(fieldtype);
+
+    switch(field)
+      {
+      case PBF_VAL_DENSE_NODE_ID: /* packed sint64 */
+       ids=pbf_length_delimited(&data,&idlen);
+       ids_end=ids+idlen;
+       break;
+
+      case PBF_VAL_DENSE_NODE_LAT: /* packed sint64 */
+       lats=pbf_length_delimited(&data,NULL);
+       break;
+
+      case PBF_VAL_DENSE_NODE_LON: /* packed sint64 */
+       lons=pbf_length_delimited(&data,NULL);
+       break;
+
+      case PBF_VAL_DENSE_NODE_KEYS_VALS: /* packed int32 */
+       keys_vals=pbf_length_delimited(&data,NULL);
+       break;
+
+      default:
+       pbf_skip(&data,PBF_TYPE(fieldtype));
+      }
+   }
+
+ while(ids<ids_end)
+   {
+    int64_t delta_id;
+    int64_t delta_lat,delta_lon;
+
+    delta_id=pbf_sint64(&ids);
+    delta_lat=pbf_sint64(&lats);
+    delta_lon=pbf_sint64(&lons);
+
+    id+=delta_id;
+    lat+=delta_lat;
+    lon+=delta_lon;
+
+    /* Mangle the data and send it to the OSM parser */
+
+    nnodes++;
+
+    if(!(nnodes%10000))
+       printf_middle("Reading: Bytes=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,byteno,nnodes,nways,nrelations);
+
+    tags=NewTagList();
+
+    if(keys_vals)
+      {
+       while(1)
+         {
+          uint32_t key=pbf_int32(&keys_vals),val;
+
+          if(key==0)
+             break;
+
+          val=pbf_int32(&keys_vals);
+
+          AppendTag(tags,(char*)string_table[key],(char*)string_table[val]);
+         }
+      }
+
+    result=ApplyNodeTaggingRules(tags,id);
+
+    ProcessNodeTags(result,id,PBF_LATITUDE(lat),PBF_LONGITUDE(lon),MODE_NORMAL);
+
+    DeleteTagList(tags);
+    DeleteTagList(result);
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process a PBF Way message.
+
+  unsigned char *data The data to process.
+
+  uint32_t length The length of the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void process_ways(unsigned char *data,uint32_t length)
+{
+ unsigned char *end=data+length;
+ int64_t id=0;
+ unsigned char *keys=NULL,*vals=NULL,*refs=NULL;
+ unsigned char *keys_end=NULL,*vals_end=NULL,*refs_end=NULL;
+ uint32_t keylen=0,vallen=0,reflen=0;
+ int64_t ref=0;
+ TagList *tags=NULL,*result;
+
+ while(data<end)
+   {
+    int fieldtype=pbf_int32(&data);
+    int field=PBF_FIELD(fieldtype);
+
+    switch(field)
+      {
+      case PBF_VAL_WAY_ID:      /* int64 */
+       id=pbf_int64(&data);
+       break;
+
+      case PBF_VAL_WAY_KEYS:    /* packed int32 */
+       keys=pbf_length_delimited(&data,&keylen);
+       keys_end=keys+keylen;
+       break;
+
+      case PBF_VAL_WAY_VALS:    /* packed int32 */
+       vals=pbf_length_delimited(&data,&vallen);
+       vals_end=vals+vallen;
+       break;
+
+      case PBF_VAL_WAY_REFS:    /* packed sint64 */
+       refs=pbf_length_delimited(&data,&reflen);
+       refs_end=refs+reflen;
+       break;
+
+      default:
+       pbf_skip(&data,PBF_TYPE(fieldtype));
+      }
+   }
+
+ /* Mangle the data and send it to the OSM parser */
+
+ nways++;
+
+ if(!(nways%1000))
+    printf_middle("Reading: Bytes=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,byteno,nnodes,nways,nrelations);
+
+ tags=NewTagList();
+
+ if(keys && vals)
+   {
+    while(keys<keys_end && vals<vals_end)
+      {
+       uint32_t key=pbf_int32(&keys);
+       uint32_t val=pbf_int32(&vals);
+
+       AppendTag(tags,(char*)string_table[key],(char*)string_table[val]);
+      }
+   }
+
+ AddWayRefs(0);
+
+ if(refs)
+    while(refs<refs_end)
+      {
+       int64_t delta_ref;
+
+       delta_ref=pbf_sint64(&refs);
+
+       ref+=delta_ref;
+
+       if(ref==0)
+          break;
+
+       AddWayRefs(ref);
+      }
+
+ result=ApplyWayTaggingRules(tags,id);
+
+ ProcessWayTags(result,id,MODE_NORMAL);
+
+ DeleteTagList(tags);
+ DeleteTagList(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process a PBF Relation message.
+
+  unsigned char *data The data to process.
+
+  uint32_t length The length of the data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void process_relations(unsigned char *data,uint32_t length)
+{
+ unsigned char *end=data+length;
+ int64_t id=0;
+ unsigned char *keys=NULL,*vals=NULL,*roles=NULL,*memids=NULL,*types=NULL;
+ unsigned char *keys_end=NULL,*vals_end=NULL,*memids_end=NULL,*types_end=NULL;
+ uint32_t keylen=0,vallen=0,rolelen=0,memidlen=0,typelen=0;
+ int64_t memid=0;
+ TagList *tags=NULL,*result;
+
+ while(data<end)
+   {
+    int fieldtype=pbf_int32(&data);
+    int field=PBF_FIELD(fieldtype);
+
+    switch(field)
+      {
+      case PBF_VAL_RELATION_ID: /* int64 */
+       id=pbf_int64(&data);
+       break;
+
+      case PBF_VAL_RELATION_KEYS: /* packed string */
+       keys=pbf_length_delimited(&data,&keylen);
+       keys_end=keys+keylen;
+       break;
+
+      case PBF_VAL_RELATION_VALS: /* packed string */
+       vals=pbf_length_delimited(&data,&vallen);
+       vals_end=vals+vallen;
+       break;
+
+      case PBF_VAL_RELATION_ROLES: /* packed int32 */
+       roles=pbf_length_delimited(&data,&rolelen);
+       break;
+
+      case PBF_VAL_RELATION_MEMIDS: /* packed sint64 */
+       memids=pbf_length_delimited(&data,&memidlen);
+       memids_end=memids+memidlen;
+       break;
+
+      case PBF_VAL_RELATION_TYPES: /* packed enum */
+       types=pbf_length_delimited(&data,&typelen);
+       types_end=types+typelen;
+       break;
+
+      default:
+       pbf_skip(&data,PBF_TYPE(fieldtype));
+      }
+   }
+
+ /* Mangle the data and send it to the OSM parser */
+
+ nrelations++;
+
+ if(!(nrelations%1000))
+    printf_middle("Reading: Bytes=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,byteno,nnodes,nways,nrelations);
+
+ AddRelationRefs(0,0,0,NULL);
+
+ tags=NewTagList();
+
+ if(keys && vals)
+   {
+    while(keys<keys_end && vals<vals_end)
+      {
+       uint32_t key=pbf_int32(&keys);
+       uint32_t val=pbf_int32(&vals);
+
+       AppendTag(tags,(char*)string_table[key],(char*)string_table[val]);
+      }
+   }
+
+ if(memids && types)
+    while(memids<memids_end && types<types_end)
+      {
+       int64_t delta_memid;
+       unsigned char *role=NULL;
+       int type;
+
+       delta_memid=pbf_sint64(&memids);
+       type=pbf_int32(&types);
+
+       if(roles)
+          role=string_table[pbf_int32(&roles)];
+
+       memid+=delta_memid;
+
+       if(type==0)
+          AddRelationRefs(memid,0,0,(char*)role);
+       else if(type==1)
+          AddRelationRefs(0,memid,0,(char*)role);
+       else if(type==2)
+          AddRelationRefs(0,0,memid,(char*)role);
+      }
+
+ result=ApplyRelationTaggingRules(tags,id);
+
+ ProcessRelationTags(result,id,MODE_NORMAL);
+
+ DeleteTagList(tags);
+ DeleteTagList(result);
+}
+
+
+#if defined(USE_GZIP) && USE_GZIP
+
+/*++++++++++++++++++++++++++++++++++++++
+  Uncompress the part of the PBF data that is compressed.
+
+  int uncompress_pbf Returns the error state or 0 if OK.
+
+  unsigned char *data The data to uncompress.
+
+  uint32_t compressed The number of bytes to uncompress.
+
+  uint32_t uncompressed The number of bytes expected when uncompressed.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int uncompress_pbf(unsigned char *data,uint32_t compressed,uint32_t uncompressed)
+{
+ z_stream z={0};
+
+ if(uncompressed>zbuffer_allocated)
+    zbuffer=(unsigned char *)realloc(zbuffer,zbuffer_allocated=uncompressed);
+
+ if(inflateInit2(&z,15+32)!=Z_OK)
+    return(PBF_ERROR_GZIP_INIT);
+
+ z.next_in=data;
+ z.avail_in=compressed;
+
+ z.next_out=zbuffer;
+ z.avail_out=uncompressed;
+
+ if(inflate(&z,Z_FINISH)!=Z_STREAM_END)
+    return(PBF_ERROR_GZIP_INFLATE);
+
+ if(z.avail_out!=0)
+    return(PBF_ERROR_GZIP_WRONG_LEN);
+
+ if(inflateEnd(&z)!=Z_OK)
+    return(PBF_ERROR_GZIP_END);
+
+ buffer_ptr=zbuffer;
+ buffer_end=zbuffer+uncompressed;
+
+ return(0);
+}
+
+#endif /* USE_GZIP */
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse a PBF format OSM file (from planet download).
+
+  int ParsePBFFile Returns 0 if OK or something else in case of an error.
+
+  int fd The file descriptor of the file to read from.
+
+  NodesX *OSMNodes The data structure of nodes to fill in.
+
+  WaysX *OSMWays The data structure of ways to fill in.
+
+  RelationsX *OSMRelations The data structure of relations to fill in.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int ParsePBFFile(int fd,NodesX *OSMNodes,WaysX *OSMWays,RelationsX *OSMRelations)
+{
+ int retval;
+
+ /* Initialise the parser */
+
+ InitialiseParser(OSMNodes,OSMWays,OSMRelations);
+
+ /* Parse the file */
+
+ retval=ParsePBF(fd);
+
+ /* Cleanup the parser */
+
+ CleanupParser();
+
+ return(retval);
+}
diff --git a/3rdparty/Routino/src/osmxmlparse.c b/3rdparty/Routino/src/osmxmlparse.c
new file mode 100644
index 0000000..b38155f
--- /dev/null
+++ b/3rdparty/Routino/src/osmxmlparse.c
@@ -0,0 +1,711 @@
+/***************************************
+ OSM XML file parser (either JOSM or planet)
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#include "osmparser.h"
+#include "xmlparse.h"
+#include "tagging.h"
+#include "logging.h"
+
+
+/* Local parsing variables (re-initialised for each file) */
+
+static int current_mode=MODE_NORMAL;
+
+static uint64_t nnodes,nways,nrelations;
+
+static TagList *current_tags;
+
+
+/* The XML tag processing function prototypes */
+
+//static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding);
+static int osmType_function(const char *_tag_,int _type_,const char *version);
+static int osmChangeType_function(const char *_tag_,int _type_,const char *version);
+//static int boundsType_function(const char *_tag_,int _type_);
+//static int boundType_function(const char *_tag_,int _type_);
+static int changesetType_function(const char *_tag_,int _type_);
+static int modifyType_function(const char *_tag_,int _type_);
+static int createType_function(const char *_tag_,int _type_);
+static int deleteType_function(const char *_tag_,int _type_);
+static int nodeType_function(const char *_tag_,int _type_,const char *id,const char *lat,const char *lon);
+static int wayType_function(const char *_tag_,int _type_,const char *id);
+static int relationType_function(const char *_tag_,int _type_,const char *id);
+static int tagType_function(const char *_tag_,int _type_,const char *k,const char *v);
+static int ndType_function(const char *_tag_,int _type_,const char *ref);
+static int memberType_function(const char *_tag_,int _type_,const char *type,const char *ref,const char *role);
+
+
+/* The XML tag definitions (forward declarations) */
+
+static const xmltag xmlDeclaration_tag;
+static const xmltag osmType_tag;
+static const xmltag osmChangeType_tag;
+static const xmltag boundsType_tag;
+static const xmltag boundType_tag;
+static const xmltag changesetType_tag;
+static const xmltag modifyType_tag;
+static const xmltag createType_tag;
+static const xmltag deleteType_tag;
+static const xmltag nodeType_tag;
+static const xmltag wayType_tag;
+static const xmltag relationType_tag;
+static const xmltag tagType_tag;
+static const xmltag ndType_tag;
+static const xmltag memberType_tag;
+
+
+/* The XML tag definition values */
+
+/*+ The complete set of tags at the top level for OSM. +*/
+static const xmltag * const xml_osm_toplevel_tags[]={&xmlDeclaration_tag,&osmType_tag,NULL};
+
+/*+ The complete set of tags at the top level for OSC. +*/
+static const xmltag * const xml_osc_toplevel_tags[]={&xmlDeclaration_tag,&osmChangeType_tag,NULL};
+
+/*+ The xmlDeclaration type tag. +*/
+static const xmltag xmlDeclaration_tag=
+              {"xml",
+               2, {"version","encoding"},
+               NULL,
+               {NULL}};
+
+/*+ The osmType type tag. +*/
+static const xmltag osmType_tag=
+              {"osm",
+               1, {"version"},
+               osmType_function,
+               {&boundsType_tag,&boundType_tag,&changesetType_tag,&nodeType_tag,&wayType_tag,&relationType_tag,NULL}};
+
+/*+ The osmChangeType type tag. +*/
+static const xmltag osmChangeType_tag=
+              {"osmChange",
+               1, {"version"},
+               osmChangeType_function,
+               {&boundsType_tag,&modifyType_tag,&createType_tag,&deleteType_tag,NULL}};
+
+/*+ The boundsType type tag. +*/
+static const xmltag boundsType_tag=
+              {"bounds",
+               0, {NULL},
+               NULL,
+               {NULL}};
+
+/*+ The boundType type tag. +*/
+static const xmltag boundType_tag=
+              {"bound",
+               0, {NULL},
+               NULL,
+               {NULL}};
+
+/*+ The changesetType type tag. +*/
+static const xmltag changesetType_tag=
+              {"changeset",
+               0, {NULL},
+               changesetType_function,
+               {&tagType_tag,NULL}};
+
+/*+ The modifyType type tag. +*/
+static const xmltag modifyType_tag=
+              {"modify",
+               0, {NULL},
+               modifyType_function,
+               {&nodeType_tag,&wayType_tag,&relationType_tag,NULL}};
+
+/*+ The createType type tag. +*/
+static const xmltag createType_tag=
+              {"create",
+               0, {NULL},
+               createType_function,
+               {&nodeType_tag,&wayType_tag,&relationType_tag,NULL}};
+
+/*+ The deleteType type tag. +*/
+static const xmltag deleteType_tag=
+              {"delete",
+               0, {NULL},
+               deleteType_function,
+               {&nodeType_tag,&wayType_tag,&relationType_tag,NULL}};
+
+/*+ The nodeType type tag. +*/
+static const xmltag nodeType_tag=
+              {"node",
+               3, {"id","lat","lon"},
+               nodeType_function,
+               {&tagType_tag,NULL}};
+
+/*+ The wayType type tag. +*/
+static const xmltag wayType_tag=
+              {"way",
+               1, {"id"},
+               wayType_function,
+               {&ndType_tag,&tagType_tag,NULL}};
+
+/*+ The relationType type tag. +*/
+static const xmltag relationType_tag=
+              {"relation",
+               1, {"id"},
+               relationType_function,
+               {&memberType_tag,&tagType_tag,NULL}};
+
+/*+ The tagType type tag. +*/
+static const xmltag tagType_tag=
+              {"tag",
+               2, {"k","v"},
+               tagType_function,
+               {NULL}};
+
+/*+ The ndType type tag. +*/
+static const xmltag ndType_tag=
+              {"nd",
+               1, {"ref"},
+               ndType_function,
+               {NULL}};
+
+/*+ The memberType type tag. +*/
+static const xmltag memberType_tag=
+              {"member",
+               3, {"type","ref","role"},
+               memberType_function,
+               {NULL}};
+
+
+/* The XML tag processing functions */
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the XML declaration is seen
+
+  int xmlDeclaration_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *version The contents of the 'version' attribute (or NULL if not defined).
+
+  const char *encoding The contents of the 'encoding' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+//static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding)
+//{
+// return(0);
+//}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the osmType XSD type is seen
+
+  int osmType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *version The contents of the 'version' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int osmType_function(const char *_tag_,int _type_,const char *version)
+{
+ /* Print the initial message */
+
+ if(_type_&XMLPARSE_TAG_START)
+    printf_first("Read: Lines=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,ParseXML_LineNumber(),nnodes=0,nways=0,nrelations=0);
+
+ /* Check the tag values */
+
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    current_mode=MODE_NORMAL;
+
+    if(!version || strcmp(version,"0.6"))
+       XMLPARSE_MESSAGE(_tag_,"Invalid value for 'version' (only '0.6' accepted)");
+   }
+
+ /* Print the final message */
+
+ if(_type_&XMLPARSE_TAG_END)
+    printf_last("Read: Lines=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,ParseXML_LineNumber(),nnodes,nways,nrelations);
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the osmChangeType XSD type is seen
+
+  int osmChangeType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *version The contents of the 'version' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int osmChangeType_function(const char *_tag_,int _type_,const char *version)
+{
+ /* Print the initial message */
+
+ if(_type_&XMLPARSE_TAG_START)
+    printf_first("Read: Lines=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,ParseXML_LineNumber(),nnodes=0,nways=0,nrelations=0);
+
+ /* Check the tag values */
+
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    if(!version || strcmp(version,"0.6"))
+       XMLPARSE_MESSAGE(_tag_,"Invalid value for 'version' (only '0.6' accepted)");
+   }
+
+ /* Print the final message */
+
+ if(_type_&XMLPARSE_TAG_END)
+    printf_last("Read: Lines=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,ParseXML_LineNumber(),nnodes,nways,nrelations);
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the boundsType XSD type is seen
+
+  int boundsType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+//static int boundsType_function(const char *_tag_,int _type_)
+//{
+// return(0);
+//}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the boundType XSD type is seen
+
+  int boundType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+//static int boundType_function(const char *_tag_,int _type_)
+//{
+// return(0);
+//}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the changesetType XSD type is seen
+
+  int changesetType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int changesetType_function(const char *_tag_,int _type_)
+{
+ current_tags=NULL;
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the modifyType XSD type is seen
+
+  int modifyType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int modifyType_function(const char *_tag_,int _type_)
+{
+ if(_type_&XMLPARSE_TAG_START)
+    current_mode=MODE_MODIFY;
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the createType XSD type is seen
+
+  int createType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int createType_function(const char *_tag_,int _type_)
+{
+ if(_type_&XMLPARSE_TAG_START)
+    current_mode=MODE_CREATE;
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the deleteType XSD type is seen
+
+  int deleteType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int deleteType_function(const char *_tag_,int _type_)
+{
+ if(_type_&XMLPARSE_TAG_START)
+    current_mode=MODE_DELETE;
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the nodeType XSD type is seen
+
+  int nodeType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *id The contents of the 'id' attribute (or NULL if not defined).
+
+  const char *lat The contents of the 'lat' attribute (or NULL if not defined).
+
+  const char *lon The contents of the 'lon' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int nodeType_function(const char *_tag_,int _type_,const char *id,const char *lat,const char *lon)
+{
+ static int64_t llid;              /* static variable to store attributes from <node> tag until </node> tag */
+ static double latitude,longitude; /* static variable to store attributes from <node> tag until </node> tag */
+
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    nnodes++;
+
+    if(!(nnodes%10000))
+       printf_middle("Reading: Lines=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,ParseXML_LineNumber(),nnodes,nways,nrelations);
+
+    current_tags=NewTagList();
+
+    /* Handle the node information */
+
+    XMLPARSE_ASSERT_INTEGER(_tag_,id); llid=atoll(id); /* need int64_t conversion */
+
+    if(current_mode!=MODE_DELETE)
+      {
+       XMLPARSE_ASSERT_FLOATING(_tag_,lat); latitude =atof(lat);
+       XMLPARSE_ASSERT_FLOATING(_tag_,lon); longitude=atof(lon);
+      }
+   }
+
+ if(_type_&XMLPARSE_TAG_END)
+   {
+    TagList *result=ApplyNodeTaggingRules(current_tags,llid);
+
+    ProcessNodeTags(result,llid,latitude,longitude,current_mode);
+
+    DeleteTagList(current_tags); current_tags=NULL;
+    DeleteTagList(result);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the wayType XSD type is seen
+
+  int wayType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *id The contents of the 'id' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int wayType_function(const char *_tag_,int _type_,const char *id)
+{
+ static int64_t llid; /* static variable to store attributes from <way> tag until </way> tag */
+
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    nways++;
+
+    if(!(nways%1000))
+       printf_middle("Reading: Lines=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,ParseXML_LineNumber(),nnodes,nways,nrelations);
+
+    current_tags=NewTagList();
+
+    AddWayRefs(0);
+
+    /* Handle the way information */
+
+    XMLPARSE_ASSERT_INTEGER(_tag_,id); llid=atoll(id); /* need int64_t conversion */
+   }
+
+ if(_type_&XMLPARSE_TAG_END)
+   {
+    TagList *result=ApplyWayTaggingRules(current_tags,llid);
+
+    ProcessWayTags(result,llid,current_mode);
+
+    DeleteTagList(current_tags); current_tags=NULL;
+    DeleteTagList(result);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the relationType XSD type is seen
+
+  int relationType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *id The contents of the 'id' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int relationType_function(const char *_tag_,int _type_,const char *id)
+{
+ static int64_t llid; /* static variable to store attributes from <relation> tag until </relation> tag */
+
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    nrelations++;
+
+    if(!(nrelations%1000))
+       printf_middle("Reading: Lines=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,ParseXML_LineNumber(),nnodes,nways,nrelations);
+
+    current_tags=NewTagList();
+
+    AddRelationRefs(0,0,0,NULL);
+
+    /* Handle the relation information */
+
+    XMLPARSE_ASSERT_INTEGER(_tag_,id); llid=atoll(id); /* need int64_t conversion */
+   }
+
+ if(_type_&XMLPARSE_TAG_END)
+   {
+    TagList *result=ApplyRelationTaggingRules(current_tags,llid);
+
+    ProcessRelationTags(result,llid,current_mode);
+
+    DeleteTagList(current_tags); current_tags=NULL;
+    DeleteTagList(result);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the tagType XSD type is seen
+
+  int tagType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *k The contents of the 'k' attribute (or NULL if not defined).
+
+  const char *v The contents of the 'v' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int tagType_function(const char *_tag_,int _type_,const char *k,const char *v)
+{
+ if(_type_&XMLPARSE_TAG_START && current_tags)
+   {
+    XMLPARSE_ASSERT_STRING(_tag_,k);
+    XMLPARSE_ASSERT_STRING(_tag_,v);
+
+    AppendTag(current_tags,k,v);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the ndType XSD type is seen
+
+  int ndType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *ref The contents of the 'ref' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int ndType_function(const char *_tag_,int _type_,const char *ref)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    int64_t llid;
+
+    XMLPARSE_ASSERT_INTEGER(_tag_,ref); llid=atoll(ref); /* need int64_t conversion */
+
+    AddWayRefs(llid);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the memberType XSD type is seen
+
+  int memberType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *type The contents of the 'type' attribute (or NULL if not defined).
+
+  const char *ref The contents of the 'ref' attribute (or NULL if not defined).
+
+  const char *role The contents of the 'role' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int memberType_function(const char *_tag_,int _type_,const char *type,const char *ref,const char *role)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    int64_t llid;
+
+    XMLPARSE_ASSERT_STRING(_tag_,type);
+    XMLPARSE_ASSERT_INTEGER(_tag_,ref); llid=atoll(ref); /* need int64_t conversion */
+
+    if(!strcmp(type,"node"))
+       AddRelationRefs(llid,0,0,role);
+    else if(!strcmp(type,"way"))
+       AddRelationRefs(0,llid,0,role);
+    else if(!strcmp(type,"relation"))
+       AddRelationRefs(0,0,llid,role);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse an OSM XML file (from JOSM or planet download).
+
+  int ParseOSMFile Returns 0 if OK or something else in case of an error.
+
+  int fd The file descriptor of the file to read from.
+
+  NodesX *OSMNodes The data structure of nodes to fill in.
+
+  WaysX *OSMWays The data structure of ways to fill in.
+
+  RelationsX *OSMRelations The data structure of relations to fill in.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int ParseOSMFile(int fd,NodesX *OSMNodes,WaysX *OSMWays,RelationsX *OSMRelations)
+{
+ int retval;
+
+ /* Initialise the parser */
+
+ InitialiseParser(OSMNodes,OSMWays,OSMRelations);
+
+ /* Parse the file */
+
+ nnodes=0,nways=0,nrelations=0;
+
+ current_tags=NULL;
+
+ retval=ParseXML(fd,xml_osm_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_IGNORE);
+
+ /* Cleanup the parser */
+
+ CleanupParser();
+
+ return(retval);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse an OSC XML file (from planet download).
+
+  int ParseOSCFile Returns 0 if OK or something else in case of an error.
+
+  int fd The file descriptor of the file to read from.
+
+  NodesX *OSMNodes The data structure of nodes to fill in.
+
+  WaysX *OSMWays The data structure of ways to fill in.
+
+  RelationsX *OSMRelations The data structure of relations to fill in.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int ParseOSCFile(int fd,NodesX *OSMNodes,WaysX *OSMWays,RelationsX *OSMRelations)
+{
+ int retval;
+
+ /* Initialise the parser */
+
+ InitialiseParser(OSMNodes,OSMWays,OSMRelations);
+
+ /* Parse the file */
+
+ nnodes=0,nways=0,nrelations=0;
+
+ current_tags=NULL;
+
+ retval=ParseXML(fd,xml_osc_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_IGNORE);
+
+ /* Cleanup the parser */
+
+ CleanupParser();
+
+ return(retval);
+}
diff --git a/3rdparty/Routino/src/output.c b/3rdparty/Routino/src/output.c
new file mode 100644
index 0000000..9f1cf3a
--- /dev/null
+++ b/3rdparty/Routino/src/output.c
@@ -0,0 +1,954 @@
+/***************************************
+ Routing output generator.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <math.h>
+#include <errno.h>
+
+#include "types.h"
+#include "nodes.h"
+#include "segments.h"
+#include "ways.h"
+
+#include "functions.h"
+#include "fakes.h"
+#include "translations.h"
+#include "results.h"
+#include "xmlparse.h"
+
+
+#define DEBUG 0
+
+/* Constants */
+
+#define IMP_IGNORE      -1      /*+ Ignore this point. +*/
+#define IMP_UNIMPORTANT  0      /*+ An unimportant, intermediate, node. +*/
+#define IMP_RB_NOT_EXIT  1      /*+ A roundabout exit that is not taken. +*/
+#define IMP_JUNCT_CONT   2      /*+ An un-interesting junction where the route continues without comment. +*/
+#define IMP_CHANGE       3      /*+ The highway changes type but nothing else happens. +*/
+#define IMP_JUNCT_IMPORT 4      /*+ An interesting junction to be described. +*/
+#define IMP_RB_ENTRY     5      /*+ The entrance to a roundabout. +*/
+#define IMP_RB_EXIT      6      /*+ The exit from a roundabout. +*/
+#define IMP_MINI_RB      7      /*+ The location of a mini-roundabout. +*/
+#define IMP_UTURN        8      /*+ The location of a U-turn. +*/
+#define IMP_WAYPOINT     9      /*+ A waypoint. +*/
+
+
+/* Global variables */
+
+/*+ The option to calculate the quickest route insted of the shortest. +*/
+extern int option_quickest;
+
+/*+ The options to select the format of the output. +*/
+extern int option_html,option_gpx_track,option_gpx_route,option_text,option_text_all,option_stdout;
+
+
+/* Local variables */
+
+/*+ Heuristics for determining if a junction is important. +*/
+static const char junction_other_way[Highway_Count][Highway_Count]=
+ { /* M, T, P, S, T, U, R, S, T, C, P, S, F = Way type of route not taken */
+  {   1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, /* Motorway     */
+  {   1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, /* Trunk        */
+  {   1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, /* Primary      */
+  {   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, /* Secondary    */
+  {   1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 }, /* Tertiary     */
+  {   1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1 }, /* Unclassified */
+  {   1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1 }, /* Residential  */
+  {   1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1 }, /* Service      */
+  {   1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1 }, /* Track        */
+  {   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1 }, /* Cycleway     */
+  {   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* Path         */
+  {   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* Steps        */
+  {   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* Ferry        */
+ };
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print the optimum route between two nodes.
+
+  Results **results The set of results to print (consecutive in array even if not consecutive waypoints).
+
+  int nresults The number of results in the list.
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Profile *profile The profile containing the transport type, speeds and allowed highways.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void PrintRoute(Results **results,int nresults,Nodes *nodes,Segments *segments,Ways *ways,Profile *profile)
+{
+ FILE *htmlfile=NULL,*gpxtrackfile=NULL,*gpxroutefile=NULL,*textfile=NULL,*textallfile=NULL;
+
+ char *prev_bearing=NULL,*prev_wayname=NULL;
+ index_t prev_node=NO_NODE;
+ distance_t cum_distance=0;
+ duration_t cum_duration=0;
+
+ int point=0;
+ int segment_count=0,route_count=0;
+ int point_count=0;
+ int roundabout=0;
+
+ /* Open the files */
+
+ if(option_stdout)
+   {
+    if(option_html)
+       htmlfile    =stdout;
+    if(option_gpx_track)
+       gpxtrackfile=stdout;
+    if(option_gpx_route)
+       gpxroutefile=stdout;
+    if(option_text)
+       textfile    =stdout;
+    if(option_text_all)
+       textallfile =stdout;
+   }
+ else
+   {
+#if defined(_MSC_VER) || defined(__MINGW32__)
+    const char *open_mode="wb";
+#else
+    const char *open_mode="w";
+#endif
+
+    if(option_quickest==0)
+      {
+       /* Print the result for the shortest route */
+
+       if(option_html)
+          htmlfile    =fopen("shortest.html",open_mode);
+       if(option_gpx_track)
+          gpxtrackfile=fopen("shortest-track.gpx",open_mode);
+       if(option_gpx_route)
+          gpxroutefile=fopen("shortest-route.gpx",open_mode);
+       if(option_text)
+          textfile    =fopen("shortest.txt",open_mode);
+       if(option_text_all)
+          textallfile =fopen("shortest-all.txt",open_mode);
+
+#ifndef LIBROUTINO
+       if(option_html && !htmlfile)
+          fprintf(stderr,"Warning: Cannot open file 'shortest.html' for writing [%s].\n",strerror(errno));
+       if(option_gpx_track && !gpxtrackfile)
+          fprintf(stderr,"Warning: Cannot open file 'shortest-track.gpx' for writing [%s].\n",strerror(errno));
+       if(option_gpx_route && !gpxroutefile)
+          fprintf(stderr,"Warning: Cannot open file 'shortest-route.gpx' for writing [%s].\n",strerror(errno));
+       if(option_text && !textfile)
+          fprintf(stderr,"Warning: Cannot open file 'shortest.txt' for writing [%s].\n",strerror(errno));
+       if(option_text_all && !textallfile)
+          fprintf(stderr,"Warning: Cannot open file 'shortest-all.txt' for writing [%s].\n",strerror(errno));
+#endif
+      }
+    else
+      {
+       /* Print the result for the quickest route */
+
+       if(option_html)
+          htmlfile    =fopen("quickest.html",open_mode);
+       if(option_gpx_track)
+          gpxtrackfile=fopen("quickest-track.gpx",open_mode);
+       if(option_gpx_route)
+          gpxroutefile=fopen("quickest-route.gpx",open_mode);
+       if(option_text)
+          textfile    =fopen("quickest.txt",open_mode);
+       if(option_text_all)
+          textallfile =fopen("quickest-all.txt",open_mode);
+
+#ifndef LIBROUTINO
+       if(option_html && !htmlfile)
+          fprintf(stderr,"Warning: Cannot open file 'quickest.html' for writing [%s].\n",strerror(errno));
+       if(option_gpx_track && !gpxtrackfile)
+          fprintf(stderr,"Warning: Cannot open file 'quickest-track.gpx' for writing [%s].\n",strerror(errno));
+       if(option_gpx_route && !gpxroutefile)
+          fprintf(stderr,"Warning: Cannot open file 'quickest-route.gpx' for writing [%s].\n",strerror(errno));
+       if(option_text && !textfile)
+          fprintf(stderr,"Warning: Cannot open file 'quickest.txt' for writing [%s].\n",strerror(errno));
+       if(option_text_all && !textallfile)
+          fprintf(stderr,"Warning: Cannot open file 'quickest-all.txt' for writing [%s].\n",strerror(errno));
+#endif
+      }
+   }
+
+ /* Print the head of the files */
+
+ if(htmlfile)
+   {
+    fprintf(htmlfile,"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n");
+    fprintf(htmlfile,"<html>\n");
+    if(translation->xml_copyright_creator[0] && translation->xml_copyright_creator[1])
+       fprintf(htmlfile,"<!-- %s : %s -->\n",translation->xml_copyright_creator[0],translation->xml_copyright_creator[1]);
+    if(translation->xml_copyright_source[0] && translation->xml_copyright_source[1])
+       fprintf(htmlfile,"<!-- %s : %s -->\n",translation->xml_copyright_source[0],translation->xml_copyright_source[1]);
+    if(translation->xml_copyright_license[0] && translation->xml_copyright_license[1])
+       fprintf(htmlfile,"<!-- %s : %s -->\n",translation->xml_copyright_license[0],translation->xml_copyright_license[1]);
+    fprintf(htmlfile,"<head>\n");
+    fprintf(htmlfile,"<title>");
+    fprintf(htmlfile,translation->html_title,option_quickest?translation->xml_route_quickest:translation->xml_route_shortest);
+    fprintf(htmlfile,"</title>\n");
+    fprintf(htmlfile,"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
+    fprintf(htmlfile,"<style type=\"text/css\">\n");
+    fprintf(htmlfile,"<!--\n");
+    fprintf(htmlfile,"   table   {table-layout: fixed; border: none; border-collapse: collapse;}\n");
+    fprintf(htmlfile,"   table.c {color: grey; font-size: x-small;} /* copyright */\n");
+    fprintf(htmlfile,"   tr      {border: 0px;}\n");
+    fprintf(htmlfile,"   tr.c    {display: none;} /* coords */\n");
+    fprintf(htmlfile,"   tr.n    {} /* node */\n");
+    fprintf(htmlfile,"   tr.s    {} /* segment */\n");
+    fprintf(htmlfile,"   tr.t    {font-weight: bold;} /* total */\n");
+    fprintf(htmlfile,"   td.l    {font-weight: bold;}\n");
+    fprintf(htmlfile,"   td.r    {}\n");
+    fprintf(htmlfile,"   span.w  {font-weight: bold;} /* waypoint */\n");
+    fprintf(htmlfile,"   span.h  {text-decoration: underline;} /* highway */\n");
+    fprintf(htmlfile,"   span.d  {} /* segment distance */\n");
+    fprintf(htmlfile,"   span.j  {font-style: italic;} /* total journey distance */\n");
+    fprintf(htmlfile,"   span.t  {font-variant: small-caps;} /* turn */\n");
+    fprintf(htmlfile,"   span.b  {font-variant: small-caps;} /* bearing */\n");
+    fprintf(htmlfile,"-->\n");
+    fprintf(htmlfile,"</style>\n");
+    fprintf(htmlfile,"</head>\n");
+    fprintf(htmlfile,"<body>\n");
+    fprintf(htmlfile,"<h1>");
+    fprintf(htmlfile,translation->html_title,option_quickest?translation->xml_route_quickest:translation->xml_route_shortest);
+    fprintf(htmlfile,"</h1>\n");
+    fprintf(htmlfile,"<table>\n");
+   }
+
+ if(gpxtrackfile)
+   {
+    fprintf(gpxtrackfile,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+    fprintf(gpxtrackfile,"<gpx version=\"1.1\" creator=\"Routino\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.topografix.com/GPX/1/1\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">\n");
+
+    fprintf(gpxtrackfile,"<metadata>\n");
+    fprintf(gpxtrackfile,"<desc>%s : %s</desc>\n",translation->xml_copyright_creator[0],translation->xml_copyright_creator[1]);
+    if(translation->xml_copyright_source[1])
+      {
+       fprintf(gpxtrackfile,"<copyright author=\"%s\">\n",translation->xml_copyright_source[1]);
+
+       if(translation->xml_copyright_license[1])
+          fprintf(gpxtrackfile,"<license>%s</license>\n",translation->xml_copyright_license[1]);
+
+       fprintf(gpxtrackfile,"</copyright>\n");
+      }
+    fprintf(gpxtrackfile,"</metadata>\n");
+
+    fprintf(gpxtrackfile,"<trk>\n");
+    fprintf(gpxtrackfile,"<name>");
+    fprintf(gpxtrackfile,translation->gpx_name,option_quickest?translation->xml_route_quickest:translation->xml_route_shortest);
+    fprintf(gpxtrackfile,"</name>\n");
+    fprintf(gpxtrackfile,"<desc>");
+    fprintf(gpxtrackfile,translation->gpx_desc,option_quickest?translation->xml_route_quickest:translation->xml_route_shortest);
+    fprintf(gpxtrackfile,"</desc>\n");
+   }
+
+ if(gpxroutefile)
+   {
+    fprintf(gpxroutefile,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+    fprintf(gpxroutefile,"<gpx version=\"1.1\" creator=\"Routino\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.topografix.com/GPX/1/1\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">\n");
+
+    fprintf(gpxroutefile,"<metadata>\n");
+    fprintf(gpxroutefile,"<desc>%s : %s</desc>\n",translation->xml_copyright_creator[0],translation->xml_copyright_creator[1]);
+    if(translation->xml_copyright_source[1])
+      {
+       fprintf(gpxroutefile,"<copyright author=\"%s\">\n",translation->xml_copyright_source[1]);
+
+       if(translation->xml_copyright_license[1])
+          fprintf(gpxroutefile,"<license>%s</license>\n",translation->xml_copyright_license[1]);
+
+       fprintf(gpxroutefile,"</copyright>\n");
+      }
+    fprintf(gpxroutefile,"</metadata>\n");
+
+    fprintf(gpxroutefile,"<rte>\n");
+    fprintf(gpxroutefile,"<name>");
+    fprintf(gpxroutefile,translation->gpx_name,option_quickest?translation->xml_route_quickest:translation->xml_route_shortest);
+    fprintf(gpxroutefile,"</name>\n");
+    fprintf(gpxroutefile,"<desc>");
+    fprintf(gpxroutefile,translation->gpx_desc,option_quickest?translation->xml_route_quickest:translation->xml_route_shortest);
+    fprintf(gpxroutefile,"</desc>\n");
+   }
+
+ if(textfile)
+   {
+    if(translation->raw_copyright_creator[0] && translation->raw_copyright_creator[1])
+       fprintf(textfile,"# %s : %s\n",translation->raw_copyright_creator[0],translation->raw_copyright_creator[1]);
+    if(translation->raw_copyright_source[0] && translation->raw_copyright_source[1])
+       fprintf(textfile,"# %s : %s\n",translation->raw_copyright_source[0],translation->raw_copyright_source[1]);
+    if(translation->raw_copyright_license[0] && translation->raw_copyright_license[1])
+       fprintf(textfile,"# %s : %s\n",translation->raw_copyright_license[0],translation->raw_copyright_license[1]);
+    if((translation->raw_copyright_creator[0] && translation->raw_copyright_creator[1]) ||
+       (translation->raw_copyright_source[0]  && translation->raw_copyright_source[1]) ||
+       (translation->raw_copyright_license[0] && translation->raw_copyright_license[1]))
+       fprintf(textfile,"#\n");
+
+    fprintf(textfile,"#Latitude\tLongitude\tSection \tSection \tTotal   \tTotal   \tPoint\tTurn\tBearing\tHighway\n");
+    fprintf(textfile,"#        \t         \tDistance\tDuration\tDistance\tDuration\tType \t    \t       \t       \n");
+                     /* "%10.6f\t%11.6f\t%6.3f km\t%4.1f min\t%5.1f km\t%4.0f min\t%s\t %+d\t %+d\t%s\n" */
+   }
+
+ if(textallfile)
+   {
+    if(translation->raw_copyright_creator[0] && translation->raw_copyright_creator[1])
+       fprintf(textallfile,"# %s : %s\n",translation->raw_copyright_creator[0],translation->raw_copyright_creator[1]);
+    if(translation->raw_copyright_source[0] && translation->raw_copyright_source[1])
+       fprintf(textallfile,"# %s : %s\n",translation->raw_copyright_source[0],translation->raw_copyright_source[1]);
+    if(translation->raw_copyright_license[0] && translation->raw_copyright_license[1])
+       fprintf(textallfile,"# %s : %s\n",translation->raw_copyright_license[0],translation->raw_copyright_license[1]);
+    if((translation->raw_copyright_creator[0] && translation->raw_copyright_creator[1]) ||
+       (translation->raw_copyright_source[0]  && translation->raw_copyright_source[1]) ||
+       (translation->raw_copyright_license[0] && translation->raw_copyright_license[1]))
+       fprintf(textallfile,"#\n");
+
+    fprintf(textallfile,"#Latitude\tLongitude\t    Node\tType\tSegment\tSegment\tTotal\tTotal  \tSpeed\tBearing\tHighway\n");
+    fprintf(textallfile,"#        \t         \t        \t    \tDist   \tDurat'n\tDist \tDurat'n\t     \t       \t       \n");
+                        /* "%10.6f\t%11.6f\t%8d%c\t%s\t%5.3f\t%5.2f\t%5.2f\t%5.1f\t%3d\t%4d\t%s\n" */
+   }
+
+ /* Loop through all the sections of the route and print them */
+
+ do
+   {
+    int first=1;
+    int next_point=point;
+    distance_t junc_distance=0;
+    duration_t junc_duration=0;
+    Result *result;
+
+#if DEBUG
+    printf("Route section %d - waypoint %d to waypoint %d\n",point,results[point]->start_waypoint,results[point]->finish_waypoint);
+    printf("  start_node=%"Pindex_t" prev_segment=%"Pindex_t"\n",results[point]->start_node,results[point]->prev_segment);
+    printf("  finish_node=%"Pindex_t" last_segment=%"Pindex_t"\n",results[point]->finish_node,results[point]->last_segment);
+
+    Result *r=FindResult(results[point],results[point]->start_node,results[point]->prev_segment);
+
+    while(r)
+      {
+       printf("    node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score);
+
+       r=r->next;
+      }
+#endif
+
+    result=FindResult(results[point],results[point]->start_node,results[point]->prev_segment);
+
+    /* Print the start of the segment */
+
+    if(gpxtrackfile)
+       fprintf(gpxtrackfile,"<trkseg>\n");
+
+    /* Loop through all the points within a section of the route and print them */
+
+    do
+      {
+       double latitude,longitude;
+       Node *resultnodep=NULL;
+       index_t realsegment=NO_SEGMENT,next_realsegment=NO_SEGMENT;
+       Segment *resultsegmentp=NULL,*next_resultsegmentp=NULL;
+       Way *resultwayp=NULL,*next_resultwayp=NULL;
+       Result *next_result;
+       int important=IMP_UNIMPORTANT;
+
+       distance_t seg_distance=0;
+       duration_t seg_duration=0;
+       speed_t seg_speed=0;
+       char *waynameraw=NULL,*wayname=NULL,*next_waynameraw=NULL,*next_wayname=NULL;
+       int bearing_int=0,turn_int=0,next_bearing_int=0;
+       char *turn=NULL,*next_bearing=NULL;
+
+       /* Calculate the information about this point */
+
+       if(IsFakeNode(result->node))
+          GetFakeLatLong(result->node,&latitude,&longitude);
+       else
+         {
+          resultnodep=LookupNode(nodes,result->node,6);
+
+          GetLatLong(nodes,result->node,resultnodep,&latitude,&longitude);
+         }
+
+       /* Calculate the next result */
+
+       next_result=result->next;
+
+       if(!next_result)
+         {
+          next_point++;
+
+          if(next_point<nresults)
+            {
+             next_result=FindResult(results[next_point],results[next_point]->start_node,results[next_point]->prev_segment);
+             next_result=next_result->next;
+            }
+         }
+
+       /* Calculate the information about this segment */
+
+       if(!first)               /* not first point of a section of the route */
+         {
+          if(IsFakeSegment(result->segment))
+            {
+             resultsegmentp=LookupFakeSegment(result->segment);
+             realsegment=IndexRealSegment(result->segment);
+            }
+          else
+            {
+             resultsegmentp=LookupSegment(segments,result->segment,2);
+             realsegment=result->segment;
+            }
+
+          resultwayp=LookupWay(ways,resultsegmentp->way,1);
+
+          seg_distance+=DISTANCE(resultsegmentp->distance);
+          seg_duration+=Duration(resultsegmentp,resultwayp,profile);
+
+          /* Calculate the cumulative distance/duration */
+
+          junc_distance+=seg_distance;
+          junc_duration+=seg_duration;
+          cum_distance+=seg_distance;
+          cum_duration+=seg_duration;
+         }
+
+       /* Calculate the information about the next segment */
+
+       if(next_result)
+         {
+          if(IsFakeSegment(next_result->segment))
+            {
+             next_resultsegmentp=LookupFakeSegment(next_result->segment);
+             next_realsegment=IndexRealSegment(next_result->segment);
+            }
+          else
+            {
+             next_resultsegmentp=LookupSegment(segments,next_result->segment,1);
+             next_realsegment=next_result->segment;
+            }
+         }
+
+       /* Decide if this is a roundabout */
+
+       if(next_result)
+         {
+          next_resultwayp=LookupWay(ways,next_resultsegmentp->way,2);
+
+          if(next_resultwayp->type&Highway_Roundabout)
+            {
+             if(roundabout==0)
+               {
+                roundabout++;
+                important=IMP_RB_ENTRY;
+               }
+             else
+               {
+                Segment *segmentp;
+
+                if(resultnodep)
+                   segmentp=FirstSegment(segments,resultnodep,3);
+                else
+                   segmentp=FirstFakeSegment(result->node);
+
+                do
+                  {
+                   index_t othernode=OtherNode(segmentp,result->node);
+                   index_t thissegment;
+
+                   if(IsFakeNode(result->node))
+                      thissegment=IndexFakeSegment(segmentp);
+                   else
+                      thissegment=IndexSegment(segments,segmentp);
+
+                   if(othernode!=prev_node && othernode!=next_result->node &&
+                      thissegment!=realsegment && IsNormalSegment(segmentp))
+                     {
+                      int canexit=1;
+
+                      if(profile->oneway && IsOnewayTo(segmentp,result->node))
+                        {
+                         if(profile->allow!=Transports_Bicycle)
+                            canexit=0;
+                         else
+                           {
+                            Way *wayp=LookupWay(ways,segmentp->way,3);
+
+                            if(!(wayp->type&Highway_CycleBothWays))
+                               canexit=0;
+                           }
+                        }
+
+                      if(canexit)
+                        {
+                         Way *wayp=LookupWay(ways,segmentp->way,3);
+
+                         if(!(wayp->type&Highway_Roundabout))
+                           {
+                            roundabout++;
+                            important=IMP_RB_NOT_EXIT;
+                           }
+                        }
+                     }
+
+                   if(resultnodep)
+                      segmentp=NextSegment(segments,segmentp,result->node);
+                   else
+                      segmentp=NextFakeSegment(segmentp,result->node);
+                  }
+                while(segmentp);
+               }
+            }
+          else
+             if(roundabout)
+               {
+                roundabout++;
+                important=IMP_RB_EXIT;
+               }
+         }
+
+       /* Decide if this is an important junction */
+
+       if(point_count==0)  /* first point overall = Waypoint */
+          important=IMP_WAYPOINT;
+       else if(result->next==NULL) /* Waypoint */
+          important=IMP_WAYPOINT;
+       else if(first)           /* first point of a section of the route */
+          important=IMP_IGNORE;
+       else if(roundabout)      /* roundabout */
+          ;
+       else if(realsegment==next_realsegment) /* U-turn */
+          important=IMP_UTURN;
+       else if(resultnodep && (resultnodep->flags&NODE_MINIRNDBT))
+          important=IMP_MINI_RB; /* mini-roundabout */
+       else
+         {
+          Segment *segmentp=FirstSegment(segments,resultnodep,3);
+
+          do
+            {
+             index_t seg=IndexSegment(segments,segmentp);
+
+             if(seg!=realsegment && IsNormalSegment(segmentp))
+               {
+                int cango=1;
+
+                if(profile->oneway && IsOnewayTo(segmentp,result->node))
+                  {
+                   if(profile->allow!=Transports_Bicycle)
+                      cango=0;
+                   else
+                     {
+                      Way *wayp=LookupWay(ways,segmentp->way,3);
+
+                      if(!(wayp->type&Highway_CycleBothWays))
+                         cango=0;
+                     }
+                  }
+
+                if(cango)
+                  {
+                   Way *wayp=LookupWay(ways,segmentp->way,3);
+
+                   if(seg==next_realsegment) /* the next segment that we follow */
+                     {
+                      if(HIGHWAY(wayp->type)!=HIGHWAY(resultwayp->type))
+                         if(important<IMP_CHANGE)
+                            important=IMP_CHANGE;
+                     }
+                   else /* a segment that we don't follow */
+                     {
+                      if(junction_other_way[HIGHWAY(resultwayp->type)-1][HIGHWAY(wayp->type)-1])
+                         if(important<IMP_JUNCT_IMPORT)
+                            important=IMP_JUNCT_IMPORT;
+
+                      if(important<IMP_JUNCT_CONT)
+                         important=IMP_JUNCT_CONT;
+                     }
+                  }
+               }
+
+             segmentp=NextSegment(segments,segmentp,result->node);
+            }
+          while(segmentp);
+         }
+
+       /* Calculate the strings to be used */
+
+       if(!first && textallfile)
+         {
+          waynameraw=WayName(ways,resultwayp);
+          if(!*waynameraw)
+             waynameraw=translation->raw_highway[HIGHWAY(resultwayp->type)];
+
+          bearing_int=(int)BearingAngle(nodes,resultsegmentp,result->node);
+
+          seg_speed=profile->speed[HIGHWAY(resultwayp->type)];
+         }
+
+       if(next_result && important>IMP_JUNCT_CONT)
+         {
+          if(!first && (htmlfile || textfile))
+            {
+             if(DISTANCE(resultsegmentp->distance)==0 || DISTANCE(next_resultsegmentp->distance)==0)
+                turn_int=0;
+             else
+                turn_int=(int)TurnAngle(nodes,resultsegmentp,next_resultsegmentp,result->node);
+
+             turn=translation->xml_turn[((202+turn_int)/45)%8];
+            }
+
+          if(gpxroutefile || htmlfile)
+            {
+             next_waynameraw=WayName(ways,next_resultwayp);
+             if(!*next_waynameraw)
+                next_waynameraw=translation->raw_highway[HIGHWAY(next_resultwayp->type)];
+
+             next_wayname=ParseXML_Encode_Safe_XML(next_waynameraw);
+            }
+
+          if(htmlfile || gpxroutefile || textfile)
+            {
+             if(!first && DISTANCE(next_resultsegmentp->distance)==0)
+                next_bearing_int=(int)BearingAngle(nodes,resultsegmentp,result->node);
+             else
+                next_bearing_int=(int)BearingAngle(nodes,next_resultsegmentp,next_result->node);
+
+             next_bearing=translation->xml_heading[(4+(22+next_bearing_int)/45)%8];
+            }
+         }
+
+       /* Print out the important points (junctions / waypoints) */
+
+       if(important>IMP_JUNCT_CONT)
+         {
+          if(htmlfile)
+            {
+             char *type;
+
+             if(important==IMP_WAYPOINT)
+                type=translation->html_waypoint;
+             else if(important==IMP_MINI_RB)
+                type=translation->html_roundabout;
+             else
+                type=translation->html_junction;
+
+             if(point_count>0)  /* not the first point */
+               {
+                /* <tr class='s'><td class='l'>Follow:<td class='r'><span class='h'>*highway name*</span> for <span class='d'>*distance* km, *time* min</span> [<span class='j'>*distance* km, *time* minutes</span>] */
+                fprintf(htmlfile,"<tr class='s'><td class='l'>%s:<td class='r'>",translation->html_segment[0]);
+                fprintf(htmlfile,translation->html_segment[1],
+                                 (roundabout>1?translation->html_roundabout:prev_wayname),
+                                 distance_to_km(junc_distance),duration_to_minutes(junc_duration));
+                fprintf(htmlfile," [<span class='j'>");
+                fprintf(htmlfile,translation->html_total[1],
+                                 distance_to_km(cum_distance),duration_to_minutes(cum_duration));
+                fprintf(htmlfile,"</span>]\n");
+               }
+
+             /* <tr class='c'><td class='l'>*N*:<td class='r'>*latitude* *longitude* */
+             fprintf(htmlfile,"<tr class='c'><td class='l'>%d:<td class='r'>%.6f %.6f\n",
+                              point_count+1,
+                              radians_to_degrees(latitude),radians_to_degrees(longitude));
+
+             if(point_count==0) /* first point */
+               {
+                /* <tr class='n'><td class='l'>Start:<td class='r'>At <span class='w'>Waypoint</span>, head <span class='b'>*heading*</span> */
+                fprintf(htmlfile,"<tr class='n'><td class='l'>%s:<td class='r'>",translation->html_start[0]);
+                fprintf(htmlfile,translation->html_start[1],
+                                 translation->html_waypoint,
+                                 next_bearing);
+                fprintf(htmlfile,"\n");
+               }
+             else if(next_result) /* middle point */
+               {
+                if(roundabout>1 && important!=IMP_WAYPOINT)
+                  {
+                   /* <tr class='n'><td class='l'>At:<td class='r'>Roundabout, take <span class='t'>the *Nth* exit</span> heading <span class='b'>*heading*</span> */
+                   fprintf(htmlfile,"<tr class='n'><td class='l'>%s:<td class='r'>",translation->html_rbnode[0]);
+                   fprintf(htmlfile,translation->html_rbnode[1],
+                                    translation->html_roundabout,
+                                    translation->xml_ordinal[roundabout-2],
+                                    next_bearing);
+                   fprintf(htmlfile,"\n");
+                  }
+                else
+                  {
+                   /* <tr class='n'><td class='l'>At:<td class='r'>Junction, go <span class='t'>*direction*</span> heading <span class='b'>*heading*</span> */
+                   fprintf(htmlfile,"<tr class='n'><td class='l'>%s:<td class='r'>",translation->html_node[0]);
+                   fprintf(htmlfile,translation->html_node[1],
+                                    type,
+                                    turn,
+                                    next_bearing);
+                   fprintf(htmlfile,"\n");
+                  }
+               }
+             else            /* end point */
+               {
+                /* <tr class='n'><td class='l'>Stop:<td class='r'>At <span class='w'>Waypoint</span> */
+                fprintf(htmlfile,"<tr class='n'><td class='l'>%s:<td class='r'>",translation->html_stop[0]);
+                fprintf(htmlfile,translation->html_stop[1],
+                                 translation->html_waypoint);
+                fprintf(htmlfile,"\n");
+
+                /* <tr class='t'><td class='l'>Total:<td class='r'><span class='j'>*distance* km, *time* minutes</span> */
+                fprintf(htmlfile,"<tr class='t'><td class='l'>%s:<td class='r'><span class='j'>",translation->html_total[0]);
+                fprintf(htmlfile,translation->html_total[1],
+                                 distance_to_km(cum_distance),duration_to_minutes(cum_duration));
+                fprintf(htmlfile,"</span>\n");
+               }
+            }
+
+          if(gpxroutefile)
+            {
+             if(point_count>0) /* not first point */
+               {
+                fprintf(gpxroutefile,"<desc>");
+                fprintf(gpxroutefile,translation->gpx_step,
+                                     prev_bearing,
+                                     prev_wayname,
+                                     distance_to_km(junc_distance),duration_to_minutes(junc_duration));
+                fprintf(gpxroutefile,"</desc></rtept>\n");
+               }
+
+             if(point_count==0) /* first point */
+               {
+                fprintf(gpxroutefile,"<rtept lat=\"%.6f\" lon=\"%.6f\"><name>%s</name>\n",
+                                     radians_to_degrees(latitude),radians_to_degrees(longitude),
+                                     translation->gpx_start);
+               }
+             else if(!next_result) /* end point */
+               {
+                fprintf(gpxroutefile,"<rtept lat=\"%.6f\" lon=\"%.6f\"><name>%s</name>\n",
+                                     radians_to_degrees(latitude),radians_to_degrees(longitude),
+                                     translation->gpx_finish);
+                fprintf(gpxroutefile,"<desc>");
+                fprintf(gpxroutefile,translation->gpx_final,
+                                     distance_to_km(cum_distance),duration_to_minutes(cum_duration));
+                fprintf(gpxroutefile,"</desc></rtept>\n");
+               }
+             else            /* middle point */
+               {
+                if(important==IMP_WAYPOINT)
+                   fprintf(gpxroutefile,"<rtept lat=\"%.6f\" lon=\"%.6f\"><name>%s%d</name>\n",
+                                        radians_to_degrees(latitude),radians_to_degrees(longitude),
+                                        translation->gpx_inter,++segment_count);
+                else
+                   fprintf(gpxroutefile,"<rtept lat=\"%.6f\" lon=\"%.6f\"><name>%s%03d</name>\n",
+                                        radians_to_degrees(latitude),radians_to_degrees(longitude),
+                                        translation->gpx_trip,++route_count);
+               }
+            }
+
+          if(textfile)
+            {
+             char *type;
+
+             if(important==IMP_WAYPOINT)
+                type="Waypt";
+             else
+                type="Junct";
+
+             if(point_count==0) /* first point */
+               {
+                fprintf(textfile,"%10.6f\t%11.6f\t%6.3f km\t%4.1f min\t%5.1f km\t%4.0f min\t%s\t\t %+d\t%s\n",
+                                 radians_to_degrees(latitude),radians_to_degrees(longitude),
+                                 0.0,0.0,0.0,0.0,
+                                 type,
+                                 ((22+next_bearing_int)/45+4)%8-4,
+                                 next_waynameraw);
+               }
+             else if(!next_result) /* end point */
+               {
+                fprintf(textfile,"%10.6f\t%11.6f\t%6.3f km\t%4.1f min\t%5.1f km\t%4.0f min\t%s\t\t\t\n",
+                                 radians_to_degrees(latitude),radians_to_degrees(longitude),
+                                 distance_to_km(junc_distance),duration_to_minutes(junc_duration),
+                                 distance_to_km(cum_distance),duration_to_minutes(cum_duration),
+                                 type);
+               }
+             else               /* middle point */
+               {
+                fprintf(textfile,"%10.6f\t%11.6f\t%6.3f km\t%4.1f min\t%5.1f km\t%4.0f min\t%s\t %+d\t %+d\t%s\n",
+                                 radians_to_degrees(latitude),radians_to_degrees(longitude),
+                                 distance_to_km(junc_distance),duration_to_minutes(junc_duration),
+                                 distance_to_km(cum_distance),duration_to_minutes(cum_duration),
+                                 type,
+                                 (22+turn_int)/45,
+                                 ((22+next_bearing_int)/45+4)%8-4,
+                                 next_waynameraw);
+               }
+            }
+
+          junc_distance=0;
+          junc_duration=0;
+
+          if(htmlfile || gpxroutefile)
+            {
+             if(prev_wayname)
+                free(prev_wayname);
+
+             if(next_wayname)
+                prev_wayname=strcpy((char*)malloc(strlen(next_wayname)+1),next_wayname);
+             else
+                prev_wayname=NULL;
+            }
+
+          if(gpxroutefile)
+             prev_bearing=next_bearing;
+
+          if(roundabout>1)
+             roundabout=0;
+         }
+
+       /* Print out all of the results */
+
+       if(gpxtrackfile)
+          fprintf(gpxtrackfile,"<trkpt lat=\"%.6f\" lon=\"%.6f\"/>\n",
+                               radians_to_degrees(latitude),radians_to_degrees(longitude));
+
+       if(important>IMP_IGNORE)
+         {
+          if(textallfile)
+            {
+             char *type;
+
+             if(important==IMP_WAYPOINT)
+                type="Waypt";
+             else if(important==IMP_UTURN)
+                type="U-turn";
+             else if(important==IMP_MINI_RB)
+                type="Mini-RB";
+             else if(important==IMP_CHANGE)
+                type="Change";
+             else if(important==IMP_JUNCT_CONT || important==IMP_RB_NOT_EXIT)
+                type="Junct-";
+             else if(important==IMP_UNIMPORTANT)
+                type="Inter";
+             else
+                type="Junct";
+
+             if(point_count==0) /* first point */
+               {
+                fprintf(textallfile,"%10.6f\t%11.6f\t%8d%c\t%s\t%5.3f\t%5.2f\t%5.2f\t%5.1f\t\t\t\n",
+                                    radians_to_degrees(latitude),radians_to_degrees(longitude),
+                                    IsFakeNode(result->node)?(NODE_FAKE-result->node):result->node,
+                                    (resultnodep && IsSuperNode(resultnodep))?'*':' ',type,
+                                    0.0,0.0,0.0,0.0);
+               }
+             else               /* not the first point */
+               {
+                fprintf(textallfile,"%10.6f\t%11.6f\t%8d%c\t%s\t%5.3f\t%5.2f\t%5.2f\t%5.1f\t%3d\t%4d\t%s\n",
+                                    radians_to_degrees(latitude),radians_to_degrees(longitude),
+                                    IsFakeNode(result->node)?(NODE_FAKE-result->node):result->node,
+                                    (resultnodep && IsSuperNode(resultnodep))?'*':' ',type,
+                                    distance_to_km(seg_distance),duration_to_minutes(seg_duration),
+                                    distance_to_km(cum_distance),duration_to_minutes(cum_duration),
+                                    speed_to_kph(seg_speed),
+                                    bearing_int,
+                                    waynameraw);
+               }
+            }
+         }
+
+       if(wayname && wayname!=waynameraw)
+          free(wayname);
+
+       result=next_result;
+
+       if(important>IMP_JUNCT_CONT)
+          point_count++;
+
+       first=0;
+      }
+    while(point==next_point);
+
+    /* Print the end of the segment */
+
+    if(gpxtrackfile)
+       fprintf(gpxtrackfile,"</trkseg>\n");
+
+    point=next_point;
+
+    if(result)
+       prev_node=result->node;
+    else
+       prev_node=NO_NODE;
+   }
+ while(point<nresults);
+
+ /* Print the tail of the files */
+
+ if(htmlfile)
+   {
+    fprintf(htmlfile,"</table>\n");
+
+    if((translation->xml_copyright_creator[0] && translation->xml_copyright_creator[1]) ||
+       (translation->xml_copyright_source[0]  && translation->xml_copyright_source[1]) ||
+       (translation->xml_copyright_license[0] && translation->xml_copyright_license[1]))
+      {
+       fprintf(htmlfile,"<p>\n");
+       fprintf(htmlfile,"<table class='c'>\n");
+       if(translation->xml_copyright_creator[0] && translation->xml_copyright_creator[1])
+          fprintf(htmlfile,"<tr><td class='l'>%s:<td class='r'>%s\n",translation->xml_copyright_creator[0],translation->xml_copyright_creator[1]);
+       if(translation->xml_copyright_source[0] && translation->xml_copyright_source[1])
+          fprintf(htmlfile,"<tr><td class='l'>%s:<td class='r'>%s\n",translation->xml_copyright_source[0],translation->xml_copyright_source[1]);
+       if(translation->xml_copyright_license[0] && translation->xml_copyright_license[1])
+          fprintf(htmlfile,"<tr><td class='l'>%s:<td class='r'>%s\n",translation->xml_copyright_license[0],translation->xml_copyright_license[1]);
+       fprintf(htmlfile,"</table>\n");
+      }
+
+    fprintf(htmlfile,"</body>\n");
+    fprintf(htmlfile,"</html>\n");
+   }
+
+ if(gpxtrackfile)
+   {
+    fprintf(gpxtrackfile,"</trk>\n");
+    fprintf(gpxtrackfile,"</gpx>\n");
+   }
+
+ if(gpxroutefile)
+   {
+    fprintf(gpxroutefile,"</rte>\n");
+    fprintf(gpxroutefile,"</gpx>\n");
+   }
+
+ /* Close the files */
+
+ if(!option_stdout)
+   {
+    if(htmlfile)
+       fclose(htmlfile);
+    if(gpxtrackfile)
+       fclose(gpxtrackfile);
+    if(gpxroutefile)
+       fclose(gpxroutefile);
+    if(textfile)
+       fclose(textfile);
+    if(textallfile)
+       fclose(textallfile);
+   }
+}
diff --git a/3rdparty/Routino/src/planetsplitter.c b/3rdparty/Routino/src/planetsplitter.c
new file mode 100644
index 0000000..dc6f61f
--- /dev/null
+++ b/3rdparty/Routino/src/planetsplitter.c
@@ -0,0 +1,731 @@
+/***************************************
+ OSM planet file splitter.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "types.h"
+#include "ways.h"
+
+#include "typesx.h"
+#include "nodesx.h"
+#include "segmentsx.h"
+#include "waysx.h"
+#include "relationsx.h"
+#include "superx.h"
+#include "prunex.h"
+
+#include "files.h"
+#include "logging.h"
+#include "errorlogx.h"
+#include "functions.h"
+#include "osmparser.h"
+#include "tagging.h"
+#include "uncompress.h"
+
+
+/* Global variables */
+
+/*+ The name of the temporary directory. +*/
+char *option_tmpdirname=NULL;
+
+/*+ The amount of RAM to use for filesorting. +*/
+size_t option_filesort_ramsize=0;
+
+/*+ The number of threads to use for filesorting. +*/
+int option_filesort_threads=1;
+
+
+/* Local functions */
+
+static void print_usage(int detail,const char *argerr,const char *err);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The main program for the planetsplitter.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int main(int argc,char** argv)
+{
+ NodesX     *OSMNodes;
+ SegmentsX  *OSMSegments,*SuperSegments=NULL,*MergedSegments=NULL;
+ WaysX      *OSMWays;
+ RelationsX *OSMRelations;
+ int         iteration=0,quit=0;
+ int         max_iterations=5;
+ char       *dirname=NULL,*prefix=NULL,*tagging=NULL,*errorlog=NULL;
+ int         option_parse_only=0,option_process_only=0;
+ int         option_append=0,option_keep=0,option_changes=0;
+ int         option_filenames=0;
+ int         option_prune_isolated=500,option_prune_short=5,option_prune_straight=3;
+ int         arg;
+
+ printf_program_start();
+
+ /* Parse the command line arguments */
+
+ for(arg=1;arg<argc;arg++)
+   {
+    if(!strcmp(argv[arg],"--help"))
+       print_usage(1,NULL,NULL);
+    else if(!strncmp(argv[arg],"--dir=",6))
+       dirname=&argv[arg][6];
+    else if(!strncmp(argv[arg],"--prefix=",9))
+       prefix=&argv[arg][9];
+    else if(!strncmp(argv[arg],"--sort-ram-size=",16))
+       option_filesort_ramsize=atoi(&argv[arg][16]);
+#if defined(USE_PTHREADS) && USE_PTHREADS
+    else if(!strncmp(argv[arg],"--sort-threads=",15))
+       option_filesort_threads=atoi(&argv[arg][15]);
+#endif
+    else if(!strncmp(argv[arg],"--tmpdir=",9))
+       option_tmpdirname=&argv[arg][9];
+    else if(!strncmp(argv[arg],"--tagging=",10))
+       tagging=&argv[arg][10];
+    else if(!strcmp(argv[arg],"--loggable"))
+       option_loggable=1;
+    else if(!strcmp(argv[arg],"--logtime"))
+       option_logtime=1;
+    else if(!strcmp(argv[arg],"--logmemory"))
+       option_logmemory=1;
+    else if(!strcmp(argv[arg],"--errorlog"))
+       errorlog="error.log";
+    else if(!strncmp(argv[arg],"--errorlog=",11))
+       errorlog=&argv[arg][11];
+    else if(!strcmp(argv[arg],"--parse-only"))
+       option_parse_only=1;
+    else if(!strcmp(argv[arg],"--process-only"))
+       option_process_only=1;
+    else if(!strcmp(argv[arg],"--append"))
+       option_append=1;
+    else if(!strcmp(argv[arg],"--keep"))
+       option_keep=1;
+    else if(!strcmp(argv[arg],"--changes"))
+       option_changes=1;
+    else if(!strncmp(argv[arg],"--max-iterations=",17))
+       max_iterations=atoi(&argv[arg][17]);
+    else if(!strncmp(argv[arg],"--prune",7))
+      {
+       if(!strcmp(&argv[arg][7],"-none"))
+          option_prune_isolated=option_prune_short=option_prune_straight=0;
+       else if(!strncmp(&argv[arg][7],"-isolated=",10))
+          option_prune_isolated=atoi(&argv[arg][17]);
+       else if(!strncmp(&argv[arg][7],"-short=",7))
+          option_prune_short=atoi(&argv[arg][14]);
+       else if(!strncmp(&argv[arg][7],"-straight=",10))
+          option_prune_straight=atoi(&argv[arg][17]);
+       else
+          print_usage(0,argv[arg],NULL);
+      }
+    else if(argv[arg][0]=='-' && argv[arg][1]=='-')
+       print_usage(0,argv[arg],NULL);
+    else
+       option_filenames++;
+   }
+
+ /* Check the specified command line options */
+
+ if(option_parse_only && option_process_only)
+    print_usage(0,NULL,"Cannot use '--parse-only' and '--process-only' at the same time.");
+
+ if(option_append && option_process_only)
+    print_usage(0,NULL,"Cannot use '--append' and '--process-only' at the same time.");
+
+ if(option_filenames && option_process_only)
+    print_usage(0,NULL,"Cannot use '--process-only' and filenames at the same time.");
+
+ if(!option_filenames && !option_process_only)
+    print_usage(0,NULL,"File names must be specified unless using '--process-only'");
+
+ if(!option_filesort_ramsize)
+   {
+#if SLIM
+    option_filesort_ramsize=64*1024*1024;
+#else
+    option_filesort_ramsize=256*1024*1024;
+#endif
+   }
+ else
+    option_filesort_ramsize*=1024*1024;
+
+ if(!option_tmpdirname)
+   {
+    if(!dirname)
+       option_tmpdirname=".";
+    else
+       option_tmpdirname=dirname;
+   }
+
+ if(!option_process_only)
+   {
+    if(tagging)
+      {
+       if(!ExistsFile(tagging))
+         {
+          fprintf(stderr,"Error: The '--tagging' option specifies a file that does not exist.\n");
+          exit(EXIT_FAILURE);
+         }
+      }
+    else
+      {
+       tagging=FileName(dirname,prefix,"tagging.xml");
+
+       if(!ExistsFile(tagging))
+         {
+          free(tagging);
+
+          tagging=FileName(ROUTINO_DATADIR,NULL,"tagging.xml");
+
+          if(!ExistsFile(tagging))
+            {
+             fprintf(stderr,"Error: The '--tagging' option was not used and the default 'tagging.xml' does not exist.\n");
+             exit(EXIT_FAILURE);
+            }
+         }
+      }
+
+    if(ParseXMLTaggingRules(tagging))
+      {
+       fprintf(stderr,"Error: Cannot read the tagging rules in the file '%s'.\n",tagging);
+       exit(EXIT_FAILURE);
+      }
+   }
+
+ /* Create new node, segment, way and relation variables */
+
+ OSMNodes=NewNodeList(option_append||option_changes,option_process_only);
+
+ OSMWays=NewWayList(option_append||option_changes,option_process_only);
+
+ OSMRelations=NewRelationList(option_append||option_changes,option_process_only);
+
+ /* Create the error log file */
+
+ if(errorlog)
+    open_errorlog(FileName(dirname,prefix,errorlog),option_append||option_changes||option_process_only,option_keep);
+
+ /* Parse the file */
+
+if(!option_process_only)
+  {
+   for(arg=1;arg<argc;arg++)
+     {
+      int fd;
+      char *filename,*p;
+
+      if(argv[arg][0]=='-' && argv[arg][1]=='-')
+         continue;
+
+      filename=strcpy(malloc(strlen(argv[arg])+1),argv[arg]);
+
+      fd=OpenFile(filename);
+
+      if((p=strstr(filename,".bz2")) && !strcmp(p,".bz2"))
+        {
+         fd=Uncompress_Bzip2(fd);
+         *p=0;
+        }
+
+      if((p=strstr(filename,".gz")) && !strcmp(p,".gz"))
+        {
+         fd=Uncompress_Gzip(fd);
+         *p=0;
+        }
+
+      if((p=strstr(filename,".xz")) && !strcmp(p,".xz"))
+        {
+         fd=Uncompress_Xz(fd);
+         *p=0;
+        }
+
+      if(option_changes)
+        {
+         printf("\nParse OSC Data [%s]\n==============\n\n",filename);
+         fflush(stdout);
+
+         if((p=strstr(filename,".pbf")) && !strcmp(p,".pbf"))
+           {
+            logassert(0,"Unable to read a PBF file to apply changes (format does not permit this)");
+           }
+         else if((p=strstr(filename,".o5c")) && !strcmp(p,".o5c"))
+           {
+            if(ParseO5CFile(fd,OSMNodes,OSMWays,OSMRelations))
+               exit(EXIT_FAILURE);
+           }
+         else
+           {
+            if(ParseOSCFile(fd,OSMNodes,OSMWays,OSMRelations))
+               exit(EXIT_FAILURE);
+           }
+        }
+      else
+        {
+         printf("\nParse OSM Data [%s]\n==============\n\n",filename);
+         fflush(stdout);
+
+         if((p=strstr(filename,".pbf")) && !strcmp(p,".pbf"))
+           {
+            if(ParsePBFFile(fd,OSMNodes,OSMWays,OSMRelations))
+               exit(EXIT_FAILURE);
+           }
+         else if((p=strstr(filename,".o5m")) && !strcmp(p,".o5m"))
+           {
+            if(ParseO5MFile(fd,OSMNodes,OSMWays,OSMRelations))
+               exit(EXIT_FAILURE);
+           }
+         else
+           {
+            if(ParseOSMFile(fd,OSMNodes,OSMWays,OSMRelations))
+               exit(EXIT_FAILURE);
+           }
+        }
+
+      CloseFile(fd);
+
+      free(filename);
+     }
+
+   DeleteXMLTaggingRules();
+  }
+
+ FinishNodeList(OSMNodes);
+ FinishWayList(OSMWays);
+ FinishRelationList(OSMRelations);
+
+ if(option_parse_only)
+   {
+    FreeNodeList(OSMNodes,1);
+    FreeWayList(OSMWays,1);
+    FreeRelationList(OSMRelations,1);
+
+    exit(EXIT_SUCCESS);
+   }
+
+
+ /* Sort the data */
+
+ printf("\nSort OSM Data\n=============\n\n");
+ fflush(stdout);
+
+ /* Sort the nodes, ways and relations */
+
+ SortNodeList(OSMNodes);
+
+ SortWayList(OSMWays);
+
+ SortRelationList(OSMRelations);
+
+ /* Process the data */
+
+ printf("\nProcess OSM Data\n================\n\n");
+ fflush(stdout);
+
+ /* Remove non-highway nodes by looking through the ways (must be before splitting the ways) */
+
+ RemoveNonHighwayNodes(OSMNodes,OSMWays,option_keep||option_changes);
+
+ /* Separate the segments and way names and sort them (must be before processing the segments) */
+
+ OSMSegments=SplitWays(OSMWays,OSMNodes,option_keep||option_changes);
+
+ SortWayNames(OSMWays);
+
+ SortSegmentList(OSMSegments);
+
+ /* Process the segments and index them (must be before processing relations) */
+
+ ProcessSegments(OSMSegments,OSMNodes,OSMWays);
+
+ IndexSegments(OSMSegments,OSMNodes,OSMWays);
+
+ /* Process the route relations and turn relations (must be before compacting the ways) */
+
+ ProcessRouteRelations(OSMRelations,OSMWays,option_keep||option_changes);
+
+ ProcessTurnRelations(OSMRelations,OSMNodes,OSMSegments,OSMWays,option_keep||option_changes);
+
+ /* Compact the ways */
+
+ CompactWayList(OSMWays,OSMSegments);
+
+ /* Sort the nodes and segments geographically */
+
+ SortNodeListGeographically(OSMNodes);
+
+ SortSegmentListGeographically(OSMSegments,OSMNodes);
+
+ /* Re-index the segments */
+
+ IndexSegments(OSMSegments,OSMNodes,OSMWays);
+
+ /* Sort the turn relations geographically */
+
+ SortTurnRelationListGeographically(OSMRelations,OSMNodes,OSMSegments,0);
+
+ /* Prune unwanted nodes/segments */
+
+ if(option_prune_straight || option_prune_isolated || option_prune_short)
+   {
+    printf("\nPrune Unneeded Data\n===================\n\n");
+    fflush(stdout);
+
+    if(option_prune_straight)
+      {
+       StartPruning(OSMNodes,OSMSegments,OSMWays);
+
+       PruneStraightHighwayNodes(OSMNodes,OSMSegments,OSMWays,option_prune_straight);
+
+       FinishPruning(OSMNodes,OSMSegments,OSMWays);
+
+       RemovePrunedNodes(OSMNodes,OSMSegments);
+       RemovePrunedSegments(OSMSegments,OSMWays);
+       CompactWayList(OSMWays,OSMSegments);
+       RemovePrunedTurnRelations(OSMRelations,OSMNodes);
+
+       IndexSegments(OSMSegments,OSMNodes,OSMWays);
+      }
+
+    if(option_prune_isolated)
+      {
+       StartPruning(OSMNodes,OSMSegments,OSMWays);
+
+       PruneIsolatedRegions(OSMNodes,OSMSegments,OSMWays,option_prune_isolated);
+
+       FinishPruning(OSMNodes,OSMSegments,OSMWays);
+
+       RemovePrunedNodes(OSMNodes,OSMSegments);
+       RemovePrunedSegments(OSMSegments,OSMWays);
+       CompactWayList(OSMWays,OSMSegments);
+       RemovePrunedTurnRelations(OSMRelations,OSMNodes);
+
+       IndexSegments(OSMSegments,OSMNodes,OSMWays);
+      }
+
+    if(option_prune_short)
+      {
+       StartPruning(OSMNodes,OSMSegments,OSMWays);
+
+       PruneShortSegments(OSMNodes,OSMSegments,OSMWays,option_prune_short);
+
+       FinishPruning(OSMNodes,OSMSegments,OSMWays);
+
+       RemovePrunedNodes(OSMNodes,OSMSegments);
+       RemovePrunedSegments(OSMSegments,OSMWays);
+       CompactWayList(OSMWays,OSMSegments);
+       RemovePrunedTurnRelations(OSMRelations,OSMNodes);
+
+       IndexSegments(OSMSegments,OSMNodes,OSMWays);
+      }
+   }
+
+ /* Repeated iteration on Super-Nodes and Super-Segments */
+
+ do
+   {
+    index_t nsuper;
+
+    printf("\nProcess Super-Data (iteration %d)\n================================%s\n\n",iteration,iteration>9?"=":"");
+    fflush(stdout);
+
+    if(iteration==0)
+      {
+       /* Select the super-nodes */
+
+       ChooseSuperNodes(OSMNodes,OSMSegments,OSMWays);
+
+       /* Select the super-segments */
+
+       SuperSegments=CreateSuperSegments(OSMNodes,OSMSegments,OSMWays);
+
+       nsuper=OSMSegments->number;
+      }
+    else
+      {
+       SegmentsX *SuperSegments2;
+
+       /* Index the super-segments */
+
+       IndexSegments(SuperSegments,OSMNodes,OSMWays);
+
+       /* Select the super-nodes */
+
+       ChooseSuperNodes(OSMNodes,SuperSegments,OSMWays);
+
+       /* Select the super-segments */
+
+       SuperSegments2=CreateSuperSegments(OSMNodes,SuperSegments,OSMWays);
+
+       nsuper=SuperSegments->number;
+
+       FreeSegmentList(SuperSegments);
+
+       SuperSegments=SuperSegments2;
+      }
+
+    /* Sort the super-segments and remove duplicates */
+
+    DeduplicateSuperSegments(SuperSegments,OSMWays);
+
+    /* Check for end condition */
+
+    if(SuperSegments->number==nsuper)
+       quit=1;
+
+    iteration++;
+
+    if(iteration>max_iterations)
+       quit=1;
+   }
+ while(!quit);
+
+ /* Combine the super-segments */
+
+ printf("\nCombine Segments and Super-Segments\n===================================\n\n");
+ fflush(stdout);
+
+ /* Merge the super-segments */
+
+ MergedSegments=MergeSuperSegments(OSMSegments,SuperSegments);
+
+ FreeSegmentList(OSMSegments);
+
+ FreeSegmentList(SuperSegments);
+
+ OSMSegments=MergedSegments;
+
+ /* Cross reference the nodes and segments */
+
+ printf("\nCross-Reference Nodes and Segments\n==================================\n\n");
+ fflush(stdout);
+
+ /* Sort the nodes and segments geographically */
+
+ SortNodeListGeographically(OSMNodes);
+
+ SortSegmentListGeographically(OSMSegments,OSMNodes);
+
+ /* Re-index the segments */
+
+ IndexSegments(OSMSegments,OSMNodes,OSMWays);
+
+ /* Sort the turn relations geographically */
+
+ SortTurnRelationListGeographically(OSMRelations,OSMNodes,OSMSegments,1);
+
+ /* Output the results */
+
+ printf("\nWrite Out Database Files\n========================\n\n");
+ fflush(stdout);
+
+ /* Write out the nodes */
+
+ SaveNodeList(OSMNodes,FileName(dirname,prefix,"nodes.mem"),OSMSegments);
+
+ /* Write out the segments */
+
+ SaveSegmentList(OSMSegments,FileName(dirname,prefix,"segments.mem"));
+
+ /* Write out the ways */
+
+ SaveWayList(OSMWays,FileName(dirname,prefix,"ways.mem"));
+
+ /* Write out the relations */
+
+ SaveRelationList(OSMRelations,FileName(dirname,prefix,"relations.mem"));
+
+ /* Free the memory (delete the temporary files) */
+
+ FreeSegmentList(OSMSegments);
+
+ /* Close the error log file and process the data */
+
+ if(errorlog)
+   {
+    close_errorlog();
+
+    if(option_keep)
+      {
+       ErrorLogsX *OSMErrorLogs;
+
+       printf("\nCreate Error Log\n================\n\n");
+       fflush(stdout);
+
+       OSMErrorLogs=NewErrorLogList();
+
+       ProcessErrorLogs(OSMErrorLogs,OSMNodes,OSMWays,OSMRelations);
+
+       SortErrorLogsGeographically(OSMErrorLogs);
+
+       SaveErrorLogs(OSMErrorLogs,FileName(dirname,prefix,"errorlogs.mem"));
+
+       FreeErrorLogList(OSMErrorLogs);
+      }
+   }
+
+ /* Free the memory (delete the temporary files) */
+
+ FreeNodeList(OSMNodes,0);
+ FreeWayList(OSMWays,0);
+ FreeRelationList(OSMRelations,0);
+
+ printf("\n");
+ fflush(stdout);
+
+ printf_program_end();
+
+ exit(EXIT_SUCCESS);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the usage information.
+
+  int detail The level of detail to use - 0 = low, 1 = high.
+
+  const char *argerr The argument that gave the error (if there is one).
+
+  const char *err Other error message (if there is one).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_usage(int detail,const char *argerr,const char *err)
+{
+ fprintf(stderr,
+         "Usage: planetsplitter [--help]\n"
+         "                      [--dir=<dirname>] [--prefix=<name>]\n"
+#if defined(USE_PTHREADS) && USE_PTHREADS
+         "                      [--sort-ram-size=<size>] [--sort-threads=<number>]\n"
+#else
+         "                      [--sort-ram-size=<size>]\n"
+#endif
+         "                      [--tmpdir=<dirname>]\n"
+         "                      [--tagging=<filename>]\n"
+         "                      [--loggable] [--logtime] [--logmemory]\n"
+         "                      [--errorlog[=<name>]]\n"
+         "                      [--parse-only | --process-only]\n"
+         "                      [--append] [--keep] [--changes]\n"
+         "                      [--max-iterations=<number>]\n"
+         "                      [--prune-none]\n"
+         "                      [--prune-isolated=<len>]\n"
+         "                      [--prune-short=<len>]\n"
+         "                      [--prune-straight=<len>]\n"
+         "                      [<filename.osm> ... | <filename.osc> ...\n"
+         "                       | <filename.pbf> ...\n"
+         "                       | <filename.o5m> ... | <filename.o5c> ..."
+#if defined(USE_BZIP2) && USE_BZIP2
+         "\n                       | <filename.(osm|osc|o5m|o5c).bz2> ..."
+#endif
+#if defined(USE_GZIP) && USE_GZIP
+         "\n                       | <filename.(osm|osc|o5m|o5c).gz> ..."
+#endif
+#if defined(USE_XZ) && USE_XZ
+         "\n                       | <filename.(osm|osc|o5m|o5c).xz> ..."
+#endif
+         "]\n");
+
+ if(argerr)
+    fprintf(stderr,
+            "\n"
+            "Error with command line parameter: %s\n",argerr);
+
+ if(err)
+    fprintf(stderr,
+            "\n"
+            "Error: %s\n",err);
+
+ if(detail)
+    fprintf(stderr,
+            "\n"
+            "--help                    Prints this information.\n"
+            "\n"
+            "--dir=<dirname>           The directory containing the routing database.\n"
+            "--prefix=<name>           The filename prefix for the routing database.\n"
+            "\n"
+            "--sort-ram-size=<size>    The amount of RAM (in MB) to use for data sorting\n"
+#if SLIM
+            "                          (defaults to 64MB otherwise.)\n"
+#else
+            "                          (defaults to 256MB otherwise.)\n"
+#endif
+#if defined(USE_PTHREADS) && USE_PTHREADS
+            "--sort-threads=<number>   The number of threads to use for data sorting.\n"
+#endif
+            "\n"
+            "--tmpdir=<dirname>        The directory name for temporary files.\n"
+            "                          (defaults to the '--dir' option directory.)\n"
+            "\n"
+            "--tagging=<filename>      The name of the XML file containing the tagging rules\n"
+            "                          (defaults to 'tagging.xml' with '--dir' and\n"
+            "                           '--prefix' options or the file installed in\n"
+            "                           '" ROUTINO_DATADIR "').\n"
+            "\n"
+            "--loggable                Print progress messages suitable for logging to file.\n"
+            "--logtime                 Print the elapsed time for each processing step.\n"
+            "--logmemory               Print the max allocated/mapped memory for each step.\n"
+            "--errorlog[=<name>]       Log parsing errors to 'error.log' or the given name\n"
+            "                          (the '--dir' and '--prefix' options are applied).\n"
+            "\n"
+            "--parse-only              Parse the OSM/OSC file(s) and store the results.\n"
+            "--process-only            Process the stored results from previous option.\n"
+            "--append                  Parse the OSM file(s) and append to existing results.\n"
+            "--keep                    Keep the intermediate files after parsing & sorting.\n"
+            "--changes                 Parse the data as an OSC file and apply the changes.\n"
+            "\n"
+            "--max-iterations=<number> The number of iterations for finding super-nodes\n"
+            "                          (defaults to 5).\n"
+            "\n"
+            "--prune-none              Disable the prune options below, they are re-enabled\n"
+            "                          by adding them to the command line after this option.\n"
+            "--prune-isolated=<len>    Remove access from small disconnected segment groups\n"
+            "                          (defaults to removing groups under 500m).\n"
+            "--prune-short=<len>       Remove short segments (defaults to removing segments\n"
+            "                          up to a maximum length of 5m).\n"
+            "--prune-straight=<len>    Remove nodes in almost straight highways (defaults to\n"
+            "                          removing nodes up to 3m offset from a straight line).\n"
+            "\n"
+            "<filename.osm>, <filename.osc>, <filename.pbf>, <filename.o5m>, <filename.o5c>\n"
+            "                          The name(s) of the file(s) to read and parse.\n"
+            "                          Filenames ending '.pbf' read as PBF, filenames ending\n"
+            "                          '.o5m' or '.o5c' read as O5M/O5C, others as XML.\n"
+#if defined(USE_BZIP2) && USE_BZIP2
+            "                          Filenames ending '.bz2' will be bzip2 uncompressed.\n"
+#endif
+#if defined(USE_GZIP) && USE_GZIP
+            "                          Filenames ending '.gz' will be gzip uncompressed.\n"
+#endif
+#if defined(USE_XZ) && USE_XZ
+            "                          Filenames ending '.xz' will be xz uncompressed.\n"
+#endif
+            "\n"
+            "<transport> defaults to all but can be set to:\n"
+            "%s"
+            "\n"
+            "<highway> can be selected from:\n"
+            "%s"
+            "\n"
+            "<property> can be selected from:\n"
+            "%s",
+            TransportList(),HighwayList(),PropertyList());
+
+ exit(!detail);
+}
diff --git a/3rdparty/Routino/src/profiles.c b/3rdparty/Routino/src/profiles.c
new file mode 100644
index 0000000..a23575e
--- /dev/null
+++ b/3rdparty/Routino/src/profiles.c
@@ -0,0 +1,1119 @@
+/***************************************
+ Load the profiles from a file and the functions for handling them.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "types.h"
+#include "ways.h"
+
+#include "files.h"
+#include "profiles.h"
+#include "xmlparse.h"
+
+
+/* Local variables (re-intialised by FreeXMLProfiles() function) */
+
+/*+ The profiles that have been loaded from file. +*/
+static Profile **loaded_profiles;
+
+/*+ The number of profiles that have been loaded from file. +*/
+static int nloaded_profiles=0;
+
+
+/* The XML tag processing function prototypes */
+
+//static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding);
+//static int RoutinoProfilesType_function(const char *_tag_,int _type_);
+static int profileType_function(const char *_tag_,int _type_,const char *name,const char *transport);
+//static int speedsType_function(const char *_tag_,int _type_);
+//static int preferencesType_function(const char *_tag_,int _type_);
+//static int propertiesType_function(const char *_tag_,int _type_);
+//static int restrictionsType_function(const char *_tag_,int _type_);
+static int speedType_function(const char *_tag_,int _type_,const char *highway,const char *kph);
+static int preferenceType_function(const char *_tag_,int _type_,const char *highway,const char *percent);
+static int propertyType_function(const char *_tag_,int _type_,const char *type,const char *percent);
+static int onewayType_function(const char *_tag_,int _type_,const char *obey);
+static int turnsType_function(const char *_tag_,int _type_,const char *obey);
+static int weightType_function(const char *_tag_,int _type_,const char *limit);
+static int heightType_function(const char *_tag_,int _type_,const char *limit);
+static int widthType_function(const char *_tag_,int _type_,const char *limit);
+static int lengthType_function(const char *_tag_,int _type_,const char *limit);
+
+
+/* The XML tag definitions (forward declarations) */
+
+static const xmltag xmlDeclaration_tag;
+static const xmltag RoutinoProfilesType_tag;
+static const xmltag profileType_tag;
+static const xmltag speedsType_tag;
+static const xmltag preferencesType_tag;
+static const xmltag propertiesType_tag;
+static const xmltag restrictionsType_tag;
+static const xmltag speedType_tag;
+static const xmltag preferenceType_tag;
+static const xmltag propertyType_tag;
+static const xmltag onewayType_tag;
+static const xmltag turnsType_tag;
+static const xmltag weightType_tag;
+static const xmltag heightType_tag;
+static const xmltag widthType_tag;
+static const xmltag lengthType_tag;
+
+
+/* The XML tag definition values */
+
+/*+ The complete set of tags at the top level. +*/
+static const xmltag * const xml_toplevel_tags[]={&xmlDeclaration_tag,&RoutinoProfilesType_tag,NULL};
+
+/*+ The xmlDeclaration type tag. +*/
+static const xmltag xmlDeclaration_tag=
+              {"xml",
+               2, {"version","encoding"},
+               NULL,
+               {NULL}};
+
+/*+ The RoutinoProfilesType type tag. +*/
+static const xmltag RoutinoProfilesType_tag=
+              {"routino-profiles",
+               0, {NULL},
+               NULL,
+               {&profileType_tag,NULL}};
+
+/*+ The profileType type tag. +*/
+static const xmltag profileType_tag=
+              {"profile",
+               2, {"name","transport"},
+               profileType_function,
+               {&speedsType_tag,&preferencesType_tag,&propertiesType_tag,&restrictionsType_tag,NULL}};
+
+/*+ The speedsType type tag. +*/
+static const xmltag speedsType_tag=
+              {"speeds",
+               0, {NULL},
+               NULL,
+               {&speedType_tag,NULL}};
+
+/*+ The preferencesType type tag. +*/
+static const xmltag preferencesType_tag=
+              {"preferences",
+               0, {NULL},
+               NULL,
+               {&preferenceType_tag,NULL}};
+
+/*+ The propertiesType type tag. +*/
+static const xmltag propertiesType_tag=
+              {"properties",
+               0, {NULL},
+               NULL,
+               {&propertyType_tag,NULL}};
+
+/*+ The restrictionsType type tag. +*/
+static const xmltag restrictionsType_tag=
+              {"restrictions",
+               0, {NULL},
+               NULL,
+               {&onewayType_tag,&turnsType_tag,&weightType_tag,&heightType_tag,&widthType_tag,&lengthType_tag,NULL}};
+
+/*+ The speedType type tag. +*/
+static const xmltag speedType_tag=
+              {"speed",
+               2, {"highway","kph"},
+               speedType_function,
+               {NULL}};
+
+/*+ The preferenceType type tag. +*/
+static const xmltag preferenceType_tag=
+              {"preference",
+               2, {"highway","percent"},
+               preferenceType_function,
+               {NULL}};
+
+/*+ The propertyType type tag. +*/
+static const xmltag propertyType_tag=
+              {"property",
+               2, {"type","percent"},
+               propertyType_function,
+               {NULL}};
+
+/*+ The onewayType type tag. +*/
+static const xmltag onewayType_tag=
+              {"oneway",
+               1, {"obey"},
+               onewayType_function,
+               {NULL}};
+
+/*+ The turnsType type tag. +*/
+static const xmltag turnsType_tag=
+              {"turns",
+               1, {"obey"},
+               turnsType_function,
+               {NULL}};
+
+/*+ The weightType type tag. +*/
+static const xmltag weightType_tag=
+              {"weight",
+               1, {"limit"},
+               weightType_function,
+               {NULL}};
+
+/*+ The heightType type tag. +*/
+static const xmltag heightType_tag=
+              {"height",
+               1, {"limit"},
+               heightType_function,
+               {NULL}};
+
+/*+ The widthType type tag. +*/
+static const xmltag widthType_tag=
+              {"width",
+               1, {"limit"},
+               widthType_function,
+               {NULL}};
+
+/*+ The lengthType type tag. +*/
+static const xmltag lengthType_tag=
+              {"length",
+               1, {"limit"},
+               lengthType_function,
+               {NULL}};
+
+
+/* The XML tag processing functions */
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the XML declaration is seen
+
+  int xmlDeclaration_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *version The contents of the 'version' attribute (or NULL if not defined).
+
+  const char *encoding The contents of the 'encoding' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+//static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding)
+//{
+// return(0);
+//}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the RoutinoProfilesType XSD type is seen
+
+  int RoutinoProfilesType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+//static int RoutinoProfilesType_function(const char *_tag_,int _type_)
+//{
+// return(0);
+//}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the profileType XSD type is seen
+
+  int profileType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *name The contents of the 'name' attribute (or NULL if not defined).
+
+  const char *transport The contents of the 'transport' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int profileType_function(const char *_tag_,int _type_,const char *name,const char *transport)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    Transport transporttype;
+    int i;
+
+    XMLPARSE_ASSERT_STRING(_tag_,name);
+    XMLPARSE_ASSERT_STRING(_tag_,transport);
+
+    for(i=0;i<nloaded_profiles;i++)
+       if(!strcmp(name,loaded_profiles[i]->name))
+          XMLPARSE_MESSAGE(_tag_,"profile name must be unique");
+
+    transporttype=TransportType(transport);
+
+    if(transporttype==Transport_None)
+       XMLPARSE_INVALID(_tag_,transport);
+
+    if((nloaded_profiles%16)==0)
+       loaded_profiles=(Profile**)realloc((void*)loaded_profiles,(nloaded_profiles+16)*sizeof(Profile*));
+
+    nloaded_profiles++;
+
+    loaded_profiles[nloaded_profiles-1]=(Profile*)calloc(1,sizeof(Profile));
+
+    loaded_profiles[nloaded_profiles-1]->name=strcpy(malloc(strlen(name)+1),name);
+    loaded_profiles[nloaded_profiles-1]->transport=transporttype;
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the speedsType XSD type is seen
+
+  int speedsType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+//static int speedsType_function(const char *_tag_,int _type_)
+//{
+// return(0);
+//}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the preferencesType XSD type is seen
+
+  int preferencesType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+//static int preferencesType_function(const char *_tag_,int _type_)
+//{
+// return(0);
+//}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the propertiesType XSD type is seen
+
+  int propertiesType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+//static int propertiesType_function(const char *_tag_,int _type_)
+//{
+// return(0);
+//}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the restrictionsType XSD type is seen
+
+  int restrictionsType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+//static int restrictionsType_function(const char *_tag_,int _type_)
+//{
+// return(0);
+//}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the speedType XSD type is seen
+
+  int speedType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *highway The contents of the 'highway' attribute (or NULL if not defined).
+
+  const char *kph The contents of the 'kph' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int speedType_function(const char *_tag_,int _type_,const char *highway,const char *kph)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    double speed;
+    Highway highwaytype;
+
+    XMLPARSE_ASSERT_STRING(_tag_,highway);
+
+    highwaytype=HighwayType(highway);
+
+    if(highwaytype==Highway_None)
+       XMLPARSE_INVALID(_tag_,highway);
+
+    XMLPARSE_ASSERT_FLOATING(_tag_,kph); speed=atof(kph);
+
+    loaded_profiles[nloaded_profiles-1]->speed[highwaytype]=kph_to_speed(speed);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the preferenceType XSD type is seen
+
+  int preferenceType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *highway The contents of the 'highway' attribute (or NULL if not defined).
+
+  const char *percent The contents of the 'percent' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int preferenceType_function(const char *_tag_,int _type_,const char *highway,const char *percent)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    Highway highwaytype;
+    double p;
+
+    XMLPARSE_ASSERT_STRING(_tag_,highway);
+
+    highwaytype=HighwayType(highway);
+
+    if(highwaytype==Highway_None)
+       XMLPARSE_INVALID(_tag_,highway);
+
+    XMLPARSE_ASSERT_FLOATING(_tag_,percent); p=atof(percent);
+
+    loaded_profiles[nloaded_profiles-1]->highway[highwaytype]=(score_t)p;
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the propertyType XSD type is seen
+
+  int propertyType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *type The contents of the 'type' attribute (or NULL if not defined).
+
+  const char *percent The contents of the 'percent' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int propertyType_function(const char *_tag_,int _type_,const char *type,const char *percent)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    Property property;
+    double p;
+
+    XMLPARSE_ASSERT_STRING(_tag_,type);
+
+    property=PropertyType(type);
+
+    if(property==Property_None)
+       XMLPARSE_INVALID(_tag_,type);
+
+    XMLPARSE_ASSERT_FLOATING(_tag_,percent); p=atof(percent);
+
+    loaded_profiles[nloaded_profiles-1]->props_yes[property]=(score_t)p;
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the onewayType XSD type is seen
+
+  int onewayType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *obey The contents of the 'obey' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int onewayType_function(const char *_tag_,int _type_,const char *obey)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    int o;
+
+    XMLPARSE_ASSERT_INTEGER(_tag_,obey); o=atoi(obey);
+
+    loaded_profiles[nloaded_profiles-1]->oneway=!!o;
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the turnsType XSD type is seen
+
+  int turnsType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *obey The contents of the 'obey' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int turnsType_function(const char *_tag_,int _type_,const char *obey)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    int o;
+
+    XMLPARSE_ASSERT_INTEGER(_tag_,obey); o=atoi(obey);
+
+    loaded_profiles[nloaded_profiles-1]->turns=!!o;
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the weightType XSD type is seen
+
+  int weightType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *limit The contents of the 'limit' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int weightType_function(const char *_tag_,int _type_,const char *limit)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    double l;
+
+    XMLPARSE_ASSERT_FLOATING(_tag_,limit); l=atof(limit);
+
+    loaded_profiles[nloaded_profiles-1]->weight=tonnes_to_weight(l);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the heightType XSD type is seen
+
+  int heightType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *limit The contents of the 'limit' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int heightType_function(const char *_tag_,int _type_,const char *limit)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    double l;
+
+    XMLPARSE_ASSERT_FLOATING(_tag_,limit); l=atof(limit);
+
+    loaded_profiles[nloaded_profiles-1]->height=metres_to_height(l);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the widthType XSD type is seen
+
+  int widthType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *limit The contents of the 'limit' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int widthType_function(const char *_tag_,int _type_,const char *limit)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    double l;
+
+    XMLPARSE_ASSERT_FLOATING(_tag_,limit); l=atof(limit);
+
+    loaded_profiles[nloaded_profiles-1]->width=metres_to_width(l);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the lengthType XSD type is seen
+
+  int lengthType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *limit The contents of the 'limit' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int lengthType_function(const char *_tag_,int _type_,const char *limit)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    double l;
+
+    XMLPARSE_ASSERT_FLOATING(_tag_,limit); l=atof(limit);
+
+    loaded_profiles[nloaded_profiles-1]->length=metres_to_length(l);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The XML profile parser.
+
+  int ParseXMLProfiles Returns 0 if OK or something else in case of an error.
+
+  const char *filename The name of the file to read.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int ParseXMLProfiles(const char *filename)
+{
+ int fd;
+ int retval;
+
+ if(!ExistsFile(filename))
+   {
+#ifndef LIBROUTINO
+    fprintf(stderr,"Error: Specified profiles file '%s' does not exist.\n",filename);
+#endif
+    return(1);
+   }
+
+ fd=OpenFile(filename);
+
+ retval=ParseXML(fd,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_ERRNONAME);
+
+ CloseFile(fd);
+
+ if(retval)
+   {
+    FreeXMLProfiles();
+
+    return(1);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Free the memory allocated when reading the profiles.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FreeXMLProfiles(void)
+{
+ int i;
+
+ if(!loaded_profiles)
+    return;
+
+ for(i=0;i<nloaded_profiles;i++)
+   {
+    if(loaded_profiles[i]->name)
+       free(loaded_profiles[i]->name);
+
+    free(loaded_profiles[i]);
+   }
+
+ free(loaded_profiles);
+
+ loaded_profiles=NULL;
+ nloaded_profiles=0;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Get a named profile.
+
+  Profile *GetProfile Returns a pointer to the profile.
+
+  const char *name The name of the profile.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Profile *GetProfile(const char *name)
+{
+ int i;
+
+ for(i=0;i<nloaded_profiles;i++)
+    if(!strcmp(loaded_profiles[i]->name,name))
+       return(loaded_profiles[i]);
+
+ return(NULL);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Update a profile with the highway preference scaling factors.
+
+  int UpdateProfile Returns 1 in case of a problem.
+
+  Profile *profile The profile to be updated.
+
+  Ways *ways The set of ways to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int UpdateProfile(Profile *profile,Ways *ways)
+{
+ score_t hmax=0;
+ int i;
+
+ /* Fix up the allowed transport types. */
+
+ profile->allow=TRANSPORTS(profile->transport);
+
+ if(!(profile->allow & ways->file.allow))
+    return(1);
+
+ /* Normalise the highway preferences into the range ~0 -> 1 */
+
+ for(i=1;i<Highway_Count;i++)
+   {
+    if(profile->highway[i]<0)
+       profile->highway[i]=0;
+
+    if(profile->highway[i]>hmax)
+       hmax=profile->highway[i];
+   }
+
+ if(hmax==0)
+    return(1);
+
+ for(i=1;i<Highway_Count;i++)
+   {
+    profile->highway[i]/=hmax;
+
+    if(profile->highway[i]<0.0001f)
+       profile->highway[i]=0.0001f;
+   }
+
+ /* Normalise the property preferences into the range ~0 -> 1 */
+
+ for(i=1;i<Property_Count;i++)
+   {
+    if(profile->props_yes[i]<0)
+       profile->props_yes[i]=0;
+
+    if(profile->props_yes[i]>100)
+       profile->props_yes[i]=100;
+
+    profile->props_yes[i]/=100;
+    profile->props_no [i] =1-profile->props_yes[i];
+
+    /* Squash the properties; selecting 60% preference without the sqrt() allows
+       routes 50% longer on highways with the property compared to ones without.
+       With the sqrt() function the ratio is only 22% allowing finer control. */
+
+    profile->props_yes[i]=(score_t)sqrt(profile->props_yes[i]);
+    profile->props_no [i]=(score_t)sqrt(profile->props_no[i] );
+
+    if(profile->props_yes[i]<0.01f)
+       profile->props_yes[i]=0.01f;
+
+    if(profile->props_no[i]<0.01f)
+       profile->props_no[i]=0.01f;
+   }
+
+ /* Find the fastest preferred speed */
+
+ profile->max_speed=0;
+
+ for(i=1;i<Highway_Count;i++)
+    if(profile->speed[i]>profile->max_speed)
+       profile->max_speed=profile->speed[i];
+
+ if(profile->max_speed==0)
+    return(1);
+
+ /* Find the most preferred property combination */
+
+ profile->max_pref=1; /* since highway prefs were normalised to 1 */
+
+ for(i=1;i<Property_Count;i++)
+    if(ways->file.props & PROPERTIES(i))
+      {
+       if(profile->props_yes[i]>profile->props_no[i])
+          profile->max_pref*=profile->props_yes[i];
+       else
+          profile->max_pref*=profile->props_no[i];
+      }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out a profile.
+
+  const Profile *profile The profile to print.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void PrintProfile(const Profile *profile)
+{
+ int i;
+
+ printf("Profile\n=======\n");
+
+ printf("\n");
+
+ printf("Transport: %s\n",TransportName(profile->transport));
+
+ printf("\n");
+
+ for(i=1;i<Highway_Count;i++)
+    printf("Highway %-12s: %3d%%\n",HighwayName(i),(int)profile->highway[i]);
+
+ printf("\n");
+
+ for(i=1;i<Highway_Count;i++)
+    if(profile->highway[i])
+       printf("Speed on %-12s: %3d km/h / %2.0f mph\n",HighwayName(i),profile->speed[i],(double)profile->speed[i]/1.6);
+
+ printf("\n");
+
+ for(i=1;i<Property_Count;i++)
+    printf("Highway property %-12s: %3d%%\n",PropertyName(i),(int)profile->props_yes[i]);
+
+ printf("\n");
+
+ printf("Obey one-way  : %s\n",profile->oneway?"yes":"no");
+ printf("Obey turns    : %s\n",profile->turns?"yes":"no");
+ printf("Minimum weight: %.1f tonnes\n",weight_to_tonnes(profile->weight));
+ printf("Minimum height: %.1f metres\n",height_to_metres(profile->height));
+ printf("Minimum width : %.1f metres\n",width_to_metres(profile->width));
+ printf("Minimum length: %.1f metres\n",length_to_metres(profile->length));
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out all of the loaded profiles as XML for use as program input.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void PrintProfilesXML(void)
+{
+ int i,j;
+ char *padding="                ";
+
+ printf("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
+ printf("\n");
+
+ printf("<routino-profiles xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"routino-profiles.xsd\">\n");
+ printf("\n");
+
+ for(j=0;j<nloaded_profiles;j++)
+   {
+    printf("  <profile name=\"%s\" transport=\"%s\">\n",loaded_profiles[j]->name,TransportName(loaded_profiles[j]->transport));
+
+    printf("    <speeds>\n");
+    for(i=1;i<Highway_Count;i++)
+       printf("      <speed highway=\"%s\"%s kph=\"%d\" />\n",HighwayName(i),padding+3+strlen(HighwayName(i)),loaded_profiles[j]->speed[i]);
+    printf("    </speeds>\n");
+
+    printf("    <preferences>\n");
+    for(i=1;i<Highway_Count;i++)
+       printf("      <preference highway=\"%s\"%s percent=\"%.0f\" />\n",HighwayName(i),padding+3+strlen(HighwayName(i)),loaded_profiles[j]->highway[i]);
+    printf("    </preferences>\n");
+
+    printf("    <properties>\n");
+    for(i=1;i<Property_Count;i++)
+       printf("      <property type=\"%s\"%s percent=\"%.0f\" />\n",PropertyName(i),padding+6+strlen(PropertyName(i)),loaded_profiles[j]->props_yes[i]);
+    printf("    </properties>\n");
+
+    printf("    <restrictions>\n");
+    printf("      <oneway obey=\"%d\" /> \n",loaded_profiles[j]->oneway);
+    printf("      <turns  obey=\"%d\" /> \n",loaded_profiles[j]->turns);
+    printf("      <weight limit=\"%.1f\" />\n",weight_to_tonnes(loaded_profiles[j]->weight));
+    printf("      <height limit=\"%.1f\" />\n",height_to_metres(loaded_profiles[j]->height));
+    printf("      <width  limit=\"%.1f\" />\n",width_to_metres(loaded_profiles[j]->width));
+    printf("      <length limit=\"%.1f\" />\n",length_to_metres(loaded_profiles[j]->length));
+    printf("    </restrictions>\n");
+
+    printf("  </profile>\n");
+    printf("\n");
+   }
+
+ printf("</routino-profiles>\n");
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out all of the loaded profiles as JavaScript Object Notation for use in a web page.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void PrintProfilesJSON(void)
+{
+ int i,j;
+
+ printf("var routino={ // contains all default Routino options (generated using \"--help-profile-json\").\n");
+ printf("\n");
+
+ printf("  // Default transport type\n");
+ printf("  transport: \"motorcar\",\n");
+ printf("\n");
+
+ printf("  // Transport types\n");
+ printf("  transports: { ");
+ for(j=0;j<nloaded_profiles;j++)
+    printf("%s%s: %d",j==0?"":", ",TransportName(loaded_profiles[j]->transport),j+1);
+ printf(" },\n");
+ printf("\n");
+
+ printf("  // Highway types\n");
+ printf("  highways: { ");
+ for(i=1;i<Highway_Count;i++)
+    printf("%s%s: %d",i==1?"":", ",HighwayName(i),i);
+ printf(" },\n");
+ printf("\n");
+
+ printf("  // Property types\n");
+ printf("  properties: { ");
+ for(i=1;i<Property_Count;i++)
+    printf("%s%s: %d",i==1?"":", ",PropertyName(i),i);
+ printf(" },\n");
+ printf("\n");
+
+ printf("  // Restriction types\n");
+ printf("  restrictions: { oneway: 1, turns: 2, weight: 3, height: 4, width: 5, length: 6 },\n");
+ printf("\n");
+
+ printf("  // Allowed highways\n");
+ printf("  profile_highway: {\n");
+ for(i=1;i<Highway_Count;i++)
+   {
+    printf("    %12s: { ",HighwayName(i));
+    for(j=0;j<nloaded_profiles;j++)
+       printf("%s%s: %3d",j==0?"":", ",TransportName(loaded_profiles[j]->transport),(int)loaded_profiles[j]->highway[i]);
+    printf(" }%s\n",i==(Highway_Count-1)?"":",");
+   }
+ printf("     },\n");
+ printf("\n");
+
+ printf("  // Speed limits\n");
+ printf("  profile_speed: {\n");
+ for(i=1;i<Highway_Count;i++)
+   {
+    printf("    %12s: { ",HighwayName(i));
+    for(j=0;j<nloaded_profiles;j++)
+       printf("%s%s: %3d",j==0?"":", ",TransportName(loaded_profiles[j]->transport),loaded_profiles[j]->speed[i]);
+    printf(" }%s\n",i==(Highway_Count-1)?"":",");
+   }
+ printf("     },\n");
+ printf("\n");
+
+ printf("  // Highway properties\n");
+ printf("  profile_property: {\n");
+ for(i=1;i<Property_Count;i++)
+   {
+    printf("    %13s: { ",PropertyName(i));
+    for(j=0;j<nloaded_profiles;j++)
+       printf("%s%s: %3d",j==0?"":", ",TransportName(loaded_profiles[j]->transport),(int)loaded_profiles[j]->props_yes[i]);
+    printf(" }%s\n",i==(Property_Count-1)?"":",");
+   }
+ printf("     },\n");
+ printf("\n");
+
+ printf("  // Restrictions\n");
+ printf("  profile_restrictions: {\n");
+ printf("    %12s: { ","oneway");
+ for(j=0;j<nloaded_profiles;j++)
+    printf("%s%s: %4d",j==0?"":", ",TransportName(loaded_profiles[j]->transport),loaded_profiles[j]->oneway);
+ printf(" },\n");
+ printf("    %12s: { ","turns");
+ for(j=0;j<nloaded_profiles;j++)
+    printf("%s%s: %4d",j==0?"":", ",TransportName(loaded_profiles[j]->transport),loaded_profiles[j]->turns);
+ printf(" },\n");
+ printf("    %12s: { ","weight");
+ for(j=0;j<nloaded_profiles;j++)
+    printf("%s%s: %4.1f",j==0?"":", ",TransportName(loaded_profiles[j]->transport),weight_to_tonnes(loaded_profiles[j]->weight));
+ printf(" },\n");
+ printf("    %12s: { ","height");
+ for(j=0;j<nloaded_profiles;j++)
+    printf("%s%s: %4.1f",j==0?"":", ",TransportName(loaded_profiles[j]->transport),height_to_metres(loaded_profiles[j]->height));
+ printf(" },\n");
+ printf("    %12s: { ","width");
+ for(j=0;j<nloaded_profiles;j++)
+    printf("%s%s: %4.1f",j==0?"":", ",TransportName(loaded_profiles[j]->transport),width_to_metres(loaded_profiles[j]->width));
+ printf(" },\n");
+ printf("    %12s: { ","length");
+ for(j=0;j<nloaded_profiles;j++)
+    printf("%s%s: %4.1f",j==0?"":", ",TransportName(loaded_profiles[j]->transport),length_to_metres(loaded_profiles[j]->length));
+ printf(" }\n");
+ printf("     }\n");
+ printf("\n");
+
+ printf("}; // end of routino variable\n");
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out all of the loaded profiles as Perl for use in a web CGI.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void PrintProfilesPerl(void)
+{
+ int i,j;
+
+ printf("$routino={ # contains all default Routino options (generated using \"--help-profile-perl\").\n");
+ printf("\n");
+
+ printf("  # Default transport type\n");
+ printf("  transport => \"motorcar\",\n");
+ printf("\n");
+
+ printf("  # Transport types\n");
+ printf("  transports => { ");
+ for(j=0;j<nloaded_profiles;j++)
+    printf("%s%s => %d",j==0?"":", ",TransportName(loaded_profiles[j]->transport),j+1);
+ printf(" },\n");
+ printf("\n");
+
+ printf("  # Highway types\n");
+ printf("  highways => { ");
+ for(i=1;i<Highway_Count;i++)
+    printf("%s%s => %d",i==1?"":", ",HighwayName(i),i);
+ printf(" },\n");
+ printf("\n");
+
+ printf("  # Property types\n");
+ printf("  properties => { ");
+ for(i=1;i<Property_Count;i++)
+    printf("%s%s => %d",i==1?"":", ",PropertyName(i),i);
+ printf(" },\n");
+ printf("\n");
+
+ printf("  # Restriction types\n");
+ printf("  restrictions => { oneway => 1, turns => 2, weight => 3, height => 4, width => 5, length => 6 },\n");
+ printf("\n");
+
+ printf("  # Allowed highways\n");
+ printf("  profile_highway => {\n");
+ for(i=1;i<Highway_Count;i++)
+   {
+    printf("  %12s => {",HighwayName(i));
+    for(j=0;j<nloaded_profiles;j++)
+       printf("%s %s => %3d",j==0?"":", ",TransportName(loaded_profiles[j]->transport),(int)loaded_profiles[j]->highway[i]);
+    printf(" }%s\n",i==(Highway_Count-1)?"":",");
+   }
+ printf("     },\n");
+ printf("\n");
+
+ printf("  # Speed limits\n");
+ printf("  profile_speed => {\n");
+ for(i=1;i<Highway_Count;i++)
+   {
+    printf("  %12s => {",HighwayName(i));
+    for(j=0;j<nloaded_profiles;j++)
+       printf("%s %s => %3d",j==0?"":", ",TransportName(loaded_profiles[j]->transport),loaded_profiles[j]->speed[i]);
+    printf(" }%s\n",i==(Highway_Count-1)?"":",");
+   }
+ printf("     },\n");
+ printf("\n");
+
+ printf("  # Highway properties\n");
+ printf("  profile_property => {\n");
+ for(i=1;i<Property_Count;i++)
+   {
+    printf("  %13s => {",PropertyName(i));
+    for(j=0;j<nloaded_profiles;j++)
+       printf("%s %s => %3d",j==0?"":", ",TransportName(loaded_profiles[j]->transport),(int)loaded_profiles[j]->props_yes[i]);
+    printf(" }%s\n",i==(Property_Count-1)?"":",");
+   }
+ printf("     },\n");
+ printf("\n");
+
+ printf("  # Restrictions\n");
+ printf("  profile_restrictions => {\n");
+ printf("    %12s => {","oneway");
+ for(j=0;j<nloaded_profiles;j++)
+    printf("%s %s => %4d",j==0?"":", ",TransportName(loaded_profiles[j]->transport),loaded_profiles[j]->oneway);
+ printf(" },\n");
+ printf("    %12s => {","turns");
+ for(j=0;j<nloaded_profiles;j++)
+    printf("%s %s => %4d",j==0?"":", ",TransportName(loaded_profiles[j]->transport),loaded_profiles[j]->turns);
+ printf(" },\n");
+ printf("    %12s => {","weight");
+ for(j=0;j<nloaded_profiles;j++)
+    printf("%s %s => %4.1f",j==0?"":", ",TransportName(loaded_profiles[j]->transport),weight_to_tonnes(loaded_profiles[j]->weight));
+ printf(" },\n");
+ printf("    %12s => {","height");
+ for(j=0;j<nloaded_profiles;j++)
+    printf("%s %s => %4.1f",j==0?"":", ",TransportName(loaded_profiles[j]->transport),height_to_metres(loaded_profiles[j]->height));
+ printf(" },\n");
+ printf("    %12s => {","width");
+ for(j=0;j<nloaded_profiles;j++)
+    printf("%s %s => %4.1f",j==0?"":", ",TransportName(loaded_profiles[j]->transport),width_to_metres(loaded_profiles[j]->width));
+ printf(" },\n");
+ printf("    %12s => {","length");
+ for(j=0;j<nloaded_profiles;j++)
+    printf("%s %s => %4.1f",j==0?"":", ",TransportName(loaded_profiles[j]->transport),length_to_metres(loaded_profiles[j]->length));
+ printf(" }\n");
+ printf("     }\n");
+ printf("\n");
+
+ printf("}; # end of routino variable\n");
+}
diff --git a/3rdparty/Routino/src/profiles.h b/3rdparty/Routino/src/profiles.h
new file mode 100644
index 0000000..319fe80
--- /dev/null
+++ b/3rdparty/Routino/src/profiles.h
@@ -0,0 +1,80 @@
+/***************************************
+ A header file for the profiles.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef PROFILES_H
+#define PROFILES_H    /*+ To stop multiple inclusions. +*/
+
+#include "types.h"
+
+
+/* Data structures */
+
+/*+ A data structure to hold a transport type profile. +*/
+typedef struct _Profile
+{
+ char        *name;                      /*+ The name of the profile. +*/
+
+ Transport    transport;                 /*+ The type of transport. +*/
+
+ transports_t allow;                     /*+ The type of transport expressed as a bitmask. +*/
+
+ score_t      highway[Highway_Count];    /*+ A floating point preference for travel on the highway. +*/
+ score_t      max_pref;                  /*+ The maximum preference for any highway type. +*/
+
+ speed_t      speed[Highway_Count];      /*+ The maximum speed on each type of highway. +*/
+ speed_t      max_speed;                 /*+ The maximum speed for any highway type. +*/
+
+ score_t      props_yes[Property_Count]; /*+ A floating point preference for ways with this attribute. +*/
+ score_t      props_no [Property_Count]; /*+ A floating point preference for ways without this attribute. +*/
+
+ int          oneway;                    /*+ A flag to indicate if one-way restrictions apply. +*/
+ int          turns;                     /*+ A flag to indicate if turn restrictions apply. +*/
+
+ weight_t     weight;                    /*+ The minimum weight of the route. +*/
+
+ height_t     height;                    /*+ The minimum height of vehicles on the route. +*/
+ width_t      width;                     /*+ The minimum width of vehicles on the route. +*/
+ length_t     length;                    /*+ The minimum length of vehicles on the route. +*/
+}
+ Profile;
+
+
+/* Functions in profiles.c */
+
+int ParseXMLProfiles(const char *filename);
+
+void FreeXMLProfiles(void);
+
+Profile *GetProfile(const char *name);
+
+int UpdateProfile(Profile *profile,Ways *ways);
+
+void PrintProfile(const Profile *profile);
+
+void PrintProfilesXML(void);
+
+void PrintProfilesJSON(void);
+
+void PrintProfilesPerl(void);
+
+
+#endif /* PROFILES_H */
diff --git a/3rdparty/Routino/src/prunex.c b/3rdparty/Routino/src/prunex.c
new file mode 100644
index 0000000..140cef2
--- /dev/null
+++ b/3rdparty/Routino/src/prunex.c
@@ -0,0 +1,1497 @@
+/***************************************
+ Data pruning functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2011-2014 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+
+#include "types.h"
+#include "segments.h"
+
+#include "typesx.h"
+#include "nodesx.h"
+#include "segmentsx.h"
+#include "waysx.h"
+
+#include "prunex.h"
+
+#include "files.h"
+#include "logging.h"
+
+
+/* Global variables */
+
+/*+ The command line '--tmpdir' option or its default value. +*/
+extern char *option_tmpdirname;
+
+/* Local functions */
+
+static void prune_segment(SegmentsX *segmentsx,SegmentX *segmentx);
+static void modify_segment(SegmentsX *segmentsx,SegmentX *segmentx,index_t newnode1,index_t newnode2);
+
+static void unlink_segment_node1_refs(SegmentsX *segmentsx,SegmentX *segmentx);
+static void unlink_segment_node2_refs(SegmentsX *segmentsx,SegmentX *segmentx);
+
+static double distance(double lat1,double lon1,double lat2,double lon2);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Initialise the data structures needed for pruning.
+
+  NodesX *nodesx The set of nodes to use.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  WaysX *waysx The set of ways to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void StartPruning(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
+{
+ SegmentX segmentx;
+ index_t index=0,lastnode1=NO_NODE;
+
+ if(segmentsx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Adding Extra Segment Indexes: Segments=0");
+
+ /* Allocate the array of next segment */
+
+ segmentsx->next1=(index_t*)calloc(segmentsx->number,sizeof(index_t));
+ log_malloc(segmentsx->next1,segmentsx->number*sizeof(index_t));
+
+ logassert(segmentsx->next1,"Failed to allocate memory (try using slim mode?)"); /* Check calloc() worked */
+
+ /* Open the file read-only */
+
+ segmentsx->fd=ReOpenFileBuffered(segmentsx->filename_tmp);
+
+ /* Read the on-disk image */
+
+ while(!ReadFileBuffered(segmentsx->fd,&segmentx,sizeof(SegmentX)))
+   {
+    index_t node1=segmentx.node1;
+
+    if(index==0)
+       ;
+    else if(lastnode1==node1)
+       segmentsx->next1[index-1]=index;
+    else
+       segmentsx->next1[index-1]=NO_SEGMENT;
+
+    lastnode1=node1;
+    index++;
+
+    if(!(index%10000))
+       printf_middle("Added Extra Segment Indexes: Segments=%"Pindex_t,index);
+   }
+
+ segmentsx->next1[index-1]=NO_SEGMENT;
+
+ /* Close the file */
+
+ segmentsx->fd=CloseFileBuffered(segmentsx->fd);
+
+ /* Print the final message */
+
+ printf_last("Added Extra Segment Indexes: Segments=%"Pindex_t,segmentsx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Delete the data structures needed for pruning.
+
+  NodesX *nodesx The set of nodes to use.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  WaysX *waysx The set of ways to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FinishPruning(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
+{
+ if(segmentsx->next1)
+   {
+    log_free(segmentsx->next1);
+    free(segmentsx->next1);
+    segmentsx->next1=NULL;
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Prune out any groups of nodes and segments whose total length is less than a
+  specified minimum.
+
+  NodesX *nodesx The set of nodes to use.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  WaysX *waysx The set of ways to use.
+
+  distance_t minimum The minimum distance to keep.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void PruneIsolatedRegions(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distance_t minimum)
+{
+ WaysX *newwaysx;
+ WayX tmpwayx;
+ transport_t transport;
+ BitMask *connected,*region;
+ index_t *regionsegments,*othersegments;
+ index_t nallocregionsegments,nallocothersegments;
+
+ if(nodesx->number==0 || segmentsx->number==0)
+    return;
+
+ /* Map into memory / open the files */
+
+#if !SLIM
+ nodesx->data=MapFile(nodesx->filename_tmp);
+ segmentsx->data=MapFileWriteable(segmentsx->filename_tmp);
+ waysx->data=MapFile(waysx->filename_tmp);
+#else
+ nodesx->fd=SlimMapFile(nodesx->filename_tmp);
+ segmentsx->fd=SlimMapFileWriteable(segmentsx->filename_tmp);
+ waysx->fd=SlimMapFile(waysx->filename_tmp);
+
+ InvalidateNodeXCache(nodesx->cache);
+ InvalidateSegmentXCache(segmentsx->cache);
+ InvalidateWayXCache(waysx->cache);
+#endif
+
+ newwaysx=NewWayList(0,0);
+ CloseFileBuffered(newwaysx->fd);
+
+ newwaysx->fd=SlimMapFileWriteable(newwaysx->filename_tmp);
+
+ connected=AllocBitMask(segmentsx->number);
+ region   =AllocBitMask(segmentsx->number);
+
+ log_malloc(connected,LengthBitMask(segmentsx->number)*sizeof(BitMask));
+ log_malloc(region   ,LengthBitMask(segmentsx->number)*sizeof(BitMask));
+
+ logassert(connected,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
+ logassert(region   ,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
+
+ regionsegments=(index_t*)malloc((nallocregionsegments=1024)*sizeof(index_t));
+ othersegments =(index_t*)malloc((nallocothersegments =1024)*sizeof(index_t));
+
+ logassert(regionsegments,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
+ logassert(othersegments ,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
+
+ /* Loop through the transport types */
+
+ for(transport=Transport_None+1;transport<Transport_Count;transport++)
+   {
+    index_t i,j;
+    index_t nregions=0,npruned=0,nadjusted=0;
+    const char *transport_str=TransportName(transport);
+    transports_t transports=TRANSPORTS(transport);
+
+    if(!(waysx->allow&transports))
+       continue;
+
+    /* Print the start message */
+
+    printf_first("Pruning Isolated Regions (%s): Segments=0 Adjusted=0 Pruned=0",transport_str);
+
+    /* Loop through the segments and find the disconnected ones */
+
+    ClearAllBits(connected,segmentsx->number);
+    ClearAllBits(region   ,segmentsx->number);
+
+    for(i=0;i<segmentsx->number;i++)
+      {
+       index_t nregionsegments=0,nothersegments=0;
+       distance_t total=0;
+       SegmentX *segmentx;
+       WayX *wayx;
+
+       if(IsBitSet(connected,i))
+          goto endloop;
+
+       segmentx=LookupSegmentX(segmentsx,i,1);
+
+       if(IsPrunedSegmentX(segmentx))
+          goto endloop;
+
+       if(segmentx->way<waysx->number)
+          wayx=LookupWayX(waysx,segmentx->way,1);
+       else
+          SlimFetch(newwaysx->fd,(wayx=&tmpwayx),sizeof(WayX),(segmentx->way-waysx->number)*sizeof(WayX));
+
+       if(!(wayx->way.allow&transports))
+          goto endloop;
+
+       othersegments[nothersegments++]=i;
+       SetBit(region,i);
+
+       do
+         {
+          index_t thissegment,nodes[2];
+
+          thissegment=othersegments[--nothersegments];
+
+          if(nregionsegments==nallocregionsegments)
+             regionsegments=(index_t*)realloc(regionsegments,(nallocregionsegments+=1024)*sizeof(index_t));
+
+          regionsegments[nregionsegments++]=thissegment;
+
+          segmentx=LookupSegmentX(segmentsx,thissegment,1);
+
+          nodes[0]=segmentx->node1;
+          nodes[1]=segmentx->node2;
+          total+=DISTANCE(segmentx->distance);
+
+          for(j=0;j<2;j++)
+            {
+             NodeX *nodex=LookupNodeX(nodesx,nodes[j],1);
+
+             if(!(nodex->allow&transports))
+                continue;
+
+             segmentx=FirstSegmentX(segmentsx,nodes[j],1);
+
+             while(segmentx)
+               {
+                index_t segment=IndexSegmentX(segmentsx,segmentx);
+
+                if(segment!=thissegment)
+                  {
+                   if(segmentx->way<waysx->number)
+                      wayx=LookupWayX(waysx,segmentx->way,1);
+                   else
+                      SlimFetch(newwaysx->fd,(wayx=&tmpwayx),sizeof(WayX),(segmentx->way-waysx->number)*sizeof(WayX));
+
+                   if(wayx->way.allow&transports)
+                     {
+                      /* Already connected - finish */
+
+                      if(IsBitSet(connected,segment))
+                        {
+                         total=minimum;
+                         goto foundconnection;
+                        }
+
+                      /* Not in region - add to list */
+
+                      if(!IsBitSet(region,segment))
+                        {
+                         if(nothersegments==nallocothersegments)
+                            othersegments=(index_t*)realloc(othersegments,(nallocothersegments+=1024)*sizeof(index_t));
+
+                         othersegments[nothersegments++]=segment;
+                         SetBit(region,segment);
+                        }
+                     }
+                  }
+
+                segmentx=NextSegmentX(segmentsx,segmentx,nodes[j]);
+               }
+            }
+         }
+       while(nothersegments>0 && total<minimum);
+
+      foundconnection:
+
+       /* Prune the segments or mark them as connected */
+
+       if(total<minimum)        /* not connected - delete them */
+         {
+          nregions++;
+
+          for(j=0;j<nregionsegments;j++)
+            {
+             SegmentX *segmentx;
+             WayX *wayx,tmpwayx;
+
+             SetBit(connected,regionsegments[j]); /* not really connected, but don't need to check again */
+             ClearBit(region,regionsegments[j]);
+
+             segmentx=LookupSegmentX(segmentsx,regionsegments[j],1);
+
+             if(segmentx->way<waysx->number)
+                wayx=LookupWayX(waysx,segmentx->way,1);
+             else
+                SlimFetch(newwaysx->fd,(wayx=&tmpwayx),sizeof(WayX),(segmentx->way-waysx->number)*sizeof(WayX));
+
+             if(wayx->way.allow==transports)
+               {
+                prune_segment(segmentsx,segmentx);
+
+                npruned++;
+               }
+             else
+               {
+                if(segmentx->way<waysx->number) /* create a new way */
+                  {
+                   tmpwayx=*wayx;
+
+                   tmpwayx.way.allow&=~transports;
+
+                   segmentx->way=waysx->number+newwaysx->number;
+
+                   SlimReplace(newwaysx->fd,&tmpwayx,sizeof(WayX),(segmentx->way-waysx->number)*sizeof(WayX));
+
+                   newwaysx->number++;
+
+                   PutBackSegmentX(segmentsx,segmentx);
+                  }
+                else            /* modify the existing one */
+                  {
+                   tmpwayx.way.allow&=~transports;
+
+                   SlimReplace(newwaysx->fd,&tmpwayx,sizeof(WayX),(segmentx->way-waysx->number)*sizeof(WayX));
+                  }
+
+                nadjusted++;
+               }
+            }
+         }
+       else                     /* connected - mark as part of the main region */
+         {
+          for(j=0;j<nregionsegments;j++)
+            {
+             SetBit(connected,regionsegments[j]);
+             ClearBit(region,regionsegments[j]);
+            }
+
+          for(j=0;j<nothersegments;j++)
+            {
+             SetBit(connected,othersegments[j]);
+             ClearBit(region,othersegments[j]);
+            }
+         }
+
+      endloop:
+
+       if(!((i+1)%10000))
+          printf_middle("Pruning Isolated Regions (%s): Segments=%"Pindex_t" Adjusted=%"Pindex_t" Pruned=%"Pindex_t" (%"Pindex_t" Regions)",transport_str,i+1,nadjusted,npruned,nregions);
+      }
+
+    /* Print the final message */
+
+    printf_last("Pruned Isolated Regions (%s): Segments=%"Pindex_t" Adjusted=%"Pindex_t" Pruned=%"Pindex_t" (%"Pindex_t" Regions)",transport_str,segmentsx->number,nadjusted,npruned,nregions);
+   }
+
+ /* Unmap from memory / close the files */
+
+ log_free(region);
+ log_free(connected);
+
+ free(region);
+ free(connected);
+
+ free(regionsegments);
+ free(othersegments);
+
+#if !SLIM
+ nodesx->data=UnmapFile(nodesx->data);
+ segmentsx->data=UnmapFile(segmentsx->data);
+ waysx->data=UnmapFile(waysx->data);
+#else
+ nodesx->fd=SlimUnmapFile(nodesx->fd);
+ segmentsx->fd=SlimUnmapFile(segmentsx->fd);
+ waysx->fd=SlimUnmapFile(waysx->fd);
+#endif
+
+ SlimUnmapFile(newwaysx->fd);
+
+ waysx->number+=newwaysx->number;
+
+ waysx->fd=OpenFileBufferedAppend(waysx->filename_tmp);
+
+ newwaysx->fd=ReOpenFileBuffered(newwaysx->filename_tmp);
+
+ while(!ReadFileBuffered(newwaysx->fd,&tmpwayx,sizeof(WayX)))
+    WriteFileBuffered(waysx->fd,&tmpwayx,sizeof(WayX));
+
+ CloseFileBuffered(waysx->fd);
+ CloseFileBuffered(newwaysx->fd);
+
+ FreeWayList(newwaysx,0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Prune out any segments that are shorter than a specified minimum.
+
+  NodesX *nodesx The set of nodes to use.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  WaysX *waysx The set of ways to use.
+
+  distance_t minimum The maximum length to remove or one less than the minimum length to keep.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void PruneShortSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distance_t minimum)
+{
+ index_t i;
+ index_t nshort=0,npruned=0;
+
+ if(nodesx->number==0 || segmentsx->number==0 || waysx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Pruning Short Segments: Segments=0 Short=0 Pruned=0");
+
+ /* Map into memory / open the files */
+
+#if !SLIM
+ nodesx->data=MapFileWriteable(nodesx->filename_tmp);
+ segmentsx->data=MapFileWriteable(segmentsx->filename_tmp);
+ waysx->data=MapFile(waysx->filename_tmp);
+#else
+ nodesx->fd=SlimMapFileWriteable(nodesx->filename_tmp);
+ segmentsx->fd=SlimMapFileWriteable(segmentsx->filename_tmp);
+ waysx->fd=SlimMapFile(waysx->filename_tmp);
+
+ InvalidateNodeXCache(nodesx->cache);
+ InvalidateSegmentXCache(segmentsx->cache);
+ InvalidateWayXCache(waysx->cache);
+#endif
+
+ /* Loop through the segments and find the short ones for possible modification */
+
+ for(i=0;i<segmentsx->number;i++)
+   {
+    SegmentX *segmentx2=LookupSegmentX(segmentsx,i,2);
+
+    if(IsPrunedSegmentX(segmentx2))
+       goto endloop;
+
+    /*
+                       :
+      Initial state: ..N3 -------- N2
+                       :     S2
+
+                       :
+      Final state:   ..N3
+                       :
+
+      = OR =
+
+                       :                               :
+      Initial state: ..N1 -------- N2 ---- N3 -------- N4..
+                       :     S1        S2        S3    :
+
+                       :                               :
+      Final state:   ..N1 ------------ N3 ------------ N4..
+                       :       S1               S3     :
+
+      Not if N1 is the same as N4.
+      Must not delete N2 (or N3) if S2 (or S3) has different one-way properties from S1.
+      Must not delete N2 (or N3) if S2 (or S3) has different highway properties from S1.
+      Must combine N2, S2 and N3 disallowed transports into new N3.
+      Must not delete N2 (or N3) if it is a mini-roundabout.
+      Must not delete N2 (or N3) if it is involved in a turn restriction.
+
+      = OR =
+
+                       :                   :
+      Initial state: ..N1 -------- N2 ---- N3..
+                       :     S1        S2  :
+
+                       :               :
+      Final state:   ..N1 ------------ N3..
+                       :       S1      :
+
+      Not if N1 is the same as N3.
+      Not if S1 has different one-way properties from S2.
+      Not if S1 has different highway properties from S2.
+      Not if N2 disallows transports allowed on S1 and S2.
+      Not if N2 is a mini-roundabout.
+      Not if N2 is involved in a turn restriction.
+     */
+
+    if(DISTANCE(segmentx2->distance)<=minimum)
+      {
+       index_t node1=NO_NODE,node2,node3,node4=NO_NODE;
+       index_t segment1=NO_SEGMENT,segment2=i,segment3=NO_SEGMENT;
+       SegmentX *segmentx;
+       int segcount2=0,segcount3=0;
+
+       nshort++;
+
+       node2=segmentx2->node1;
+       node3=segmentx2->node2;
+
+       /* Count the segments connected to N2 */
+
+       segmentx=FirstSegmentX(segmentsx,node2,4);
+
+       while(segmentx)
+         {
+          segcount2++;
+
+          if(segment1==NO_SEGMENT)
+            {
+             index_t segment=IndexSegmentX(segmentsx,segmentx);
+
+             if(segment!=segment2)
+               {
+                segment1=segment;
+                node1=OtherNode(segmentx,node2);
+               }
+            }
+          else if(segcount2>2)
+             break;
+
+          segmentx=NextSegmentX(segmentsx,segmentx,node2);
+         }
+
+       /* Count the segments connected to N3 */
+
+       segmentx=FirstSegmentX(segmentsx,node3,4);
+
+       while(segmentx)
+         {
+          segcount3++;
+
+          if(segment3==NO_SEGMENT)
+            {
+             index_t segment=IndexSegmentX(segmentsx,segmentx);
+
+             if(segment!=segment2)
+               {
+                segment3=segment;
+                node4=OtherNode(segmentx,node3);
+               }
+            }
+          else if(segcount3>2)
+             break;
+
+          segmentx=NextSegmentX(segmentsx,segmentx,node3);
+         }
+
+       /* Check which case we are handling (and canonicalise) */
+
+       if(segcount2>2 && segcount3>2) /* none of the cases in diagram - too complicated */
+         {
+          goto endloop;
+         }
+       else if(segcount2==1 || segcount3==1) /* first case in diagram - prune segment */
+         {
+          prune_segment(segmentsx,segmentx2);
+         }
+       else if(segcount2==2 && segcount3==2) /* second case in diagram - modify one segment and prune segment */
+         {
+          SegmentX *segmentx1,*segmentx3;
+          WayX *wayx1,*wayx2,*wayx3;
+          NodeX *nodex2,*nodex3,*newnodex;
+          index_t newnode;
+          int join12=1,join23=1,same13=1;
+
+          /* Check if pruning would collapse a loop */
+
+          if(node1==node4)
+             goto endloop;
+
+          /* Check if allowed due to one-way properties */
+
+          segmentx1=LookupSegmentX(segmentsx,segment1,1);
+          segmentx3=LookupSegmentX(segmentsx,segment3,3);
+
+          if(!IsOneway(segmentx1) && !IsOneway(segmentx2))
+             ;
+          else if(IsOneway(segmentx1) && IsOneway(segmentx2))
+            {
+             if(IsOnewayTo(segmentx1,node2) && !IsOnewayFrom(segmentx2,node2)) /* S1 is one-way but S2 doesn't continue */
+                join12=0;
+
+             if(IsOnewayFrom(segmentx1,node2) && !IsOnewayTo(segmentx2,node2)) /* S1 is one-way but S2 doesn't continue */
+                join12=0;
+            }
+          else
+             join12=0;
+
+          if(!IsOneway(segmentx3) && !IsOneway(segmentx2))
+             ;
+          else if(IsOneway(segmentx3) && IsOneway(segmentx2))
+            {
+             if(IsOnewayTo(segmentx3,node3) && !IsOnewayFrom(segmentx2,node3)) /* S3 is one-way but S2 doesn't continue */
+                join23=0;
+
+             if(IsOnewayFrom(segmentx3,node3) && !IsOnewayTo(segmentx2,node3)) /* S3 is one-way but S2 doesn't continue */
+                join23=0;
+            }
+          else
+             join23=0;
+
+          if(!join12 && !join23)
+             goto endloop;
+
+          /* Check if allowed due to highway properties */
+
+          wayx1=LookupWayX(waysx,segmentx1->way,1);
+          wayx2=LookupWayX(waysx,segmentx2->way,2);
+          wayx3=LookupWayX(waysx,segmentx3->way,3);
+
+          if(WaysCompare(&wayx1->way,&wayx2->way))
+             join12=0;
+
+          if(WaysCompare(&wayx3->way,&wayx2->way))
+             join23=0;
+
+          if(!join12 && !join23)
+             goto endloop;
+
+          /* Check if allowed due to mini-roundabout and turn restriction */
+
+          nodex2=LookupNodeX(nodesx,node2,2);
+          nodex3=LookupNodeX(nodesx,node3,3);
+
+          if(nodex2->flags&NODE_MINIRNDBT)
+             join12=0;
+
+          if(nodex3->flags&NODE_MINIRNDBT)
+             join23=0;
+
+          if(!join12 && !join23)
+             goto endloop;
+
+          if(nodex2->flags&NODE_TURNRSTRCT2 || nodex2->flags&NODE_TURNRSTRCT)
+             join12=0;
+
+          if(nodex3->flags&NODE_TURNRSTRCT2 || nodex3->flags&NODE_TURNRSTRCT)
+             join23=0;
+
+          if(!join12 && !join23)
+             goto endloop;
+
+          /* New node properties */
+
+          if(join12)
+            {
+             newnode=node3;
+             newnodex=nodex3;
+            }
+          else /* if(join23) */
+            {
+             newnode=node2;
+             newnodex=nodex2;
+            }
+
+          newnodex->allow=nodex2->allow&nodex3->allow; /* combine the restrictions of the two nodes */
+          newnodex->allow&=~((~wayx2->way.allow)&wayx3->way.allow); /* disallow anything blocked by segment2 */
+          newnodex->allow&=~((~wayx2->way.allow)&wayx1->way.allow); /* disallow anything blocked by segment2 */
+
+          newnodex->latitude =(nodex2->latitude +nodex3->latitude )/2;
+          newnodex->longitude=(nodex2->longitude+nodex3->longitude)/2;
+
+          PutBackNodeX(nodesx,newnodex);
+
+          /* Modify segments - update the distances */
+
+          if(!IsOneway(segmentx1) && !IsOneway(segmentx3))
+             ;
+          else if(IsOneway(segmentx1) && IsOneway(segmentx3))
+            {
+             if(IsOnewayTo(segmentx1,node3) && !IsOnewayFrom(segmentx3,node3)) /* S1 is one-way but S3 doesn't continue */
+                same13=0;
+
+             if(IsOnewayFrom(segmentx1,node3) && !IsOnewayTo(segmentx3,node3)) /* S1 is one-way but S3 doesn't continue */
+                same13=0;
+            }
+          else
+             same13=0;
+
+          if(WaysCompare(&wayx1->way,&wayx3->way))
+             same13=0;
+
+          if(same13)
+            {
+             segmentx1->distance+=DISTANCE(segmentx2->distance)/2;
+             segmentx3->distance+=DISTANCE(segmentx2->distance)-DISTANCE(segmentx2->distance)/2;
+            }
+          else if(join12)
+             segmentx1->distance+=DISTANCE(segmentx2->distance);
+          else /* if(join23) */
+             segmentx3->distance+=DISTANCE(segmentx2->distance);
+
+          /* Modify segments - update the segments */
+
+          if(segmentx1->node1==node1)
+            {
+             if(segmentx1->node2!=newnode)
+                modify_segment(segmentsx,segmentx1,node1,newnode);
+             else
+                PutBackSegmentX(segmentsx,segmentx1);
+            }
+          else /* if(segmentx1->node2==node1) */
+            {
+             if(segmentx1->node1!=newnode)
+                modify_segment(segmentsx,segmentx1,newnode,node1);
+             else
+                PutBackSegmentX(segmentsx,segmentx1);
+            }
+
+          if(segmentx3->node1==node4)
+            {
+             if(segmentx3->node2!=newnode)
+                modify_segment(segmentsx,segmentx3,node4,newnode);
+             else
+                PutBackSegmentX(segmentsx,segmentx3);
+            }
+          else /* if(segmentx3->node2==node4) */
+            {
+             if(segmentx3->node1!=newnode)
+                modify_segment(segmentsx,segmentx3,newnode,node4);
+             else
+                PutBackSegmentX(segmentsx,segmentx3);
+            }
+
+          ReLookupSegmentX(segmentsx,segmentx2);
+
+          prune_segment(segmentsx,segmentx2);
+         }
+       else                     /* third case in diagram - prune one segment */
+         {
+          SegmentX *segmentx1;
+          WayX *wayx1,*wayx2;
+          NodeX *nodex2;
+
+          if(segcount3==2) /* not as in diagram, shuffle things round */
+            {
+             index_t temp;
+
+             temp=segment1; segment1=segment3; segment3=temp;
+             temp=node1; node1=node4; node4=temp;
+             temp=node2; node2=node3; node3=temp;
+            }
+
+          /* Check if pruning would collapse a loop */
+
+          if(node1==node3)
+             goto endloop;
+
+          /* Check if allowed due to one-way properties */
+
+          segmentx1=LookupSegmentX(segmentsx,segment1,1);
+
+          if(!IsOneway(segmentx1) && !IsOneway(segmentx2))
+             ;
+          else if(IsOneway(segmentx1) && IsOneway(segmentx2))
+            {
+             if(IsOnewayTo(segmentx1,node2) && !IsOnewayFrom(segmentx2,node2)) /* S1 is one-way but S2 doesn't continue */
+                goto endloop;
+
+             if(IsOnewayFrom(segmentx1,node2) && !IsOnewayTo(segmentx2,node2)) /* S1 is one-way but S2 doesn't continue */
+                goto endloop;
+            }
+          else
+             goto endloop;
+
+          /* Check if allowed due to highway properties */
+
+          wayx1=LookupWayX(waysx,segmentx1->way,1);
+          wayx2=LookupWayX(waysx,segmentx2->way,2);
+
+          if(WaysCompare(&wayx1->way,&wayx2->way))
+             goto endloop;
+
+          /* Check if allowed due to mini-roundabout and turn restriction */
+
+          nodex2=LookupNodeX(nodesx,node2,2);
+
+          if(nodex2->flags&NODE_MINIRNDBT)
+             goto endloop;
+
+          if(nodex2->flags&NODE_TURNRSTRCT2 || nodex2->flags&NODE_TURNRSTRCT)
+             goto endloop;
+
+          /* Check if allowed due to node restrictions */
+
+          if((nodex2->allow&wayx1->way.allow)!=wayx1->way.allow)
+             goto endloop;
+
+          if((nodex2->allow&wayx2->way.allow)!=wayx2->way.allow)
+             goto endloop;
+
+          /* Modify segments */
+
+          segmentx1->distance+=DISTANCE(segmentx2->distance);
+
+          if(segmentx1->node1==node1)
+             modify_segment(segmentsx,segmentx1,node1,node3);
+          else /* if(segmentx1->node2==node1) */
+             modify_segment(segmentsx,segmentx1,node3,node1);
+
+          ReLookupSegmentX(segmentsx,segmentx2);
+
+          prune_segment(segmentsx,segmentx2);
+         }
+
+       npruned++;
+      }
+
+   endloop:
+
+    if(!((i+1)%10000))
+       printf_middle("Pruning Short Segments: Segments=%"Pindex_t" Short=%"Pindex_t" Pruned=%"Pindex_t,i+1,nshort,npruned);
+   }
+
+ /* Unmap from memory / close the files */
+
+#if !SLIM
+ nodesx->data=UnmapFile(nodesx->data);
+ segmentsx->data=UnmapFile(segmentsx->data);
+ waysx->data=UnmapFile(waysx->data);
+#else
+ nodesx->fd=SlimUnmapFile(nodesx->fd);
+ segmentsx->fd=SlimUnmapFile(segmentsx->fd);
+ waysx->fd=SlimUnmapFile(waysx->fd);
+#endif
+
+ /* Print the final message */
+
+ printf_last("Pruned Short Segments: Segments=%"Pindex_t" Short=%"Pindex_t" Pruned=%"Pindex_t,segmentsx->number,nshort,npruned);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Prune out any nodes from straight highways where the introduced error is smaller than a specified maximum.
+
+  NodesX *nodesx The set of nodes to use.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  WaysX *waysx The set of ways to use.
+
+  distance_t maximum The maximum error to introduce.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void PruneStraightHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distance_t maximum)
+{
+ index_t i;
+ index_t npruned=0;
+ index_t nalloc;
+ BitMask *checked;
+ index_t *nodes,*segments;
+ double *lats,*lons;
+ double maximumf;
+
+ if(nodesx->number==0 || segmentsx->number==0 || waysx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Pruning Straight Highway Nodes: Nodes=0 Pruned=0");
+
+ /* Map into memory / open the files */
+
+#if !SLIM
+ nodesx->data=MapFile(nodesx->filename_tmp);
+ segmentsx->data=MapFileWriteable(segmentsx->filename_tmp);
+ waysx->data=MapFile(waysx->filename_tmp);
+#else
+ nodesx->fd=SlimMapFile(nodesx->filename_tmp);
+ segmentsx->fd=SlimMapFileWriteable(segmentsx->filename_tmp);
+ waysx->fd=SlimMapFile(waysx->filename_tmp);
+
+ InvalidateNodeXCache(nodesx->cache);
+ InvalidateSegmentXCache(segmentsx->cache);
+ InvalidateWayXCache(waysx->cache);
+#endif
+
+ checked=AllocBitMask(nodesx->number);
+
+ log_malloc(checked,LengthBitMask(nodesx->number)*sizeof(BitMask));
+
+ logassert(checked,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
+
+ nodes   =(index_t*)malloc((nalloc=1024)*sizeof(index_t));
+ segments=(index_t*)malloc( nalloc      *sizeof(index_t));
+
+ logassert(nodes   ,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
+ logassert(segments,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
+
+ lats=(double*)malloc(nalloc*sizeof(double));
+ lons=(double*)malloc(nalloc*sizeof(double));
+
+ logassert(lats,"Failed to allocate memory (try using slim mode?)");    /* Check malloc() worked */
+ logassert(lons,"Failed to allocate memory (try using slim mode?)");    /* Check malloc() worked */
+
+ /* Loop through the nodes and find stretches of simple highway for possible modification */
+
+ maximumf=distance_to_km(maximum);
+
+ for(i=0;i<nodesx->number;i++)
+   {
+    int lowerbounded=0,upperbounded=0;
+    index_t lower=nalloc/2,current=nalloc/2,upper=nalloc/2;
+
+    if(IsBitSet(checked,i))
+       goto endloop;
+
+    if(segmentsx->firstnode[i]==NO_SEGMENT)
+       goto endloop;
+
+    /* Find all connected nodes */
+
+    nodes[current]=i;
+
+    do
+      {
+       index_t node1=NO_NODE,node2=NO_NODE;
+       index_t segment1=NO_SEGMENT,segment2=NO_SEGMENT;
+       index_t way1=NO_WAY,way2=NO_WAY;
+       int segcount=0;
+       NodeX *nodex;
+
+       /* Get the node data */
+
+       nodex=LookupNodeX(nodesx,nodes[current],1);
+
+       lats[current]=latlong_to_radians(nodex->latitude);
+       lons[current]=latlong_to_radians(nodex->longitude);
+
+       /* Count the segments at the node if not forced to be an end node */
+
+       if(IsBitSet(checked,nodes[current]))
+          ;
+       else if(nodex->flags&NODE_MINIRNDBT)
+          ;
+       else if(nodex->flags&NODE_TURNRSTRCT2 || nodex->flags&NODE_TURNRSTRCT)
+          ;
+       else
+         {
+          SegmentX *segmentx;
+
+          /* Count the segments connected to the node */
+
+          segmentx=FirstSegmentX(segmentsx,nodes[current],3);
+
+          while(segmentx)
+            {
+             segcount++;
+
+             if(node1==NO_NODE)
+               {
+                segment1=IndexSegmentX(segmentsx,segmentx);
+                node1=OtherNode(segmentx,nodes[current]);
+                way1=segmentx->way;
+               }
+             else if(node2==NO_NODE)
+               {
+                segment2=IndexSegmentX(segmentsx,segmentx);
+                node2=OtherNode(segmentx,nodes[current]);
+                way2=segmentx->way;
+               }
+             else
+                break;
+
+             segmentx=NextSegmentX(segmentsx,segmentx,nodes[current]);
+            }
+         }
+
+       /* Check if allowed due to one-way properties */
+
+       if(segcount==2)
+         {
+          SegmentX *segmentx1,*segmentx2;
+
+          segmentx1=LookupSegmentX(segmentsx,segment1,1);
+          segmentx2=LookupSegmentX(segmentsx,segment2,2);
+
+          if(!IsOneway(segmentx1) && !IsOneway(segmentx2))
+             ;
+          else if(IsOneway(segmentx1) && IsOneway(segmentx2))
+            {
+             if(IsOnewayTo(segmentx1,nodes[current]) && !IsOnewayFrom(segmentx2,nodes[current])) /* S1 is one-way but S2 doesn't continue */
+                segcount=0;
+
+             if(IsOnewayFrom(segmentx1,nodes[current]) && !IsOnewayTo(segmentx2,nodes[current])) /* S1 is one-way but S2 doesn't continue */
+                segcount=0;
+            }
+          else
+             segcount=0;
+         }
+
+       /* Check if allowed due to highway properties and node restrictions */
+
+       if(segcount==2)
+         {
+          WayX *wayx1,*wayx2;
+
+          wayx1=LookupWayX(waysx,way1,1);
+          wayx2=LookupWayX(waysx,way2,2);
+
+          if(WaysCompare(&wayx1->way,&wayx2->way))
+             segcount=0;
+
+          if(wayx1->way.name!=wayx2->way.name)
+             segcount=0;
+
+          if((nodex->allow&wayx1->way.allow)!=wayx1->way.allow)
+             segcount=0;
+
+          if((nodex->allow&wayx2->way.allow)!=wayx2->way.allow)
+             segcount=0;
+         }
+
+       /* Update the lists */
+
+       if(segcount==2)
+         {
+          /* Make space in the lists */
+
+          if(upper==(nalloc-1))
+            {
+             nodes   =(index_t*)realloc(nodes   ,(nalloc+=1024)*sizeof(index_t));
+             segments=(index_t*)realloc(segments, nalloc       *sizeof(index_t));
+
+             lats=(double*)realloc(lats,nalloc*sizeof(double));
+             lons=(double*)realloc(lons,nalloc*sizeof(double));
+            }
+
+          if(lower==0)     /* move everything up by one */
+            {
+             memmove(nodes+1   ,nodes   ,(1+upper-lower)*sizeof(index_t));
+             memmove(segments+1,segments,(1+upper-lower)*sizeof(index_t));
+
+             memmove(lats+1,lats,(1+upper-lower)*sizeof(double));
+             memmove(lons+1,lons,(1+upper-lower)*sizeof(double));
+
+             current++;
+             lower++;
+             upper++;
+            }
+
+          if(lower==upper) /* first */
+            {
+             lower--;
+
+             nodes[lower]=node1;
+             segments[lower]=segment1;
+
+             upper++;
+
+             nodes[upper]=node2;
+             segments[upper-1]=segment2;
+             segments[upper]=NO_SEGMENT;
+
+             current--;
+            }
+          else if(current==lower)
+            {
+             lower--;
+
+             if(nodes[current+1]==node2)
+               {
+                nodes[lower]=node1;
+                segments[lower]=segment1;
+               }
+             else /* if(nodes[current+1]==node1) */
+               {
+                nodes[lower]=node2;
+                segments[lower]=segment2;
+               }
+
+             current--;
+            }
+          else /* if(current==upper) */
+            {
+             upper++;
+
+             if(nodes[current-1]==node2)
+               {
+                nodes[upper]=node1;
+                segments[upper-1]=segment1;
+               }
+             else /* if(nodes[current-1]==node1) */
+               {
+                nodes[upper]=node2;
+                segments[upper-1]=segment2;
+               }
+
+             segments[upper]=NO_SEGMENT;
+
+             current++;
+            }
+
+          if(nodes[upper]==nodes[lower])
+            {
+             if(!lowerbounded && !upperbounded)
+               {
+                nodex=LookupNodeX(nodesx,nodes[lower],1);
+
+                lats[lower]=latlong_to_radians(nodex->latitude);
+                lons[lower]=latlong_to_radians(nodex->longitude);
+               }
+
+             lats[upper]=lats[lower];
+             lons[upper]=lons[lower];
+
+             lowerbounded=1;
+             upperbounded=1;
+            }
+         }
+       else /* if(segment!=2) */
+         {
+          if(current==upper)
+             upperbounded=1;
+
+          if(current==lower)
+            {
+             lowerbounded=1;
+             current=upper;
+            }
+         }
+      }
+    while(!(lowerbounded && upperbounded));
+
+    /* Mark the nodes */
+
+    for(current=lower;current<=upper;current++)
+       SetBit(checked,nodes[current]);
+
+    /* Check for straight highway */
+
+    for(;lower<(upper-1);lower++)
+      {
+       for(current=upper;current>(lower+1);current--)
+         {
+          SegmentX *segmentx;
+          distance_t dist=0;
+          double dist1,dist2,dist3,distp;
+          index_t c;
+
+          dist3=distance(lats[lower],lons[lower],lats[current],lons[current]);
+
+          for(c=lower+1;c<current;c++)
+            {
+             dist1=distance(lats[lower]  ,lons[lower]  ,lats[c],lons[c]);
+             dist2=distance(lats[current],lons[current],lats[c],lons[c]);
+
+             /* Use law of cosines (assume flat Earth) */
+
+             if(dist3==0)
+                distp=dist1; /* == dist2 */
+             else if((dist1+dist2)<dist3)
+                distp=0;
+             else
+               {
+                double dist3a=(dist1*dist1-dist2*dist2+dist3*dist3)/(2.0*dist3);
+                double dist3b=dist3-dist3a;
+
+                if(dist3a>=0 && dist3b>=0)
+                   distp=sqrt(dist1*dist1-dist3a*dist3a);
+                else if(dist3a>0)
+                   distp=dist2;
+                else /* if(dist3b>0) */
+                   distp=dist1;
+               }
+
+             if(distp>maximumf) /* gone too far */
+                break;
+            }
+
+          if(c<current) /* not finished */
+             continue;
+
+          /* Delete some segments and shift along */
+
+          for(c=lower+1;c<current;c++)
+            {
+             segmentx=LookupSegmentX(segmentsx,segments[c],1);
+
+             dist+=DISTANCE(segmentx->distance);
+
+             prune_segment(segmentsx,segmentx);
+
+             npruned++;
+            }
+
+          segmentx=LookupSegmentX(segmentsx,segments[lower],1);
+
+          if(nodes[lower]==nodes[current]) /* loop; all within maximum distance */
+            {
+             prune_segment(segmentsx,segmentx);
+
+             npruned++;
+            }
+          else
+            {
+             segmentx->distance+=dist;
+
+             if(segmentx->node1==nodes[lower])
+                modify_segment(segmentsx,segmentx,nodes[lower],nodes[current]);
+             else /* if(segmentx->node2==nodes[lower]) */
+                modify_segment(segmentsx,segmentx,nodes[current],nodes[lower]);
+            }
+
+          lower=current-1;
+          break;
+         }
+      }
+
+   endloop:
+
+    if(!((i+1)%10000))
+       printf_middle("Pruning Straight Highway Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,i+1,npruned);
+   }
+
+ /* Unmap from memory / close the files */
+
+ log_free(checked);
+ free(checked);
+
+ free(nodes);
+ free(segments);
+
+ free(lats);
+ free(lons);
+
+#if !SLIM
+ nodesx->data=UnmapFile(nodesx->data);
+ segmentsx->data=UnmapFile(segmentsx->data);
+ waysx->data=UnmapFile(waysx->data);
+#else
+ nodesx->fd=SlimUnmapFile(nodesx->fd);
+ segmentsx->fd=SlimUnmapFile(segmentsx->fd);
+ waysx->fd=SlimUnmapFile(waysx->fd);
+#endif
+
+ /* Print the final message */
+
+ printf_last("Pruned Straight Highway Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,nodesx->number,npruned);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Prune a segment; unused nodes and ways will get marked for pruning later.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  SegmentX *segmentx The segment to be pruned.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void prune_segment(SegmentsX *segmentsx,SegmentX *segmentx)
+{
+ unlink_segment_node1_refs(segmentsx,segmentx);
+
+ unlink_segment_node2_refs(segmentsx,segmentx);
+
+ segmentx->node1=NO_NODE;
+ segmentx->node2=NO_NODE;
+ segmentx->next2=NO_SEGMENT;
+
+ PutBackSegmentX(segmentsx,segmentx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Modify a segment's nodes; unused nodes will get marked for pruning later.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  SegmentX *segmentx The segment to be modified.
+
+  index_t newnode1 The new value of node1.
+
+  index_t newnode2 The new value of node2.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void modify_segment(SegmentsX *segmentsx,SegmentX *segmentx,index_t newnode1,index_t newnode2)
+{
+ index_t thissegment=IndexSegmentX(segmentsx,segmentx);
+
+ if(newnode1>newnode2)          /* rotate the segment around */
+   {
+    index_t temp;
+
+    if(segmentx->distance&(ONEWAY_2TO1|ONEWAY_1TO2))
+       segmentx->distance^=ONEWAY_2TO1|ONEWAY_1TO2;
+
+    temp=newnode1;
+    newnode1=newnode2;
+    newnode2=temp;
+   }
+
+ if(newnode1!=segmentx->node1)
+    unlink_segment_node1_refs(segmentsx,segmentx);
+
+ if(newnode2!=segmentx->node2)
+    unlink_segment_node2_refs(segmentsx,segmentx);
+
+ if(newnode1!=segmentx->node1) /* only modify it if the node has changed */
+   {
+    segmentx->node1=newnode1;
+
+    segmentsx->next1[thissegment]=segmentsx->firstnode[newnode1];
+    segmentsx->firstnode[newnode1]=thissegment;
+   }
+
+ if(newnode2!=segmentx->node2) /* only modify it if the node has changed */
+   {
+    segmentx->node2=newnode2;
+
+    segmentx->next2=segmentsx->firstnode[newnode2];
+    segmentsx->firstnode[newnode2]=thissegment;
+   }
+
+ PutBackSegmentX(segmentsx,segmentx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Unlink a node1 from a segment by modifying the linked list type arrangement of node references.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  SegmentX *segmentx The segment to be modified.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void unlink_segment_node1_refs(SegmentsX *segmentsx,SegmentX *segmentx)
+{
+ index_t segment,thissegment;
+
+ thissegment=IndexSegmentX(segmentsx,segmentx);
+
+ segment=segmentsx->firstnode[segmentx->node1];
+
+ if(segment==thissegment)
+    segmentsx->firstnode[segmentx->node1]=segmentsx->next1[thissegment];
+ else
+   {
+    do
+      {
+       index_t nextsegment;
+       SegmentX *segx=LookupSegmentX(segmentsx,segment,4);
+
+       if(segx->node1==segmentx->node1)
+         {
+          nextsegment=segmentsx->next1[segment];
+
+          if(nextsegment==thissegment)
+             segmentsx->next1[segment]=segmentsx->next1[thissegment];
+         }
+       else /* if(segx->node2==segmentx->node1) */
+         {
+          nextsegment=segx->next2;
+
+          if(nextsegment==thissegment)
+            {
+             segx->next2=segmentsx->next1[thissegment];
+
+             PutBackSegmentX(segmentsx,segx);
+            }
+         }
+
+       segment=nextsegment;
+      }
+    while(segment!=thissegment && segment!=NO_SEGMENT);
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Unlink a node2 from a segment by modifying the linked list type arrangement of node references.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  SegmentX *segmentx The segment to be modified.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void unlink_segment_node2_refs(SegmentsX *segmentsx,SegmentX *segmentx)
+{
+ index_t segment,thissegment;
+
+ thissegment=IndexSegmentX(segmentsx,segmentx);
+
+ segment=segmentsx->firstnode[segmentx->node2];
+
+ if(segment==thissegment)
+    segmentsx->firstnode[segmentx->node2]=segmentx->next2;
+ else
+   {
+    do
+      {
+       index_t nextsegment;
+       SegmentX *segx=LookupSegmentX(segmentsx,segment,4);
+
+       if(segx->node1==segmentx->node2)
+         {
+          nextsegment=segmentsx->next1[segment];
+
+          if(nextsegment==thissegment)
+             segmentsx->next1[segment]=segmentx->next2;
+         }
+       else /* if(segx->node2==segmentx->node2) */
+         {
+          nextsegment=segx->next2;
+
+          if(nextsegment==thissegment)
+            {
+             segx->next2=segmentx->next2;
+
+             PutBackSegmentX(segmentsx,segx);
+            }
+         }
+
+       segment=nextsegment;
+      }
+    while(segment!=thissegment && segment!=NO_SEGMENT);
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Calculate the distance between two locations.
+
+  double distance Returns the distance between the locations.
+
+  double lat1 The latitude of the first location.
+
+  double lon1 The longitude of the first location.
+
+  double lat2 The latitude of the second location.
+
+  double lon2 The longitude of the second location.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static double distance(double lat1,double lon1,double lat2,double lon2)
+{
+ double dlon = lon1 - lon2;
+ double dlat = lat1 - lat2;
+
+ double a1,a2,a,sa,c,d;
+
+ if(dlon==0 && dlat==0)
+   return 0;
+
+ a1 = sin (dlat / 2);
+ a2 = sin (dlon / 2);
+ a = (a1 * a1) + cos (lat1) * cos (lat2) * a2 * a2;
+ sa = sqrt (a);
+ if (sa <= 1.0)
+   {c = 2 * asin (sa);}
+ else
+   {c = 2 * asin (1.0);}
+ d = 6378.137 * c;
+
+ return(d);
+}
diff --git a/3rdparty/Routino/src/prunex.h b/3rdparty/Routino/src/prunex.h
new file mode 100644
index 0000000..1cdc113
--- /dev/null
+++ b/3rdparty/Routino/src/prunex.h
@@ -0,0 +1,43 @@
+/***************************************
+ Header for super-node and super-segment pruning functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2011-2012 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef PRUNEX_H
+#define PRUNEX_H    /*+ To stop multiple inclusions. +*/
+
+#include "types.h"
+
+#include "typesx.h"
+
+
+/* Functions in prunex.c */
+
+void StartPruning(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx);
+void FinishPruning(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx);
+
+void PruneIsolatedRegions(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distance_t minimum);
+
+void PruneShortSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distance_t minimum);
+
+void PruneStraightHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distance_t maximum);
+
+
+#endif /* PRUNEX_H */
diff --git a/3rdparty/Routino/src/queue.c b/3rdparty/Routino/src/queue.c
new file mode 100644
index 0000000..226b729
--- /dev/null
+++ b/3rdparty/Routino/src/queue.c
@@ -0,0 +1,225 @@
+/***************************************
+ Queue data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2013 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "results.h"
+
+
+/*+ A queue of results. +*/
+struct _Queue
+{
+ int      nincrement;           /*+ The amount to increment the queue when full. +*/
+ int      nallocated;           /*+ The number of entries allocated. +*/
+ int      noccupied;            /*+ The number of entries occupied. +*/
+
+ Result **results;              /*+ The queue of pointers to results. +*/
+};
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Allocate a new queue.
+
+  Queue *NewQueueList Returns the queue.
+
+  uint8_t log2bins The base 2 logarithm of the initial number of bins in the queue.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Queue *NewQueueList(uint8_t log2bins)
+{
+ Queue *queue;
+
+ queue=(Queue*)malloc(sizeof(Queue));
+
+ queue->nincrement=1<<log2bins;
+
+ queue->nallocated=queue->nincrement;
+ queue->noccupied=0;
+
+ queue->results=(Result**)malloc(queue->nallocated*sizeof(Result*));
+
+ return(queue);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Re-use an existing queue.
+
+  Queue *queue The queue to reset for re-use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void ResetQueueList(Queue *queue)
+{
+ queue->noccupied=0;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Free a queue.
+
+  Queue *queue The queue to be freed.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FreeQueueList(Queue *queue)
+{
+ free(queue->results);
+
+ free(queue);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Insert a new item into the queue in the right place.
+
+  The data is stored in a "Binary Heap" http://en.wikipedia.org/wiki/Binary_heap
+  and this operation is adding an item to the heap.
+
+  Queue *queue The queue to insert the result into.
+
+  Result *result The result to insert into the queue.
+
+  score_t score The score to use for sorting the node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void InsertInQueue(Queue *queue,Result *result,score_t score)
+{
+ int index;
+
+ if(result->queued==NOT_QUEUED)
+   {
+    queue->noccupied++;
+    index=queue->noccupied;
+
+    if(queue->noccupied==queue->nallocated)
+      {
+       queue->nallocated=queue->nallocated+queue->nincrement;
+       queue->results=(Result**)realloc((void*)queue->results,queue->nallocated*sizeof(Result*));
+      }
+
+    queue->results[index]=result;
+    queue->results[index]->queued=index;
+   }
+ else
+    index=result->queued;
+
+ queue->results[index]->sortby=score;
+
+ /* Bubble up the new value */
+
+ while(index>1)
+   {
+    int newindex;
+    Result *temp;
+
+    newindex=index/2;
+
+    if(queue->results[index]->sortby>=queue->results[newindex]->sortby)
+       break;
+
+    temp=queue->results[index];
+    queue->results[index]=queue->results[newindex];
+    queue->results[newindex]=temp;
+
+    queue->results[index]->queued=index;
+    queue->results[newindex]->queued=newindex;
+
+    index=newindex;
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Pop an item from the front of the queue.
+
+  The data is stored in a "Binary Heap" http://en.wikipedia.org/wiki/Binary_heap
+  and this operation is deleting the root item from the heap.
+
+  Result *PopFromQueue Returns the top item.
+
+  Queue *queue The queue to remove the result from.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Result *PopFromQueue(Queue *queue)
+{
+ int index;
+ Result *retval;
+
+ if(queue->noccupied==0)
+    return(NULL);
+
+ retval=queue->results[1];
+ retval->queued=NOT_QUEUED;
+
+ index=1;
+
+ queue->results[index]=queue->results[queue->noccupied];
+
+ queue->noccupied--;
+
+ /* Bubble down the newly promoted value */
+
+ while((2*index)<queue->noccupied)
+   {
+    int newindex;
+    Result *temp;
+
+    newindex=2*index;
+
+    if(queue->results[newindex]->sortby>queue->results[newindex+1]->sortby)
+       newindex=newindex+1;
+
+    if(queue->results[index]->sortby<=queue->results[newindex]->sortby)
+       break;
+
+    temp=queue->results[newindex];
+    queue->results[newindex]=queue->results[index];
+    queue->results[index]=temp;
+
+    queue->results[index]->queued=index;
+    queue->results[newindex]->queued=newindex;
+
+    index=newindex;
+   }
+
+ if((2*index)==queue->noccupied)
+   {
+    int newindex;
+    Result *temp;
+
+    newindex=2*index;
+
+    if(queue->results[index]->sortby<=queue->results[newindex]->sortby)
+       ; /* break */
+    else
+      {
+       temp=queue->results[newindex];
+       queue->results[newindex]=queue->results[index];
+       queue->results[index]=temp;
+
+       queue->results[index]->queued=index;
+       queue->results[newindex]->queued=newindex;
+      }
+   }
+
+ return(retval);
+}
diff --git a/3rdparty/Routino/src/relations.c b/3rdparty/Routino/src/relations.c
new file mode 100644
index 0000000..09f73bd
--- /dev/null
+++ b/3rdparty/Routino/src/relations.c
@@ -0,0 +1,405 @@
+/***************************************
+ Relation data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+
+#include "types.h"
+#include "relations.h"
+#include "fakes.h"
+
+#include "files.h"
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Load in a relation list from a file.
+
+  Relations *LoadRelationList Returns the relation list.
+
+  const char *filename The name of the file to load.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Relations *LoadRelationList(const char *filename)
+{
+ Relations *relations;
+
+ relations=(Relations*)malloc(sizeof(Relations));
+
+#if !SLIM
+
+ relations->data=MapFile(filename);
+
+ /* Copy the RelationsFile header structure from the loaded data */
+
+ relations->file=*((RelationsFile*)relations->data);
+
+ /* Set the pointers in the Relations structure. */
+
+ relations->turnrelations=(TurnRelation*)(relations->data+sizeof(RelationsFile));
+
+#else
+
+ relations->fd=SlimMapFile(filename);
+
+ /* Copy the RelationsFile header structure from the loaded data */
+
+ SlimFetch(relations->fd,&relations->file,sizeof(RelationsFile),0);
+
+ relations->troffset=sizeof(RelationsFile);
+
+ relations->cache=NewTurnRelationCache();
+#ifndef LIBROUTINO
+ log_malloc(relations->cache,sizeof(*relations->cache));
+#endif
+
+#endif
+
+ if(relations->file.trnumber>0)
+   {
+    TurnRelation *relation;
+
+    relation=LookupTurnRelation(relations,0,1);
+
+    relations->via_start =relation->via;
+
+    relation=LookupTurnRelation(relations,relations->file.trnumber-1,1);
+
+    relations->via_end =relation->via;
+   }
+
+ return(relations);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Destroy the relation list.
+
+  Relations *relations The relation list to destroy.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void DestroyRelationList(Relations *relations)
+{
+#if !SLIM
+
+ relations->data=UnmapFile(relations->data);
+
+#else
+
+ relations->fd=SlimUnmapFile(relations->fd);
+
+#ifndef LIBROUTINO
+ log_free(relations->cache);
+#endif
+ DeleteTurnRelationCache(relations->cache);
+
+#endif
+
+ free(relations);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the first turn relation in the file whose 'via' matches a specific node.
+
+  index_t FindFirstTurnRelation1 Returns the index of the first turn relation matching.
+
+  Relations *relations The set of relations to use.
+
+  index_t via The node that the route is going via.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t FindFirstTurnRelation1(Relations *relations,index_t via)
+{
+ TurnRelation *relation;
+ index_t start=0;
+ index_t end=relations->file.trnumber-1;
+ index_t mid;
+ index_t match=NO_RELATION;
+
+ /* Binary search - search key any exact match is required.
+  *
+  *  # <- start  |  Check mid and move start or end if it doesn't match
+  *  #           |
+  *  #           |  Since an exact match is wanted we can set end=mid-1
+  *  # <- mid    |  or start=mid+1 because we know that mid doesn't match.
+  *  #           |
+  *  #           |  Eventually either end=start or end=start+1 and one of
+  *  # <- end    |  start or end matches (but may not be the first).
+  */
+
+ do
+   {
+    mid=(start+end)/2;              /* Choose mid point */
+
+    relation=LookupTurnRelation(relations,mid,1);
+
+    if(relation->via<via)           /* Mid point is too low for 'via' */
+       start=mid+1;
+    else if(relation->via>via)      /* Mid point is too high for 'via' */
+       end=mid?(mid-1):mid;
+    else                            /* Mid point is correct for 'from' */
+      {
+       match=mid;
+       break;
+      }
+   }
+ while((end-start)>1);
+
+ if(match==NO_RELATION)             /* Check if start matches */
+   {
+    relation=LookupTurnRelation(relations,start,1);
+
+    if(relation->via==via)
+       match=start;
+   }
+
+ if(match==NO_RELATION)             /* Check if end matches */
+   {
+    relation=LookupTurnRelation(relations,end,1);
+
+    if(relation->via==via)
+       match=end;
+   }
+
+ if(match==NO_RELATION)
+    return(match);
+
+ while(match>0)                     /* Search backwards for the first match */
+   {
+    relation=LookupTurnRelation(relations,match-1,1);
+
+    if(relation->via==via)
+       match--;
+    else
+       break;
+   }
+
+ return(match);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the next turn relation in the file whose 'via' matches a specific node.
+
+  index_t FindNextTurnRelation1 Returns the index of the next turn relation matching.
+
+  Relations *relations The set of relations to use.
+
+  index_t current The current index of a relation that matches.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t FindNextTurnRelation1(Relations *relations,index_t current)
+{
+ TurnRelation *relation;
+ index_t via;
+
+ relation=LookupTurnRelation(relations,current,1);
+
+ via=relation->via;
+
+ current++;
+
+ if(current==relations->file.trnumber)
+    return(NO_RELATION);
+
+ relation=LookupTurnRelation(relations,current,1);
+
+ if(relation->via==via)
+    return(current);
+ else
+    return(NO_RELATION);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the first turn relation in the file whose 'via' and 'from' match a specific node and segment.
+
+  index_t FindFirstTurnRelation2 Returns the index of the first turn relation matching.
+
+  Relations *relations The set of relations to use.
+
+  index_t via The node that the route is going via.
+
+  index_t from The segment that the route is coming from.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t FindFirstTurnRelation2(Relations *relations,index_t via,index_t from)
+{
+ TurnRelation *relation;
+ index_t start=0;
+ index_t end=relations->file.trnumber-1;
+ index_t mid;
+ index_t match=NO_RELATION;
+
+ if(IsFakeSegment(from))
+    from=IndexRealSegment(from);
+
+ /* Binary search - search key first match is required.
+  *
+  *  # <- start  |  Check mid and move start or end if it doesn't match
+  *  #           |
+  *  #           |  Since an exact match is wanted we can set end=mid-1
+  *  # <- mid    |  or start=mid+1 because we know that mid doesn't match.
+  *  #           |
+  *  #           |  Eventually either end=start or end=start+1 and one of
+  *  # <- end    |  start or end matches (but may not be the first).
+  */
+
+ do
+   {
+    mid=(start+end)/2;              /* Choose mid point */
+
+    relation=LookupTurnRelation(relations,mid,1);
+
+    if(relation->via<via)           /* Mid point is too low for 'via' */
+       start=mid+1;
+    else if(relation->via>via)      /* Mid point is too high for 'via' */
+       end=mid?(mid-1):mid;
+    else                            /* Mid point is correct for 'via' */
+      {
+       if(relation->from<from)      /* Mid point is too low for 'from' */
+          start=mid+1;
+       else if(relation->from>from) /* Mid point is too high for 'from' */
+          end=mid?(mid-1):mid;
+       else                         /* Mid point is correct for 'from' */
+         {
+          match=mid;
+          break;
+         }
+      }
+   }
+ while((end-start)>1);
+
+ if(match==NO_RELATION)             /* Check if start matches */
+   {
+    relation=LookupTurnRelation(relations,start,1);
+
+    if(relation->via==via && relation->from==from)
+       match=start;
+   }
+
+ if(match==NO_RELATION)             /* Check if end matches */
+   {
+    relation=LookupTurnRelation(relations,end,1);
+
+    if(relation->via==via && relation->from==from)
+       match=end;
+   }
+
+ if(match==NO_RELATION)
+    return(match);
+
+ while(match>0)                     /* Search backwards for the first match */
+   {
+    relation=LookupTurnRelation(relations,match-1,1);
+
+    if(relation->via==via && relation->from==from)
+       match--;
+    else
+       break;
+   }
+
+ return(match);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the next turn relation in the file whose 'via' and 'from' match a specific node and segment.
+
+  index_t FindNextTurnRelation2 Returns the index of the next turn relation matching.
+
+  Relations *relations The set of relations to use.
+
+  index_t current The current index of a relation that matches.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t FindNextTurnRelation2(Relations *relations,index_t current)
+{
+ TurnRelation *relation;
+ index_t via,from;
+
+ relation=LookupTurnRelation(relations,current,1);
+
+ via=relation->via;
+ from=relation->from;
+
+ current++;
+
+ if(current==relations->file.trnumber)
+    return(NO_RELATION);
+
+ relation=LookupTurnRelation(relations,current,1);
+
+ if(relation->via==via && relation->from==from)
+    return(current);
+ else
+    return(NO_RELATION);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Determine if a turn is allowed between the nodes 'from', 'via' and 'to' for a particular transport type.
+
+  int IsTurnAllowed Return 1 if the turn is allowed or 0 if not.
+
+  Relations *relations The set of relations to use.
+
+  index_t index The index of the first turn relation containing 'via' and 'from'.
+
+  index_t via The via node.
+
+  index_t from The from segment.
+
+  index_t to The to segment.
+
+  transports_t transport The type of transport that is being routed.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int IsTurnAllowed(Relations *relations,index_t index,index_t via,index_t from,index_t to,transports_t transport)
+{
+ if(IsFakeSegment(from))
+    from=IndexRealSegment(from);
+
+ if(IsFakeSegment(to))
+    to=IndexRealSegment(to);
+
+ while(index<relations->file.trnumber)
+   {
+    TurnRelation *relation=LookupTurnRelation(relations,index,1);
+
+    if(relation->via!=via)
+       return(1);
+
+    if(relation->from!=from)
+       return(1);
+
+    if(relation->to>to)
+       return(1);
+
+    if(relation->to==to)
+       if(!(relation->except & transport))
+          return(0);
+
+    index++;
+   }
+
+ return(1);
+}
diff --git a/3rdparty/Routino/src/relations.h b/3rdparty/Routino/src/relations.h
new file mode 100644
index 0000000..42b56c1
--- /dev/null
+++ b/3rdparty/Routino/src/relations.h
@@ -0,0 +1,151 @@
+/***************************************
+ A header file for the relations.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef RELATIONS_H
+#define RELATIONS_H    /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "types.h"
+
+#include "cache.h"
+#include "files.h"
+#include "profiles.h"
+
+
+/* Data structures */
+
+
+/*+ A structure containing a single relation. +*/
+struct _TurnRelation
+{
+ index_t      from;             /*+ The segment that the path comes from. +*/
+ index_t      via;              /*+ The node that the path goes via. +*/
+ index_t      to;               /*+ The segment that the path goes to. +*/
+
+ transports_t except;           /*+ The types of transports that that this relation does not apply to. +*/
+};
+
+
+/*+ A structure containing the header from the file. +*/
+typedef struct _RelationsFile
+{
+ index_t       trnumber;        /*+ The number of turn relations in total. +*/
+}
+ RelationsFile;
+
+
+/*+ A structure containing a set of relations (and pointers to mmap file). +*/
+struct _Relations
+{
+ RelationsFile file;            /*+ The header data from the file. +*/
+
+#if !SLIM
+
+ char         *data;            /*+ The memory mapped data. +*/
+
+ TurnRelation *turnrelations;   /*+ An array of nodes. +*/
+
+#else
+
+ int           fd;              /*+ The file descriptor for the file. +*/
+
+ off_t         troffset;        /*+ The offset of the turn relations in the file. +*/
+
+ TurnRelation  cached[2];       /*+ Two cached relations read from the file in slim mode. +*/
+
+ TurnRelationCache *cache;      /*+ A RAM cache of turn relations read from the file. +*/
+
+#endif
+
+ index_t       via_start;       /*+ The first via node in the file. +*/
+ index_t       via_end;         /*+ The last via node in the file. +*/
+};
+
+
+/* Functions in relations.c */
+
+Relations *LoadRelationList(const char *filename);
+
+void DestroyRelationList(Relations *relations);
+
+index_t FindFirstTurnRelation1(Relations *relations,index_t via);
+index_t FindNextTurnRelation1(Relations *relations,index_t current);
+
+index_t FindFirstTurnRelation2(Relations *relations,index_t via,index_t from);
+index_t FindNextTurnRelation2(Relations *relations,index_t current);
+
+int IsTurnAllowed(Relations *relations,index_t index,index_t via,index_t from,index_t to,transports_t transport);
+
+
+/* Macros and inline functions */
+
+#if !SLIM
+
+/*+ Return a Relation pointer given a set of relations and an index. +*/
+#define LookupTurnRelation(xxx,yyy,ppp)   (&(xxx)->turnrelations[yyy])
+
+#else
+
+/* Prototypes */
+
+static inline TurnRelation *LookupTurnRelation(Relations *relations,index_t index,int position);
+
+CACHE_NEWCACHE_PROTO(TurnRelation)
+CACHE_DELETECACHE_PROTO(TurnRelation)
+CACHE_FETCHCACHE_PROTO(TurnRelation)
+CACHE_INVALIDATECACHE_PROTO(TurnRelation)
+
+
+/* Inline functions */
+
+CACHE_STRUCTURE(TurnRelation)
+CACHE_NEWCACHE(TurnRelation)
+CACHE_DELETECACHE(TurnRelation)
+CACHE_FETCHCACHE(TurnRelation)
+CACHE_INVALIDATECACHE(TurnRelation)
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the Relation information for a particular relation.
+
+  TurnRelation *LookupTurnRelation Returns a pointer to the cached relation information.
+
+  Relations *relations The set of relations to use.
+
+  index_t index The index of the relation.
+
+  int position The position in the cache to store this result.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline TurnRelation *LookupTurnRelation(Relations *relations,index_t index,int position)
+{
+ relations->cached[position-1]=*FetchCachedTurnRelation(relations->cache,index,relations->fd,relations->troffset);
+
+ return(&relations->cached[position-1]);
+}
+
+#endif
+
+
+#endif /* RELATIONS_H */
diff --git a/3rdparty/Routino/src/relationsx.c b/3rdparty/Routino/src/relationsx.c
new file mode 100644
index 0000000..f623c23
--- /dev/null
+++ b/3rdparty/Routino/src/relationsx.c
@@ -0,0 +1,1460 @@
+/***************************************
+ Extended Relation data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "types.h"
+#include "segments.h"
+#include "relations.h"
+
+#include "nodesx.h"
+#include "segmentsx.h"
+#include "waysx.h"
+#include "relationsx.h"
+
+#include "files.h"
+#include "logging.h"
+#include "sorting.h"
+
+
+/* Global variables */
+
+/*+ The command line '--tmpdir' option or its default value. +*/
+extern char *option_tmpdirname;
+
+/* Local variables */
+
+/*+ Temporary file-local variables for use by the sort functions (re-initialised for each sort). +*/
+static SegmentsX *sortsegmentsx;
+static NodesX *sortnodesx;
+
+/* Local functions */
+
+static int sort_route_by_id(RouteRelX *a,RouteRelX *b);
+static int deduplicate_route_by_id(RouteRelX *relationx,index_t index);
+
+static int sort_turn_by_id(TurnRelX *a,TurnRelX *b);
+static int deduplicate_turn_by_id(TurnRelX *relationx,index_t index);
+
+static int geographically_index(TurnRelX *relationx,index_t index);
+static int geographically_index_convert_segments(TurnRelX *relationx,index_t index);
+static int sort_by_via(TurnRelX *a,TurnRelX *b);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Allocate a new relation list (create a new file or open an existing one).
+
+  RelationsX *NewRelationList Returns the relation list.
+
+  int append Set to 1 if the file is to be opened for appending.
+
+  int readonly Set to 1 if the file is to be opened for reading.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+RelationsX *NewRelationList(int append,int readonly)
+{
+ RelationsX *relationsx;
+
+ relationsx=(RelationsX*)calloc(1,sizeof(RelationsX));
+
+ logassert(relationsx,"Failed to allocate memory (try using slim mode?)"); /* Check calloc() worked */
+
+
+ /* Route Relations */
+
+ relationsx->rrfilename    =(char*)malloc(strlen(option_tmpdirname)+32);
+ relationsx->rrfilename_tmp=(char*)malloc(strlen(option_tmpdirname)+48); /* allow %p to be up to 20 bytes */
+
+ sprintf(relationsx->rrfilename    ,"%s/relationsx.route.parsed.mem",option_tmpdirname);
+ sprintf(relationsx->rrfilename_tmp,"%s/relationsx.route.%p.tmp"    ,option_tmpdirname,(void*)relationsx);
+
+ if(append || readonly)
+    if(ExistsFile(relationsx->rrfilename))
+      {
+       FILESORT_VARINT relationsize;
+       int rrfd;
+
+       rrfd=ReOpenFileBuffered(relationsx->rrfilename);
+
+       while(!ReadFileBuffered(rrfd,&relationsize,FILESORT_VARSIZE))
+         {
+          SkipFileBuffered(rrfd,relationsize);
+
+          relationsx->rrnumber++;
+         }
+
+       CloseFileBuffered(rrfd);
+
+       RenameFile(relationsx->rrfilename,relationsx->rrfilename_tmp);
+      }
+
+ if(append)
+    relationsx->rrfd=OpenFileBufferedAppend(relationsx->rrfilename_tmp);
+ else if(!readonly)
+    relationsx->rrfd=OpenFileBufferedNew(relationsx->rrfilename_tmp);
+ else
+    relationsx->rrfd=-1;
+
+
+ /* Turn Restriction Relations */
+
+ relationsx->trfilename    =(char*)malloc(strlen(option_tmpdirname)+32);
+ relationsx->trfilename_tmp=(char*)malloc(strlen(option_tmpdirname)+48); /* allow %p to be up to 20 bytes */
+
+ sprintf(relationsx->trfilename    ,"%s/relationsx.turn.parsed.mem",option_tmpdirname);
+ sprintf(relationsx->trfilename_tmp,"%s/relationsx.turn.%p.tmp"    ,option_tmpdirname,(void*)relationsx);
+
+ if(append || readonly)
+    if(ExistsFile(relationsx->trfilename))
+      {
+       off_t size;
+
+       size=SizeFile(relationsx->trfilename);
+
+       relationsx->trnumber=size/sizeof(TurnRelX);
+
+       RenameFile(relationsx->trfilename,relationsx->trfilename_tmp);
+      }
+
+ if(append)
+    relationsx->trfd=OpenFileBufferedAppend(relationsx->trfilename_tmp);
+ else if(!readonly)
+    relationsx->trfd=OpenFileBufferedNew(relationsx->trfilename_tmp);
+ else
+    relationsx->trfd=-1;
+
+ return(relationsx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Free a relation list.
+
+  RelationsX *relationsx The set of relations to be freed.
+
+  int keep If set then the results file is to be kept.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FreeRelationList(RelationsX *relationsx,int keep)
+{
+ /* Route relations */
+
+ if(keep)
+    RenameFile(relationsx->rrfilename_tmp,relationsx->rrfilename);
+ else
+    DeleteFile(relationsx->rrfilename_tmp);
+
+ free(relationsx->rrfilename);
+ free(relationsx->rrfilename_tmp);
+
+ if(relationsx->rridata)
+   {
+    log_free(relationsx->rridata);
+    free(relationsx->rridata);
+   }
+
+ if(relationsx->rrodata)
+   {
+    log_free(relationsx->rrodata);
+    free(relationsx->rrodata);
+   }
+
+
+ /* Turn Restriction relations */
+
+ if(keep)
+    RenameFile(relationsx->trfilename_tmp,relationsx->trfilename);
+ else
+    DeleteFile(relationsx->trfilename_tmp);
+
+ free(relationsx->trfilename);
+ free(relationsx->trfilename_tmp);
+
+ if(relationsx->tridata)
+   {
+    log_free(relationsx->tridata);
+    free(relationsx->tridata);
+   }
+
+
+ free(relationsx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Append a single relation to an unsorted route relation list.
+
+  RelationsX* relationsx The set of relations to process.
+
+  relation_t id The ID of the relation.
+
+  transports_t routes The types of routes that this relation is for.
+
+  node_t *nodes The array of nodes that are members of the relation.
+
+  int nnodes The number of nodes that are members of the relation.
+
+  way_t *ways The array of ways that are members of the relation.
+
+  int nways The number of ways that are members of the relation.
+
+  relation_t *relations The array of relations that are members of the relation.
+
+  int nrelations The number of relations that are members of the relation.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void AppendRouteRelationList(RelationsX* relationsx,relation_t id,
+                             transports_t routes,
+                             node_t *nodes,int nnodes,
+                             way_t *ways,int nways,
+                             relation_t *relations,int nrelations)
+{
+ RouteRelX relationx={0};
+ FILESORT_VARINT size;
+ node_t nonode=NO_NODE_ID;
+ way_t noway=NO_WAY_ID;
+ relation_t norelation=NO_RELATION_ID;
+
+ relationx.id=id;
+ relationx.routes=routes;
+
+ size=sizeof(RouteRelX)+(nnodes+1)*sizeof(node_t)+(nways+1)*sizeof(way_t)+(nrelations+1)*sizeof(relation_t);
+
+ WriteFileBuffered(relationsx->rrfd,&size,FILESORT_VARSIZE);
+ WriteFileBuffered(relationsx->rrfd,&relationx,sizeof(RouteRelX));
+
+ WriteFileBuffered(relationsx->rrfd,nodes  ,nnodes*sizeof(node_t));
+ WriteFileBuffered(relationsx->rrfd,&nonode,       sizeof(node_t));
+
+ WriteFileBuffered(relationsx->rrfd,ways  ,nways*sizeof(way_t));
+ WriteFileBuffered(relationsx->rrfd,&noway,      sizeof(way_t));
+
+ WriteFileBuffered(relationsx->rrfd,relations  ,nrelations*sizeof(relation_t));
+ WriteFileBuffered(relationsx->rrfd,&norelation,           sizeof(relation_t));
+
+ relationsx->rrnumber++;
+
+ logassert(relationsx->rrnumber!=0,"Too many route relations (change index_t to 64-bits?)"); /* Zero marks the high-water mark for relations. */
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Append a single relation to an unsorted turn restriction relation list.
+
+  RelationsX* relationsx The set of relations to process.
+
+  relation_t id The ID of the relation.
+
+  way_t from The way that the turn restriction starts from.
+
+  way_t to The way that the restriction finished on.
+
+  node_t via The node that the turn restriction passes through.
+
+  TurnRestriction restriction The type of restriction.
+
+  transports_t except The set of transports allowed to bypass the restriction.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void AppendTurnRelationList(RelationsX* relationsx,relation_t id,
+                            way_t from,way_t to,node_t via,
+                            TurnRestriction restriction,transports_t except)
+{
+ TurnRelX relationx={0};
+
+ relationx.id=id;
+ relationx.from=from;
+ relationx.to=to;
+ relationx.via=via;
+ relationx.restriction=restriction;
+ relationx.except=except;
+
+ WriteFileBuffered(relationsx->trfd,&relationx,sizeof(TurnRelX));
+
+ relationsx->trnumber++;
+
+ logassert(relationsx->trnumber!=0,"Too many turn relations (change index_t to 64-bits?)"); /* Zero marks the high-water mark for relations. */
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Finish appending relations and change the filename over.
+
+  RelationsX *relationsx The relations that have been appended.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FinishRelationList(RelationsX *relationsx)
+{
+ if(relationsx->rrfd!=-1)
+    relationsx->rrfd =CloseFileBuffered(relationsx->rrfd);
+
+ if(relationsx->trfd!=-1)
+    relationsx->trfd=CloseFileBuffered(relationsx->trfd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find a particular route relation index.
+
+  index_t IndexRouteRelX Returns the index of the route relation with the specified id.
+
+  RelationsX *relationsx The set of relations to process.
+
+  relation_t id The relation id to look for.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t IndexRouteRelX(RelationsX *relationsx,relation_t id)
+{
+ index_t start=0;
+ index_t end=relationsx->rrnumber-1;
+ index_t mid;
+
+ if(relationsx->rrnumber==0)             /* There are no route relations */
+    return(NO_RELATION);
+
+ if(id<relationsx->rridata[start])       /* Key is before start */
+    return(NO_RELATION);
+
+ if(id>relationsx->rridata[end])         /* Key is after end */
+    return(NO_RELATION);
+
+ /* Binary search - search key exact match only is required.
+  *
+  *  # <- start  |  Check mid and move start or end if it doesn't match
+  *  #           |
+  *  #           |  Since an exact match is wanted we can set end=mid-1
+  *  # <- mid    |  or start=mid+1 because we know that mid doesn't match.
+  *  #           |
+  *  #           |  Eventually either end=start or end=start+1 and one of
+  *  # <- end    |  start or end is the wanted one.
+  */
+
+ do
+   {
+    mid=(start+end)/2;                  /* Choose mid point */
+
+    if(relationsx->rridata[mid]<id)      /* Mid point is too low */
+       start=mid+1;
+    else if(relationsx->rridata[mid]>id) /* Mid point is too high */
+       end=mid?(mid-1):mid;
+    else                                /* Mid point is correct */
+       return(mid);
+   }
+ while((end-start)>1);
+
+ if(relationsx->rridata[start]==id)      /* Start is correct */
+    return(start);
+
+ if(relationsx->rridata[end]==id)        /* End is correct */
+    return(end);
+
+ return(NO_RELATION);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find a particular route relation index.
+
+  index_t IndexTurnRelX Returns the index of the turn relation with the specified id.
+
+  RelationsX *relationsx The set of relations to process.
+
+  relation_t id The relation id to look for.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t IndexTurnRelX(RelationsX *relationsx,relation_t id)
+{
+ index_t start=0;
+ index_t end=relationsx->trnumber-1;
+ index_t mid;
+
+ if(relationsx->trnumber==0)            /* There are no route relations */
+    return(NO_RELATION);
+
+ if(id<relationsx->tridata[start])      /* Key is before start */
+    return(NO_RELATION);
+
+ if(id>relationsx->tridata[end])        /* Key is after end */
+    return(NO_RELATION);
+
+ /* Binary search - search key exact match only is required.
+  *
+  *  # <- start  |  Check mid and move start or end if it doesn't match
+  *  #           |
+  *  #           |  Since an exact match is wanted we can set end=mid-1
+  *  # <- mid    |  or start=mid+1 because we know that mid doesn't match.
+  *  #           |
+  *  #           |  Eventually either end=start or end=start+1 and one of
+  *  # <- end    |  start or end is the wanted one.
+  */
+
+ do
+   {
+    mid=(start+end)/2;                   /* Choose mid point */
+
+    if(relationsx->tridata[mid]<id)      /* Mid point is too low */
+       start=mid+1;
+    else if(relationsx->tridata[mid]>id) /* Mid point is too high */
+       end=mid?(mid-1):mid;
+    else                                 /* Mid point is correct */
+       return(mid);
+   }
+ while((end-start)>1);
+
+ if(relationsx->tridata[start]==id)      /* Start is correct */
+    return(start);
+
+ if(relationsx->tridata[end]==id)        /* End is correct */
+    return(end);
+
+ return(NO_RELATION);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the list of relations.
+
+  RelationsX* relationsx The set of relations to process.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SortRelationList(RelationsX* relationsx)
+{
+ /* Route Relations */
+
+ if(relationsx->rrnumber)
+   {
+    index_t rrxnumber;
+    int rrfd;
+
+    /* Print the start message */
+
+    printf_first("Sorting Route Relations");
+
+    /* Re-open the file read-only and a new file writeable */
+
+    rrfd=ReplaceFileBuffered(relationsx->rrfilename_tmp,&relationsx->rrfd);
+
+    /* Sort the relations */
+
+    rrxnumber=relationsx->rrnumber;
+
+    relationsx->rrnumber=filesort_vary(relationsx->rrfd,rrfd,NULL,
+                                                           (int (*)(const void*,const void*))sort_route_by_id,
+                                                           (int (*)(void*,index_t))deduplicate_route_by_id);
+
+    relationsx->rrknumber=relationsx->rrnumber;
+
+    /* Close the files */
+
+    relationsx->rrfd=CloseFileBuffered(relationsx->rrfd);
+    CloseFileBuffered(rrfd);
+
+    /* Print the final message */
+
+    printf_last("Sorted Route Relations: Relations=%"Pindex_t" Duplicates=%"Pindex_t,rrxnumber,rrxnumber-relationsx->rrnumber);
+   }
+
+ /* Turn Restriction Relations. */
+
+ if(relationsx->trnumber)
+   {
+    index_t trxnumber;
+    int trfd;
+
+    /* Print the start message */
+
+    printf_first("Sorting Turn Relations");
+
+    /* Re-open the file read-only and a new file writeable */
+
+    trfd=ReplaceFileBuffered(relationsx->trfilename_tmp,&relationsx->trfd);
+
+    /* Sort the relations */
+
+    trxnumber=relationsx->trnumber;
+
+    relationsx->trnumber=filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRelX),NULL,
+                                                                               (int (*)(const void*,const void*))sort_turn_by_id,
+                                                                               (int (*)(void*,index_t))deduplicate_turn_by_id);
+
+    relationsx->trknumber=relationsx->trnumber;
+
+    /* Close the files */
+
+    relationsx->trfd=CloseFileBuffered(relationsx->trfd);
+    CloseFileBuffered(trfd);
+
+    /* Print the final message */
+
+    printf_last("Sorted Turn Relations: Relations=%"Pindex_t" Duplicates=%"Pindex_t,trxnumber,trxnumber-relationsx->trnumber);
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the route relations into id order.
+
+  int sort_route_by_id Returns the comparison of the id fields.
+
+  RouteRelX *a The first extended relation.
+
+  RouteRelX *b The second extended relation.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int sort_route_by_id(RouteRelX *a,RouteRelX *b)
+{
+ relation_t a_id=a->id;
+ relation_t b_id=b->id;
+
+ if(a_id<b_id)
+    return(-1);
+ else if(a_id>b_id)
+    return(1);
+ else
+    return(-FILESORT_PRESERVE_ORDER(a,b)); /* latest version first */
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Deduplicate the route relations using the id after sorting.
+
+  int deduplicate_route_by_id Return 1 if the value is to be kept, otherwise 0.
+
+  RouteRelX *relationx The extended relation.
+
+  index_t index The number of sorted relations that have already been written to the output file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int deduplicate_route_by_id(RouteRelX *relationx,index_t index)
+{
+ static relation_t previd; /* internal variable (reset by first call in each sort; index==0) */
+
+ if(index==0 || relationx->id!=previd)
+   {
+    previd=relationx->id;
+
+    if(relationx->routes==RELATION_DELETED)
+       return(0);
+    else
+       return(1);
+   }
+ else
+    return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the turn restriction relations into id order.
+
+  int sort_turn_by_id Returns the comparison of the id fields.
+
+  TurnRelX *a The first extended relation.
+
+  TurnRelX *b The second extended relation.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int sort_turn_by_id(TurnRelX *a,TurnRelX *b)
+{
+ relation_t a_id=a->id;
+ relation_t b_id=b->id;
+
+ if(a_id<b_id)
+    return(-1);
+ else if(a_id>b_id)
+    return(1);
+ else
+    return(-FILESORT_PRESERVE_ORDER(a,b)); /* latest version first */
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Deduplicate the turn restriction relations using the id after sorting.
+
+  int deduplicate_turn_by_id Return 1 if the value is to be kept, otherwise 0.
+
+  TurnRelX *relationx The extended relation.
+
+  index_t index The number of sorted relations that have already been written to the output file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int deduplicate_turn_by_id(TurnRelX *relationx,index_t index)
+{
+ static relation_t previd; /* internal variable (reset by first call in each sort; index==0) */
+
+ if(index==0 || relationx->id!=previd)
+   {
+    previd=relationx->id;
+
+    if(relationx->except==RELATION_DELETED)
+       return(0);
+    else
+       return(1);
+   }
+ else
+    return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process the route relations and apply the information to the ways.
+
+  RelationsX *relationsx The set of relations to use.
+
+  WaysX *waysx The set of ways to modify.
+
+  int keep If set to 1 then keep the old data file otherwise delete it.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void ProcessRouteRelations(RelationsX *relationsx,WaysX *waysx,int keep)
+{
+ RouteRelX *unmatched=NULL,*lastunmatched=NULL;
+ int nunmatched=0,lastnunmatched=0,iteration=1;
+
+ if(waysx->number==0)
+    return;
+
+ /* Map into memory / open the files */
+
+#if !SLIM
+ waysx->data=MapFileWriteable(waysx->filename_tmp);
+#else
+ waysx->fd=SlimMapFileWriteable(waysx->filename_tmp);
+
+ InvalidateWayXCache(waysx->cache);
+#endif
+
+ /* Re-open the file read-only */
+
+ relationsx->rrfd=ReOpenFileBuffered(relationsx->rrfilename_tmp);
+
+ /* Read through the file. */
+
+ do
+   {
+    int ways=0,relations=0;
+    index_t i;
+
+    /* Print the start message */
+
+    printf_first("Processing Route Relations (%d): Relations=0 Modified Ways=0",iteration);
+
+    SeekFileBuffered(relationsx->rrfd,0);
+
+    for(i=0;i<relationsx->rrnumber;i++)
+      {
+       FILESORT_VARINT size;
+       RouteRelX relationx;
+       way_t wayid;
+       node_t nodeid;
+       relation_t relationid;
+       transports_t routes=Transports_None;
+
+       /* Read each route relation */
+
+       ReadFileBuffered(relationsx->rrfd,&size,FILESORT_VARSIZE);
+       ReadFileBuffered(relationsx->rrfd,&relationx,sizeof(RouteRelX));
+
+       /* Decide what type of route it is */
+
+       if(iteration==1)
+         {
+          relations++;
+          routes=relationx.routes;
+         }
+       else
+         {
+          int j;
+
+          for(j=0;j<lastnunmatched;j++)
+             if(lastunmatched[j].id==relationx.id)
+               {
+                relations++;
+
+                if((lastunmatched[j].routes|relationx.routes)==relationx.routes)
+                   routes=0; /* Nothing new to add */
+                else
+                   routes=lastunmatched[j].routes;
+
+                break;
+               }
+         }
+
+       /* Skip the nodes */
+
+       while(!ReadFileBuffered(relationsx->rrfd,&nodeid,sizeof(node_t)) && nodeid!=NO_NODE_ID)
+          ;
+
+       /* Loop through the ways */
+
+       while(!ReadFileBuffered(relationsx->rrfd,&wayid,sizeof(way_t)) && wayid!=NO_WAY_ID)
+         {
+          /* Update the ways that are listed for the relation */
+
+          if(routes)
+            {
+             index_t way=IndexWayX(waysx,wayid);
+
+             if(way!=NO_WAY)
+               {
+                WayX *wayx=LookupWayX(waysx,way,1);
+
+                if(routes&Transports_Foot)
+                  {
+                   if(!(wayx->way.allow&Transports_Foot))
+                     {
+                      logerror("Route Relation %"Prelation_t" for Foot contains Way %"Pway_t" that does not allow Foot transport; overriding.\n",logerror_relation(relationx.id),logerror_way(wayid));
+                      wayx->way.allow|=Transports_Foot;
+                     }
+                   wayx->way.props|=Properties_FootRoute;
+                  }
+
+                if(routes&Transports_Bicycle)
+                  {
+                   if(!(wayx->way.allow&Transports_Bicycle))
+                     {
+                      logerror("Route Relation %"Prelation_t" for Bicycle contains Way %"Pway_t" that does not allow Bicycle transport; overriding.\n",logerror_relation(relationx.id),logerror_way(wayid));
+                      wayx->way.allow|=Transports_Bicycle;
+                     }
+                   wayx->way.props|=Properties_BicycleRoute;
+                  }
+
+                PutBackWayX(waysx,wayx);
+
+                ways++;
+               }
+             else
+                logerror("Route Relation %"Prelation_t" contains Way %"Pway_t" that does not exist in the Routino database (not a highway?).\n",logerror_relation(relationx.id),logerror_way(wayid));
+            }
+         }
+
+       /* Loop through the relations */
+
+       while(!ReadFileBuffered(relationsx->rrfd,&relationid,sizeof(relation_t)) && relationid!=NO_RELATION_ID)
+         {
+          /* Add the relations that are listed for this relation to the list for next time */
+
+          if(relationid==relationx.id)
+             logerror("Relation %"Prelation_t" contains itself.\n",logerror_relation(relationx.id));
+          else if(routes)
+            {
+             if(nunmatched%256==0)
+                unmatched=(RouteRelX*)realloc((void*)unmatched,(nunmatched+256)*sizeof(RouteRelX));
+
+             unmatched[nunmatched].id=relationid;
+             unmatched[nunmatched].routes=routes;
+
+             nunmatched++;
+            }
+         }
+
+       if(!((i+1)%1000))
+          printf_middle("Processing Route Relations (%d): Relations=%"Pindex_t" Modified Ways=%"Pindex_t,iteration,relations,ways);
+      }
+
+    if(lastunmatched)
+       free(lastunmatched);
+
+    lastunmatched=unmatched;
+    lastnunmatched=nunmatched;
+
+    unmatched=NULL;
+    nunmatched=0;
+
+    /* Print the final message */
+
+    printf_last("Processed Route Relations (%d): Relations=%"Pindex_t" Modified Ways=%"Pindex_t,iteration,relations,ways);
+   }
+ while(lastnunmatched && iteration++<8);
+
+ if(lastunmatched)
+    free(lastunmatched);
+
+ /* Close the file */
+
+ relationsx->rrfd=CloseFileBuffered(relationsx->rrfd);
+
+ if(keep)
+    RenameFile(relationsx->rrfilename_tmp,relationsx->rrfilename);
+
+ /* Unmap from memory / close the files */
+
+#if !SLIM
+ waysx->data=UnmapFile(waysx->data);
+#else
+ waysx->fd=SlimUnmapFile(waysx->fd);
+#endif
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process the turn relations to update them with node/segment information.
+
+  RelationsX *relationsx The set of relations to modify.
+
+  NodesX *nodesx The set of nodes to use.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  WaysX *waysx The set of ways to use.
+
+  int keep If set to 1 then keep the old data file otherwise delete it.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void ProcessTurnRelations(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,int keep)
+{
+ int trfd;
+ index_t i,total=0,deleted=0;
+
+ if(nodesx->number==0 || segmentsx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Processing Turn Relations: Relations=0 Deleted=0 Added=0");
+
+ /* Map into memory / open the files */
+
+#if !SLIM
+ nodesx->data=MapFileWriteable(nodesx->filename_tmp);
+ segmentsx->data=MapFile(segmentsx->filename_tmp);
+ waysx->data=MapFile(waysx->filename_tmp);
+#else
+ nodesx->fd=SlimMapFileWriteable(nodesx->filename_tmp);
+ segmentsx->fd=SlimMapFile(segmentsx->filename_tmp);
+ waysx->fd=SlimMapFile(waysx->filename_tmp);
+
+ InvalidateNodeXCache(nodesx->cache);
+ InvalidateSegmentXCache(segmentsx->cache);
+ InvalidateWayXCache(waysx->cache);
+#endif
+
+ /* Re-open the file read-only and a new file writeable */
+
+ if(keep)
+   {
+    RenameFile(relationsx->trfilename_tmp,relationsx->trfilename);
+
+    relationsx->trfd=ReOpenFileBuffered(relationsx->trfilename);
+
+    trfd=OpenFileBufferedNew(relationsx->trfilename_tmp);
+   }
+ else
+    trfd=ReplaceFileBuffered(relationsx->trfilename_tmp,&relationsx->trfd);
+
+ /* Process all of the relations */
+
+ for(i=0;i<relationsx->trnumber;i++)
+   {
+    TurnRelX relationx;
+    NodeX *nodex;
+    SegmentX *segmentx;
+    index_t via,from,to;
+
+    ReadFileBuffered(relationsx->trfd,&relationx,sizeof(TurnRelX));
+
+    via =IndexNodeX(nodesx,relationx.via);
+    from=IndexWayX(waysx,relationx.from);
+    to  =IndexWayX(waysx,relationx.to);
+
+    if(via==NO_NODE)
+      {
+       logerror("Turn Relation %"Prelation_t" contains Node %"Pnode_t" that does not exist in the Routino database (not a highway node?).\n",logerror_relation(relationx.id),logerror_node(relationx.via));
+       deleted++;
+       goto endloop;
+      }
+
+    if(from==NO_WAY)
+      {
+       logerror("Turn Relation %"Prelation_t" contains Way %"Pway_t" that does not exist in the Routino database (not a highway?).\n",logerror_relation(relationx.id),logerror_way(relationx.from));
+       deleted++;
+       goto endloop;
+      }
+
+    if(to==NO_WAY)
+      {
+       logerror("Turn Relation %"Prelation_t" contains Way %"Pway_t" that does not exist in the Routino database (not a highway?).\n",logerror_relation(relationx.id),logerror_way(relationx.to));
+       deleted++;
+       goto endloop;
+      }
+
+    relationx.via =via;
+    relationx.from=from;
+    relationx.to  =to;
+
+    if(relationx.restriction==TurnRestrict_no_right_turn ||
+       relationx.restriction==TurnRestrict_no_left_turn ||
+       relationx.restriction==TurnRestrict_no_u_turn ||
+       relationx.restriction==TurnRestrict_no_straight_on)
+      {
+       index_t node_from=NO_NODE,node_to=NO_NODE;
+       int oneway_from=0,oneway_to=0,vehicles_from=1,vehicles_to=1;
+
+       /* Find the segments that join the node 'via' */
+
+       segmentx=FirstSegmentX(segmentsx,relationx.via,1);
+
+       while(segmentx)
+         {
+          if(segmentx->way==relationx.from)
+            {
+             WayX *wayx=LookupWayX(waysx,segmentx->way,1);
+
+             if(node_from!=NO_NODE) /* Only one segment can be on the 'from' way */
+               {
+                logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not at the end of the 'from' way.\n",logerror_relation(relationx.id));
+                deleted++;
+                goto endloop;
+               }
+
+             node_from=OtherNode(segmentx,relationx.via);
+
+             if(IsOnewayFrom(segmentx,relationx.via))
+                oneway_from=1;  /* not allowed */
+
+             if(!(wayx->way.allow&(Transports_Bicycle|Transports_Moped|Transports_Motorcycle|Transports_Motorcar|Transports_Goods|Transports_HGV|Transports_PSV)))
+                vehicles_from=0;  /* not allowed */
+            }
+
+          if(segmentx->way==relationx.to)
+            {
+             WayX *wayx=LookupWayX(waysx,segmentx->way,1);
+
+             if(node_to!=NO_NODE) /* Only one segment can be on the 'to' way */
+               {
+                logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not at the end of the 'to' way.\n",logerror_relation(relationx.id));
+                deleted++;
+                goto endloop;
+               }
+
+             node_to=OtherNode(segmentx,relationx.via);
+
+             if(IsOnewayTo(segmentx,relationx.via))
+                oneway_to=1;  /* not allowed */
+
+             if(!(wayx->way.allow&(Transports_Bicycle|Transports_Moped|Transports_Motorcycle|Transports_Motorcar|Transports_Goods|Transports_HGV|Transports_PSV)))
+                vehicles_to=0;  /* not allowed */
+            }
+
+          segmentx=NextSegmentX(segmentsx,segmentx,relationx.via);
+         }
+
+       if(node_from==NO_NODE)
+          logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not part of the 'from' way.\n",logerror_relation(relationx.id));
+
+       if(node_to==NO_NODE)
+          logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not part of the 'to' way.\n",logerror_relation(relationx.id));
+
+       if(oneway_from)
+          logerror("Turn Relation %"Prelation_t" is not needed because the 'from' way is oneway away from the 'via' node.\n",logerror_relation(relationx.id));
+
+       if(oneway_to)
+          logerror("Turn Relation %"Prelation_t" is not needed because the 'to' way is oneway towards the 'via' node.\n",logerror_relation(relationx.id));
+
+       if(!vehicles_from)
+          logerror("Turn Relation %"Prelation_t" is not needed because the 'from' way does not allow vehicles.\n",logerror_relation(relationx.id));
+
+       if(!vehicles_to)
+          logerror("Turn Relation %"Prelation_t" is not needed because the 'to' way does not allow vehicles.\n",logerror_relation(relationx.id));
+
+       if(oneway_from || oneway_to || !vehicles_from || !vehicles_to || node_from==NO_NODE || node_to==NO_NODE)
+         {
+          deleted++;
+          goto endloop;
+         }
+
+       /* Write the results */
+
+       relationx.from=node_from;
+       relationx.to  =node_to;
+
+       WriteFileBuffered(trfd,&relationx,sizeof(TurnRelX));
+
+       total++;
+      }
+    else
+      {
+       index_t node_from=NO_NODE,node_to=NO_NODE,node_other[MAX_SEG_PER_NODE];
+       int nnodes_other=0,i;
+       int oneway_from=0,vehicles_from=1;
+
+       /* Find the segments that join the node 'via' */
+
+       segmentx=FirstSegmentX(segmentsx,relationx.via,1);
+
+       while(segmentx)
+         {
+          if(segmentx->way==relationx.from)
+            {
+             WayX *wayx=LookupWayX(waysx,segmentx->way,1);
+
+             if(node_from!=NO_NODE) /* Only one segment can be on the 'from' way */
+               {
+                logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not at the end of the 'from' way.\n",logerror_relation(relationx.id));
+                deleted++;
+                goto endloop;
+               }
+
+             node_from=OtherNode(segmentx,relationx.via);
+
+             if(IsOnewayFrom(segmentx,relationx.via))
+                oneway_from=1;  /* not allowed */
+
+             if(!(wayx->way.allow&(Transports_Bicycle|Transports_Moped|Transports_Motorcycle|Transports_Motorcar|Transports_Goods|Transports_HGV|Transports_PSV)))
+                vehicles_from=0;  /* not allowed */
+            }
+
+          if(segmentx->way==relationx.to)
+            {
+             if(node_to!=NO_NODE) /* Only one segment can be on the 'to' way */
+               {
+                logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not at the end of the 'to' way.\n",logerror_relation(relationx.id));
+                deleted++;
+                goto endloop;
+               }
+
+             node_to=OtherNode(segmentx,relationx.via);
+            }
+
+          if(segmentx->way!=relationx.from && segmentx->way!=relationx.to)
+            {
+             WayX *wayx=LookupWayX(waysx,segmentx->way,1);
+
+             if(IsOnewayTo(segmentx,relationx.via))
+                ;  /* not allowed */
+             else if(!(wayx->way.allow&(Transports_Bicycle|Transports_Moped|Transports_Motorcycle|Transports_Motorcar|Transports_Goods|Transports_HGV|Transports_PSV)))
+                ;  /* not allowed */
+             else
+               {
+                logassert(nnodes_other<MAX_SEG_PER_NODE,"Too many segments for one node (increase MAX_SEG_PER_NODE?)"); /* Only a limited amount of information stored. */
+
+                node_other[nnodes_other++]=OtherNode(segmentx,relationx.via);
+               }
+            }
+
+          segmentx=NextSegmentX(segmentsx,segmentx,relationx.via);
+         }
+
+       if(node_from==NO_NODE)
+          logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not part of the 'from' way.\n",logerror_relation(relationx.id));
+
+       if(node_to==NO_NODE)
+          logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not part of the 'to' way.\n",logerror_relation(relationx.id));
+
+       if(nnodes_other==0)
+          logerror("Turn Relation %"Prelation_t" is not needed because the only allowed exit from the 'via' node is the 'to' way.\n",logerror_relation(relationx.id));
+
+       if(oneway_from)
+          logerror("Turn Relation %"Prelation_t" is not needed because the 'from' way is oneway away from the 'via' node.\n",logerror_relation(relationx.id));
+
+       if(!vehicles_from)
+          logerror("Turn Relation %"Prelation_t" is not needed because the 'from' way does not allow vehicles.\n",logerror_relation(relationx.id));
+
+       if(oneway_from || !vehicles_from || node_from==NO_NODE || node_to==NO_NODE || nnodes_other==0)
+         {
+          deleted++;
+          goto endloop;
+         }
+
+       /* Write the results */
+
+       for(i=0;i<nnodes_other;i++)
+         {
+          relationx.from=node_from;
+          relationx.to  =node_other[i];
+
+          WriteFileBuffered(trfd,&relationx,sizeof(TurnRelX));
+
+          total++;
+         }
+      }
+
+    /* Force super nodes on via node and adjacent nodes */
+
+    nodex=LookupNodeX(nodesx,relationx.via,1);
+    nodex->flags|=NODE_TURNRSTRCT;
+    PutBackNodeX(nodesx,nodex);
+
+    segmentx=FirstSegmentX(segmentsx,relationx.via,1);
+
+    while(segmentx)
+      {
+       index_t othernode=OtherNode(segmentx,relationx.via);
+
+       nodex=LookupNodeX(nodesx,othernode,1);
+       nodex->flags|=NODE_TURNRSTRCT2;
+       PutBackNodeX(nodesx,nodex);
+
+       segmentx=NextSegmentX(segmentsx,segmentx,relationx.via);
+      }
+
+   endloop:
+
+    if(!((i+1)%1000))
+       printf_middle("Processing Turn Relations: Relations=%"Pindex_t" Deleted=%"Pindex_t" Added=%"Pindex_t,i+1,deleted,total-relationsx->trnumber+deleted);
+   }
+
+ /* Close the files */
+
+ relationsx->trfd=CloseFileBuffered(relationsx->trfd);
+ CloseFileBuffered(trfd);
+
+ /* Free the now-unneeded indexes */
+
+ log_free(nodesx->idata);
+ free(nodesx->idata);
+ nodesx->idata=NULL;
+
+ log_free(waysx->idata);
+ free(waysx->idata);
+ waysx->idata=NULL;
+
+ log_free(segmentsx->firstnode);
+ free(segmentsx->firstnode);
+ segmentsx->firstnode=NULL;
+
+ /* Unmap from memory / close the files */
+
+#if !SLIM
+ nodesx->data=UnmapFile(nodesx->data);
+ segmentsx->data=UnmapFile(segmentsx->data);
+ waysx->data=UnmapFile(waysx->data);
+#else
+ nodesx->fd=SlimUnmapFile(nodesx->fd);
+ segmentsx->fd=SlimUnmapFile(segmentsx->fd);
+ waysx->fd=SlimUnmapFile(waysx->fd);
+#endif
+
+ /* Print the final message */
+
+ printf_last("Processed Turn Relations: Relations=%"Pindex_t" Deleted=%"Pindex_t" Added=%"Pindex_t,total,deleted,total-relationsx->trnumber+deleted);
+
+ relationsx->trnumber=total;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Remove pruned turn relations and update the node indexes after pruning nodes.
+
+  RelationsX *relationsx The set of relations to modify.
+
+  NodesX *nodesx The set of nodes to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void RemovePrunedTurnRelations(RelationsX *relationsx,NodesX *nodesx)
+{
+ TurnRelX relationx;
+ index_t total=0,pruned=0,notpruned=0;
+ int trfd;
+
+ if(relationsx->trnumber==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Deleting Pruned Turn Relations: Relations=0 Pruned=0");
+
+ /* Re-open the file read-only and a new file writeable */
+
+ trfd=ReplaceFileBuffered(relationsx->trfilename_tmp,&relationsx->trfd);
+
+ /* Process all of the relations */
+
+ while(!ReadFileBuffered(relationsx->trfd,&relationx,sizeof(TurnRelX)))
+   {
+    relationx.from=nodesx->pdata[relationx.from];
+    relationx.via =nodesx->pdata[relationx.via];
+    relationx.to  =nodesx->pdata[relationx.to];
+
+    if(relationx.from==NO_NODE || relationx.via==NO_NODE || relationx.to==NO_NODE)
+       pruned++;
+    else
+      {
+       WriteFileBuffered(trfd,&relationx,sizeof(TurnRelX));
+
+       notpruned++;
+      }
+
+    total++;
+
+    if(!(total%1000))
+       printf_middle("Deleting Pruned Turn Relations: Relations=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
+   }
+
+ relationsx->trnumber=notpruned;
+
+ /* Close the files */
+
+ relationsx->trfd=CloseFileBuffered(relationsx->trfd);
+ CloseFileBuffered(trfd);
+
+ /* Print the final message */
+
+ printf_last("Deleted Pruned Turn Relations: Relations=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the turn relations geographically after updating the node indexes.
+
+  RelationsX *relationsx The set of relations to modify.
+
+  NodesX *nodesx The set of nodes to use.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  int convert Set to 1 to convert the segments as well as sorting them (the second time it is called).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SortTurnRelationListGeographically(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx,int convert)
+{
+ int trfd;
+
+ if(segmentsx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Sorting Turn Relations Geographically");
+
+ /* Map into memory / open the files */
+
+#if !SLIM
+ segmentsx->data=MapFile(segmentsx->filename_tmp);
+#else
+ segmentsx->fd=SlimMapFile(segmentsx->filename_tmp);
+
+ InvalidateSegmentXCache(segmentsx->cache);
+#endif
+
+ /* Re-open the file read-only and a new file writeable */
+
+ trfd=ReplaceFileBuffered(relationsx->trfilename_tmp,&relationsx->trfd);
+
+ /* Update the segments with geographically sorted node indexes and sort them */
+
+ sortnodesx=nodesx;
+ sortsegmentsx=segmentsx;
+
+ if(!convert)
+    filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRelX),(int (*)(void*,index_t))geographically_index,
+                                                          (int (*)(const void*,const void*))sort_by_via,
+                                                          NULL);
+ else
+    filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRelX),(int (*)(void*,index_t))geographically_index_convert_segments,
+                                                          (int (*)(const void*,const void*))sort_by_via,
+                                                          NULL);
+
+ /* Close the files */
+
+ relationsx->trfd=CloseFileBuffered(relationsx->trfd);
+ CloseFileBuffered(trfd);
+
+ /* Unmap from memory / close the files */
+
+#if !SLIM
+ segmentsx->data=UnmapFile(segmentsx->data);
+#else
+ segmentsx->fd=SlimUnmapFile(segmentsx->fd);
+#endif
+
+ /* Free the memory */
+
+ if(nodesx->gdata)
+   {
+    log_free(nodesx->gdata);
+    free(nodesx->gdata);
+    nodesx->gdata=NULL;
+   }
+
+ /* Print the final message */
+
+ printf_last("Sorted Turn Relations Geographically: Turn Relations=%"Pindex_t,relationsx->trnumber);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Update the turn relation indexes.
+
+  int geographically_index Return 1 if the value is to be kept, otherwise 0.
+
+  TurnRelX *relationx The extended turn relation.
+
+  index_t index The number of unsorted turn relations that have been read from the input file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int geographically_index(TurnRelX *relationx,index_t index)
+{
+ relationx->from=sortnodesx->gdata[relationx->from];
+ relationx->via =sortnodesx->gdata[relationx->via];
+ relationx->to  =sortnodesx->gdata[relationx->to];
+
+ return(1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Update the turn relation indexes and replace them with segments.
+
+  int geographically_index_convert_segments Return 1 if the value is to be kept, otherwise 0.
+
+  TurnRelX *relationx The extended turn relation.
+
+  index_t index The number of unsorted turn relations that have been read from the input file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int geographically_index_convert_segments(TurnRelX *relationx,index_t index)
+{
+ SegmentX *segmentx;
+ index_t from_node,via_node,to_node;
+
+ from_node=sortnodesx->gdata[relationx->from];
+ via_node =sortnodesx->gdata[relationx->via];
+ to_node  =sortnodesx->gdata[relationx->to];
+
+ segmentx=FirstSegmentX(sortsegmentsx,via_node,1);
+
+ do
+   {
+    if(OtherNode(segmentx,via_node)==from_node)
+       relationx->from=IndexSegmentX(sortsegmentsx,segmentx);
+
+    if(OtherNode(segmentx,via_node)==to_node)
+       relationx->to=IndexSegmentX(sortsegmentsx,segmentx);
+
+    segmentx=NextSegmentX(sortsegmentsx,segmentx,via_node);
+   }
+ while(segmentx);
+
+ relationx->via=via_node;
+
+ return(1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the turn restriction relations into via index order (then by from and to segments).
+
+  int sort_by_via Returns the comparison of the via, from and to fields.
+
+  TurnRelX *a The first extended relation.
+
+  TurnRelX *b The second extended relation.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int sort_by_via(TurnRelX *a,TurnRelX *b)
+{
+ index_t a_id=a->via;
+ index_t b_id=b->via;
+
+ if(a_id<b_id)
+    return(-1);
+ else if(a_id>b_id)
+    return(1);
+ else
+   {
+    index_t a_id=a->from;
+    index_t b_id=b->from;
+
+    if(a_id<b_id)
+       return(-1);
+    else if(a_id>b_id)
+       return(1);
+    else
+      {
+       index_t a_id=a->to;
+       index_t b_id=b->to;
+
+       if(a_id<b_id)
+          return(-1);
+       else if(a_id>b_id)
+          return(1);
+       else
+          return(FILESORT_PRESERVE_ORDER(a,b));
+      }
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Save the relation list to a file.
+
+  RelationsX* relationsx The set of relations to save.
+
+  const char *filename The name of the file to save.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SaveRelationList(RelationsX* relationsx,const char *filename)
+{
+ index_t i;
+ int fd;
+ RelationsFile relationsfile={0};
+
+ /* Print the start message */
+
+ printf_first("Writing Relations: Turn Relations=0");
+
+ /* Re-open the file read-only */
+
+ relationsx->trfd=ReOpenFileBuffered(relationsx->trfilename_tmp);
+
+ /* Write out the relations data */
+
+ fd=OpenFileBufferedNew(filename);
+
+ SeekFileBuffered(fd,sizeof(RelationsFile));
+
+ for(i=0;i<relationsx->trnumber;i++)
+   {
+    TurnRelX relationx;
+    TurnRelation relation={0};
+
+    ReadFileBuffered(relationsx->trfd,&relationx,sizeof(TurnRelX));
+
+    relation.from=relationx.from;
+    relation.via=relationx.via;
+    relation.to=relationx.to;
+    relation.except=relationx.except;
+
+    WriteFileBuffered(fd,&relation,sizeof(TurnRelation));
+
+    if(!((i+1)%1000))
+       printf_middle("Writing Relations: Turn Relations=%"Pindex_t,i+1);
+   }
+
+ /* Write out the header structure */
+
+ relationsfile.trnumber=relationsx->trnumber;
+
+ SeekFileBuffered(fd,0);
+ WriteFileBuffered(fd,&relationsfile,sizeof(RelationsFile));
+
+ CloseFileBuffered(fd);
+
+ /* Close the file */
+
+ relationsx->trfd=CloseFileBuffered(relationsx->trfd);
+
+ /* Print the final message */
+
+ printf_last("Wrote Relations: Turn Relations=%"Pindex_t,relationsx->trnumber);
+}
diff --git a/3rdparty/Routino/src/relationsx.h b/3rdparty/Routino/src/relationsx.h
new file mode 100644
index 0000000..f12e4cd
--- /dev/null
+++ b/3rdparty/Routino/src/relationsx.h
@@ -0,0 +1,120 @@
+/***************************************
+ A header file for the extended Relations structure.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef RELATIONSX_H
+#define RELATIONSX_H    /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+
+#include "types.h"
+
+#include "typesx.h"
+
+
+/* Data structures */
+
+
+/*+ An extended structure containing a single route relation. +*/
+struct _RouteRelX
+{
+ relation_t   id;              /*+ The relation identifier. +*/
+
+ transports_t routes;          /*+ The types of transports that that this relation is for. +*/
+};
+
+
+/*+ An extended structure containing a single turn restriction relation. +*/
+struct _TurnRelX
+{
+ relation_t      id;           /*+ The relation identifier. +*/
+
+ way_t           from;         /*+ The id of the starting way; initially the OSM value, later the SegmentX index. +*/
+ node_t          via;          /*+ The id of the via node; initially the OSM value, later the NodeX index. +*/
+ way_t           to;           /*+ The id of the ending way; initially the OSM value, later the SegmentX index. +*/
+
+ TurnRestriction restriction;  /*+ The type of restriction. +*/
+ transports_t    except;       /*+ The types of transports that that this relation does not apply to. +*/
+};
+
+
+/*+ A structure containing a set of relations. +*/
+struct _RelationsX
+{
+ /* Route relations */
+
+ char       *rrfilename;       /*+ The name of the intermediate file (for the RouteRelX). +*/
+ char       *rrfilename_tmp;   /*+ The name of the temporary file (for the RouteRelX). +*/
+
+ int         rrfd;             /*+ The file descriptor of the open file (for the RouteRelX). +*/
+
+ index_t     rrnumber;         /*+ The number of extended route relations. +*/
+ index_t     rrknumber;        /*+ The number of extended route relations kept for next time. +*/
+
+ relation_t *rridata;          /*+ The extended relation IDs (sorted by ID). +*/
+ off_t      *rrodata;          /*+ The offset of the route relation in the file (used for error log). +*/
+
+ /* Turn restriction relations */
+
+ char       *trfilename;       /*+ The name of the intermediate file (for the TurnRelX). +*/
+ char       *trfilename_tmp;   /*+ The name of the temporary file (for the TurnRelX). +*/
+
+ int         trfd;             /*+ The file descriptor of the temporary file (for the TurnRelX). +*/
+
+ index_t     trnumber;         /*+ The number of extended turn restriction relations. +*/
+ index_t     trknumber;        /*+ The number of extended turn relations kept for next time. +*/
+
+ relation_t *tridata;          /*+ The extended relation IDs (sorted by ID). +*/
+};
+
+
+/* Functions in relationsx.c */
+
+RelationsX *NewRelationList(int append,int readonly);
+void FreeRelationList(RelationsX *relationsx,int keep);
+
+void AppendRouteRelationList(RelationsX* relationsx,relation_t id,
+                             transports_t routes,
+                             node_t *nodes,int nnodes,
+                             way_t *ways,int nways,
+                             relation_t *relations,int nrelations);
+void AppendTurnRelationList(RelationsX* relationsx,relation_t id,
+                            way_t from,way_t to,node_t via,
+                            TurnRestriction restriction,transports_t except);
+void FinishRelationList(RelationsX *relationsx);
+
+index_t IndexRouteRelX(RelationsX *relationsx,relation_t id);
+index_t IndexTurnRelX(RelationsX *relationsx,relation_t id);
+
+void SortRelationList(RelationsX *relationsx);
+
+void ProcessRouteRelations(RelationsX *relationsx,WaysX *waysx,int keep);
+
+void ProcessTurnRelations(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,int keep);
+
+void RemovePrunedTurnRelations(RelationsX *relationsx,NodesX *nodesx);
+
+void SortTurnRelationListGeographically(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx,int convert);
+
+void SaveRelationList(RelationsX* relationsx,const char *filename);
+
+
+#endif /* RELATIONSX_H */
diff --git a/3rdparty/Routino/src/results.c b/3rdparty/Routino/src/results.c
new file mode 100644
index 0000000..0496798
--- /dev/null
+++ b/3rdparty/Routino/src/results.c
@@ -0,0 +1,334 @@
+/***************************************
+ Result data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "results.h"
+
+#include "logging.h"
+
+
+#define HASH_NODE_SEGMENT(node,segment) ((node)^(segment<<4))
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Allocate a new results list.
+
+  Results *NewResultsList Returns the results list.
+
+  uint8_t log2bins The base 2 logarithm of the initial number of bins in the results array.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Results *NewResultsList(uint8_t log2bins)
+{
+ Results *results;
+
+ results=(Results*)malloc(sizeof(Results));
+
+ results->nbins=1<<log2bins;
+ results->mask=results->nbins-1;
+ results->ncollisions=log2bins-4;
+
+ results->number=0;
+
+ results->count=(uint8_t*)calloc(results->nbins,sizeof(uint8_t));
+ results->point=(Result**)calloc(results->nbins,sizeof(Result*));
+
+#ifndef LIBROUTINO
+ log_malloc(results->count,results->nbins*sizeof(uint8_t));
+ log_malloc(results->point,results->nbins*sizeof(Result*));
+#endif
+
+ results->ndata1=0;
+ results->nallocdata1=0;
+ results->ndata2=results->nbins>>2;
+
+ results->data=NULL;
+
+ results->start_node=NO_NODE;
+ results->prev_segment=NO_SEGMENT;
+
+ results->finish_node=NO_NODE;
+ results->last_segment=NO_SEGMENT;
+
+ results->start_waypoint=NO_WAYPOINT;
+ results->finish_waypoint=NO_WAYPOINT;
+
+ return(results);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Allocate a new results list.
+
+  Results *results The results list to be reset.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void ResetResultsList(Results *results)
+{
+ uint32_t i;
+
+ results->number=0;
+ results->ndata1=0;
+
+ for(i=0;i<results->nbins;i++)
+   {
+    results->point[i]=NULL;
+    results->count[i]=0;
+   }
+
+ results->start_node=NO_NODE;
+ results->prev_segment=NO_SEGMENT;
+
+ results->finish_node=NO_NODE;
+ results->last_segment=NO_SEGMENT;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Free a results list.
+
+  Results *results The results list to be destroyed.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FreeResultsList(Results *results)
+{
+ uint32_t i;
+
+ for(i=0;i<results->nallocdata1;i++)
+   {
+#ifndef LIBROUTINO
+    log_free(results->data[i]);
+#endif
+    free(results->data[i]);
+   }
+
+ free(results->data);
+
+#ifndef LIBROUTINO
+ log_free(results->point);
+#endif
+ free(results->point);
+
+#ifndef LIBROUTINO
+ log_free(results->count);
+#endif
+ free(results->count);
+
+ free(results);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Insert a new result into the results data structure in the right order.
+
+  Result *InsertResult Returns the result that has been inserted.
+
+  Results *results The results structure to insert into.
+
+  index_t node The node that is to be inserted into the results.
+
+  index_t segment The segment that is to be inserted into the results.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Result *InsertResult(Results *results,index_t node,index_t segment)
+{
+ Result *result;
+ uint32_t bin=HASH_NODE_SEGMENT(node,segment)&results->mask;
+
+ /* Check if we have hit the limit on the number of collisions per bin */
+
+ if(results->count[bin]==results->ncollisions)
+   {
+    uint32_t i;
+
+    results->nbins<<=1;
+    results->mask=results->nbins-1;
+    results->ncollisions++;
+
+    results->count=(uint8_t*)realloc((void*)results->count,results->nbins*sizeof(uint8_t));
+    results->point=(Result**)realloc((void*)results->point,results->nbins*sizeof(Result*));
+
+#ifndef LIBROUTINO
+    log_malloc(results->count,results->nbins*sizeof(uint8_t));
+    log_malloc(results->point,results->nbins*sizeof(Result*));
+#endif
+
+    for(i=0;i<results->nbins/2;i++)
+      {
+       Result *r=results->point[i];
+       Result **bin1,**bin2;
+
+       results->count[i]                 =0;
+       results->count[i+results->nbins/2]=0;
+
+       bin1=&results->point[i];
+       bin2=&results->point[i+results->nbins/2];
+
+       *bin1=NULL;
+       *bin2=NULL;
+
+       while(r)
+         {
+          Result *rh=r->hashnext;
+          uint32_t newbin=HASH_NODE_SEGMENT(r->node,r->segment)&results->mask;
+
+          r->hashnext=NULL;
+
+          if(newbin==i)
+            { *bin1=r; bin1=&r->hashnext; }
+          else
+            { *bin2=r; bin2=&r->hashnext; }
+
+          results->count[newbin]++;
+
+          r=rh;
+         }
+      }
+
+    bin=HASH_NODE_SEGMENT(node,segment)&results->mask;
+   }
+
+ /* Check if we need more data space allocated */
+
+ if((results->number%results->ndata2)==0)
+   {
+    results->ndata1++;
+
+    if(results->ndata1>=results->nallocdata1)
+      {
+       results->nallocdata1++;
+       results->data=(Result**)realloc((void*)results->data,results->nallocdata1*sizeof(Result*));
+       results->data[results->nallocdata1-1]=(Result*)malloc(results->ndata2*sizeof(Result));
+#ifndef LIBROUTINO
+       log_malloc(results->data[results->nallocdata1-1],results->ndata2*sizeof(Result));
+#endif
+      }
+   }
+
+ /* Insert the new entry */
+
+ result=&results->data[results->ndata1-1][results->number%results->ndata2];
+
+ result->hashnext=results->point[bin];
+
+ results->point[bin]=result;
+
+ results->count[bin]++;
+
+ results->number++;
+
+ /* Initialise the result */
+
+ result->node=node;
+ result->segment=segment;
+
+ result->prev=NULL;
+ result->next=NULL;
+
+ result->score=0;
+ result->sortby=0;
+
+ result->queued=NOT_QUEUED;
+
+ return(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find a result; search by node and segment.
+
+  Result *FindResult Returns the result that has been found.
+
+  Results *results The results structure to search.
+
+  index_t node The node that is to be found.
+
+  index_t segment The segment that was used to reach this node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Result *FindResult(Results *results,index_t node,index_t segment)
+{
+ Result *r;
+ uint32_t bin=HASH_NODE_SEGMENT(node,segment)&results->mask;
+
+ r=results->point[bin];
+
+ while(r)
+   {
+    if(r->segment==segment && r->node==node)
+       break;
+
+    r=r->hashnext;
+   }
+
+ return(r);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the first result from a set of results.
+
+  Result *FirstResult Returns the first result.
+
+  Results *results The set of results.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Result *FirstResult(Results *results)
+{
+ return(&results->data[0][0]);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the next result from a set of results.
+
+  Result *NextResult Returns the next result.
+
+  Results *results The set of results.
+
+  Result *result The previous result.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Result *NextResult(Results *results,Result *result)
+{
+ uint32_t i;
+ size_t j=0;
+
+ for(i=0;i<results->ndata1;i++)
+    if(result>=results->data[i])
+      {
+       j=result-results->data[i];
+
+       if(j<results->ndata2)
+          break;
+      }
+
+ if(++j>=results->ndata2)
+   {i++;j=0;}
+
+ if((i*results->ndata2+j)>=results->number)
+    return(NULL);
+
+ return(&results->data[i][j]);
+}
diff --git a/3rdparty/Routino/src/results.h b/3rdparty/Routino/src/results.h
new file mode 100644
index 0000000..736211b
--- /dev/null
+++ b/3rdparty/Routino/src/results.h
@@ -0,0 +1,122 @@
+/***************************************
+ A header file for the results.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2014 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef RESULTS_H
+#define RESULTS_H    /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+
+#include "types.h"
+
+
+/* Constants */
+
+/*+ A result is not currently queued. +*/
+#define NOT_QUEUED (uint32_t)(0)
+
+
+/* Data structures */
+
+typedef struct _Result Result;
+
+/*+ The result for a node. +*/
+struct _Result
+{
+ index_t   node;                /*+ The node for which this result applies. +*/
+ index_t   segment;             /*+ The segmemt used to get to the node for which this result applies. +*/
+
+ Result   *prev;                /*+ The previous result following the best path to get to this node via the segment. +*/
+ Result   *next;                /*+ The next result following the best path from this node that was reached via the segment. +*/
+
+ score_t   score;               /*+ The best actual weighted distance or duration score from the start to the node. +*/
+ score_t   sortby;              /*+ The best possible weighted distance or duration score from the start to the finish. +*/
+
+ uint32_t  queued;              /*+ The position of this result in the queue. +*/
+
+ Result   *hashnext;            /*+ The next result in the linked list for this hash bin. +*/
+};
+
+/*+ A list of results. +*/
+typedef struct _Results
+{
+ uint32_t  nbins;               /*+ The number of bins in the has table. +*/
+ uint32_t  mask;                /*+ A bit mask to select the bottom log2(nbins) bits. +*/
+
+ uint32_t  number;              /*+ The total number of occupied results. +*/
+
+ uint8_t   ncollisions;         /*+ The number of results allowed in each hash bin. +*/
+ uint8_t  *count;               /*+ An array of nbins counters of results in each hash bin. +*/
+
+ Result  **point;               /*+ An array of nbins linked lists of results for one hash bin. +*/
+
+ uint32_t  ndata1;              /*+ The size of the first dimension of the 'data' array. +*/
+ uint32_t  ndata2;              /*+ The size of the second dimension of the 'data' array. +*/
+
+ uint32_t  nallocdata1;         /*+ The amount of allocated space in the first dimension of the 'data' array. +*/
+
+ Result  **data;                /*+ An array of arrays containing the actual results, the first
+                                    dimension is reallocated but the second dimension is not.
+                                    Most importantly pointers into the real data don't change
+                                    as more space is allocated (since realloc is not being used). +*/
+
+ index_t start_node;            /*+ The start node. +*/
+ index_t prev_segment;          /*+ The previous segment to get to the start node (if any). +*/
+
+ index_t finish_node;           /*+ The finish node. +*/
+ index_t last_segment;          /*+ The last segment (to arrive at the finish node). +*/
+
+ waypoint_t start_waypoint;     /*+ The number of the starting waypoint. +*/
+ waypoint_t finish_waypoint;    /*+ The number of the finish waypoint. +*/
+}
+ Results;
+
+
+/* Forward definition for opaque type */
+
+typedef struct _Queue Queue;
+
+
+/* Results functions in results.c */
+
+Results *NewResultsList(uint8_t log2bins);
+void ResetResultsList(Results *results);
+void FreeResultsList(Results *results);
+
+Result *InsertResult(Results *results,index_t node,index_t segment);
+
+Result *FindResult(Results *results,index_t node,index_t segment);
+
+Result *FirstResult(Results *results);
+Result *NextResult(Results *results,Result *result);
+
+
+/* Queue functions in queue.c */
+
+Queue *NewQueueList(uint8_t log2bins);
+void ResetQueueList(Queue *queue);
+void FreeQueueList(Queue *queue);
+
+void InsertInQueue(Queue *queue,Result *result,score_t score);
+Result *PopFromQueue(Queue *queue);
+
+
+#endif /* RESULTS_H */
diff --git a/3rdparty/Routino/src/router.c b/3rdparty/Routino/src/router.c
new file mode 100644
index 0000000..571dc07
--- /dev/null
+++ b/3rdparty/Routino/src/router.c
@@ -0,0 +1,955 @@
+/***************************************
+ OSM router.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "types.h"
+#include "nodes.h"
+#include "segments.h"
+#include "ways.h"
+#include "relations.h"
+
+#include "files.h"
+#include "logging.h"
+#include "functions.h"
+#include "fakes.h"
+#include "translations.h"
+#include "profiles.h"
+
+
+/*+ To help when debugging +*/
+#define DEBUG 0
+
+/*+ The maximum distance from the specified point to search for a node or segment (in km). +*/
+#define MAXSEARCH  1
+
+
+/* Global variables */
+
+/*+ The option not to print any progress information. +*/
+int option_quiet=0;
+
+/*+ The options to select the format of the output. +*/
+int option_html=0,option_gpx_track=0,option_gpx_route=0,option_text=0,option_text_all=0,option_none=0,option_stdout=0;
+
+/*+ The option to calculate the quickest route insted of the shortest. +*/
+int option_quickest=0;
+
+
+/* Local functions */
+
+static void print_usage(int detail,const char *argerr,const char *err);
+
+static Results *CalculateRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,
+                               index_t start_node,index_t prev_segment,index_t finish_node,
+                               int start_waypoint,int finish_waypoint);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The main program for the router.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int main(int argc,char** argv)
+{
+ Nodes     *OSMNodes;
+ Segments  *OSMSegments;
+ Ways      *OSMWays;
+ Relations *OSMRelations;
+ Results   *results[NWAYPOINTS+1]={NULL};
+ int        point_used[NWAYPOINTS+1]={0};
+ double     point_lon[NWAYPOINTS+1],point_lat[NWAYPOINTS+1];
+ double     heading=-999;
+ int        help_profile=0,help_profile_xml=0,help_profile_json=0,help_profile_pl=0;
+ char      *dirname=NULL,*prefix=NULL;
+ char      *profiles=NULL,*profilename=NULL;
+ char      *translations=NULL,*language=NULL;
+ int        exactnodes=0,reverse=0,loop=0;
+ Transport  transport=Transport_None;
+ Profile   *profile=NULL;
+ index_t    start_node,finish_node=NO_NODE,first_node=NO_NODE;
+ index_t    join_segment=NO_SEGMENT;
+ int        arg,nresults=0;
+ waypoint_t start_waypoint,finish_waypoint=NO_WAYPOINT;
+ waypoint_t first_waypoint=NWAYPOINTS,last_waypoint=1,inc_dec_waypoint,waypoint;
+
+#if !DEBUG
+ printf_program_start();
+#endif
+
+ /* Parse the command line arguments */
+
+ if(argc<2)
+    print_usage(0,NULL,NULL);
+
+ /* Get the non-routing, general program options */
+
+ for(arg=1;arg<argc;arg++)
+   {
+    if(!strcmp(argv[arg],"--help"))
+       print_usage(1,NULL,NULL);
+    else if(!strcmp(argv[arg],"--help-profile"))
+       help_profile=1;
+    else if(!strcmp(argv[arg],"--help-profile-xml"))
+       help_profile_xml=1;
+    else if(!strcmp(argv[arg],"--help-profile-json"))
+       help_profile_json=1;
+    else if(!strcmp(argv[arg],"--help-profile-perl"))
+       help_profile_pl=1;
+    else if(!strncmp(argv[arg],"--dir=",6))
+       dirname=&argv[arg][6];
+    else if(!strncmp(argv[arg],"--prefix=",9))
+       prefix=&argv[arg][9];
+    else if(!strncmp(argv[arg],"--profiles=",11))
+       profiles=&argv[arg][11];
+    else if(!strncmp(argv[arg],"--translations=",15))
+       translations=&argv[arg][15];
+    else if(!strcmp(argv[arg],"--exact-nodes-only"))
+       exactnodes=1;
+    else if(!strcmp(argv[arg],"--reverse"))
+       reverse=1;
+    else if(!strcmp(argv[arg],"--loop"))
+       loop=1;
+    else if(!strcmp(argv[arg],"--quiet"))
+       option_quiet=1;
+    else if(!strcmp(argv[arg],"--loggable"))
+       option_loggable=1;
+    else if(!strcmp(argv[arg],"--logtime"))
+       option_logtime=2;
+    else if(!strcmp(argv[arg],"--logmemory"))
+       option_logmemory=1;
+    else if(!strcmp(argv[arg],"--output-html"))
+       option_html=1;
+    else if(!strcmp(argv[arg],"--output-gpx-track"))
+       option_gpx_track=1;
+    else if(!strcmp(argv[arg],"--output-gpx-route"))
+       option_gpx_route=1;
+    else if(!strcmp(argv[arg],"--output-text"))
+       option_text=1;
+    else if(!strcmp(argv[arg],"--output-text-all"))
+       option_text_all=1;
+    else if(!strcmp(argv[arg],"--output-none"))
+       option_none=1;
+    else if(!strcmp(argv[arg],"--output-stdout"))
+      { option_stdout=1; option_quiet=1; }
+    else if(!strncmp(argv[arg],"--profile=",10))
+       profilename=&argv[arg][10];
+    else if(!strncmp(argv[arg],"--language=",11))
+       language=&argv[arg][11];
+    else if(!strncmp(argv[arg],"--transport=",12))
+      {
+       transport=TransportType(&argv[arg][12]);
+
+       if(transport==Transport_None)
+          print_usage(0,argv[arg],NULL);
+      }
+    else
+       continue;
+
+    argv[arg]=NULL;
+   }
+
+ /* Check the specified command line options */
+
+ if(option_stdout && (option_html+option_gpx_track+option_gpx_route+option_text+option_text_all)!=1)
+   {
+    fprintf(stderr,"Error: The '--output-stdout' option requires exactly one other output option (but not '--output-none').\n");
+    exit(EXIT_FAILURE);
+   }
+
+ /* Load in the profiles */
+
+ if(transport==Transport_None)
+    transport=Transport_Motorcar;
+
+ if(profiles)
+   {
+    if(!ExistsFile(profiles))
+      {
+       fprintf(stderr,"Error: The '--profiles' option specifies a file that does not exist.\n");
+       exit(EXIT_FAILURE);
+      }
+   }
+ else
+   {
+    profiles=FileName(dirname,prefix,"profiles.xml");
+
+    if(!ExistsFile(profiles))
+      {
+       free(profiles);
+
+       profiles=FileName(ROUTINO_DATADIR,NULL,"profiles.xml");
+
+       if(!ExistsFile(profiles))
+         {
+          fprintf(stderr,"Error: The '--profiles' option was not used and the default 'profiles.xml' does not exist.\n");
+          exit(EXIT_FAILURE);
+         }
+      }
+   }
+
+ if(ParseXMLProfiles(profiles))
+   {
+    fprintf(stderr,"Error: Cannot read the profiles in the file '%s'.\n",profiles);
+    exit(EXIT_FAILURE);
+   }
+
+ /* Choose the selected profile. */
+
+ if(profilename)
+   {
+    profile=GetProfile(profilename);
+
+    if(!profile)
+      {
+       fprintf(stderr,"Error: Cannot find a profile called '%s' in '%s'.\n",profilename,profiles);
+       exit(EXIT_FAILURE);
+      }
+   }
+ else
+    profile=GetProfile(TransportName(transport));
+
+ if(!profile)
+   {
+    profile=(Profile*)calloc(1,sizeof(Profile));
+    profile->transport=transport;
+   }
+
+ /* Parse the other command line arguments */
+
+ for(arg=1;arg<argc;arg++)
+   {
+    if(!argv[arg])
+       continue;
+    else if(!strcmp(argv[arg],"--shortest"))
+       option_quickest=0;
+    else if(!strcmp(argv[arg],"--quickest"))
+       option_quickest=1;
+    else if(!strncmp(argv[arg],"--lon",5) && isdigit(argv[arg][5]))
+      {
+       int point;
+       char *p=&argv[arg][6];
+
+       while(isdigit(*p)) p++;
+       if(*p++!='=')
+          print_usage(0,argv[arg],NULL);
+ 
+       point=atoi(&argv[arg][5]);
+       if(point>NWAYPOINTS || point_used[point]&1)
+          print_usage(0,argv[arg],NULL);
+ 
+       point_lon[point]=degrees_to_radians(atof(p));
+       point_used[point]+=1;
+
+       if(point<first_waypoint)
+          first_waypoint=point;
+       if(point>last_waypoint)
+          last_waypoint=point;
+      }
+    else if(!strncmp(argv[arg],"--lat",5) && isdigit(argv[arg][5]))
+      {
+       int point;
+       char *p=&argv[arg][6];
+
+       while(isdigit(*p)) p++;
+       if(*p++!='=')
+          print_usage(0,argv[arg],NULL);
+ 
+       point=atoi(&argv[arg][5]);
+       if(point>NWAYPOINTS || point_used[point]&2)
+          print_usage(0,argv[arg],NULL);
+ 
+       point_lat[point]=degrees_to_radians(atof(p));
+       point_used[point]+=2;
+
+       if(point<first_waypoint)
+          first_waypoint=point;
+       if(point>last_waypoint)
+          last_waypoint=point;
+      }
+    else if(!strncmp(argv[arg],"--heading=",10))
+      {
+       double h=atof(&argv[arg][10]);
+
+       if(h>=-360 && h<=360)
+         {
+          heading=h;
+
+          if(heading<0) heading+=360;
+         }
+      }
+    else if(!strncmp(argv[arg],"--transport=",12))
+       ; /* Done this already */
+    else if(!strncmp(argv[arg],"--highway-",10))
+      {
+       Highway highway;
+       char *equal=strchr(argv[arg],'=');
+       char *string;
+
+       if(!equal)
+           print_usage(0,argv[arg],NULL);
+
+       string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+10);
+       string[equal-argv[arg]-10]=0;
+
+       highway=HighwayType(string);
+
+       if(highway==Highway_None)
+          print_usage(0,argv[arg],NULL);
+
+       profile->highway[highway]=(score_t)atof(equal+1);
+
+       free(string);
+      }
+    else if(!strncmp(argv[arg],"--speed-",8))
+      {
+       Highway highway;
+       char *equal=strchr(argv[arg],'=');
+       char *string;
+
+       if(!equal)
+          print_usage(0,argv[arg],NULL);
+
+       string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+8);
+       string[equal-argv[arg]-8]=0;
+
+       highway=HighwayType(string);
+
+       if(highway==Highway_None)
+          print_usage(0,argv[arg],NULL);
+
+       profile->speed[highway]=kph_to_speed(atof(equal+1));
+
+       free(string);
+      }
+    else if(!strncmp(argv[arg],"--property-",11))
+      {
+       Property property;
+       char *equal=strchr(argv[arg],'=');
+       char *string;
+
+       if(!equal)
+          print_usage(0,argv[arg],NULL);
+
+       string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+11);
+       string[equal-argv[arg]-11]=0;
+
+       property=PropertyType(string);
+
+       if(property==Property_None)
+          print_usage(0,argv[arg],NULL);
+
+       profile->props_yes[property]=(score_t)atof(equal+1);
+
+       free(string);
+      }
+    else if(!strncmp(argv[arg],"--oneway=",9))
+       profile->oneway=!!atoi(&argv[arg][9]);
+    else if(!strncmp(argv[arg],"--turns=",8))
+       profile->turns=!!atoi(&argv[arg][8]);
+    else if(!strncmp(argv[arg],"--weight=",9))
+       profile->weight=tonnes_to_weight(atof(&argv[arg][9]));
+    else if(!strncmp(argv[arg],"--height=",9))
+       profile->height=metres_to_height(atof(&argv[arg][9]));
+    else if(!strncmp(argv[arg],"--width=",8))
+       profile->width=metres_to_width(atof(&argv[arg][8]));
+    else if(!strncmp(argv[arg],"--length=",9))
+       profile->length=metres_to_length(atof(&argv[arg][9]));
+    else
+       print_usage(0,argv[arg],NULL);
+   }
+
+ /* Print one of the profiles if requested */
+
+ if(help_profile)
+   {
+    PrintProfile(profile);
+
+    exit(EXIT_SUCCESS);
+   }
+ else if(help_profile_xml)
+   {
+    PrintProfilesXML();
+
+    exit(EXIT_SUCCESS);
+   }
+ else if(help_profile_json)
+   {
+    PrintProfilesJSON();
+
+    exit(EXIT_SUCCESS);
+   }
+ else if(help_profile_pl)
+   {
+    PrintProfilesPerl();
+
+    exit(EXIT_SUCCESS);
+   }
+
+ /* Check the waypoints are valid */
+
+ for(waypoint=1;waypoint<=NWAYPOINTS;waypoint++)
+    if(point_used[waypoint]==1 || point_used[waypoint]==2)
+       print_usage(0,NULL,"All waypoints must have latitude and longitude.");
+
+ if(first_waypoint>=last_waypoint)
+    print_usage(0,NULL,"At least two waypoints must be specified.");
+
+ /* Load in the translations */
+
+ if(option_html==0 && option_gpx_track==0 && option_gpx_route==0 && option_text==0 && option_text_all==0 && option_none==0)
+    option_html=option_gpx_track=option_gpx_route=option_text=option_text_all=1;
+
+ if(option_html || option_gpx_route || option_gpx_track || option_text || option_text_all)
+   {
+    if(translations)
+      {
+       if(!ExistsFile(translations))
+         {
+          fprintf(stderr,"Error: The '--translations' option specifies a file that does not exist.\n");
+          exit(EXIT_FAILURE);
+         }
+      }
+    else
+      {
+       translations=FileName(dirname,prefix,"translations.xml");
+
+       if(!ExistsFile(translations))
+         {
+          free(translations);
+
+          translations=FileName(ROUTINO_DATADIR,NULL,"translations.xml");
+
+          if(!ExistsFile(translations))
+            {
+             fprintf(stderr,"Error: The '--translations' option was not used and the default 'translations.xml' does not exist.\n");
+             exit(EXIT_FAILURE);
+            }
+         }
+      }
+
+    if(ParseXMLTranslations(translations,language))
+      {
+       fprintf(stderr,"Error: Cannot read the translations in the file '%s'.\n",translations);
+       exit(EXIT_FAILURE);
+      }
+   }
+
+ /* Load in the data - Note: No error checking because Load*List() will call exit() in case of an error. */
+
+#if !DEBUG
+ if(!option_quiet)
+    printf_first("Loading Files:");
+#endif
+
+ OSMNodes=LoadNodeList(FileName(dirname,prefix,"nodes.mem"));
+
+ OSMSegments=LoadSegmentList(FileName(dirname,prefix,"segments.mem"));
+
+ OSMWays=LoadWayList(FileName(dirname,prefix,"ways.mem"));
+
+ OSMRelations=LoadRelationList(FileName(dirname,prefix,"relations.mem"));
+
+#if !DEBUG
+ if(!option_quiet)
+    printf_last("Loaded Files: nodes, segments, ways & relations");
+#endif
+
+ /* Check the profile compared to the types of ways available */
+
+ if(UpdateProfile(profile,OSMWays))
+   {
+    fprintf(stderr,"Error: Profile is invalid or not compatible with database.\n");
+    exit(EXIT_FAILURE);
+   }
+
+ /* Check for reverse direction */
+
+ if(reverse)
+   {
+    waypoint_t temp;
+
+    temp=first_waypoint;
+    first_waypoint=last_waypoint;
+    last_waypoint=temp;
+
+    last_waypoint--;
+
+    inc_dec_waypoint=-1;
+   }
+ else
+   {
+    last_waypoint++;
+
+    inc_dec_waypoint=1;
+   }
+
+ /* Loop through all pairs of waypoints */
+
+ for(waypoint=first_waypoint;waypoint!=last_waypoint;waypoint+=inc_dec_waypoint)
+   {
+    distance_t distmax=km_to_distance(MAXSEARCH);
+    distance_t distmin;
+    index_t segment=NO_SEGMENT;
+    index_t node1,node2;
+
+    if(point_used[waypoint]!=3)
+       continue;
+
+#if !DEBUG
+    if(!option_quiet)
+       printf_first("Finding Closest Point: Waypoint %d",waypoint);
+#endif
+
+    /* Find the closest point */
+
+    start_node=finish_node;
+    start_waypoint=finish_waypoint;
+
+    if(exactnodes)
+      {
+       finish_node=FindClosestNode(OSMNodes,OSMSegments,OSMWays,point_lat[waypoint],point_lon[waypoint],distmax,profile,&distmin);
+      }
+    else
+      {
+       distance_t dist1,dist2;
+
+       segment=FindClosestSegment(OSMNodes,OSMSegments,OSMWays,point_lat[waypoint],point_lon[waypoint],distmax,profile,&distmin,&node1,&node2,&dist1,&dist2);
+
+       if(segment!=NO_SEGMENT)
+          finish_node=CreateFakes(OSMNodes,OSMSegments,waypoint,LookupSegment(OSMSegments,segment,1),node1,node2,dist1,dist2);
+       else
+          finish_node=NO_NODE;
+      }
+
+#if !DEBUG
+    if(!option_quiet)
+       printf_last("Found Closest Point: Waypoint %d",waypoint);
+#endif
+
+    if(finish_node==NO_NODE)
+      {
+       fprintf(stderr,"Error: Cannot find node close to specified point %d.\n",waypoint);
+       exit(EXIT_FAILURE);
+      }
+
+    finish_waypoint=waypoint;
+
+    if(!option_quiet)
+      {
+       double lat,lon;
+
+       if(IsFakeNode(finish_node))
+          GetFakeLatLong(finish_node,&lat,&lon);
+       else
+          GetLatLong(OSMNodes,finish_node,NULL,&lat,&lon);
+
+       if(IsFakeNode(finish_node))
+          printf("Waypoint %d is segment %"Pindex_t" (node %"Pindex_t" -> %"Pindex_t"): %3.6f %4.6f = %2.3f km\n",waypoint,segment,node1,node2,
+                 radians_to_degrees(lon),radians_to_degrees(lat),distance_to_km(distmin));
+       else
+          printf("Waypoint %d is node %"Pindex_t": %3.6f %4.6f = %2.3f km\n",waypoint,finish_node,
+                 radians_to_degrees(lon),radians_to_degrees(lat),distance_to_km(distmin));
+      }
+
+    /* Check the nodes */
+
+    if(start_node==NO_NODE)
+       continue;
+
+    if(first_node==NO_NODE)
+       first_node=start_node;
+
+    if(heading!=-999 && join_segment==NO_SEGMENT)
+       join_segment=FindClosestSegmentHeading(OSMNodes,OSMSegments,OSMWays,start_node,heading,profile);
+
+    /* Calculate the route */
+
+    results[nresults]=CalculateRoute(OSMNodes,OSMSegments,OSMWays,OSMRelations,profile,start_node,join_segment,finish_node,start_waypoint,finish_waypoint);
+
+    join_segment=results[nresults]->last_segment;
+
+    nresults++;
+   }
+
+ /* Finish the loop */
+
+ if(loop && finish_node!=NO_NODE)
+   {
+    results[nresults]=CalculateRoute(OSMNodes,OSMSegments,OSMWays,OSMRelations,profile,finish_node,join_segment,first_node,last_waypoint,first_waypoint);
+
+    nresults++;
+   }
+
+ if(!option_quiet)
+   {
+    printf("Routed OK\n");
+    fflush(stdout);
+   }
+
+ /* Print out the combined route */
+
+#if !DEBUG
+ if(!option_quiet)
+    printf_first("Generating Result Outputs");
+#endif
+
+ if(!option_none)
+    PrintRoute(results,nresults,OSMNodes,OSMSegments,OSMWays,profile);
+
+#if !DEBUG
+ if(!option_quiet)
+    printf_last("Generated Result Outputs");
+#endif
+
+ /* Destroy the remaining results lists and data structures */
+
+#ifdef DEBUG_MEMORY_LEAK
+
+ for(waypoint=0;waypoint<nresults;waypoint++)
+    FreeResultsList(results[waypoint]);
+
+ DestroyNodeList(OSMNodes);
+ DestroySegmentList(OSMSegments);
+ DestroyWayList(OSMWays);
+ DestroyRelationList(OSMRelations);
+
+ FreeXMLProfiles();
+
+ FreeXMLTranslations();
+
+#endif
+
+#if !DEBUG
+ if(!option_quiet)
+    printf_program_end();
+#endif
+
+ exit(EXIT_SUCCESS);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find a complete route from a specified node to another node.
+
+  Results *CalculateRoute Returns a set of results.
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  Profile *profile The profile containing the transport type, speeds and allowed highways.
+
+  index_t start_node The start node.
+
+  index_t prev_segment The previous segment before the start node.
+
+  index_t finish_node The finish node.
+
+  int start_waypoint The starting waypoint.
+
+  int finish_waypoint The finish waypoint.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static Results *CalculateRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,
+                               index_t start_node,index_t prev_segment,index_t finish_node,
+                               int start_waypoint,int finish_waypoint)
+{
+ Results *complete=NULL;
+
+ /* A special case if the first and last nodes are the same */
+
+ if(start_node==finish_node)
+   {
+    index_t fake_segment;
+    Result *result1,*result2;
+
+    complete=NewResultsList(8);
+
+    if(prev_segment==NO_SEGMENT)
+      {
+       double lat,lon;
+       distance_t distmin,dist1,dist2;
+       index_t node1,node2;
+
+       GetLatLong(nodes,start_node,NULL,&lat,&lon);
+
+       prev_segment=FindClosestSegment(nodes,segments,ways,lat,lon,1,profile,&distmin,&node1,&node2,&dist1,&dist2);
+      }
+
+    fake_segment=CreateFakeNullSegment(segments,start_node,prev_segment,finish_waypoint);
+
+    result1=InsertResult(complete,start_node,prev_segment);
+    result2=InsertResult(complete,finish_node,fake_segment);
+
+    result1->next=result2;
+
+    complete->start_node=start_node;
+    complete->prev_segment=prev_segment;
+
+    complete->finish_node=finish_node;
+    complete->last_segment=fake_segment;
+   }
+ else
+   {
+    Results *begin;
+
+    /* Calculate the beginning of the route */
+
+    begin=FindStartRoutes(nodes,segments,ways,relations,profile,start_node,prev_segment,finish_node);
+
+    if(begin)
+      {
+       /* Check if the end of the route was reached */
+
+       if(begin->finish_node!=NO_NODE)
+          complete=begin;
+      }
+    else
+      {
+       if(prev_segment!=NO_SEGMENT)
+         {
+          /* Try again but allow a U-turn at the start waypoint -
+             this solves the problem of facing a dead-end that contains no super-nodes. */
+
+          prev_segment=NO_SEGMENT;
+
+          begin=FindStartRoutes(nodes,segments,ways,relations,profile,start_node,prev_segment,finish_node);
+         }
+
+       if(begin)
+         {
+          /* Check if the end of the route was reached */
+
+          if(begin->finish_node!=NO_NODE)
+             complete=begin;
+         }
+       else
+         {
+          fprintf(stderr,"Error: Cannot find initial section of route compatible with profile.\n");
+          exit(EXIT_FAILURE);
+         }
+      }
+
+    /* Calculate the rest of the route */
+
+    if(!complete)
+      {
+       Results *middle,*end;
+
+       /* Calculate the end of the route */
+
+       end=FindFinishRoutes(nodes,segments,ways,relations,profile,finish_node);
+
+       if(!end)
+         {
+          fprintf(stderr,"Error: Cannot find final section of route compatible with profile.\n");
+          exit(EXIT_FAILURE);
+         }
+
+       /* Calculate the middle of the route */
+
+       middle=FindMiddleRoute(nodes,segments,ways,relations,profile,begin,end);
+
+       if(!middle && prev_segment!=NO_SEGMENT)
+         {
+          /* Try again but allow a U-turn at the start waypoint -
+             this solves the problem of facing a dead-end that contains some super-nodes. */
+
+          FreeResultsList(begin);
+
+          begin=FindStartRoutes(nodes,segments,ways,relations,profile,start_node,NO_SEGMENT,finish_node);
+
+          if(begin)
+             middle=FindMiddleRoute(nodes,segments,ways,relations,profile,begin,end);
+         }
+
+       if(!middle)
+         {
+          fprintf(stderr,"Error: Cannot find super-route compatible with profile.\n");
+          exit(EXIT_FAILURE);
+         }
+
+       complete=CombineRoutes(nodes,segments,ways,relations,profile,begin,middle,end);
+
+       if(!complete)
+         {
+          fprintf(stderr,"Error: Cannot create combined route following super-route.\n");
+          exit(EXIT_FAILURE);
+         }
+
+       FreeResultsList(begin);
+       FreeResultsList(middle);
+       FreeResultsList(end);
+      }
+   }
+
+ complete->start_waypoint=start_waypoint;
+ complete->finish_waypoint=finish_waypoint;
+
+#if DEBUG
+ Result *r=FindResult(complete,complete->start_node,complete->prev_segment);
+
+ printf("The final route is:\n");
+
+ while(r)
+   {
+    printf("  node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score);
+
+    r=r->next;
+   }
+#endif
+
+ return(complete);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Print out the usage information.
+
+  int detail The level of detail to use - 0 = low, 1 = high.
+
+  const char *argerr The argument that gave the error (if there is one).
+
+  const char *err Other error message (if there is one).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void print_usage(int detail,const char *argerr,const char *err)
+{
+ fprintf(stderr,
+         "Usage: router [--help | --help-profile | --help-profile-xml |\n"
+         "                        --help-profile-json | --help-profile-perl ]\n"
+         "              [--dir=<dirname>] [--prefix=<name>]\n"
+         "              [--profiles=<filename>] [--translations=<filename>]\n"
+         "              [--exact-nodes-only]\n"
+         "              [--quiet | [--loggable] [--logtime] [--logmemory]]\n"
+         "              [--language=<lang>]\n"
+         "              [--output-html]\n"
+         "              [--output-gpx-track] [--output-gpx-route]\n"
+         "              [--output-text] [--output-text-all]\n"
+         "              [--output-none] [--output-stdout]\n"
+         "              [--profile=<name>]\n"
+         "              [--transport=<transport>]\n"
+         "              [--shortest | --quickest]\n"
+         "              --lon1=<longitude> --lat1=<latitude>\n"
+         "              --lon2=<longitude> --lon2=<latitude>\n"
+         "              [ ... --lon99=<longitude> --lon99=<latitude>]\n"
+         "              [--reverse] [--loop]\n"
+         "              [--highway-<highway>=<preference> ...]\n"
+         "              [--speed-<highway>=<speed> ...]\n"
+         "              [--property-<property>=<preference> ...]\n"
+         "              [--oneway=(0|1)] [--turns=(0|1)]\n"
+         "              [--weight=<weight>]\n"
+         "              [--height=<height>] [--width=<width>] [--length=<length>]\n");
+
+ if(argerr)
+    fprintf(stderr,
+            "\n"
+            "Error with command line parameter: %s\n",argerr);
+
+ if(err)
+    fprintf(stderr,
+            "\n"
+            "Error: %s\n",err);
+
+ if(detail)
+    fprintf(stderr,
+            "\n"
+            "--help                  Prints this information.\n"
+            "--help-profile          Prints the information about the selected profile.\n"
+            "--help-profile-xml      Prints all loaded profiles in XML format.\n"
+            "--help-profile-json     Prints all loaded profiles in JSON format.\n"
+            "--help-profile-perl     Prints all loaded profiles in Perl format.\n"
+            "\n"
+            "--dir=<dirname>         The directory containing the routing database.\n"
+            "--prefix=<name>         The filename prefix for the routing database.\n"
+            "--profiles=<filename>   The name of the XML file containing the profiles\n"
+            "                        (defaults to 'profiles.xml' with '--dir' and\n"
+            "                         '--prefix' options or the file installed in\n"
+            "                         '" ROUTINO_DATADIR "').\n"
+            "--translations=<fname>  The name of the XML file containing the translations\n"
+            "                        (defaults to 'translations.xml' with '--dir' and\n"
+            "                         '--prefix' options or the file installed in\n"
+            "                         '" ROUTINO_DATADIR "').\n"
+            "\n"
+            "--exact-nodes-only      Only route between nodes (don't find closest segment).\n"
+            "\n"
+            "--quiet                 Don't print any screen output when running.\n"
+            "--loggable              Print progress messages suitable for logging to file.\n"
+            "--logtime               Print the elapsed time for each processing step.\n"
+            "--logmemory             Print the max allocated/mapped memory for each step.\n"
+            "\n"
+            "--language=<lang>       Use the translations for specified language.\n"
+            "--output-html           Write an HTML description of the route.\n"
+            "--output-gpx-track      Write a GPX track file with all route points.\n"
+            "--output-gpx-route      Write a GPX route file with interesting junctions.\n"
+            "--output-text           Write a plain text file with interesting junctions.\n"
+            "--output-text-all       Write a plain test file with all route points.\n"
+            "--output-none           Don't write any output files or read any translations.\n"
+            "                        (If no output option is given then all are written.)\n"
+            "--output-stdout         Write to stdout instead of a file (requires exactly\n"
+            "                        one output format option, implies '--quiet').\n"
+            "\n"
+            "--profile=<name>        Select the loaded profile with this name.\n"
+            "--transport=<transport> Select the transport to use (selects the profile\n"
+            "                        named after the transport if '--profile' is not used.)\n"
+            "\n"
+            "--shortest              Find the shortest route between the waypoints.\n"
+            "--quickest              Find the quickest route between the waypoints.\n"
+            "\n"
+            "--lon<n>=<longitude>    Specify the longitude of the n'th waypoint.\n"
+            "--lat<n>=<latitude>     Specify the latitude of the n'th waypoint.\n"
+            "\n"
+            "--reverse               Find a route between the waypoints in reverse order.\n"
+            "--loop                  Find a route that returns to the first waypoint.\n"
+            "\n"
+            "--heading=<bearing>     Initial compass bearing at lowest numbered waypoint.\n"
+            "\n"
+            "                                   Routing preference options\n"
+            "--highway-<highway>=<preference>   * preference for highway type (%%).\n"
+            "--speed-<highway>=<speed>          * speed for highway type (km/h).\n"
+            "--property-<property>=<preference> * preference for proprty type (%%).\n"
+            "--oneway=(0|1)                     * oneway restrictions are to be obeyed.\n"
+            "--turns=(0|1)                      * turn restrictions are to be obeyed.\n"
+            "--weight=<weight>                  * maximum weight limit (tonnes).\n"
+            "--height=<height>                  * maximum height limit (metres).\n"
+            "--width=<width>                    * maximum width limit (metres).\n"
+            "--length=<length>                  * maximum length limit (metres).\n"
+            "\n"
+            "<transport> defaults to motorcar but can be set to:\n"
+            "%s"
+            "\n"
+            "<highway> can be selected from:\n"
+            "%s"
+            "\n"
+            "<property> can be selected from:\n"
+            "%s",
+            TransportList(),HighwayList(),PropertyList());
+
+ exit(!detail);
+}
diff --git a/3rdparty/Routino/src/routino.c b/3rdparty/Routino/src/routino.c
new file mode 100644
index 0000000..3a49e41
--- /dev/null
+++ b/3rdparty/Routino/src/routino.c
@@ -0,0 +1,26 @@
+/***************************************
+ Routino library functions file.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+#include "routino.h"
+
+DLL_PUBLIC void Routino(void)
+{
+}
diff --git a/3rdparty/Routino/src/routino.h b/3rdparty/Routino/src/routino.h
new file mode 100644
index 0000000..3e27d76
--- /dev/null
+++ b/3rdparty/Routino/src/routino.h
@@ -0,0 +1,74 @@
+/***************************************
+ Routino library header file.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef ROUTINO_H
+#define ROUTINO_H    /*+ To stop multiple inclusions. +*/
+
+/* Limit the exported symbols in the library */
+
+#if defined(_MSC_VER)
+  #ifdef LIBROUTINO
+    #define DLL_PUBLIC __declspec(dllexport)
+  #else
+    #define DLL_PUBLIC __declspec(dllimport)
+  #endif
+#endif
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+  #if defined(__MINGW32__) || defined(__CYGWIN__)
+    #ifdef LIBROUTINO
+      #define DLL_PUBLIC __attribute__ ((dllexport))
+    #else
+      #define DLL_PUBLIC __attribute__ ((dllimport))
+    #endif
+  #else
+    #ifdef LIBROUTINO
+      #define DLL_PUBLIC __attribute__ ((visibility ("default")))
+    #endif
+  #endif
+#endif
+
+#ifndef DLL_PUBLIC
+  #define DLL_PUBLIC
+#endif
+
+
+/* Handle compilation with a C++ compiler */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+ /* Library functions */
+
+ DLL_PUBLIC void Routino(void);
+
+
+/* Handle compilation with a C++ compiler */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ROUTINO_H */
diff --git a/3rdparty/Routino/src/segments.c b/3rdparty/Routino/src/segments.c
new file mode 100644
index 0000000..baa9737
--- /dev/null
+++ b/3rdparty/Routino/src/segments.c
@@ -0,0 +1,437 @@
+/***************************************
+ Segment data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "types.h"
+#include "nodes.h"
+#include "segments.h"
+#include "ways.h"
+
+#include "fakes.h"
+#include "files.h"
+#include "profiles.h"
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Load in a segment list from a file.
+
+  Segments *LoadSegmentList Returns the segment list that has just been loaded.
+
+  const char *filename The name of the file to load.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Segments *LoadSegmentList(const char *filename)
+{
+ Segments *segments;
+
+ segments=(Segments*)malloc(sizeof(Segments));
+
+#if !SLIM
+
+ segments->data=MapFile(filename);
+
+ /* Copy the SegmentsFile structure from the loaded data */
+
+ segments->file=*((SegmentsFile*)segments->data);
+
+ /* Set the pointers in the Segments structure. */
+
+ segments->segments=(Segment*)(segments->data+sizeof(SegmentsFile));
+
+#else
+
+ segments->fd=SlimMapFile(filename);
+
+ /* Copy the SegmentsFile header structure from the loaded data */
+
+ SlimFetch(segments->fd,&segments->file,sizeof(SegmentsFile),0);
+
+ segments->cache=NewSegmentCache();
+#ifndef LIBROUTINO
+ log_malloc(segments->cache,sizeof(*segments->cache));
+#endif
+
+#endif
+
+ return(segments);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Destroy the segment list.
+
+  Segments *segments The segment list to destroy.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void DestroySegmentList(Segments *segments)
+{
+#if !SLIM
+
+ segments->data=UnmapFile(segments->data);
+
+#else
+
+ segments->fd=SlimUnmapFile(segments->fd);
+
+#ifndef LIBROUTINO
+ log_free(segments->cache);
+#endif
+ DeleteSegmentCache(segments->cache);
+
+#endif
+
+ free(segments);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the closest segment from a specified node heading in a particular direction and optionally profile.
+
+  index_t FindClosestSegmentHeading Returns the closest heading segment index.
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  index_t node1 The node to start from.
+
+  double heading The desired heading from the node.
+
+  Profile *profile The profile of the mode of transport (or NULL).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t FindClosestSegmentHeading(Nodes *nodes,Segments *segments,Ways *ways,index_t node1,double heading,Profile *profile)
+{
+ Segment *segmentp;
+ index_t best_seg=NO_SEGMENT;
+ double best_difference=360;
+
+ if(IsFakeNode(node1))
+    segmentp=FirstFakeSegment(node1);
+ else
+   {
+    Node *nodep=LookupNode(nodes,node1,3);
+
+    segmentp=FirstSegment(segments,nodep,1);
+   }
+
+ while(segmentp)
+   {
+    Way *wayp;
+    index_t node2,seg2;
+    double bearing,difference;
+
+    node2=OtherNode(segmentp,node1);  /* need this here because we use node2 at the end of the loop */
+
+    if(!IsNormalSegment(segmentp))
+       goto endloop;
+
+    if(IsFakeNode(node1) || IsFakeNode(node2))
+       seg2=IndexFakeSegment(segmentp);
+    else
+       seg2=IndexSegment(segments,segmentp);
+
+    wayp=LookupWay(ways,segmentp->way,1);
+
+    if(!(wayp->allow&profile->allow))
+       goto endloop;
+
+    if(profile->oneway && IsOnewayFrom(segmentp,node1))
+      {
+       if(profile->allow!=Transports_Bicycle)
+          goto endloop;
+
+       if(!(wayp->type&Highway_CycleBothWays))
+          goto endloop;
+      }
+
+    bearing=BearingAngle(nodes,segmentp,node1);
+
+    difference=(heading-bearing);
+
+    if(difference<-180) difference+=360;
+    if(difference> 180) difference-=360;
+
+    if(difference<0) difference=-difference;
+
+    if(difference<best_difference)
+      {
+       best_difference=difference;
+       best_seg=seg2;
+      }
+
+   endloop:
+
+    if(IsFakeNode(node1))
+       segmentp=NextFakeSegment(segmentp,node1);
+    else if(IsFakeNode(node2))
+       segmentp=NULL; /* cannot call NextSegment() with a fake segment */
+    else
+       segmentp=NextSegment(segments,segmentp,node1);
+   }
+
+ return(best_seg);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Calculate the distance between two locations.
+
+  distance_t Distance Returns the distance between the locations.
+
+  double lat1 The latitude of the first location.
+
+  double lon1 The longitude of the first location.
+
+  double lat2 The latitude of the second location.
+
+  double lon2 The longitude of the second location.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+distance_t Distance(double lat1,double lon1,double lat2,double lon2)
+{
+ double dlon = lon1 - lon2;
+ double dlat = lat1 - lat2;
+
+ double a1,a2,a,sa,c,d;
+
+ if(dlon==0 && dlat==0)
+   return 0;
+
+ a1 = sin (dlat / 2);
+ a2 = sin (dlon / 2);
+ a = a1 * a1 + cos (lat1) * cos (lat2) * a2 * a2;
+ sa = sqrt (a);
+ if (sa <= 1.0)
+   {c = 2 * asin (sa);}
+ else
+   {c = 2 * asin (1.0);}
+ d = 6378.137 * c;
+
+ return km_to_distance(d);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Calculate the change in latitude (same longitude) between two locations a known distance apart.
+
+  double DeltaLat Returns the difference in latitude between the locations.
+
+  double lon The longitude of the locations.
+
+  distance_t distance The distance between the locations.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+double DeltaLat(double lon,distance_t distance)
+{
+ double dlat;
+
+ double c,d;
+
+ if(distance==0)
+   return 0;
+
+ d = distance_to_km(distance);
+
+ c = d / 6378.137;
+
+ dlat = c;
+
+ return dlat;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Calculate the change in longitude (same latitude) between two locations a known distance apart.
+
+  double DeltaLon Returns the difference in longitude between the locations.
+
+  double lat The latitude of the locations.
+
+  distance_t distance The distance between the locations.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+double DeltaLon(double lat,distance_t distance)
+{
+ double dlon;
+
+ double a2,sa,c,d;
+
+ if(distance==0)
+   return 0;
+
+ d = distance_to_km(distance);
+
+ c = d / 6378.137;
+
+ sa = sin(c/2);
+
+ a2 = sa / cos(lat);
+
+ dlon = 2*asin(a2);
+
+ return dlon;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Calculate the duration of travel on a segment.
+
+  duration_t Duration Returns the duration of travel.
+
+  Segment *segmentp The segment to traverse.
+
+  Way *wayp The way that the segment belongs to.
+
+  Profile *profile The profile of the transport being used.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+duration_t Duration(Segment *segmentp,Way *wayp,Profile *profile)
+{
+ speed_t    speed1=wayp->speed;
+ speed_t    speed2=profile->speed[HIGHWAY(wayp->type)];
+ distance_t distance=DISTANCE(segmentp->distance);
+
+ if(speed1==0)
+   {
+    if(speed2==0)
+       return(hours_to_duration(10));
+    else
+       return distance_speed_to_duration(distance,speed2);
+   }
+ else /* if(speed1!=0) */
+   {
+    if(speed2==0)
+       return distance_speed_to_duration(distance,speed1);
+    else if(speed1<=speed2)
+       return distance_speed_to_duration(distance,speed1);
+    else
+       return distance_speed_to_duration(distance,speed2);
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Calculate the angle to turn at a junction from segment1 to segment2 at node.
+
+  double TurnAngle Returns a value in the range -180 to +180 indicating the angle to turn.
+
+  Nodes *nodes The set of nodes to use.
+
+  Segment *segment1p The current segment.
+
+  Segment *segment2p The next segment.
+
+  index_t node The node at which they join.
+
+  Straight ahead is zero, turning to the right is positive (e.g. +90 degrees) and turning to the left is negative (e.g. -90 degrees).
+  Angles are calculated using flat Cartesian lat/long grid approximation (after scaling longitude due to latitude).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+double TurnAngle(Nodes *nodes,Segment *segment1p,Segment *segment2p,index_t node)
+{
+ double lat1,latm,lat2;
+ double lon1,lonm,lon2;
+ double angle1,angle2,angle;
+ index_t node1,node2;
+
+ node1=OtherNode(segment1p,node);
+ node2=OtherNode(segment2p,node);
+
+ if(IsFakeNode(node1))
+    GetFakeLatLong(node1,&lat1,&lon1);
+ else
+    GetLatLong(nodes,node1,NULL,&lat1,&lon1);
+
+ if(IsFakeNode(node))
+    GetFakeLatLong(node,&latm,&lonm);
+ else
+    GetLatLong(nodes,node,NULL,&latm,&lonm);
+
+ if(IsFakeNode(node2))
+    GetFakeLatLong(node2,&lat2,&lon2);
+ else
+    GetLatLong(nodes,node2,NULL,&lat2,&lon2);
+
+ angle1=atan2((lonm-lon1)*cos(latm),(latm-lat1));
+ angle2=atan2((lon2-lonm)*cos(latm),(lat2-latm));
+
+ angle=angle2-angle1;
+
+ angle=radians_to_degrees(angle);
+
+ if(angle<-180) angle+=360;
+ if(angle> 180) angle-=360;
+
+ return(angle);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Calculate the bearing of a segment when heading to the given node.
+
+  double BearingAngle Returns a value in the range 0 to 359 indicating the bearing.
+
+  Nodes *nodes The set of nodes to use.
+
+  Segment *segmentp The segment.
+
+  index_t node The node to finish.
+
+  Angles are calculated using flat Cartesian lat/long grid approximation (after scaling longitude due to latitude).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+double BearingAngle(Nodes *nodes,Segment *segmentp,index_t node)
+{
+ double lat1,lat2;
+ double lon1,lon2;
+ double angle;
+ index_t node1,node2;
+
+ node1=node;
+ node2=OtherNode(segmentp,node);
+
+ if(IsFakeNode(node1))
+    GetFakeLatLong(node1,&lat1,&lon1);
+ else
+    GetLatLong(nodes,node1,NULL,&lat1,&lon1);
+
+ if(IsFakeNode(node2))
+    GetFakeLatLong(node2,&lat2,&lon2);
+ else
+    GetLatLong(nodes,node2,NULL,&lat2,&lon2);
+
+ angle=atan2((lat2-lat1),(lon2-lon1)*cos(lat1));
+
+ angle=radians_to_degrees(angle);
+
+ angle=270-angle;
+
+ if(angle<  0) angle+=360;
+ if(angle>360) angle-=360;
+
+ return(angle);
+}
diff --git a/3rdparty/Routino/src/segments.h b/3rdparty/Routino/src/segments.h
new file mode 100644
index 0000000..3af3f45
--- /dev/null
+++ b/3rdparty/Routino/src/segments.h
@@ -0,0 +1,279 @@
+/***************************************
+ $Header: /home/amb/CVS/routino/src/segments.h,v 1.38 2010-12-21 17:18:41 amb Exp $
+
+ A header file for the segments.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef SEGMENTS_H
+#define SEGMENTS_H    /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+
+#include "types.h"
+
+#include "cache.h"
+#include "files.h"
+#include "profiles.h"
+
+
+/* Data structures */
+
+
+/*+ A structure containing a single segment. +*/
+struct _Segment
+{
+ index_t    node1;              /*+ The index of the starting node. +*/
+ index_t    node2;              /*+ The index of the finishing node. +*/
+
+ index_t    next2;              /*+ The index of the next segment sharing node2. +*/
+
+ index_t    way;                /*+ The index of the way associated with the segment. +*/
+
+ distance_t distance;           /*+ The distance between the nodes. +*/
+};
+
+
+/*+ A structure containing the header from the file. +*/
+typedef struct _SegmentsFile
+{
+ index_t   number;              /*+ The number of segments in total. +*/
+ index_t   snumber;             /*+ The number of super-segments. +*/
+ index_t   nnumber;             /*+ The number of normal segments. +*/
+}
+ SegmentsFile;
+
+
+/*+ A structure containing a set of segments (and pointers to mmap file). +*/
+struct _Segments
+{
+ SegmentsFile file;             /*+ The header data from the file. +*/
+
+#if !SLIM
+
+ char        *data;             /*+ The memory mapped data. +*/
+
+ Segment     *segments;         /*+ An array of segments. +*/
+
+#else
+
+ int          fd;               /*+ The file descriptor for the file. +*/
+
+ Segment      cached[4];        /*+ Three cached segments read from the file in slim mode. +*/
+ index_t      incache[4];       /*+ The indexes of the cached segments. +*/
+
+ SegmentCache *cache;           /*+ A RAM cache of segments read from the file. +*/
+
+#endif
+};
+
+
+/* Functions in segments.c */
+
+Segments *LoadSegmentList(const char *filename);
+
+void DestroySegmentList(Segments *segments);
+
+index_t FindClosestSegmentHeading(Nodes *nodes,Segments *segments,Ways *ways,index_t node1,double heading,Profile *profile);
+
+distance_t Distance(double lat1,double lon1,double lat2,double lon2);
+
+double DeltaLat(double lon,distance_t distance);
+double DeltaLon(double lat,distance_t distance);
+
+duration_t Duration(Segment *segmentp,Way *wayp,Profile *profile);
+
+double TurnAngle(Nodes *nodes,Segment *segment1p,Segment *segment2p,index_t node);
+double BearingAngle(Nodes *nodes,Segment *segmentp,index_t node);
+
+
+static inline Segment *NextSegment(Segments *segments,Segment *segmentp,index_t node);
+
+
+/* Macros and inline functions */
+
+/*+ Return true if this is a normal segment. +*/
+#define IsNormalSegment(xxx)   (((xxx)->distance)&SEGMENT_NORMAL)
+
+/*+ Return true if this is a super-segment. +*/
+#define IsSuperSegment(xxx)    (((xxx)->distance)&SEGMENT_SUPER)
+
+/*+ Return true if the segment is oneway. +*/
+#define IsOneway(xxx)          ((xxx)->distance&(ONEWAY_2TO1|ONEWAY_1TO2))
+
+/*+ Return true if the segment is oneway towards the specified node. +*/
+#define IsOnewayTo(xxx,yyy)    ((xxx)->node1==(yyy)?((xxx)->distance&ONEWAY_2TO1):((xxx)->distance&ONEWAY_1TO2))
+
+/*+ Return true if the segment is oneway from the specified node. +*/
+#define IsOnewayFrom(xxx,yyy)  ((xxx)->node2==(yyy)?((xxx)->distance&ONEWAY_2TO1):((xxx)->distance&ONEWAY_1TO2))
+
+/*+ Return the other node in the segment that is not the specified node. +*/
+#define OtherNode(xxx,yyy)     ((xxx)->node1==(yyy)?(xxx)->node2:(xxx)->node1)
+
+
+#if !SLIM
+
+/*+ Return a segment pointer given a set of segments and an index. +*/
+#define LookupSegment(xxx,yyy,ppp) (&(xxx)->segments[yyy])
+
+/*+ Return a segment index given a set of segments and a pointer. +*/
+#define IndexSegment(xxx,yyy)      (index_t)((yyy)-&(xxx)->segments[0])
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the next segment with a particular starting node.
+
+  Segment *NextSegment Returns a pointer to the next segment.
+
+  Segments *segments The set of segments to use.
+
+  Segment *segmentp The current segment.
+
+  index_t node The wanted node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline Segment *NextSegment(Segments *segments,Segment *segmentp,index_t node)
+{
+ if(segmentp->node1==node)
+   {
+    segmentp++;
+
+    if(IndexSegment(segments,segmentp)>=segments->file.number || segmentp->node1!=node)
+       return(NULL);
+    else
+       return(segmentp);
+   }
+ else
+   {
+    if(segmentp->next2==NO_SEGMENT)
+       return(NULL);
+    else
+       return(LookupSegment(segments,segmentp->next2,1));
+   }
+}
+
+#else
+
+/* Prototypes */
+
+static inline Segment *LookupSegment(Segments *segments,index_t index,int position);
+
+static inline index_t IndexSegment(Segments *segments,Segment *segmentp);
+
+CACHE_NEWCACHE_PROTO(Segment)
+CACHE_DELETECACHE_PROTO(Segment)
+CACHE_FETCHCACHE_PROTO(Segment)
+CACHE_INVALIDATECACHE_PROTO(Segment)
+
+
+/* Inline functions */
+
+CACHE_STRUCTURE(Segment)
+CACHE_NEWCACHE(Segment)
+CACHE_DELETECACHE(Segment)
+CACHE_FETCHCACHE(Segment)
+CACHE_INVALIDATECACHE(Segment)
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the Segment information for a particular segment.
+
+  Segment *LookupSegment Returns a pointer to the cached segment information.
+
+  Segments *segments The set of segments to use.
+
+  index_t index The index of the segment.
+
+  int position The position in the cache to store the value.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline Segment *LookupSegment(Segments *segments,index_t index,int position)
+{
+ segments->cached[position-1]=*FetchCachedSegment(segments->cache,index,segments->fd,sizeof(SegmentsFile));
+
+ segments->incache[position-1]=index;
+
+ return(&segments->cached[position-1]);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the segment index for a particular segment pointer.
+
+  index_t IndexSegment Returns the index of the segment in the list.
+
+  Segments *segments The set of segments to use.
+
+  Segment *segmentp The segment whose index is to be found.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline index_t IndexSegment(Segments *segments,Segment *segmentp)
+{
+ int position1=(int)(segmentp-&segments->cached[0]);
+
+ return(segments->incache[position1]);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the next segment with a particular starting node.
+
+  Segment *NextSegment Returns a pointer to the next segment.
+
+  Segments *segments The set of segments to use.
+
+  Segment *segmentp The current segment.
+
+  index_t node The wanted node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline Segment *NextSegment(Segments *segments,Segment *segmentp,index_t node)
+{
+ int position=(int)(segmentp-&segments->cached[-1]);
+
+ if(segmentp->node1==node)
+   {
+    index_t index=IndexSegment(segments,segmentp);
+
+    index++;
+
+    if(index>=segments->file.number)
+       return(NULL);
+
+    segmentp=LookupSegment(segments,index,position);
+
+    if(segmentp->node1!=node)
+       return(NULL);
+    else
+       return(segmentp);
+   }
+ else
+   {
+    if(segmentp->next2==NO_SEGMENT)
+       return(NULL);
+    else
+       return(LookupSegment(segments,segmentp->next2,position));
+   }
+}
+
+#endif
+
+
+#endif /* SEGMENTS_H */
diff --git a/3rdparty/Routino/src/segmentsx.c b/3rdparty/Routino/src/segmentsx.c
new file mode 100644
index 0000000..bcd2ccc
--- /dev/null
+++ b/3rdparty/Routino/src/segmentsx.c
@@ -0,0 +1,1003 @@
+/***************************************
+ Extended Segment data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "types.h"
+#include "segments.h"
+#include "ways.h"
+
+#include "typesx.h"
+#include "nodesx.h"
+#include "segmentsx.h"
+#include "waysx.h"
+
+#include "files.h"
+#include "logging.h"
+#include "sorting.h"
+
+
+/* Global variables */
+
+/*+ The command line '--tmpdir' option or its default value. +*/
+extern char *option_tmpdirname;
+
+/* Local variables */
+
+/*+ Temporary file-local variables for use by the sort functions (re-initialised for each sort). +*/
+static NodesX *sortnodesx;
+static SegmentsX *sortsegmentsx;
+static WaysX *sortwaysx;
+
+/* Local functions */
+
+static int sort_by_id(SegmentX *a,SegmentX *b);
+
+static int delete_pruned(SegmentX *segmentx,index_t index);
+
+static int deduplicate_super(SegmentX *segmentx,index_t index);
+
+static int geographically_index(SegmentX *segmentx,index_t index);
+
+static distance_t DistanceX(NodeX *nodex1,NodeX *nodex2);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Allocate a new segment list (create a new file or open an existing one).
+
+  SegmentsX *NewSegmentList Returns the segment list.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+SegmentsX *NewSegmentList(void)
+{
+ SegmentsX *segmentsx;
+
+ segmentsx=(SegmentsX*)calloc(1,sizeof(SegmentsX));
+
+ logassert(segmentsx,"Failed to allocate memory (try using slim mode?)"); /* Check calloc() worked */
+
+ segmentsx->filename_tmp=(char*)malloc(strlen(option_tmpdirname)+40); /* allow %p to be up to 20 bytes */
+
+ sprintf(segmentsx->filename_tmp,"%s/segmentsx.%p.tmp",option_tmpdirname,(void*)segmentsx);
+
+ segmentsx->fd=OpenFileBufferedNew(segmentsx->filename_tmp);
+
+#if SLIM
+ segmentsx->cache=NewSegmentXCache();
+ log_malloc(segmentsx->cache,sizeof(*segmentsx->cache));
+#endif
+
+ return(segmentsx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Free a segment list.
+
+  SegmentsX *segmentsx The set of segments to be freed.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FreeSegmentList(SegmentsX *segmentsx)
+{
+ DeleteFile(segmentsx->filename_tmp);
+
+ free(segmentsx->filename_tmp);
+
+ if(segmentsx->usedway)
+   {
+    log_free(segmentsx->usedway);
+    free(segmentsx->usedway);
+   }
+
+ if(segmentsx->firstnode)
+   {
+    log_free(segmentsx->firstnode);
+    free(segmentsx->firstnode);
+   }
+
+ if(segmentsx->next1)
+   {
+    log_free(segmentsx->next1);
+    free(segmentsx->next1);
+   }
+
+#if SLIM
+ log_free(segmentsx->cache);
+ DeleteSegmentXCache(segmentsx->cache);
+#endif
+
+ free(segmentsx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Append a single segment to an unsorted segment list.
+
+  SegmentsX *segmentsx The set of segments to modify.
+
+  index_t way The index of the way that the segment belongs to.
+
+  index_t node1 The index of the first node in the segment.
+
+  index_t node2 The index of the second node in the segment.
+
+  distance_t distance The distance between the nodes (or just the flags).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void AppendSegmentList(SegmentsX *segmentsx,index_t way,index_t node1,index_t node2,distance_t distance)
+{
+ SegmentX segmentx;
+
+ if(node1>node2)
+   {
+    index_t temp;
+
+    temp=node1;
+    node1=node2;
+    node2=temp;
+
+    if(distance&(ONEWAY_2TO1|ONEWAY_1TO2))
+       distance^=ONEWAY_2TO1|ONEWAY_1TO2;
+   }
+
+ segmentx.node1=node1;
+ segmentx.node2=node2;
+ segmentx.next2=NO_SEGMENT;
+ segmentx.way=way;
+ segmentx.distance=distance;
+
+ WriteFileBuffered(segmentsx->fd,&segmentx,sizeof(SegmentX));
+
+ segmentsx->number++;
+
+ logassert(segmentsx->number<SEGMENT_FAKE,"Too many segments (change index_t to 64-bits?)"); /* SEGMENT_FAKE marks the high-water mark for real segments. */
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Finish appending segments and change the filename over.
+
+  SegmentsX *segmentsx The segments that have been appended.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FinishSegmentList(SegmentsX *segmentsx)
+{
+ if(segmentsx->fd!=-1)
+    segmentsx->fd=CloseFileBuffered(segmentsx->fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the first extended segment with a particular starting node index.
+ 
+  SegmentX *FirstSegmentX Returns a pointer to the first extended segment with the specified id.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  index_t nodeindex The node index to look for.
+
+  int position A flag to pass through.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+SegmentX *FirstSegmentX(SegmentsX *segmentsx,index_t nodeindex,int position)
+{
+ index_t index=segmentsx->firstnode[nodeindex];
+ SegmentX *segmentx;
+
+ if(index==NO_SEGMENT)
+    return(NULL);
+
+ segmentx=LookupSegmentX(segmentsx,index,position);
+
+ return(segmentx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the next segment with a particular starting node index.
+
+  SegmentX *NextSegmentX Returns a pointer to the next segment with the same id.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  SegmentX *segmentx The current segment.
+
+  index_t nodeindex The node index.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+SegmentX *NextSegmentX(SegmentsX *segmentsx,SegmentX *segmentx,index_t nodeindex)
+{
+#if SLIM
+ int position=1+(segmentx-&segmentsx->cached[0]);
+#endif
+
+ if(segmentx->node1==nodeindex)
+   {
+    if(segmentsx->next1)
+      {
+       index_t index=IndexSegmentX(segmentsx,segmentx);
+
+       if(segmentsx->next1[index]==NO_SEGMENT)
+          return(NULL);
+
+       segmentx=LookupSegmentX(segmentsx,segmentsx->next1[index],position);
+
+       return(segmentx);
+      }
+    else
+      {
+#if SLIM
+       index_t index=IndexSegmentX(segmentsx,segmentx);
+       index++;
+
+       if(index>=segmentsx->number)
+          return(NULL);
+
+       segmentx=LookupSegmentX(segmentsx,index,position);
+#else
+       segmentx++;
+
+       if(IndexSegmentX(segmentsx,segmentx)>=segmentsx->number)
+          return(NULL);
+#endif
+
+       if(segmentx->node1!=nodeindex)
+          return(NULL);
+
+       return(segmentx);
+      }
+   }
+ else
+   {
+    if(segmentx->next2==NO_SEGMENT)
+       return(NULL);
+
+    return(LookupSegmentX(segmentsx,segmentx->next2,position));
+   }
+}
+ 
+ 
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the segment list.
+
+  SegmentsX *segmentsx The set of segments to sort.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SortSegmentList(SegmentsX *segmentsx)
+{
+ int fd;
+
+ /* Print the start message */
+
+ printf_first("Sorting Segments");
+
+ /* Re-open the file read-only and a new file writeable */
+
+ fd=ReplaceFileBuffered(segmentsx->filename_tmp,&segmentsx->fd);
+
+ /* Sort by node indexes */
+
+ segmentsx->number=filesort_fixed(segmentsx->fd,fd,sizeof(SegmentX),NULL,
+                                                                    (int (*)(const void*,const void*))sort_by_id,
+                                                                    NULL);
+
+ /* Close the files */
+
+ segmentsx->fd=CloseFileBuffered(segmentsx->fd);
+ CloseFileBuffered(fd);
+
+ /* Print the final message */
+
+ printf_last("Sorted Segments: Segments=%"Pindex_t,segmentsx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the segments into id order, first by node1 then by node2, finally by distance.
+
+  int sort_by_id Returns the comparison of the node fields.
+
+  SegmentX *a The first segment.
+
+  SegmentX *b The second segment.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int sort_by_id(SegmentX *a,SegmentX *b)
+{
+ index_t a_id1=a->node1;
+ index_t b_id1=b->node1;
+
+ if(a_id1<b_id1)
+    return(-1);
+ else if(a_id1>b_id1)
+    return(1);
+ else /* if(a_id1==b_id1) */
+   {
+    index_t a_id2=a->node2;
+    index_t b_id2=b->node2;
+
+    if(a_id2<b_id2)
+       return(-1);
+    else if(a_id2>b_id2)
+       return(1);
+    else
+      {
+       distance_t a_distance=DISTANCE(a->distance);
+       distance_t b_distance=DISTANCE(b->distance);
+
+       if(a_distance<b_distance)
+          return(-1);
+       else if(a_distance>b_distance)
+          return(1);
+       else
+         {
+          distance_t a_distflag=DISTFLAG(a->distance);
+          distance_t b_distflag=DISTFLAG(b->distance);
+
+          if(a_distflag<b_distflag)
+             return(-1);
+          else if(a_distflag>b_distflag)
+             return(1);
+          else
+             return(FILESORT_PRESERVE_ORDER(a,b)); /* preserve order */
+         }
+      }
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process segments (non-trivial duplicates).
+
+  SegmentsX *segmentsx The set of segments to modify.
+
+  NodesX *nodesx The set of nodes to use.
+
+  WaysX *waysx The set of ways to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void ProcessSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx)
+{
+ index_t duplicate=0,good=0,total=0;
+ index_t prevnode1=NO_NODE,prevnode2=NO_NODE;
+ index_t prevway=NO_WAY;
+ distance_t prevdist=0;
+ SegmentX segmentx;
+ int fd;
+
+ /* Print the start message */
+
+ printf_first("Processing Segments: Segments=0 Duplicates=0");
+
+ /* Map into memory /  open the file */
+
+#if !SLIM
+ nodesx->data=MapFile(nodesx->filename_tmp);
+#else
+ nodesx->fd=SlimMapFile(nodesx->filename_tmp);
+
+ InvalidateNodeXCache(nodesx->cache);
+#endif
+
+ /* Allocate the way usage bitmask */
+
+ segmentsx->usedway=AllocBitMask(waysx->number);
+ log_malloc(segmentsx->usedway,LengthBitMask(waysx->number)*sizeof(BitMask));
+
+ logassert(segmentsx->usedway,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
+
+ /* Re-open the file read-only and a new file writeable */
+
+ fd=ReplaceFileBuffered(segmentsx->filename_tmp,&segmentsx->fd);
+
+ /* Modify the on-disk image */
+
+ while(!ReadFileBuffered(segmentsx->fd,&segmentx,sizeof(SegmentX)))
+   {
+    if(prevnode1==segmentx.node1 && prevnode2==segmentx.node2)
+      {
+       node_t id1=nodesx->idata[segmentx.node1];
+       node_t id2=nodesx->idata[segmentx.node2];
+
+       if(prevway==segmentx.way)
+         {
+          way_t id=waysx->idata[segmentx.way];
+
+          logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" in way %"Pway_t" is duplicated.\n",logerror_node(id1),logerror_node(id2),logerror_way(id));
+         }
+       else
+         {
+          if(!(prevdist&SEGMENT_AREA) && !(segmentx.distance&SEGMENT_AREA))
+             logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated.\n",logerror_node(id1),logerror_node(id2));
+
+          if(!(prevdist&SEGMENT_AREA) && (segmentx.distance&SEGMENT_AREA))
+             logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated (discarded the area).\n",logerror_node(id1),logerror_node(id2));
+
+          if((prevdist&SEGMENT_AREA) && !(segmentx.distance&SEGMENT_AREA))
+             logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated (discarded the non-area).\n",logerror_node(id1),logerror_node(id2));
+
+          if((prevdist&SEGMENT_AREA) && (segmentx.distance&SEGMENT_AREA))
+             logerror("Segment connecting nodes %"Pnode_t" and %"Pnode_t" is duplicated (both are areas).\n",logerror_node(id1),logerror_node(id2));
+         }
+
+       duplicate++;
+      }
+    else
+      {
+       NodeX *nodex1=LookupNodeX(nodesx,segmentx.node1,1);
+       NodeX *nodex2=LookupNodeX(nodesx,segmentx.node2,2);
+
+       prevnode1=segmentx.node1;
+       prevnode2=segmentx.node2;
+       prevway=segmentx.way;
+       prevdist=DISTANCE(segmentx.distance);
+
+       /* Mark the ways which are used */
+
+       SetBit(segmentsx->usedway,segmentx.way);
+
+       /* Set the distance but keep the other flags except for area */
+
+       segmentx.distance=DISTANCE(DistanceX(nodex1,nodex2))|DISTFLAG(segmentx.distance);
+       segmentx.distance&=~SEGMENT_AREA;
+
+       /* Write the modified segment */
+
+       WriteFileBuffered(fd,&segmentx,sizeof(SegmentX));
+
+       good++;
+      }
+
+    total++;
+
+    if(!(total%10000))
+       printf_middle("Processing Segments: Segments=%"Pindex_t" Duplicates=%"Pindex_t,total,duplicate);
+   }
+
+ segmentsx->number=good;
+
+ /* Close the files */
+
+ segmentsx->fd=CloseFileBuffered(segmentsx->fd);
+ CloseFileBuffered(fd);
+
+ /* Unmap from memory / close the file */
+
+#if !SLIM
+ nodesx->data=UnmapFile(nodesx->data);
+#else
+ nodesx->fd=SlimUnmapFile(nodesx->fd);
+#endif
+
+ /* Print the final message */
+
+ printf_last("Processed Segments: Segments=%"Pindex_t" Duplicates=%"Pindex_t,total,duplicate);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Index the segments by creating the firstnode index and filling in the segment next2 parameter.
+
+  SegmentsX *segmentsx The set of segments to modify.
+
+  NodesX *nodesx The set of nodes to use.
+
+  WaysX *waysx The set of ways to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void IndexSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx)
+{
+ index_t index,start=0,i;
+ SegmentX *segmentx_list=NULL;
+#if SLIM
+ index_t length=0;
+#endif
+
+ if(segmentsx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Indexing Segments: Segments=0");
+
+ /* Allocate the array of indexes */
+
+ segmentsx->firstnode=(index_t*)malloc(nodesx->number*sizeof(index_t));
+ log_malloc(segmentsx->firstnode,nodesx->number*sizeof(index_t));
+
+ logassert(segmentsx->firstnode,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
+
+ for(i=0;i<nodesx->number;i++)
+    segmentsx->firstnode[i]=NO_SEGMENT;
+
+ /* Map into memory / open the files */
+
+#if !SLIM
+ segmentsx->data=MapFileWriteable(segmentsx->filename_tmp);
+#else
+ segmentsx->fd=SlimMapFileWriteable(segmentsx->filename_tmp);
+
+ segmentx_list=(SegmentX*)malloc(1024*sizeof(SegmentX));
+#endif
+
+ /* Read through the segments in reverse order (in chunks to help slim mode) */
+
+ for(index=segmentsx->number-1;index!=NO_SEGMENT;index--)
+   {
+    SegmentX *segmentx;
+
+    if((index%1024)==1023 || index==(segmentsx->number-1))
+      {
+       start=1024*(index/1024);
+
+#if !SLIM
+       segmentx_list=LookupSegmentX(segmentsx,start,1);
+#else
+       length=index-start+1;
+
+       SlimFetch(segmentsx->fd,segmentx_list,length*sizeof(SegmentX),start*sizeof(SegmentX));
+#endif
+      }
+
+    segmentx=segmentx_list+(index-start);
+
+    if(nodesx->pdata)
+      {
+       segmentx->node1=nodesx->pdata[segmentx->node1];
+       segmentx->node2=nodesx->pdata[segmentx->node2];
+      }
+
+    if(waysx->cdata)
+       segmentx->way=waysx->cdata[segmentx->way];
+
+    segmentx->next2=segmentsx->firstnode[segmentx->node2];
+
+    segmentsx->firstnode[segmentx->node1]=index;
+    segmentsx->firstnode[segmentx->node2]=index;
+
+    if(!(index%10000))
+       printf_middle("Indexing Segments: Segments=%"Pindex_t,segmentsx->number-index);
+
+#if SLIM
+    if(index==start)
+       SlimReplace(segmentsx->fd,segmentx_list,length*sizeof(SegmentX),start*sizeof(SegmentX));
+#endif
+   }
+
+ /* Unmap from memory / close the files */
+
+#if !SLIM
+ segmentsx->data=UnmapFile(segmentsx->data);
+#else
+ segmentsx->fd=SlimUnmapFile(segmentsx->fd);
+
+ free(segmentx_list);
+#endif
+
+ /* Free the memory */
+
+ if(nodesx->pdata)
+   {
+    log_free(nodesx->pdata);
+    free(nodesx->pdata);
+    nodesx->pdata=NULL;
+   }
+
+ if(waysx->cdata)
+   {
+    log_free(waysx->cdata);
+    free(waysx->cdata);
+    waysx->cdata=NULL;
+   }
+
+ /* Print the final message */
+
+ printf_last("Indexed Segments: Segments=%"Pindex_t,segmentsx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Prune the deleted segments while resorting the list.
+
+  SegmentsX *segmentsx The set of segments to sort and modify.
+
+  WaysX *waysx The set of ways to check.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void RemovePrunedSegments(SegmentsX *segmentsx,WaysX *waysx)
+{
+ int fd;
+ index_t xnumber;
+
+ if(segmentsx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Sorting and Pruning Segments");
+
+ /* Allocate the way usage bitmask */
+
+ segmentsx->usedway=AllocBitMask(waysx->number);
+ log_malloc(segmentsx->usedway,LengthBitMask(waysx->number)*sizeof(BitMask));
+
+ logassert(segmentsx->usedway,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
+
+ /* Re-open the file read-only and a new file writeable */
+
+ fd=ReplaceFileBuffered(segmentsx->filename_tmp,&segmentsx->fd);
+
+ /* Sort by node indexes */
+
+ xnumber=segmentsx->number;
+
+ sortsegmentsx=segmentsx;
+
+ segmentsx->number=filesort_fixed(segmentsx->fd,fd,sizeof(SegmentX),(int (*)(void*,index_t))delete_pruned,
+                                                                    (int (*)(const void*,const void*))sort_by_id,
+                                                                    NULL);
+
+ /* Close the files */
+
+ segmentsx->fd=CloseFileBuffered(segmentsx->fd);
+ CloseFileBuffered(fd);
+
+ /* Print the final message */
+
+ printf_last("Sorted and Pruned Segments: Segments=%"Pindex_t" Deleted=%"Pindex_t,xnumber,xnumber-segmentsx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Delete the pruned segments.
+
+  int delete_pruned Return 1 if the value is to be kept, otherwise 0.
+
+  SegmentX *segmentx The extended segment.
+
+  index_t index The number of unsorted segments that have been read from the input file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int delete_pruned(SegmentX *segmentx,index_t index)
+{
+ if(IsPrunedSegmentX(segmentx))
+    return(0);
+
+ SetBit(sortsegmentsx->usedway,segmentx->way);
+
+ return(1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Remove the duplicate super-segments.
+
+  SegmentsX *segmentsx The set of super-segments to modify.
+
+  WaysX *waysx The set of ways to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void DeduplicateSuperSegments(SegmentsX *segmentsx,WaysX *waysx)
+{
+ int fd;
+ index_t xnumber;
+
+ if(waysx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Sorting and Deduplicating Super-Segments");
+
+ /* Map into memory / open the file */
+
+#if !SLIM
+ waysx->data=MapFile(waysx->filename_tmp);
+#else
+ waysx->fd=SlimMapFile(waysx->filename_tmp);
+
+ InvalidateWayXCache(waysx->cache);
+#endif
+
+ /* Re-open the file read-only and a new file writeable */
+
+ fd=ReplaceFileBuffered(segmentsx->filename_tmp,&segmentsx->fd);
+
+ /* Sort by node indexes */
+
+ xnumber=segmentsx->number;
+
+ sortsegmentsx=segmentsx;
+ sortwaysx=waysx;
+
+ segmentsx->number=filesort_fixed(segmentsx->fd,fd,sizeof(SegmentX),NULL,
+                                                                    (int (*)(const void*,const void*))sort_by_id,
+                                                                    (int (*)(void*,index_t))deduplicate_super);
+
+ /* Close the files */
+
+ segmentsx->fd=CloseFileBuffered(segmentsx->fd);
+ CloseFileBuffered(fd);
+
+ /* Unmap from memory / close the file */
+
+#if !SLIM
+ waysx->data=UnmapFile(waysx->data);
+#else
+ waysx->fd=SlimUnmapFile(waysx->fd);
+#endif
+
+ /* Print the final message */
+
+ printf_last("Sorted and Deduplicated Super-Segments: Super-Segments=%"Pindex_t" Duplicate=%"Pindex_t,xnumber,xnumber-segmentsx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  De-duplicate super-segments.
+
+  int deduplicate_super Return 1 if the value is to be kept, otherwise 0.
+
+  SegmentX *segmentx The extended super-segment.
+
+  index_t index The number of sorted super-segments that have already been written to the output file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int deduplicate_super(SegmentX *segmentx,index_t index)
+{
+ static int nprev;                           /* internal variable (reset by first call in each sort; index==0) */
+ static index_t prevnode1,prevnode2;         /* internal variable (reset by first call in each sort; index==0) */
+ static SegmentX prevsegx[MAX_SEG_PER_NODE]; /* internal variable (reset by first call in each sort; index==0) */
+ static Way prevway[MAX_SEG_PER_NODE];       /* internal variable (reset by first call in each sort; index==0) */
+
+ WayX *wayx=LookupWayX(sortwaysx,segmentx->way,1);
+ int isduplicate=0;
+
+ if(index==0 || segmentx->node1!=prevnode1 || segmentx->node2!=prevnode2)
+   {
+    nprev=1;
+    prevnode1=segmentx->node1;
+    prevnode2=segmentx->node2;
+    prevsegx[0]=*segmentx;
+    prevway[0] =wayx->way;
+   }
+ else
+   {
+    int offset;
+
+    for(offset=0;offset<nprev;offset++)
+      {
+       if(DISTFLAG(segmentx->distance)==DISTFLAG(prevsegx[offset].distance))
+          if(!WaysCompare(&prevway[offset],&wayx->way))
+            {
+             isduplicate=1;
+             break;
+            }
+      }
+
+    if(isduplicate)
+      {
+       nprev--;
+
+       for(;offset<nprev;offset++)
+         {
+          prevsegx[offset]=prevsegx[offset+1];
+          prevway[offset] =prevway[offset+1];
+         }
+      }
+    else
+      {
+       logassert(nprev<MAX_SEG_PER_NODE,"Too many segments for one node (increase MAX_SEG_PER_NODE?)"); /* Only a limited amount of information stored. */
+
+       prevsegx[nprev]=*segmentx;
+       prevway[nprev] =wayx->way;
+
+       nprev++;
+      }
+   }
+
+ return(!isduplicate);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the segments geographically after updating the node indexes.
+
+  SegmentsX *segmentsx The set of segments to modify.
+
+  NodesX *nodesx The set of nodes to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SortSegmentListGeographically(SegmentsX *segmentsx,NodesX *nodesx)
+{
+ int fd;
+
+ if(segmentsx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Sorting Segments Geographically");
+
+ /* Re-open the file read-only and a new file writeable */
+
+ fd=ReplaceFileBuffered(segmentsx->filename_tmp,&segmentsx->fd);
+
+ /* Update the segments with geographically sorted node indexes and sort them */
+
+ sortnodesx=nodesx;
+
+ filesort_fixed(segmentsx->fd,fd,sizeof(SegmentX),(int (*)(void*,index_t))geographically_index,
+                                                  (int (*)(const void*,const void*))sort_by_id,
+                                                  NULL);
+ /* Close the files */
+
+ segmentsx->fd=CloseFileBuffered(segmentsx->fd);
+ CloseFileBuffered(fd);
+
+ /* Print the final message */
+
+ printf_last("Sorted Segments Geographically: Segments=%"Pindex_t,segmentsx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Update the segment indexes.
+
+  int geographically_index Return 1 if the value is to be kept, otherwise 0.
+
+  SegmentX *segmentx The extended segment.
+
+  index_t index The number of unsorted segments that have been read from the input file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int geographically_index(SegmentX *segmentx,index_t index)
+{
+ segmentx->node1=sortnodesx->gdata[segmentx->node1];
+ segmentx->node2=sortnodesx->gdata[segmentx->node2];
+
+ if(segmentx->node1>segmentx->node2)
+   {
+    index_t temp;
+
+    temp=segmentx->node1;
+    segmentx->node1=segmentx->node2;
+    segmentx->node2=temp;
+
+    if(segmentx->distance&(ONEWAY_2TO1|ONEWAY_1TO2))
+       segmentx->distance^=ONEWAY_2TO1|ONEWAY_1TO2;
+   }
+
+ return(1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Save the segment list to a file.
+
+  SegmentsX *segmentsx The set of segments to save.
+
+  const char *filename The name of the file to save.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SaveSegmentList(SegmentsX *segmentsx,const char *filename)
+{
+ index_t i;
+ int fd;
+ SegmentsFile segmentsfile={0};
+ index_t super_number=0,normal_number=0;
+
+ /* Print the start message */
+
+ printf_first("Writing Segments: Segments=0");
+
+ /* Re-open the file */
+
+ segmentsx->fd=ReOpenFileBuffered(segmentsx->filename_tmp);
+
+ /* Write out the segments data */
+
+ fd=OpenFileBufferedNew(filename);
+
+ SeekFileBuffered(fd,sizeof(SegmentsFile));
+
+ for(i=0;i<segmentsx->number;i++)
+   {
+    SegmentX segmentx;
+    Segment  segment={0};
+
+    ReadFileBuffered(segmentsx->fd,&segmentx,sizeof(SegmentX));
+
+    segment.node1   =segmentx.node1;
+    segment.node2   =segmentx.node2;
+    segment.next2   =segmentx.next2;
+    segment.way     =segmentx.way;
+    segment.distance=segmentx.distance;
+
+    if(IsSuperSegment(&segment))
+       super_number++;
+    if(IsNormalSegment(&segment))
+       normal_number++;
+
+    WriteFileBuffered(fd,&segment,sizeof(Segment));
+
+    if(!((i+1)%10000))
+       printf_middle("Writing Segments: Segments=%"Pindex_t,i+1);
+   }
+
+ /* Write out the header structure */
+
+ segmentsfile.number=segmentsx->number;
+ segmentsfile.snumber=super_number;
+ segmentsfile.nnumber=normal_number;
+
+ SeekFileBuffered(fd,0);
+ WriteFileBuffered(fd,&segmentsfile,sizeof(SegmentsFile));
+
+ CloseFileBuffered(fd);
+
+ /* Close the file */
+
+ segmentsx->fd=CloseFileBuffered(segmentsx->fd);
+
+ /* Print the final message */
+
+ printf_last("Wrote Segments: Segments=%"Pindex_t,segmentsx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Calculate the distance between two nodes.
+
+  distance_t DistanceX Returns the distance between the extended nodes.
+
+  NodeX *nodex1 The starting node.
+
+  NodeX *nodex2 The end node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static distance_t DistanceX(NodeX *nodex1,NodeX *nodex2)
+{
+ double dlon = latlong_to_radians(nodex1->longitude) - latlong_to_radians(nodex2->longitude);
+ double dlat = latlong_to_radians(nodex1->latitude)  - latlong_to_radians(nodex2->latitude);
+ double lat1 = latlong_to_radians(nodex1->latitude);
+ double lat2 = latlong_to_radians(nodex2->latitude);
+
+ double a1,a2,a,sa,c,d;
+
+ if(dlon==0 && dlat==0)
+   return 0;
+
+ a1 = sin (dlat / 2);
+ a2 = sin (dlon / 2);
+ a = a1 * a1 + cos (lat1) * cos (lat2) * a2 * a2;
+ sa = sqrt (a);
+ if (sa <= 1.0)
+   {c = 2 * asin (sa);}
+ else
+   {c = 2 * asin (1.0);}
+ d = 6378.137 * c;
+
+ return km_to_distance(d);
+}
diff --git a/3rdparty/Routino/src/segmentsx.h b/3rdparty/Routino/src/segmentsx.h
new file mode 100644
index 0000000..df04c62
--- /dev/null
+++ b/3rdparty/Routino/src/segmentsx.h
@@ -0,0 +1,228 @@
+/***************************************
+ A header file for the extended segments.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2013 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef SEGMENTSX_H
+#define SEGMENTSX_H    /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+
+#include "types.h"
+
+#include "typesx.h"
+
+#include "cache.h"
+#include "files.h"
+
+
+/* Data structures */
+
+
+/*+ An extended structure used for processing. +*/
+struct _SegmentX
+{
+ index_t    node1;              /*+ The NodeX index of the starting node. +*/
+ index_t    node2;              /*+ The NodeX index of the finishing node. +*/
+
+ index_t    next2;              /*+ The index of the next segment with the same node2. +*/
+
+ index_t    way;                /*+ The WayX index of the way. +*/
+
+ distance_t distance;           /*+ The distance between the nodes. +*/
+};
+
+
+/*+ A structure containing a set of segments (memory format). +*/
+struct _SegmentsX
+{
+ char      *filename_tmp;       /*+ The name of the temporary file (for the SegmentsX). +*/
+
+ int        fd;                 /*+ The file descriptor of the open file (for the SegmentsX). +*/
+
+ index_t    number;             /*+ The number of extended segments still being considered. +*/
+
+#if !SLIM
+
+ SegmentX  *data;               /*+ The extended segment data (when mapped into memory). +*/
+
+#else
+
+ SegmentX   cached[4];          /*+ Four cached extended segments read from the file in slim mode. +*/
+ index_t    incache[4];         /*+ The indexes of the cached extended segments. +*/
+
+ SegmentXCache *cache;          /*+ A RAM cache of extended segments read from the file. +*/
+
+#endif
+
+ index_t   *firstnode;          /*+ The first segment index for each node. +*/
+
+ index_t   *next1;              /*+ The index of the next segment with the same node1 (used while pruning). +*/
+
+ BitMask   *usedway;            /*+ A flag to indicate if a way is used (used for removing pruned ways). +*/
+};
+
+
+/* Functions in segmentsx.c */
+
+SegmentsX *NewSegmentList(void);
+void FreeSegmentList(SegmentsX *segmentsx);
+
+void AppendSegmentList(SegmentsX *segmentsx,index_t way,index_t node1,index_t node2,distance_t distance);
+void FinishSegmentList(SegmentsX *segmentsx);
+
+SegmentX *FirstSegmentX(SegmentsX *segmentsx,index_t nodeindex,int position);
+SegmentX *NextSegmentX(SegmentsX *segmentsx,SegmentX *segmentx,index_t nodeindex);
+
+void SortSegmentList(SegmentsX *segmentsx);
+
+void IndexSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx);
+
+void ProcessSegments(SegmentsX *segmentsx,NodesX *nodesx,WaysX *waysx);
+
+void RemovePrunedSegments(SegmentsX *segmentsx,WaysX *waysx);
+
+void DeduplicateSuperSegments(SegmentsX *segmentsx,WaysX *waysx);
+
+void SortSegmentListGeographically(SegmentsX *segmentsx,NodesX *nodesx);
+
+void SaveSegmentList(SegmentsX *segmentsx,const char *filename);
+
+
+/* Macros / inline functions */
+
+/*+ Return true if this is a pruned segment. +*/
+#define IsPrunedSegmentX(xxx)   ((xxx)->node1==NO_NODE)
+
+
+#if !SLIM
+
+#define LookupSegmentX(segmentsx,index,position)         &(segmentsx)->data[index]
+
+#define IndexSegmentX(segmentsx,segmentx)                (index_t)((segmentx)-&(segmentsx)->data[0])
+
+#define PutBackSegmentX(segmentsx,segmentx)              while(0) { /* nop */ }
+
+#define ReLookupSegmentX(segmentsx,segmentx)             while(0) { /* nop */ }
+  
+#else
+
+/* Prototypes */
+
+static inline SegmentX *LookupSegmentX(SegmentsX *segmentsx,index_t index,int position);
+
+static inline index_t IndexSegmentX(SegmentsX *segmentsx,SegmentX *segmentx);
+
+static inline void PutBackSegmentX(SegmentsX *segmentsx,SegmentX *segmentx);
+
+static inline void ReLookupSegmentX(SegmentsX *segmentsx,SegmentX *segmentx);
+
+CACHE_NEWCACHE_PROTO(SegmentX)
+CACHE_DELETECACHE_PROTO(SegmentX)
+CACHE_FETCHCACHE_PROTO(SegmentX)
+CACHE_REPLACECACHE_PROTO(SegmentX)
+CACHE_INVALIDATECACHE_PROTO(SegmentX)
+
+
+/* Inline functions */
+
+CACHE_STRUCTURE(SegmentX)
+CACHE_NEWCACHE(SegmentX)
+CACHE_DELETECACHE(SegmentX)
+CACHE_FETCHCACHE(SegmentX)
+CACHE_REPLACECACHE(SegmentX)
+CACHE_INVALIDATECACHE(SegmentX)
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Lookup a particular extended segment with the specified id from the file on disk.
+
+  SegmentX *LookupSegmentX Returns a pointer to a cached copy of the extended segment.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  index_t index The segment index to look for.
+
+  int position The position in the cache to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline SegmentX *LookupSegmentX(SegmentsX *segmentsx,index_t index,int position)
+{
+ segmentsx->cached[position-1]=*FetchCachedSegmentX(segmentsx->cache,index,segmentsx->fd,0);
+
+ segmentsx->incache[position-1]=index;
+
+ return(&segmentsx->cached[position-1]);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the extended segment index for a particular extended segment pointer.
+
+  index_t IndexSegmentX Returns the index of the extended segment.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  SegmentX *segmentx The extended segment whose index is to be found.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline index_t IndexSegmentX(SegmentsX *segmentsx,SegmentX *segmentx)
+{
+ int position1=segmentx-&segmentsx->cached[0];
+
+ return(segmentsx->incache[position1]);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Put back an extended segment's data into the file on disk.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  SegmentX *segmentx The extended segment to be put back.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline void PutBackSegmentX(SegmentsX *segmentsx,SegmentX *segmentx)
+{
+ int position1=segmentx-&segmentsx->cached[0];
+
+ ReplaceCachedSegmentX(segmentsx->cache,segmentx,segmentsx->incache[position1],segmentsx->fd,0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Lookup an extended segment's data from the disk into file again after the disk was updated.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  SegmentX *segmentx The extended segment to refresh.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline void ReLookupSegmentX(SegmentsX *segmentsx,SegmentX *segmentx)
+{
+ int position1=segmentx-&segmentsx->cached[0];
+
+ segmentsx->cached[position1]=*FetchCachedSegmentX(segmentsx->cache,segmentsx->incache[position1],segmentsx->fd,0);
+}
+
+#endif /* SLIM */
+
+
+#endif /* SEGMENTSX_H */
diff --git a/3rdparty/Routino/src/sorting.c b/3rdparty/Routino/src/sorting.c
new file mode 100644
index 0000000..6390c33
--- /dev/null
+++ b/3rdparty/Routino/src/sorting.c
@@ -0,0 +1,1078 @@
+/***************************************
+ Merge sort functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2009-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(USE_PTHREADS) && USE_PTHREADS
+#include <pthread.h>
+#endif
+
+#include "types.h"
+
+#include "logging.h"
+#include "files.h"
+#include "sorting.h"
+
+
+/* Global variables */
+
+/*+ The command line '--tmpdir' option or its default value. +*/
+extern char *option_tmpdirname;
+
+/*+ The amount of RAM to use for filesorting. +*/
+extern size_t option_filesort_ramsize;
+
+/*+ The number of filesorting threads allowed. +*/
+extern int option_filesort_threads;
+
+
+/* Thread data type definitions */
+
+/*+ A data type for holding data for a thread. +*/
+typedef struct _thread_data
+ {
+#if defined(USE_PTHREADS) && USE_PTHREADS
+
+  pthread_t thread;             /*+ The thread identifier. +*/
+
+  int       running;            /*+ A flag indicating the current state of the thread. +*/
+
+#endif
+
+  char     *data;               /*+ The main data array. +*/
+  void    **datap;              /*+ An array of pointers to the data objects. +*/
+  size_t    n;                  /*+ The number of pointers. +*/
+
+  char    *filename;            /*+ The name of the file to write the results to. +*/
+
+  size_t   itemsize;            /*+ The size of each item. +*/
+  int    (*compare)(const void*,const void*); /*+ The comparison function. +*/
+ }
+ thread_data;
+
+/* Thread variables */
+
+#if defined(USE_PTHREADS) && USE_PTHREADS
+
+static pthread_mutex_t running_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t running_cond = PTHREAD_COND_INITIALIZER;
+
+#endif
+
+/* Thread helper functions */
+
+static void *filesort_fixed_heapsort_thread(thread_data *thread);
+static void *filesort_vary_heapsort_thread(thread_data *thread);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  A function to sort the contents of a file of fixed length objects using a
+  limited amount of RAM.
+
+  The data is sorted using a "Merge sort" http://en.wikipedia.org/wiki/Merge_sort
+  and in particular an "external sort" http://en.wikipedia.org/wiki/External_sorting.
+  The individual sort steps and the merge step both use a "Heap sort"
+  http://en.wikipedia.org/wiki/Heapsort.  The combination of the two should work well
+  if the data is already partially sorted.
+
+  index_t filesort_fixed Returns the number of objects kept.
+
+  int fd_in The file descriptor of the input file (opened for reading and at the beginning).
+
+  int fd_out The file descriptor of the output file (opened for writing and empty).
+
+  size_t itemsize The size of each item in the file that needs sorting.
+
+  int (*pre_sort_function)(void *,index_t) If non-NULL then this function is called for
+     each item before they have been sorted.  The second parameter is the number of objects
+     previously read from the input file.  If the function returns 1 then the object is kept
+     and it is sorted, otherwise it is ignored.
+
+  int (*compare_function)(const void*, const void*) The comparison function.  This is identical
+     to qsort if the data to be sorted is an array of things not pointers.
+
+  int (*post_sort_function)(void *,index_t) If non-NULL then this function is called for
+     each item after they have been sorted.  The second parameter is the number of objects
+     already written to the output file.  If the function returns 1 then the object is written
+     to the output file., otherwise it is ignored.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*pre_sort_function)(void*,index_t),
+                                                            int (*compare_function)(const void*,const void*),
+                                                            int (*post_sort_function)(void*,index_t))
+{
+ int *fds=NULL,*heap=NULL;
+ int nfiles=0,ndata=0;
+ index_t count_out=0,count_in=0,total=0;
+ size_t nitems;
+ char *data;
+ void **datap;
+ thread_data *threads;
+ size_t item;
+ int i,more=1;
+#if defined(USE_PTHREADS) && USE_PTHREADS
+ int nthreads=0;
+#endif
+
+ /* Allocate the RAM buffer and other bits */
+
+ nitems=SizeFileFD(fd_in)/itemsize;
+
+ if(nitems==0)
+    return(0);
+
+ if((nitems*(itemsize+sizeof(void*)))<option_filesort_ramsize)
+    nitems=1+nitems/option_filesort_threads;
+ else
+    nitems=option_filesort_ramsize/(option_filesort_threads*(itemsize+sizeof(void*)));
+
+ threads=(thread_data*)calloc(option_filesort_threads,sizeof(thread_data));
+
+ for(i=0;i<option_filesort_threads;i++)
+   {
+    threads[i].data=malloc(nitems*itemsize);
+    threads[i].datap=malloc(nitems*sizeof(void*));
+
+    log_malloc(threads[i].data,nitems*itemsize);
+    log_malloc(threads[i].datap,nitems*sizeof(void*));
+
+    threads[i].filename=(char*)malloc(strlen(option_tmpdirname)+24);
+
+    threads[i].itemsize=itemsize;
+    threads[i].compare=compare_function;
+   }
+
+ /* Loop around, fill the buffer, sort the data and write a temporary file */
+
+ do
+   {
+    int thread=0;
+
+#if defined(USE_PTHREADS) && USE_PTHREADS
+
+    if(option_filesort_threads>1)
+      {
+       /* Find a spare slot (one *must* be unused at all times) */
+
+       pthread_mutex_lock(&running_mutex);
+
+       for(thread=0;thread<option_filesort_threads;thread++)
+          if(!threads[thread].running)
+             break;
+
+       pthread_mutex_unlock(&running_mutex);
+      }
+
+#endif
+
+    /* Read in the data and create pointers */
+
+    for(item=0;item<nitems;)
+      {
+       threads[thread].datap[item]=threads[thread].data+item*itemsize;
+
+       if(ReadFileBuffered(fd_in,threads[thread].datap[item],itemsize))
+         {
+          more=0;
+          break;
+         }
+
+       if(!pre_sort_function || pre_sort_function(threads[thread].datap[item],count_in))
+         {
+          item++;
+          total++;
+         }
+
+       count_in++;
+      }
+
+    threads[thread].n=item;
+
+    /* Shortcut if there is no previous data and no more data (i.e. no data at all) */
+
+    if(more==0 && total==0)
+       goto tidy_and_exit;
+
+    /* No new data read in this time round */
+
+    if(threads[thread].n==0)
+       break;
+
+    /* Sort the data pointers using a heap sort (potentially in a thread) */
+
+    sprintf(threads[thread].filename,"%s/filesort.%d.tmp",option_tmpdirname,nfiles);
+
+#if defined(USE_PTHREADS) && USE_PTHREADS
+
+    /* Shortcut if only one file, don't write to disk */
+
+    if(more==0 && nfiles==0)
+       filesort_heapsort(threads[thread].datap,threads[thread].n,threads[thread].compare);
+    else if(option_filesort_threads>1)
+      {
+       pthread_mutex_lock(&running_mutex);
+
+       while(nthreads==(option_filesort_threads-1))
+         {
+          for(i=0;i<option_filesort_threads;i++)
+             if(threads[i].running==2)
+               {
+                pthread_join(threads[i].thread,NULL);
+                threads[i].running=0;
+                nthreads--;
+               }
+
+          if(nthreads==(option_filesort_threads-1))
+             pthread_cond_wait(&running_cond,&running_mutex);
+         }
+
+       threads[thread].running=1;
+
+       pthread_mutex_unlock(&running_mutex);
+
+       pthread_create(&threads[thread].thread,NULL,(void* (*)(void*))filesort_fixed_heapsort_thread,&threads[thread]);
+
+       nthreads++;
+      }
+    else
+       filesort_fixed_heapsort_thread(&threads[thread]);
+
+#else
+
+    /* Shortcut if only one file, don't write to disk */
+
+    if(more==0 && nfiles==0)
+       filesort_heapsort(threads[thread].datap,threads[thread].n,threads[thread].compare);
+    else
+       filesort_fixed_heapsort_thread(&threads[thread]);
+
+#endif
+
+    nfiles++;
+   }
+ while(more);
+
+ /* Wait for all of the threads to finish */
+
+#if defined(USE_PTHREADS) && USE_PTHREADS
+
+ while(option_filesort_threads>1 && nthreads)
+   {
+    pthread_mutex_lock(&running_mutex);
+
+    pthread_cond_wait(&running_cond,&running_mutex);
+
+    for(i=0;i<option_filesort_threads;i++)
+       if(threads[i].running==2)
+         {
+          pthread_join(threads[i].thread,NULL);
+          threads[i].running=0;
+          nthreads--;
+         }
+
+    pthread_mutex_unlock(&running_mutex);
+   }
+
+#endif
+
+ /* Shortcut if only one file, lucky for us we still have the data in RAM) */
+
+ if(nfiles==1)
+   {
+    for(item=0;item<threads[0].n;item++)
+      {
+       if(!post_sort_function || post_sort_function(threads[0].datap[item],count_out))
+         {
+          WriteFileBuffered(fd_out,threads[0].datap[item],itemsize);
+          count_out++;
+         }
+      }
+
+    DeleteFile(threads[0].filename);
+
+    goto tidy_and_exit;
+   }
+
+ /* Check that number of files is less than file size */
+
+ logassert((unsigned)nfiles<nitems,"Too many temporary files (use more sorting memory?)");
+
+ /* Open all of the temporary files */
+
+ fds=(int*)malloc(nfiles*sizeof(int));
+
+ for(i=0;i<nfiles;i++)
+   {
+    char *filename=threads[0].filename;
+
+    sprintf(filename,"%s/filesort.%d.tmp",option_tmpdirname,i);
+
+    fds[i]=ReOpenFileBuffered(filename);
+
+    DeleteFile(filename);
+   }
+
+ /* Perform an n-way merge using a binary heap */
+
+ heap=(int*)malloc((1+nfiles)*sizeof(int));
+
+ data =threads[0].data;
+ datap=threads[0].datap;
+
+ /* Fill the heap to start with */
+
+ for(i=0;i<nfiles;i++)
+   {
+    int index;
+
+    datap[i]=data+i*itemsize;
+
+    ReadFileBuffered(fds[i],datap[i],itemsize);
+
+    index=i+1;
+
+    heap[index]=i;
+
+    /* Bubble up the new value */
+
+    while(index>1)
+      {
+       int newindex;
+       int temp;
+
+       newindex=index/2;
+
+       if(compare_function(datap[heap[index]],datap[heap[newindex]])>=0)
+          break;
+
+       temp=heap[index];
+       heap[index]=heap[newindex];
+       heap[newindex]=temp;
+
+       index=newindex;
+      }
+   }
+
+ /* Repeatedly pull out the root of the heap and refill from the same file */
+
+ ndata=nfiles;
+
+ do
+   {
+    int index=1;
+
+    if(!post_sort_function || post_sort_function(datap[heap[index]],count_out))
+      {
+       WriteFileBuffered(fd_out,datap[heap[index]],itemsize);
+       count_out++;
+      }
+
+    if(ReadFileBuffered(fds[heap[index]],datap[heap[index]],itemsize))
+      {
+       heap[index]=heap[ndata];
+       ndata--;
+      }
+
+    /* Bubble down the new value */
+
+    while((2*index)<ndata)
+      {
+       int newindex;
+       int temp;
+
+       newindex=2*index;
+
+       if(compare_function(datap[heap[newindex]],datap[heap[newindex+1]])>=0)
+          newindex=newindex+1;
+
+       if(compare_function(datap[heap[index]],datap[heap[newindex]])<=0)
+          break;
+
+       temp=heap[newindex];
+       heap[newindex]=heap[index];
+       heap[index]=temp;
+
+       index=newindex;
+      }
+
+    if((2*index)==ndata)
+      {
+       int newindex;
+       int temp;
+
+       newindex=2*index;
+
+       if(compare_function(datap[heap[index]],datap[heap[newindex]])<=0)
+          ; /* break */
+       else
+         {
+          temp=heap[newindex];
+          heap[newindex]=heap[index];
+          heap[index]=temp;
+         }
+      }
+   }
+ while(ndata>0);
+
+ /* Tidy up */
+
+ tidy_and_exit:
+
+ if(fds)
+   {
+    for(i=0;i<nfiles;i++)
+       CloseFileBuffered(fds[i]);
+    free(fds);
+   }
+
+ if(heap)
+    free(heap);
+
+ for(i=0;i<option_filesort_threads;i++)
+   {
+    log_free(threads[i].data);
+    log_free(threads[i].datap);
+
+    free(threads[i].data);
+    free(threads[i].datap);
+
+    free(threads[i].filename);
+   }
+
+ free(threads);
+
+ return(count_out);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  A function to sort the contents of a file of variable length objects (each
+  preceded by its length in FILESORT_VARSIZE bytes) using a limited amount of RAM.
+
+  The data is sorted using a "Merge sort" http://en.wikipedia.org/wiki/Merge_sort
+  and in particular an "external sort" http://en.wikipedia.org/wiki/External_sorting.
+  The individual sort steps and the merge step both use a "Heap sort"
+  http://en.wikipedia.org/wiki/Heapsort.  The combination of the two should work well
+  if the data is already partially sorted.
+
+  index_t filesort_vary Returns the number of objects kept.
+
+  int fd_in The file descriptor of the input file (opened for reading and at the beginning).
+
+  int fd_out The file descriptor of the output file (opened for writing and empty).
+
+  int (*pre_sort_function)(void *,index_t) If non-NULL then this function is called for
+     each item before they have been sorted.  The second parameter is the number of objects
+     previously read from the input file.  If the function returns 1 then the object is kept
+     and it is sorted, otherwise it is ignored.
+
+  int (*compare_function)(const void*, const void*) The comparison function.  This is identical
+     to qsort if the data to be sorted is an array of things not pointers.
+
+  int (*post_sort_function)(void *,index_t) If non-NULL then this function is called for
+     each item after they have been sorted.  The second parameter is the number of objects
+     already written to the output file.  If the function returns 1 then the object is written
+     to the output file., otherwise it is ignored.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t filesort_vary(int fd_in,int fd_out,int (*pre_sort_function)(void*,index_t),
+                                           int (*compare_function)(const void*,const void*),
+                                           int (*post_sort_function)(void*,index_t))
+{
+ int *fds=NULL,*heap=NULL;
+ int nfiles=0,ndata=0;
+ index_t count_out=0,count_in=0,total=0;
+ size_t datasize;
+ FILESORT_VARINT nextitemsize,largestitemsize=0;
+ char *data;
+ void **datap;
+ thread_data *threads;
+ size_t item;
+ int i,more=1;
+#if defined(USE_PTHREADS) && USE_PTHREADS
+ int nthreads=0;
+#endif
+
+ /* Allocate the RAM buffer and other bits */
+
+ datasize=SizeFileFD(fd_in);
+
+ if(datasize==0)
+    return(0);
+
+ /* We can not know in advance how many data items there are.  Each
+    one will require RAM for data, FILESORT_VARALIGN and sizeof(void*)
+    Assume that data+FILESORT_VARALIGN+sizeof(void*) is 4*data. */
+
+ if((datasize*4)<option_filesort_ramsize)
+    datasize=(datasize*4)/option_filesort_threads;
+ else
+    datasize=option_filesort_ramsize/option_filesort_threads;
+
+ threads=(thread_data*)calloc(option_filesort_threads,sizeof(thread_data));
+
+ for(i=0;i<option_filesort_threads;i++)
+   {
+    threads[i].data=malloc(datasize);
+    threads[i].datap=NULL;
+
+    log_malloc(threads[i].data,datasize);
+
+    threads[i].filename=(char*)malloc(strlen(option_tmpdirname)+24);
+
+    threads[i].compare=compare_function;
+   }
+
+ /* Loop around, fill the buffer, sort the data and write a temporary file */
+
+ if(ReadFileBuffered(fd_in,&nextitemsize,FILESORT_VARSIZE))    /* Always have the next item size known in advance */
+    goto tidy_and_exit;
+
+ do
+   {
+    size_t ramused=FILESORT_VARALIGN-FILESORT_VARSIZE;
+    int thread=0;
+
+#if defined(USE_PTHREADS) && USE_PTHREADS
+
+    if(option_filesort_threads>1)
+      {
+       /* Find a spare slot (one *must* be unused at all times) */
+
+       pthread_mutex_lock(&running_mutex);
+
+       for(thread=0;thread<option_filesort_threads;thread++)
+          if(!threads[thread].running)
+             break;
+
+       pthread_mutex_unlock(&running_mutex);
+      }
+
+#endif
+
+    threads[thread].datap=(void**)(threads[thread].data+datasize);
+
+    threads[thread].n=0;
+
+    /* Read in the data and create pointers */
+
+    while((ramused+FILESORT_VARSIZE+nextitemsize)<=(size_t)((char*)threads[thread].datap-sizeof(void*)-threads[thread].data))
+      {
+       FILESORT_VARINT itemsize=nextitemsize;
+
+       *(FILESORT_VARINT*)(threads[thread].data+ramused)=itemsize;
+
+       ramused+=FILESORT_VARSIZE;
+
+       ReadFileBuffered(fd_in,threads[thread].data+ramused,itemsize);
+
+       if(!pre_sort_function || pre_sort_function(threads[thread].data+ramused,count_in))
+         {
+          *--threads[thread].datap=threads[thread].data+ramused; /* points to real data */
+
+          if(itemsize>largestitemsize)
+             largestitemsize=itemsize;
+
+          ramused+=itemsize;
+
+          ramused =FILESORT_VARALIGN*((ramused+FILESORT_VARSIZE-1)/FILESORT_VARALIGN);
+          ramused+=FILESORT_VARALIGN-FILESORT_VARSIZE;
+
+          total++;
+          threads[thread].n++;
+         }
+       else
+          ramused-=FILESORT_VARSIZE;
+
+       count_in++;
+
+       if(ReadFileBuffered(fd_in,&nextitemsize,FILESORT_VARSIZE))
+         {
+          more=0;
+          break;
+         }
+      }
+
+    /* No new data read in this time round */
+
+    if(threads[thread].n==0)
+       break;
+
+    /* Sort the data pointers using a heap sort (potentially in a thread) */
+
+    if(more==0 && nfiles==0)
+       threads[thread].filename[0]=0;
+    else
+       sprintf(threads[thread].filename,"%s/filesort.%d.tmp",option_tmpdirname,nfiles);
+
+#if defined(USE_PTHREADS) && USE_PTHREADS
+
+    /* Shortcut if only one file, don't write to disk */
+
+    if(more==0 && nfiles==0)
+       filesort_heapsort(threads[thread].datap,threads[thread].n,threads[thread].compare);
+    else if(option_filesort_threads>1)
+      {
+       pthread_mutex_lock(&running_mutex);
+
+       while(nthreads==(option_filesort_threads-1))
+         {
+          for(i=0;i<option_filesort_threads;i++)
+             if(threads[i].running==2)
+               {
+                pthread_join(threads[i].thread,NULL);
+                threads[i].running=0;
+                nthreads--;
+               }
+
+          if(nthreads==(option_filesort_threads-1))
+             pthread_cond_wait(&running_cond,&running_mutex);
+         }
+
+       threads[thread].running=1;
+
+       pthread_mutex_unlock(&running_mutex);
+
+       pthread_create(&threads[thread].thread,NULL,(void* (*)(void*))filesort_vary_heapsort_thread,&threads[thread]);
+
+       nthreads++;
+      }
+    else
+       filesort_vary_heapsort_thread(&threads[thread]);
+
+#else
+
+    /* Shortcut if only one file, don't write to disk */
+
+    if(more==0 && nfiles==0)
+       filesort_heapsort(threads[thread].datap,threads[thread].n,threads[thread].compare);
+    else
+       filesort_vary_heapsort_thread(&threads[thread]);
+
+#endif
+
+    nfiles++;
+   }
+ while(more);
+
+ /* Wait for all of the threads to finish */
+
+#if defined(USE_PTHREADS) && USE_PTHREADS
+
+ while(option_filesort_threads>1 && nthreads)
+   {
+    pthread_mutex_lock(&running_mutex);
+
+    pthread_cond_wait(&running_cond,&running_mutex);
+
+    for(i=0;i<option_filesort_threads;i++)
+       if(threads[i].running==2)
+         {
+          pthread_join(threads[i].thread,NULL);
+          threads[i].running=0;
+          nthreads--;
+         }
+
+    pthread_mutex_unlock(&running_mutex);
+   }
+
+#endif
+
+ /* Shortcut if only one file, lucky for us we still have the data in RAM) */
+
+ if(nfiles==1)
+   {
+    for(item=0;item<threads[0].n;item++)
+      {
+       if(!post_sort_function || post_sort_function(threads[0].datap[item],count_out))
+         {
+          FILESORT_VARINT itemsize=*(FILESORT_VARINT*)((char*)threads[0].datap[item]-FILESORT_VARSIZE);
+
+          WriteFileBuffered(fd_out,(char*)threads[0].datap[item]-FILESORT_VARSIZE,itemsize+FILESORT_VARSIZE);
+          count_out++;
+         }
+      }
+
+    DeleteFile(threads[0].filename);
+
+    goto tidy_and_exit;
+   }
+
+ /* Check that number of files is less than file size */
+
+ largestitemsize=FILESORT_VARALIGN*(1+(largestitemsize+FILESORT_VARALIGN-FILESORT_VARSIZE)/FILESORT_VARALIGN);
+
+ logassert((unsigned)nfiles<((datasize-nfiles*sizeof(void*))/largestitemsize),"Too many temporary files (use more sorting memory?)");
+
+ /* Open all of the temporary files */
+
+ fds=(int*)malloc(nfiles*sizeof(int));
+
+ for(i=0;i<nfiles;i++)
+   {
+    char *filename=threads[0].filename;
+
+    sprintf(filename,"%s/filesort.%d.tmp",option_tmpdirname,i);
+
+    fds[i]=ReOpenFileBuffered(filename);
+
+    DeleteFile(filename);
+   }
+
+ /* Perform an n-way merge using a binary heap */
+
+ heap=(int*)malloc((1+nfiles)*sizeof(int));
+
+ data=threads[0].data;
+ datap=(void**)(data+datasize-nfiles*sizeof(void*));
+
+ /* Fill the heap to start with */
+
+ for(i=0;i<nfiles;i++)
+   {
+    int index;
+    FILESORT_VARINT itemsize;
+
+    datap[i]=data+FILESORT_VARALIGN-FILESORT_VARSIZE+i*largestitemsize;
+
+    ReadFileBuffered(fds[i],&itemsize,FILESORT_VARSIZE);
+
+    *(FILESORT_VARINT*)((char*)datap[i]-FILESORT_VARSIZE)=itemsize;
+
+    ReadFileBuffered(fds[i],datap[i],itemsize);
+
+    index=i+1;
+
+    heap[index]=i;
+
+    /* Bubble up the new value */
+
+    while(index>1)
+      {
+       int newindex;
+       int temp;
+
+       newindex=index/2;
+
+       if(compare_function(datap[heap[index]],datap[heap[newindex]])>=0)
+          break;
+
+       temp=heap[index];
+       heap[index]=heap[newindex];
+       heap[newindex]=temp;
+
+       index=newindex;
+      }
+   }
+
+ /* Repeatedly pull out the root of the heap and refill from the same file */
+
+ ndata=nfiles;
+
+ do
+   {
+    int index=1;
+    FILESORT_VARINT itemsize;
+
+    if(!post_sort_function || post_sort_function(datap[heap[index]],count_out))
+      {
+       itemsize=*(FILESORT_VARINT*)((char*)datap[heap[index]]-FILESORT_VARSIZE);
+
+       WriteFileBuffered(fd_out,(char*)datap[heap[index]]-FILESORT_VARSIZE,itemsize+FILESORT_VARSIZE);
+       count_out++;
+      }
+
+    if(ReadFileBuffered(fds[heap[index]],&itemsize,FILESORT_VARSIZE))
+      {
+       heap[index]=heap[ndata];
+       ndata--;
+      }
+    else
+      {
+       *(FILESORT_VARINT*)((char*)datap[heap[index]]-FILESORT_VARSIZE)=itemsize;
+
+       ReadFileBuffered(fds[heap[index]],datap[heap[index]],itemsize);
+      }
+
+    /* Bubble down the new value */
+
+    while((2*index)<ndata)
+      {
+       int newindex;
+       int temp;
+
+       newindex=2*index;
+
+       if(compare_function(datap[heap[newindex]],datap[heap[newindex+1]])>=0)
+          newindex=newindex+1;
+
+       if(compare_function(datap[heap[index]],datap[heap[newindex]])<=0)
+          break;
+
+       temp=heap[newindex];
+       heap[newindex]=heap[index];
+       heap[index]=temp;
+
+       index=newindex;
+      }
+
+    if((2*index)==ndata)
+      {
+       int newindex;
+       int temp;
+
+       newindex=2*index;
+
+       if(compare_function(datap[heap[index]],datap[heap[newindex]])<=0)
+          ; /* break */
+       else
+         {
+          temp=heap[newindex];
+          heap[newindex]=heap[index];
+          heap[index]=temp;
+         }
+      }
+   }
+ while(ndata>0);
+
+ /* Tidy up */
+
+ tidy_and_exit:
+
+ if(fds)
+   {
+    for(i=0;i<nfiles;i++)
+       CloseFileBuffered(fds[i]);
+    free(fds);
+   }
+
+ if(heap)
+    free(heap);
+
+ for(i=0;i<option_filesort_threads;i++)
+   {
+    log_free(threads[i].data);
+
+    free(threads[i].data);
+
+    free(threads[i].filename);
+   }
+
+ free(threads);
+
+ return(count_out);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  A wrapper function that can be run in a thread for fixed data.
+
+  void *filesort_fixed_heapsort_thread Returns NULL (required to return void*).
+
+  thread_data *thread The data to be processed in this thread.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void *filesort_fixed_heapsort_thread(thread_data *thread)
+{
+ int fd;
+ size_t item;
+
+ /* Sort the data pointers using a heap sort */
+
+ filesort_heapsort(thread->datap,thread->n,thread->compare);
+
+ /* Create a temporary file and write the result */
+
+ fd=OpenFileBufferedNew(thread->filename);
+
+ for(item=0;item<thread->n;item++)
+    WriteFileBuffered(fd,thread->datap[item],thread->itemsize);
+
+ CloseFileBuffered(fd);
+
+#if defined(USE_PTHREADS) && USE_PTHREADS
+
+ if(option_filesort_threads>1)
+   {
+    pthread_mutex_lock(&running_mutex);
+
+    thread->running=2;
+
+    pthread_cond_signal(&running_cond);
+
+    pthread_mutex_unlock(&running_mutex);
+   }
+
+#endif
+
+ return(NULL);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  A wrapper function that can be run in a thread for variable data.
+
+  void *filesort_vary_heapsort_thread Returns NULL (required to return void*).
+
+  thread_data *thread The data to be processed in this thread.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void *filesort_vary_heapsort_thread(thread_data *thread)
+{
+ int fd;
+ size_t item;
+
+ /* Sort the data pointers using a heap sort */
+
+ filesort_heapsort(thread->datap,thread->n,thread->compare);
+
+ /* Create a temporary file and write the result */
+
+ fd=OpenFileBufferedNew(thread->filename);
+
+ for(item=0;item<thread->n;item++)
+   {
+    FILESORT_VARINT itemsize=*(FILESORT_VARINT*)((char*)thread->datap[item]-FILESORT_VARSIZE);
+
+    WriteFileBuffered(fd,(char*)thread->datap[item]-FILESORT_VARSIZE,itemsize+FILESORT_VARSIZE);
+   }
+
+ CloseFileBuffered(fd);
+
+#if defined(USE_PTHREADS) && USE_PTHREADS
+
+ if(option_filesort_threads>1)
+   {
+    pthread_mutex_lock(&running_mutex);
+
+    thread->running=2;
+
+    pthread_cond_signal(&running_cond);
+
+    pthread_mutex_unlock(&running_mutex);
+   }
+
+#endif
+
+ return(NULL);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  A function to sort an array of pointers efficiently.
+
+  The data is sorted using a "Heap sort" http://en.wikipedia.org/wiki/Heapsort,
+  in particular, this is good because it can operate in-place and doesn't
+  allocate more memory like using qsort() does.
+
+  void **datap A pointer to the array of pointers to sort.
+
+  size_t nitems The number of items of data to sort.
+
+  int (*compare_function)(const void*, const void*) The comparison function.  This is identical
+     to qsort if the data to be sorted is an array of things not pointers.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void filesort_heapsort(void **datap,size_t nitems,int(*compare_function)(const void*, const void*))
+{
+ void **datap1=&datap[-1];
+ size_t item;
+
+ /* Fill the heap by pretending to insert the data that is already there */
+
+ for(item=2;item<=nitems;item++)
+   {
+    size_t index=item;
+
+    /* Bubble up the new value (upside-down, put largest at top) */
+
+    while(index>1)
+      {
+       int newindex;
+       void *temp;
+
+       newindex=index/2;
+
+       if(compare_function(datap1[index],datap1[newindex])<=0) /* reversed comparison to filesort_fixed() above */
+          break;
+
+       temp=datap1[index];
+       datap1[index]=datap1[newindex];
+       datap1[newindex]=temp;
+
+       index=newindex;
+      }
+   }
+
+ /* Repeatedly pull out the root of the heap and swap with the bottom item */
+
+ for(item=nitems;item>1;item--)
+   {
+    size_t index=1;
+    void *temp;
+
+    temp=datap1[index];
+    datap1[index]=datap1[item];
+    datap1[item]=temp;
+
+    /* Bubble down the new value (upside-down, put largest at top) */
+
+    while((2*index)<(item-1))
+      {
+       int newindex;
+       void *temp;
+
+       newindex=2*index;
+
+       if(compare_function(datap1[newindex],datap1[newindex+1])<=0) /* reversed comparison to filesort_fixed() above */
+          newindex=newindex+1;
+
+       if(compare_function(datap1[index],datap1[newindex])>=0) /* reversed comparison to filesort_fixed() above */
+          break;
+
+       temp=datap1[newindex];
+       datap1[newindex]=datap1[index];
+       datap1[index]=temp;
+
+       index=newindex;
+      }
+
+    if((2*index)==(item-1))
+      {
+       int newindex;
+       void *temp;
+
+       newindex=2*index;
+
+       if(compare_function(datap1[index],datap1[newindex])>=0) /* reversed comparison to filesort_fixed() above */
+          ; /* break */
+       else
+         {
+          temp=datap1[newindex];
+          datap1[newindex]=datap1[index];
+          datap1[index]=temp;
+         }
+      }
+   }
+}
diff --git a/3rdparty/Routino/src/sorting.h b/3rdparty/Routino/src/sorting.h
new file mode 100644
index 0000000..8e9033e
--- /dev/null
+++ b/3rdparty/Routino/src/sorting.h
@@ -0,0 +1,59 @@
+/***************************************
+ Header file for sorting function prototypes
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2012 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef SORTING_H
+#define SORTING_H    /*+ To stop multiple inclusions. +*/
+
+#include <sys/types.h>
+
+#include "types.h"
+
+
+/* Constants */
+
+/*+ The type, size and alignment of variable to store the variable length +*/
+#define FILESORT_VARINT   unsigned short
+#define FILESORT_VARSIZE  sizeof(FILESORT_VARINT)
+#define FILESORT_VARALIGN sizeof(void*)
+
+
+/* Macros */
+
+/*+ A macro to use as a last resort in the comparison function to preserve
+    on the output the input order of items that compare equally. +*/
+#define FILESORT_PRESERVE_ORDER(a,b) ( ((a)<(b)) ? -1 : +1)
+
+
+/* Functions in sorting.c */
+
+index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*pre_sort_function)(void*,index_t),
+                                                            int (*compare_function)(const void*,const void*),
+                                                            int (*post_sort_function)(void*,index_t));
+
+index_t filesort_vary(int fd_in,int fd_out,int (*pre_sort_function)(void*,index_t),
+                                           int (*compare_function)(const void*,const void*),
+                                           int (*post_sort_function)(void*,index_t));
+
+void filesort_heapsort(void **datap,size_t nitems,int(*compare)(const void*, const void*));
+
+
+#endif /* SORTING_H */
diff --git a/3rdparty/Routino/src/superx.c b/3rdparty/Routino/src/superx.c
new file mode 100644
index 0000000..b7fc96b
--- /dev/null
+++ b/3rdparty/Routino/src/superx.c
@@ -0,0 +1,588 @@
+/***************************************
+ Super-Segment data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+
+#include "types.h"
+#include "segments.h"
+#include "ways.h"
+
+#include "typesx.h"
+#include "nodesx.h"
+#include "segmentsx.h"
+#include "waysx.h"
+#include "superx.h"
+
+#include "files.h"
+#include "logging.h"
+#include "results.h"
+
+
+/* Local functions */
+
+static Results *FindSuperRoutes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,node_t start,Way *match);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Select the super-nodes from the list of nodes.
+
+  NodesX *nodesx The set of nodes to use.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  WaysX *waysx The set of ways to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void ChooseSuperNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
+{
+ index_t i;
+ index_t nnodes=0;
+
+ if(nodesx->number==0 || segmentsx->number==0 || waysx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Finding Super-Nodes: Nodes=0 Super-Nodes=0");
+
+ /* Allocate and set the super-node markers */
+
+ if(!nodesx->super)
+   {
+    nodesx->super=AllocBitMask(nodesx->number);
+    log_malloc(nodesx->super,LengthBitMask(nodesx->number)*sizeof(BitMask));
+
+    logassert(nodesx->super,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
+
+    SetAllBits(nodesx->super,nodesx->number);
+   }
+
+ /* Map into memory / open the files */
+
+ nodesx->fd=ReOpenFileBuffered(nodesx->filename_tmp);
+
+#if !SLIM
+ segmentsx->data=MapFile(segmentsx->filename_tmp);
+ waysx->data=MapFile(waysx->filename_tmp);
+#else
+ segmentsx->fd=SlimMapFile(segmentsx->filename_tmp);
+ waysx->fd=SlimMapFile(waysx->filename_tmp);
+
+ InvalidateSegmentXCache(segmentsx->cache);
+ InvalidateWayXCache(waysx->cache);
+#endif
+
+ /* Find super-nodes */
+
+ for(i=0;i<nodesx->number;i++)
+   {
+    NodeX nodex;
+
+    ReadFileBuffered(nodesx->fd,&nodex,sizeof(NodeX));
+
+    if(IsBitSet(nodesx->super,i))
+      {
+       int issuper=0;
+
+       if(nodex.flags&(NODE_TURNRSTRCT|NODE_TURNRSTRCT2))
+          issuper=1;
+       else
+         {
+          int count=0,j;
+          Way segmentway[MAX_SEG_PER_NODE];
+          int segmentweight[MAX_SEG_PER_NODE];
+          SegmentX *segmentx=FirstSegmentX(segmentsx,i,1);
+
+          while(segmentx)
+            {
+             WayX *wayx=LookupWayX(waysx,segmentx->way,1);
+             int nsegments;
+
+             /* Segments that are loops count twice */
+
+             logassert(count<MAX_SEG_PER_NODE,"Too many segments for one node (increase MAX_SEG_PER_NODE?)"); /* Only a limited amount of information stored. */
+
+             if(segmentx->node1==segmentx->node2)
+                segmentweight[count]=2;
+             else
+                segmentweight[count]=1;
+
+             segmentway[count]=wayx->way;
+
+             /* If the node allows less traffic types than any connecting way then it is super if it allows anything */
+
+             if((wayx->way.allow&nodex.allow)!=wayx->way.allow && nodex.allow!=Transports_None)
+               {
+                issuper=1;
+                break;
+               }
+
+             nsegments=segmentweight[count];
+
+             for(j=0;j<count;j++)
+                if(wayx->way.allow & segmentway[j].allow)
+                  {
+                   /* If two ways are different in any attribute and there is a type of traffic that can use both then it is super */
+
+                   if(WaysCompare(&segmentway[j],&wayx->way))
+                     {
+                      issuper=1;
+                      break;
+                     }
+
+                   /* If there are two other segments that can be used by the same types of traffic as this one then it is super */
+
+                   nsegments+=segmentweight[j];
+                   if(nsegments>2)
+                     {
+                      issuper=1;
+                      break;
+                     }
+                  }
+
+             if(issuper)
+                break;
+
+             segmentx=NextSegmentX(segmentsx,segmentx,i);
+
+             count++;
+            }
+         }
+
+       /* Mark the node as super if it is. */
+
+       if(issuper)
+          nnodes++;
+       else
+          ClearBit(nodesx->super,i);
+      }
+
+    if(!((i+1)%10000))
+       printf_middle("Finding Super-Nodes: Nodes=%"Pindex_t" Super-Nodes=%"Pindex_t,i+1,nnodes);
+   }
+
+ /* Unmap from memory / close the files */
+
+#if !SLIM
+ segmentsx->data=UnmapFile(segmentsx->data);
+ waysx->data=UnmapFile(waysx->data);
+#else
+ segmentsx->fd=SlimUnmapFile(segmentsx->fd);
+ waysx->fd=SlimUnmapFile(waysx->fd);
+#endif
+
+ nodesx->fd=CloseFileBuffered(nodesx->fd);
+
+ /* Print the final message */
+
+ printf_last("Found Super-Nodes: Nodes=%"Pindex_t" Super-Nodes=%"Pindex_t,nodesx->number,nnodes);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create the super-segments from the existing segments.
+
+  SegmentsX *CreateSuperSegments Returns the new super segments.
+
+  NodesX *nodesx The set of nodes to use.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  WaysX *waysx The set of ways to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+SegmentsX *CreateSuperSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
+{
+ index_t i;
+ SegmentsX *supersegmentsx;
+ index_t sn=0,ss=0;
+
+ supersegmentsx=NewSegmentList();
+
+ if(segmentsx->number==0 || waysx->number==0)
+   {
+    FinishSegmentList(supersegmentsx);
+
+    return(supersegmentsx);
+   }
+
+ /* Print the start message */
+
+ printf_first("Creating Super-Segments: Super-Nodes=0 Super-Segments=0");
+
+ /* Map into memory / open the files */
+
+#if !SLIM
+ nodesx->data=MapFile(nodesx->filename_tmp);
+ segmentsx->data=MapFile(segmentsx->filename_tmp);
+ waysx->data=MapFile(waysx->filename_tmp);
+#else
+ nodesx->fd=SlimMapFile(nodesx->filename_tmp);
+ segmentsx->fd=SlimMapFile(segmentsx->filename_tmp);
+ waysx->fd=SlimMapFile(waysx->filename_tmp);
+
+ InvalidateNodeXCache(nodesx->cache);
+ InvalidateSegmentXCache(segmentsx->cache);
+ InvalidateWayXCache(waysx->cache);
+#endif
+
+ /* Create super-segments for each super-node. */
+
+ for(i=0;i<nodesx->number;i++)
+   {
+    if(IsBitSet(nodesx->super,i))
+      {
+       SegmentX *segmentx;
+       int count=0,match;
+       Way prevway[MAX_SEG_PER_NODE];
+
+       segmentx=FirstSegmentX(segmentsx,i,1);
+
+       while(segmentx)
+         {
+          WayX *wayx=LookupWayX(waysx,segmentx->way,1);
+
+          /* Check that this type of way hasn't already been routed */
+
+          match=0;
+
+          if(count>0)
+            {
+             int j;
+
+             for(j=0;j<count;j++)
+                if(!WaysCompare(&prevway[j],&wayx->way))
+                  {
+                   match=1;
+                   break;
+                  }
+            }
+
+          logassert(count<MAX_SEG_PER_NODE,"Too many segments for one node (increase MAX_SEG_PER_NODE?)"); /* Only a limited amount of history stored. */
+
+          prevway[count++]=wayx->way;
+
+          /* Route the way and store the super-segments. */
+
+          if(!match)
+            {
+             Results *results=FindSuperRoutes(nodesx,segmentsx,waysx,i,&wayx->way);
+             Result *result=FirstResult(results);
+
+             while(result)
+               {
+                if(IsBitSet(nodesx->super,result->node) && result->segment!=NO_SEGMENT)
+                  {
+                   if(wayx->way.type&Highway_OneWay && result->node!=i)
+                      AppendSegmentList(supersegmentsx,segmentx->way,i,result->node,DISTANCE((distance_t)result->score)|ONEWAY_1TO2);
+                   else
+                      AppendSegmentList(supersegmentsx,segmentx->way,i,result->node,DISTANCE((distance_t)result->score));
+
+                   ss++;
+                  }
+
+                result=NextResult(results,result);
+               }
+            }
+
+          segmentx=NextSegmentX(segmentsx,segmentx,i);
+         }
+
+       sn++;
+
+       if(!(sn%10000))
+          printf_middle("Creating Super-Segments: Super-Nodes=%"Pindex_t" Super-Segments=%"Pindex_t,sn,ss);
+      }
+   }
+
+ FinishSegmentList(supersegmentsx);
+
+ /* Unmap from memory / close the files */
+
+#if !SLIM
+ nodesx->data=UnmapFile(nodesx->data);
+ segmentsx->data=UnmapFile(segmentsx->data);
+ waysx->data=UnmapFile(waysx->data);
+#else
+ nodesx->fd=SlimUnmapFile(nodesx->fd);
+ segmentsx->fd=SlimUnmapFile(segmentsx->fd);
+ waysx->fd=SlimUnmapFile(waysx->fd);
+#endif
+
+ /* Free the no-longer required memory */
+
+ if(segmentsx->firstnode)
+   {
+    log_free(segmentsx->firstnode);
+    free(segmentsx->firstnode);
+    segmentsx->firstnode=NULL;
+   }
+
+ /* Print the final message */
+
+ printf_last("Created Super-Segments: Super-Nodes=%"Pindex_t" Super-Segments=%"Pindex_t,sn,ss);
+
+ return(supersegmentsx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Merge the segments and super-segments into a new segment list.
+
+  SegmentsX *MergeSuperSegments Returns a new set of merged segments.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  SegmentsX *supersegmentsx The set of super-segments to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+SegmentsX *MergeSuperSegments(SegmentsX *segmentsx,SegmentsX *supersegmentsx)
+{
+ index_t i,j,lastj;
+ index_t merged=0,added=0;
+ SegmentsX *mergedsegmentsx;
+ SegmentX supersegmentx;
+
+ mergedsegmentsx=NewSegmentList();
+
+ if(segmentsx->number==0)
+   {
+    FinishSegmentList(mergedsegmentsx);
+
+    return(mergedsegmentsx);
+   }
+
+ /* Print the start message */
+
+ printf_first("Merging Segments: Segments=0 Super=0 Merged=0 Added=0");
+
+ /* Open the files */
+
+ segmentsx->fd=ReOpenFileBuffered(segmentsx->filename_tmp);
+ if(supersegmentsx->number>0)
+    supersegmentsx->fd=ReOpenFileBuffered(supersegmentsx->filename_tmp);
+
+ /* Loop through and create a new list of combined segments */
+
+ lastj=-1;
+ j=0;
+
+ for(i=0;i<segmentsx->number;i++)
+   {
+    int super=0;
+    SegmentX segmentx;
+
+    ReadFileBuffered(segmentsx->fd,&segmentx,sizeof(SegmentX));
+
+    while(j<supersegmentsx->number)
+      {
+       if(j!=lastj)
+         {
+          ReadFileBuffered(supersegmentsx->fd,&supersegmentx,sizeof(SegmentX));
+          lastj=j;
+         }
+
+       if(segmentx.node1   ==supersegmentx.node1 &&
+          segmentx.node2   ==supersegmentx.node2 &&
+          segmentx.distance==supersegmentx.distance)
+         {
+          merged++;
+          j++;
+          /* mark as super-segment and normal segment */
+          super=1;
+          break;
+         }
+       else if((segmentx.node1==supersegmentx.node1 &&
+                segmentx.node2==supersegmentx.node2) ||
+               (segmentx.node1==supersegmentx.node1 &&
+                segmentx.node2>supersegmentx.node2) ||
+               (segmentx.node1>supersegmentx.node1))
+         {
+          /* mark as super-segment */
+          AppendSegmentList(mergedsegmentsx,supersegmentx.way,supersegmentx.node1,supersegmentx.node2,supersegmentx.distance|SEGMENT_SUPER);
+          added++;
+          j++;
+         }
+       else
+         {
+          /* mark as normal segment */
+          break;
+         }
+      }
+
+    if(super)
+       AppendSegmentList(mergedsegmentsx,segmentx.way,segmentx.node1,segmentx.node2,segmentx.distance|SEGMENT_SUPER|SEGMENT_NORMAL);
+    else
+       AppendSegmentList(mergedsegmentsx,segmentx.way,segmentx.node1,segmentx.node2,segmentx.distance|SEGMENT_NORMAL);
+
+    if(!((i+1)%10000))
+       printf_middle("Merging Segments: Segments=%"Pindex_t" Super=%"Pindex_t" Merged=%"Pindex_t" Added=%"Pindex_t,i+1,j,merged,added);
+   }
+
+ if(j<supersegmentsx->number)
+   {
+    if(j==lastj)
+      {
+       AppendSegmentList(mergedsegmentsx,supersegmentx.way,supersegmentx.node1,supersegmentx.node2,supersegmentx.distance|SEGMENT_SUPER);
+
+       j++;
+      }
+
+    while(j<supersegmentsx->number)
+      {
+       ReadFileBuffered(supersegmentsx->fd,&supersegmentx,sizeof(SegmentX));
+
+       AppendSegmentList(mergedsegmentsx,supersegmentx.way,supersegmentx.node1,supersegmentx.node2,supersegmentx.distance|SEGMENT_SUPER);
+
+       added++;
+       j++;
+      }
+   }
+
+ FinishSegmentList(mergedsegmentsx);
+
+ /* Close the files */
+
+ segmentsx->fd=CloseFileBuffered(segmentsx->fd);
+ if(supersegmentsx->number>0)
+    supersegmentsx->fd=CloseFileBuffered(supersegmentsx->fd);
+
+ /* Print the final message */
+
+ printf_last("Merged Segments: Segments=%"Pindex_t" Super=%"Pindex_t" Merged=%"Pindex_t" Added=%"Pindex_t,segmentsx->number,supersegmentsx->number,merged,added);
+
+ return(mergedsegmentsx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find all routes from a specified super-node to any other super-node that follows a certain type of way.
+
+  Results *FindSuperRoutes Returns a set of results.
+
+  NodesX *nodesx The set of nodes to use.
+
+  SegmentsX *segmentsx The set of segments to use.
+
+  WaysX *waysx The set of ways to use.
+
+  node_t start The start node.
+
+  Way *match A template for the type of way that the route must follow.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static Results *FindSuperRoutes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,node_t start,Way *match)
+{
+ static Results *results=NULL; /* static allocation of return value (reset each call) */
+ static Queue *queue=NULL;     /* static allocation of internal value (reset each call) */
+ Result *result1,*result2;
+ WayX *wayx;
+
+ /* Insert the first node into the queue */
+
+ if(!results)
+    results=NewResultsList(8);
+ else
+    ResetResultsList(results);
+
+ if(!queue)
+    queue=NewQueueList(8);
+ else
+    ResetQueueList(queue);
+
+ result1=InsertResult(results,start,NO_SEGMENT);
+
+ InsertInQueue(queue,result1,0);
+
+ /* Loop across all nodes in the queue */
+
+ while((result1=PopFromQueue(queue)))
+   {
+    index_t node1;
+    SegmentX *segmentx;
+
+    node1=result1->node;
+
+    segmentx=FirstSegmentX(segmentsx,node1,2); /* position 1 is already used */
+
+    while(segmentx)
+      {
+       NodeX  *node2x;
+       index_t node2,seg2;
+       distance_t cumulative_distance;
+
+       /* must not be one-way against the direction of travel */
+       if(IsOnewayTo(segmentx,node1))
+          goto endloop;
+
+       seg2=IndexSegmentX(segmentsx,segmentx);
+
+       /* must not be a u-turn */
+       if(result1->segment==seg2)
+          goto endloop;
+
+       wayx=LookupWayX(waysx,segmentx->way,2); /* position 1 is already used */
+
+       /* must be the right type of way */
+       if(WaysCompare(&wayx->way,match))
+          goto endloop;
+
+       node2=OtherNode(segmentx,node1);
+
+       node2x=LookupNodeX(nodesx,node2,2); /* position 1 is already used */
+
+       /* Don't route beyond a node with no access */
+       if(node2x->allow==Transports_None)
+          goto endloop;
+
+       cumulative_distance=(distance_t)result1->score+DISTANCE(segmentx->distance);
+
+       result2=FindResult(results,node2,seg2);
+
+       if(!result2)                         /* New end node */
+         {
+          result2=InsertResult(results,node2,seg2);
+          result2->prev=result1;
+          result2->score=cumulative_distance;
+
+          /* don't route beyond a super-node. */
+          if(!IsBitSet(nodesx->super,node2))
+             InsertInQueue(queue,result2,cumulative_distance);
+         }
+       else if(cumulative_distance<result2->score)
+         {
+          result2->prev=result1;
+          result2->score=cumulative_distance;
+
+          /* don't route beyond a super-node. */
+          if(!IsBitSet(nodesx->super,node2))
+             InsertInQueue(queue,result2,cumulative_distance);
+         }
+
+      endloop:
+
+       segmentx=NextSegmentX(segmentsx,segmentx,node1);
+      }
+   }
+
+ return(results);
+}
diff --git a/3rdparty/Routino/src/superx.h b/3rdparty/Routino/src/superx.h
new file mode 100644
index 0000000..dc95b81
--- /dev/null
+++ b/3rdparty/Routino/src/superx.h
@@ -0,0 +1,38 @@
+/***************************************
+ Header for super-node and super-segment functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2011 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef SUPERX_H
+#define SUPERX_H    /*+ To stop multiple inclusions. +*/
+
+#include "typesx.h"
+
+
+/* Functions in superx.c */
+
+void ChooseSuperNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx);
+
+SegmentsX *CreateSuperSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx);
+
+SegmentsX *MergeSuperSegments(SegmentsX *segmentsx,SegmentsX *supersegmentsx);
+
+
+#endif /* SUPERX_H */
diff --git a/3rdparty/Routino/src/tagging.c b/3rdparty/Routino/src/tagging.c
new file mode 100644
index 0000000..97af158
--- /dev/null
+++ b/3rdparty/Routino/src/tagging.c
@@ -0,0 +1,980 @@
+/***************************************
+ Load the tagging rules from a file and the functions for handling them.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#include "files.h"
+#include "tagging.h"
+#include "xmlparse.h"
+#include "logging.h"
+
+
+/* Constants */
+
+#define TAGACTION_IF       1
+#define TAGACTION_IFNOT    2
+
+#define TAGACTION_INHERIT  3    /* Not a real action, just a marker */
+
+#define TAGACTION_SET      4
+#define TAGACTION_UNSET    5
+#define TAGACTION_OUTPUT   6
+#define TAGACTION_LOGERROR 7
+
+static const char* const default_logerror_message="ignoring it";
+
+
+/* Local variable (intialised before each use) */
+
+static int64_t current_id;
+
+/* Local parsing variables (re-initialised by DeleteXMLTaggingRules() function) */
+
+static TaggingRuleList NodeRules={NULL,0};
+static TaggingRuleList WayRules={NULL,0};
+static TaggingRuleList RelationRules={NULL,0};
+
+static int current_list_stack_depth=0;
+static TaggingRuleList **current_list_stack=NULL;
+static TaggingRuleList *current_list=NULL;
+
+/* Local parsing functions */
+
+static TaggingRuleList *AppendTaggingRule(TaggingRuleList *rules,const char *k,const char *v,int action);
+static void AppendTaggingAction(TaggingRuleList *rules,const char *k,const char *v,int action,const char *message);
+static void DeleteTaggingRuleList(TaggingRuleList *rules);
+
+static void ApplyRules(TaggingRuleList *rules,TagList *input,TagList *output,const char *match_k,const char *match_v);
+
+
+/* The XML tag processing function prototypes */
+
+//static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding);
+//static int RoutinoTaggingType_function(const char *_tag_,int _type_);
+static int NodeType_function(const char *_tag_,int _type_);
+static int WayType_function(const char *_tag_,int _type_);
+static int RelationType_function(const char *_tag_,int _type_);
+static int IfType_function(const char *_tag_,int _type_,const char *k,const char *v);
+static int IfNotType_function(const char *_tag_,int _type_,const char *k,const char *v);
+static int SetType_function(const char *_tag_,int _type_,const char *k,const char *v);
+static int UnsetType_function(const char *_tag_,int _type_,const char *k);
+static int OutputType_function(const char *_tag_,int _type_,const char *k,const char *v);
+static int LogErrorType_function(const char *_tag_,int _type_,const char *k,const char *v,const char *message);
+
+
+/* The XML tag definitions (forward declarations) */
+
+static const xmltag xmlDeclaration_tag;
+static const xmltag RoutinoTaggingType_tag;
+static const xmltag NodeType_tag;
+static const xmltag WayType_tag;
+static const xmltag RelationType_tag;
+static const xmltag IfType_tag;
+static const xmltag IfNotType_tag;
+static const xmltag SetType_tag;
+static const xmltag UnsetType_tag;
+static const xmltag OutputType_tag;
+static const xmltag LogErrorType_tag;
+
+
+/* The XML tag definition values */
+
+/*+ The complete set of tags at the top level. +*/
+static const xmltag * const xml_toplevel_tags[]={&xmlDeclaration_tag,&RoutinoTaggingType_tag,NULL};
+
+/*+ The xmlDeclaration type tag. +*/
+static const xmltag xmlDeclaration_tag=
+              {"xml",
+               2, {"version","encoding"},
+               NULL,
+               {NULL}};
+
+/*+ The RoutinoTaggingType type tag. +*/
+static const xmltag RoutinoTaggingType_tag=
+              {"routino-tagging",
+               0, {NULL},
+               NULL,
+               {&NodeType_tag,&WayType_tag,&RelationType_tag,NULL}};
+
+/*+ The NodeType type tag. +*/
+static const xmltag NodeType_tag=
+              {"node",
+               0, {NULL},
+               NodeType_function,
+               {&IfType_tag,&IfNotType_tag,NULL}};
+
+/*+ The WayType type tag. +*/
+static const xmltag WayType_tag=
+              {"way",
+               0, {NULL},
+               WayType_function,
+               {&IfType_tag,&IfNotType_tag,NULL}};
+
+/*+ The RelationType type tag. +*/
+static const xmltag RelationType_tag=
+              {"relation",
+               0, {NULL},
+               RelationType_function,
+               {&IfType_tag,&IfNotType_tag,NULL}};
+
+/*+ The IfType type tag. +*/
+static const xmltag IfType_tag=
+              {"if",
+               2, {"k","v"},
+               IfType_function,
+               {&IfType_tag,&IfNotType_tag,&SetType_tag,&UnsetType_tag,&OutputType_tag,&LogErrorType_tag,NULL}};
+
+/*+ The IfNotType type tag. +*/
+static const xmltag IfNotType_tag=
+              {"ifnot",
+               2, {"k","v"},
+               IfNotType_function,
+               {&IfType_tag,&IfNotType_tag,&SetType_tag,&UnsetType_tag,&OutputType_tag,&LogErrorType_tag,NULL}};
+
+/*+ The SetType type tag. +*/
+static const xmltag SetType_tag=
+              {"set",
+               2, {"k","v"},
+               SetType_function,
+               {NULL}};
+
+/*+ The UnsetType type tag. +*/
+static const xmltag UnsetType_tag=
+              {"unset",
+               1, {"k"},
+               UnsetType_function,
+               {NULL}};
+
+/*+ The OutputType type tag. +*/
+static const xmltag OutputType_tag=
+              {"output",
+               2, {"k","v"},
+               OutputType_function,
+               {NULL}};
+
+/*+ The LogErrorType type tag. +*/
+static const xmltag LogErrorType_tag=
+              {"logerror",
+               3, {"k","v","message"},
+               LogErrorType_function,
+               {NULL}};
+
+
+/* The XML tag processing functions */
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the XML declaration is seen
+
+  int xmlDeclaration_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *version The contents of the 'version' attribute (or NULL if not defined).
+
+  const char *encoding The contents of the 'encoding' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+//static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding)
+//{
+// return(0);
+//}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the RoutinoTaggingType XSD type is seen
+
+  int RoutinoTaggingType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+//static int RoutinoTaggingType_function(const char *_tag_,int _type_)
+//{
+// return(0);
+//}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the NodeType XSD type is seen
+
+  int NodeType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int NodeType_function(const char *_tag_,int _type_)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    current_list_stack_depth=0;
+    current_list=&NodeRules;
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the WayType XSD type is seen
+
+  int WayType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int WayType_function(const char *_tag_,int _type_)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    current_list_stack_depth=0;
+    current_list=&WayRules;
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the RelationType XSD type is seen
+
+  int RelationType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int RelationType_function(const char *_tag_,int _type_)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    current_list_stack_depth=0;
+    current_list=&RelationRules;
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the IfType XSD type is seen
+
+  int IfType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *k The contents of the 'k' attribute (or NULL if not defined).
+
+  const char *v The contents of the 'v' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int IfType_function(const char *_tag_,int _type_,const char *k,const char *v)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    if(!current_list_stack || (current_list_stack_depth%8)==7)
+       current_list_stack=(TaggingRuleList**)realloc((void*)current_list_stack,(current_list_stack_depth+8)*sizeof(TaggingRuleList*));
+
+    current_list_stack[current_list_stack_depth++]=current_list;
+
+    current_list=AppendTaggingRule(current_list,k,v,TAGACTION_IF);
+   }
+
+ if(_type_&XMLPARSE_TAG_END)
+    current_list=current_list_stack[--current_list_stack_depth];
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the IfNotType XSD type is seen
+
+  int IfNotType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *k The contents of the 'k' attribute (or NULL if not defined).
+
+  const char *v The contents of the 'v' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int IfNotType_function(const char *_tag_,int _type_,const char *k,const char *v)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    if(!current_list_stack || (current_list_stack_depth%8)==7)
+       current_list_stack=(TaggingRuleList**)realloc((void*)current_list_stack,(current_list_stack_depth+8)*sizeof(TaggingRuleList*));
+
+    current_list_stack[current_list_stack_depth++]=current_list;
+
+    current_list=AppendTaggingRule(current_list,k,v,TAGACTION_IFNOT);
+   }
+
+ if(_type_&XMLPARSE_TAG_END)
+    current_list=current_list_stack[--current_list_stack_depth];
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the SetType XSD type is seen
+
+  int SetType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *k The contents of the 'k' attribute (or NULL if not defined).
+
+  const char *v The contents of the 'v' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int SetType_function(const char *_tag_,int _type_,const char *k,const char *v)
+{
+ if(_type_&XMLPARSE_TAG_START)
+    AppendTaggingAction(current_list,k,v,TAGACTION_SET,NULL);
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the UnsetType XSD type is seen
+
+  int UnsetType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *k The contents of the 'k' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int UnsetType_function(const char *_tag_,int _type_,const char *k)
+{
+ if(_type_&XMLPARSE_TAG_START)
+    AppendTaggingAction(current_list,k,NULL,TAGACTION_UNSET,NULL);
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the OutputType XSD type is seen
+
+  int OutputType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *k The contents of the 'k' attribute (or NULL if not defined).
+
+  const char *v The contents of the 'v' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int OutputType_function(const char *_tag_,int _type_,const char *k,const char *v)
+{
+ if(_type_&XMLPARSE_TAG_START)
+    AppendTaggingAction(current_list,k,v,TAGACTION_OUTPUT,NULL);
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the LogErrorType XSD type is seen
+
+  int LogErrorType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *k The contents of the 'k' attribute (or NULL if not defined).
+
+  const char *v The contents of the 'v' attribute (or NULL if not defined).
+
+  const char *message The contents of the 'message' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int LogErrorType_function(const char *_tag_,int _type_,const char *k,const char *v,const char *message)
+{
+ if(_type_&XMLPARSE_TAG_START)
+    AppendTaggingAction(current_list,k,v,TAGACTION_LOGERROR,message);
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The XML tagging rules parser.
+
+  int ParseXMLTaggingRules Returns 0 if OK or something else in case of an error.
+
+  const char *filename The name of the file to read.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int ParseXMLTaggingRules(const char *filename)
+{
+ int fd;
+ int retval;
+
+ if(!ExistsFile(filename))
+   {
+    fprintf(stderr,"Error: Specified tagging rules file '%s' does not exist.\n",filename);
+    return(1);
+   }
+
+ fd=OpenFile(filename);
+
+ /* Initialise variables used for parsing */
+
+ retval=ParseXML(fd,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_ERRNONAME);
+
+ CloseFile(fd);
+
+ if(current_list_stack)
+    free(current_list_stack);
+
+ if(retval)
+    return(1);
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Delete the tagging rules loaded from the XML file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void DeleteXMLTaggingRules(void)
+{
+ current_list_stack_depth=0;
+ current_list_stack=NULL;
+ current_list=NULL;
+
+ DeleteTaggingRuleList(&NodeRules);
+ DeleteTaggingRuleList(&WayRules);
+ DeleteTaggingRuleList(&RelationRules);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Append a tagging rule to the list of rules.
+
+  TaggingRuleList *AppendTaggingRule Returns the new TaggingRuleList inside the new TaggingRule.
+
+  TaggingRuleList *rules The list of rules to add to.
+
+  const char *k The tag key.
+
+  const char *v The tag value.
+
+  int action Set to the type of action.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+TaggingRuleList *AppendTaggingRule(TaggingRuleList *rules,const char *k,const char *v,int action)
+{
+ if((rules->nrules%16)==0)
+    rules->rules=(TaggingRule*)realloc((void*)rules->rules,(rules->nrules+16)*sizeof(TaggingRule));
+
+ rules->nrules++;
+
+ rules->rules[rules->nrules-1].action=action;
+
+ if(k)
+    rules->rules[rules->nrules-1].k=strcpy(malloc(strlen(k)+1),k);
+ else
+    rules->rules[rules->nrules-1].k=NULL;
+
+ if(v)
+    rules->rules[rules->nrules-1].v=strcpy(malloc(strlen(v)+1),v);
+ else
+    rules->rules[rules->nrules-1].v=NULL;
+
+ rules->rules[rules->nrules-1].message=NULL;
+
+ rules->rules[rules->nrules-1].rulelist=(TaggingRuleList*)calloc(sizeof(TaggingRuleList),1);
+
+ return(rules->rules[rules->nrules-1].rulelist);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Append a tagging action to the list of rules.
+
+  TaggingRuleList *rules The list of rules to add to.
+
+  const char *k The tag key.
+
+  const char *v The tag value.
+
+  int action Set to the type of action.
+
+  const char *message The message to use for the logerror action.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void AppendTaggingAction(TaggingRuleList *rules,const char *k,const char *v,int action,const char *message)
+{
+ if((rules->nrules%16)==0)
+    rules->rules=(TaggingRule*)realloc((void*)rules->rules,(rules->nrules+16)*sizeof(TaggingRule));
+
+ rules->nrules++;
+
+ rules->rules[rules->nrules-1].action=action;
+
+ if(k)
+    rules->rules[rules->nrules-1].k=strcpy(malloc(strlen(k)+1),k);
+ else
+    rules->rules[rules->nrules-1].k=NULL;
+
+ if(v)
+    rules->rules[rules->nrules-1].v=strcpy(malloc(strlen(v)+1),v);
+ else
+    rules->rules[rules->nrules-1].v=NULL;
+
+ if(message)
+    rules->rules[rules->nrules-1].message=strcpy(malloc(strlen(message)+1),message);
+ else
+    rules->rules[rules->nrules-1].message=(char*)default_logerror_message;
+
+ rules->rules[rules->nrules-1].rulelist=NULL;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Delete a tagging rule.
+
+  TaggingRuleList *rules The list of rules to be deleted.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void DeleteTaggingRuleList(TaggingRuleList *rules)
+{
+ int i;
+
+ for(i=0;i<rules->nrules;i++)
+   {
+    if(rules->rules[i].k)
+       free(rules->rules[i].k);
+    if(rules->rules[i].v)
+       free(rules->rules[i].v);
+    if(rules->rules[i].message && rules->rules[i].message!=default_logerror_message)
+       free(rules->rules[i].message);
+
+    if(rules->rules[i].rulelist)
+      {
+       DeleteTaggingRuleList(rules->rules[i].rulelist);
+       free(rules->rules[i].rulelist);
+      }
+   }
+
+ if(rules->rules)
+    free(rules->rules);
+
+ rules->rules=NULL;
+ rules->nrules=0;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create a new TagList structure.
+
+  TagList *NewTagList Returns the new allocated TagList.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+TagList *NewTagList(void)
+{
+ return((TagList*)calloc(sizeof(TagList),1));
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Delete a tag list and the contents.
+
+  TagList *tags The list of tags to delete.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void DeleteTagList(TagList *tags)
+{
+ int i;
+
+ for(i=0;i<tags->ntags;i++)
+   {
+    if(tags->k[i]) free(tags->k[i]);
+    if(tags->v[i]) free(tags->v[i]);
+   }
+
+ if(tags->k) free(tags->k);
+ if(tags->v) free(tags->v);
+
+ free(tags);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Append a tag to the list of tags.
+
+  TagList *tags The list of tags to add to.
+
+  const char *k The tag key.
+
+  const char *v The tag value.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void AppendTag(TagList *tags,const char *k,const char *v)
+{
+ if((tags->ntags%8)==0)
+   {
+    int i;
+
+    tags->k=(char**)realloc((void*)tags->k,(tags->ntags+8)*sizeof(char*));
+    tags->v=(char**)realloc((void*)tags->v,(tags->ntags+8)*sizeof(char*));
+
+    for(i=tags->ntags;i<(tags->ntags+8);i++)
+       tags->k[i]=tags->v[i]=NULL;
+   }
+
+ tags->k[tags->ntags]=strcpy(realloc(tags->k[tags->ntags],strlen(k)+1),k);
+ tags->v[tags->ntags]=strcpy(realloc(tags->v[tags->ntags],strlen(v)+1),v);
+
+ tags->ntags++;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Modify an existing tag or append a new tag to the list of tags.
+
+  TagList *tags The list of tags to modify.
+
+  const char *k The tag key.
+
+  const char *v The tag value.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void ModifyTag(TagList *tags,const char *k,const char *v)
+{
+ int i;
+
+ for(i=0;i<tags->ntags;i++)
+    if(!strcmp(tags->k[i],k))
+      {
+       tags->v[i]=strcpy(realloc(tags->v[i],strlen(v)+1),v);
+       return;
+      }
+
+ AppendTag(tags,k,v);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Delete an existing tag from the list of tags.
+
+  TagList *tags The list of tags to modify.
+
+  const char *k The tag key.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void DeleteTag(TagList *tags,const char *k)
+{
+ int i,j;
+
+ for(i=0;i<tags->ntags;i++)
+    if(!strcmp(tags->k[i],k))
+      {
+       if(tags->k[i]) free(tags->k[i]);
+       if(tags->v[i]) free(tags->v[i]);
+
+       for(j=i+1;j<tags->ntags;j++)
+         {
+          tags->k[j-1]=tags->k[j];
+          tags->v[j-1]=tags->v[j];
+         }
+
+       tags->ntags--;
+
+       tags->k[tags->ntags]=NULL;
+       tags->v[tags->ntags]=NULL;
+
+       return;
+      }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create a string containing all of the tags formatted as if HTML.
+
+  char *StringifyTag Returns a static pointer to the created string.
+
+  TagList *tags The list of tags to convert.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+char *StringifyTag(TagList *tags)
+{
+ static char *string=NULL; /* static allocation of return value */
+ int i,length=0,used=0;
+
+ for(i=0;i<tags->ntags;i++)
+   {
+    length+=strlen(tags->k[i]);
+    length+=strlen(tags->v[i]);
+
+    length+=16;
+   }
+
+ string=realloc((char*)string,length);
+
+ for(i=0;i<tags->ntags;i++)
+    used+=sprintf(string+used,"<tag k='%s' v='%s'>",tags->k[i],tags->v[i]);
+
+ return(string);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Apply a set of tagging rules to a set of node tags.
+
+  TagList *ApplyNodeTaggingRules Returns the list of output tags after modification.
+
+  TagList *tags The tags to be modified.
+
+  int64_t id The ID of the node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+TagList *ApplyNodeTaggingRules(TagList *tags,int64_t id)
+{
+ TagList *result=NewTagList();
+
+ current_id=id;
+ current_list=&NodeRules;
+
+ ApplyRules(current_list,tags,result,NULL,NULL);
+
+ return(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Apply a set of tagging rules to a set of way tags.
+
+  TagList *ApplyWayTaggingRules Returns the list of output tags after modification.
+
+  TagList *tags The tags to be modified.
+
+  int64_t id The ID of the way.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+TagList *ApplyWayTaggingRules(TagList *tags,int64_t id)
+{
+ TagList *result=NewTagList();
+
+ current_id=id;
+ current_list=&WayRules;
+
+ ApplyRules(current_list,tags,result,NULL,NULL);
+
+ return(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Apply a set of tagging rules to a set of relation tags.
+
+  TagList *ApplyRelationTaggingRules Returns the list of output tags after modification.
+
+  TagList *tags The tags to be modified.
+
+  int64_t id The ID of the relation.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+TagList *ApplyRelationTaggingRules(TagList *tags,int64_t id)
+{
+ TagList *result=NewTagList();
+
+ current_id=id;
+ current_list=&RelationRules;
+
+ ApplyRules(current_list,tags,result,NULL,NULL);
+
+ return(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Apply a set of rules to a matching tag.
+
+  TaggingRuleList *rules The rules that are to be matched.
+
+  TagList *input The input tags.
+
+  TagList *output The output tags.
+
+  const char *match_k The key matched at the higher level rule.
+
+  const char *match_v The value matched at the higher level rule.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void ApplyRules(TaggingRuleList *rules,TagList *input,TagList *output,const char *match_k,const char *match_v)
+{
+ int i,j;
+ char *match_k_copy=NULL,*match_v_copy=NULL;
+ 
+ if(match_k)
+    match_k_copy=strcpy(malloc(strlen(match_k)+1),match_k);
+
+ if(match_v)
+    match_v_copy=strcpy(malloc(strlen(match_v)+1),match_v);
+
+ for(i=0;i<rules->nrules;i++)
+   {
+    const char *k,*v;
+
+    k=rules->rules[i].k;
+
+    if(!k && rules->rules[i].action >= TAGACTION_INHERIT)
+       k=match_k_copy;
+
+    v=rules->rules[i].v;
+
+    if(!v && rules->rules[i].action >= TAGACTION_INHERIT)
+       v=match_v_copy;
+
+    switch(rules->rules[i].action)
+      {
+      case TAGACTION_IF:
+       if(k && v)
+         {
+          for(j=0;j<input->ntags;j++)
+             if(!strcmp(input->k[j],k) && !strcmp(input->v[j],v))
+                ApplyRules(rules->rules[i].rulelist,input,output,input->k[j],input->v[j]);
+         }
+       else if(k && !v)
+         {
+          for(j=0;j<input->ntags;j++)
+             if(!strcmp(input->k[j],k))
+                ApplyRules(rules->rules[i].rulelist,input,output,input->k[j],input->v[j]);
+         }
+       else if(!k && v)
+         {
+          for(j=0;j<input->ntags;j++)
+             if(!strcmp(input->v[j],v))
+                ApplyRules(rules->rules[i].rulelist,input,output,input->k[j],input->v[j]);
+         }
+       else /* if(!k && !v) */
+         {
+          if(!input->ntags)
+             ApplyRules(rules->rules[i].rulelist,input,output,"","");
+          else
+             for(j=0;j<input->ntags;j++)
+                ApplyRules(rules->rules[i].rulelist,input,output,input->k[j],input->v[j]);
+         }
+       break;
+
+      case TAGACTION_IFNOT:
+       if(k && v)
+         {
+          for(j=0;j<input->ntags;j++)
+             if(!strcmp(input->k[j],k) && !strcmp(input->v[j],v))
+                break;
+
+          if(j!=input->ntags)
+             break;
+         }
+       else if(k && !v)
+         {
+          for(j=0;j<input->ntags;j++)
+             if(!strcmp(input->k[j],k))
+                break;
+
+          if(j!=input->ntags)
+             break;
+         }
+       else if(!k && v)
+         {
+          for(j=0;j<input->ntags;j++)
+             if(!strcmp(input->v[j],v))
+                break;
+
+          if(j!=input->ntags)
+             break;
+         }
+       else /* if(!k && !v) */
+         {
+          break;
+         }
+
+       ApplyRules(rules->rules[i].rulelist,input,output,k,v);
+       break;
+
+      case TAGACTION_SET:
+       ModifyTag(input,k,v);
+       break;
+
+      case TAGACTION_UNSET:
+       DeleteTag(input,k);
+       break;
+
+      case TAGACTION_OUTPUT:
+       ModifyTag(output,k,v);
+       break;
+
+      case TAGACTION_LOGERROR:
+       if(rules->rules[i].k && !rules->rules[i].v)
+          for(j=0;j<input->ntags;j++)
+             if(!strcmp(input->k[j],rules->rules[i].k))
+               {
+                v=input->v[j];
+                break;
+               }
+
+       if(current_list==&NodeRules)
+          logerror("Node %"Pnode_t" has an unrecognised tag '%s' = '%s' (in tagging rules); %s.\n",logerror_node(current_id),k,v,rules->rules[i].message);
+       if(current_list==&WayRules)
+          logerror("Way %"Pway_t" has an unrecognised tag '%s' = '%s' (in tagging rules); %s.\n",logerror_way(current_id),k,v,rules->rules[i].message);
+       if(current_list==&RelationRules)
+          logerror("Relation %"Prelation_t" has an unrecognised tag '%s' = '%s' (in tagging rules); %s.\n",logerror_relation(current_id),k,v,rules->rules[i].message);
+      }
+   }
+
+ if(match_k_copy) free(match_k_copy);
+ if(match_v_copy) free(match_v_copy);
+}
diff --git a/3rdparty/Routino/src/tagging.h b/3rdparty/Routino/src/tagging.h
new file mode 100644
index 0000000..e745718
--- /dev/null
+++ b/3rdparty/Routino/src/tagging.h
@@ -0,0 +1,85 @@
+/***************************************
+ The data types for the tagging rules.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010-2013 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+#ifndef TAGGING_H
+#define TAGGING_H    /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+
+
+/* Data types */
+
+typedef struct _TaggingRuleList TaggingRuleList;
+
+
+/*+ A structure to contain the tagging rule/action. +*/
+typedef struct _TaggingRule
+{
+ int action;                    /*+ A flag to indicate the type of action. +*/
+
+ char *k;                       /*+ The tag key (or NULL). +*/
+ char *v;                       /*+ The tag value (or NULL). +*/
+ char *message;                 /*+ The message string for logerror (or NULL). +*/
+
+ TaggingRuleList *rulelist;     /*+ The sub-rules belonging to this rule. +*/
+}
+ TaggingRule;
+
+
+/*+ A structure to contain the list of rules and associated information. +*/
+struct _TaggingRuleList
+{
+ TaggingRule *rules;            /*+ The array of rules. +*/
+ int          nrules;           /*+ The number of rules. +*/
+};
+
+
+/*+ A structure to hold a list of tags to be processed. +*/
+typedef struct _TagList
+{
+ int ntags;                     /*+ The number of tags. +*/
+
+ char **k;                      /*+ The list of tag keys. +*/
+ char **v;                      /*+ The list of tag values. +*/
+}
+ TagList;
+
+
+/* Functions in tagging.c */
+
+int ParseXMLTaggingRules(const char *filename);
+void DeleteXMLTaggingRules(void);
+
+TagList *NewTagList(void);
+void DeleteTagList(TagList *tags);
+
+void AppendTag(TagList *tags,const char *k,const char *v);
+void ModifyTag(TagList *tags,const char *k,const char *v);
+void DeleteTag(TagList *tags,const char *k);
+
+char *StringifyTag(TagList *tags);
+
+TagList *ApplyNodeTaggingRules(TagList *tags,int64_t id);
+TagList *ApplyWayTaggingRules(TagList *tags,int64_t id);
+TagList *ApplyRelationTaggingRules(TagList *tags,int64_t id);
+
+
+#endif /* TAGGING_H */
diff --git a/3rdparty/Routino/src/test/Makefile b/3rdparty/Routino/src/test/Makefile
new file mode 100644
index 0000000..c296ca4
--- /dev/null
+++ b/3rdparty/Routino/src/test/Makefile
@@ -0,0 +1,121 @@
+# Test cases Makefile
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2011-2015 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# All configuration is in the top-level Makefile.conf
+
+include ../../Makefile.conf
+
+# executables
+
+ROUTINO_EXE=../planetsplitter ../planetsplitter-slim \
+            ../router ../router-slim \
+            ../filedumper ../filedumper-slim
+
+EXE=is-fast-math
+
+# Compilation targets
+
+O=$(notdir $(wildcard *.osm))
+S=$(foreach f,$(O),$(addsuffix .sh,$(basename $f)))
+
+########
+
+all :
+
+########
+
+test : $(ROUTINO_EXE) $(EXE)
+	@status=true ;\
+	echo ""; \
+	./is-fast-math message; \
+	for script in $(S); do \
+	   echo "" ;\
+	   echo "Testing: $$script (non-slim, no pruning) ... " ;\
+	   if ./$$script fat; then echo "... passed"; else echo "... FAILED"; status=false; fi ;\
+	done ;\
+	for script in $(S); do \
+	   echo "" ;\
+	   echo "Testing: $$script (slim, no pruning) ... " ;\
+	   if ./$$script slim; then echo "... passed"; else echo "... FAILED"; status=false; fi ;\
+	done ;\
+	echo "" ;\
+	if $$status; then echo "Success: all tests passed"; else echo "Warning: Some tests FAILED"; fi ;\
+	$$status || exit 1 ;\
+	echo "" ;\
+	echo "Comparing: slim and non-slim results ... " ;\
+	if diff -q -r slim fat; then echo "... matched"; else echo "... match FAILED"; status=false; fi ;\
+	echo "" ;\
+	if $$status; then echo "Success: slim and non-slim results match"; else echo "Warning: slim and non-slim results are different - FAILED"; fi ;\
+	for script in $(S); do \
+	   echo "" ;\
+	   echo "Testing: $$script (non-slim, pruning) ... " ;\
+	   if ./$$script fat prune; then echo "... passed"; else echo "... FAILED"; status=false; fi ;\
+	done ;\
+	for script in $(S); do \
+	   echo "" ;\
+	   echo "Testing: $$script (slim, pruning) ... " ;\
+	   if ./$$script slim prune; then echo "... passed"; else echo "... FAILED"; status=false; fi ;\
+	done ;\
+	echo "" ;\
+	if $$status; then echo "Success: all tests passed"; else echo "Warning: Some tests FAILED"; fi ;\
+	$$status || exit 1 ;\
+	echo "" ;\
+	echo "Comparing: slim and non-slim results ... " ;\
+	if diff -q -r slim-pruned fat-pruned; then echo "... matched"; else echo "... match FAILED"; status=false; fi ;\
+	echo "" ;\
+	if $$status; then echo "Success: slim and non-slim results match"; else echo "Warning: slim and non-slim results are different - FAILED"; fi ;\
+	$$status
+
+########
+
+$(ROUTINO_EXE) ::
+	cd .. && $(MAKE) $(notdir $@)
+
+is-fast-math : is-fast-math.o
+	$(LD) $< -o $@ $(LDFLAGS)
+
+is-fast-math.o : is-fast-math.c
+	$(CC) -c $(CFLAGS) $< -o $@
+
+########
+
+install:
+
+########
+
+clean:
+	rm -rf fat
+	rm -rf slim
+	rm -rf fat-pruned
+	rm -rf slim-pruned
+	rm -f *.log
+	rm -f *~
+	rm -f *.o
+	rm -f $(EXE) *.exe
+	rm -f core
+	rm -f *.gcda *.gcno *.gcov gmon.out
+
+########
+
+distclean: clean
+
+########
+
+.PHONY:: all test install clean distclean
diff --git a/3rdparty/Routino/src/test/a-b-c-d.sh b/3rdparty/Routino/src/test/a-b-c-d.sh
new file mode 100755
index 0000000..d1cbdf2
--- /dev/null
+++ b/3rdparty/Routino/src/test/a-b-c-d.sh
@@ -0,0 +1,105 @@
+#!/bin/sh
+
+# Exit on error
+
+set -e
+
+# Test name
+
+name=`basename $0 .sh`
+
+# Slim or non-slim
+
+if [ "$1" = "slim" ]; then
+    slim="-slim"
+    dir="slim"
+else
+    slim=""
+    dir="fat"
+fi
+
+# Pruned or non-pruned
+
+if [ "$2" = "prune" ]; then
+    prune=""
+    pruned="-pruned"
+else
+    prune="--prune-none"
+    pruned=""
+fi
+
+# Create the output directory
+
+dir="$dir$pruned"
+
+[ -d $dir ] || mkdir $dir
+
+# Run the programs under a run-time debugger
+
+debugger=valgrind
+debugger=
+
+# Name related options
+
+osm=$name.osm
+log=$name$slim$pruned.log
+
+option_prefix="--prefix=$name"
+option_dir="--dir=$dir"
+
+# Generic program options
+
+option_planetsplitter="--loggable --tagging=../../xml/routino-tagging.xml --errorlog $prune"
+option_filedumper="--dump-osm"
+option_router="--loggable --transport=motorcar --profiles=../../xml/routino-profiles.xml --translations=copyright.xml"
+
+# Run planetsplitter
+
+echo "Running planetsplitter"
+
+echo ../planetsplitter$slim $option_dir $option_prefix $option_planetsplitter $osm > $log
+$debugger ../planetsplitter$slim $option_dir $option_prefix $option_planetsplitter $osm >> $log
+
+# Run filedumper
+
+echo "Running filedumper"
+
+echo ../filedumper$slim $option_dir $option_prefix $option_filedumper >> $log
+$debugger ../filedumper$slim $option_dir $option_prefix $option_filedumper > $dir/$osm
+
+# Waypoints
+
+waypoints=`perl waypoints.pl $osm list`
+
+# Run the router for each waypoint
+
+for waypoint in $waypoints; do
+
+    case $waypoint in
+        *a) waypoint=`echo $waypoint | sed -e 's%a$%%'` ;;
+        *) continue ;;
+    esac
+
+    echo "Running router : $waypoint"
+
+    waypoint_a=`perl waypoints.pl $osm ${waypoint}a 1`
+    waypoint_b=`perl waypoints.pl $osm ${waypoint}b 2`
+    waypoint_c=`perl waypoints.pl $osm ${waypoint}c 3`
+    waypoint_d=`perl waypoints.pl $osm ${waypoint}d 4`
+
+    [ -d $dir/$name-$waypoint ] || mkdir $dir/$name-$waypoint
+
+    echo ../router$slim $option_dir $option_prefix $option_osm $option_router $waypoint_a $waypoint_b $waypoint_c $waypoint_d >> $log
+    $debugger ../router$slim $option_dir $option_prefix $option_osm $option_router $waypoint_a $waypoint_b $waypoint_c $waypoint_d >> $log
+
+    mv shortest* $dir/$name-$waypoint
+
+    echo diff -u expected/$name-$waypoint.txt $dir/$name-$waypoint/shortest-all.txt >> $log
+
+    if ./is-fast-math; then
+        diff -U 0 expected/$name-$waypoint.txt $dir/$name-$waypoint/shortest-all.txt | 2>&1 egrep '^[-+] ' || true
+    else
+        diff -u expected/$name-$waypoint.txt $dir/$name-$waypoint/shortest-all.txt >> $log
+    fi
+
+done
diff --git a/3rdparty/Routino/src/test/a-b-c.sh b/3rdparty/Routino/src/test/a-b-c.sh
new file mode 100755
index 0000000..f13f51b
--- /dev/null
+++ b/3rdparty/Routino/src/test/a-b-c.sh
@@ -0,0 +1,104 @@
+#!/bin/sh
+
+# Exit on error
+
+set -e
+
+# Test name
+
+name=`basename $0 .sh`
+
+# Slim or non-slim
+
+if [ "$1" = "slim" ]; then
+    slim="-slim"
+    dir="slim"
+else
+    slim=""
+    dir="fat"
+fi
+
+# Pruned or non-pruned
+
+if [ "$2" = "prune" ]; then
+    prune=""
+    pruned="-pruned"
+else
+    prune="--prune-none"
+    pruned=""
+fi
+
+# Create the output directory
+
+dir="$dir$pruned"
+
+[ -d $dir ] || mkdir $dir
+
+# Run the programs under a run-time debugger
+
+debugger=valgrind
+debugger=
+
+# Name related options
+
+osm=$name.osm
+log=$name$slim$pruned.log
+
+option_prefix="--prefix=$name"
+option_dir="--dir=$dir"
+
+# Generic program options
+
+option_planetsplitter="--loggable --tagging=../../xml/routino-tagging.xml --errorlog $prune"
+option_filedumper="--dump-osm"
+option_router="--loggable --transport=motorcar --profiles=../../xml/routino-profiles.xml --translations=copyright.xml"
+
+# Run planetsplitter
+
+echo "Running planetsplitter"
+
+echo ../planetsplitter$slim $option_dir $option_prefix $option_planetsplitter $osm > $log
+$debugger ../planetsplitter$slim $option_dir $option_prefix $option_planetsplitter $osm >> $log
+
+# Run filedumper
+
+echo "Running filedumper"
+
+echo ../filedumper$slim $option_dir $option_prefix $option_filedumper >> $log
+$debugger ../filedumper$slim $option_dir $option_prefix $option_filedumper > $dir/$osm
+
+# Waypoints
+
+waypoints=`perl waypoints.pl $osm list`
+
+# Run the router for each waypoint
+
+for waypoint in $waypoints; do
+
+    case $waypoint in
+        *a) waypoint=`echo $waypoint | sed -e 's%a$%%'` ;;
+        *) continue ;;
+    esac
+
+    echo "Running router : $waypoint"
+
+    waypoint_a=`perl waypoints.pl $osm ${waypoint}a 1`
+    waypoint_b=`perl waypoints.pl $osm ${waypoint}b 2`
+    waypoint_c=`perl waypoints.pl $osm ${waypoint}c 3`
+
+    [ -d $dir/$name-$waypoint ] || mkdir $dir/$name-$waypoint
+
+    echo ../router$slim $option_dir $option_prefix $option_osm $option_router $waypoint_a $waypoint_b $waypoint_c >> $log
+    $debugger ../router$slim $option_dir $option_prefix $option_osm $option_router $waypoint_a $waypoint_b $waypoint_c >> $log
+
+    mv shortest* $dir/$name-$waypoint
+
+    echo diff -u expected/$name-$waypoint.txt $dir/$name-$waypoint/shortest-all.txt >> $log
+
+    if ./is-fast-math; then
+        diff -U 0 expected/$name-$waypoint.txt $dir/$name-$waypoint/shortest-all.txt | 2>&1 egrep '^[-+] ' || true
+    else
+        diff -u expected/$name-$waypoint.txt $dir/$name-$waypoint/shortest-all.txt >> $log
+    fi
+
+done
diff --git a/3rdparty/Routino/src/test/a-b.sh b/3rdparty/Routino/src/test/a-b.sh
new file mode 100755
index 0000000..9064d79
--- /dev/null
+++ b/3rdparty/Routino/src/test/a-b.sh
@@ -0,0 +1,103 @@
+#!/bin/sh
+
+# Exit on error
+
+set -e
+
+# Test name
+
+name=`basename $0 .sh`
+
+# Slim or non-slim
+
+if [ "$1" = "slim" ]; then
+    slim="-slim"
+    dir="slim"
+else
+    slim=""
+    dir="fat"
+fi
+
+# Pruned or non-pruned
+
+if [ "$2" = "prune" ]; then
+    prune=""
+    pruned="-pruned"
+else
+    prune="--prune-none"
+    pruned=""
+fi
+
+# Create the output directory
+
+dir="$dir$pruned"
+
+[ -d $dir ] || mkdir $dir
+
+# Run the programs under a run-time debugger
+
+debugger=valgrind
+debugger=
+
+# Name related options
+
+osm=$name.osm
+log=$name$slim$pruned.log
+
+option_prefix="--prefix=$name"
+option_dir="--dir=$dir"
+
+# Generic program options
+
+option_planetsplitter="--loggable --tagging=../../xml/routino-tagging.xml --errorlog $prune"
+option_filedumper="--dump-osm"
+option_router="--loggable --transport=motorcar --profiles=../../xml/routino-profiles.xml --translations=copyright.xml"
+
+# Run planetsplitter
+
+echo "Running planetsplitter"
+
+echo ../planetsplitter$slim $option_dir $option_prefix $option_planetsplitter $osm > $log
+$debugger ../planetsplitter$slim $option_dir $option_prefix $option_planetsplitter $osm >> $log
+
+# Run filedumper
+
+echo "Running filedumper"
+
+echo ../filedumper$slim $option_dir $option_prefix $option_filedumper >> $log
+$debugger ../filedumper$slim $option_dir $option_prefix $option_filedumper > $dir/$osm
+
+# Waypoints
+
+waypoints=`perl waypoints.pl $osm list`
+
+# Run the router for each waypoint
+
+for waypoint in $waypoints; do
+
+    case $waypoint in
+        *a) waypoint=`echo $waypoint | sed -e 's%a$%%'` ;;
+        *) continue ;;
+    esac
+
+    echo "Running router : $waypoint"
+
+    waypoint_a=`perl waypoints.pl $osm ${waypoint}a 1`
+    waypoint_b=`perl waypoints.pl $osm ${waypoint}b 2`
+
+    [ -d $dir/$name-$waypoint ] || mkdir $dir/$name-$waypoint
+
+    echo ../router$slim $option_dir $option_prefix $option_osm $option_router $waypoint_a $waypoint_b >> $log
+    $debugger ../router$slim $option_dir $option_prefix $option_osm $option_router $waypoint_a $waypoint_b >> $log
+
+    mv shortest* $dir/$name-$waypoint
+
+    echo diff -u expected/$name-$waypoint.txt $dir/$name-$waypoint/shortest-all.txt >> $log
+
+    if ./is-fast-math; then
+        diff -U 0 expected/$name-$waypoint.txt $dir/$name-$waypoint/shortest-all.txt | 2>&1 egrep '^[-+] ' || true
+    else
+        diff -u expected/$name-$waypoint.txt $dir/$name-$waypoint/shortest-all.txt >> $log
+    fi
+
+done
diff --git a/3rdparty/Routino/src/test/coincident-waypoint.osm b/3rdparty/Routino/src/test/coincident-waypoint.osm
new file mode 100644
index 0000000..57d1cb8
--- /dev/null
+++ b/3rdparty/Routino/src/test/coincident-waypoint.osm
@@ -0,0 +1,101 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' generator='JOSM'>
+  <node id='4' visible='true' version='1' lat='-0.21661291636529073' lon='-0.520761488739697' />
+  <node id='6' visible='true' version='1' lat='-0.2163742693028532' lon='-0.5205061674081213' />
+  <node id='8' visible='true' version='1' lat='-0.2161202780565698' lon='-0.5207419121625206' />
+  <node id='10' visible='true' version='1' lat='-0.2163536787625498' lon='-0.5209987436557322' />
+  <node id='35' visible='true' version='1' lat='-0.21848333709591153' lon='-0.5218427454267438' />
+  <node id='37' visible='true' version='1' lat='-0.21855669147258072' lon='-0.5198307250334835' />
+  <node id='47' visible='true' version='1' lat='-0.21695597822189805' lon='-0.5206870145975311'>
+    <tag k='name' v='WP02a' />
+  </node>
+  <node id='48' visible='true' version='1' lat='-0.21775028231343874' lon='-0.5206857546917354'>
+    <tag k='name' v='WP01c' />
+  </node>
+  <node id='49' visible='true' version='1' lat='-0.21911476984589462' lon='-0.5207363917442211'>
+    <tag k='name' v='WP02d' />
+  </node>
+  <node id='59' visible='true' version='1' lat='-0.21852291461431964' lon='-0.5208066156936016' />
+  <node id='61' visible='true' version='1' lat='-0.21724703005097415' lon='-0.5218177543802404' />
+  <node id='62' visible='true' version='1' lat='-0.2172864966637643' lon='-0.5207796778404852' />
+  <node id='65' visible='true' version='1' lat='-0.2173314123555489' lon='-0.5198074556089362' />
+  <node id='89' visible='true' version='1' lat='-0.2190801322909824' lon='-0.5207370616265178'>
+    <tag k='name' v='WP01d' />
+  </node>
+  <node id='96' visible='true' version='1' lat='-0.21997515560812292' lon='-0.5208564106644373' />
+  <node id='97' visible='true' version='1' lat='-0.2197365085990034' lon='-0.5206010893328616' />
+  <node id='99' visible='true' version='1' lat='-0.21971591806329774' lon='-0.5210936655804727' />
+  <node id='105' visible='true' version='1' lat='-0.21851780554404734' lon='-0.5208002940891365'>
+    <tag k='name' v='WP02b' />
+  </node>
+  <node id='106' visible='true' version='1' lat='-0.21851780554404734' lon='-0.5208002940891365'>
+    <tag k='name' v='WP02c' />
+  </node>
+  <node id='113' visible='true' version='1' lat='-0.2170269645236478' lon='-0.5206865769695495'>
+    <tag k='name' v='WP03a' />
+  </node>
+  <node id='114' visible='true' version='1' lat='-0.2170269645236478' lon='-0.5206865769695495'>
+    <tag k='name' v='WP03b' />
+  </node>
+  <node id='118' visible='true' version='1' lat='-0.21914996849699317' lon='-0.5207357110104526'>
+    <tag k='name' v='WP03c' />
+  </node>
+  <node id='122' visible='true' version='1' lat='-0.2172821880270113' lon='-0.5207768336434417'>
+    <tag k='name' v='WP04a' />
+  </node>
+  <node id='123' visible='true' version='1' lat='-0.2172821880270113' lon='-0.5207768336434417'>
+    <tag k='name' v='WP04b' />
+  </node>
+  <node id='127' visible='true' version='1' lat='-0.21851780554404734' lon='-0.5208002940891365'>
+    <tag k='name' v='WP04c' />
+  </node>
+  <node id='163' visible='true' version='1' lat='-0.21914996849699317' lon='-0.5207357110104526'>
+    <tag k='name' v='WP03d' />
+  </node>
+  <node id='166' visible='true' version='1' lat='-0.21851780554404734' lon='-0.5208002940891365'>
+    <tag k='name' v='WP04d' />
+  </node>
+  <node id='204' visible='true' version='1' lat='-0.21775028231343874' lon='-0.5206857546917354'>
+    <tag k='name' v='WP01b' />
+  </node>
+  <node id='208' visible='true' version='1' lat='-0.21691021404678168' lon='-0.5206872967320134'>
+    <tag k='name' v='WP01a' />
+  </node>
+  <node id='438' visible='true' version='1' lat='-0.21948251740942368' lon='-0.520836834087261' />
+  <way id='13' visible='true' version='1'>
+    <nd ref='4' />
+    <nd ref='6' />
+    <nd ref='8' />
+    <nd ref='10' />
+    <nd ref='4' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='36' visible='true' version='1'>
+    <nd ref='35' />
+    <nd ref='59' />
+    <nd ref='37' />
+    <tag k='highway' v='footway' />
+  </way>
+  <way id='63' visible='true' version='1'>
+    <nd ref='61' />
+    <nd ref='62' />
+    <nd ref='65' />
+    <tag k='highway' v='footway' />
+  </way>
+  <way id='95' visible='true' version='1'>
+    <nd ref='96' />
+    <nd ref='97' />
+    <nd ref='438' />
+    <nd ref='99' />
+    <nd ref='96' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='240' visible='true' version='1'>
+    <nd ref='438' />
+    <nd ref='59' />
+    <nd ref='62' />
+    <nd ref='4' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 1' />
+  </way>
+</osm>
diff --git a/3rdparty/Routino/src/test/coincident-waypoint.sh b/3rdparty/Routino/src/test/coincident-waypoint.sh
new file mode 120000
index 0000000..7256a60
--- /dev/null
+++ b/3rdparty/Routino/src/test/coincident-waypoint.sh
@@ -0,0 +1 @@
+a-b-c-d.sh
\ No newline at end of file
diff --git a/3rdparty/Routino/src/test/copyright.xml b/3rdparty/Routino/src/test/copyright.xml
new file mode 100644
index 0000000..8cbc553
--- /dev/null
+++ b/3rdparty/Routino/src/test/copyright.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- ============================================================
+     An XML format file containing Routino output translations.
+
+     Part of the Routino routing software.
+     ============================================================
+     This file Copyright 2010-2011 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<routino-translations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                      xsi:noNamespaceSchemaLocation="http://www.routino.org/xml/routino-translations.xsd">
+
+  <language lang="en">
+
+    <!-- Copyright of the data being routed, not of this file  -->
+    <copyright>
+      <creator string="Creator" text="Routino - http://www.routino.org/" />
+      <source  string="Source"  text="Routino test cases - (c) Andrew M. Bishop" />
+      <license string="License" text="GNU Affero General Public License v3 or later" />
+    </copyright>
+
+  </language>
+
+</routino-translations>
diff --git a/3rdparty/Routino/src/test/cycle-both-ways.osm b/3rdparty/Routino/src/test/cycle-both-ways.osm
new file mode 100644
index 0000000..7c1ffed
--- /dev/null
+++ b/3rdparty/Routino/src/test/cycle-both-ways.osm
@@ -0,0 +1,107 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' generator='JOSM'>
+  <node id='3' visible='true' version='1' lat='-0.2217201380129468' lon='-0.5209275966384278' />
+  <node id='4' visible='true' version='1' lat='-0.21828070777942268' lon='-0.5207912709437164' />
+  <node id='6' visible='true' version='1' lat='-0.21804206074333024' lon='-0.5205359496121407' />
+  <node id='8' visible='true' version='1' lat='-0.21778806952505525' lon='-0.52077169436654' />
+  <node id='10' visible='true' version='1' lat='-0.21802147020530807' lon='-0.5210285258597515' />
+  <node id='21' visible='true' version='1' lat='-0.2221908395649969' lon='-0.5209415430673436' />
+  <node id='22' visible='true' version='1' lat='-0.22195451857008858' lon='-0.5207002437384278' />
+  <node id='24' visible='true' version='1' lat='-0.22193543526189635' lon='-0.5211703062894754' />
+  <node id='43' visible='true' version='1' lat='-0.21930218575050586' lon='-0.5189086431233668' />
+  <node id='45' visible='true' version='1' lat='-0.22081066523325596' lon='-0.5189389950470827' />
+  <node id='47' visible='true' version='1' lat='-0.21834718947014287' lon='-0.5188894277663167' />
+  <node id='50' visible='true' version='1' lat='-0.2218359709346708' lon='-0.5189596250943859' />
+  <node id='204' visible='true' version='1' lat='-0.22140697109084054' lon='-0.5208125513491403'>
+    <tag k='name' v='WPstart' />
+  </node>
+  <node id='208' visible='true' version='1' lat='-0.22131959074544644' lon='-0.5188644539458277'>
+    <tag k='name' v='WPfinish' />
+  </node>
+  <node id='242' visible='true' version='1' lat='-0.21969184942143533' lon='-0.520508838695913' />
+  <node id='244' visible='true' version='1' lat='-0.2200812203297903' lon='-0.5205220270076113' />
+  <node id='246' visible='true' version='1' lat='-0.21966460614165306' lon='-0.5211903128432791' />
+  <node id='248' visible='true' version='1' lat='-0.22006229057645915' lon='-0.5212037827409091' />
+  <node id='253' visible='true' version='1' lat='-0.21927153579637806' lon='-0.5195315927529504' />
+  <node id='255' visible='true' version='1' lat='-0.2207678018006232' lon='-0.5197417721359917' />
+  <node id='257' visible='true' version='1' lat='-0.22054261127446687' lon='-0.5220737624335469' />
+  <node id='259' visible='true' version='1' lat='-0.21914142570197062' lon='-0.5220187154522741' />
+  <node id='345' visible='true' version='1' lat='-0.22026866394788633' lon='-0.5208635679861234' />
+  <node id='438' visible='true' version='1' lat='-0.21948172568612254' lon='-0.5208369137424373' />
+  <way id='5' visible='true' version='1'>
+    <nd ref='3' />
+    <nd ref='345' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 2' />
+  </way>
+  <way id='13' visible='true' version='1'>
+    <nd ref='4' />
+    <nd ref='6' />
+    <nd ref='8' />
+    <nd ref='10' />
+    <nd ref='4' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='20' visible='true' version='1'>
+    <nd ref='21' />
+    <nd ref='22' />
+    <nd ref='3' />
+    <nd ref='24' />
+    <nd ref='21' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='48' visible='true' version='1'>
+    <nd ref='47' />
+    <nd ref='43' />
+    <nd ref='45' />
+    <nd ref='50' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 3' />
+  </way>
+  <way id='239' visible='true' version='1'>
+    <nd ref='345' />
+    <nd ref='248' />
+    <nd ref='246' />
+    <nd ref='438' />
+    <nd ref='242' />
+    <nd ref='244' />
+    <nd ref='345' />
+    <tag k='highway' v='primary' />
+    <tag k='junction' v='roundabout' />
+    <tag k='name' v='roundabout' />
+    <tag k='oneway' v='yes' />
+  </way>
+  <way id='240' visible='true' version='1'>
+    <nd ref='438' />
+    <nd ref='4' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 1' />
+  </way>
+  <way id='254' visible='true' version='1'>
+    <nd ref='43' />
+    <nd ref='253' />
+    <nd ref='242' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='256' visible='true' version='1'>
+    <nd ref='45' />
+    <nd ref='255' />
+    <nd ref='244' />
+    <tag k='cycleway' v='opposite' />
+    <tag k='highway' v='residential' />
+    <tag k='oneway' v='yes' />
+  </way>
+  <way id='258' visible='true' version='1'>
+    <nd ref='257' />
+    <nd ref='248' />
+    <tag k='highway' v='residential' />
+    <tag k='oneway' v='yes' />
+  </way>
+  <way id='260' visible='true' version='1'>
+    <nd ref='259' />
+    <nd ref='246' />
+    <tag k='cycleway' v='opposite' />
+    <tag k='highway' v='residential' />
+    <tag k='oneway' v='yes' />
+  </way>
+</osm>
diff --git a/3rdparty/Routino/src/test/cycle-both-ways.sh b/3rdparty/Routino/src/test/cycle-both-ways.sh
new file mode 120000
index 0000000..0614a94
--- /dev/null
+++ b/3rdparty/Routino/src/test/cycle-both-ways.sh
@@ -0,0 +1 @@
+cycle-drive.sh
\ No newline at end of file
diff --git a/3rdparty/Routino/src/test/cycle-drive.sh b/3rdparty/Routino/src/test/cycle-drive.sh
new file mode 100755
index 0000000..4e7a329
--- /dev/null
+++ b/3rdparty/Routino/src/test/cycle-drive.sh
@@ -0,0 +1,105 @@
+#!/bin/sh
+
+# Exit on error
+
+set -e
+
+# Test name
+
+name=`basename $0 .sh`
+
+# Slim or non-slim
+
+if [ "$1" = "slim" ]; then
+    slim="-slim"
+    dir="slim"
+else
+    slim=""
+    dir="fat"
+fi
+
+# Pruned or non-pruned
+
+if [ "$2" = "prune" ]; then
+    prune=""
+    pruned="-pruned"
+else
+    prune="--prune-none"
+    pruned=""
+fi
+
+# Create the output directory
+
+dir="$dir$pruned"
+
+[ -d $dir ] || mkdir $dir
+
+# Run the programs under a run-time debugger
+
+debugger=valgrind
+debugger=
+
+# Name related options
+
+osm=$name.osm
+log=$name$slim$pruned.log
+
+option_prefix="--prefix=$name"
+option_dir="--dir=$dir"
+
+# Generic program options
+
+option_planetsplitter="--loggable --tagging=../../xml/routino-tagging.xml --errorlog $prune"
+option_filedumper="--dump-osm"
+option_router="--loggable --profiles=../../xml/routino-profiles.xml --translations=copyright.xml"
+
+# Run planetsplitter
+
+echo "Running planetsplitter"
+
+echo ../planetsplitter$slim $option_dir $option_prefix $option_planetsplitter $osm > $log
+$debugger ../planetsplitter$slim $option_dir $option_prefix $option_planetsplitter $osm >> $log
+
+# Run filedumper
+
+echo "Running filedumper"
+
+echo ../filedumper$slim $option_dir $option_prefix $option_filedumper >> $log
+$debugger ../filedumper$slim $option_dir $option_prefix $option_filedumper > $dir/$osm
+
+# Waypoints
+
+waypoints=`perl waypoints.pl $osm list`
+
+waypoint_start=`perl waypoints.pl $osm WPstart 1`
+waypoint_finish=`perl waypoints.pl $osm WPfinish 2`
+
+# Run the router for each transport type
+
+transports="motorcar bicycle"
+
+for transport in $transports; do
+
+    case $transport in
+        motorcar) waypoint=WP01 ;;
+        *)        waypoint=WP02 ;;
+    esac
+
+    echo "Running router : $waypoint"
+
+    [ -d $dir/$name-$waypoint ] || mkdir $dir/$name-$waypoint
+
+    echo ../router$slim $option_dir $option_prefix $option_osm $option_router --transport=$transport $waypoint_start $waypoint_finish >> $log
+    $debugger ../router$slim $option_dir $option_prefix $option_osm $option_router --transport=$transport $waypoint_start $waypoint_finish >> $log
+
+    mv shortest* $dir/$name-$waypoint
+
+    echo diff -u expected/$name-$waypoint.txt $dir/$name-$waypoint/shortest-all.txt >> $log
+
+    if ./is-fast-math; then
+        diff -U 0 expected/$name-$waypoint.txt $dir/$name-$waypoint/shortest-all.txt | 2>&1 egrep '^[-+] ' || true
+    else
+        diff -u expected/$name-$waypoint.txt $dir/$name-$waypoint/shortest-all.txt >> $log
+    fi
+
+done
diff --git a/3rdparty/Routino/src/test/dead-ends.osm b/3rdparty/Routino/src/test/dead-ends.osm
new file mode 100644
index 0000000..70a4a22
--- /dev/null
+++ b/3rdparty/Routino/src/test/dead-ends.osm
@@ -0,0 +1,176 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' generator='JOSM'>
+  <node id='257' visible='true' version='1' lat='-0.21809858996693385' lon='-0.5191028643883174' />
+  <node id='259' visible='true' version='1' lat='-0.22070178828290346' lon='-0.5194778136559395' />
+  <node id='261' visible='true' version='1' lat='-0.22026348707492585' lon='-0.5193082654147766'>
+    <tag k='name' v='WP01' />
+  </node>
+  <node id='263' visible='true' version='1' lat='-0.2199233360272462' lon='-0.5191790778221413'>
+    <tag k='name' v='WP02' />
+  </node>
+  <node id='267' visible='true' version='1' lat='-0.21923442817890232' lon='-0.519554450499408' />
+  <node id='269' visible='true' version='1' lat='-0.21955455458130574' lon='-0.5193510859959124'>
+    <tag k='name' v='WP03' />
+  </node>
+  <node id='271' visible='true' version='1' lat='-0.21838648826301083' lon='-0.5191374278276153'>
+    <tag k='name' v='WP04' />
+  </node>
+  <node id='273' visible='true' version='1' lat='-0.21967045850547667' lon='-0.5160319121186099'>
+    <tag k='name' v='WP10' />
+  </node>
+  <node id='275' visible='true' version='1' lat='-0.22001919809793816' lon='-0.5158468652583799'>
+    <tag k='name' v='WP09' />
+  </node>
+  <node id='277' visible='true' version='1' lat='-0.2203608205479482' lon='-0.5159607402492906'>
+    <tag k='name' v='WP08' />
+  </node>
+  <node id='279' visible='true' version='1' lat='-0.21999072956008625' lon='-0.5175122870004505'>
+    <tag k='name' v='WP06' />
+  </node>
+  <node id='281' visible='true' version='1' lat='-0.21962194811581368' lon='-0.5176842951742215'>
+    <tag k='name' v='WP07' />
+  </node>
+  <node id='283' visible='true' version='1' lat='-0.21954697775967735' lon='-0.5139082939501117'>
+    <tag k='name' v='WPfinish' />
+  </node>
+  <node id='285' visible='true' version='1' lat='-0.21952490240955844' lon='-0.5211328425348463'>
+    <tag k='name' v='WPstart' />
+  </node>
+  <node id='311' visible='true' version='1' lat='-0.21873259914979318' lon='-0.5139721830599432' />
+  <node id='315' visible='true' version='1' lat='-0.21894473644285053' lon='-0.5177120426858725' />
+  <node id='317' visible='true' version='1' lat='-0.21881956658439772' lon='-0.5209796816567882' />
+  <node id='319' visible='true' version='1' lat='-0.22034447159225826' lon='-0.5140417639627524' />
+  <node id='323' visible='true' version='1' lat='-0.22029573308467093' lon='-0.5176333429804723'>
+    <tag k='name' v='WP05' />
+  </node>
+  <node id='325' visible='true' version='1' lat='-0.22022296242215664' lon='-0.5210519045762619' />
+  <node id='329' visible='true' version='1' lat='-0.218492980018636' lon='-0.5157886455630277'>
+    <tag k='name' v='WP11' />
+  </node>
+  <node id='331' visible='true' version='1' lat='-0.21934091992851262' lon='-0.5162056682348201' />
+  <node id='333' visible='true' version='1' lat='-0.2207820589348417' lon='-0.5161366988387935' />
+  <node id='335' visible='true' version='1' lat='-0.21845388180276712' lon='-0.5174706370059244' />
+  <node id='337' visible='true' version='1' lat='-0.21930182171484336' lon='-0.5178876596777171' />
+  <node id='339' visible='true' version='1' lat='-0.22073883963391433' lon='-0.5178047502907365' />
+  <node id='341' visible='true' version='1' lat='-0.22081738237868836' lon='-0.5140621784576588' />
+  <node id='343' visible='true' version='1' lat='-0.2206667536990629' lon='-0.5210598093726763' />
+  <node id='345' visible='true' version='1' lat='-0.22192916244766508' lon='-0.514332326947849' />
+  <node id='347' visible='true' version='1' lat='-0.2219482141512544' lon='-0.5138620338011963' />
+  <node id='349' visible='true' version='1' lat='-0.22217484074642313' lon='-0.5141041642151607' />
+  <node id='351' visible='true' version='1' lat='-0.22170436926410486' lon='-0.5140901916750656' />
+  <node id='353' visible='true' version='1' lat='-0.21801516712553526' lon='-0.5141909410905267' />
+  <node id='355' visible='true' version='1' lat='-0.2177803096434024' lon='-0.5139345260591944' />
+  <node id='357' visible='true' version='1' lat='-0.2180357522245965' lon='-0.5136983548940309' />
+  <node id='359' visible='true' version='1' lat='-0.21827293796270247' lon='-0.5139541080318566' />
+  <node id='361' visible='true' version='1' lat='-0.22193543526189635' lon='-0.5213371153581924' />
+  <node id='363' visible='true' version='1' lat='-0.22195451857008858' lon='-0.5208670528071448' />
+  <node id='365' visible='true' version='1' lat='-0.2221908395649969' lon='-0.5211083521360607' />
+  <node id='367' visible='true' version='1' lat='-0.21802147020530807' lon='-0.5211953349284685' />
+  <node id='369' visible='true' version='1' lat='-0.21778806952505525' lon='-0.520938503435257' />
+  <node id='371' visible='true' version='1' lat='-0.21804206074333024' lon='-0.5207027586808577' />
+  <node id='373' visible='true' version='1' lat='-0.21828070777942268' lon='-0.5209580800124335' />
+  <node id='375' visible='true' version='1' lat='-0.2217201380129468' lon='-0.5210944057071448' />
+  <way id='377' visible='true' version='1'>
+    <nd ref='259' />
+    <nd ref='261' />
+    <nd ref='263' />
+    <nd ref='267' />
+    <nd ref='271' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='dead-end 1' />
+  </way>
+  <way id='383' visible='true' version='1'>
+    <nd ref='317' />
+    <nd ref='257' />
+    <nd ref='315' />
+    <nd ref='329' />
+    <nd ref='311' />
+    <tag k='highway' v='footway' />
+  </way>
+  <way id='385' visible='true' version='1'>
+    <nd ref='325' />
+    <nd ref='261' />
+    <nd ref='323' />
+    <nd ref='277' />
+    <nd ref='319' />
+    <tag k='highway' v='footway' />
+  </way>
+  <way id='387' visible='true' version='1'>
+    <nd ref='333' />
+    <nd ref='277' />
+    <nd ref='275' />
+    <nd ref='331' />
+    <nd ref='329' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='dead-end 3' />
+  </way>
+  <way id='389' visible='true' version='1'>
+    <nd ref='339' />
+    <nd ref='323' />
+    <nd ref='279' />
+    <nd ref='337' />
+    <nd ref='315' />
+    <nd ref='335' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='dead-end 2' />
+  </way>
+  <way id='391' visible='true' version='1'>
+    <nd ref='343' />
+    <nd ref='259' />
+    <nd ref='339' />
+    <nd ref='333' />
+    <nd ref='341' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='high street' />
+  </way>
+  <way id='393' visible='true' version='1'>
+    <nd ref='349' />
+    <nd ref='347' />
+    <nd ref='351' />
+    <nd ref='345' />
+    <nd ref='349' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='395' visible='true' version='1'>
+    <nd ref='351' />
+    <nd ref='341' />
+    <nd ref='319' />
+    <nd ref='311' />
+    <nd ref='359' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 2' />
+  </way>
+  <way id='397' visible='true' version='1'>
+    <nd ref='359' />
+    <nd ref='357' />
+    <nd ref='355' />
+    <nd ref='353' />
+    <nd ref='359' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='399' visible='true' version='1'>
+    <nd ref='365' />
+    <nd ref='363' />
+    <nd ref='375' />
+    <nd ref='361' />
+    <nd ref='365' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='401' visible='true' version='1'>
+    <nd ref='373' />
+    <nd ref='371' />
+    <nd ref='369' />
+    <nd ref='367' />
+    <nd ref='373' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='403' visible='true' version='1'>
+    <nd ref='375' />
+    <nd ref='343' />
+    <nd ref='325' />
+    <nd ref='317' />
+    <nd ref='373' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 1' />
+  </way>
+</osm>
diff --git a/3rdparty/Routino/src/test/dead-ends.sh b/3rdparty/Routino/src/test/dead-ends.sh
new file mode 120000
index 0000000..b627b17
--- /dev/null
+++ b/3rdparty/Routino/src/test/dead-ends.sh
@@ -0,0 +1 @@
+start-1-finish.sh
\ No newline at end of file
diff --git a/3rdparty/Routino/src/test/expected/coincident-waypoint-WP01.txt b/3rdparty/Routino/src/test/expected/coincident-waypoint-WP01.txt
new file mode 100644
index 0000000..e2daa78
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/coincident-waypoint-WP01.txt
@@ -0,0 +1,12 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.216904	  -0.520770	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.217286	  -0.520780	       7 	Junct-	0.042	 0.03	 0.04	  0.0	 96	 181	main 1
+ -0.217741	  -0.520789	      -2 	Waypt	0.050	 0.03	 0.09	  0.1	 96	 181	main 1
+ -0.217741	  -0.520789	      -3 	Waypt	0.000	 0.00	 0.09	  0.1	 96	 270	main 1
+ -0.218523	  -0.520806	       6 	Junct-	0.086	 0.05	 0.18	  0.1	 96	 181	main 1
+ -0.219080	  -0.520824	      -4 	Waypt	0.061	 0.04	 0.24	  0.1	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/coincident-waypoint-WP02.txt b/3rdparty/Routino/src/test/expected/coincident-waypoint-WP02.txt
new file mode 100644
index 0000000..8123d44
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/coincident-waypoint-WP02.txt
@@ -0,0 +1,11 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.216959	  -0.520771	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.217286	  -0.520780	       7 	Junct-	0.036	 0.02	 0.04	  0.0	 96	 181	main 1
+ -0.218523	  -0.520806	       6 	Waypt	0.137	 0.09	 0.17	  0.1	 96	 181	main 1
+ -0.218523	  -0.520806	       6 	Waypt	0.000	 0.00	 0.17	  0.1	 96	 270	main 1
+ -0.219117	  -0.520825	      -4 	Waypt	0.065	 0.04	 0.24	  0.1	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/coincident-waypoint-WP03.txt b/3rdparty/Routino/src/test/expected/coincident-waypoint-WP03.txt
new file mode 100644
index 0000000..32b1fa8
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/coincident-waypoint-WP03.txt
@@ -0,0 +1,12 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.217022	  -0.520773	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.217022	  -0.520773	      -2 	Waypt	0.000	 0.00	 0.00	  0.0	 96	 270	main 1
+ -0.217286	  -0.520780	       7 	Junct-	0.029	 0.02	 0.03	  0.0	 96	 181	main 1
+ -0.218523	  -0.520806	       6 	Junct-	0.137	 0.09	 0.17	  0.1	 96	 181	main 1
+ -0.219153	  -0.520826	      -3 	Waypt	0.069	 0.04	 0.23	  0.1	 96	 181	main 1
+ -0.219153	  -0.520826	      -4 	Waypt	0.000	 0.00	 0.23	  0.1	 96	 270	main 1
diff --git a/3rdparty/Routino/src/test/expected/coincident-waypoint-WP04.txt b/3rdparty/Routino/src/test/expected/coincident-waypoint-WP04.txt
new file mode 100644
index 0000000..c79a7e2
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/coincident-waypoint-WP04.txt
@@ -0,0 +1,10 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.217286	  -0.520780	       7 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.217286	  -0.520780	       7 	Waypt	0.000	 0.00	 0.00	  0.0	 96	 270	main 1
+ -0.218523	  -0.520806	       6 	Waypt	0.137	 0.09	 0.14	  0.1	 96	 181	main 1
+ -0.218523	  -0.520806	       6 	Waypt	0.000	 0.00	 0.14	  0.1	 96	 270	main 1
diff --git a/3rdparty/Routino/src/test/expected/cycle-both-ways-WP01.txt b/3rdparty/Routino/src/test/expected/cycle-both-ways-WP01.txt
new file mode 100644
index 0000000..60c2867
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/cycle-both-ways-WP01.txt
@@ -0,0 +1,16 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.221402	  -0.520913	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220268	  -0.520863	       8*	Junct	0.125	 0.08	 0.12	  0.1	 96	   2	main 2
+ -0.220062	  -0.521204	       2 	Inter	0.044	 0.03	 0.17	  0.1	 96	 301	roundabout
+ -0.219665	  -0.521190	       3 	Inter	0.044	 0.03	 0.21	  0.1	 96	   1	roundabout
+ -0.219482	  -0.520837	       9*	Junct-	0.044	 0.03	 0.26	  0.2	 96	  62	roundabout
+ -0.219692	  -0.520509	      15*	Junct	0.043	 0.03	 0.30	  0.2	 96	 122	roundabout
+ -0.219271	  -0.519532	      17 	Inter	0.118	 0.15	 0.42	  0.3	 48	  66	residential road
+ -0.219302	  -0.518908	      20*	Junct	0.069	 0.09	 0.49	  0.4	 48	  92	residential road
+ -0.220811	  -0.518939	      19*	Junct-	0.167	 0.10	 0.65	  0.5	 96	 181	main 3
+ -0.221319	  -0.518949	      -2 	Waypt	0.056	 0.04	 0.71	  0.6	 96	 181	main 3
diff --git a/3rdparty/Routino/src/test/expected/cycle-both-ways-WP02.txt b/3rdparty/Routino/src/test/expected/cycle-both-ways-WP02.txt
new file mode 100644
index 0000000..22a5bc8
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/cycle-both-ways-WP02.txt
@@ -0,0 +1,16 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.221402	  -0.520913	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220268	  -0.520863	       8*	Junct	0.125	 0.38	 0.12	  0.4	 20	   2	main 2
+ -0.220062	  -0.521204	       2 	Inter	0.044	 0.13	 0.17	  0.5	 20	 301	roundabout
+ -0.219665	  -0.521190	       3 	Junct-	0.044	 0.13	 0.21	  0.6	 20	   1	roundabout
+ -0.219482	  -0.520837	       9*	Junct-	0.044	 0.13	 0.26	  0.8	 20	  62	roundabout
+ -0.219692	  -0.520509	      15*	Junct-	0.043	 0.13	 0.30	  0.9	 20	 122	roundabout
+ -0.220082	  -0.520522	      14*	Junct	0.043	 0.13	 0.34	  1.0	 20	 181	roundabout
+ -0.220768	  -0.519742	      16 	Inter	0.115	 0.34	 0.46	  1.4	 20	 131	residential road
+ -0.220811	  -0.518939	      19*	Junct	0.089	 0.27	 0.55	  1.6	 20	  93	residential road
+ -0.221319	  -0.518949	      -2 	Waypt	0.056	 0.17	 0.60	  1.8	 20	 181	main 3
diff --git a/3rdparty/Routino/src/test/expected/dead-ends-WP01.txt b/3rdparty/Routino/src/test/expected/dead-ends-WP01.txt
new file mode 100644
index 0000000..72c402f
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/dead-ends-WP01.txt
@@ -0,0 +1,17 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219535	  -0.521016	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.521052	       5*	Junct-	0.076	 0.05	 0.08	  0.0	 96	 182	main 1
+ -0.220666	  -0.521060	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 180	main 1
+ -0.220702	  -0.519478	      12*	Junct	0.176	 0.22	 0.30	  0.3	 48	  91	high street
+ -0.220263	  -0.519309	      13*	Waypt	0.052	 0.07	 0.35	  0.4	 48	  21	dead-end 1
+ -0.220702	  -0.519478	      12*	Junct	0.052	 0.07	 0.41	  0.4	 48	 201	dead-end 1
+ -0.220739	  -0.517804	      18*	Junct	0.186	 0.23	 0.59	  0.7	 48	  91	high street
+ -0.220782	  -0.516137	      24*	Junct	0.185	 0.23	 0.78	  0.9	 48	  91	high street
+ -0.220817	  -0.514062	      32*	Junct	0.230	 0.29	 1.01	  1.2	 48	  90	high street
+ -0.220344	  -0.514042	      33*	Junct-	0.052	 0.03	 1.06	  1.2	 96	   2	main 2
+ -0.219539	  -0.514007	      -3 	Waypt	0.089	 0.06	 1.15	  1.3	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/dead-ends-WP02.txt b/3rdparty/Routino/src/test/expected/dead-ends-WP02.txt
new file mode 100644
index 0000000..0becf02
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/dead-ends-WP02.txt
@@ -0,0 +1,19 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219535	  -0.521016	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.521052	       5*	Junct-	0.076	 0.05	 0.08	  0.0	 96	 182	main 1
+ -0.220666	  -0.521060	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 180	main 1
+ -0.220702	  -0.519478	      12*	Junct	0.176	 0.22	 0.30	  0.3	 48	  91	high street
+ -0.220263	  -0.519309	      13*	Junct-	0.052	 0.07	 0.35	  0.4	 48	  21	dead-end 1
+ -0.219924	  -0.519179	      14 	Waypt	0.040	 0.05	 0.39	  0.4	 48	  20	dead-end 1
+ -0.220263	  -0.519309	      13*	Junct-	0.040	 0.05	 0.43	  0.5	 48	 200	dead-end 1
+ -0.220702	  -0.519478	      12*	Junct	0.052	 0.07	 0.48	  0.5	 48	 201	dead-end 1
+ -0.220739	  -0.517804	      18*	Junct	0.186	 0.23	 0.67	  0.8	 48	  91	high street
+ -0.220782	  -0.516137	      24*	Junct	0.185	 0.23	 0.86	  1.0	 48	  91	high street
+ -0.220817	  -0.514062	      32*	Junct	0.230	 0.29	 1.09	  1.3	 48	  90	high street
+ -0.220344	  -0.514042	      33*	Junct-	0.052	 0.03	 1.14	  1.3	 96	   2	main 2
+ -0.219539	  -0.514007	      -3 	Waypt	0.089	 0.06	 1.23	  1.4	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/dead-ends-WP03.txt b/3rdparty/Routino/src/test/expected/dead-ends-WP03.txt
new file mode 100644
index 0000000..52cdacc
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/dead-ends-WP03.txt
@@ -0,0 +1,21 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219535	  -0.521016	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.521052	       5*	Junct-	0.076	 0.05	 0.08	  0.0	 96	 182	main 1
+ -0.220666	  -0.521060	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 180	main 1
+ -0.220702	  -0.519478	      12*	Junct	0.176	 0.22	 0.30	  0.3	 48	  91	high street
+ -0.220263	  -0.519309	      13*	Junct-	0.052	 0.07	 0.35	  0.4	 48	  21	dead-end 1
+ -0.219924	  -0.519179	      14 	Inter	0.040	 0.05	 0.39	  0.4	 48	  20	dead-end 1
+ -0.219567	  -0.519373	      -2 	Waypt	0.045	 0.06	 0.44	  0.5	 48	 331	dead-end 1
+ -0.219924	  -0.519179	      14 	Inter	0.045	 0.06	 0.48	  0.5	 48	 151	dead-end 1
+ -0.220263	  -0.519309	      13*	Junct-	0.040	 0.05	 0.52	  0.6	 48	 200	dead-end 1
+ -0.220702	  -0.519478	      12*	Junct	0.052	 0.07	 0.57	  0.6	 48	 201	dead-end 1
+ -0.220739	  -0.517804	      18*	Junct	0.186	 0.23	 0.76	  0.9	 48	  91	high street
+ -0.220782	  -0.516137	      24*	Junct	0.185	 0.23	 0.95	  1.1	 48	  91	high street
+ -0.220817	  -0.514062	      32*	Junct	0.230	 0.29	 1.18	  1.4	 48	  90	high street
+ -0.220344	  -0.514042	      33*	Junct-	0.052	 0.03	 1.23	  1.4	 96	   2	main 2
+ -0.219539	  -0.514007	      -3 	Waypt	0.089	 0.06	 1.32	  1.5	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/dead-ends-WP04.txt b/3rdparty/Routino/src/test/expected/dead-ends-WP04.txt
new file mode 100644
index 0000000..941340a
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/dead-ends-WP04.txt
@@ -0,0 +1,23 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219535	  -0.521016	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.521052	       5*	Junct-	0.076	 0.05	 0.08	  0.0	 96	 182	main 1
+ -0.220666	  -0.521060	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 180	main 1
+ -0.220702	  -0.519478	      12*	Junct	0.176	 0.22	 0.30	  0.3	 48	  91	high street
+ -0.220263	  -0.519309	      13*	Junct-	0.052	 0.07	 0.35	  0.4	 48	  21	dead-end 1
+ -0.219924	  -0.519179	      14 	Inter	0.040	 0.05	 0.39	  0.4	 48	  20	dead-end 1
+ -0.219235	  -0.519555	      11 	Inter	0.087	 0.11	 0.48	  0.5	 48	 331	dead-end 1
+ -0.218387	  -0.519137	      15 	Waypt	0.105	 0.13	 0.58	  0.7	 48	  26	dead-end 1
+ -0.219235	  -0.519555	      11 	Inter	0.105	 0.13	 0.69	  0.8	 48	 206	dead-end 1
+ -0.219924	  -0.519179	      14 	Inter	0.087	 0.11	 0.78	  0.9	 48	 151	dead-end 1
+ -0.220263	  -0.519309	      13*	Junct-	0.040	 0.05	 0.82	  0.9	 48	 200	dead-end 1
+ -0.220702	  -0.519478	      12*	Junct	0.052	 0.07	 0.87	  1.0	 48	 201	dead-end 1
+ -0.220739	  -0.517804	      18*	Junct	0.186	 0.23	 1.05	  1.2	 48	  91	high street
+ -0.220782	  -0.516137	      24*	Junct	0.185	 0.23	 1.24	  1.5	 48	  91	high street
+ -0.220817	  -0.514062	      32*	Junct	0.230	 0.29	 1.47	  1.8	 48	  90	high street
+ -0.220344	  -0.514042	      33*	Junct-	0.052	 0.03	 1.52	  1.8	 96	   2	main 2
+ -0.219539	  -0.514007	      -3 	Waypt	0.089	 0.06	 1.61	  1.8	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/dead-ends-WP05.txt b/3rdparty/Routino/src/test/expected/dead-ends-WP05.txt
new file mode 100644
index 0000000..c243705
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/dead-ends-WP05.txt
@@ -0,0 +1,17 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219535	  -0.521016	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.521052	       5*	Junct-	0.076	 0.05	 0.08	  0.0	 96	 182	main 1
+ -0.220666	  -0.521060	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 180	main 1
+ -0.220702	  -0.519478	      12*	Junct	0.176	 0.22	 0.30	  0.3	 48	  91	high street
+ -0.220739	  -0.517804	      18*	Junct	0.186	 0.23	 0.49	  0.5	 48	  91	high street
+ -0.220296	  -0.517634	      20*	Waypt	0.052	 0.07	 0.54	  0.6	 48	  21	dead-end 2
+ -0.220739	  -0.517804	      18*	Junct	0.052	 0.07	 0.59	  0.7	 48	 201	dead-end 2
+ -0.220782	  -0.516137	      24*	Junct	0.185	 0.23	 0.78	  0.9	 48	  91	high street
+ -0.220817	  -0.514062	      32*	Junct	0.230	 0.29	 1.01	  1.2	 48	  90	high street
+ -0.220344	  -0.514042	      33*	Junct-	0.052	 0.03	 1.06	  1.2	 96	   2	main 2
+ -0.219539	  -0.514007	      -3 	Waypt	0.089	 0.06	 1.15	  1.3	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/dead-ends-WP06.txt b/3rdparty/Routino/src/test/expected/dead-ends-WP06.txt
new file mode 100644
index 0000000..086b2fe
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/dead-ends-WP06.txt
@@ -0,0 +1,19 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219535	  -0.521016	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.521052	       5*	Junct-	0.076	 0.05	 0.08	  0.0	 96	 182	main 1
+ -0.220666	  -0.521060	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 180	main 1
+ -0.220702	  -0.519478	      12*	Junct	0.176	 0.22	 0.30	  0.3	 48	  91	high street
+ -0.220739	  -0.517804	      18*	Junct	0.186	 0.23	 0.49	  0.5	 48	  91	high street
+ -0.220296	  -0.517634	      20*	Junct-	0.052	 0.07	 0.54	  0.6	 48	  21	dead-end 2
+ -0.219991	  -0.517512	      21 	Waypt	0.036	 0.04	 0.57	  0.6	 48	  21	dead-end 2
+ -0.220296	  -0.517634	      20*	Junct-	0.036	 0.04	 0.61	  0.7	 48	 201	dead-end 2
+ -0.220739	  -0.517804	      18*	Junct	0.052	 0.07	 0.66	  0.7	 48	 201	dead-end 2
+ -0.220782	  -0.516137	      24*	Junct	0.185	 0.23	 0.85	  1.0	 48	  91	high street
+ -0.220817	  -0.514062	      32*	Junct	0.230	 0.29	 1.08	  1.3	 48	  90	high street
+ -0.220344	  -0.514042	      33*	Junct-	0.052	 0.03	 1.13	  1.3	 96	   2	main 2
+ -0.219539	  -0.514007	      -3 	Waypt	0.089	 0.06	 1.22	  1.4	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/dead-ends-WP07.txt b/3rdparty/Routino/src/test/expected/dead-ends-WP07.txt
new file mode 100644
index 0000000..946c8a9
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/dead-ends-WP07.txt
@@ -0,0 +1,21 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219535	  -0.521016	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.521052	       5*	Junct-	0.076	 0.05	 0.08	  0.0	 96	 182	main 1
+ -0.220666	  -0.521060	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 180	main 1
+ -0.220702	  -0.519478	      12*	Junct	0.176	 0.22	 0.30	  0.3	 48	  91	high street
+ -0.220739	  -0.517804	      18*	Junct	0.186	 0.23	 0.49	  0.5	 48	  91	high street
+ -0.220296	  -0.517634	      20*	Junct-	0.052	 0.07	 0.54	  0.6	 48	  21	dead-end 2
+ -0.219991	  -0.517512	      21 	Inter	0.036	 0.04	 0.57	  0.6	 48	  21	dead-end 2
+ -0.219635	  -0.517707	      -2 	Waypt	0.045	 0.06	 0.62	  0.7	 48	 331	dead-end 2
+ -0.219991	  -0.517512	      21 	Inter	0.045	 0.06	 0.67	  0.7	 48	 151	dead-end 2
+ -0.220296	  -0.517634	      20*	Junct-	0.036	 0.04	 0.70	  0.8	 48	 201	dead-end 2
+ -0.220739	  -0.517804	      18*	Junct	0.052	 0.07	 0.75	  0.9	 48	 201	dead-end 2
+ -0.220782	  -0.516137	      24*	Junct	0.185	 0.23	 0.94	  1.1	 48	  91	high street
+ -0.220817	  -0.514062	      32*	Junct	0.230	 0.29	 1.17	  1.4	 48	  90	high street
+ -0.220344	  -0.514042	      33*	Junct-	0.052	 0.03	 1.22	  1.4	 96	   2	main 2
+ -0.219539	  -0.514007	      -3 	Waypt	0.089	 0.06	 1.31	  1.5	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/dead-ends-WP08.txt b/3rdparty/Routino/src/test/expected/dead-ends-WP08.txt
new file mode 100644
index 0000000..eedd51d
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/dead-ends-WP08.txt
@@ -0,0 +1,17 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219535	  -0.521016	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.521052	       5*	Junct-	0.076	 0.05	 0.08	  0.0	 96	 182	main 1
+ -0.220666	  -0.521060	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 180	main 1
+ -0.220702	  -0.519478	      12*	Junct	0.176	 0.22	 0.30	  0.3	 48	  91	high street
+ -0.220739	  -0.517804	      18*	Junct	0.186	 0.23	 0.49	  0.5	 48	  91	high street
+ -0.220782	  -0.516137	      24*	Junct	0.185	 0.23	 0.67	  0.8	 48	  91	high street
+ -0.220361	  -0.515961	      25*	Waypt	0.050	 0.06	 0.72	  0.8	 48	  22	dead-end 3
+ -0.220782	  -0.516137	      24*	Junct	0.050	 0.06	 0.77	  0.9	 48	 202	dead-end 3
+ -0.220817	  -0.514062	      32*	Junct	0.230	 0.29	 1.00	  1.2	 48	  90	high street
+ -0.220344	  -0.514042	      33*	Junct-	0.052	 0.03	 1.05	  1.2	 96	   2	main 2
+ -0.219539	  -0.514007	      -3 	Waypt	0.089	 0.06	 1.14	  1.3	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/dead-ends-WP09.txt b/3rdparty/Routino/src/test/expected/dead-ends-WP09.txt
new file mode 100644
index 0000000..97db084
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/dead-ends-WP09.txt
@@ -0,0 +1,19 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219535	  -0.521016	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.521052	       5*	Junct-	0.076	 0.05	 0.08	  0.0	 96	 182	main 1
+ -0.220666	  -0.521060	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 180	main 1
+ -0.220702	  -0.519478	      12*	Junct	0.176	 0.22	 0.30	  0.3	 48	  91	high street
+ -0.220739	  -0.517804	      18*	Junct	0.186	 0.23	 0.49	  0.5	 48	  91	high street
+ -0.220782	  -0.516137	      24*	Junct	0.185	 0.23	 0.67	  0.8	 48	  91	high street
+ -0.220361	  -0.515961	      25*	Junct-	0.050	 0.06	 0.72	  0.8	 48	  22	dead-end 3
+ -0.220019	  -0.515847	      26 	Waypt	0.040	 0.05	 0.76	  0.9	 48	  18	dead-end 3
+ -0.220361	  -0.515961	      25*	Junct-	0.040	 0.05	 0.80	  0.9	 48	 198	dead-end 3
+ -0.220782	  -0.516137	      24*	Junct	0.050	 0.06	 0.85	  1.0	 48	 202	dead-end 3
+ -0.220817	  -0.514062	      32*	Junct	0.230	 0.29	 1.08	  1.3	 48	  90	high street
+ -0.220344	  -0.514042	      33*	Junct-	0.052	 0.03	 1.13	  1.3	 96	   2	main 2
+ -0.219539	  -0.514007	      -3 	Waypt	0.089	 0.06	 1.22	  1.4	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/dead-ends-WP10.txt b/3rdparty/Routino/src/test/expected/dead-ends-WP10.txt
new file mode 100644
index 0000000..b75124f
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/dead-ends-WP10.txt
@@ -0,0 +1,21 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219535	  -0.521016	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.521052	       5*	Junct-	0.076	 0.05	 0.08	  0.0	 96	 182	main 1
+ -0.220666	  -0.521060	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 180	main 1
+ -0.220702	  -0.519478	      12*	Junct	0.176	 0.22	 0.30	  0.3	 48	  91	high street
+ -0.220739	  -0.517804	      18*	Junct	0.186	 0.23	 0.49	  0.5	 48	  91	high street
+ -0.220782	  -0.516137	      24*	Junct	0.185	 0.23	 0.67	  0.8	 48	  91	high street
+ -0.220361	  -0.515961	      25*	Junct-	0.050	 0.06	 0.72	  0.8	 48	  22	dead-end 3
+ -0.220019	  -0.515847	      26 	Inter	0.040	 0.05	 0.76	  0.9	 48	  18	dead-end 3
+ -0.219672	  -0.516031	      -2 	Waypt	0.043	 0.05	 0.81	  0.9	 48	 332	dead-end 3
+ -0.220019	  -0.515847	      26 	Inter	0.043	 0.05	 0.85	  1.0	 48	 152	dead-end 3
+ -0.220361	  -0.515961	      25*	Junct-	0.040	 0.05	 0.89	  1.0	 48	 198	dead-end 3
+ -0.220782	  -0.516137	      24*	Junct	0.050	 0.06	 0.94	  1.1	 48	 202	dead-end 3
+ -0.220817	  -0.514062	      32*	Junct	0.230	 0.29	 1.17	  1.4	 48	  90	high street
+ -0.220344	  -0.514042	      33*	Junct-	0.052	 0.03	 1.22	  1.4	 96	   2	main 2
+ -0.219539	  -0.514007	      -3 	Waypt	0.089	 0.06	 1.31	  1.5	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/dead-ends-WP11.txt b/3rdparty/Routino/src/test/expected/dead-ends-WP11.txt
new file mode 100644
index 0000000..3cbc217
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/dead-ends-WP11.txt
@@ -0,0 +1,23 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219535	  -0.521016	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.521052	       5*	Junct-	0.076	 0.05	 0.08	  0.0	 96	 182	main 1
+ -0.220666	  -0.521060	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 180	main 1
+ -0.220702	  -0.519478	      12*	Junct	0.176	 0.22	 0.30	  0.3	 48	  91	high street
+ -0.220739	  -0.517804	      18*	Junct	0.186	 0.23	 0.49	  0.5	 48	  91	high street
+ -0.220782	  -0.516137	      24*	Junct	0.185	 0.23	 0.67	  0.8	 48	  91	high street
+ -0.220361	  -0.515961	      25*	Junct-	0.050	 0.06	 0.72	  0.8	 48	  22	dead-end 3
+ -0.220019	  -0.515847	      26 	Inter	0.040	 0.05	 0.76	  0.9	 48	  18	dead-end 3
+ -0.219341	  -0.516206	      23 	Inter	0.085	 0.10	 0.85	  1.0	 48	 332	dead-end 3
+ -0.218493	  -0.515789	      27*	Waypt	0.105	 0.13	 0.95	  1.1	 48	  26	dead-end 3
+ -0.219341	  -0.516206	      23 	Inter	0.105	 0.13	 1.06	  1.2	 48	 206	dead-end 3
+ -0.220019	  -0.515847	      26 	Inter	0.085	 0.10	 1.14	  1.3	 48	 152	dead-end 3
+ -0.220361	  -0.515961	      25*	Junct-	0.040	 0.05	 1.18	  1.4	 48	 198	dead-end 3
+ -0.220782	  -0.516137	      24*	Junct	0.050	 0.06	 1.23	  1.5	 48	 202	dead-end 3
+ -0.220817	  -0.514062	      32*	Junct	0.230	 0.29	 1.46	  1.7	 48	  90	high street
+ -0.220344	  -0.514042	      33*	Junct-	0.052	 0.03	 1.51	  1.8	 96	   2	main 2
+ -0.219539	  -0.514007	      -3 	Waypt	0.089	 0.06	 1.60	  1.8	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/fake-node-with-loop-WP01.txt b/3rdparty/Routino/src/test/expected/fake-node-with-loop-WP01.txt
new file mode 100644
index 0000000..7ab2431
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/fake-node-with-loop-WP01.txt
@@ -0,0 +1,19 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.216904	  -0.520770	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.217286	  -0.520780	      10 	Junct-	0.042	 0.03	 0.04	  0.0	 96	 181	main 1
+ -0.218086	  -0.520797	      -2 	Waypt	0.088	 0.06	 0.13	  0.1	 96	 181	main 1
+ -0.218523	  -0.520806	       9 	Junct-	0.048	 0.03	 0.18	  0.1	 96	 181	main 1
+ -0.219482	  -0.520837	       8*	Junct	0.106	 0.07	 0.28	  0.2	 96	 181	main 1
+ -0.219692	  -0.520509	      14 	Junct-	0.043	 0.03	 0.33	  0.2	 96	 122	roundabout
+ -0.220082	  -0.520522	      13 	Junct-	0.043	 0.03	 0.37	  0.2	 96	 181	roundabout
+ -0.220268	  -0.520863	       7 	Inter	0.043	 0.03	 0.41	  0.3	 96	 241	roundabout
+ -0.220062	  -0.521204	       4 	Junct-	0.044	 0.03	 0.46	  0.3	 96	 301	roundabout
+ -0.219665	  -0.521190	       5 	Junct-	0.044	 0.03	 0.50	  0.3	 96	   1	roundabout
+ -0.219482	  -0.520837	       8*	Junct	0.044	 0.03	 0.55	  0.3	 96	  62	roundabout
+ -0.218523	  -0.520806	       9 	Junct-	0.106	 0.07	 0.65	  0.4	 96	   1	main 1
+ -0.217741	  -0.520789	      -3 	Waypt	0.086	 0.05	 0.74	  0.5	 96	   1	main 1
diff --git a/3rdparty/Routino/src/test/expected/fake-node-with-loop-WP02.txt b/3rdparty/Routino/src/test/expected/fake-node-with-loop-WP02.txt
new file mode 100644
index 0000000..6c32260
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/fake-node-with-loop-WP02.txt
@@ -0,0 +1,18 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.216959	  -0.520771	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.217286	  -0.520780	      10 	Junct-	0.036	 0.02	 0.04	  0.0	 96	 181	main 1
+ -0.218523	  -0.520806	       9 	Junct-	0.137	 0.09	 0.17	  0.1	 96	 181	main 1
+ -0.219171	  -0.520827	      -2 	Waypt	0.071	 0.04	 0.24	  0.1	 96	 181	main 1
+ -0.219482	  -0.520837	       8*	Junct	0.034	 0.02	 0.28	  0.2	 96	 181	main 1
+ -0.219692	  -0.520509	      14 	Junct-	0.043	 0.03	 0.32	  0.2	 96	 122	roundabout
+ -0.220082	  -0.520522	      13 	Junct-	0.043	 0.03	 0.36	  0.2	 96	 181	roundabout
+ -0.220268	  -0.520863	       7 	Inter	0.043	 0.03	 0.41	  0.2	 96	 241	roundabout
+ -0.220062	  -0.521204	       4 	Junct-	0.044	 0.03	 0.45	  0.3	 96	 301	roundabout
+ -0.219665	  -0.521190	       5 	Junct-	0.044	 0.03	 0.49	  0.3	 96	   1	roundabout
+ -0.219482	  -0.520837	       8*	Junct	0.044	 0.03	 0.54	  0.3	 96	  62	roundabout
+ -0.218842	  -0.520816	      -3 	Waypt	0.070	 0.04	 0.61	  0.4	 96	   1	main 1
diff --git a/3rdparty/Routino/src/test/expected/loops-WP01.txt b/3rdparty/Routino/src/test/expected/loops-WP01.txt
new file mode 100644
index 0000000..06ab275
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/loops-WP01.txt
@@ -0,0 +1,24 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219562	  -0.520851	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.520885	       5*	Junct-	0.073	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 181	main 1
+ -0.220695	  -0.519489	      11*	Junct	0.156	 0.20	 0.28	  0.3	 48	  91	high street
+ -0.220280	  -0.519256	      15*	Waypt	0.052	 0.07	 0.33	  0.3	 48	  29	loop 1
+ -0.219910	  -0.519112	      17 	Inter	0.044	 0.06	 0.37	  0.4	 48	  21	loop 1
+ -0.219237	  -0.519286	      13*	Junct	0.077	 0.10	 0.45	  0.5	 48	 345	loop 1
+ -0.218764	  -0.519471	      12 	Inter	0.056	 0.07	 0.51	  0.6	 48	 338	loop 1
+ -0.218380	  -0.519134	      16 	Inter	0.056	 0.07	 0.56	  0.6	 48	  41	loop 1
+ -0.218776	  -0.518838	      18 	Inter	0.055	 0.07	 0.62	  0.7	 48	 143	loop 1
+ -0.219237	  -0.519286	      13*	Junct	0.071	 0.09	 0.69	  0.8	 48	 224	loop 1
+ -0.219910	  -0.519112	      17 	Inter	0.077	 0.10	 0.77	  0.9	 48	 165	loop 1
+ -0.220280	  -0.519256	      15*	Junct-	0.044	 0.06	 0.81	  0.9	 48	 201	loop 1
+ -0.220695	  -0.519489	      11*	Junct	0.052	 0.07	 0.86	  1.0	 48	 209	loop 1
+ -0.220739	  -0.517801	      19*	Junct	0.187	 0.23	 1.05	  1.2	 48	  91	high street
+ -0.220784	  -0.516035	      30*	Junct	0.196	 0.24	 1.25	  1.5	 48	  91	high street
+ -0.220311	  -0.516015	      31*	Junct-	0.052	 0.03	 1.30	  1.5	 96	   2	main 2
+ -0.219596	  -0.515984	      -3 	Waypt	0.079	 0.05	 1.38	  1.6	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/loops-WP02.txt b/3rdparty/Routino/src/test/expected/loops-WP02.txt
new file mode 100644
index 0000000..2564227
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/loops-WP02.txt
@@ -0,0 +1,24 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219562	  -0.520851	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.520885	       5*	Junct-	0.073	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 181	main 1
+ -0.220695	  -0.519489	      11*	Junct	0.156	 0.20	 0.28	  0.3	 48	  91	high street
+ -0.220280	  -0.519256	      15*	Junct-	0.052	 0.07	 0.33	  0.3	 48	  29	loop 1
+ -0.219910	  -0.519112	      17 	Waypt	0.044	 0.06	 0.37	  0.4	 48	  21	loop 1
+ -0.219237	  -0.519286	      13*	Junct	0.077	 0.10	 0.45	  0.5	 48	 345	loop 1
+ -0.218764	  -0.519471	      12 	Inter	0.056	 0.07	 0.51	  0.6	 48	 338	loop 1
+ -0.218380	  -0.519134	      16 	Inter	0.056	 0.07	 0.56	  0.6	 48	  41	loop 1
+ -0.218776	  -0.518838	      18 	Inter	0.055	 0.07	 0.62	  0.7	 48	 143	loop 1
+ -0.219237	  -0.519286	      13*	Junct	0.071	 0.09	 0.69	  0.8	 48	 224	loop 1
+ -0.219910	  -0.519112	      17 	Inter	0.077	 0.10	 0.77	  0.9	 48	 165	loop 1
+ -0.220280	  -0.519256	      15*	Junct-	0.044	 0.06	 0.81	  0.9	 48	 201	loop 1
+ -0.220695	  -0.519489	      11*	Junct	0.052	 0.07	 0.86	  1.0	 48	 209	loop 1
+ -0.220739	  -0.517801	      19*	Junct	0.187	 0.23	 1.05	  1.2	 48	  91	high street
+ -0.220784	  -0.516035	      30*	Junct	0.196	 0.24	 1.25	  1.5	 48	  91	high street
+ -0.220311	  -0.516015	      31*	Junct-	0.052	 0.03	 1.30	  1.5	 96	   2	main 2
+ -0.219596	  -0.515984	      -3 	Waypt	0.079	 0.05	 1.38	  1.6	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/loops-WP03.txt b/3rdparty/Routino/src/test/expected/loops-WP03.txt
new file mode 100644
index 0000000..c58ac3f
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/loops-WP03.txt
@@ -0,0 +1,25 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219562	  -0.520851	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.520885	       5*	Junct-	0.073	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 181	main 1
+ -0.220695	  -0.519489	      11*	Junct	0.156	 0.20	 0.28	  0.3	 48	  91	high street
+ -0.220280	  -0.519256	      15*	Junct-	0.052	 0.07	 0.33	  0.3	 48	  29	loop 1
+ -0.219910	  -0.519112	      17 	Inter	0.044	 0.06	 0.37	  0.4	 48	  21	loop 1
+ -0.219578	  -0.519198	      -2 	Waypt	0.038	 0.05	 0.41	  0.4	 48	 345	loop 1
+ -0.219237	  -0.519286	      13*	Junct	0.039	 0.05	 0.45	  0.5	 48	 345	loop 1
+ -0.218764	  -0.519471	      12 	Inter	0.056	 0.07	 0.51	  0.6	 48	 338	loop 1
+ -0.218380	  -0.519134	      16 	Inter	0.056	 0.07	 0.56	  0.6	 48	  41	loop 1
+ -0.218776	  -0.518838	      18 	Inter	0.055	 0.07	 0.62	  0.7	 48	 143	loop 1
+ -0.219237	  -0.519286	      13*	Junct	0.071	 0.09	 0.69	  0.8	 48	 224	loop 1
+ -0.219910	  -0.519112	      17 	Inter	0.077	 0.10	 0.77	  0.9	 48	 165	loop 1
+ -0.220280	  -0.519256	      15*	Junct-	0.044	 0.06	 0.81	  0.9	 48	 201	loop 1
+ -0.220695	  -0.519489	      11*	Junct	0.052	 0.07	 0.86	  1.0	 48	 209	loop 1
+ -0.220739	  -0.517801	      19*	Junct	0.187	 0.23	 1.05	  1.2	 48	  91	high street
+ -0.220784	  -0.516035	      30*	Junct	0.196	 0.24	 1.25	  1.5	 48	  91	high street
+ -0.220311	  -0.516015	      31*	Junct-	0.052	 0.03	 1.30	  1.5	 96	   2	main 2
+ -0.219596	  -0.515984	      -3 	Waypt	0.079	 0.05	 1.38	  1.6	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/loops-WP04.txt b/3rdparty/Routino/src/test/expected/loops-WP04.txt
new file mode 100644
index 0000000..078e769
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/loops-WP04.txt
@@ -0,0 +1,25 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219562	  -0.520851	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.520885	       5*	Junct-	0.073	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 181	main 1
+ -0.220695	  -0.519489	      11*	Junct	0.156	 0.20	 0.28	  0.3	 48	  91	high street
+ -0.220280	  -0.519256	      15*	Junct-	0.052	 0.07	 0.33	  0.3	 48	  29	loop 1
+ -0.219910	  -0.519112	      17 	Inter	0.044	 0.06	 0.37	  0.4	 48	  21	loop 1
+ -0.219237	  -0.519286	      13*	Junct	0.077	 0.10	 0.45	  0.5	 48	 345	loop 1
+ -0.218997	  -0.519053	      -2 	Waypt	0.037	 0.04	 0.49	  0.5	 48	  44	loop 1
+ -0.218776	  -0.518838	      18 	Inter	0.034	 0.04	 0.52	  0.6	 48	  44	loop 1
+ -0.218380	  -0.519134	      16 	Inter	0.055	 0.07	 0.58	  0.6	 48	 323	loop 1
+ -0.218764	  -0.519471	      12 	Inter	0.056	 0.07	 0.63	  0.7	 48	 221	loop 1
+ -0.219237	  -0.519286	      13*	Junct	0.056	 0.07	 0.69	  0.8	 48	 158	loop 1
+ -0.219910	  -0.519112	      17 	Inter	0.077	 0.10	 0.77	  0.9	 48	 165	loop 1
+ -0.220280	  -0.519256	      15*	Junct-	0.044	 0.06	 0.81	  0.9	 48	 201	loop 1
+ -0.220695	  -0.519489	      11*	Junct	0.052	 0.07	 0.86	  1.0	 48	 209	loop 1
+ -0.220739	  -0.517801	      19*	Junct	0.187	 0.23	 1.05	  1.2	 48	  91	high street
+ -0.220784	  -0.516035	      30*	Junct	0.196	 0.24	 1.25	  1.5	 48	  91	high street
+ -0.220311	  -0.516015	      31*	Junct-	0.052	 0.03	 1.30	  1.5	 96	   2	main 2
+ -0.219596	  -0.515984	      -3 	Waypt	0.079	 0.05	 1.38	  1.6	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/loops-WP05.txt b/3rdparty/Routino/src/test/expected/loops-WP05.txt
new file mode 100644
index 0000000..d959214
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/loops-WP05.txt
@@ -0,0 +1,24 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219562	  -0.520851	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.520885	       5*	Junct-	0.073	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 181	main 1
+ -0.220695	  -0.519489	      11*	Junct	0.156	 0.20	 0.28	  0.3	 48	  91	high street
+ -0.220280	  -0.519256	      15*	Junct-	0.052	 0.07	 0.33	  0.3	 48	  29	loop 1
+ -0.219910	  -0.519112	      17 	Inter	0.044	 0.06	 0.37	  0.4	 48	  21	loop 1
+ -0.219237	  -0.519286	      13*	Junct	0.077	 0.10	 0.45	  0.5	 48	 345	loop 1
+ -0.218764	  -0.519471	      12 	Inter	0.056	 0.07	 0.51	  0.6	 48	 338	loop 1
+ -0.218380	  -0.519134	      16 	Waypt	0.056	 0.07	 0.56	  0.6	 48	  41	loop 1
+ -0.218776	  -0.518838	      18 	Inter	0.055	 0.07	 0.62	  0.7	 48	 143	loop 1
+ -0.219237	  -0.519286	      13*	Junct	0.071	 0.09	 0.69	  0.8	 48	 224	loop 1
+ -0.219910	  -0.519112	      17 	Inter	0.077	 0.10	 0.77	  0.9	 48	 165	loop 1
+ -0.220280	  -0.519256	      15*	Junct-	0.044	 0.06	 0.81	  0.9	 48	 201	loop 1
+ -0.220695	  -0.519489	      11*	Junct	0.052	 0.07	 0.86	  1.0	 48	 209	loop 1
+ -0.220739	  -0.517801	      19*	Junct	0.187	 0.23	 1.05	  1.2	 48	  91	high street
+ -0.220784	  -0.516035	      30*	Junct	0.196	 0.24	 1.25	  1.5	 48	  91	high street
+ -0.220311	  -0.516015	      31*	Junct-	0.052	 0.03	 1.30	  1.5	 96	   2	main 2
+ -0.219596	  -0.515984	      -3 	Waypt	0.079	 0.05	 1.38	  1.6	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/loops-WP06.txt b/3rdparty/Routino/src/test/expected/loops-WP06.txt
new file mode 100644
index 0000000..8310598
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/loops-WP06.txt
@@ -0,0 +1,24 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219562	  -0.520851	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.520885	       5*	Junct-	0.073	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 181	main 1
+ -0.220695	  -0.519489	      11*	Junct	0.156	 0.20	 0.28	  0.3	 48	  91	high street
+ -0.220739	  -0.517801	      19*	Junct	0.187	 0.23	 0.47	  0.5	 48	  91	high street
+ -0.220301	  -0.517576	      22*	Waypt	0.054	 0.07	 0.52	  0.6	 48	  27	loop 2
+ -0.219946	  -0.517397	      24 	Inter	0.044	 0.06	 0.56	  0.6	 48	  26	loop 2
+ -0.219266	  -0.517579	      21*	Junct	0.078	 0.10	 0.64	  0.7	 48	 345	loop 2
+ -0.218794	  -0.517763	      20 	Inter	0.056	 0.07	 0.70	  0.8	 48	 338	loop 2
+ -0.218417	  -0.517462	      23*	Junct-	0.053	 0.07	 0.75	  0.9	 48	  38	loop 2
+ -0.218805	  -0.517131	      25 	Inter	0.056	 0.07	 0.81	  0.9	 48	 139	loop 2
+ -0.219266	  -0.517579	      21*	Junct	0.071	 0.09	 0.88	  1.0	 48	 224	loop 2
+ -0.219946	  -0.517397	      24 	Inter	0.078	 0.10	 0.95	  1.1	 48	 165	loop 2
+ -0.220301	  -0.517576	      22*	Junct-	0.044	 0.06	 1.00	  1.2	 48	 206	loop 2
+ -0.220739	  -0.517801	      19*	Junct	0.054	 0.07	 1.05	  1.2	 48	 207	loop 2
+ -0.220784	  -0.516035	      30*	Junct	0.196	 0.24	 1.25	  1.5	 48	  91	high street
+ -0.220311	  -0.516015	      31*	Junct-	0.052	 0.03	 1.30	  1.5	 96	   2	main 2
+ -0.219596	  -0.515984	      -3 	Waypt	0.079	 0.05	 1.38	  1.6	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/loops-WP07.txt b/3rdparty/Routino/src/test/expected/loops-WP07.txt
new file mode 100644
index 0000000..5bc2e8a
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/loops-WP07.txt
@@ -0,0 +1,24 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219562	  -0.520851	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.520885	       5*	Junct-	0.073	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 181	main 1
+ -0.220695	  -0.519489	      11*	Junct	0.156	 0.20	 0.28	  0.3	 48	  91	high street
+ -0.220739	  -0.517801	      19*	Junct	0.187	 0.23	 0.47	  0.5	 48	  91	high street
+ -0.220301	  -0.517576	      22*	Junct-	0.054	 0.07	 0.52	  0.6	 48	  27	loop 2
+ -0.219946	  -0.517397	      24 	Waypt	0.044	 0.06	 0.56	  0.6	 48	  26	loop 2
+ -0.219266	  -0.517579	      21*	Junct	0.078	 0.10	 0.64	  0.7	 48	 345	loop 2
+ -0.218794	  -0.517763	      20 	Inter	0.056	 0.07	 0.70	  0.8	 48	 338	loop 2
+ -0.218417	  -0.517462	      23*	Junct-	0.053	 0.07	 0.75	  0.9	 48	  38	loop 2
+ -0.218805	  -0.517131	      25 	Inter	0.056	 0.07	 0.81	  0.9	 48	 139	loop 2
+ -0.219266	  -0.517579	      21*	Junct	0.071	 0.09	 0.88	  1.0	 48	 224	loop 2
+ -0.219946	  -0.517397	      24 	Inter	0.078	 0.10	 0.95	  1.1	 48	 165	loop 2
+ -0.220301	  -0.517576	      22*	Junct-	0.044	 0.06	 1.00	  1.2	 48	 206	loop 2
+ -0.220739	  -0.517801	      19*	Junct	0.054	 0.07	 1.05	  1.2	 48	 207	loop 2
+ -0.220784	  -0.516035	      30*	Junct	0.196	 0.24	 1.25	  1.5	 48	  91	high street
+ -0.220311	  -0.516015	      31*	Junct-	0.052	 0.03	 1.30	  1.5	 96	   2	main 2
+ -0.219596	  -0.515984	      -3 	Waypt	0.079	 0.05	 1.38	  1.6	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/loops-WP08.txt b/3rdparty/Routino/src/test/expected/loops-WP08.txt
new file mode 100644
index 0000000..eed204d
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/loops-WP08.txt
@@ -0,0 +1,25 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219562	  -0.520851	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.520885	       5*	Junct-	0.073	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 181	main 1
+ -0.220695	  -0.519489	      11*	Junct	0.156	 0.20	 0.28	  0.3	 48	  91	high street
+ -0.220739	  -0.517801	      19*	Junct	0.187	 0.23	 0.47	  0.5	 48	  91	high street
+ -0.220301	  -0.517576	      22*	Junct-	0.054	 0.07	 0.52	  0.6	 48	  27	loop 2
+ -0.219946	  -0.517397	      24 	Inter	0.044	 0.06	 0.56	  0.6	 48	  26	loop 2
+ -0.219597	  -0.517490	      -2 	Waypt	0.040	 0.05	 0.60	  0.7	 48	 345	loop 2
+ -0.219266	  -0.517579	      21*	Junct	0.038	 0.05	 0.64	  0.7	 48	 345	loop 2
+ -0.218794	  -0.517763	      20 	Inter	0.056	 0.07	 0.70	  0.8	 48	 338	loop 2
+ -0.218417	  -0.517462	      23*	Junct-	0.053	 0.07	 0.75	  0.9	 48	  38	loop 2
+ -0.218805	  -0.517131	      25 	Inter	0.056	 0.07	 0.81	  0.9	 48	 139	loop 2
+ -0.219266	  -0.517579	      21*	Junct	0.071	 0.09	 0.88	  1.0	 48	 224	loop 2
+ -0.219946	  -0.517397	      24 	Inter	0.078	 0.10	 0.95	  1.1	 48	 165	loop 2
+ -0.220301	  -0.517576	      22*	Junct-	0.044	 0.06	 1.00	  1.2	 48	 206	loop 2
+ -0.220739	  -0.517801	      19*	Junct	0.054	 0.07	 1.05	  1.2	 48	 207	loop 2
+ -0.220784	  -0.516035	      30*	Junct	0.196	 0.24	 1.25	  1.5	 48	  91	high street
+ -0.220311	  -0.516015	      31*	Junct-	0.052	 0.03	 1.30	  1.5	 96	   2	main 2
+ -0.219596	  -0.515984	      -3 	Waypt	0.079	 0.05	 1.38	  1.6	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/loops-WP09.txt b/3rdparty/Routino/src/test/expected/loops-WP09.txt
new file mode 100644
index 0000000..d7b8fde
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/loops-WP09.txt
@@ -0,0 +1,25 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219562	  -0.520851	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.520885	       5*	Junct-	0.073	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 181	main 1
+ -0.220695	  -0.519489	      11*	Junct	0.156	 0.20	 0.28	  0.3	 48	  91	high street
+ -0.220739	  -0.517801	      19*	Junct	0.187	 0.23	 0.47	  0.5	 48	  91	high street
+ -0.220301	  -0.517576	      22*	Junct-	0.054	 0.07	 0.52	  0.6	 48	  27	loop 2
+ -0.219946	  -0.517397	      24 	Inter	0.044	 0.06	 0.56	  0.6	 48	  26	loop 2
+ -0.219266	  -0.517579	      21*	Junct	0.078	 0.10	 0.64	  0.7	 48	 345	loop 2
+ -0.219013	  -0.517333	      -2 	Waypt	0.039	 0.05	 0.68	  0.8	 48	  44	loop 2
+ -0.218805	  -0.517131	      25 	Inter	0.032	 0.04	 0.71	  0.8	 48	  44	loop 2
+ -0.218417	  -0.517462	      23*	Junct-	0.056	 0.07	 0.77	  0.9	 48	 319	loop 2
+ -0.218794	  -0.517763	      20 	Inter	0.053	 0.07	 0.82	  0.9	 48	 218	loop 2
+ -0.219266	  -0.517579	      21*	Junct	0.056	 0.07	 0.88	  1.0	 48	 158	loop 2
+ -0.219946	  -0.517397	      24 	Inter	0.078	 0.10	 0.95	  1.1	 48	 165	loop 2
+ -0.220301	  -0.517576	      22*	Junct-	0.044	 0.06	 1.00	  1.2	 48	 206	loop 2
+ -0.220739	  -0.517801	      19*	Junct	0.054	 0.07	 1.05	  1.2	 48	 207	loop 2
+ -0.220784	  -0.516035	      30*	Junct	0.196	 0.24	 1.25	  1.5	 48	  91	high street
+ -0.220311	  -0.516015	      31*	Junct-	0.052	 0.03	 1.30	  1.5	 96	   2	main 2
+ -0.219596	  -0.515984	      -3 	Waypt	0.079	 0.05	 1.38	  1.6	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/loops-WP10.txt b/3rdparty/Routino/src/test/expected/loops-WP10.txt
new file mode 100644
index 0000000..1cd80bd
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/loops-WP10.txt
@@ -0,0 +1,24 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219562	  -0.520851	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.520885	       5*	Junct-	0.073	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 181	main 1
+ -0.220695	  -0.519489	      11*	Junct	0.156	 0.20	 0.28	  0.3	 48	  91	high street
+ -0.220739	  -0.517801	      19*	Junct	0.187	 0.23	 0.47	  0.5	 48	  91	high street
+ -0.220301	  -0.517576	      22*	Junct-	0.054	 0.07	 0.52	  0.6	 48	  27	loop 2
+ -0.219946	  -0.517397	      24 	Inter	0.044	 0.06	 0.56	  0.6	 48	  26	loop 2
+ -0.219266	  -0.517579	      21*	Junct	0.078	 0.10	 0.64	  0.7	 48	 345	loop 2
+ -0.218805	  -0.517131	      25 	Waypt	0.071	 0.09	 0.71	  0.8	 48	  44	loop 2
+ -0.218417	  -0.517462	      23*	Junct-	0.056	 0.07	 0.77	  0.9	 48	 319	loop 2
+ -0.218794	  -0.517763	      20 	Inter	0.053	 0.07	 0.82	  0.9	 48	 218	loop 2
+ -0.219266	  -0.517579	      21*	Junct	0.056	 0.07	 0.88	  1.0	 48	 158	loop 2
+ -0.219946	  -0.517397	      24 	Inter	0.078	 0.10	 0.95	  1.1	 48	 165	loop 2
+ -0.220301	  -0.517576	      22*	Junct-	0.044	 0.06	 1.00	  1.2	 48	 206	loop 2
+ -0.220739	  -0.517801	      19*	Junct	0.054	 0.07	 1.05	  1.2	 48	 207	loop 2
+ -0.220784	  -0.516035	      30*	Junct	0.196	 0.24	 1.25	  1.5	 48	  91	high street
+ -0.220311	  -0.516015	      31*	Junct-	0.052	 0.03	 1.30	  1.5	 96	   2	main 2
+ -0.219596	  -0.515984	      -3 	Waypt	0.079	 0.05	 1.38	  1.6	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/loops-WP11.txt b/3rdparty/Routino/src/test/expected/loops-WP11.txt
new file mode 100644
index 0000000..f73fb5f
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/loops-WP11.txt
@@ -0,0 +1,24 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219562	  -0.520851	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220223	  -0.520885	       5*	Junct-	0.073	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       4*	Junct	0.049	 0.03	 0.12	  0.1	 96	 181	main 1
+ -0.220695	  -0.519489	      11*	Junct	0.156	 0.20	 0.28	  0.3	 48	  91	high street
+ -0.220739	  -0.517801	      19*	Junct	0.187	 0.23	 0.47	  0.5	 48	  91	high street
+ -0.220301	  -0.517576	      22*	Junct-	0.054	 0.07	 0.52	  0.6	 48	  27	loop 2
+ -0.219946	  -0.517397	      24 	Inter	0.044	 0.06	 0.56	  0.6	 48	  26	loop 2
+ -0.219266	  -0.517579	      21*	Junct	0.078	 0.10	 0.64	  0.7	 48	 345	loop 2
+ -0.218794	  -0.517763	      20 	Inter	0.056	 0.07	 0.70	  0.8	 48	 338	loop 2
+ -0.218417	  -0.517462	      23*	Waypt	0.053	 0.07	 0.75	  0.9	 48	  38	loop 2
+ -0.218805	  -0.517131	      25 	Inter	0.056	 0.07	 0.81	  0.9	 48	 139	loop 2
+ -0.219266	  -0.517579	      21*	Junct	0.071	 0.09	 0.88	  1.0	 48	 224	loop 2
+ -0.219946	  -0.517397	      24 	Inter	0.078	 0.10	 0.95	  1.1	 48	 165	loop 2
+ -0.220301	  -0.517576	      22*	Junct-	0.044	 0.06	 1.00	  1.2	 48	 206	loop 2
+ -0.220739	  -0.517801	      19*	Junct	0.054	 0.07	 1.05	  1.2	 48	 207	loop 2
+ -0.220784	  -0.516035	      30*	Junct	0.196	 0.24	 1.25	  1.5	 48	  91	high street
+ -0.220311	  -0.516015	      31*	Junct-	0.052	 0.03	 1.30	  1.5	 96	   2	main 2
+ -0.219596	  -0.515984	      -3 	Waypt	0.079	 0.05	 1.38	  1.6	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/no-super-WP01.txt b/3rdparty/Routino/src/test/expected/no-super-WP01.txt
new file mode 100644
index 0000000..e4ca14f
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/no-super-WP01.txt
@@ -0,0 +1,16 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.215814	  -0.519419	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.215737	  -0.519035	       7 	Inter	0.043	 0.05	 0.04	  0.1	 48	  78	road1
+ -0.215935	  -0.518253	      10 	Inter	0.089	 0.11	 0.13	  0.2	 48	 104	road1
+ -0.215772	  -0.517713	      13 	Inter	0.062	 0.08	 0.19	  0.2	 48	  73	road1
+ -0.215952	  -0.516838	      15 	Inter	0.099	 0.12	 0.29	  0.4	 48	 101	road1
+ -0.215755	  -0.515945	      19 	Inter	0.101	 0.12	 0.39	  0.5	 48	  77	road1
+ -0.215897	  -0.515462	      -2 	Waypt	0.055	 0.07	 0.45	  0.6	 48	 106	road1
+ -0.215755	  -0.515945	      19 	Inter	0.055	 0.07	 0.50	  0.6	 48	 286	road1
+ -0.215952	  -0.516838	      15 	Inter	0.101	 0.12	 0.60	  0.8	 48	 257	road1
+ -0.215868	  -0.517244	      -3 	Waypt	0.046	 0.06	 0.65	  0.8	 48	 281	road1
diff --git a/3rdparty/Routino/src/test/expected/no-super-WP02.txt b/3rdparty/Routino/src/test/expected/no-super-WP02.txt
new file mode 100644
index 0000000..fa321e3
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/no-super-WP02.txt
@@ -0,0 +1,9 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.216472	  -0.519026	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.216671	  -0.515660	      -2 	Waypt	0.374	 0.47	 0.37	  0.5	 48	  93	road2
+ -0.216579	  -0.517212	      -3 	Waypt	0.172	 0.21	 0.55	  0.7	 48	 273	road2
diff --git a/3rdparty/Routino/src/test/expected/no-super-WP03.txt b/3rdparty/Routino/src/test/expected/no-super-WP03.txt
new file mode 100644
index 0000000..e0630c4
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/no-super-WP03.txt
@@ -0,0 +1,13 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.217185	  -0.519054	       5 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.217382	  -0.518273	       8 	Inter	0.089	 0.11	 0.09	  0.1	 48	 104	road3
+ -0.217219	  -0.517733	      11 	Inter	0.062	 0.08	 0.15	  0.2	 48	  73	road3
+ -0.217399	  -0.516857	      14 	Inter	0.099	 0.12	 0.25	  0.3	 48	 101	road3
+ -0.217202	  -0.515964	      17 	Waypt	0.101	 0.12	 0.35	  0.4	 48	  77	road3
+ -0.217399	  -0.516857	      14 	Inter	0.101	 0.12	 0.45	  0.6	 48	 257	road3
+ -0.217219	  -0.517733	      11 	Waypt	0.099	 0.12	 0.55	  0.7	 48	 281	road3
diff --git a/3rdparty/Routino/src/test/expected/no-super-WP04.txt b/3rdparty/Routino/src/test/expected/no-super-WP04.txt
new file mode 100644
index 0000000..901aced
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/no-super-WP04.txt
@@ -0,0 +1,17 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.217903	  -0.519035	       6 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.218100	  -0.518253	       9 	Inter	0.089	 0.11	 0.09	  0.1	 48	 104	road4
+ -0.217937	  -0.517713	      12 	Inter	0.062	 0.08	 0.15	  0.2	 48	  73	road4
+ -0.218117	  -0.516837	      16 	Inter	0.099	 0.12	 0.25	  0.3	 48	 101	road4
+ -0.217920	  -0.515945	      18 	Inter	0.101	 0.12	 0.35	  0.4	 48	  77	road4
+ -0.218143	  -0.515189	      21 	Inter	0.087	 0.11	 0.44	  0.5	 48	 106	road4
+ -0.217911	  -0.514640	      26 	Waypt	0.066	 0.08	 0.50	  0.6	 48	  67	road4
+ -0.218143	  -0.515189	      21 	Inter	0.066	 0.08	 0.57	  0.7	 48	 247	road4
+ -0.217920	  -0.515945	      18 	Inter	0.087	 0.11	 0.66	  0.8	 48	 286	road4
+ -0.218117	  -0.516837	      16 	Inter	0.101	 0.12	 0.76	  0.9	 48	 257	road4
+ -0.217937	  -0.517713	      12 	Waypt	0.099	 0.12	 0.86	  1.1	 48	 281	road4
diff --git a/3rdparty/Routino/src/test/expected/node-restrictions-WP01.txt b/3rdparty/Routino/src/test/expected/node-restrictions-WP01.txt
new file mode 100644
index 0000000..48b600b
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/node-restrictions-WP01.txt
@@ -0,0 +1,24 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219564	  -0.520846	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220666	  -0.520893	       4*	Junct	0.122	 0.07	 0.12	  0.1	 96	 182	main 1
+ -0.220682	  -0.520141	       9*	Junct	0.083	 0.08	 0.20	  0.2	 64	  91	high street
+ -0.220695	  -0.519489	      12*	Change	0.072	 0.07	 0.28	  0.2	 64	  91	high street
+ -0.221123	  -0.519360	      13 	Inter	0.049	 0.06	 0.33	  0.3	 48	 163	somepass road
+ -0.221156	  -0.518615	      19*	Waypt	0.082	 0.10	 0.41	  0.4	 48	  92	somepass road
+ -0.221123	  -0.519360	      13 	Inter	0.082	 0.10	 0.49	  0.5	 48	 272	somepass road
+ -0.220695	  -0.519489	      12*	Junct	0.049	 0.06	 0.54	  0.5	 48	 343	somepass road
+ -0.220694	  -0.519227	      15 	Inter	0.029	 0.04	 0.57	  0.6	 48	  89	long road
+ -0.220386	  -0.519076	      16 	Inter	0.038	 0.05	 0.61	  0.6	 48	  26	long road
+ -0.220961	  -0.518928	      17 	Inter	0.066	 0.08	 0.67	  0.7	 48	 165	long road
+ -0.220427	  -0.518622	      18 	Inter	0.068	 0.09	 0.74	  0.8	 48	  29	long road
+ -0.220949	  -0.518422	      21 	Inter	0.062	 0.08	 0.80	  0.9	 48	 159	long road
+ -0.220455	  -0.518238	      22 	Inter	0.058	 0.07	 0.86	  0.9	 48	  20	long road
+ -0.220746	  -0.518070	      23 	Inter	0.037	 0.04	 0.90	  1.0	 48	 149	long road
+ -0.220739	  -0.517801	      26*	Junct	0.029	 0.04	 0.93	  1.0	 48	  88	long road
+ -0.220784	  -0.516035	      31*	Junct	0.196	 0.18	 1.12	  1.2	 64	  91	high street
+ -0.219593	  -0.515985	      -3 	Waypt	0.132	 0.08	 1.25	  1.3	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/node-restrictions-WP02.txt b/3rdparty/Routino/src/test/expected/node-restrictions-WP02.txt
new file mode 100644
index 0000000..266baec
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/node-restrictions-WP02.txt
@@ -0,0 +1,24 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219564	  -0.520846	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220666	  -0.520893	       4*	Junct	0.122	 0.07	 0.12	  0.1	 96	 182	main 1
+ -0.220682	  -0.520141	       9*	Junct	0.083	 0.08	 0.20	  0.2	 64	  91	high street
+ -0.220695	  -0.519489	      12*	Change	0.072	 0.07	 0.28	  0.2	 64	  91	high street
+ -0.221123	  -0.519360	      13 	Inter	0.049	 0.06	 0.33	  0.3	 48	 163	somepass road
+ -0.221154	  -0.518671	      -2 	Waypt	0.075	 0.09	 0.40	  0.4	 48	  92	somepass road
+ -0.221123	  -0.519360	      13 	Inter	0.075	 0.09	 0.48	  0.5	 48	 272	somepass road
+ -0.220695	  -0.519489	      12*	Junct	0.049	 0.06	 0.53	  0.5	 48	 343	somepass road
+ -0.220694	  -0.519227	      15 	Inter	0.029	 0.04	 0.55	  0.6	 48	  89	long road
+ -0.220386	  -0.519076	      16 	Inter	0.038	 0.05	 0.59	  0.6	 48	  26	long road
+ -0.220961	  -0.518928	      17 	Inter	0.066	 0.08	 0.66	  0.7	 48	 165	long road
+ -0.220427	  -0.518622	      18 	Inter	0.068	 0.09	 0.73	  0.8	 48	  29	long road
+ -0.220949	  -0.518422	      21 	Inter	0.062	 0.08	 0.79	  0.8	 48	 159	long road
+ -0.220455	  -0.518238	      22 	Inter	0.058	 0.07	 0.85	  0.9	 48	  20	long road
+ -0.220746	  -0.518070	      23 	Inter	0.037	 0.04	 0.88	  1.0	 48	 149	long road
+ -0.220739	  -0.517801	      26*	Junct	0.029	 0.04	 0.91	  1.0	 48	  88	long road
+ -0.220784	  -0.516035	      31*	Junct	0.196	 0.18	 1.11	  1.2	 64	  91	high street
+ -0.219593	  -0.515985	      -3 	Waypt	0.132	 0.08	 1.24	  1.3	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/node-restrictions-WP03.txt b/3rdparty/Routino/src/test/expected/node-restrictions-WP03.txt
new file mode 100644
index 0000000..db18d43
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/node-restrictions-WP03.txt
@@ -0,0 +1,24 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219564	  -0.520846	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220666	  -0.520893	       4*	Junct	0.122	 0.07	 0.12	  0.1	 96	 182	main 1
+ -0.220682	  -0.520141	       9*	Junct	0.083	 0.08	 0.20	  0.2	 64	  91	high street
+ -0.220695	  -0.519489	      12*	Change	0.072	 0.07	 0.28	  0.2	 64	  91	high street
+ -0.220694	  -0.519227	      15 	Inter	0.029	 0.04	 0.31	  0.3	 48	  89	long road
+ -0.220386	  -0.519076	      16 	Inter	0.038	 0.05	 0.34	  0.3	 48	  26	long road
+ -0.220961	  -0.518928	      17 	Inter	0.066	 0.08	 0.41	  0.4	 48	 165	long road
+ -0.220427	  -0.518622	      18 	Inter	0.068	 0.09	 0.48	  0.5	 48	  29	long road
+ -0.220949	  -0.518422	      21 	Inter	0.062	 0.08	 0.54	  0.5	 48	 159	long road
+ -0.220455	  -0.518238	      22 	Inter	0.058	 0.07	 0.60	  0.6	 48	  20	long road
+ -0.220746	  -0.518070	      23 	Inter	0.037	 0.04	 0.64	  0.7	 48	 149	long road
+ -0.220739	  -0.517801	      26*	Junct	0.029	 0.04	 0.66	  0.7	 48	  88	long road
+ -0.221166	  -0.517916	      24 	Inter	0.049	 0.06	 0.71	  0.8	 48	 195	somepass road
+ -0.221157	  -0.518560	      -2 	Waypt	0.070	 0.09	 0.78	  0.8	 48	 270	somepass road
+ -0.221166	  -0.517916	      24 	Inter	0.070	 0.09	 0.85	  0.9	 48	  90	somepass road
+ -0.220739	  -0.517801	      26*	Junct	0.049	 0.06	 0.90	  1.0	 48	  15	somepass road
+ -0.220784	  -0.516035	      31*	Junct	0.196	 0.18	 1.10	  1.2	 64	  91	high street
+ -0.219593	  -0.515985	      -3 	Waypt	0.132	 0.08	 1.23	  1.3	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/node-restrictions-WP04.txt b/3rdparty/Routino/src/test/expected/node-restrictions-WP04.txt
new file mode 100644
index 0000000..44982e4
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/node-restrictions-WP04.txt
@@ -0,0 +1,24 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219564	  -0.520846	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220666	  -0.520893	       4*	Junct	0.122	 0.07	 0.12	  0.1	 96	 182	main 1
+ -0.220682	  -0.520141	       9*	Junct	0.083	 0.08	 0.20	  0.2	 64	  91	high street
+ -0.220695	  -0.519489	      12*	Change	0.072	 0.07	 0.28	  0.2	 64	  91	high street
+ -0.220140	  -0.519342	      14 	Inter	0.063	 0.08	 0.34	  0.3	 48	  14	nopass road
+ -0.220173	  -0.518597	      20 	Waypt	0.082	 0.10	 0.42	  0.4	 48	  92	nopass road
+ -0.220140	  -0.519342	      14 	Inter	0.082	 0.10	 0.50	  0.5	 48	 272	nopass road
+ -0.220695	  -0.519489	      12*	Junct	0.063	 0.08	 0.57	  0.6	 48	 194	nopass road
+ -0.220694	  -0.519227	      15 	Inter	0.029	 0.04	 0.60	  0.6	 48	  89	long road
+ -0.220386	  -0.519076	      16 	Inter	0.038	 0.05	 0.63	  0.7	 48	  26	long road
+ -0.220961	  -0.518928	      17 	Inter	0.066	 0.08	 0.70	  0.7	 48	 165	long road
+ -0.220427	  -0.518622	      18 	Inter	0.068	 0.09	 0.77	  0.8	 48	  29	long road
+ -0.220949	  -0.518422	      21 	Inter	0.062	 0.08	 0.83	  0.9	 48	 159	long road
+ -0.220455	  -0.518238	      22 	Inter	0.058	 0.07	 0.89	  1.0	 48	  20	long road
+ -0.220746	  -0.518070	      23 	Inter	0.037	 0.04	 0.93	  1.0	 48	 149	long road
+ -0.220739	  -0.517801	      26*	Junct	0.029	 0.04	 0.95	  1.1	 48	  88	long road
+ -0.220784	  -0.516035	      31*	Junct	0.196	 0.18	 1.15	  1.2	 64	  91	high street
+ -0.219593	  -0.515985	      -3 	Waypt	0.132	 0.08	 1.28	  1.3	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/node-restrictions-WP05.txt b/3rdparty/Routino/src/test/expected/node-restrictions-WP05.txt
new file mode 100644
index 0000000..b415fda
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/node-restrictions-WP05.txt
@@ -0,0 +1,24 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219564	  -0.520846	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220666	  -0.520893	       4*	Junct	0.122	 0.07	 0.12	  0.1	 96	 182	main 1
+ -0.220682	  -0.520141	       9*	Junct	0.083	 0.08	 0.20	  0.2	 64	  91	high street
+ -0.220695	  -0.519489	      12*	Change	0.072	 0.07	 0.28	  0.2	 64	  91	high street
+ -0.220140	  -0.519342	      14 	Inter	0.063	 0.08	 0.34	  0.3	 48	  14	nopass road
+ -0.220170	  -0.518653	      -2 	Waypt	0.075	 0.09	 0.41	  0.4	 48	  92	nopass road
+ -0.220140	  -0.519342	      14 	Inter	0.075	 0.09	 0.49	  0.5	 48	 272	nopass road
+ -0.220695	  -0.519489	      12*	Junct	0.063	 0.08	 0.55	  0.6	 48	 194	nopass road
+ -0.220694	  -0.519227	      15 	Inter	0.029	 0.04	 0.58	  0.6	 48	  89	long road
+ -0.220386	  -0.519076	      16 	Inter	0.038	 0.05	 0.62	  0.6	 48	  26	long road
+ -0.220961	  -0.518928	      17 	Inter	0.066	 0.08	 0.69	  0.7	 48	 165	long road
+ -0.220427	  -0.518622	      18 	Inter	0.068	 0.09	 0.75	  0.8	 48	  29	long road
+ -0.220949	  -0.518422	      21 	Inter	0.062	 0.08	 0.82	  0.9	 48	 159	long road
+ -0.220455	  -0.518238	      22 	Inter	0.058	 0.07	 0.87	  1.0	 48	  20	long road
+ -0.220746	  -0.518070	      23 	Inter	0.037	 0.04	 0.91	  1.0	 48	 149	long road
+ -0.220739	  -0.517801	      26*	Junct	0.029	 0.04	 0.94	  1.0	 48	  88	long road
+ -0.220784	  -0.516035	      31*	Junct	0.196	 0.18	 1.14	  1.2	 64	  91	high street
+ -0.219593	  -0.515985	      -3 	Waypt	0.132	 0.08	 1.27	  1.3	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/node-restrictions-WP06.txt b/3rdparty/Routino/src/test/expected/node-restrictions-WP06.txt
new file mode 100644
index 0000000..f233e8c
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/node-restrictions-WP06.txt
@@ -0,0 +1,24 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219564	  -0.520846	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220666	  -0.520893	       4*	Junct	0.122	 0.07	 0.12	  0.1	 96	 182	main 1
+ -0.220682	  -0.520141	       9*	Junct	0.083	 0.08	 0.20	  0.2	 64	  91	high street
+ -0.220695	  -0.519489	      12*	Change	0.072	 0.07	 0.28	  0.2	 64	  91	high street
+ -0.220694	  -0.519227	      15 	Inter	0.029	 0.04	 0.31	  0.3	 48	  89	long road
+ -0.220386	  -0.519076	      16 	Inter	0.038	 0.05	 0.34	  0.3	 48	  26	long road
+ -0.220961	  -0.518928	      17 	Inter	0.066	 0.08	 0.41	  0.4	 48	 165	long road
+ -0.220427	  -0.518622	      18 	Inter	0.068	 0.09	 0.48	  0.5	 48	  29	long road
+ -0.220949	  -0.518422	      21 	Inter	0.062	 0.08	 0.54	  0.5	 48	 159	long road
+ -0.220455	  -0.518238	      22 	Inter	0.058	 0.07	 0.60	  0.6	 48	  20	long road
+ -0.220746	  -0.518070	      23 	Inter	0.037	 0.04	 0.64	  0.7	 48	 149	long road
+ -0.220739	  -0.517801	      26*	Junct	0.029	 0.04	 0.66	  0.7	 48	  88	long road
+ -0.220212	  -0.517903	      25 	Inter	0.059	 0.07	 0.72	  0.8	 48	 349	nopass road
+ -0.220176	  -0.518543	      -2 	Waypt	0.070	 0.09	 0.79	  0.9	 48	 273	nopass road
+ -0.220212	  -0.517903	      25 	Inter	0.070	 0.09	 0.86	  0.9	 48	  93	nopass road
+ -0.220739	  -0.517801	      26*	Junct	0.059	 0.07	 0.92	  1.0	 48	 169	nopass road
+ -0.220784	  -0.516035	      31*	Junct	0.196	 0.18	 1.12	  1.2	 64	  91	high street
+ -0.219593	  -0.515985	      -3 	Waypt	0.132	 0.08	 1.25	  1.3	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/node-restrictions-WP07.txt b/3rdparty/Routino/src/test/expected/node-restrictions-WP07.txt
new file mode 100644
index 0000000..d9df640
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/node-restrictions-WP07.txt
@@ -0,0 +1,22 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219564	  -0.520846	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220666	  -0.520893	       4*	Junct	0.122	 0.07	 0.12	  0.1	 96	 182	main 1
+ -0.220682	  -0.520141	       9*	Junct	0.083	 0.08	 0.20	  0.2	 64	  91	high street
+ -0.219009	  -0.520075	      10*	Waypt	0.186	 0.17	 0.39	  0.3	 64	   2	dead end road
+ -0.220682	  -0.520141	       9*	Junct	0.186	 0.17	 0.58	  0.5	 64	 182	dead end road
+ -0.220695	  -0.519489	      12*	Change	0.072	 0.07	 0.65	  0.6	 64	  91	high street
+ -0.220694	  -0.519227	      15 	Inter	0.029	 0.04	 0.68	  0.6	 48	  89	long road
+ -0.220386	  -0.519076	      16 	Inter	0.038	 0.05	 0.72	  0.6	 48	  26	long road
+ -0.220961	  -0.518928	      17 	Inter	0.066	 0.08	 0.78	  0.7	 48	 165	long road
+ -0.220427	  -0.518622	      18 	Inter	0.068	 0.09	 0.85	  0.8	 48	  29	long road
+ -0.220949	  -0.518422	      21 	Inter	0.062	 0.08	 0.91	  0.9	 48	 159	long road
+ -0.220455	  -0.518238	      22 	Inter	0.058	 0.07	 0.97	  1.0	 48	  20	long road
+ -0.220746	  -0.518070	      23 	Inter	0.037	 0.04	 1.01	  1.0	 48	 149	long road
+ -0.220739	  -0.517801	      26*	Junct	0.029	 0.04	 1.04	  1.0	 48	  88	long road
+ -0.220784	  -0.516035	      31*	Junct	0.196	 0.18	 1.23	  1.2	 64	  91	high street
+ -0.219593	  -0.515985	      -3 	Waypt	0.132	 0.08	 1.36	  1.3	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/node-restrictions-WP08.txt b/3rdparty/Routino/src/test/expected/node-restrictions-WP08.txt
new file mode 100644
index 0000000..d9df640
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/node-restrictions-WP08.txt
@@ -0,0 +1,22 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219564	  -0.520846	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220666	  -0.520893	       4*	Junct	0.122	 0.07	 0.12	  0.1	 96	 182	main 1
+ -0.220682	  -0.520141	       9*	Junct	0.083	 0.08	 0.20	  0.2	 64	  91	high street
+ -0.219009	  -0.520075	      10*	Waypt	0.186	 0.17	 0.39	  0.3	 64	   2	dead end road
+ -0.220682	  -0.520141	       9*	Junct	0.186	 0.17	 0.58	  0.5	 64	 182	dead end road
+ -0.220695	  -0.519489	      12*	Change	0.072	 0.07	 0.65	  0.6	 64	  91	high street
+ -0.220694	  -0.519227	      15 	Inter	0.029	 0.04	 0.68	  0.6	 48	  89	long road
+ -0.220386	  -0.519076	      16 	Inter	0.038	 0.05	 0.72	  0.6	 48	  26	long road
+ -0.220961	  -0.518928	      17 	Inter	0.066	 0.08	 0.78	  0.7	 48	 165	long road
+ -0.220427	  -0.518622	      18 	Inter	0.068	 0.09	 0.85	  0.8	 48	  29	long road
+ -0.220949	  -0.518422	      21 	Inter	0.062	 0.08	 0.91	  0.9	 48	 159	long road
+ -0.220455	  -0.518238	      22 	Inter	0.058	 0.07	 0.97	  1.0	 48	  20	long road
+ -0.220746	  -0.518070	      23 	Inter	0.037	 0.04	 1.01	  1.0	 48	 149	long road
+ -0.220739	  -0.517801	      26*	Junct	0.029	 0.04	 1.04	  1.0	 48	  88	long road
+ -0.220784	  -0.516035	      31*	Junct	0.196	 0.18	 1.23	  1.2	 64	  91	high street
+ -0.219593	  -0.515985	      -3 	Waypt	0.132	 0.08	 1.36	  1.3	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/oneway-loop-WP01.txt b/3rdparty/Routino/src/test/expected/oneway-loop-WP01.txt
new file mode 100644
index 0000000..bbe397a
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/oneway-loop-WP01.txt
@@ -0,0 +1,17 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.219564	  -0.520846	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.220666	  -0.520893	       4*	Junct	0.122	 0.07	 0.12	  0.1	 96	 182	main 1
+ -0.220695	  -0.519489	       9*	Inter	0.156	 0.20	 0.28	  0.3	 48	  91	high street
+ -0.220739	  -0.517801	      12*	Junct	0.187	 0.23	 0.47	  0.5	 48	  91	high street
+ -0.220405	  -0.517799	      13 	Inter	0.037	 0.04	 0.50	  0.5	 48	   0	reverse loop
+ -0.220210	  -0.518605	      11 	Waypt	0.092	 0.12	 0.59	  0.7	 48	 283	reverse loop
+ -0.220333	  -0.519485	      10 	Inter	0.098	 0.12	 0.69	  0.8	 48	 262	reverse loop
+ -0.220695	  -0.519489	       9*	Inter	0.040	 0.05	 0.73	  0.8	 48	 180	reverse loop
+ -0.220739	  -0.517801	      12*	Junct	0.187	 0.23	 0.92	  1.1	 48	  91	high street
+ -0.220784	  -0.516035	      18*	Junct	0.196	 0.24	 1.11	  1.3	 48	  91	high street
+ -0.219593	  -0.515985	      -3 	Waypt	0.132	 0.08	 1.25	  1.4	 96	   2	main 2
diff --git a/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP01.txt b/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP01.txt
new file mode 100644
index 0000000..304b108
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP01.txt
@@ -0,0 +1,12 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218454	  -0.520798	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219482	  -0.520837	       9*	Waypt	0.113	 0.07	 0.11	  0.1	 96	 182	main 1
+ -0.219692	  -0.520509	      15 	Junct-	0.043	 0.03	 0.16	  0.1	 96	 122	roundabout
+ -0.220082	  -0.520522	      14 	Junct-	0.043	 0.03	 0.20	  0.1	 96	 181	roundabout
+ -0.220268	  -0.520863	       8*	Junct	0.043	 0.03	 0.24	  0.1	 96	 241	roundabout
+ -0.221566	  -0.520921	      -3 	Waypt	0.143	 0.09	 0.39	  0.2	 96	 182	main 2
diff --git a/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP02.txt b/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP02.txt
new file mode 100644
index 0000000..5ce9cbf
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP02.txt
@@ -0,0 +1,13 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218454	  -0.520798	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219482	  -0.520837	       9*	Junct	0.113	 0.07	 0.11	  0.1	 96	 182	main 1
+ -0.219577	  -0.520689	      -2 	Waypt	0.019	 0.01	 0.13	  0.1	 96	 122	roundabout
+ -0.219692	  -0.520509	      15 	Junct-	0.023	 0.01	 0.15	  0.1	 96	 122	roundabout
+ -0.220082	  -0.520522	      14 	Junct-	0.043	 0.03	 0.20	  0.1	 96	 181	roundabout
+ -0.220268	  -0.520863	       8*	Junct	0.043	 0.03	 0.24	  0.1	 96	 241	roundabout
+ -0.221566	  -0.520921	      -3 	Waypt	0.143	 0.09	 0.38	  0.2	 96	 182	main 2
diff --git a/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP03.txt b/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP03.txt
new file mode 100644
index 0000000..a5a6398
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP03.txt
@@ -0,0 +1,12 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218454	  -0.520798	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219482	  -0.520837	       9*	Junct	0.113	 0.07	 0.11	  0.1	 96	 182	main 1
+ -0.219692	  -0.520509	      15 	Waypt	0.043	 0.03	 0.16	  0.1	 96	 122	roundabout
+ -0.220082	  -0.520522	      14 	Junct-	0.043	 0.03	 0.20	  0.1	 96	 181	roundabout
+ -0.220268	  -0.520863	       8*	Junct	0.043	 0.03	 0.24	  0.1	 96	 241	roundabout
+ -0.221566	  -0.520921	      -3 	Waypt	0.143	 0.09	 0.39	  0.2	 96	 182	main 2
diff --git a/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP04.txt b/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP04.txt
new file mode 100644
index 0000000..dc04878
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP04.txt
@@ -0,0 +1,13 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218454	  -0.520798	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219482	  -0.520837	       9*	Junct	0.113	 0.07	 0.11	  0.1	 96	 182	main 1
+ -0.219692	  -0.520509	      15 	Junct-	0.043	 0.03	 0.16	  0.1	 96	 122	roundabout
+ -0.219878	  -0.520515	      -2 	Waypt	0.020	 0.01	 0.18	  0.1	 96	 181	roundabout
+ -0.220082	  -0.520522	      14 	Junct-	0.022	 0.01	 0.20	  0.1	 96	 181	roundabout
+ -0.220268	  -0.520863	       8*	Junct	0.043	 0.03	 0.24	  0.1	 96	 241	roundabout
+ -0.221566	  -0.520921	      -3 	Waypt	0.143	 0.09	 0.38	  0.2	 96	 182	main 2
diff --git a/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP05.txt b/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP05.txt
new file mode 100644
index 0000000..d8e2149
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP05.txt
@@ -0,0 +1,12 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218454	  -0.520798	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219482	  -0.520837	       9*	Junct	0.113	 0.07	 0.11	  0.1	 96	 182	main 1
+ -0.219692	  -0.520509	      15 	Junct-	0.043	 0.03	 0.16	  0.1	 96	 122	roundabout
+ -0.220082	  -0.520522	      14 	Waypt	0.043	 0.03	 0.20	  0.1	 96	 181	roundabout
+ -0.220268	  -0.520863	       8*	Junct	0.043	 0.03	 0.24	  0.1	 96	 241	roundabout
+ -0.221566	  -0.520921	      -3 	Waypt	0.143	 0.09	 0.39	  0.2	 96	 182	main 2
diff --git a/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP06.txt b/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP06.txt
new file mode 100644
index 0000000..097a52a
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP06.txt
@@ -0,0 +1,13 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218454	  -0.520798	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219482	  -0.520837	       9*	Junct	0.113	 0.07	 0.11	  0.1	 96	 182	main 1
+ -0.219692	  -0.520509	      15 	Junct-	0.043	 0.03	 0.16	  0.1	 96	 122	roundabout
+ -0.220082	  -0.520522	      14 	Junct-	0.043	 0.03	 0.20	  0.1	 96	 181	roundabout
+ -0.220171	  -0.520685	      -2 	Waypt	0.020	 0.01	 0.22	  0.1	 96	 241	roundabout
+ -0.220268	  -0.520863	       8*	Junct	0.022	 0.01	 0.24	  0.1	 96	 241	roundabout
+ -0.221566	  -0.520921	      -3 	Waypt	0.143	 0.09	 0.38	  0.2	 96	 182	main 2
diff --git a/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP07.txt b/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP07.txt
new file mode 100644
index 0000000..5dd7a74
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/roundabout-waypoints-WP07.txt
@@ -0,0 +1,12 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218454	  -0.520798	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219482	  -0.520837	       9*	Junct	0.113	 0.07	 0.11	  0.1	 96	 182	main 1
+ -0.219692	  -0.520509	      15 	Junct-	0.043	 0.03	 0.16	  0.1	 96	 122	roundabout
+ -0.220082	  -0.520522	      14 	Junct-	0.043	 0.03	 0.20	  0.1	 96	 181	roundabout
+ -0.220268	  -0.520863	       8*	Waypt	0.043	 0.03	 0.24	  0.1	 96	 241	roundabout
+ -0.221566	  -0.520921	      -3 	Waypt	0.143	 0.09	 0.39	  0.2	 96	 182	main 2
diff --git a/3rdparty/Routino/src/test/expected/super-or-not-WP01.txt b/3rdparty/Routino/src/test/expected/super-or-not-WP01.txt
new file mode 100644
index 0000000..d76ce16
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/super-or-not-WP01.txt
@@ -0,0 +1,13 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.216158	  -0.518809	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.216435	  -0.518515	       4 	Inter	0.044	 0.06	 0.04	  0.1	 48	 133	Local road
+ -0.215866	  -0.517931	       5 	Inter	0.090	 0.11	 0.13	  0.2	 48	  45	Local road
+ -0.216470	  -0.517412	       6 	Inter	0.088	 0.11	 0.22	  0.3	 48	 139	Local road
+ -0.215930	  -0.516823	       7 	Inter	0.088	 0.11	 0.31	  0.4	 48	  47	Local road
+ -0.216451	  -0.516221	       8 	Inter	0.088	 0.11	 0.40	  0.5	 48	 130	Local road
+ -0.216158	  -0.515870	      -2 	Waypt	0.050	 0.06	 0.45	  0.6	 48	  50	Local road
diff --git a/3rdparty/Routino/src/test/expected/super-or-not-WP02.txt b/3rdparty/Routino/src/test/expected/super-or-not-WP02.txt
new file mode 100644
index 0000000..dc35d71
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/super-or-not-WP02.txt
@@ -0,0 +1,10 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.216828	  -0.519457	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.217245	  -0.519637	       2*	Junct	0.050	 0.06	 0.05	  0.1	 48	 203	Local road
+ -0.217248	  -0.515206	      10*	Junct	0.493	 0.31	 0.54	  0.4	 96	  90	Main road
+ -0.216919	  -0.515308	      -2 	Waypt	0.038	 0.05	 0.58	  0.4	 48	 342	Local road
diff --git a/3rdparty/Routino/src/test/expected/super-or-not-WP03.txt b/3rdparty/Routino/src/test/expected/super-or-not-WP03.txt
new file mode 100644
index 0000000..4e51634
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/super-or-not-WP03.txt
@@ -0,0 +1,10 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.217245	  -0.519637	       2*	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.215919	  -0.519064	       3 	Inter	0.160	 0.20	 0.16	  0.2	 48	  23	Local road
+ -0.216435	  -0.518515	       4 	Inter	0.083	 0.10	 0.24	  0.3	 48	 133	Local road
+ -0.215866	  -0.517931	       5 	Waypt	0.090	 0.11	 0.33	  0.4	 48	  45	Local road
diff --git a/3rdparty/Routino/src/test/expected/turns-WP01.txt b/3rdparty/Routino/src/test/expected/turns-WP01.txt
new file mode 100644
index 0000000..e88758c
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/turns-WP01.txt
@@ -0,0 +1,19 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218453	  -0.520799	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219107	  -0.520828	       6*	Junct-	0.072	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       5*	Junct	0.173	 0.11	 0.24	  0.2	 96	 182	main 1
+ -0.220671	  -0.520223	      11*	Junct	0.074	 0.09	 0.32	  0.2	 48	  90	high street
+ -0.220691	  -0.519461	      19*	Junct	0.084	 0.10	 0.40	  0.3	 48	  91	high street
+ -0.220111	  -0.519553	      17 	Inter	0.065	 0.08	 0.47	  0.4	 48	 351	loop 1
+ -0.219817	  -0.519807	      15 	Inter	0.043	 0.05	 0.51	  0.5	 48	 319	loop 1
+ -0.220067	  -0.520109	      13*	Inter	0.043	 0.05	 0.55	  0.5	 48	 230	loop 1
+ -0.220191	  -0.520132	      -2 	Waypt	0.014	 0.02	 0.57	  0.6	 48	 190	loop 1
+ -0.220671	  -0.520223	      11*	Junct	0.054	 0.07	 0.62	  0.6	 48	 190	loop 1
+ -0.220666	  -0.520893	       5*	Junct	0.074	 0.09	 0.70	  0.7	 48	 270	high street
+ -0.221308	  -0.520914	       4*	Junct-	0.071	 0.04	 0.77	  0.8	 96	 181	main 1
+ -0.221561	  -0.520922	      -3 	Waypt	0.027	 0.02	 0.79	  0.8	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/turns-WP02.txt b/3rdparty/Routino/src/test/expected/turns-WP02.txt
new file mode 100644
index 0000000..7a3934d
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/turns-WP02.txt
@@ -0,0 +1,18 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218453	  -0.520799	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219107	  -0.520828	       6*	Junct-	0.072	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       5*	Junct	0.173	 0.11	 0.24	  0.2	 96	 182	main 1
+ -0.220671	  -0.520223	      11*	Junct	0.074	 0.09	 0.32	  0.2	 48	  90	high street
+ -0.220691	  -0.519461	      19*	Junct	0.084	 0.10	 0.40	  0.3	 48	  91	high street
+ -0.220111	  -0.519553	      17 	Inter	0.065	 0.08	 0.47	  0.4	 48	 351	loop 1
+ -0.219817	  -0.519807	      15 	Inter	0.043	 0.05	 0.51	  0.5	 48	 319	loop 1
+ -0.220067	  -0.520109	      13*	Waypt	0.043	 0.05	 0.55	  0.5	 48	 230	loop 1
+ -0.220671	  -0.520223	      11*	Junct	0.068	 0.09	 0.62	  0.6	 48	 190	loop 1
+ -0.220666	  -0.520893	       5*	Junct	0.074	 0.09	 0.70	  0.7	 48	 270	high street
+ -0.221308	  -0.520914	       4*	Junct-	0.071	 0.04	 0.77	  0.8	 96	 181	main 1
+ -0.221561	  -0.520922	      -3 	Waypt	0.027	 0.02	 0.79	  0.8	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/turns-WP03.txt b/3rdparty/Routino/src/test/expected/turns-WP03.txt
new file mode 100644
index 0000000..bb60cf0
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/turns-WP03.txt
@@ -0,0 +1,18 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218453	  -0.520799	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219107	  -0.520828	       6*	Junct-	0.072	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       5*	Junct	0.173	 0.11	 0.24	  0.2	 96	 182	main 1
+ -0.220671	  -0.520223	      11*	Junct	0.074	 0.09	 0.32	  0.2	 48	  90	high street
+ -0.220691	  -0.519461	      19*	Junct	0.084	 0.10	 0.40	  0.3	 48	  91	high street
+ -0.220111	  -0.519553	      17 	Inter	0.065	 0.08	 0.47	  0.4	 48	 351	loop 1
+ -0.219817	  -0.519807	      15 	Waypt	0.043	 0.05	 0.51	  0.5	 48	 319	loop 1
+ -0.220067	  -0.520109	      13*	Inter	0.043	 0.05	 0.55	  0.5	 48	 230	loop 1
+ -0.220671	  -0.520223	      11*	Junct	0.068	 0.09	 0.62	  0.6	 48	 190	loop 1
+ -0.220666	  -0.520893	       5*	Junct	0.074	 0.09	 0.70	  0.7	 48	 270	high street
+ -0.221308	  -0.520914	       4*	Junct-	0.071	 0.04	 0.77	  0.8	 96	 181	main 1
+ -0.221561	  -0.520922	      -3 	Waypt	0.027	 0.02	 0.79	  0.8	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/turns-WP04.txt b/3rdparty/Routino/src/test/expected/turns-WP04.txt
new file mode 100644
index 0000000..13cc313
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/turns-WP04.txt
@@ -0,0 +1,27 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218453	  -0.520799	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219107	  -0.520828	       6*	Junct-	0.072	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       5*	Junct	0.173	 0.11	 0.24	  0.2	 96	 182	main 1
+ -0.220671	  -0.520223	      11*	Junct	0.074	 0.09	 0.32	  0.2	 48	  90	high street
+ -0.220691	  -0.519461	      19*	Junct	0.084	 0.10	 0.40	  0.3	 48	  91	high street
+ -0.220708	  -0.518842	      22*	Junct	0.069	 0.09	 0.47	  0.4	 48	  91	high street
+ -0.220724	  -0.518071	      31*	Junct	0.085	 0.10	 0.56	  0.5	 48	  91	high street
+ -0.220143	  -0.518162	      30 	Inter	0.065	 0.08	 0.62	  0.6	 48	 351	loop 2
+ -0.219850	  -0.518416	      27 	Inter	0.043	 0.05	 0.67	  0.7	 48	 319	loop 2
+ -0.220100	  -0.518718	      24*	Inter	0.043	 0.05	 0.71	  0.7	 48	 230	loop 2
+ -0.220206	  -0.518739	      -2 	Waypt	0.012	 0.01	 0.72	  0.7	 48	 191	loop 2
+ -0.220708	  -0.518842	      22*	Junct	0.057	 0.07	 0.78	  0.8	 48	 191	loop 2
+ -0.220724	  -0.518071	      31*	Junct	0.085	 0.10	 0.86	  0.9	 48	  91	high street
+ -0.220739	  -0.517425	      34*	Junct	0.071	 0.09	 0.93	  1.0	 48	  91	high street
+ -0.220760	  -0.516647	      48*	Junct	0.086	 0.11	 1.02	  1.1	 48	  91	high street
+ -0.220784	  -0.516035	      54*	Junct	0.068	 0.09	 1.09	  1.2	 48	  92	high street
+ -0.221431	  -0.516056	      53*	Junct	0.072	 0.04	 1.16	  1.2	 96	 181	main 2
+ -0.221376	  -0.518235	      29*	Junct	0.242	 0.30	 1.40	  1.5	 48	 271	bottom road
+ -0.221360	  -0.518860	      21*	Junct	0.069	 0.09	 1.47	  1.6	 48	 271	bottom road
+ -0.221308	  -0.520914	       4*	Junct	0.228	 0.28	 1.70	  1.9	 48	 271	bottom road
+ -0.221561	  -0.520922	      -3 	Waypt	0.027	 0.02	 1.73	  1.9	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/turns-WP05.txt b/3rdparty/Routino/src/test/expected/turns-WP05.txt
new file mode 100644
index 0000000..1d7f66b
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/turns-WP05.txt
@@ -0,0 +1,26 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218453	  -0.520799	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219107	  -0.520828	       6*	Junct-	0.072	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       5*	Junct	0.173	 0.11	 0.24	  0.2	 96	 182	main 1
+ -0.220671	  -0.520223	      11*	Junct	0.074	 0.09	 0.32	  0.2	 48	  90	high street
+ -0.220691	  -0.519461	      19*	Junct	0.084	 0.10	 0.40	  0.3	 48	  91	high street
+ -0.220708	  -0.518842	      22*	Junct	0.069	 0.09	 0.47	  0.4	 48	  91	high street
+ -0.220724	  -0.518071	      31*	Junct	0.085	 0.10	 0.56	  0.5	 48	  91	high street
+ -0.220143	  -0.518162	      30 	Inter	0.065	 0.08	 0.62	  0.6	 48	 351	loop 2
+ -0.219850	  -0.518416	      27 	Inter	0.043	 0.05	 0.67	  0.7	 48	 319	loop 2
+ -0.220100	  -0.518718	      24*	Waypt	0.043	 0.05	 0.71	  0.7	 48	 230	loop 2
+ -0.220708	  -0.518842	      22*	Junct	0.069	 0.09	 0.78	  0.8	 48	 191	loop 2
+ -0.220724	  -0.518071	      31*	Junct	0.085	 0.10	 0.86	  0.9	 48	  91	high street
+ -0.220739	  -0.517425	      34*	Junct	0.071	 0.09	 0.93	  1.0	 48	  91	high street
+ -0.220760	  -0.516647	      48*	Junct	0.086	 0.11	 1.02	  1.1	 48	  91	high street
+ -0.220784	  -0.516035	      54*	Junct	0.068	 0.09	 1.09	  1.2	 48	  92	high street
+ -0.221431	  -0.516056	      53*	Junct	0.072	 0.04	 1.16	  1.2	 96	 181	main 2
+ -0.221376	  -0.518235	      29*	Junct	0.242	 0.30	 1.40	  1.5	 48	 271	bottom road
+ -0.221360	  -0.518860	      21*	Junct	0.069	 0.09	 1.47	  1.6	 48	 271	bottom road
+ -0.221308	  -0.520914	       4*	Junct	0.228	 0.28	 1.70	  1.9	 48	 271	bottom road
+ -0.221561	  -0.520922	      -3 	Waypt	0.027	 0.02	 1.73	  1.9	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/turns-WP06.txt b/3rdparty/Routino/src/test/expected/turns-WP06.txt
new file mode 100644
index 0000000..e89e68f
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/turns-WP06.txt
@@ -0,0 +1,26 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218453	  -0.520799	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219107	  -0.520828	       6*	Junct-	0.072	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       5*	Junct	0.173	 0.11	 0.24	  0.2	 96	 182	main 1
+ -0.220671	  -0.520223	      11*	Junct	0.074	 0.09	 0.32	  0.2	 48	  90	high street
+ -0.220691	  -0.519461	      19*	Junct	0.084	 0.10	 0.40	  0.3	 48	  91	high street
+ -0.220708	  -0.518842	      22*	Junct	0.069	 0.09	 0.47	  0.4	 48	  91	high street
+ -0.220724	  -0.518071	      31*	Junct	0.085	 0.10	 0.56	  0.5	 48	  91	high street
+ -0.220143	  -0.518162	      30 	Inter	0.065	 0.08	 0.62	  0.6	 48	 351	loop 2
+ -0.219850	  -0.518416	      27 	Waypt	0.043	 0.05	 0.67	  0.7	 48	 319	loop 2
+ -0.220100	  -0.518718	      24*	Inter	0.043	 0.05	 0.71	  0.7	 48	 230	loop 2
+ -0.220708	  -0.518842	      22*	Junct	0.069	 0.09	 0.78	  0.8	 48	 191	loop 2
+ -0.220724	  -0.518071	      31*	Junct	0.085	 0.10	 0.86	  0.9	 48	  91	high street
+ -0.220739	  -0.517425	      34*	Junct	0.071	 0.09	 0.93	  1.0	 48	  91	high street
+ -0.220760	  -0.516647	      48*	Junct	0.086	 0.11	 1.02	  1.1	 48	  91	high street
+ -0.220784	  -0.516035	      54*	Junct	0.068	 0.09	 1.09	  1.2	 48	  92	high street
+ -0.221431	  -0.516056	      53*	Junct	0.072	 0.04	 1.16	  1.2	 96	 181	main 2
+ -0.221376	  -0.518235	      29*	Junct	0.242	 0.30	 1.40	  1.5	 48	 271	bottom road
+ -0.221360	  -0.518860	      21*	Junct	0.069	 0.09	 1.47	  1.6	 48	 271	bottom road
+ -0.221308	  -0.520914	       4*	Junct	0.228	 0.28	 1.70	  1.9	 48	 271	bottom road
+ -0.221561	  -0.520922	      -3 	Waypt	0.027	 0.02	 1.73	  1.9	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/turns-WP07.txt b/3rdparty/Routino/src/test/expected/turns-WP07.txt
new file mode 100644
index 0000000..fae0c9b
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/turns-WP07.txt
@@ -0,0 +1,34 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218453	  -0.520799	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219107	  -0.520828	       6*	Junct	0.072	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.219123	  -0.520207	      12*	Junct	0.069	 0.09	 0.14	  0.1	 48	  91	top road
+ -0.219131	  -0.519426	      20*	Junct	0.086	 0.11	 0.23	  0.2	 48	  90	top road
+ -0.219135	  -0.518823	      23*	Junct	0.067	 0.08	 0.29	  0.3	 48	  90	top road
+ -0.219145	  -0.517626	      33*	Junct	0.133	 0.17	 0.43	  0.5	 48	  90	top road
+ -0.219144	  -0.517257	      36*	Junct	0.041	 0.05	 0.47	  0.5	 48	  89	top road
+ -0.219291	  -0.517193	      38 	Inter	0.017	 0.02	 0.48	  0.6	 48	 156	roundabout
+ -0.219352	  -0.517060	      42 	Junct-	0.016	 0.02	 0.50	  0.6	 48	 114	roundabout
+ -0.219304	  -0.516904	      45 	Inter	0.018	 0.02	 0.52	  0.6	 48	  72	roundabout
+ -0.219153	  -0.516826	      46*	Junct	0.018	 0.02	 0.54	  0.6	 48	  27	roundabout
+ -0.219184	  -0.515968	      55*	Junct	0.095	 0.12	 0.63	  0.7	 48	  92	top road
+ -0.220784	  -0.516035	      54*	Junct	0.178	 0.11	 0.81	  0.8	 96	 182	main 2
+ -0.220760	  -0.516647	      48*	Junct	0.068	 0.09	 0.88	  0.9	 48	 272	high street
+ -0.220739	  -0.517425	      34*	Junct	0.086	 0.11	 0.96	  1.0	 48	 271	high street
+ -0.220238	  -0.517313	      -2 	Waypt	0.057	 0.07	 1.02	  1.1	 48	  12	loop 3
+ -0.220089	  -0.517279	      35*	Inter	0.017	 0.02	 1.04	  1.1	 48	  12	loop 3
+ -0.219872	  -0.517009	      43 	Inter	0.038	 0.05	 1.08	  1.2	 48	  51	loop 3
+ -0.220097	  -0.516762	      47*	Inter	0.037	 0.04	 1.11	  1.2	 48	 132	loop 3
+ -0.220760	  -0.516647	      48*	Junct	0.074	 0.09	 1.19	  1.3	 48	 170	loop 3
+ -0.220739	  -0.517425	      34*	Junct	0.086	 0.11	 1.27	  1.4	 48	 271	high street
+ -0.220724	  -0.518071	      31*	Junct	0.071	 0.09	 1.34	  1.5	 48	 271	high street
+ -0.220708	  -0.518842	      22*	Junct	0.085	 0.10	 1.43	  1.6	 48	 271	high street
+ -0.220691	  -0.519461	      19*	Junct	0.069	 0.09	 1.50	  1.7	 48	 271	high street
+ -0.220671	  -0.520223	      11*	Junct	0.084	 0.10	 1.58	  1.8	 48	 271	high street
+ -0.220666	  -0.520893	       5*	Junct	0.074	 0.09	 1.66	  1.9	 48	 270	high street
+ -0.221308	  -0.520914	       4*	Junct-	0.071	 0.04	 1.73	  1.9	 96	 181	main 1
+ -0.221561	  -0.520922	      -3 	Waypt	0.027	 0.02	 1.75	  2.0	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/turns-WP08.txt b/3rdparty/Routino/src/test/expected/turns-WP08.txt
new file mode 100644
index 0000000..5b53349
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/turns-WP08.txt
@@ -0,0 +1,31 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218453	  -0.520799	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219107	  -0.520828	       6*	Junct	0.072	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.219123	  -0.520207	      12*	Junct	0.069	 0.09	 0.14	  0.1	 48	  91	top road
+ -0.219131	  -0.519426	      20*	Junct	0.086	 0.11	 0.23	  0.2	 48	  90	top road
+ -0.219135	  -0.518823	      23*	Junct	0.067	 0.08	 0.29	  0.3	 48	  90	top road
+ -0.219145	  -0.517626	      33*	Junct	0.133	 0.17	 0.43	  0.5	 48	  90	top road
+ -0.219144	  -0.517257	      36*	Junct	0.041	 0.05	 0.47	  0.5	 48	  89	top road
+ -0.219291	  -0.517193	      38 	Inter	0.017	 0.02	 0.48	  0.6	 48	 156	roundabout
+ -0.219352	  -0.517060	      42 	Junct-	0.016	 0.02	 0.50	  0.6	 48	 114	roundabout
+ -0.219304	  -0.516904	      45 	Inter	0.018	 0.02	 0.52	  0.6	 48	  72	roundabout
+ -0.219153	  -0.516826	      46*	Junct	0.018	 0.02	 0.54	  0.6	 48	  27	roundabout
+ -0.219184	  -0.515968	      55*	Junct	0.095	 0.12	 0.63	  0.7	 48	  92	top road
+ -0.220784	  -0.516035	      54*	Junct	0.178	 0.11	 0.81	  0.8	 96	 182	main 2
+ -0.220760	  -0.516647	      48*	Junct	0.068	 0.09	 0.88	  0.9	 48	 272	high street
+ -0.220097	  -0.516762	      47*	Inter	0.074	 0.09	 0.95	  1.0	 48	 350	loop 3
+ -0.219872	  -0.517009	      43 	Inter	0.037	 0.04	 0.99	  1.1	 48	 312	loop 3
+ -0.220089	  -0.517279	      35*	Waypt	0.038	 0.05	 1.03	  1.1	 48	 231	loop 3
+ -0.220739	  -0.517425	      34*	Junct	0.074	 0.09	 1.10	  1.2	 48	 192	loop 3
+ -0.220724	  -0.518071	      31*	Junct	0.071	 0.09	 1.17	  1.3	 48	 271	high street
+ -0.220708	  -0.518842	      22*	Junct	0.085	 0.10	 1.26	  1.4	 48	 271	high street
+ -0.220691	  -0.519461	      19*	Junct	0.069	 0.09	 1.33	  1.5	 48	 271	high street
+ -0.220671	  -0.520223	      11*	Junct	0.084	 0.10	 1.41	  1.6	 48	 271	high street
+ -0.220666	  -0.520893	       5*	Junct	0.074	 0.09	 1.48	  1.7	 48	 270	high street
+ -0.221308	  -0.520914	       4*	Junct-	0.071	 0.04	 1.55	  1.7	 96	 181	main 1
+ -0.221561	  -0.520922	      -3 	Waypt	0.027	 0.02	 1.58	  1.7	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/turns-WP09.txt b/3rdparty/Routino/src/test/expected/turns-WP09.txt
new file mode 100644
index 0000000..684a7ba
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/turns-WP09.txt
@@ -0,0 +1,31 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218453	  -0.520799	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219107	  -0.520828	       6*	Junct	0.072	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.219123	  -0.520207	      12*	Junct	0.069	 0.09	 0.14	  0.1	 48	  91	top road
+ -0.219131	  -0.519426	      20*	Junct	0.086	 0.11	 0.23	  0.2	 48	  90	top road
+ -0.219135	  -0.518823	      23*	Junct	0.067	 0.08	 0.29	  0.3	 48	  90	top road
+ -0.219145	  -0.517626	      33*	Junct	0.133	 0.17	 0.43	  0.5	 48	  90	top road
+ -0.219144	  -0.517257	      36*	Junct	0.041	 0.05	 0.47	  0.5	 48	  89	top road
+ -0.219291	  -0.517193	      38 	Inter	0.017	 0.02	 0.48	  0.6	 48	 156	roundabout
+ -0.219352	  -0.517060	      42 	Junct-	0.016	 0.02	 0.50	  0.6	 48	 114	roundabout
+ -0.219304	  -0.516904	      45 	Inter	0.018	 0.02	 0.52	  0.6	 48	  72	roundabout
+ -0.219153	  -0.516826	      46*	Junct	0.018	 0.02	 0.54	  0.6	 48	  27	roundabout
+ -0.219184	  -0.515968	      55*	Junct	0.095	 0.12	 0.63	  0.7	 48	  92	top road
+ -0.220784	  -0.516035	      54*	Junct	0.178	 0.11	 0.81	  0.8	 96	 182	main 2
+ -0.220760	  -0.516647	      48*	Junct	0.068	 0.09	 0.88	  0.9	 48	 272	high street
+ -0.220097	  -0.516762	      47*	Inter	0.074	 0.09	 0.95	  1.0	 48	 350	loop 3
+ -0.219872	  -0.517009	      43 	Waypt	0.037	 0.04	 0.99	  1.1	 48	 312	loop 3
+ -0.220089	  -0.517279	      35*	Inter	0.038	 0.05	 1.03	  1.1	 48	 231	loop 3
+ -0.220739	  -0.517425	      34*	Junct	0.074	 0.09	 1.10	  1.2	 48	 192	loop 3
+ -0.220724	  -0.518071	      31*	Junct	0.071	 0.09	 1.17	  1.3	 48	 271	high street
+ -0.220708	  -0.518842	      22*	Junct	0.085	 0.10	 1.26	  1.4	 48	 271	high street
+ -0.220691	  -0.519461	      19*	Junct	0.069	 0.09	 1.33	  1.5	 48	 271	high street
+ -0.220671	  -0.520223	      11*	Junct	0.084	 0.10	 1.41	  1.6	 48	 271	high street
+ -0.220666	  -0.520893	       5*	Junct	0.074	 0.09	 1.48	  1.7	 48	 270	high street
+ -0.221308	  -0.520914	       4*	Junct-	0.071	 0.04	 1.55	  1.7	 96	 181	main 1
+ -0.221561	  -0.520922	      -3 	Waypt	0.027	 0.02	 1.58	  1.7	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/turns-WP10.txt b/3rdparty/Routino/src/test/expected/turns-WP10.txt
new file mode 100644
index 0000000..dfa0ca1
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/turns-WP10.txt
@@ -0,0 +1,35 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218453	  -0.520799	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219107	  -0.520828	       6*	Junct	0.072	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.219123	  -0.520207	      12*	Junct	0.069	 0.09	 0.14	  0.1	 48	  91	top road
+ -0.219131	  -0.519426	      20*	Junct	0.086	 0.11	 0.23	  0.2	 48	  90	top road
+ -0.219135	  -0.518823	      23*	Junct	0.067	 0.08	 0.29	  0.3	 48	  90	top road
+ -0.219145	  -0.517626	      33*	Junct	0.133	 0.17	 0.43	  0.5	 48	  90	top road
+ -0.219144	  -0.517257	      36*	Junct	0.041	 0.05	 0.47	  0.5	 48	  89	top road
+ -0.219291	  -0.517193	      38 	Inter	0.017	 0.02	 0.48	  0.6	 48	 156	roundabout
+ -0.219352	  -0.517060	      42 	Junct-	0.016	 0.02	 0.50	  0.6	 48	 114	roundabout
+ -0.219304	  -0.516904	      45 	Inter	0.018	 0.02	 0.52	  0.6	 48	  72	roundabout
+ -0.219153	  -0.516826	      46*	Junct-	0.018	 0.02	 0.54	  0.6	 48	  27	roundabout
+ -0.218966	  -0.516910	      44 	Inter	0.022	 0.03	 0.56	  0.6	 48	 335	roundabout
+ -0.218923	  -0.517072	      39 	Junct-	0.018	 0.02	 0.58	  0.7	 48	 284	roundabout
+ -0.218998	  -0.517207	      37 	Inter	0.017	 0.02	 0.59	  0.7	 48	 240	roundabout
+ -0.219144	  -0.517257	      36*	Junct	0.017	 0.02	 0.61	  0.7	 48	 199	roundabout
+ -0.219145	  -0.517626	      33*	Junct	0.041	 0.05	 0.65	  0.8	 48	 269	top road
+ -0.219135	  -0.518823	      23*	Junct	0.133	 0.17	 0.79	  0.9	 48	 270	top road
+ -0.219131	  -0.519426	      20*	Junct	0.067	 0.08	 0.85	  1.0	 48	 270	top road
+ -0.219123	  -0.520207	      12*	Junct	0.086	 0.11	 0.94	  1.1	 48	 270	top road
+ -0.218605	  -0.520090	      -2 	Waypt	0.059	 0.07	 1.00	  1.2	 48	  12	loop 4
+ -0.218474	  -0.520060	      14*	Inter	0.015	 0.02	 1.01	  1.2	 48	  12	loop 4
+ -0.218258	  -0.519789	      16 	Inter	0.038	 0.05	 1.05	  1.2	 48	  51	loop 4
+ -0.218482	  -0.519542	      18*	Inter	0.037	 0.04	 1.09	  1.3	 48	 132	loop 4
+ -0.219131	  -0.519426	      20*	Junct	0.073	 0.09	 1.16	  1.4	 48	 169	loop 4
+ -0.219123	  -0.520207	      12*	Junct	0.086	 0.11	 1.25	  1.5	 48	 270	top road
+ -0.219107	  -0.520828	       6*	Junct	0.069	 0.09	 1.31	  1.6	 48	 271	top road
+ -0.220666	  -0.520893	       5*	Junct-	0.173	 0.11	 1.49	  1.7	 96	 182	main 1
+ -0.221308	  -0.520914	       4*	Junct-	0.071	 0.04	 1.56	  1.7	 96	 181	main 1
+ -0.221561	  -0.520922	      -3 	Waypt	0.027	 0.02	 1.59	  1.7	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/turns-WP11.txt b/3rdparty/Routino/src/test/expected/turns-WP11.txt
new file mode 100644
index 0000000..406afcf
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/turns-WP11.txt
@@ -0,0 +1,32 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218453	  -0.520799	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219107	  -0.520828	       6*	Junct	0.072	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.219123	  -0.520207	      12*	Junct	0.069	 0.09	 0.14	  0.1	 48	  91	top road
+ -0.219131	  -0.519426	      20*	Junct	0.086	 0.11	 0.23	  0.2	 48	  90	top road
+ -0.219135	  -0.518823	      23*	Junct	0.067	 0.08	 0.29	  0.3	 48	  90	top road
+ -0.219145	  -0.517626	      33*	Junct	0.133	 0.17	 0.43	  0.5	 48	  90	top road
+ -0.219144	  -0.517257	      36*	Junct	0.041	 0.05	 0.47	  0.5	 48	  89	top road
+ -0.219291	  -0.517193	      38 	Inter	0.017	 0.02	 0.48	  0.6	 48	 156	roundabout
+ -0.219352	  -0.517060	      42 	Junct-	0.016	 0.02	 0.50	  0.6	 48	 114	roundabout
+ -0.219304	  -0.516904	      45 	Inter	0.018	 0.02	 0.52	  0.6	 48	  72	roundabout
+ -0.219153	  -0.516826	      46*	Junct-	0.018	 0.02	 0.54	  0.6	 48	  27	roundabout
+ -0.218966	  -0.516910	      44 	Inter	0.022	 0.03	 0.56	  0.6	 48	 335	roundabout
+ -0.218923	  -0.517072	      39 	Junct-	0.018	 0.02	 0.58	  0.7	 48	 284	roundabout
+ -0.218998	  -0.517207	      37 	Inter	0.017	 0.02	 0.59	  0.7	 48	 240	roundabout
+ -0.219144	  -0.517257	      36*	Junct	0.017	 0.02	 0.61	  0.7	 48	 199	roundabout
+ -0.219145	  -0.517626	      33*	Junct	0.041	 0.05	 0.65	  0.8	 48	 269	top road
+ -0.219135	  -0.518823	      23*	Junct	0.133	 0.17	 0.79	  0.9	 48	 270	top road
+ -0.219131	  -0.519426	      20*	Junct	0.067	 0.08	 0.85	  1.0	 48	 270	top road
+ -0.218482	  -0.519542	      18*	Inter	0.073	 0.09	 0.93	  1.1	 48	 349	loop 4
+ -0.218258	  -0.519789	      16 	Inter	0.037	 0.04	 0.96	  1.1	 48	 312	loop 4
+ -0.218474	  -0.520060	      14*	Waypt	0.038	 0.05	 1.00	  1.2	 48	 231	loop 4
+ -0.219123	  -0.520207	      12*	Junct	0.074	 0.09	 1.07	  1.3	 48	 192	loop 4
+ -0.219107	  -0.520828	       6*	Junct	0.069	 0.09	 1.14	  1.4	 48	 271	top road
+ -0.220666	  -0.520893	       5*	Junct-	0.173	 0.11	 1.32	  1.5	 96	 182	main 1
+ -0.221308	  -0.520914	       4*	Junct-	0.071	 0.04	 1.39	  1.5	 96	 181	main 1
+ -0.221561	  -0.520922	      -3 	Waypt	0.027	 0.02	 1.41	  1.5	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/turns-WP12.txt b/3rdparty/Routino/src/test/expected/turns-WP12.txt
new file mode 100644
index 0000000..2f660d7
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/turns-WP12.txt
@@ -0,0 +1,32 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218453	  -0.520799	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219107	  -0.520828	       6*	Junct	0.072	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.219123	  -0.520207	      12*	Junct	0.069	 0.09	 0.14	  0.1	 48	  91	top road
+ -0.219131	  -0.519426	      20*	Junct	0.086	 0.11	 0.23	  0.2	 48	  90	top road
+ -0.219135	  -0.518823	      23*	Junct	0.067	 0.08	 0.29	  0.3	 48	  90	top road
+ -0.219145	  -0.517626	      33*	Junct	0.133	 0.17	 0.43	  0.5	 48	  90	top road
+ -0.219144	  -0.517257	      36*	Junct	0.041	 0.05	 0.47	  0.5	 48	  89	top road
+ -0.219291	  -0.517193	      38 	Inter	0.017	 0.02	 0.48	  0.6	 48	 156	roundabout
+ -0.219352	  -0.517060	      42 	Junct-	0.016	 0.02	 0.50	  0.6	 48	 114	roundabout
+ -0.219304	  -0.516904	      45 	Inter	0.018	 0.02	 0.52	  0.6	 48	  72	roundabout
+ -0.219153	  -0.516826	      46*	Junct-	0.018	 0.02	 0.54	  0.6	 48	  27	roundabout
+ -0.218966	  -0.516910	      44 	Inter	0.022	 0.03	 0.56	  0.6	 48	 335	roundabout
+ -0.218923	  -0.517072	      39 	Junct-	0.018	 0.02	 0.58	  0.7	 48	 284	roundabout
+ -0.218998	  -0.517207	      37 	Inter	0.017	 0.02	 0.59	  0.7	 48	 240	roundabout
+ -0.219144	  -0.517257	      36*	Junct	0.017	 0.02	 0.61	  0.7	 48	 199	roundabout
+ -0.219145	  -0.517626	      33*	Junct	0.041	 0.05	 0.65	  0.8	 48	 269	top road
+ -0.219135	  -0.518823	      23*	Junct	0.133	 0.17	 0.79	  0.9	 48	 270	top road
+ -0.219131	  -0.519426	      20*	Junct	0.067	 0.08	 0.85	  1.0	 48	 270	top road
+ -0.218482	  -0.519542	      18*	Inter	0.073	 0.09	 0.93	  1.1	 48	 349	loop 4
+ -0.218258	  -0.519789	      16 	Waypt	0.037	 0.04	 0.96	  1.1	 48	 312	loop 4
+ -0.218474	  -0.520060	      14*	Inter	0.038	 0.05	 1.00	  1.2	 48	 231	loop 4
+ -0.219123	  -0.520207	      12*	Junct	0.074	 0.09	 1.07	  1.3	 48	 192	loop 4
+ -0.219107	  -0.520828	       6*	Junct	0.069	 0.09	 1.14	  1.4	 48	 271	top road
+ -0.220666	  -0.520893	       5*	Junct-	0.173	 0.11	 1.32	  1.5	 96	 182	main 1
+ -0.221308	  -0.520914	       4*	Junct-	0.071	 0.04	 1.39	  1.5	 96	 181	main 1
+ -0.221561	  -0.520922	      -3 	Waypt	0.027	 0.02	 1.41	  1.5	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/turns-WP13.txt b/3rdparty/Routino/src/test/expected/turns-WP13.txt
new file mode 100644
index 0000000..cea2aab
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/turns-WP13.txt
@@ -0,0 +1,45 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218453	  -0.520799	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219107	  -0.520828	       6*	Junct	0.072	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.219123	  -0.520207	      12*	Junct	0.069	 0.09	 0.14	  0.1	 48	  91	top road
+ -0.219131	  -0.519426	      20*	Junct	0.086	 0.11	 0.23	  0.2	 48	  90	top road
+ -0.219135	  -0.518823	      23*	Junct	0.067	 0.08	 0.29	  0.3	 48	  90	top road
+ -0.219145	  -0.517626	      33*	Junct	0.133	 0.17	 0.43	  0.5	 48	  90	top road
+ -0.219144	  -0.517257	      36*	Junct	0.041	 0.05	 0.47	  0.5	 48	  89	top road
+ -0.219291	  -0.517193	      38 	Inter	0.017	 0.02	 0.48	  0.6	 48	 156	roundabout
+ -0.219352	  -0.517060	      42 	Junct-	0.016	 0.02	 0.50	  0.6	 48	 114	roundabout
+ -0.219304	  -0.516904	      45 	Inter	0.018	 0.02	 0.52	  0.6	 48	  72	roundabout
+ -0.219153	  -0.516826	      46*	Junct-	0.018	 0.02	 0.54	  0.6	 48	  27	roundabout
+ -0.218966	  -0.516910	      44 	Inter	0.022	 0.03	 0.56	  0.6	 48	 335	roundabout
+ -0.218923	  -0.517072	      39 	Junct-	0.018	 0.02	 0.58	  0.7	 48	 284	roundabout
+ -0.218998	  -0.517207	      37 	Inter	0.017	 0.02	 0.59	  0.7	 48	 240	roundabout
+ -0.219144	  -0.517257	      36*	Junct	0.017	 0.02	 0.61	  0.7	 48	 199	roundabout
+ -0.219145	  -0.517626	      33*	Junct	0.041	 0.05	 0.65	  0.8	 48	 269	top road
+ -0.218619	  -0.517921	      32*	Inter	0.067	 0.08	 0.72	  0.8	 48	 330	loop 5
+ -0.218431	  -0.518243	      28 	Inter	0.041	 0.05	 0.76	  0.9	 48	 300	loop 5
+ -0.218600	  -0.518557	      25*	Inter	0.039	 0.05	 0.80	  0.9	 48	 241	loop 5
+ -0.218691	  -0.518602	      -2 	Waypt	0.011	 0.01	 0.81	  1.0	 48	 206	loop 5
+ -0.219135	  -0.518823	      23*	Junct	0.054	 0.07	 0.86	  1.0	 48	 206	loop 5
+ -0.219145	  -0.517626	      33*	Junct	0.133	 0.17	 1.00	  1.2	 48	  90	top road
+ -0.219144	  -0.517257	      36*	Junct	0.041	 0.05	 1.04	  1.2	 48	  89	top road
+ -0.219291	  -0.517193	      38 	Inter	0.017	 0.02	 1.05	  1.3	 48	 156	roundabout
+ -0.219352	  -0.517060	      42 	Junct-	0.016	 0.02	 1.07	  1.3	 48	 114	roundabout
+ -0.219304	  -0.516904	      45 	Inter	0.018	 0.02	 1.09	  1.3	 48	  72	roundabout
+ -0.219153	  -0.516826	      46*	Junct-	0.018	 0.02	 1.11	  1.3	 48	  27	roundabout
+ -0.218966	  -0.516910	      44 	Inter	0.022	 0.03	 1.13	  1.3	 48	 335	roundabout
+ -0.218923	  -0.517072	      39 	Junct-	0.018	 0.02	 1.15	  1.4	 48	 284	roundabout
+ -0.218998	  -0.517207	      37 	Inter	0.017	 0.02	 1.16	  1.4	 48	 240	roundabout
+ -0.219144	  -0.517257	      36*	Junct	0.017	 0.02	 1.18	  1.4	 48	 199	roundabout
+ -0.219145	  -0.517626	      33*	Junct	0.041	 0.05	 1.22	  1.5	 48	 269	top road
+ -0.219135	  -0.518823	      23*	Junct	0.133	 0.17	 1.35	  1.6	 48	 270	top road
+ -0.219131	  -0.519426	      20*	Junct	0.067	 0.08	 1.42	  1.7	 48	 270	top road
+ -0.219123	  -0.520207	      12*	Junct	0.086	 0.11	 1.51	  1.8	 48	 270	top road
+ -0.219107	  -0.520828	       6*	Junct	0.069	 0.09	 1.58	  1.9	 48	 271	top road
+ -0.220666	  -0.520893	       5*	Junct-	0.173	 0.11	 1.75	  2.0	 96	 182	main 1
+ -0.221308	  -0.520914	       4*	Junct-	0.071	 0.04	 1.82	  2.0	 96	 181	main 1
+ -0.221561	  -0.520922	      -3 	Waypt	0.027	 0.02	 1.85	  2.1	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/turns-WP14.txt b/3rdparty/Routino/src/test/expected/turns-WP14.txt
new file mode 100644
index 0000000..8e694cb
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/turns-WP14.txt
@@ -0,0 +1,44 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218453	  -0.520799	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219107	  -0.520828	       6*	Junct	0.072	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.219123	  -0.520207	      12*	Junct	0.069	 0.09	 0.14	  0.1	 48	  91	top road
+ -0.219131	  -0.519426	      20*	Junct	0.086	 0.11	 0.23	  0.2	 48	  90	top road
+ -0.219135	  -0.518823	      23*	Junct	0.067	 0.08	 0.29	  0.3	 48	  90	top road
+ -0.219145	  -0.517626	      33*	Junct	0.133	 0.17	 0.43	  0.5	 48	  90	top road
+ -0.219144	  -0.517257	      36*	Junct	0.041	 0.05	 0.47	  0.5	 48	  89	top road
+ -0.219291	  -0.517193	      38 	Inter	0.017	 0.02	 0.48	  0.6	 48	 156	roundabout
+ -0.219352	  -0.517060	      42 	Junct-	0.016	 0.02	 0.50	  0.6	 48	 114	roundabout
+ -0.219304	  -0.516904	      45 	Inter	0.018	 0.02	 0.52	  0.6	 48	  72	roundabout
+ -0.219153	  -0.516826	      46*	Junct-	0.018	 0.02	 0.54	  0.6	 48	  27	roundabout
+ -0.218966	  -0.516910	      44 	Inter	0.022	 0.03	 0.56	  0.6	 48	 335	roundabout
+ -0.218923	  -0.517072	      39 	Junct-	0.018	 0.02	 0.58	  0.7	 48	 284	roundabout
+ -0.218998	  -0.517207	      37 	Inter	0.017	 0.02	 0.59	  0.7	 48	 240	roundabout
+ -0.219144	  -0.517257	      36*	Junct	0.017	 0.02	 0.61	  0.7	 48	 199	roundabout
+ -0.219145	  -0.517626	      33*	Junct	0.041	 0.05	 0.65	  0.8	 48	 269	top road
+ -0.218619	  -0.517921	      32*	Inter	0.067	 0.08	 0.72	  0.8	 48	 330	loop 5
+ -0.218431	  -0.518243	      28 	Inter	0.041	 0.05	 0.76	  0.9	 48	 300	loop 5
+ -0.218600	  -0.518557	      25*	Waypt	0.039	 0.05	 0.80	  0.9	 48	 241	loop 5
+ -0.219135	  -0.518823	      23*	Junct	0.066	 0.08	 0.86	  1.0	 48	 206	loop 5
+ -0.219145	  -0.517626	      33*	Junct	0.133	 0.17	 1.00	  1.2	 48	  90	top road
+ -0.219144	  -0.517257	      36*	Junct	0.041	 0.05	 1.04	  1.2	 48	  89	top road
+ -0.219291	  -0.517193	      38 	Inter	0.017	 0.02	 1.06	  1.3	 48	 156	roundabout
+ -0.219352	  -0.517060	      42 	Junct-	0.016	 0.02	 1.07	  1.3	 48	 114	roundabout
+ -0.219304	  -0.516904	      45 	Inter	0.018	 0.02	 1.09	  1.3	 48	  72	roundabout
+ -0.219153	  -0.516826	      46*	Junct-	0.018	 0.02	 1.11	  1.3	 48	  27	roundabout
+ -0.218966	  -0.516910	      44 	Inter	0.022	 0.03	 1.13	  1.3	 48	 335	roundabout
+ -0.218923	  -0.517072	      39 	Junct-	0.018	 0.02	 1.15	  1.4	 48	 284	roundabout
+ -0.218998	  -0.517207	      37 	Inter	0.017	 0.02	 1.17	  1.4	 48	 240	roundabout
+ -0.219144	  -0.517257	      36*	Junct	0.017	 0.02	 1.18	  1.4	 48	 199	roundabout
+ -0.219145	  -0.517626	      33*	Junct	0.041	 0.05	 1.22	  1.5	 48	 269	top road
+ -0.219135	  -0.518823	      23*	Junct	0.133	 0.17	 1.36	  1.6	 48	 270	top road
+ -0.219131	  -0.519426	      20*	Junct	0.067	 0.08	 1.42	  1.7	 48	 270	top road
+ -0.219123	  -0.520207	      12*	Junct	0.086	 0.11	 1.51	  1.8	 48	 270	top road
+ -0.219107	  -0.520828	       6*	Junct	0.069	 0.09	 1.58	  1.9	 48	 271	top road
+ -0.220666	  -0.520893	       5*	Junct-	0.173	 0.11	 1.75	  2.0	 96	 182	main 1
+ -0.221308	  -0.520914	       4*	Junct-	0.071	 0.04	 1.82	  2.0	 96	 181	main 1
+ -0.221561	  -0.520922	      -3 	Waypt	0.027	 0.02	 1.85	  2.1	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/turns-WP15.txt b/3rdparty/Routino/src/test/expected/turns-WP15.txt
new file mode 100644
index 0000000..2aa0907
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/turns-WP15.txt
@@ -0,0 +1,44 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218453	  -0.520799	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219107	  -0.520828	       6*	Junct	0.072	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.219123	  -0.520207	      12*	Junct	0.069	 0.09	 0.14	  0.1	 48	  91	top road
+ -0.219131	  -0.519426	      20*	Junct	0.086	 0.11	 0.23	  0.2	 48	  90	top road
+ -0.219135	  -0.518823	      23*	Junct	0.067	 0.08	 0.29	  0.3	 48	  90	top road
+ -0.219145	  -0.517626	      33*	Junct	0.133	 0.17	 0.43	  0.5	 48	  90	top road
+ -0.219144	  -0.517257	      36*	Junct	0.041	 0.05	 0.47	  0.5	 48	  89	top road
+ -0.219291	  -0.517193	      38 	Inter	0.017	 0.02	 0.48	  0.6	 48	 156	roundabout
+ -0.219352	  -0.517060	      42 	Junct-	0.016	 0.02	 0.50	  0.6	 48	 114	roundabout
+ -0.219304	  -0.516904	      45 	Inter	0.018	 0.02	 0.52	  0.6	 48	  72	roundabout
+ -0.219153	  -0.516826	      46*	Junct-	0.018	 0.02	 0.54	  0.6	 48	  27	roundabout
+ -0.218966	  -0.516910	      44 	Inter	0.022	 0.03	 0.56	  0.6	 48	 335	roundabout
+ -0.218923	  -0.517072	      39 	Junct-	0.018	 0.02	 0.58	  0.7	 48	 284	roundabout
+ -0.218998	  -0.517207	      37 	Inter	0.017	 0.02	 0.59	  0.7	 48	 240	roundabout
+ -0.219144	  -0.517257	      36*	Junct	0.017	 0.02	 0.61	  0.7	 48	 199	roundabout
+ -0.219145	  -0.517626	      33*	Junct	0.041	 0.05	 0.65	  0.8	 48	 269	top road
+ -0.218619	  -0.517921	      32*	Inter	0.067	 0.08	 0.72	  0.8	 48	 330	loop 5
+ -0.218431	  -0.518243	      28 	Waypt	0.041	 0.05	 0.76	  0.9	 48	 300	loop 5
+ -0.218600	  -0.518557	      25*	Inter	0.039	 0.05	 0.80	  0.9	 48	 241	loop 5
+ -0.219135	  -0.518823	      23*	Junct	0.066	 0.08	 0.86	  1.0	 48	 206	loop 5
+ -0.219145	  -0.517626	      33*	Junct	0.133	 0.17	 1.00	  1.2	 48	  90	top road
+ -0.219144	  -0.517257	      36*	Junct	0.041	 0.05	 1.04	  1.2	 48	  89	top road
+ -0.219291	  -0.517193	      38 	Inter	0.017	 0.02	 1.06	  1.3	 48	 156	roundabout
+ -0.219352	  -0.517060	      42 	Junct-	0.016	 0.02	 1.07	  1.3	 48	 114	roundabout
+ -0.219304	  -0.516904	      45 	Inter	0.018	 0.02	 1.09	  1.3	 48	  72	roundabout
+ -0.219153	  -0.516826	      46*	Junct-	0.018	 0.02	 1.11	  1.3	 48	  27	roundabout
+ -0.218966	  -0.516910	      44 	Inter	0.022	 0.03	 1.13	  1.3	 48	 335	roundabout
+ -0.218923	  -0.517072	      39 	Junct-	0.018	 0.02	 1.15	  1.4	 48	 284	roundabout
+ -0.218998	  -0.517207	      37 	Inter	0.017	 0.02	 1.17	  1.4	 48	 240	roundabout
+ -0.219144	  -0.517257	      36*	Junct	0.017	 0.02	 1.18	  1.4	 48	 199	roundabout
+ -0.219145	  -0.517626	      33*	Junct	0.041	 0.05	 1.22	  1.5	 48	 269	top road
+ -0.219135	  -0.518823	      23*	Junct	0.133	 0.17	 1.36	  1.6	 48	 270	top road
+ -0.219131	  -0.519426	      20*	Junct	0.067	 0.08	 1.42	  1.7	 48	 270	top road
+ -0.219123	  -0.520207	      12*	Junct	0.086	 0.11	 1.51	  1.8	 48	 270	top road
+ -0.219107	  -0.520828	       6*	Junct	0.069	 0.09	 1.58	  1.9	 48	 271	top road
+ -0.220666	  -0.520893	       5*	Junct-	0.173	 0.11	 1.75	  2.0	 96	 182	main 1
+ -0.221308	  -0.520914	       4*	Junct-	0.071	 0.04	 1.82	  2.0	 96	 181	main 1
+ -0.221561	  -0.520922	      -3 	Waypt	0.027	 0.02	 1.85	  2.1	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/expected/turns-WP16.txt b/3rdparty/Routino/src/test/expected/turns-WP16.txt
new file mode 100644
index 0000000..dcc59ae
--- /dev/null
+++ b/3rdparty/Routino/src/test/expected/turns-WP16.txt
@@ -0,0 +1,16 @@
+# Creator : Routino - http://www.routino.org/
+# Source : Routino test cases - (c) Andrew M. Bishop
+# License : GNU Affero General Public License v3 or later
+#
+#Latitude	Longitude	    Node	Type	Segment	Segment	Total	Total  	Speed	Bearing	Highway
+#        	         	        	    	Dist   	Durat'n	Dist 	Durat'n	     	       	       
+ -0.218453	  -0.520799	      -1 	Waypt	0.000	 0.00	 0.00	  0.0			
+ -0.219107	  -0.520828	       6*	Junct-	0.072	 0.04	 0.07	  0.0	 96	 182	main 1
+ -0.220666	  -0.520893	       5*	Junct-	0.173	 0.11	 0.24	  0.2	 96	 182	main 1
+ -0.221308	  -0.520914	       4*	Junct	0.071	 0.04	 0.32	  0.2	 96	 181	main 1
+ -0.221360	  -0.518860	      21*	Junct	0.228	 0.28	 0.54	  0.5	 48	  91	bottom road
+ -0.221711	  -0.518511	      26*	Waypt	0.055	 0.07	 0.60	  0.5	 48	 135	loop 6
+ -0.221376	  -0.518235	      29*	Junct	0.048	 0.06	 0.65	  0.6	 48	  39	loop 6
+ -0.221360	  -0.518860	      21*	Junct	0.069	 0.09	 0.72	  0.7	 48	 271	bottom road
+ -0.221308	  -0.520914	       4*	Junct	0.228	 0.28	 0.94	  1.0	 48	 271	bottom road
+ -0.221561	  -0.520922	      -3 	Waypt	0.027	 0.02	 0.97	  1.0	 96	 181	main 1
diff --git a/3rdparty/Routino/src/test/fake-node-with-loop.osm b/3rdparty/Routino/src/test/fake-node-with-loop.osm
new file mode 100644
index 0000000..5fc81d2
--- /dev/null
+++ b/3rdparty/Routino/src/test/fake-node-with-loop.osm
@@ -0,0 +1,102 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' generator='JOSM'>
+  <node id='4' visible='true' version='1' lat='-0.21661291636529073' lon='-0.520761488739697' />
+  <node id='6' visible='true' version='1' lat='-0.2163742693028532' lon='-0.5205061674081213' />
+  <node id='8' visible='true' version='1' lat='-0.2161202780565698' lon='-0.5207419121625206' />
+  <node id='10' visible='true' version='1' lat='-0.2163536787625498' lon='-0.5209987436557322' />
+  <node id='35' visible='true' version='1' lat='-0.21848333709591153' lon='-0.5218427454267438' />
+  <node id='37' visible='true' version='1' lat='-0.21855669147258072' lon='-0.5198307250334835' />
+  <node id='47' visible='true' version='1' lat='-0.21695596294699857' lon='-0.5206845368680583'>
+    <tag k='name' v='WP02a' />
+  </node>
+  <node id='48' visible='true' version='1' lat='-0.21775028231343874' lon='-0.5206857546917354'>
+    <tag k='name' v='WP01c' />
+  </node>
+  <node id='49' visible='true' version='1' lat='-0.2188482915170263' lon='-0.5207295158812542'>
+    <tag k='name' v='WP02c' />
+  </node>
+  <node id='59' visible='true' version='1' lat='-0.21852291461431964' lon='-0.5208066156936016' />
+  <node id='61' visible='true' version='1' lat='-0.21724703005097415' lon='-0.5218177543802404' />
+  <node id='62' visible='true' version='1' lat='-0.2172864966637643' lon='-0.5207796778404852' />
+  <node id='65' visible='true' version='1' lat='-0.2173314123555489' lon='-0.5198074556089362' />
+  <node id='89' visible='true' version='1' lat='-0.21917467817079206' lon='-0.5207413591979394'>
+    <tag k='name' v='WP02b' />
+  </node>
+  <node id='204' visible='true' version='1' lat='-0.21809098400469543' lon='-0.5207047848008673'>
+    <tag k='name' v='WP01b' />
+  </node>
+  <node id='208' visible='true' version='1' lat='-0.21691021404678168' lon='-0.5206872967320134'>
+    <tag k='name' v='WP01a' />
+  </node>
+  <node id='242' visible='true' version='1' lat='-0.21969184942143533' lon='-0.520508838695913' />
+  <node id='244' visible='true' version='1' lat='-0.2200812203297903' lon='-0.5205220270076113' />
+  <node id='246' visible='true' version='1' lat='-0.21966460614165306' lon='-0.5211903128432791' />
+  <node id='248' visible='true' version='1' lat='-0.22006229057645915' lon='-0.5212037827409091' />
+  <node id='253' visible='true' version='1' lat='-0.21927153579637806' lon='-0.5195315927529504' />
+  <node id='255' visible='true' version='1' lat='-0.2207678018006232' lon='-0.5197417721359917' />
+  <node id='257' visible='true' version='1' lat='-0.22054261127446687' lon='-0.5220737624335469' />
+  <node id='259' visible='true' version='1' lat='-0.21914142570197062' lon='-0.5220187154522741' />
+  <node id='345' visible='true' version='1' lat='-0.22026866394788633' lon='-0.5208635679861234' />
+  <node id='438' visible='true' version='1' lat='-0.21948172568612254' lon='-0.5208369137424373' />
+  <way id='13' visible='true' version='1'>
+    <nd ref='4' />
+    <nd ref='6' />
+    <nd ref='8' />
+    <nd ref='10' />
+    <nd ref='4' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='36' visible='true' version='1'>
+    <nd ref='35' />
+    <nd ref='59' />
+    <nd ref='37' />
+    <tag k='highway' v='footway' />
+  </way>
+  <way id='63' visible='true' version='1'>
+    <nd ref='61' />
+    <nd ref='62' />
+    <nd ref='65' />
+    <tag k='highway' v='footway' />
+  </way>
+  <way id='239' visible='true' version='1'>
+    <nd ref='345' />
+    <nd ref='248' />
+    <nd ref='246' />
+    <nd ref='438' />
+    <nd ref='242' />
+    <nd ref='244' />
+    <nd ref='345' />
+    <tag k='highway' v='primary' />
+    <tag k='junction' v='roundabout' />
+    <tag k='name' v='roundabout' />
+    <tag k='oneway' v='yes' />
+  </way>
+  <way id='240' visible='true' version='1'>
+    <nd ref='438' />
+    <nd ref='59' />
+    <nd ref='62' />
+    <nd ref='4' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 1' />
+  </way>
+  <way id='254' visible='true' version='1'>
+    <nd ref='253' />
+    <nd ref='242' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='256' visible='true' version='1'>
+    <nd ref='255' />
+    <nd ref='244' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='258' visible='true' version='1'>
+    <nd ref='257' />
+    <nd ref='248' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='260' visible='true' version='1'>
+    <nd ref='259' />
+    <nd ref='246' />
+    <tag k='highway' v='residential' />
+  </way>
+</osm>
diff --git a/3rdparty/Routino/src/test/fake-node-with-loop.sh b/3rdparty/Routino/src/test/fake-node-with-loop.sh
new file mode 120000
index 0000000..a093b70
--- /dev/null
+++ b/3rdparty/Routino/src/test/fake-node-with-loop.sh
@@ -0,0 +1 @@
+a-b-c.sh
\ No newline at end of file
diff --git a/3rdparty/Routino/src/test/invalid-turn-relations.osm b/3rdparty/Routino/src/test/invalid-turn-relations.osm
new file mode 100644
index 0000000..675057e
--- /dev/null
+++ b/3rdparty/Routino/src/test/invalid-turn-relations.osm
@@ -0,0 +1,230 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' generator='JOSM'>
+  <node id='57' visible='true' version='1' lat='-0.2206639471091671' lon='-0.5206861212034376' />
+  <node id='58' visible='true' version='1' lat='-0.22077223999470932' lon='-0.5163392044926929' />
+  <node id='61' visible='true' version='1' lat='-0.22068542234146674' lon='-0.5199851724982207' />
+  <node id='63' visible='true' version='1' lat='-0.22121142780027955' lon='-0.5200031409736897' />
+  <node id='68' visible='true' version='1' lat='-0.22070209612901087' lon='-0.51927521490923' />
+  <node id='72' visible='true' version='1' lat='-0.22071777806715892' lon='-0.5186074895360361' />
+  <node id='74' visible='true' version='1' lat='-0.22125354169876188' lon='-0.5186133719636564' />
+  <node id='86' visible='true' version='1' lat='-0.22073699379599293' lon='-0.5177892979578822' />
+  <node id='96' visible='true' version='1' lat='-0.221280772661584' lon='-0.5177920778771439' />
+  <node id='106' visible='true' version='1' lat='-0.22129681282128807' lon='-0.5170144218511278' />
+  <node id='107' visible='true' version='1' lat='-0.22075303395629983' lon='-0.5170116419318662' />
+  <node id='118' visible='true' version='1' lat='-0.2195990670258593' lon='-0.5163091229123892' />
+  <node id='119' visible='true' version='1' lat='-0.21949625394184963' lon='-0.5205982296714888' />
+  <node id='122' visible='true' version='1' lat='-0.2195106565302976' lon='-0.5199911498477413' />
+  <node id='124' visible='true' version='1' lat='-0.21952740822631348' lon='-0.5192511136098236' />
+  <node id='126' visible='true' version='1' lat='-0.21954320401859898' lon='-0.5185533061341185' />
+  <node id='142' visible='true' version='1' lat='-0.22008353464611746' lon='-0.5185561500168592' />
+  <node id='162' visible='true' version='1' lat='-0.2195613199707841' lon='-0.517753001429538' />
+  <node id='173' visible='true' version='1' lat='-0.22012793202460473' lon='-0.5169903885686242' />
+  <node id='174' visible='true' version='1' lat='-0.21958760139871253' lon='-0.5169875446858836' />
+  <node id='277' visible='true' version='1' lat='-0.21896493881565954' lon='-0.5192522336393591' />
+  <node id='279' visible='true' version='1' lat='-0.22009496450308905' lon='-0.519247211266105' />
+  <node id='465' visible='true' version='1' lat='-0.21947721713787466' lon='-0.5212084480218759' />
+  <node id='485' visible='true' version='1' lat='-0.21961229394941645' lon='-0.5156863486288665' />
+  <way id='593' visible='true' version='1'>
+    <nd ref='279' />
+    <nd ref='124' />
+    <tag k='highway' v='unclassified' />
+    <tag k='oneway' v='yes' />
+  </way>
+  <way id='59' visible='true' version='1'>
+    <nd ref='57' />
+    <nd ref='61' />
+    <tag k='highway' v='unclassified' />
+  </way>
+  <way id='64' visible='true' version='1'>
+    <nd ref='61' />
+    <nd ref='63' />
+    <tag k='highway' v='footway' />
+  </way>
+  <way id='66' visible='true' version='1'>
+    <nd ref='61' />
+    <nd ref='68' />
+    <tag k='highway' v='unclassified' />
+  </way>
+  <way id='70' visible='true' version='1'>
+    <nd ref='68' />
+    <nd ref='72' />
+    <tag k='highway' v='unclassified' />
+  </way>
+  <way id='75' visible='true' version='1'>
+    <nd ref='74' />
+    <nd ref='72' />
+    <tag k='highway' v='unclassified' />
+    <tag k='oneway' v='yes' />
+  </way>
+  <way id='80' visible='true' version='1'>
+    <nd ref='72' />
+    <nd ref='86' />
+    <tag k='highway' v='unclassified' />
+  </way>
+  <way id='88' visible='true' version='1'>
+    <nd ref='86' />
+    <nd ref='107' />
+    <tag k='highway' v='unclassified' />
+  </way>
+  <way id='95' visible='true' version='1'>
+    <nd ref='96' />
+    <nd ref='86' />
+    <tag k='highway' v='unclassified' />
+    <tag k='oneway' v='yes' />
+  </way>
+  <way id='105' visible='true' version='1'>
+    <nd ref='106' />
+    <nd ref='107' />
+    <tag k='highway' v='footway' />
+  </way>
+  <way id='114' visible='true' version='1'>
+    <nd ref='107' />
+    <nd ref='58' />
+    <tag k='highway' v='unclassified' />
+  </way>
+  <way id='128' visible='true' version='1'>
+    <nd ref='126' />
+    <nd ref='124' />
+    <tag k='highway' v='unclassified' />
+    <tag k='oneway' v='yes' />
+  </way>
+  <way id='129' visible='true' version='1'>
+    <nd ref='122' />
+    <nd ref='124' />
+    <tag k='highway' v='unclassified' />
+  </way>
+  <way id='130' visible='true' version='1'>
+    <nd ref='119' />
+    <nd ref='122' />
+    <tag k='highway' v='unclassified' />
+  </way>
+  <way id='141' visible='true' version='1'>
+    <nd ref='142' />
+    <nd ref='126' />
+    <tag k='highway' v='unclassified' />
+  </way>
+  <way id='167' visible='true' version='1'>
+    <nd ref='118' />
+    <nd ref='174' />
+    <nd ref='162' />
+    <nd ref='126' />
+    <tag k='highway' v='unclassified' />
+  </way>
+  <way id='172' visible='true' version='1'>
+    <nd ref='173' />
+    <nd ref='174' />
+    <tag k='highway' v='unclassified' />
+  </way>
+  <way id='278' visible='true' version='1'>
+    <nd ref='277' />
+    <nd ref='124' />
+    <tag k='highway' v='unclassified' />
+    <tag k='oneway' v='yes' />
+  </way>
+  <way id='466' visible='true' version='1'>
+    <nd ref='465' />
+    <nd ref='119' />
+    <tag k='highway' v='footway' />
+  </way>
+  <way id='483' visible='true' version='1'>
+    <nd ref='118' />
+    <nd ref='485' />
+    <tag k='highway' v='footway' />
+  </way>
+  <relation id='79' visible='true' version='1'>
+    <member type='way' ref='59' role='from' />
+    <member type='node' ref='61' role='via' />
+    <member type='way' ref='66' role='to' />
+    <tag k='name' v='straight on but only turn is not for motor vehicles' />
+    <tag k='restriction' v='only_straight_on' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='83' visible='true' version='1'>
+    <member type='node' ref='68' role='via' />
+    <member type='way' ref='70' role='to' />
+    <member type='way' ref='66' role='from' />
+    <tag k='name' v='straight on but no turn possible' />
+    <tag k='restriction' v='only_straight_on' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='91' visible='true' version='1'>
+    <member type='way' ref='70' role='from' />
+    <member type='node' ref='72' role='via' />
+    <member type='way' ref='80' role='to' />
+    <tag k='name' v='straight on but only turn is oneway' />
+    <tag k='restriction' v='only_straight_on' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='101' visible='true' version='1'>
+    <member type='way' ref='80' role='from' />
+    <member type='node' ref='86' role='via' />
+    <member type='way' ref='95' role='to' />
+    <tag k='name' v='no right turn into oneway' />
+    <tag k='restriction' v='no_right_turn' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='117' visible='true' version='1'>
+    <member type='way' ref='88' role='from' />
+    <member type='node' ref='107' role='via' />
+    <member type='way' ref='105' role='to' />
+    <tag k='name' v='no right turn into non-vehicle way' />
+    <tag k='restriction' v='no_right_turn' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='133' visible='true' version='1'>
+    <member type='way' ref='130' role='from' />
+    <member type='node' ref='122' role='via' />
+    <member type='way' ref='129' role='to' />
+    <tag k='name' v='straight on from incorrect oneway' />
+    <tag k='restriction' v='only_straight_on' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='137' visible='true' version='1'>
+    <member type='way' ref='128' role='to' />
+    <member type='way' ref='129' role='from' />
+    <member type='node' ref='124' role='via' />
+    <tag k='name' v='straight on but all directions are incorrect oneway' />
+    <tag k='restriction' v='only_straight_on' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='148' visible='true' version='1'>
+    <member type='way' ref='128' role='from' />
+    <member type='way' ref='141' role='to' />
+    <member type='node' ref='126' role='via' />
+    <tag k='name' v='no right turn from incorrect oneway' />
+    <tag k='restriction' v='no_right_turn' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='182' visible='true' version='1'>
+    <member type='way' ref='167' role='from' />
+    <member type='node' ref='162' role='via' />
+    <member type='way' ref='167' role='to' />
+    <tag k='name' v='straight on not at end of way' />
+    <tag k='restriction' v='only_straight_on' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='184' visible='true' version='1'>
+    <member type='way' ref='167' role='from' />
+    <member type='node' ref='174' role='via' />
+    <member type='way' ref='172' role='to' />
+    <tag k='name' v='no right turn not at end of way' />
+    <tag k='restriction' v='no_right_turn' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='477' visible='true' version='1'>
+    <member type='way' ref='466' role='from' />
+    <member type='node' ref='119' role='via' />
+    <member type='way' ref='130' role='to' />
+    <tag k='name' v='straight on from non-vehicle way' />
+    <tag k='restriction' v='only_straight_on' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='489' visible='true' version='1'>
+    <member type='way' ref='483' role='from' />
+    <member type='node' ref='118' role='via' />
+    <member type='way' ref='167' role='to' />
+    <tag k='name' v='no straight on from non-vehicle way' />
+    <tag k='restriction' v='no_straight_on' />
+    <tag k='type' v='restriction' />
+  </relation>
+</osm>
diff --git a/3rdparty/Routino/src/test/invalid-turn-relations.sh b/3rdparty/Routino/src/test/invalid-turn-relations.sh
new file mode 120000
index 0000000..bc8f799
--- /dev/null
+++ b/3rdparty/Routino/src/test/invalid-turn-relations.sh
@@ -0,0 +1 @@
+only-split.sh
\ No newline at end of file
diff --git a/3rdparty/Routino/src/test/is-fast-math.c b/3rdparty/Routino/src/test/is-fast-math.c
new file mode 100644
index 0000000..78c667b
--- /dev/null
+++ b/3rdparty/Routino/src/test/is-fast-math.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+
+int main(int argc,char **argv)
+{
+#ifdef __FAST_MATH__
+
+ if(argc>1)
+    printf("Compiled with -ffast-math => results may differ slightly.\n");
+
+ return 0;
+
+#else
+
+ if(argc>1)
+    printf("Not compiled with -ffast-math => results should match exactly.\n");
+
+ return 1;
+
+#endif
+}
diff --git a/3rdparty/Routino/src/test/loops.osm b/3rdparty/Routino/src/test/loops.osm
new file mode 100644
index 0000000..b83186e
--- /dev/null
+++ b/3rdparty/Routino/src/test/loops.osm
@@ -0,0 +1,168 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' generator='JOSM'>
+  <node id='484' version='1' visible='true' lat='-0.21901312467042416' lon='-0.517332609859675'>
+    <tag k='name' v='WP09' />
+  </node>
+  <node id='482' version='1' visible='true' lat='-0.2195967297237718' lon='-0.5174891879721774'>
+    <tag k='name' v='WP08' />
+  </node>
+  <node id='478' version='1' visible='true' lat='-0.21994546931795161' lon='-0.5173966645420623'>
+    <tag k='name' v='WP07' />
+  </node>
+  <node id='468' version='1' visible='true' lat='-0.2183796996477898' lon='-0.5191332581534525'>
+    <tag k='name' v='WP05' />
+  </node>
+  <node id='466' version='1' visible='true' lat='-0.21899177326561078' lon='-0.5190549690972014'>
+    <tag k='name' v='WP04' />
+  </node>
+  <node id='464' version='1' visible='true' lat='-0.21957537831978627' lon='-0.5191901956489079'>
+    <tag k='name' v='WP03' />
+  </node>
+  <node id='460' version='1' visible='true' lat='-0.2199098836454558' lon='-0.5191119065926569'>
+    <tag k='name' v='WP02' />
+  </node>
+  <node id='208' version='1' visible='true' lat='-0.21960114860694938' lon='-0.515860763795797'>
+    <tag k='name' v='WPfinish' />
+  </node>
+  <node id='204' version='1' visible='true' lat='-0.21955223220675274' lon='-0.5210161384621299'>
+    <tag k='name' v='WPstart' />
+  </node>
+  <node id='193' version='1' visible='true' lat='-0.21880536397011213' lon='-0.5171306758615497'>
+    <tag k='name' v='WP10' />
+  </node>
+  <node id='191' version='1' visible='true' lat='-0.21879379605820587' lon='-0.5177631602471016' />
+  <node id='190' version='1' visible='true' lat='-0.21926641829948795' lon='-0.5175789752337265' />
+  <node id='157' version='1' visible='true' lat='-0.21841686561366' lon='-0.5174617719465804'>
+    <tag k='name' v='WP11' />
+  </node>
+  <node id='149' version='1' visible='true' lat='-0.218775973869117' lon='-0.5188385645044677' />
+  <node id='147' version='1' visible='true' lat='-0.21876440595719907' lon='-0.5194710488900195' />
+  <node id='146' version='1' visible='true' lat='-0.21923702819939836' lon='-0.5192868638766445' />
+  <node id='145' version='1' visible='true' lat='-0.22027992726562468' lon='-0.5192553487141034'>
+    <tag k='name' v='WP01' />
+  </node>
+  <node id='144' version='1' visible='true' lat='-0.22069487557324122' lon='-0.5194891951207509' />
+  <node id='131' version='1' visible='true' lat='-0.2186995850954771' lon='-0.515945221575862' />
+  <node id='129' version='1' visible='true' lat='-0.21807335137583664' lon='-0.5192768664531259' />
+  <node id='123' version='1' visible='true' lat='-0.21881956658439772' lon='-0.5208128725880712' />
+  <node id='120' version='1' visible='true' lat='-0.22031145754149978' lon='-0.5160148024786712' />
+  <node id='117' version='1' visible='true' lat='-0.2203009132482348' lon='-0.5175762181579412'>
+    <tag k='name' v='WP06' />
+  </node>
+  <node id='109' version='1' visible='true' lat='-0.22022296242215664' lon='-0.5208850955075449' />
+  <node id='92' version='1' visible='true' lat='-0.2207386134847756' lon='-0.5178011278670027' />
+  <node id='54' version='1' visible='true' lat='-0.22078436832897996' lon='-0.5160352169735775' />
+  <node id='52' version='1' visible='true' lat='-0.2206667536990629' lon='-0.5208930003039592' />
+  <node id='51' version='1' visible='true' lat='-0.22189614840042465' lon='-0.5163053654637676' />
+  <node id='50' version='1' visible='true' lat='-0.22191520010406854' lon='-0.515835072317115' />
+  <node id='49' version='1' visible='true' lat='-0.22214182669974075' lon='-0.5160772027310793' />
+  <node id='48' version='1' visible='true' lat='-0.2216713552163718' lon='-0.5160632301909843' />
+  <node id='47' version='1' visible='true' lat='-0.21798215306964172' lon='-0.5161639796064453' />
+  <node id='46' version='1' visible='true' lat='-0.21774729558699316' lon='-0.515907564575113' />
+  <node id='45' version='1' visible='true' lat='-0.2180027381687473' lon='-0.5156713934099496' />
+  <node id='44' version='1' visible='true' lat='-0.21823992390738106' lon='-0.5159271465477753' />
+  <node id='24' version='1' visible='true' lat='-0.22193543526189635' lon='-0.5211703062894754' />
+  <node id='22' version='1' visible='true' lat='-0.22195451857008858' lon='-0.5207002437384278' />
+  <node id='21' version='1' visible='true' lat='-0.2221908395649969' lon='-0.5209415430673436' />
+  <node id='10' version='1' visible='true' lat='-0.21802147020530807' lon='-0.5210285258597515' />
+  <node id='8' version='1' visible='true' lat='-0.21778806952505525' lon='-0.52077169436654' />
+  <node id='6' version='1' visible='true' lat='-0.21804206074333024' lon='-0.5205359496121407' />
+  <node id='4' version='1' visible='true' lat='-0.21828070777942268' lon='-0.5207912709437164' />
+  <node id='3' version='1' visible='true' lat='-0.2217201380129468' lon='-0.5209275966384278' />
+  <way id='186' version='1' visible='true'>
+    <nd ref='92' />
+    <nd ref='117' />
+    <nd ref='478' />
+    <nd ref='190' />
+    <nd ref='191' />
+    <nd ref='157' />
+    <nd ref='193' />
+    <nd ref='190' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='loop 2' />
+  </way>
+  <way id='143' version='1' visible='true'>
+    <nd ref='144' />
+    <nd ref='145' />
+    <nd ref='460' />
+    <nd ref='146' />
+    <nd ref='147' />
+    <nd ref='468' />
+    <nd ref='149' />
+    <nd ref='146' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='loop 1' />
+  </way>
+  <way id='126' version='1' visible='true'>
+    <nd ref='123' />
+    <nd ref='129' />
+    <nd ref='157' />
+    <nd ref='131' />
+    <tag k='highway' v='footway' />
+  </way>
+  <way id='112' version='1' visible='true'>
+    <nd ref='109' />
+    <nd ref='145' />
+    <nd ref='117' />
+    <nd ref='120' />
+    <tag k='highway' v='footway' />
+  </way>
+  <way id='55' version='1' visible='true'>
+    <nd ref='52' />
+    <nd ref='144' />
+    <nd ref='92' />
+    <nd ref='54' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='high street' />
+  </way>
+  <way id='43' version='1' visible='true'>
+    <nd ref='49' />
+    <nd ref='50' />
+    <nd ref='48' />
+    <nd ref='51' />
+    <nd ref='49' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='42' version='1' visible='true'>
+    <nd ref='48' />
+    <nd ref='54' />
+    <nd ref='120' />
+    <nd ref='131' />
+    <nd ref='44' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 2' />
+  </way>
+  <way id='41' version='1' visible='true'>
+    <nd ref='44' />
+    <nd ref='45' />
+    <nd ref='46' />
+    <nd ref='47' />
+    <nd ref='44' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='20' version='1' visible='true'>
+    <nd ref='21' />
+    <nd ref='22' />
+    <nd ref='3' />
+    <nd ref='24' />
+    <nd ref='21' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='13' version='1' visible='true'>
+    <nd ref='4' />
+    <nd ref='6' />
+    <nd ref='8' />
+    <nd ref='10' />
+    <nd ref='4' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='5' version='1' visible='true'>
+    <nd ref='3' />
+    <nd ref='52' />
+    <nd ref='109' />
+    <nd ref='123' />
+    <nd ref='4' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 1' />
+  </way>
+</osm>
diff --git a/3rdparty/Routino/src/test/loops.sh b/3rdparty/Routino/src/test/loops.sh
new file mode 120000
index 0000000..b627b17
--- /dev/null
+++ b/3rdparty/Routino/src/test/loops.sh
@@ -0,0 +1 @@
+start-1-finish.sh
\ No newline at end of file
diff --git a/3rdparty/Routino/src/test/no-super.osm b/3rdparty/Routino/src/test/no-super.osm
new file mode 100644
index 0000000..c939cb8
--- /dev/null
+++ b/3rdparty/Routino/src/test/no-super.osm
@@ -0,0 +1,105 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' generator='JOSM'>
+  <node id='64' visible='true' version='1' lat='-0.21580935521018227' lon='-0.5154355738232163'>
+    <tag k='name' v='WP01b' />
+  </node>
+  <node id='62' visible='true' version='1' lat='-0.21666471332302356' lon='-0.5172180810465782'>
+    <tag k='name' v='WP02c' />
+  </node>
+  <node id='60' visible='true' version='1' lat='-0.2157435584302805' lon='-0.5194312611561215'>
+    <tag k='name' v='WP01a' />
+  </node>
+  <node id='45' visible='true' version='1' lat='-0.21591728779127017' lon='-0.5199274336780653' />
+  <node id='44' visible='true' version='1' lat='-0.21597736816873858' lon='-0.5151896331179581' />
+  <node id='43' visible='true' version='1' lat='-0.21573704665745827' lon='-0.5190348045870303' />
+  <node id='42' visible='true' version='1' lat='-0.21574562956861365' lon='-0.5146403229080908' />
+  <node id='41' visible='true' version='1' lat='-0.2159516194355604' lon='-0.5168375637475604' />
+  <node id='40' visible='true' version='1' lat='-0.21575421247979204' lon='-0.5159449346565257' />
+  <node id='39' visible='true' version='1' lat='-0.21593445361342675' lon='-0.5182537541323748' />
+  <node id='38' visible='true' version='1' lat='-0.21577137830214121' lon='-0.5177130268945367' />
+  <node id='289' visible='true' version='1' lat='-0.21719295194932486' lon='-0.5146598430558845' />
+  <node id='291' visible='true' version='1' lat='-0.21742469052732205' lon='-0.5152091532657517' />
+  <node id='293' visible='true' version='1' lat='-0.21720153485967852' lon='-0.5159644548043194'>
+    <tag k='name' v='WP03b' />
+  </node>
+  <node id='295' visible='true' version='1' lat='-0.21739894179660665' lon='-0.5168570838953541' />
+  <node id='297' visible='true' version='1' lat='-0.21721870068038443' lon='-0.5177325470423303'>
+    <tag k='name' v='WP03c' />
+  </node>
+  <node id='299' visible='true' version='1' lat='-0.2173817759761041' lon='-0.5182732742801686' />
+  <node id='301' visible='true' version='1' lat='-0.21718436903897512' lon='-0.5190543247348238'>
+    <tag k='name' v='WP03a' />
+  </node>
+  <node id='303' visible='true' version='1' lat='-0.21736461015558492' lon='-0.5199469538258588' />
+  <node id='317' visible='true' version='1' lat='-0.21645258968230982' lon='-0.5193407934495843' />
+  <node id='319' visible='true' version='1' lat='-0.21665139496835623' lon='-0.5199456759923936' />
+  <node id='320' visible='true' version='1' lat='-0.21647973675399712' lon='-0.5146585652224195' />
+  <node id='322' visible='true' version='1' lat='-0.2167114753429348' lon='-0.514975821764363' />
+  <node id='337' visible='true' version='1' lat='-0.21653560167566016' lon='-0.519026065647934'>
+    <tag k='name' v='WP02a' />
+  </node>
+  <node id='340' visible='true' version='1' lat='-0.21579199919973227' lon='-0.5172285073918816'>
+    <tag k='name' v='WP01c' />
+  </node>
+  <node id='341' visible='true' version='1' lat='-0.21676781704922854' lon='-0.5156691067434341'>
+    <tag k='name' v='WP02b' />
+  </node>
+  <node id='356' visible='true' version='1' lat='-0.21808280653903642' lon='-0.5199271360673275' />
+  <node id='357' visible='true' version='1' lat='-0.21790256543101175' lon='-0.5190345069762927'>
+    <tag k='name' v='WP04a' />
+  </node>
+  <node id='358' visible='true' version='1' lat='-0.2180999723587434' lon='-0.5182534565216375' />
+  <node id='359' visible='true' version='1' lat='-0.21793689707078506' lon='-0.5177127292837991'>
+    <tag k='name' v='WP04c' />
+  </node>
+  <node id='360' visible='true' version='1' lat='-0.2181171381784273' lon='-0.516837266136823' />
+  <node id='361' visible='true' version='1' lat='-0.21791973125089717' lon='-0.5159446370457883' />
+  <node id='362' visible='true' version='1' lat='-0.21814288690791456' lon='-0.5151893355072206' />
+  <node id='363' visible='true' version='1' lat='-0.21791114834095254' lon='-0.5146400252973532'>
+    <tag k='name' v='WP04b' />
+  </node>
+  <way id='46' visible='true' version='1'>
+    <nd ref='45' />
+    <nd ref='43' />
+    <nd ref='39' />
+    <nd ref='38' />
+    <nd ref='41' />
+    <nd ref='40' />
+    <nd ref='44' />
+    <nd ref='42' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='road1' />
+  </way>
+  <way id='305' visible='true' version='1'>
+    <nd ref='303' />
+    <nd ref='301' />
+    <nd ref='299' />
+    <nd ref='297' />
+    <nd ref='295' />
+    <nd ref='293' />
+    <nd ref='291' />
+    <nd ref='289' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='road3' />
+  </way>
+  <way id='324' visible='true' version='1'>
+    <nd ref='319' />
+    <nd ref='317' />
+    <nd ref='322' />
+    <nd ref='320' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='road2' />
+  </way>
+  <way id='355' visible='true' version='1'>
+    <nd ref='356' />
+    <nd ref='357' />
+    <nd ref='358' />
+    <nd ref='359' />
+    <nd ref='360' />
+    <nd ref='361' />
+    <nd ref='362' />
+    <nd ref='363' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='road4' />
+  </way>
+</osm>
diff --git a/3rdparty/Routino/src/test/no-super.sh b/3rdparty/Routino/src/test/no-super.sh
new file mode 120000
index 0000000..a093b70
--- /dev/null
+++ b/3rdparty/Routino/src/test/no-super.sh
@@ -0,0 +1 @@
+a-b-c.sh
\ No newline at end of file
diff --git a/3rdparty/Routino/src/test/node-restrictions.osm b/3rdparty/Routino/src/test/node-restrictions.osm
new file mode 100644
index 0000000..5682e14
--- /dev/null
+++ b/3rdparty/Routino/src/test/node-restrictions.osm
@@ -0,0 +1,176 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' generator='JOSM'>
+  <node id='3' visible='true' version='1' lat='-0.2217201380129468' lon='-0.5209275966384278' />
+  <node id='4' visible='true' version='1' lat='-0.21828070777942268' lon='-0.5207912709437164' />
+  <node id='6' visible='true' version='1' lat='-0.21804206074333024' lon='-0.5205359496121407' />
+  <node id='8' visible='true' version='1' lat='-0.21778806952505525' lon='-0.52077169436654' />
+  <node id='10' visible='true' version='1' lat='-0.21802147020530807' lon='-0.5210285258597515' />
+  <node id='21' visible='true' version='1' lat='-0.2221908395649969' lon='-0.5209415430673436' />
+  <node id='22' visible='true' version='1' lat='-0.22195451857008858' lon='-0.5207002437384278' />
+  <node id='24' visible='true' version='1' lat='-0.22193543526189635' lon='-0.5211703062894754' />
+  <node id='44' visible='true' version='1' lat='-0.21823992390738106' lon='-0.5159271465477753' />
+  <node id='45' visible='true' version='1' lat='-0.2180027381687473' lon='-0.5156713934099496' />
+  <node id='46' visible='true' version='1' lat='-0.21774729558699316' lon='-0.515907564575113' />
+  <node id='47' visible='true' version='1' lat='-0.21798215306964172' lon='-0.5161639796064453' />
+  <node id='48' visible='true' version='1' lat='-0.2216713552163718' lon='-0.5160632301909843' />
+  <node id='49' visible='true' version='1' lat='-0.22214182669974075' lon='-0.5160772027310793' />
+  <node id='50' visible='true' version='1' lat='-0.22191520010406854' lon='-0.515835072317115' />
+  <node id='51' visible='true' version='1' lat='-0.22189614840042465' lon='-0.5163053654637676' />
+  <node id='52' visible='true' version='1' lat='-0.2206667536990629' lon='-0.5208930003039592' />
+  <node id='54' visible='true' version='1' lat='-0.22078436832897996' lon='-0.5160352169735775' />
+  <node id='56' visible='true' version='1' lat='-0.22042698690605275' lon='-0.5186225915804291' />
+  <node id='58' visible='true' version='1' lat='-0.22094865023036547' lon='-0.5184227225163068' />
+  <node id='60' visible='true' version='1' lat='-0.22045587324343277' lon='-0.5182381589000253' />
+  <node id='62' visible='true' version='1' lat='-0.2207458130009108' lon='-0.5180698985251141' />
+  <node id='69' visible='true' version='1' lat='-0.2202154498399145' lon='-0.5185426839821556'>
+    <tag k='name' v='WP06' />
+  </node>
+  <node id='70' visible='true' version='1' lat='-0.22013923019852472' lon='-0.5193421049505064' />
+  <node id='71' visible='true' version='1' lat='-0.22021187102420756' lon='-0.5186574474678166'>
+    <tag k='name' v='WP05' />
+  </node>
+  <node id='72' visible='true' version='1' lat='-0.2202119101259883' lon='-0.5179023077811183' />
+  <node id='73' visible='true' version='1' lat='-0.2201725235935236' lon='-0.518597315296112'>
+    <tag k='access' v='no' />
+    <tag k='barrier' v='bollard' />
+    <tag k='name' v='WP04' />
+  </node>
+  <node id='92' visible='true' version='1' lat='-0.2207386134847756' lon='-0.5178011278670027' />
+  <node id='95' visible='true' version='1' lat='-0.22096106893499964' lon='-0.5189278705598962' />
+  <node id='97' visible='true' version='1' lat='-0.2206940284663255' lon='-0.5192270362018531' />
+  <node id='117' visible='true' version='1' lat='-0.22038660084251202' lon='-0.519076345330358' />
+  <node id='144' visible='true' version='1' lat='-0.22069487557324122' lon='-0.5194891951207509' />
+  <node id='148' visible='true' version='1' lat='-0.2211969205428475' lon='-0.5185600325594629'>
+    <tag k='name' v='WP03' />
+  </node>
+  <node id='152' visible='true' version='1' lat='-0.22112295700820925' lon='-0.5193602055673212' />
+  <node id='154' visible='true' version='1' lat='-0.22116585790756746' lon='-0.517916154220049' />
+  <node id='204' visible='true' version='1' lat='-0.21955223220675274' lon='-0.5210161384621299'>
+    <tag k='name' v='WPstart' />
+  </node>
+  <node id='208' visible='true' version='1' lat='-0.21960114860694938' lon='-0.515860763795797'>
+    <tag k='name' v='WPfinish' />
+  </node>
+  <node id='769' visible='true' version='1' lat='-0.22115625040101256' lon='-0.5186154159129267'>
+    <tag k='barrier' v='bollard' />
+    <tag k='bicycle' v='yes' />
+    <tag k='foot' v='yes' />
+    <tag k='name' v='WP01' />
+  </node>
+  <node id='776' visible='true' version='1' lat='-0.2206818079575614' lon='-0.5201415124775847' />
+  <node id='778' visible='true' version='1' lat='-0.2190094723708295' lon='-0.5200753367664188'>
+    <tag k='barrier' v='bollard' />
+    <tag k='bicycle' v='yes' />
+    <tag k='foot' v='yes' />
+    <tag k='name' v='WP07' />
+  </node>
+  <node id='780' visible='true' version='1' lat='-0.2184198776926066' lon='-0.5200512715021757' />
+  <node id='790' action='modify' visible='true' version='1' lat='-0.22119409376129553' lon='-0.5186763001241391'>
+    <tag k='name' v='WP02' />
+  </node>
+  <node id='795' visible='true' version='1' lat='-0.21905497196353432' lon='-0.5200424520990057'>
+    <tag k='name' v='WP08' />
+  </node>
+  <way id='5' visible='true' version='1'>
+    <nd ref='3' />
+    <nd ref='52' />
+    <nd ref='4' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 1' />
+  </way>
+  <way id='13' visible='true' version='1'>
+    <nd ref='4' />
+    <nd ref='6' />
+    <nd ref='8' />
+    <nd ref='10' />
+    <nd ref='4' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='20' visible='true' version='1'>
+    <nd ref='21' />
+    <nd ref='22' />
+    <nd ref='3' />
+    <nd ref='24' />
+    <nd ref='21' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='41' visible='true' version='1'>
+    <nd ref='44' />
+    <nd ref='45' />
+    <nd ref='46' />
+    <nd ref='47' />
+    <nd ref='44' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='42' visible='true' version='1'>
+    <nd ref='48' />
+    <nd ref='54' />
+    <nd ref='44' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 2' />
+  </way>
+  <way id='43' visible='true' version='1'>
+    <nd ref='49' />
+    <nd ref='50' />
+    <nd ref='48' />
+    <nd ref='51' />
+    <nd ref='49' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='55' visible='true' version='1'>
+    <nd ref='144' />
+    <nd ref='152' />
+    <nd ref='769' />
+    <nd ref='154' />
+    <nd ref='92' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='somepass road' />
+  </way>
+  <way id='186' visible='true' version='1'>
+    <nd ref='54' />
+    <nd ref='92' />
+    <tag k='highway' v='unclassified' />
+    <tag k='name' v='high street' />
+  </way>
+  <way id='298' visible='true' version='1'>
+    <nd ref='144' />
+    <nd ref='70' />
+    <nd ref='73' />
+    <nd ref='72' />
+    <nd ref='92' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='nopass road' />
+  </way>
+  <way id='309' visible='true' version='1'>
+    <nd ref='92' />
+    <nd ref='62' />
+    <nd ref='60' />
+    <nd ref='58' />
+    <nd ref='56' />
+    <nd ref='95' />
+    <nd ref='117' />
+    <nd ref='97' />
+    <nd ref='144' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='long road' />
+  </way>
+  <way id='310' visible='true' version='1'>
+    <nd ref='144' />
+    <nd ref='776' />
+    <nd ref='52' />
+    <tag k='highway' v='unclassified' />
+    <tag k='name' v='high street' />
+  </way>
+  <way id='779' visible='true' version='1'>
+    <nd ref='776' />
+    <nd ref='778' />
+    <tag k='highway' v='unclassified' />
+    <tag k='name' v='dead end road' />
+  </way>
+  <way id='953' visible='true' version='1'>
+    <nd ref='778' />
+    <nd ref='780' />
+    <tag k='highway' v='unclassified' />
+    <tag k='name' v='private road' />
+  </way>
+</osm>
diff --git a/3rdparty/Routino/src/test/node-restrictions.sh b/3rdparty/Routino/src/test/node-restrictions.sh
new file mode 120000
index 0000000..b627b17
--- /dev/null
+++ b/3rdparty/Routino/src/test/node-restrictions.sh
@@ -0,0 +1 @@
+start-1-finish.sh
\ No newline at end of file
diff --git a/3rdparty/Routino/src/test/oneway-loop.osm b/3rdparty/Routino/src/test/oneway-loop.osm
new file mode 100644
index 0000000..78eaf6f
--- /dev/null
+++ b/3rdparty/Routino/src/test/oneway-loop.osm
@@ -0,0 +1,99 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' generator='JOSM'>
+  <node id='97' visible='true' version='1' lat='-0.2203330521761548' lon='-0.5194857377924652' />
+  <node id='95' visible='true' version='1' lat='-0.22040525704431851' lon='-0.517799295180183' />
+  <node id='3' visible='true' version='1' lat='-0.2217201380129468' lon='-0.5209275966384278' />
+  <node id='4' visible='true' version='1' lat='-0.21828070777942268' lon='-0.5207912709437164' />
+  <node id='6' visible='true' version='1' lat='-0.21804206074333024' lon='-0.5205359496121407' />
+  <node id='8' visible='true' version='1' lat='-0.21778806952505525' lon='-0.52077169436654' />
+  <node id='10' visible='true' version='1' lat='-0.21802147020530807' lon='-0.5210285258597515' />
+  <node id='21' visible='true' version='1' lat='-0.2221908395649969' lon='-0.5209415430673436' />
+  <node id='22' visible='true' version='1' lat='-0.22195451857008858' lon='-0.5207002437384278' />
+  <node id='24' visible='true' version='1' lat='-0.22193543526189635' lon='-0.5211703062894754' />
+  <node id='44' visible='true' version='1' lat='-0.21823992390738106' lon='-0.5159271465477753' />
+  <node id='45' visible='true' version='1' lat='-0.2180027381687473' lon='-0.5156713934099496' />
+  <node id='46' visible='true' version='1' lat='-0.21774729558699316' lon='-0.515907564575113' />
+  <node id='47' visible='true' version='1' lat='-0.21798215306964172' lon='-0.5161639796064453' />
+  <node id='48' visible='true' version='1' lat='-0.2216713552163718' lon='-0.5160632301909843' />
+  <node id='49' visible='true' version='1' lat='-0.22214182669974075' lon='-0.5160772027310793' />
+  <node id='50' visible='true' version='1' lat='-0.22191520010406854' lon='-0.515835072317115' />
+  <node id='51' visible='true' version='1' lat='-0.22189614840042465' lon='-0.5163053654637676' />
+  <node id='52' visible='true' version='1' lat='-0.2206667536990629' lon='-0.5208930003039592' />
+  <node id='54' visible='true' version='1' lat='-0.22078436832897996' lon='-0.5160352169735775' />
+  <node id='92' visible='true' version='1' lat='-0.2207386134847756' lon='-0.5178011278670027' />
+  <node id='117' visible='true' version='1' lat='-0.22021066917413948' lon='-0.5186050082043295'>
+    <tag k='name' v='WP01' />
+  </node>
+  <node id='144' visible='true' version='1' lat='-0.22069487557324122' lon='-0.5194891951207509' />
+  <node id='204' visible='true' version='1' lat='-0.21955223220675274' lon='-0.5210161384621299'>
+    <tag k='name' v='WPstart' />
+  </node>
+  <node id='208' visible='true' version='1' lat='-0.21960114860694938' lon='-0.515860763795797'>
+    <tag k='name' v='WPfinish' />
+  </node>
+  <way id='5' visible='true' version='1'>
+    <nd ref='3' />
+    <nd ref='52' />
+    <nd ref='4' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 1' />
+  </way>
+  <way id='13' visible='true' version='1'>
+    <nd ref='4' />
+    <nd ref='6' />
+    <nd ref='8' />
+    <nd ref='10' />
+    <nd ref='4' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='20' visible='true' version='1'>
+    <nd ref='21' />
+    <nd ref='22' />
+    <nd ref='3' />
+    <nd ref='24' />
+    <nd ref='21' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='41' visible='true' version='1'>
+    <nd ref='44' />
+    <nd ref='45' />
+    <nd ref='46' />
+    <nd ref='47' />
+    <nd ref='44' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='42' visible='true' version='1'>
+    <nd ref='48' />
+    <nd ref='54' />
+    <nd ref='44' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 2' />
+  </way>
+  <way id='43' visible='true' version='1'>
+    <nd ref='49' />
+    <nd ref='50' />
+    <nd ref='48' />
+    <nd ref='51' />
+    <nd ref='49' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='55' visible='true' version='1'>
+    <nd ref='52' />
+    <nd ref='144' />
+    <nd ref='92' />
+    <nd ref='54' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='high street' />
+    <tag k='oneway' v='yes' />
+  </way>
+  <way id='186' visible='true' version='1'>
+    <nd ref='92' />
+    <nd ref='95' />
+    <nd ref='117' />
+    <nd ref='97' />
+    <nd ref='144' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='reverse loop' />
+    <tag k='oneway' v='yes' />
+  </way>
+</osm>
diff --git a/3rdparty/Routino/src/test/oneway-loop.sh b/3rdparty/Routino/src/test/oneway-loop.sh
new file mode 120000
index 0000000..b627b17
--- /dev/null
+++ b/3rdparty/Routino/src/test/oneway-loop.sh
@@ -0,0 +1 @@
+start-1-finish.sh
\ No newline at end of file
diff --git a/3rdparty/Routino/src/test/only-split.sh b/3rdparty/Routino/src/test/only-split.sh
new file mode 100755
index 0000000..b823d8c
--- /dev/null
+++ b/3rdparty/Routino/src/test/only-split.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+# Exit on error
+
+set -e
+
+# Test name
+
+name=`basename $0 .sh`
+
+# Slim or non-slim
+
+if [ "$1" = "slim" ]; then
+    slim="-slim"
+    dir="slim"
+else
+    slim=""
+    dir="fat"
+fi
+
+# Pruned or non-pruned
+
+if [ "$2" = "prune" ]; then
+
+    case $name in
+        prune-isolated) prune="--prune-none --prune-isolated=100";;
+        prune-short)    prune="--prune-none --prune-short=5";;
+        prune-straight) prune="--prune-none --prune-straight=5";;
+        *)              prune="";;
+    esac
+
+    pruned="-pruned"
+else
+    prune="--prune-none"
+    pruned=""
+fi
+
+# Create the output directory
+
+dir="$dir$pruned"
+
+[ -d $dir ] || mkdir $dir
+
+# Run the programs under a run-time debugger
+
+debugger=valgrind
+debugger=
+
+# Name related options
+
+osm=$name.osm
+log=$name$slim$pruned.log
+
+option_prefix="--prefix=$name"
+option_dir="--dir=$dir"
+
+# Generic program options
+
+option_planetsplitter="--loggable --tagging=../../xml/routino-tagging.xml --errorlog $prune"
+option_filedumper="--dump-osm"
+
+# Run planetsplitter
+
+echo "Running planetsplitter"
+
+echo ../planetsplitter$slim $option_dir $option_prefix $option_planetsplitter $osm > $log
+$debugger ../planetsplitter$slim $option_dir $option_prefix $option_planetsplitter $osm >> $log
+
+# Run filedumper
+
+echo "Running filedumper"
+
+echo ../filedumper$slim $option_dir $option_prefix $option_filedumper >> $log
+$debugger ../filedumper$slim $option_dir $option_prefix $option_filedumper > $dir/$osm
+
diff --git a/3rdparty/Routino/src/test/prune-short.osm b/3rdparty/Routino/src/test/prune-short.osm
new file mode 100644
index 0000000..d78ef6e
--- /dev/null
+++ b/3rdparty/Routino/src/test/prune-short.osm
@@ -0,0 +1,629 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' generator='JOSM'>
+  <node id='3595' visible='true' version='1' lat='-0.22104660009157598' lon='-0.5159975959146365'>
+    <tag k='barrier' v='bollard' />
+  </node>
+  <node id='3594' visible='true' version='1' lat='-0.22045049050193835' lon='-0.5159942163952338' />
+  <node id='3593' visible='true' version='1' lat='-0.2201788312678428' lon='-0.5159976002642083' />
+  <node id='3592' visible='true' version='1' lat='-0.22045462692616266' lon='-0.5163068279854052' />
+  <node id='3591' visible='true' version='1' lat='-0.22044209075998147' lon='-0.5156633000250767' />
+  <node id='3288' visible='true' version='1' lat='-0.22109734126804137' lon='-0.5152506229571332' />
+  <node id='3217' visible='true' version='1' lat='-0.22113406029065996' lon='-0.5140671692051982' />
+  <node id='3179' visible='true' version='1' lat='-0.2210294380331181' lon='-0.5167574844040262'>
+    <tag k='barrier' v='bollard' />
+    <tag k='goods' v='yes' />
+    <tag k='motorcar' v='yes' />
+  </node>
+  <node id='3177' visible='true' version='1' lat='-0.2204158596326279' lon='-0.5178043240356551' />
+  <node id='3176' visible='true' version='1' lat='-0.22046453886858514' lon='-0.5152482570652049' />
+  <node id='3175' visible='true' version='1' lat='-0.22048093018165196' lon='-0.5145050025515154' />
+  <node id='3173' visible='true' version='1' lat='-0.22036977472541366' lon='-0.5200841499753365' />
+  <node id='3172' visible='true' version='1' lat='-0.22037260530871416' lon='-0.5186863255910119' />
+  <node id='3171' visible='true' version='1' lat='-0.22019287963474385' lon='-0.5152516409341795' />
+  <node id='3170' visible='true' version='1' lat='-0.22107893616237437' lon='-0.5145084240485217' />
+  <node id='3169' visible='true' version='1' lat='-0.22100970613768825' lon='-0.5174950919648864'>
+    <tag k='barrier' v='bollard' />
+  </node>
+  <node id='3168' visible='true' version='1' lat='-0.22012693295915078' lon='-0.5182599378763078' />
+  <node id='3166' visible='true' version='1' lat='-0.2203377650859623' lon='-0.5202133610231608' />
+  <node id='3165' visible='true' version='1' lat='-0.22034616420484693' lon='-0.5205477105564476' />
+  <node id='3164' visible='true' version='1' lat='-0.22101540883355839' lon='-0.519020790240951' />
+  <node id='3162' visible='true' version='1' lat='-0.2203656383011626' lon='-0.5197715383851653' />
+  <node id='3160' visible='true' version='1' lat='-0.22108342504232312' lon='-0.5159972875495841' />
+  <node id='3159' visible='true' version='1' lat='-0.22047253043973514' lon='-0.5141740861813582' />
+  <node id='3158' visible='true' version='1' lat='-0.22038100505069896' lon='-0.5190172419611692' />
+  <node id='3155' visible='true' version='1' lat='-0.22096555172390003' lon='-0.5197776970962421' />
+  <node id='3154' visible='true' version='1' lat='-0.22103299366341264' lon='-0.5182603413162163' />
+  <node id='3153' visible='true' version='1' lat='-0.22098056861233564' lon='-0.5205478256731001' />
+  <node id='3152' visible='true' version='1' lat='-0.22015988957621005' lon='-0.5167574467759948' />
+  <node id='3151' visible='true' version='1' lat='-0.2211153339602629' lon='-0.5145085508312978' />
+  <node id='3150' visible='true' version='1' lat='-0.220435685234862' lon='-0.5170666744971915' />
+  <node id='3148' visible='true' version='1' lat='-0.2201093458153487' lon='-0.5190206258301437' />
+  <node id='3147' visible='true' version='1' lat='-0.22104625848691606' lon='-0.5174952321326493' />
+  <node id='3146' visible='true' version='1' lat='-0.22094525908123056' lon='-0.5205478161580427' />
+  <node id='3145' visible='true' version='1' lat='-0.22035723855918068' lon='-0.5194406220150082' />
+  <node id='3144' visible='true' version='1' lat='-0.22097925560094275' lon='-0.5190206214805714' />
+  <node id='3143' visible='true' version='1' lat='-0.220468675292795' lon='-0.5155608686553763' />
+  <node id='3142' visible='true' version='1' lat='-0.22097252594183314' lon='-0.5210600600464496' />
+  <node id='3141' visible='true' version='1' lat='-0.22099644131416435' lon='-0.5182602011484532' />
+  <node id='3140' visible='true' version='1' lat='-0.22039859219419322' lon='-0.518256554007333' />
+  <node id='3139' visible='true' version='1' lat='-0.22007450559198807' lon='-0.5205476612622925' />
+  <node id='3137' visible='true' version='1' lat='-0.22042314906869445' lon='-0.5164231465368627' />
+  <node id='3136' visible='true' version='1' lat='-0.22045613912663242' lon='-0.5149173406950477' />
+  <node id='3135' visible='true' version='1' lat='-0.2210659903823021' lon='-0.5167576245717892' />
+  <node id='3134' visible='true' version='1' lat='-0.2202092709481208' lon='-0.5145083864204898' />
+  <node id='3133' visible='true' version='1' lat='-0.22106078891889977' lon='-0.5152504827893704'>
+    <tag k='junction' v='roundabout' />
+  </node>
+  <node id='3132' visible='true' version='1' lat='-0.2203851414749569' lon='-0.5193298535513403' />
+  <node id='3131' visible='true' version='1' lat='-0.22041172320838295' lon='-0.5174917124454843' />
+  <node id='3129' visible='true' version='1' lat='-0.2204027286184389' lon='-0.5185691655975043' />
+  <node id='3127' visible='true' version='1' lat='-0.22035030125222277' lon='-0.5208568889834893' />
+  <node id='3126' visible='true' version='1' lat='-0.22043154881062796' lon='-0.5167540629070206' />
+  <node id='3123' visible='true' version='1' lat='-0.2201400639735915' lon='-0.5174950963144586' />
+  <node id='3122' visible='true' version='1' lat='-0.220093979065534' lon='-0.5197749222541397' />
+  <node id='3120' visible='true' version='1' lat='-0.2204850666058679' lon='-0.5148176141416868' />
+  <node id='3119' visible='true' version='1' lat='-0.22040332346643296' lon='-0.5171607960753265' />
+  <node id='3118' visible='true' version='1' lat='-0.22039019245221977' lon='-0.5179256376371758' />
+  <node id='3116' visible='true' version='1' lat='-0.22100130433783766' lon='-0.5197781875878197' />
+  <node id='103' visible='true' version='1' lat='-0.2199921202808201' lon='-0.5215014225990243' />
+  <node id='105' visible='true' version='1' lat='-0.2200061092774588' lon='-0.5215256957971467' />
+  <node id='111' visible='true' version='1' lat='-0.21999591111254738' lon='-0.5213655177256614' />
+  <node id='113' visible='true' version='1' lat='-0.2199053434653081' lon='-0.5213683099539047' />
+  <node id='115' visible='true' version='1' lat='-0.2200003872856441' lon='-0.5212054858376033' />
+  <node id='117' visible='true' version='1' lat='-0.21995987449775212' lon='-0.5212056899383996' />
+  <node id='122' visible='true' version='1' lat='-0.21930388302075823' lon='-0.5204844403665726' />
+  <node id='124' visible='true' version='1' lat='-0.2183978198987466' lon='-0.520484275955765' />
+  <node id='126' visible='true' version='1' lat='-0.2186736155898939' lon='-0.5207935036769619' />
+  <node id='127' visible='true' version='1' lat='-0.21866947916516918' lon='-0.5204808920867906' />
+  <node id='130' visible='true' version='1' lat='-0.21866107942222732' lon='-0.5201499757166331' />
+  <node id='140' visible='true' version='1' lat='-0.21889092115998834' lon='-0.520482130632451' />
+  <node id='142' visible='true' version='1' lat='-0.21892747351440356' lon='-0.520482270800214' />
+  <node id='175' visible='true' version='1' lat='-0.21894694698945158' lon='-0.5197095317920613' />
+  <node id='176' visible='true' version='1' lat='-0.2184172933744773' lon='-0.5197115369476123' />
+  <node id='177' visible='true' version='1' lat='-0.21868895264054233' lon='-0.5197081530786378' />
+  <node id='178' visible='true' version='1' lat='-0.21869308906526194' lon='-0.520020764668809' />
+  <node id='179' visible='true' version='1' lat='-0.21868055289761731' lon='-0.5193772367084805' />
+  <node id='180' visible='true' version='1' lat='-0.21891039463507056' lon='-0.5197093916242983' />
+  <node id='183' visible='true' version='1' lat='-0.21932461874859735' lon='-0.5197148022812921' />
+  <node id='203' visible='true' version='1' lat='-0.21933872324591014' lon='-0.5189574049344235' />
+  <node id='204' visible='true' version='1' lat='-0.21896231374044123' lon='-0.5189552353680651' />
+  <node id='205' visible='true' version='1' lat='-0.21843266012600215' lon='-0.518957240523616' />
+  <node id='206' visible='true' version='1' lat='-0.21870431939180376' lon='-0.5189538566546416' />
+  <node id='207' visible='true' version='1' lat='-0.21870845581652365' lon='-0.5192664682448129' />
+  <node id='208' visible='true' version='1' lat='-0.21869591964887972' lon='-0.5186229402844842' />
+  <node id='209' visible='true' version='1' lat='-0.21892576138609787' lon='-0.518955095200302' />
+  <node id='242' visible='true' version='1' lat='-0.2187135067943563' lon='-0.5178622523306481' />
+  <node id='243' visible='true' version='1' lat='-0.21935631039062914' lon='-0.5181967169805877' />
+  <node id='244' visible='true' version='1' lat='-0.21845024727178483' lon='-0.5181965525697801' />
+  <node id='245' visible='true' version='1' lat='-0.21894334853131397' lon='-0.5181944072464661' />
+  <node id='246' visible='true' version='1' lat='-0.21897990088560967' lon='-0.5181945474142293' />
+  <node id='247' visible='true' version='1' lat='-0.21872604296198137' lon='-0.5185057802909768' />
+  <node id='248' visible='true' version='1' lat='-0.21872190653727555' lon='-0.5181931687008056' />
+  <node id='263' visible='true' version='1' lat='-0.22000344006187805' lon='-0.5209828473984814' />
+  <node id='265' visible='true' version='1' lat='-0.219420576342371' lon='-0.5151870004920865' />
+  <node id='278' visible='true' version='1' lat='-0.21904569740319257' lon='-0.5151860679810479'>
+    <tag k='junction' v='roundabout' />
+  </node>
+  <node id='279' visible='true' version='1' lat='-0.21878770305599066' lon='-0.5151846892676242' />
+  <node id='281' visible='true' version='1' lat='-0.21877930331311232' lon='-0.5148537728974668' />
+  <node id='282' visible='true' version='1' lat='-0.21900914504905303' lon='-0.5151859278132848' />
+  <node id='283' visible='true' version='1' lat='-0.21851604379168485' lon='-0.5151880731365988' />
+  <node id='284' visible='true' version='1' lat='-0.21879183948067282' lon='-0.5154973008577955' />
+  <node id='306' visible='true' version='1' lat='-0.2194386483838444' lon='-0.5144451655247703' />
+  <node id='307' visible='true' version='1' lat='-0.21906223888087323' lon='-0.5144429959584117' />
+  <node id='308' visible='true' version='1' lat='-0.21853258526998015' lon='-0.5144450011139624' />
+  <node id='309' visible='true' version='1' lat='-0.21880424453396874' lon='-0.514441617244988' />
+  <node id='310' visible='true' version='1' lat='-0.21880838095864102' lon='-0.5147542288351594' />
+  <node id='311' visible='true' version='1' lat='-0.21879584479109798' lon='-0.5141107008748307' />
+  <node id='312' visible='true' version='1' lat='-0.2190256865268027' lon='-0.5144428557906486' />
+  <node id='335' visible='true' version='1' lat='-0.21936944140574963' lon='-0.5174318754187385' />
+  <node id='336' visible='true' version='1' lat='-0.21899303190104727' lon='-0.51742970585238' />
+  <node id='337' visible='true' version='1' lat='-0.2184633782877009' lon='-0.5174317110079311' />
+  <node id='338' visible='true' version='1' lat='-0.21873503755293217' lon='-0.5174283271389567' />
+  <node id='339' visible='true' version='1' lat='-0.21873917397764245' lon='-0.5177409387291276' />
+  <node id='340' visible='true' version='1' lat='-0.21872663781003568' lon='-0.517097410768799' />
+  <node id='341' visible='true' version='1' lat='-0.21944646904283585' lon='-0.5139990438249045' />
+  <node id='342' visible='true' version='1' lat='-0.21895647954678618' lon='-0.517429565684617'>
+    <tag k='barrier' v='bollard' />
+  </node>
+  <node id='343' visible='true' version='1' lat='-0.21929584034936425' lon='-0.520996674739922' />
+  <node id='345' visible='true' version='1' lat='-0.22192916244766508' lon='-0.514332326947849' />
+  <node id='347' visible='true' version='1' lat='-0.2219482141512544' lon='-0.5138620338011963' />
+  <node id='349' visible='true' version='1' lat='-0.22217484074642313' lon='-0.5141041642151607' />
+  <node id='351' visible='true' version='1' lat='-0.22170436926410486' lon='-0.5140901916750656' />
+  <node id='353' visible='true' version='1' lat='-0.21801516712553526' lon='-0.5141909410905267' />
+  <node id='355' visible='true' version='1' lat='-0.2177803096434024' lon='-0.5139345260591944' />
+  <node id='357' visible='true' version='1' lat='-0.2180357522245965' lon='-0.5136983548940309' />
+  <node id='359' visible='true' version='1' lat='-0.21827293796270247' lon='-0.5139541080318566' />
+  <node id='361' visible='true' version='1' lat='-0.22193543526189635' lon='-0.5213371153581924' />
+  <node id='363' visible='true' version='1' lat='-0.22195451857008858' lon='-0.5208670528071448' />
+  <node id='365' visible='true' version='1' lat='-0.2221908395649969' lon='-0.5211083521360607' />
+  <node id='367' visible='true' version='1' lat='-0.21802147020530807' lon='-0.5211953349284685' />
+  <node id='369' visible='true' version='1' lat='-0.21778806952505525' lon='-0.520938503435257' />
+  <node id='371' visible='true' version='1' lat='-0.21804206074333024' lon='-0.5207027586808577' />
+  <node id='373' visible='true' version='1' lat='-0.21828070777942268' lon='-0.5209580800124335' />
+  <node id='375' visible='true' version='1' lat='-0.2217201380129468' lon='-0.5210944057071448' />
+  <node id='1819' visible='true' version='1' lat='-0.21874646341451853' lon='-0.5163597612303352' />
+  <node id='1820' visible='true' version='1' lat='-0.21848320389252793' lon='-0.5166940614694673' />
+  <node id='1821' visible='true' version='1' lat='-0.21875486315739293' lon='-0.516690677600493' />
+  <node id='1822' visible='true' version='1' lat='-0.21901285750516775' lon='-0.5166920563139161'>
+    <tag k='barrier' v='bollard' />
+    <tag k='goods' v='yes' />
+    <tag k='motorcar' v='yes' />
+  </node>
+  <node id='1823' visible='true' version='1' lat='-0.2189763051509611' lon='-0.5166919161461533'>
+    <tag k='barrier' v='bollard' />
+    <tag k='hgv' v='yes' />
+    <tag k='psv' v='yes' />
+  </node>
+  <node id='1824' visible='true' version='1' lat='-0.21875899958209588' lon='-0.517003289190664' />
+  <node id='1825' visible='true' version='1' lat='-0.21938926700936567' lon='-0.5166942258802748' />
+  <node id='1855' visible='true' version='1' lat='-0.21876553724829867' lon='-0.515600619980971' />
+  <node id='1856' visible='true' version='1' lat='-0.2189953789844518' lon='-0.515932774896789'>
+    <tag k='barrier' v='bollard' />
+  </node>
+  <node id='1857' visible='true' version='1' lat='-0.21877393699118441' lon='-0.5159315363511282' />
+  <node id='1858' visible='true' version='1' lat='-0.21940681027814252' lon='-0.5159338475755908' />
+  <node id='1859' visible='true' version='1' lat='-0.2190319313386278' lon='-0.515932915064552'>
+    <tag k='barrier' v='bollard' />
+  </node>
+  <node id='1860' visible='true' version='1' lat='-0.21850227772663344' lon='-0.5159349202201028' />
+  <node id='1861' visible='true' version='1' lat='-0.21877807341587224' lon='-0.5162441479412996' />
+  <node id='1875' visible='true' version='1' lat='-0.220001904692577' lon='-0.5210251383845648' />
+  <way id='3600' visible='true' version='1'>
+    <nd ref='3592' />
+    <nd ref='3594' />
+    <nd ref='3591' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3599' visible='true' version='1'>
+    <nd ref='3595' />
+    <nd ref='3594' />
+    <nd ref='3593' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3598' visible='true' version='1'>
+    <nd ref='3160' />
+    <nd ref='3595' />
+    <tag k='highway' v='footway' />
+  </way>
+  <way id='3294' visible='true' version='1'>
+    <nd ref='3151' />
+    <nd ref='3170' />
+    <nd ref='3175' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3246' visible='true' version='1'>
+    <nd ref='3179' />
+    <nd ref='3126' />
+    <nd ref='3152' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3245' visible='true' version='1'>
+    <nd ref='3135' />
+    <nd ref='3179' />
+    <tag k='goods' v='no' />
+    <tag k='highway' v='residential' />
+    <tag k='motorcar' v='no' />
+  </way>
+  <way id='3240' visible='true' version='1'>
+    <nd ref='1823' />
+    <nd ref='1821' />
+    <nd ref='1820' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3239' visible='true' version='1'>
+    <nd ref='1822' />
+    <nd ref='1823' />
+    <tag k='highway' v='residential' />
+    <tag k='moped' v='no' />
+    <tag k='motorcycle' v='no' />
+  </way>
+  <way id='3234' visible='true' version='1'>
+    <nd ref='3147' />
+    <nd ref='3169' />
+    <nd ref='3131' />
+    <nd ref='3123' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3211' visible='true' version='1'>
+    <nd ref='3132' />
+    <nd ref='3158' />
+    <nd ref='3172' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3210' visible='true' version='1'>
+    <nd ref='3164' />
+    <nd ref='3144' />
+    <tag k='highway' v='residential' />
+    <tag k='motor_vehicle' v='no' />
+    <tag k='name' v='different transport types' />
+  </way>
+  <way id='3209' visible='true' version='1'>
+    <nd ref='3153' />
+    <nd ref='3146' />
+    <nd ref='3165' />
+    <nd ref='3139' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3207' visible='true' version='1'>
+    <nd ref='3177' />
+    <nd ref='3131' />
+    <nd ref='3119' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3206' visible='true' version='1'>
+    <nd ref='3288' />
+    <nd ref='3133' />
+    <nd ref='3176' />
+    <nd ref='3171' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3205' visible='true' version='1'>
+    <nd ref='3155' />
+    <nd ref='3162' />
+    <nd ref='3122' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3204' visible='true' version='1'>
+    <nd ref='3175' />
+    <nd ref='3159' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3203' visible='true' version='1'>
+    <nd ref='3129' />
+    <nd ref='3140' />
+    <nd ref='3118' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3202' visible='true' version='1'>
+    <nd ref='3116' />
+    <nd ref='3155' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='different oneway property' />
+    <tag k='oneway' v='yes' />
+  </way>
+  <way id='3201' visible='true' version='1'>
+    <nd ref='3154' />
+    <nd ref='3141' />
+    <tag k='highway' v='residential' />
+    <tag k='maxwidth' v='3m' />
+    <tag k='name' v='different highway properties' />
+  </way>
+  <way id='3200' visible='true' version='1'>
+    <nd ref='3175' />
+    <nd ref='3134' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3198' visible='true' version='1'>
+    <nd ref='3144' />
+    <nd ref='3158' />
+    <nd ref='3148' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3196' visible='true' version='1'>
+    <nd ref='3173' />
+    <nd ref='3162' />
+    <nd ref='3145' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3195' visible='true' version='1'>
+    <nd ref='3141' />
+    <nd ref='3140' />
+    <nd ref='3168' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3193' visible='true' version='1'>
+    <nd ref='3120' />
+    <nd ref='3175' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3191' visible='true' version='1'>
+    <nd ref='3127' />
+    <nd ref='3165' />
+    <nd ref='3166' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3190' visible='true' version='1'>
+    <nd ref='3142' />
+    <nd ref='3153' />
+    <nd ref='3116' />
+    <nd ref='3164' />
+    <nd ref='3154' />
+    <nd ref='3147' />
+    <nd ref='3135' />
+    <nd ref='3160' />
+    <nd ref='3288' />
+    <nd ref='3151' />
+    <nd ref='3217' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='high street' />
+  </way>
+  <way id='3186' visible='true' version='1'>
+    <nd ref='3143' />
+    <nd ref='3176' />
+    <nd ref='3136' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='3182' visible='true' version='1'>
+    <nd ref='3150' />
+    <nd ref='3126' />
+    <nd ref='3137' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='104' visible='true' version='1'>
+    <nd ref='263' />
+    <nd ref='1875' />
+    <nd ref='115' />
+    <nd ref='111' />
+    <nd ref='103' />
+    <nd ref='105' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='114' visible='true' version='1'>
+    <nd ref='111' />
+    <nd ref='113' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='118' visible='true' version='1'>
+    <nd ref='115' />
+    <nd ref='117' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='125' visible='true' version='1'>
+    <nd ref='122' />
+    <nd ref='142' />
+    <nd ref='140' />
+    <nd ref='127' />
+    <nd ref='124' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='128' visible='true' version='1'>
+    <nd ref='126' />
+    <nd ref='127' />
+    <nd ref='130' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='181' visible='true' version='1'>
+    <nd ref='183' />
+    <nd ref='175' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='182' visible='true' version='1'>
+    <nd ref='178' />
+    <nd ref='177' />
+    <nd ref='179' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='187' visible='true' version='1'>
+    <nd ref='175' />
+    <nd ref='180' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='different oneway property' />
+    <tag k='oneway' v='yes' />
+  </way>
+  <way id='188' visible='true' version='1'>
+    <nd ref='180' />
+    <nd ref='177' />
+    <nd ref='176' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='210' visible='true' version='1'>
+    <nd ref='203' />
+    <nd ref='204' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='211' visible='true' version='1'>
+    <nd ref='207' />
+    <nd ref='206' />
+    <nd ref='208' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='214' visible='true' version='1'>
+    <nd ref='204' />
+    <nd ref='209' />
+    <tag k='highway' v='residential' />
+    <tag k='motor_vehicle' v='no' />
+    <tag k='name' v='different transport types' />
+  </way>
+  <way id='215' visible='true' version='1'>
+    <nd ref='209' />
+    <nd ref='206' />
+    <nd ref='205' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='249' visible='true' version='1'>
+    <nd ref='247' />
+    <nd ref='248' />
+    <nd ref='242' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='250' visible='true' version='1'>
+    <nd ref='243' />
+    <nd ref='246' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='251' visible='true' version='1'>
+    <nd ref='245' />
+    <nd ref='248' />
+    <nd ref='244' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='252' visible='true' version='1'>
+    <nd ref='246' />
+    <nd ref='245' />
+    <tag k='highway' v='residential' />
+    <tag k='maxwidth' v='3m' />
+    <tag k='name' v='different highway properties' />
+  </way>
+  <way id='285' visible='true' version='1'>
+    <nd ref='284' />
+    <nd ref='279' />
+    <nd ref='281' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='286' visible='true' version='1'>
+    <nd ref='282' />
+    <nd ref='279' />
+    <nd ref='283' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='287' visible='true' version='1'>
+    <nd ref='265' />
+    <nd ref='278' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='288' visible='true' version='1'>
+    <nd ref='278' />
+    <nd ref='282' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='313' visible='true' version='1'>
+    <nd ref='306' />
+    <nd ref='307' />
+    <nd ref='312' />
+    <nd ref='309' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='314' visible='true' version='1'>
+    <nd ref='310' />
+    <nd ref='309' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='317' visible='true' version='1'>
+    <nd ref='309' />
+    <nd ref='311' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='319' visible='true' version='1'>
+    <nd ref='309' />
+    <nd ref='308' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='342' visible='true' version='1'>
+    <nd ref='335' />
+    <nd ref='336' />
+    <nd ref='342' />
+    <nd ref='338' />
+    <nd ref='337' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='343' visible='true' version='1'>
+    <nd ref='339' />
+    <nd ref='338' />
+    <nd ref='340' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='393' visible='true' version='1'>
+    <nd ref='349' />
+    <nd ref='347' />
+    <nd ref='351' />
+    <nd ref='345' />
+    <nd ref='349' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='395' visible='true' version='1'>
+    <nd ref='351' />
+    <nd ref='3217' />
+    <nd ref='341' />
+    <nd ref='359' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 2' />
+  </way>
+  <way id='397' visible='true' version='1'>
+    <nd ref='359' />
+    <nd ref='357' />
+    <nd ref='355' />
+    <nd ref='353' />
+    <nd ref='359' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='399' visible='true' version='1'>
+    <nd ref='365' />
+    <nd ref='363' />
+    <nd ref='375' />
+    <nd ref='361' />
+    <nd ref='365' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='401' visible='true' version='1'>
+    <nd ref='373' />
+    <nd ref='371' />
+    <nd ref='369' />
+    <nd ref='367' />
+    <nd ref='373' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='403' visible='true' version='1'>
+    <nd ref='375' />
+    <nd ref='3142' />
+    <nd ref='1875' />
+    <nd ref='343' />
+    <nd ref='373' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 1' />
+  </way>
+  <way id='1826' visible='true' version='1'>
+    <nd ref='1825' />
+    <nd ref='1822' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='1827' visible='true' version='1'>
+    <nd ref='1824' />
+    <nd ref='1821' />
+    <nd ref='1819' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='1862' visible='true' version='1'>
+    <nd ref='1859' />
+    <nd ref='1856' />
+    <tag k='highway' v='footway' />
+  </way>
+  <way id='1863' visible='true' version='1'>
+    <nd ref='1858' />
+    <nd ref='1859' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='1864' visible='true' version='1'>
+    <nd ref='1861' />
+    <nd ref='1857' />
+    <nd ref='1855' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='1865' visible='true' version='1'>
+    <nd ref='1856' />
+    <nd ref='1857' />
+    <nd ref='1860' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='1872' visible='true' version='1'>
+    <nd ref='343' />
+    <nd ref='122' />
+    <nd ref='183' />
+    <nd ref='203' />
+    <nd ref='243' />
+    <nd ref='335' />
+    <nd ref='1825' />
+    <nd ref='1858' />
+    <nd ref='265' />
+    <nd ref='306' />
+    <nd ref='341' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='high street' />
+  </way>
+  <relation id='3300' visible='true' version='1'>
+    <member type='way' ref='3294' role='from' />
+    <member type='way' ref='3204' role='to' />
+    <member type='node' ref='3175' role='via' />
+    <tag k='restriction' v='no_right_turn' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='323' visible='true' version='1'>
+    <member type='way' ref='313' role='from' />
+    <member type='node' ref='309' role='via' />
+    <member type='way' ref='317' role='to' />
+    <tag k='restriction' v='no_right_turn' />
+    <tag k='type' v='restriction' />
+  </relation>
+</osm>
diff --git a/3rdparty/Routino/src/test/prune-short.sh b/3rdparty/Routino/src/test/prune-short.sh
new file mode 120000
index 0000000..bc8f799
--- /dev/null
+++ b/3rdparty/Routino/src/test/prune-short.sh
@@ -0,0 +1 @@
+only-split.sh
\ No newline at end of file
diff --git a/3rdparty/Routino/src/test/prune-straight.osm b/3rdparty/Routino/src/test/prune-straight.osm
new file mode 100644
index 0000000..27fe79c
--- /dev/null
+++ b/3rdparty/Routino/src/test/prune-straight.osm
@@ -0,0 +1,167 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' generator='JOSM'>
+  <node id='122' visible='true' version='1' lat='-0.2202806356012029' lon='-0.5205283172729586' />
+  <node id='183' visible='true' version='1' lat='-0.22026900997513588' lon='-0.5197565898111836' />
+  <node id='203' visible='true' version='1' lat='-0.22025358651939986' lon='-0.5189993952842524' />
+  <node id='243' visible='true' version='1' lat='-0.22030070161517012' lon='-0.518238504510479' />
+  <node id='265' visible='true' version='1' lat='-0.22036496756284105' lon='-0.5152287880219779' />
+  <node id='306' visible='true' version='1' lat='-0.2204170113536037' lon='-0.5145041750343666' />
+  <node id='335' visible='true' version='1' lat='-0.22034764780366026' lon='-0.5174764910312685' />
+  <node id='341' visible='true' version='1' lat='-0.22039086026167154' lon='-0.514040831354796' />
+  <node id='343' visible='true' version='1' lat='-0.22024023157772424' lon='-0.5210384622698134' />
+  <node id='345' visible='true' version='1' lat='-0.22192916244766508' lon='-0.514332326947849' />
+  <node id='347' visible='true' version='1' lat='-0.2219482141512544' lon='-0.5138620338011963' />
+  <node id='349' visible='true' version='1' lat='-0.22217484074642313' lon='-0.5141041642151607' />
+  <node id='351' visible='true' version='1' lat='-0.22170436926410486' lon='-0.5140901916750656' />
+  <node id='353' visible='true' version='1' lat='-0.21801516712553526' lon='-0.5141909410905267' />
+  <node id='355' visible='true' version='1' lat='-0.2177803096434024' lon='-0.5139345260591944' />
+  <node id='357' visible='true' version='1' lat='-0.2180357522245965' lon='-0.5136983548940309' />
+  <node id='359' visible='true' version='1' lat='-0.21827293796270247' lon='-0.5139541080318566' />
+  <node id='361' visible='true' version='1' lat='-0.22193543526189635' lon='-0.5213371153581924' />
+  <node id='363' visible='true' version='1' lat='-0.22195451857008858' lon='-0.5208670528071448' />
+  <node id='365' visible='true' version='1' lat='-0.2221908395649969' lon='-0.5211083521360607' />
+  <node id='367' visible='true' version='1' lat='-0.21802147020530807' lon='-0.5211953349284685' />
+  <node id='369' visible='true' version='1' lat='-0.21778806952505525' lon='-0.520938503435257' />
+  <node id='371' visible='true' version='1' lat='-0.21804206074333024' lon='-0.5207027586808577' />
+  <node id='373' visible='true' version='1' lat='-0.21828070777942268' lon='-0.5209580800124335' />
+  <node id='375' visible='true' version='1' lat='-0.2217201380129468' lon='-0.5210944057071448' />
+  <node id='514' visible='true' version='1' lat='-0.21911648466865563' lon='-0.5204548928241738' />
+  <node id='515' visible='true' version='1' lat='-0.21931060134759067' lon='-0.5197122066404057' />
+  <node id='516' visible='true' version='1' lat='-0.21951085842814533' lon='-0.518931170696933' />
+  <node id='517' visible='true' version='1' lat='-0.21935410979490197' lon='-0.5181411739474401' />
+  <node id='518' visible='true' version='1' lat='-0.2192550922021173' lon='-0.5174174318869332' />
+  <node id='519' visible='true' version='1' lat='-0.21937528739938633' lon='-0.516691643624375' />
+  <node id='520' visible='true' version='1' lat='-0.21954923963370723' lon='-0.5159137876476338' />
+  <node id='521' visible='true' version='1' lat='-0.21940663828868845' lon='-0.5151846420097191' />
+  <node id='522' visible='true' version='1' lat='-0.21930348406326042' lon='-0.5144366602347327' />
+  <node id='524' visible='true' version='1' lat='-0.2192811120690243' lon='-0.520994928100946' />
+  <node id='529' visible='true' version='1' lat='-0.219443360641783' lon='-0.5140020337469828' />
+  <node id='537' visible='true' version='1' lat='-0.2193329757546545' lon='-0.5142619714135797' />
+  <node id='539' visible='true' version='1' lat='-0.21930594099502726' lon='-0.5146628218111022' />
+  <node id='541' visible='true' version='1' lat='-0.21952184242087056' lon='-0.5156033304324728' />
+  <node id='543' visible='true' version='1' lat='-0.21950279450540236' lon='-0.516181349042567' />
+  <node id='545' visible='true' version='1' lat='-0.219277127340726' lon='-0.5171568636654659' />
+  <node id='547' visible='true' version='1' lat='-0.2192703091822638' lon='-0.5176842973588277' />
+  <node id='549' visible='true' version='1' lat='-0.2194822077936952' lon='-0.5186881745363406' />
+  <node id='551' visible='true' version='1' lat='-0.21947150748538968' lon='-0.5192131869020143' />
+  <node id='553' visible='true' version='1' lat='-0.21916581010325425' lon='-0.5202070286137637' />
+  <node id='555' visible='true' version='1' lat='-0.2191502071646719' lon='-0.5206793428462938' />
+  <node id='1825' visible='true' version='1' lat='-0.2203336582318136' lon='-0.5167360134101662' />
+  <node id='1858' visible='true' version='1' lat='-0.22031968292631743' lon='-0.5159743875972973' />
+  <node id='3116' visible='true' version='1' lat='-0.22100130433783766' lon='-0.5197781875878197' />
+  <node id='3135' visible='true' version='1' lat='-0.2210659903823021' lon='-0.5167576245717892' />
+  <node id='3142' visible='true' version='1' lat='-0.22097252594183314' lon='-0.5210600600464496' />
+  <node id='3147' visible='true' version='1' lat='-0.22104625848691606' lon='-0.5174952321326493' />
+  <node id='3151' visible='true' version='1' lat='-0.2211153339602629' lon='-0.5145085508312978' />
+  <node id='3153' visible='true' version='1' lat='-0.22098056861233564' lon='-0.5205478256731001' />
+  <node id='3154' visible='true' version='1' lat='-0.22103299366341264' lon='-0.5182603413162163' />
+  <node id='3160' visible='true' version='1' lat='-0.22108342504232312' lon='-0.5159972875495841' />
+  <node id='3164' visible='true' version='1' lat='-0.22101540883355839' lon='-0.519020790240951' />
+  <node id='3217' visible='true' version='1' lat='-0.22113406029065996' lon='-0.5140671692051982' />
+  <node id='3288' visible='true' version='1' lat='-0.22109734126804137' lon='-0.5152506229571332' />
+  <way id='393' visible='true' version='1'>
+    <nd ref='349' />
+    <nd ref='347' />
+    <nd ref='351' />
+    <nd ref='345' />
+    <nd ref='349' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='395' visible='true' version='1'>
+    <nd ref='351' />
+    <nd ref='3217' />
+    <nd ref='341' />
+    <nd ref='529' />
+    <nd ref='359' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 2' />
+  </way>
+  <way id='397' visible='true' version='1'>
+    <nd ref='359' />
+    <nd ref='357' />
+    <nd ref='355' />
+    <nd ref='353' />
+    <nd ref='359' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='399' visible='true' version='1'>
+    <nd ref='365' />
+    <nd ref='363' />
+    <nd ref='375' />
+    <nd ref='361' />
+    <nd ref='365' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='401' visible='true' version='1'>
+    <nd ref='373' />
+    <nd ref='371' />
+    <nd ref='369' />
+    <nd ref='367' />
+    <nd ref='373' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='403' visible='true' version='1'>
+    <nd ref='375' />
+    <nd ref='3142' />
+    <nd ref='343' />
+    <nd ref='524' />
+    <nd ref='373' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 1' />
+  </way>
+  <way id='512' visible='true' version='1'>
+    <nd ref='524' />
+    <nd ref='555' />
+    <nd ref='514' />
+    <nd ref='553' />
+    <nd ref='515' />
+    <nd ref='551' />
+    <nd ref='516' />
+    <nd ref='549' />
+    <nd ref='517' />
+    <nd ref='547' />
+    <nd ref='518' />
+    <nd ref='545' />
+    <nd ref='519' />
+    <nd ref='543' />
+    <nd ref='520' />
+    <nd ref='541' />
+    <nd ref='521' />
+    <nd ref='539' />
+    <nd ref='522' />
+    <nd ref='537' />
+    <nd ref='529' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='very wiggly road' />
+  </way>
+  <way id='1872' visible='true' version='1'>
+    <nd ref='343' />
+    <nd ref='122' />
+    <nd ref='183' />
+    <nd ref='203' />
+    <nd ref='243' />
+    <nd ref='335' />
+    <nd ref='1825' />
+    <nd ref='1858' />
+    <nd ref='265' />
+    <nd ref='306' />
+    <nd ref='341' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='wiggly road' />
+  </way>
+  <way id='3190' visible='true' version='1'>
+    <nd ref='3142' />
+    <nd ref='3153' />
+    <nd ref='3116' />
+    <nd ref='3164' />
+    <nd ref='3154' />
+    <nd ref='3147' />
+    <nd ref='3135' />
+    <nd ref='3160' />
+    <nd ref='3288' />
+    <nd ref='3151' />
+    <nd ref='3217' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='straight road' />
+  </way>
+</osm>
diff --git a/3rdparty/Routino/src/test/prune-straight.sh b/3rdparty/Routino/src/test/prune-straight.sh
new file mode 120000
index 0000000..bc8f799
--- /dev/null
+++ b/3rdparty/Routino/src/test/prune-straight.sh
@@ -0,0 +1 @@
+only-split.sh
\ No newline at end of file
diff --git a/3rdparty/Routino/src/test/roundabout-waypoints.osm b/3rdparty/Routino/src/test/roundabout-waypoints.osm
new file mode 100644
index 0000000..3579a74
--- /dev/null
+++ b/3rdparty/Routino/src/test/roundabout-waypoints.osm
@@ -0,0 +1,105 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' generator='JOSM'>
+  <node id='3' visible='true' version='1' lat='-0.2217201380129468' lon='-0.5209275966384278' />
+  <node id='4' visible='true' version='1' lat='-0.21828070777942268' lon='-0.5207912709437164' />
+  <node id='6' visible='true' version='1' lat='-0.21804206074333024' lon='-0.5205359496121407' />
+  <node id='8' visible='true' version='1' lat='-0.21778806952505525' lon='-0.52077169436654' />
+  <node id='10' visible='true' version='1' lat='-0.21802147020530807' lon='-0.5210285258597515' />
+  <node id='21' visible='true' version='1' lat='-0.2221908395649969' lon='-0.5209415430673436' />
+  <node id='22' visible='true' version='1' lat='-0.22195451857008858' lon='-0.5207002437384278' />
+  <node id='24' visible='true' version='1' lat='-0.22193543526189635' lon='-0.5211703062894754' />
+  <node id='204' visible='true' version='1' lat='-0.21845168535119228' lon='-0.5209389065396647'>
+    <tag k='name' v='WPstart' />
+  </node>
+  <node id='208' visible='true' version='1' lat='-0.22155124019804942' lon='-0.5210546105815851'>
+    <tag k='name' v='WPfinish' />
+  </node>
+  <node id='242' visible='true' version='1' lat='-0.21969184942143533' lon='-0.520508838695913'>
+    <tag k='name' v='WP03' />
+  </node>
+  <node id='244' visible='true' version='1' lat='-0.2200812203297903' lon='-0.5205220270076113'>
+    <tag k='name' v='WP05' />
+  </node>
+  <node id='246' visible='true' version='1' lat='-0.21966460614165306' lon='-0.5211903128432791' />
+  <node id='248' visible='true' version='1' lat='-0.22006229057645915' lon='-0.5212037827409091' />
+  <node id='253' visible='true' version='1' lat='-0.21927153579637806' lon='-0.5195315927529504' />
+  <node id='255' visible='true' version='1' lat='-0.2207678018006232' lon='-0.5197417721359917' />
+  <node id='257' visible='true' version='1' lat='-0.22054261127446687' lon='-0.5220737624335469' />
+  <node id='259' visible='true' version='1' lat='-0.21914142570197062' lon='-0.5220187154522741' />
+  <node id='269' visible='true' version='1' lat='-0.21987704814393666' lon='-0.5204373658084384'>
+    <tag k='name' v='WP04' />
+  </node>
+  <node id='270' visible='true' version='1' lat='-0.2202373530002358' lon='-0.5206475451914799'>
+    <tag k='name' v='WP06' />
+  </node>
+  <node id='345' visible='true' version='1' lat='-0.22026866394788633' lon='-0.5208635679861234'>
+    <tag k='name' v='WP07' />
+  </node>
+  <node id='381' visible='true' version='1' lat='-0.21952244127387813' lon='-0.5206514738187112'>
+    <tag k='name' v='WP02' />
+  </node>
+  <node id='438' visible='true' version='1' lat='-0.21948172568612254' lon='-0.5208369137424373'>
+    <tag k='name' v='WP01' />
+  </node>
+  <way id='5' visible='true' version='1'>
+    <nd ref='3' />
+    <nd ref='345' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 2' />
+  </way>
+  <way id='13' visible='true' version='1'>
+    <nd ref='4' />
+    <nd ref='6' />
+    <nd ref='8' />
+    <nd ref='10' />
+    <nd ref='4' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='20' visible='true' version='1'>
+    <nd ref='21' />
+    <nd ref='22' />
+    <nd ref='3' />
+    <nd ref='24' />
+    <nd ref='21' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='239' visible='true' version='1'>
+    <nd ref='345' />
+    <nd ref='248' />
+    <nd ref='246' />
+    <nd ref='438' />
+    <nd ref='242' />
+    <nd ref='244' />
+    <nd ref='345' />
+    <tag k='highway' v='primary' />
+    <tag k='junction' v='roundabout' />
+    <tag k='name' v='roundabout' />
+    <tag k='oneway' v='yes' />
+  </way>
+  <way id='240' visible='true' version='1'>
+    <nd ref='438' />
+    <nd ref='4' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 1' />
+  </way>
+  <way id='254' visible='true' version='1'>
+    <nd ref='253' />
+    <nd ref='242' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='256' visible='true' version='1'>
+    <nd ref='255' />
+    <nd ref='244' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='258' visible='true' version='1'>
+    <nd ref='257' />
+    <nd ref='248' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='260' visible='true' version='1'>
+    <nd ref='259' />
+    <nd ref='246' />
+    <tag k='highway' v='residential' />
+  </way>
+</osm>
diff --git a/3rdparty/Routino/src/test/roundabout-waypoints.sh b/3rdparty/Routino/src/test/roundabout-waypoints.sh
new file mode 120000
index 0000000..b627b17
--- /dev/null
+++ b/3rdparty/Routino/src/test/roundabout-waypoints.sh
@@ -0,0 +1 @@
+start-1-finish.sh
\ No newline at end of file
diff --git a/3rdparty/Routino/src/test/start-1-finish.sh b/3rdparty/Routino/src/test/start-1-finish.sh
new file mode 100755
index 0000000..a448943
--- /dev/null
+++ b/3rdparty/Routino/src/test/start-1-finish.sh
@@ -0,0 +1,103 @@
+#!/bin/sh
+
+# Exit on error
+
+set -e
+
+# Test name
+
+name=`basename $0 .sh`
+
+# Slim or non-slim
+
+if [ "$1" = "slim" ]; then
+    slim="-slim"
+    dir="slim"
+else
+    slim=""
+    dir="fat"
+fi
+
+# Pruned or non-pruned
+
+if [ "$2" = "prune" ]; then
+    prune=""
+    pruned="-pruned"
+else
+    prune="--prune-none"
+    pruned=""
+fi
+
+# Create the output directory
+
+dir="$dir$pruned"
+
+[ -d $dir ] || mkdir $dir
+
+# Run the programs under a run-time debugger
+
+debugger=valgrind
+debugger=
+
+# Name related options
+
+osm=$name.osm
+log=$name$slim$pruned.log
+
+option_prefix="--prefix=$name"
+option_dir="--dir=$dir"
+
+# Generic program options
+
+option_planetsplitter="--loggable --tagging=../../xml/routino-tagging.xml --errorlog $prune"
+option_filedumper="--dump-osm"
+option_router="--loggable --transport=motorcar --profiles=../../xml/routino-profiles.xml --translations=copyright.xml"
+
+# Run planetsplitter
+
+echo "Running planetsplitter"
+
+echo ../planetsplitter$slim $option_dir $option_prefix $option_planetsplitter $osm > $log
+$debugger ../planetsplitter$slim $option_dir $option_prefix $option_planetsplitter $osm >> $log
+
+# Run filedumper
+
+echo "Running filedumper"
+
+echo ../filedumper$slim $option_dir $option_prefix $option_filedumper >> $log
+$debugger ../filedumper$slim $option_dir $option_prefix $option_filedumper > $dir/$osm
+
+# Waypoints
+
+waypoints=`perl waypoints.pl $osm list`
+
+waypoint_start=`perl waypoints.pl $osm WPstart 1`
+waypoint_finish=`perl waypoints.pl $osm WPfinish 3`
+
+# Run the router for each waypoint
+
+for waypoint in $waypoints; do
+
+    [ ! $waypoint = "WPstart"  ] || continue
+    [ ! $waypoint = "WPfinish" ] || continue
+
+    echo "Running router : $waypoint"
+
+    waypoint_test=`perl waypoints.pl $osm $waypoint 2`
+
+    [ -d $dir/$name-$waypoint ] || mkdir $dir/$name-$waypoint
+
+    echo ../router$slim $option_dir $option_prefix $option_osm $option_router $waypoint_start $waypoint_test $waypoint_finish >> $log
+    $debugger ../router$slim $option_dir $option_prefix $option_osm $option_router $waypoint_start $waypoint_test $waypoint_finish >> $log
+
+    mv shortest* $dir/$name-$waypoint
+
+    echo diff -u expected/$name-$waypoint.txt $dir/$name-$waypoint/shortest-all.txt >> $log
+
+    if ./is-fast-math; then
+        diff -U 0 expected/$name-$waypoint.txt $dir/$name-$waypoint/shortest-all.txt | 2>&1 egrep '^[-+] ' || true
+    else
+        diff -u expected/$name-$waypoint.txt $dir/$name-$waypoint/shortest-all.txt >> $log
+    fi
+
+done
diff --git a/3rdparty/Routino/src/test/super-or-not.osm b/3rdparty/Routino/src/test/super-or-not.osm
new file mode 100644
index 0000000..90ecfb6
--- /dev/null
+++ b/3rdparty/Routino/src/test/super-or-not.osm
@@ -0,0 +1,55 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' generator='JOSM'>
+  <node id='86' visible='true' version='1' lat='-0.21688045301473516' lon='-0.5151829113120308'>
+    <tag k='name' v='WP02b' />
+  </node>
+  <node id='82' visible='true' version='1' lat='-0.21646963010999992' lon='-0.5174119101486654' />
+  <node id='77' visible='true' version='1' lat='-0.21721431100258048' lon='-0.5141522988242739' />
+  <node id='74' visible='true' version='1' lat='-0.21725785769610798' lon='-0.5202996845787107' />
+  <node id='72' visible='true' version='1' lat='-0.21797637812110027' lon='-0.5199295350232488' />
+  <node id='70' visible='true' version='1' lat='-0.2180562137217683' lon='-0.5149942076170893' />
+  <node id='38' visible='true' version='1' lat='-0.215865729480266' lon='-0.5179307619271613'>
+    <tag k='name' v='WP03b' />
+  </node>
+  <node id='39' visible='true' version='1' lat='-0.2164352406236952' lon='-0.5185150361715245' />
+  <node id='40' visible='true' version='1' lat='-0.21645095962829408' lon='-0.5162207323645169' />
+  <node id='41' visible='true' version='1' lat='-0.2159298460869398' lon='-0.5168230480787187' />
+  <node id='42' visible='true' version='1' lat='-0.21724799056850824' lon='-0.5152064339929149' />
+  <node id='43' visible='true' version='1' lat='-0.215918491230658' lon='-0.5190638359247135' />
+  <node id='44' visible='true' version='1' lat='-0.21594107925441666' lon='-0.5156105875143656' />
+  <node id='45' visible='true' version='1' lat='-0.2172454620011612' lon='-0.5196371203012323'>
+    <tag k='name' v='WP03a' />
+  </node>
+  <node id='60' visible='true' version='1' lat='-0.21608467422596514' lon='-0.5187345090517225'>
+    <tag k='name' v='WP01a' />
+  </node>
+  <node id='64' visible='true' version='1' lat='-0.21623756439742947' lon='-0.515812981213099'>
+    <tag k='name' v='WP01b' />
+  </node>
+  <node id='340' visible='true' version='1' lat='-0.21686615103763912' lon='-0.5193623107116035'>
+    <tag k='name' v='WP02a' />
+  </node>
+  <way id='75' visible='true' version='1'>
+    <nd ref='74' />
+    <nd ref='45' />
+    <nd ref='42' />
+    <nd ref='77' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='Main road' />
+  </way>
+  <way id='46' visible='true' version='1'>
+    <nd ref='72' />
+    <nd ref='45' />
+    <nd ref='43' />
+    <nd ref='39' />
+    <nd ref='38' />
+    <nd ref='82' />
+    <nd ref='41' />
+    <nd ref='40' />
+    <nd ref='44' />
+    <nd ref='42' />
+    <nd ref='70' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='Local road' />
+  </way>
+</osm>
diff --git a/3rdparty/Routino/src/test/super-or-not.sh b/3rdparty/Routino/src/test/super-or-not.sh
new file mode 120000
index 0000000..b1debba
--- /dev/null
+++ b/3rdparty/Routino/src/test/super-or-not.sh
@@ -0,0 +1 @@
+a-b.sh
\ No newline at end of file
diff --git a/3rdparty/Routino/src/test/turns.osm b/3rdparty/Routino/src/test/turns.osm
new file mode 100644
index 0000000..0ea119a
--- /dev/null
+++ b/3rdparty/Routino/src/test/turns.osm
@@ -0,0 +1,456 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' generator='JOSM'>
+  <node id='3' version='1' visible='true' lat='-0.2217201380129468' lon='-0.5209275966384278' />
+  <node id='4' version='1' visible='true' lat='-0.21828070777942268' lon='-0.5207912709437164' />
+  <node id='6' version='1' visible='true' lat='-0.21804206074333024' lon='-0.5205359496121407' />
+  <node id='8' version='1' visible='true' lat='-0.21778806952505525' lon='-0.52077169436654' />
+  <node id='10' version='1' visible='true' lat='-0.21802147020530807' lon='-0.5210285258597515' />
+  <node id='21' version='1' visible='true' lat='-0.2221908395649969' lon='-0.5209415430673436' />
+  <node id='22' version='1' visible='true' lat='-0.22195451857008858' lon='-0.5207002437384278' />
+  <node id='24' version='1' visible='true' lat='-0.22193543526189635' lon='-0.5211703062894754' />
+  <node id='44' version='1' visible='true' lat='-0.21823992390738106' lon='-0.5159271465477753' />
+  <node id='45' version='1' visible='true' lat='-0.2180027381687473' lon='-0.5156713934099496' />
+  <node id='46' version='1' visible='true' lat='-0.21774729558699316' lon='-0.515907564575113' />
+  <node id='47' version='1' visible='true' lat='-0.21798215306964172' lon='-0.5161639796064453' />
+  <node id='48' version='1' visible='true' lat='-0.2216713552163718' lon='-0.5160632301909843' />
+  <node id='49' version='1' visible='true' lat='-0.22214182669974075' lon='-0.5160772027310793' />
+  <node id='50' version='1' visible='true' lat='-0.22191520010406854' lon='-0.515835072317115' />
+  <node id='51' version='1' visible='true' lat='-0.22189614840042465' lon='-0.5163053654637676' />
+  <node id='52' version='1' visible='true' lat='-0.2206667536990629' lon='-0.5208930003039592' />
+  <node id='54' version='1' visible='true' lat='-0.22078436832897996' lon='-0.5160352169735775' />
+  <node id='113' version='1' visible='true' lat='-0.22135974620623747' lon='-0.518860446158009' />
+  <node id='115' version='1' visible='true' lat='-0.22171077830316824' lon='-0.5185110945906238'>
+    <tag k='name' v='WP16' />
+  </node>
+  <node id='117' version='1' visible='true' lat='-0.22137564544507876' lon='-0.5182342364502396' />
+  <node id='144' version='1' visible='true' lat='-0.22067170616836507' lon='-0.5202228983841708' />
+  <node id='146' version='1' visible='true' lat='-0.2206914242782775' lon='-0.5194618767809532' />
+  <node id='204' version='1' visible='true' lat='-0.21845168535119228' lon='-0.5209389065396647'>
+    <tag k='name' v='WPstart' />
+  </node>
+  <node id='208' version='1' visible='true' lat='-0.22155124019804942' lon='-0.5210546105815851'>
+    <tag k='name' v='WPfinish' />
+  </node>
+  <node id='345' version='1' visible='true' lat='-0.22130760599946336' lon='-0.5209140478361174' />
+  <node id='347' version='1' visible='true' lat='-0.22143095927716896' lon='-0.5160556378985264' />
+  <node id='366' version='1' visible='true' lat='-0.22006717109132917' lon='-0.5201090583078041'>
+    <tag k='name' v='WP02' />
+  </node>
+  <node id='368' version='1' visible='true' lat='-0.22011041864306613' lon='-0.5195530416788935' />
+  <node id='381' version='1' visible='true' lat='-0.22018081579726256' lon='-0.5201767078687767'>
+    <tag k='name' v='WP01' />
+  </node>
+  <node id='407' version='1' visible='true' lat='-0.2201433541990108' lon='-0.5181618144888986' />
+  <node id='408' version='1' visible='true' lat='-0.2201952178944254' lon='-0.518785480678782'>
+    <tag k='name' v='WP04' />
+  </node>
+  <node id='409' version='1' visible='true' lat='-0.22072435983293912' lon='-0.5180706495909584' />
+  <node id='410' version='1' visible='true' lat='-0.22010010664738394' lon='-0.5187178311178092'>
+    <tag k='name' v='WP05' />
+  </node>
+  <node id='411' version='1' visible='true' lat='-0.21985014157743876' lon='-0.5184157667048493'>
+    <tag k='name' v='WP06' />
+  </node>
+  <node id='414' version='1' visible='true' lat='-0.22070825072718983' lon='-0.5188415195272463' />
+  <node id='438' version='1' visible='true' lat='-0.21910696568370078' lon='-0.5208274567527769' />
+  <node id='440' version='1' visible='true' lat='-0.21914411941337283' lon='-0.517257414288283' />
+  <node id='442' version='1' visible='true' lat='-0.21915357836853688' lon='-0.5168261331058486' />
+  <node id='444' version='1' visible='true' lat='-0.21918392662304603' lon='-0.5159682545255313' />
+  <node id='450' version='1' visible='true' lat='-0.21935243417579808' lon='-0.5170599796507417' />
+  <node id='452' version='1' visible='true' lat='-0.2189233360894271' lon='-0.5170717085106757' />
+  <node id='460' version='1' visible='true' lat='-0.21981720602084437' lon='-0.5198069938948442'>
+    <tag k='name' v='WP03' />
+  </node>
+  <node id='462' version='1' visible='true' lat='-0.21956544771737352' lon='-0.5170629802253586' />
+  <node id='464' version='1' visible='true' lat='-0.21868575166121326' lon='-0.5170645248638079' />
+  <node id='466' version='1' visible='true' lat='-0.21899764600703492' lon='-0.5172063739650437' />
+  <node id='468' version='1' visible='true' lat='-0.21896530807951195' lon='-0.5169107352309166' />
+  <node id='470' version='1' visible='true' lat='-0.21930401615320513' lon='-0.5169042698221518' />
+  <node id='472' version='1' visible='true' lat='-0.2192913238300286' lon='-0.5171928800099428' />
+  <node id='476' version='1' visible='true' lat='-0.21912267853817124' lon='-0.520206478114032' />
+  <node id='478' version='1' visible='true' lat='-0.21847413773357155' lon='-0.5200595788170104'>
+    <tag k='name' v='WP11' />
+  </node>
+  <node id='480' version='1' visible='true' lat='-0.21825788992119952' lon='-0.5197892670883819'>
+    <tag k='name' v='WP12' />
+  </node>
+  <node id='482' version='1' visible='true' lat='-0.218481860869659' lon='-0.5195421249364931' />
+  <node id='484' version='1' visible='true' lat='-0.21913151893031774' lon='-0.5194265277011769' />
+  <node id='501' version='1' visible='true' lat='-0.218591557635407' lon='-0.5201383629528404'>
+    <tag k='name' v='WP10' />
+  </node>
+  <node id='523' version='1' visible='true' lat='-0.21865858904503085' lon='-0.5186744365873915'>
+    <tag k='name' v='WP13' />
+  </node>
+  <node id='524' version='1' visible='true' lat='-0.21913455501068563' lon='-0.5188231434133839' />
+  <node id='525' version='1' visible='true' lat='-0.21860054470950374' lon='-0.5185573641050701'>
+    <tag k='name' v='WP14' />
+  </node>
+  <node id='526' version='1' visible='true' lat='-0.21843089127829385' lon='-0.5182429439617734'>
+    <tag k='name' v='WP15' />
+  </node>
+  <node id='527' version='1' visible='true' lat='-0.21861908098471325' lon='-0.5179210352289688' />
+  <node id='528' version='1' visible='true' lat='-0.2191444862981745' lon='-0.5176260007804667' />
+  <node id='561' version='1' visible='true' lat='-0.22008888465226106' lon='-0.517279352425253'>
+    <tag k='name' v='WP08' />
+  </node>
+  <node id='564' version='1' visible='true' lat='-0.22022483800004092' lon='-0.5173643144262515'>
+    <tag k='name' v='WP07' />
+  </node>
+  <node id='565' version='1' visible='true' lat='-0.220096607787534' lon='-0.5167618985447355' />
+  <node id='566' version='1' visible='true' lat='-0.219872636863204' lon='-0.5170090406966246'>
+    <tag k='name' v='WP09' />
+  </node>
+  <node id='571' version='1' visible='true' lat='-0.22073868008618305' lon='-0.5174253809858272' />
+  <node id='575' version='1' visible='true' lat='-0.22076041278528005' lon='-0.5166462582606399' />
+  <way id='5' version='1' visible='true'>
+    <nd ref='3' />
+    <nd ref='345' />
+    <nd ref='52' />
+    <nd ref='438' />
+    <nd ref='4' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 1' />
+  </way>
+  <way id='13' version='1' visible='true'>
+    <nd ref='4' />
+    <nd ref='6' />
+    <nd ref='8' />
+    <nd ref='10' />
+    <nd ref='4' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='20' version='1' visible='true'>
+    <nd ref='21' />
+    <nd ref='22' />
+    <nd ref='3' />
+    <nd ref='24' />
+    <nd ref='21' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='41' version='1' visible='true'>
+    <nd ref='44' />
+    <nd ref='45' />
+    <nd ref='46' />
+    <nd ref='47' />
+    <nd ref='44' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='42' version='1' visible='true'>
+    <nd ref='48' />
+    <nd ref='347' />
+    <nd ref='54' />
+    <nd ref='444' />
+    <nd ref='44' />
+    <tag k='highway' v='primary' />
+    <tag k='name' v='main 2' />
+  </way>
+  <way id='43' version='1' visible='true'>
+    <nd ref='49' />
+    <nd ref='50' />
+    <nd ref='48' />
+    <nd ref='51' />
+    <nd ref='49' />
+    <tag k='highway' v='primary' />
+  </way>
+  <way id='55' version='1' visible='true'>
+    <nd ref='52' />
+    <nd ref='144' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='high street' />
+  </way>
+  <way id='116' version='1' visible='true'>
+    <nd ref='113' />
+    <nd ref='115' />
+    <nd ref='117' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='loop 6' />
+  </way>
+  <way id='128' version='1' visible='true'>
+    <nd ref='113' />
+    <nd ref='117' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='bottom road' />
+  </way>
+  <way id='129' version='1' visible='true'>
+    <nd ref='117' />
+    <nd ref='347' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='bottom road' />
+  </way>
+  <way id='143' version='1' visible='true'>
+    <nd ref='144' />
+    <nd ref='366' />
+    <nd ref='460' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='loop 1' />
+  </way>
+  <way id='348' version='1' visible='true'>
+    <nd ref='345' />
+    <nd ref='113' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='bottom road' />
+  </way>
+  <way id='370' version='1' visible='true'>
+    <nd ref='144' />
+    <nd ref='146' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='high street' />
+  </way>
+  <way id='372' version='1' visible='true'>
+    <nd ref='460' />
+    <nd ref='368' />
+    <nd ref='146' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='loop 1' />
+  </way>
+  <way id='412' version='1' visible='true'>
+    <nd ref='411' />
+    <nd ref='407' />
+    <nd ref='409' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='loop 2' />
+  </way>
+  <way id='413' version='1' visible='true'>
+    <nd ref='414' />
+    <nd ref='410' />
+    <nd ref='411' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='loop 2' />
+  </way>
+  <way id='425' version='1' visible='true'>
+    <nd ref='146' />
+    <nd ref='414' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='high street' />
+  </way>
+  <way id='426' version='1' visible='true'>
+    <nd ref='414' />
+    <nd ref='409' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='high street' />
+  </way>
+  <way id='427' version='1' visible='true'>
+    <nd ref='409' />
+    <nd ref='571' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='high street' />
+  </way>
+  <way id='441' version='1' visible='true'>
+    <nd ref='438' />
+    <nd ref='476' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='top road' />
+  </way>
+  <way id='447' version='1' visible='true'>
+    <nd ref='440' />
+    <nd ref='472' />
+    <nd ref='450' />
+    <nd ref='470' />
+    <nd ref='442' />
+    <nd ref='468' />
+    <nd ref='452' />
+    <nd ref='466' />
+    <nd ref='440' />
+    <tag k='highway' v='residential' />
+    <tag k='junction' v='roundabout' />
+    <tag k='name' v='roundabout' />
+    <tag k='oneway' v='yes' />
+  </way>
+  <way id='448' version='1' visible='true'>
+    <nd ref='442' />
+    <nd ref='444' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='top road' />
+  </way>
+  <way id='463' version='1' visible='true'>
+    <nd ref='450' />
+    <nd ref='462' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='465' version='1' visible='true'>
+    <nd ref='452' />
+    <nd ref='464' />
+    <tag k='highway' v='residential' />
+  </way>
+  <way id='479' version='1' visible='true'>
+    <nd ref='476' />
+    <nd ref='478' />
+    <nd ref='480' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='loop 4' />
+  </way>
+  <way id='493' version='1' visible='true'>
+    <nd ref='476' />
+    <nd ref='484' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='top road' />
+  </way>
+  <way id='494' version='1' visible='true'>
+    <nd ref='484' />
+    <nd ref='524' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='top road' />
+  </way>
+  <way id='521' version='1' visible='true'>
+    <nd ref='524' />
+    <nd ref='525' />
+    <nd ref='526' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='loop 5' />
+  </way>
+  <way id='522' version='1' visible='true'>
+    <nd ref='526' />
+    <nd ref='527' />
+    <nd ref='528' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='loop 5' />
+  </way>
+  <way id='533' version='1' visible='true'>
+    <nd ref='524' />
+    <nd ref='528' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='top road' />
+  </way>
+  <way id='534' version='1' visible='true'>
+    <nd ref='528' />
+    <nd ref='440' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='top road' />
+  </way>
+  <way id='546' version='1' visible='true'>
+    <nd ref='480' />
+    <nd ref='482' />
+    <nd ref='484' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='loop 4' />
+  </way>
+  <way id='567' version='1' visible='true'>
+    <nd ref='566' />
+    <nd ref='565' />
+    <nd ref='575' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='loop 3' />
+  </way>
+  <way id='568' version='1' visible='true'>
+    <nd ref='571' />
+    <nd ref='561' />
+    <nd ref='566' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='loop 3' />
+  </way>
+  <way id='579' version='1' visible='true'>
+    <nd ref='571' />
+    <nd ref='575' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='high street' />
+  </way>
+  <way id='580' version='1' visible='true'>
+    <nd ref='575' />
+    <nd ref='54' />
+    <tag k='highway' v='residential' />
+    <tag k='name' v='high street' />
+  </way>
+  <relation id='132' version='1' visible='true'>
+    <member type='node' ref='113' role='via' />
+    <member type='way' ref='348' role='from' />
+    <member type='way' ref='128' role='to' />
+    <tag k='except' v='motorcar' />
+    <tag k='restriction' v='only_straight_on' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='135' version='1' visible='true'>
+    <member type='node' ref='113' role='via' />
+    <member type='way' ref='348' role='to' />
+    <member type='way' ref='128' role='from' />
+    <tag k='except' v='motorcar' />
+    <tag k='restriction' v='only_straight_on' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='140' version='1' visible='true'>
+    <member type='node' ref='117' role='via' />
+    <member type='way' ref='129' role='to' />
+    <member type='way' ref='128' role='from' />
+    <tag k='except' v='motorcar' />
+    <tag k='restriction' v='only_straight_on' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='143' version='1' visible='true'>
+    <member type='node' ref='117' role='via' />
+    <member type='way' ref='129' role='from' />
+    <member type='way' ref='128' role='to' />
+    <tag k='except' v='motorcar' />
+    <tag k='restriction' v='only_straight_on' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='377' version='1' visible='true'>
+    <member type='way' ref='55' role='from' />
+    <member type='node' ref='144' role='via' />
+    <member type='way' ref='143' role='to' />
+    <tag k='restriction' v='no_left_turn' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='430' version='1' visible='true'>
+    <member type='way' ref='425' role='from' />
+    <member type='node' ref='414' role='via' />
+    <member type='way' ref='413' role='to' />
+    <tag k='restriction' v='no_left_turn' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='436' version='1' visible='true'>
+    <member type='way' ref='413' role='from' />
+    <member type='node' ref='414' role='via' />
+    <member type='way' ref='426' role='to' />
+    <tag k='restriction' v='only_left_turn' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='497' version='1' visible='true'>
+    <member type='way' ref='441' role='from' />
+    <member type='node' ref='476' role='via' />
+    <member type='way' ref='479' role='to' />
+    <tag k='restriction' v='no_left_turn' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='499' version='1' visible='true'>
+    <member type='way' ref='493' role='from' />
+    <member type='node' ref='484' role='via' />
+    <member type='way' ref='546' role='to' />
+    <tag k='restriction' v='no_left_turn' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='540' version='1' visible='true'>
+    <member type='way' ref='521' role='from' />
+    <member type='node' ref='524' role='via' />
+    <member type='way' ref='533' role='to' />
+    <tag k='restriction' v='only_left_turn' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='542' version='1' visible='true'>
+    <member type='way' ref='533' role='from' />
+    <member type='node' ref='528' role='via' />
+    <member type='way' ref='534' role='to' />
+    <tag k='restriction' v='only_straight_on' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='551' version='1' visible='true'>
+    <member type='way' ref='494' role='from' />
+    <member type='node' ref='524' role='via' />
+    <member type='way' ref='521' role='to' />
+    <tag k='restriction' v='no_left_turn' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='583' version='1' visible='true'>
+    <member type='way' ref='427' role='from' />
+    <member type='node' ref='571' role='via' />
+    <member type='way' ref='568' role='to' />
+    <tag k='restriction' v='no_left_turn' />
+    <tag k='type' v='restriction' />
+  </relation>
+  <relation id='585' version='1' visible='true'>
+    <member type='way' ref='579' role='from' />
+    <member type='node' ref='575' role='via' />
+    <member type='way' ref='567' role='to' />
+    <tag k='restriction' v='no_left_turn' />
+    <tag k='type' v='restriction' />
+  </relation>
+</osm>
diff --git a/3rdparty/Routino/src/test/turns.sh b/3rdparty/Routino/src/test/turns.sh
new file mode 120000
index 0000000..b627b17
--- /dev/null
+++ b/3rdparty/Routino/src/test/turns.sh
@@ -0,0 +1 @@
+start-1-finish.sh
\ No newline at end of file
diff --git a/3rdparty/Routino/src/test/waypoints.pl b/3rdparty/Routino/src/test/waypoints.pl
new file mode 100755
index 0000000..fefe3a6
--- /dev/null
+++ b/3rdparty/Routino/src/test/waypoints.pl
@@ -0,0 +1,78 @@
+#!/usr/bin/perl
+#
+# Routing test case generator tool.
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2011-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+
+# Command line
+
+if($#ARGV<1 || $ARGV>2 || ! -f $ARGV[0])
+  {
+   die  "Usage: waypoints.pl <filename.osm> list\n".
+        "       waypoints.pl <filename.osm> <name> <number>\n";
+  }
+
+# Parse the file
+
+open(FILE,"<$ARGV[0]") || die "Cannot open '$ARGV[0]'\n";
+
+my %waypoints=();
+my @waypoints=();
+my @waypoint_lat=();
+my @waypoint_lon=();
+my $innode=0;
+
+while(<FILE>)
+  {
+   if($innode)
+     {
+      if(m%<tag k='name' v='([^']+)'%)
+        {
+         push(@waypoints,$1);
+         $waypoints{$1}=$#waypoints;
+        }
+      $innode=0 if(m%</node>%);
+     }
+   elsif(m%<node .* lat='([-.0-9]+)' *lon='([-.0-9]+)' *>%)
+     {
+      $innode=1;
+      push(@waypoint_lat,$1);
+      push(@waypoint_lon,$2);
+     }
+  }
+
+close(FILE);
+
+# Perform the action
+
+if($ARGV[1] eq "list")
+  {
+   print join(" ",sort @waypoints)."\n";
+   exit 0;
+  }
+
+if($waypoints{$ARGV[1]} ne "")
+  {
+   print "--lat$ARGV[2]=$waypoint_lat[$waypoints{$ARGV[1]}] --lon$ARGV[2]=$waypoint_lon[$waypoints{$ARGV[1]}]\n";
+   exit 0;
+  }
+
+exit 1;
diff --git a/3rdparty/Routino/src/translations.c b/3rdparty/Routino/src/translations.c
new file mode 100644
index 0000000..c3b76fe
--- /dev/null
+++ b/3rdparty/Routino/src/translations.c
@@ -0,0 +1,1351 @@
+/***************************************
+ Load the translations from a file and the functions for handling them.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "files.h"
+#include "translations.h"
+#include "xmlparse.h"
+
+
+/* Default English translations - Must not require any UTF-8 encoding */
+
+static Translation default_translation=
+{
+ .raw_copyright_creator = {"Creator","Routino - http://www.routino.org/"},
+ .raw_copyright_source  = {NULL,NULL},
+ .raw_copyright_license = {NULL,NULL},
+
+ .xml_copyright_creator = {"Creator","Routino - http://www.routino.org/"},
+ .xml_copyright_source  = {NULL,NULL},
+ .xml_copyright_license = {NULL,NULL},
+
+ .xml_heading = {"South","South-West","West","North-West","North","North-East","East","South-East","South"},
+ .xml_turn    = {"Very sharp left","Sharp left","Left","Slight left","Straight on","Slight right","Right","Sharp right","Very sharp right"},
+ .xml_ordinal = {"First","Second","Third","Fourth","Fifth","Sixth","Seventh","Eighth","Ninth","Tenth"},
+
+ .raw_highway = {"","motorway","trunk road","primary road","secondary road","tertiary road","unclassified road","residential road","service road","track","cycleway","path","steps","ferry"},
+
+ .xml_route_shortest = "Shortest",
+ .xml_route_quickest = "Quickest",
+
+ .html_waypoint   = "<span class='w'>Waypoint</span>", /* span tag added when reading XML translations file */
+ .html_junction   = "Junction",
+ .html_roundabout = "Roundabout",
+
+ .html_title   = "%s Route",
+ .html_start   = {"Start" ,"At %s, head <span class='b'>%s</span>"}, /* span tag added when reading XML translations file */
+ .html_node    = {"At"    ,"%s, go <span class='t'>%s</span> heading <span class='b'>%s</span>"}, /* span tag added when reading XML translations file */
+ .html_rbnode  = {"Leave" ,"%s, take the <span class='b'>%s</span> exit heading <span class='b'>%s</span>"}, /* span tag added when reading XML translations file */
+ .html_segment = {"Follow","<span class='h'>%s</span> for <span class='d'>%.3f km, %.1f min</span>"}, /* span tag added when reading XML translations file */
+ .html_stop    = {"Stop"  ,"At %s"},
+ .html_total   = {"Total" ,"%.1f km, %.0f minutes"},
+
+ .gpx_desc  = "%s route between 'start' and 'finish' waypoints",
+ .gpx_name  = "%s route",
+ .gpx_step  = "%s on '%s' for %.3f km, %.1f min",
+ .gpx_final = "Total Journey %.1f km, %.0f minutes",
+
+ .gpx_start  = "START",
+ .gpx_inter  = "INTER",
+ .gpx_trip   = "TRIP",
+ .gpx_finish = "FINISH"
+};
+
+
+/* Global variables */
+
+/*+ The set of parsed translations. +*/
+Translation *translation=&default_translation;
+
+
+/* Local variables (re-initialised for each file) */
+
+/*+ The language that is to be stored. +*/
+static const char *store_lang;
+
+/*+ This current language is to be stored. +*/
+static int store;
+
+/*+ The chosen language has been stored. +*/
+static int stored;
+
+
+/* The XML tag processing function prototypes */
+
+//static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding);
+//static int RoutinoTranslationsType_function(const char *_tag_,int _type_);
+static int LanguageType_function(const char *_tag_,int _type_,const char *lang);
+//static int CopyrightType_function(const char *_tag_,int _type_);
+static int TurnType_function(const char *_tag_,int _type_,const char *direction,const char *string);
+static int HeadingType_function(const char *_tag_,int _type_,const char *direction,const char *string);
+static int OrdinalType_function(const char *_tag_,int _type_,const char *number,const char *string);
+static int HighwayType_function(const char *_tag_,int _type_,const char *type,const char *string);
+static int RouteType_function(const char *_tag_,int _type_,const char *type,const char *string);
+//static int HTMLType_function(const char *_tag_,int _type_);
+//static int GPXType_function(const char *_tag_,int _type_);
+static int CopyrightCreatorType_function(const char *_tag_,int _type_,const char *string,const char *text);
+static int CopyrightSourceType_function(const char *_tag_,int _type_,const char *string,const char *text);
+static int CopyrightLicenseType_function(const char *_tag_,int _type_,const char *string,const char *text);
+static int HTMLWaypointType_function(const char *_tag_,int _type_,const char *type,const char *string);
+static int HTMLTitleType_function(const char *_tag_,int _type_,const char *text);
+static int HTMLStartType_function(const char *_tag_,int _type_,const char *string,const char *text);
+static int HTMLNodeType_function(const char *_tag_,int _type_,const char *string,const char *text);
+static int HTMLRBNodeType_function(const char *_tag_,int _type_,const char *string,const char *text);
+static int HTMLSegmentType_function(const char *_tag_,int _type_,const char *string,const char *text);
+static int HTMLStopType_function(const char *_tag_,int _type_,const char *string,const char *text);
+static int HTMLTotalType_function(const char *_tag_,int _type_,const char *string,const char *text);
+static int GPXWaypointType_function(const char *_tag_,int _type_,const char *type,const char *string);
+static int GPXDescType_function(const char *_tag_,int _type_,const char *text);
+static int GPXNameType_function(const char *_tag_,int _type_,const char *text);
+static int GPXStepType_function(const char *_tag_,int _type_,const char *text);
+static int GPXFinalType_function(const char *_tag_,int _type_,const char *text);
+
+
+/* The XML tag definitions (forward declarations) */
+
+static const xmltag xmlDeclaration_tag;
+static const xmltag RoutinoTranslationsType_tag;
+static const xmltag LanguageType_tag;
+static const xmltag CopyrightType_tag;
+static const xmltag TurnType_tag;
+static const xmltag HeadingType_tag;
+static const xmltag OrdinalType_tag;
+static const xmltag HighwayType_tag;
+static const xmltag RouteType_tag;
+static const xmltag HTMLType_tag;
+static const xmltag GPXType_tag;
+static const xmltag CopyrightCreatorType_tag;
+static const xmltag CopyrightSourceType_tag;
+static const xmltag CopyrightLicenseType_tag;
+static const xmltag HTMLWaypointType_tag;
+static const xmltag HTMLTitleType_tag;
+static const xmltag HTMLStartType_tag;
+static const xmltag HTMLNodeType_tag;
+static const xmltag HTMLRBNodeType_tag;
+static const xmltag HTMLSegmentType_tag;
+static const xmltag HTMLStopType_tag;
+static const xmltag HTMLTotalType_tag;
+static const xmltag GPXWaypointType_tag;
+static const xmltag GPXDescType_tag;
+static const xmltag GPXNameType_tag;
+static const xmltag GPXStepType_tag;
+static const xmltag GPXFinalType_tag;
+
+
+/* The XML tag definition values */
+
+/*+ The complete set of tags at the top level. +*/
+static const xmltag * const xml_toplevel_tags[]={&xmlDeclaration_tag,&RoutinoTranslationsType_tag,NULL};
+
+/*+ The xmlDeclaration type tag. +*/
+static const xmltag xmlDeclaration_tag=
+              {"xml",
+               2, {"version","encoding"},
+               NULL,
+               {NULL}};
+
+/*+ The RoutinoTranslationsType type tag. +*/
+static const xmltag RoutinoTranslationsType_tag=
+              {"routino-translations",
+               0, {NULL},
+               NULL,
+               {&LanguageType_tag,NULL}};
+
+/*+ The LanguageType type tag. +*/
+static const xmltag LanguageType_tag=
+              {"language",
+               1, {"lang"},
+               LanguageType_function,
+               {&CopyrightType_tag,&TurnType_tag,&HeadingType_tag,&OrdinalType_tag,&HighwayType_tag,&RouteType_tag,&HTMLType_tag,&GPXType_tag,NULL}};
+
+/*+ The CopyrightType type tag. +*/
+static const xmltag CopyrightType_tag=
+              {"copyright",
+               0, {NULL},
+               NULL,
+               {&CopyrightCreatorType_tag,&CopyrightSourceType_tag,&CopyrightLicenseType_tag,NULL}};
+
+/*+ The TurnType type tag. +*/
+static const xmltag TurnType_tag=
+              {"turn",
+               2, {"direction","string"},
+               TurnType_function,
+               {NULL}};
+
+/*+ The HeadingType type tag. +*/
+static const xmltag HeadingType_tag=
+              {"heading",
+               2, {"direction","string"},
+               HeadingType_function,
+               {NULL}};
+
+/*+ The OrdinalType type tag. +*/
+static const xmltag OrdinalType_tag=
+              {"ordinal",
+               2, {"number","string"},
+               OrdinalType_function,
+               {NULL}};
+
+/*+ The HighwayType type tag. +*/
+static const xmltag HighwayType_tag=
+              {"highway",
+               2, {"type","string"},
+               HighwayType_function,
+               {NULL}};
+
+/*+ The RouteType type tag. +*/
+static const xmltag RouteType_tag=
+              {"route",
+               2, {"type","string"},
+               RouteType_function,
+               {NULL}};
+
+/*+ The HTMLType type tag. +*/
+static const xmltag HTMLType_tag=
+              {"output-html",
+               0, {NULL},
+               NULL,
+               {&HTMLWaypointType_tag,&HTMLTitleType_tag,&HTMLStartType_tag,&HTMLNodeType_tag,&HTMLRBNodeType_tag,&HTMLSegmentType_tag,&HTMLStopType_tag,&HTMLTotalType_tag,NULL}};
+
+/*+ The GPXType type tag. +*/
+static const xmltag GPXType_tag=
+              {"output-gpx",
+               0, {NULL},
+               NULL,
+               {&GPXWaypointType_tag,&GPXDescType_tag,&GPXNameType_tag,&GPXStepType_tag,&GPXFinalType_tag,NULL}};
+
+/*+ The CopyrightCreatorType type tag. +*/
+static const xmltag CopyrightCreatorType_tag=
+              {"creator",
+               2, {"string","text"},
+               CopyrightCreatorType_function,
+               {NULL}};
+
+/*+ The CopyrightSourceType type tag. +*/
+static const xmltag CopyrightSourceType_tag=
+              {"source",
+               2, {"string","text"},
+               CopyrightSourceType_function,
+               {NULL}};
+
+/*+ The CopyrightLicenseType type tag. +*/
+static const xmltag CopyrightLicenseType_tag=
+              {"license",
+               2, {"string","text"},
+               CopyrightLicenseType_function,
+               {NULL}};
+
+/*+ The HTMLWaypointType type tag. +*/
+static const xmltag HTMLWaypointType_tag=
+              {"waypoint",
+               2, {"type","string"},
+               HTMLWaypointType_function,
+               {NULL}};
+
+/*+ The HTMLTitleType type tag. +*/
+static const xmltag HTMLTitleType_tag=
+              {"title",
+               1, {"text"},
+               HTMLTitleType_function,
+               {NULL}};
+
+/*+ The HTMLStartType type tag. +*/
+static const xmltag HTMLStartType_tag=
+              {"start",
+               2, {"string","text"},
+               HTMLStartType_function,
+               {NULL}};
+
+/*+ The HTMLNodeType type tag. +*/
+static const xmltag HTMLNodeType_tag=
+              {"node",
+               2, {"string","text"},
+               HTMLNodeType_function,
+               {NULL}};
+
+/*+ The HTMLRBNodeType type tag. +*/
+static const xmltag HTMLRBNodeType_tag=
+              {"rbnode",
+               2, {"string","text"},
+               HTMLRBNodeType_function,
+               {NULL}};
+
+/*+ The HTMLSegmentType type tag. +*/
+static const xmltag HTMLSegmentType_tag=
+              {"segment",
+               2, {"string","text"},
+               HTMLSegmentType_function,
+               {NULL}};
+
+/*+ The HTMLStopType type tag. +*/
+static const xmltag HTMLStopType_tag=
+              {"stop",
+               2, {"string","text"},
+               HTMLStopType_function,
+               {NULL}};
+
+/*+ The HTMLTotalType type tag. +*/
+static const xmltag HTMLTotalType_tag=
+              {"total",
+               2, {"string","text"},
+               HTMLTotalType_function,
+               {NULL}};
+
+/*+ The GPXWaypointType type tag. +*/
+static const xmltag GPXWaypointType_tag=
+              {"waypoint",
+               2, {"type","string"},
+               GPXWaypointType_function,
+               {NULL}};
+
+/*+ The GPXDescType type tag. +*/
+static const xmltag GPXDescType_tag=
+              {"desc",
+               1, {"text"},
+               GPXDescType_function,
+               {NULL}};
+
+/*+ The GPXNameType type tag. +*/
+static const xmltag GPXNameType_tag=
+              {"name",
+               1, {"text"},
+               GPXNameType_function,
+               {NULL}};
+
+/*+ The GPXStepType type tag. +*/
+static const xmltag GPXStepType_tag=
+              {"step",
+               1, {"text"},
+               GPXStepType_function,
+               {NULL}};
+
+/*+ The GPXFinalType type tag. +*/
+static const xmltag GPXFinalType_tag=
+              {"final",
+               1, {"text"},
+               GPXFinalType_function,
+               {NULL}};
+
+
+/* The XML tag processing functions */
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the XML declaration is seen
+
+  int xmlDeclaration_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *version The contents of the 'version' attribute (or NULL if not defined).
+
+  const char *encoding The contents of the 'encoding' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+//static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding)
+//{
+// return(0);
+//}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the RoutinoTranslationsType XSD type is seen
+
+  int RoutinoTranslationsType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+//static int RoutinoTranslationsType_function(const char *_tag_,int _type_)
+//{
+// return(0);
+//}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the LanguageType XSD type is seen
+
+  int LanguageType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *lang The contents of the 'lang' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int LanguageType_function(const char *_tag_,int _type_,const char *lang)
+{
+ if(_type_&XMLPARSE_TAG_START)
+   {
+    XMLPARSE_ASSERT_STRING(_tag_,lang);
+
+    if(!store_lang && !stored)
+       store=1;
+    else if(store_lang && !strcmp(store_lang,lang))
+       store=1;
+    else
+       store=0;
+   }
+
+ if(_type_&XMLPARSE_TAG_END && store)
+   {
+    store=0;
+    stored=1;
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the CopyrightType XSD type is seen
+
+  int CopyrightType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+//static int CopyrightType_function(const char *_tag_,int _type_)
+//{
+// return(0);
+//}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the TurnType XSD type is seen
+
+  int TurnType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *direction The contents of the 'direction' attribute (or NULL if not defined).
+
+  const char *string The contents of the 'string' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int TurnType_function(const char *_tag_,int _type_,const char *direction,const char *string)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmlstring;
+    int d;
+
+    XMLPARSE_ASSERT_INTEGER(_tag_,direction); d=atoi(direction);
+    XMLPARSE_ASSERT_STRING(_tag_,string);
+
+    d+=4;
+
+    if(d<0 || d>8)
+       XMLPARSE_INVALID(_tag_,direction);
+
+    xmlstring=ParseXML_Encode_Safe_XML(string);
+
+    translation->xml_turn[d]=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the HeadingType XSD type is seen
+
+  int HeadingType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *direction The contents of the 'direction' attribute (or NULL if not defined).
+
+  const char *string The contents of the 'string' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int HeadingType_function(const char *_tag_,int _type_,const char *direction,const char *string)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmlstring;
+    int d;
+
+    XMLPARSE_ASSERT_INTEGER(_tag_,direction); d=atoi(direction);
+    XMLPARSE_ASSERT_STRING(_tag_,string);
+
+    d+=4;
+
+    if(d<0 || d>8)
+       XMLPARSE_INVALID(_tag_,direction);
+
+    xmlstring=ParseXML_Encode_Safe_XML(string);
+
+    translation->xml_heading[d]=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the OrdinalType XSD type is seen
+
+  int OrdinalType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *number The contents of the 'number' attribute (or NULL if not defined).
+
+  const char *string The contents of the 'string' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int OrdinalType_function(const char *_tag_,int _type_,const char *number,const char *string)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmlstring;
+    int n;
+
+    XMLPARSE_ASSERT_INTEGER(_tag_,number); n=atoi(number);
+    XMLPARSE_ASSERT_STRING(_tag_,string);
+
+    if(n<1 || n>10)
+       XMLPARSE_INVALID(_tag_,number);
+
+    xmlstring=ParseXML_Encode_Safe_XML(string);
+
+    translation->xml_ordinal[n-1]=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the HighwayType XSD type is seen
+
+  int HighwayType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *type The contents of the 'type' attribute (or NULL if not defined).
+
+  const char *string The contents of the 'string' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int HighwayType_function(const char *_tag_,int _type_,const char *type,const char *string)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    Highway highway;
+
+    XMLPARSE_ASSERT_STRING(_tag_,type);
+    XMLPARSE_ASSERT_STRING(_tag_,string);
+
+    highway=HighwayType(type);
+
+    if(highway==Highway_None)
+       XMLPARSE_INVALID(_tag_,type);
+
+    translation->raw_highway[highway]=strcpy(malloc(strlen(string)+1),string);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the RouteType XSD type is seen
+
+  int RouteType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *type The contents of the 'type' attribute (or NULL if not defined).
+
+  const char *string The contents of the 'string' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int RouteType_function(const char *_tag_,int _type_,const char *type,const char *string)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmlstring;
+
+    XMLPARSE_ASSERT_STRING(_tag_,type);
+    XMLPARSE_ASSERT_STRING(_tag_,string);
+
+    xmlstring=ParseXML_Encode_Safe_XML(string);
+
+    if(!strcmp(type,"shortest"))
+       translation->xml_route_shortest=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    else if(!strcmp(type,"quickest"))
+       translation->xml_route_quickest=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    else
+       XMLPARSE_INVALID(_tag_,type);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the HTMLType XSD type is seen
+
+  int HTMLType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+//static int HTMLType_function(const char *_tag_,int _type_)
+//{
+// return(0);
+//}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the GPXType XSD type is seen
+
+  int GPXType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+//static int GPXType_function(const char *_tag_,int _type_)
+//{
+// return(0);
+//}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the CopyrightCreatorType XSD type is seen
+
+  int CopyrightCreatorType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *string The contents of the 'string' attribute (or NULL if not defined).
+
+  const char *text The contents of the 'text' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int CopyrightCreatorType_function(const char *_tag_,int _type_,const char *string,const char *text)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmlstring,*xmltext;
+
+    XMLPARSE_ASSERT_STRING(_tag_,string);
+    XMLPARSE_ASSERT_STRING(_tag_,text);
+
+    translation->raw_copyright_creator[0]=strcpy(malloc(strlen(string)+1),string);
+    translation->raw_copyright_creator[1]=strcpy(malloc(strlen(text)+1)  ,text);
+
+    xmlstring=ParseXML_Encode_Safe_XML(string);
+    xmltext  =ParseXML_Encode_Safe_XML(text);
+
+    translation->xml_copyright_creator[0]=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    translation->xml_copyright_creator[1]=strcpy(malloc(strlen(xmltext)+1)  ,xmltext);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the CopyrightSourceType XSD type is seen
+
+  int CopyrightSourceType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *string The contents of the 'string' attribute (or NULL if not defined).
+
+  const char *text The contents of the 'text' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int CopyrightSourceType_function(const char *_tag_,int _type_,const char *string,const char *text)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmlstring,*xmltext;
+
+    XMLPARSE_ASSERT_STRING(_tag_,string);
+    XMLPARSE_ASSERT_STRING(_tag_,text);
+
+    translation->raw_copyright_source[0]=strcpy(malloc(strlen(string)+1),string);
+    translation->raw_copyright_source[1]=strcpy(malloc(strlen(text)+1)  ,text);
+
+    xmlstring=ParseXML_Encode_Safe_XML(string);
+    xmltext  =ParseXML_Encode_Safe_XML(text);
+
+    translation->xml_copyright_source[0]=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    translation->xml_copyright_source[1]=strcpy(malloc(strlen(xmltext)+1)  ,xmltext);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the CopyrightLicenseType XSD type is seen
+
+  int CopyrightLicenseType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *string The contents of the 'string' attribute (or NULL if not defined).
+
+  const char *text The contents of the 'text' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int CopyrightLicenseType_function(const char *_tag_,int _type_,const char *string,const char *text)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmlstring,*xmltext;
+
+    XMLPARSE_ASSERT_STRING(_tag_,string);
+    XMLPARSE_ASSERT_STRING(_tag_,text);
+
+    translation->raw_copyright_license[0]=strcpy(malloc(strlen(string)+1),string);
+    translation->raw_copyright_license[1]=strcpy(malloc(strlen(text)+1)  ,text);
+
+    xmlstring=ParseXML_Encode_Safe_XML(string);
+    xmltext  =ParseXML_Encode_Safe_XML(text);
+
+    translation->xml_copyright_license[0]=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    translation->xml_copyright_license[1]=strcpy(malloc(strlen(xmltext)+1)  ,xmltext);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the HTMLWaypointType XSD type is seen
+
+  int HTMLWaypointType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *type The contents of the 'type' attribute (or NULL if not defined).
+
+  const char *string The contents of the 'string' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int HTMLWaypointType_function(const char *_tag_,int _type_,const char *type,const char *string)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmlstring;
+
+    XMLPARSE_ASSERT_STRING(_tag_,type);
+    XMLPARSE_ASSERT_STRING(_tag_,string);
+
+    xmlstring=ParseXML_Encode_Safe_XML(string);
+
+    if(!strcmp(type,"waypoint"))
+      {
+       translation->html_waypoint=malloc(strlen(xmlstring)+1+sizeof("<span class='w'>")+sizeof("</span>"));
+       sprintf(translation->html_waypoint,"<span class='w'>%s</span>",xmlstring);
+      }
+    else if(!strcmp(type,"junction"))
+       translation->html_junction=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    else if(!strcmp(type,"roundabout"))
+       translation->html_roundabout=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    else
+       XMLPARSE_INVALID(_tag_,type);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the HTMLTitleType XSD type is seen
+
+  int HTMLTitleType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *text The contents of the 'text' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int HTMLTitleType_function(const char *_tag_,int _type_,const char *text)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmltext;
+
+    XMLPARSE_ASSERT_STRING(_tag_,text);
+
+    xmltext=ParseXML_Encode_Safe_XML(text);
+
+    translation->html_title=strcpy(malloc(strlen(xmltext)+1),xmltext);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the HTMLStartType XSD type is seen
+
+  int HTMLStartType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *string The contents of the 'string' attribute (or NULL if not defined).
+
+  const char *text The contents of the 'text' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int HTMLStartType_function(const char *_tag_,int _type_,const char *string,const char *text)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmlstring,*xmltext;
+
+    XMLPARSE_ASSERT_STRING(_tag_,string);
+    XMLPARSE_ASSERT_STRING(_tag_,text);
+
+    xmlstring=ParseXML_Encode_Safe_XML(string);
+    xmltext  =ParseXML_Encode_Safe_XML(text);
+
+    translation->html_start[0]=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    translation->html_start[1]=malloc(strlen(xmltext)+1+sizeof("<span class='b'>")+sizeof("</span>"));
+    sprintf(translation->html_start[1],xmltext,"%s","<span class='b'>%s</span>");
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the HTMLNodeType XSD type is seen
+
+  int HTMLNodeType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *string The contents of the 'string' attribute (or NULL if not defined).
+
+  const char *text The contents of the 'text' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int HTMLNodeType_function(const char *_tag_,int _type_,const char *string,const char *text)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmlstring,*xmltext;
+
+    XMLPARSE_ASSERT_STRING(_tag_,string);
+    XMLPARSE_ASSERT_STRING(_tag_,text);
+
+    xmlstring=ParseXML_Encode_Safe_XML(string);
+    xmltext  =ParseXML_Encode_Safe_XML(text);
+
+    translation->html_node[0]=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    translation->html_node[1]=malloc(strlen(xmltext)+1+2*sizeof("<span class='b'>")+2*sizeof("</span>"));
+    sprintf(translation->html_node[1],xmltext,"%s","<span class='t'>%s</span>","<span class='b'>%s</span>");
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the HTMLRBNodeType XSD type is seen
+
+  int HTMLRBNodeType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *string The contents of the 'string' attribute (or NULL if not defined).
+
+  const char *text The contents of the 'text' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int HTMLRBNodeType_function(const char *_tag_,int _type_,const char *string,const char *text)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmlstring,*xmltext;
+
+    XMLPARSE_ASSERT_STRING(_tag_,string);
+    XMLPARSE_ASSERT_STRING(_tag_,text);
+
+    xmlstring=ParseXML_Encode_Safe_XML(string);
+    xmltext  =ParseXML_Encode_Safe_XML(text);
+
+    translation->html_rbnode[0]=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    translation->html_rbnode[1]=malloc(strlen(xmltext)+1+2*sizeof("<span class='b'>")+2*sizeof("</span>"));
+    sprintf(translation->html_rbnode[1],xmltext,"%s","<span class='t'>%s</span>","<span class='b'>%s</span>");
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the HTMLSegmentType XSD type is seen
+
+  int HTMLSegmentType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *string The contents of the 'string' attribute (or NULL if not defined).
+
+  const char *text The contents of the 'text' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int HTMLSegmentType_function(const char *_tag_,int _type_,const char *string,const char *text)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmlstring,*xmltext;
+    const char *p;
+    char *q;
+
+    XMLPARSE_ASSERT_STRING(_tag_,string);
+    XMLPARSE_ASSERT_STRING(_tag_,text);
+
+    xmlstring=ParseXML_Encode_Safe_XML(string);
+    xmltext  =ParseXML_Encode_Safe_XML(text);
+
+    translation->html_segment[0]=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    translation->html_segment[1]=malloc(strlen(xmltext)+1+2*sizeof("<span class='b'>")+2*sizeof("</span>"));
+
+    p=xmltext;
+    q=translation->html_segment[1];
+
+    while(*p!='%' && *(p+1)!='s')
+       *q++=*p++;
+
+    p+=2;
+    strcpy(q,"<span class='h'>%s</span>"); q+=sizeof("<span class='h'>%s</span>")-1;
+
+    while(*p!='%')
+       *q++=*p++;
+
+    strcpy(q,"<span class='d'>"); q+=sizeof("<span class='d'>")-1;
+
+    strcpy(q,p);
+    strcat(q,"</span>");
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the HTMLStopType XSD type is seen
+
+  int HTMLStopType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *string The contents of the 'string' attribute (or NULL if not defined).
+
+  const char *text The contents of the 'text' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int HTMLStopType_function(const char *_tag_,int _type_,const char *string,const char *text)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmlstring,*xmltext;
+
+    XMLPARSE_ASSERT_STRING(_tag_,string);
+    XMLPARSE_ASSERT_STRING(_tag_,text);
+
+    xmlstring=ParseXML_Encode_Safe_XML(string);
+    xmltext  =ParseXML_Encode_Safe_XML(text);
+
+    translation->html_stop[0]=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    translation->html_stop[1]=strcpy(malloc(strlen(xmltext)+1)  ,xmltext);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the HTMLTotalType XSD type is seen
+
+  int HTMLTotalType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *string The contents of the 'string' attribute (or NULL if not defined).
+
+  const char *text The contents of the 'text' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int HTMLTotalType_function(const char *_tag_,int _type_,const char *string,const char *text)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmlstring,*xmltext;
+
+    XMLPARSE_ASSERT_STRING(_tag_,string);
+    XMLPARSE_ASSERT_STRING(_tag_,text);
+
+    xmlstring=ParseXML_Encode_Safe_XML(string);
+    xmltext  =ParseXML_Encode_Safe_XML(text);
+
+    translation->html_total[0]=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    translation->html_total[1]=strcpy(malloc(strlen(xmltext)+1)  ,xmltext);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the GPXWaypointType XSD type is seen
+
+  int GPXWaypointType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *type The contents of the 'type' attribute (or NULL if not defined).
+
+  const char *string The contents of the 'string' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int GPXWaypointType_function(const char *_tag_,int _type_,const char *type,const char *string)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmlstring;
+
+    XMLPARSE_ASSERT_STRING(_tag_,type);
+    XMLPARSE_ASSERT_STRING(_tag_,string);
+
+    xmlstring=ParseXML_Encode_Safe_XML(string);
+
+    if(!strcmp(type,"start"))
+       translation->gpx_start=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    else if(!strcmp(type,"inter"))
+       translation->gpx_inter=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    else if(!strcmp(type,"trip"))
+       translation->gpx_trip=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    else if(!strcmp(type,"finish"))
+       translation->gpx_finish=strcpy(malloc(strlen(xmlstring)+1),xmlstring);
+    else
+       XMLPARSE_INVALID(_tag_,type);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the GPXDescType XSD type is seen
+
+  int GPXDescType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *text The contents of the 'text' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int GPXDescType_function(const char *_tag_,int _type_,const char *text)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmltext;
+
+    XMLPARSE_ASSERT_STRING(_tag_,text);
+
+    xmltext=ParseXML_Encode_Safe_XML(text);
+
+    translation->gpx_desc=strcpy(malloc(strlen(xmltext)+1),xmltext);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the GPXNameType XSD type is seen
+
+  int GPXNameType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *text The contents of the 'text' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int GPXNameType_function(const char *_tag_,int _type_,const char *text)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmltext;
+
+    XMLPARSE_ASSERT_STRING(_tag_,text);
+
+    xmltext=ParseXML_Encode_Safe_XML(text);
+
+    translation->gpx_name=strcpy(malloc(strlen(xmltext)+1),xmltext);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the GPXStepType XSD type is seen
+
+  int GPXStepType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *text The contents of the 'text' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int GPXStepType_function(const char *_tag_,int _type_,const char *text)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmltext;
+
+    XMLPARSE_ASSERT_STRING(_tag_,text);
+
+    xmltext=ParseXML_Encode_Safe_XML(text);
+
+    translation->gpx_step=strcpy(malloc(strlen(xmltext)+1),xmltext);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the GPXFinalType XSD type is seen
+
+  int GPXFinalType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *text The contents of the 'text' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int GPXFinalType_function(const char *_tag_,int _type_,const char *text)
+{
+ if(_type_&XMLPARSE_TAG_START && store)
+   {
+    char *xmltext;
+
+    XMLPARSE_ASSERT_STRING(_tag_,text);
+
+    xmltext=ParseXML_Encode_Safe_XML(text);
+
+    translation->gpx_final=strcpy(malloc(strlen(xmltext)+1),xmltext);
+   }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The XML translation parser.
+
+  int ParseXMLTranslations Returns 0 if OK or something else in case of an error.
+
+  const char *filename The name of the file to read.
+
+  const char *language The language to search for (NULL means first in file).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int ParseXMLTranslations(const char *filename,const char *language)
+{
+ int fd;
+ int retval;
+
+ if(!ExistsFile(filename))
+   {
+#ifndef LIBROUTINO
+    fprintf(stderr,"Error: Specified translations file '%s' does not exist.\n",filename);
+#endif
+    return(1);
+   }
+
+ fd=OpenFile(filename);
+
+ /* Start with a copy of the default translations */
+
+ if(translation!=&default_translation)
+    FreeXMLTranslations();
+
+ translation=calloc(sizeof(Translation),1);
+
+ *translation=default_translation;
+
+ /* Initialise variables used for parsing */
+
+ store_lang=language;
+
+ store=0;
+ stored=0;
+
+ /* Parse the file */
+
+ retval=ParseXML(fd,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_ERRNONAME|XMLPARSE_RETURN_ATTR_ENCODED);
+
+ CloseFile(fd);
+
+ if(retval)
+    return(1);
+
+ if(language && !stored)
+#ifdef LIBROUTINO
+    return(1);
+#else
+    fprintf(stderr,"Warning: Cannot find translations for language '%s' using English instead.\n",language);
+#endif
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Free the memory that has been allocated for the translations.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FreeXMLTranslations()
+{
+ int i;
+
+ if(translation==&default_translation)
+    return;
+
+ for(i=0;i<2;i++)
+   {
+    if(translation->raw_copyright_creator[i] != default_translation.raw_copyright_creator[i]) free(translation->raw_copyright_creator[i]);
+    if(translation->raw_copyright_source[i]  != default_translation.raw_copyright_source[i])  free(translation->raw_copyright_source[i]);
+    if(translation->raw_copyright_license[i] != default_translation.raw_copyright_license[i]) free(translation->raw_copyright_license[i]);
+
+    if(translation->xml_copyright_creator[i] != default_translation.xml_copyright_creator[i]) free(translation->xml_copyright_creator[i]);
+    if(translation->xml_copyright_source[i]  != default_translation.xml_copyright_source[i])  free(translation->xml_copyright_source[i]);
+    if(translation->xml_copyright_license[i] != default_translation.xml_copyright_license[i]) free(translation->xml_copyright_license[i]);
+   }
+
+ for(i=0;i<9;i++)
+   {
+    if(translation->xml_heading[i] != default_translation.xml_heading[i]) free(translation->xml_heading[i]);
+    if(translation->xml_turn[i]    != default_translation.xml_turn[i])    free(translation->xml_turn[i]);
+   }
+
+ for(i=0;i<10;i++)
+    if(translation->xml_ordinal[i] != default_translation.xml_ordinal[i]) free(translation->xml_ordinal[i]);
+
+ for(i=0;i<Highway_Count;i++)
+    if(translation->raw_highway[i] != default_translation.raw_highway[i]) free(translation->raw_highway[i]);
+
+ if(translation->xml_route_shortest != default_translation.xml_route_shortest) free(translation->xml_route_shortest);
+ if(translation->xml_route_quickest != default_translation.xml_route_quickest) free(translation->xml_route_quickest);
+
+ if(translation->html_waypoint   != default_translation.html_waypoint)   free(translation->html_waypoint);
+ if(translation->html_junction   != default_translation.html_junction)   free(translation->html_junction);
+ if(translation->html_roundabout != default_translation.html_roundabout) free(translation->html_roundabout);
+
+ if(translation->html_title != default_translation.html_title) free(translation->html_title);
+
+ for(i=0;i<2;i++)
+   {
+    if(translation->html_start[i]   != default_translation.html_start[i])   free(translation->html_start[i]);
+    if(translation->html_segment[i] != default_translation.html_segment[i]) free(translation->html_segment[i]);
+    if(translation->html_node[i]    != default_translation.html_node[i])    free(translation->html_node[i]);
+    if(translation->html_rbnode[i]  != default_translation.html_rbnode[i])  free(translation->html_rbnode[i]);
+    if(translation->html_stop[i]    != default_translation.html_stop[i])    free(translation->html_stop[i]);
+    if(translation->html_total[i]   != default_translation.html_total[i])   free(translation->html_total[i]);
+   }
+
+ if(translation->gpx_desc  != default_translation.gpx_desc)  free(translation->gpx_desc);
+ if(translation->gpx_name  != default_translation.gpx_name)  free(translation->gpx_name);
+ if(translation->gpx_step  != default_translation.gpx_step)  free(translation->gpx_step);
+ if(translation->gpx_final != default_translation.gpx_final) free(translation->gpx_final);
+
+ if(translation->gpx_start  != default_translation.gpx_start)  free(translation->gpx_start);
+ if(translation->gpx_inter  != default_translation.gpx_inter)  free(translation->gpx_inter);
+ if(translation->gpx_trip   != default_translation.gpx_trip)   free(translation->gpx_trip);
+ if(translation->gpx_finish != default_translation.gpx_finish) free(translation->gpx_finish);
+
+ free(translation);
+
+ translation=&default_translation;
+}
diff --git a/3rdparty/Routino/src/translations.h b/3rdparty/Routino/src/translations.h
new file mode 100644
index 0000000..9c9407c
--- /dev/null
+++ b/3rdparty/Routino/src/translations.h
@@ -0,0 +1,87 @@
+/***************************************
+ Load the translations from a file and the functions for handling them.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef TRANSLATIONS_H
+#define TRANSLATIONS_H    /*+ To stop multiple inclusions. +*/
+
+#include "types.h"
+
+
+/* Type declarations */
+
+typedef struct _Translation
+{
+ char *raw_copyright_creator[2];
+ char *raw_copyright_source[2];
+ char *raw_copyright_license[2];
+
+ char *xml_copyright_creator[2];
+ char *xml_copyright_source[2];
+ char *xml_copyright_license[2];
+
+ char *xml_heading[9];
+ char *xml_turn[9];
+ char *xml_ordinal[10];
+
+ char *raw_highway[Highway_Count];
+
+ char *xml_route_shortest;
+ char *xml_route_quickest;
+
+ char *html_waypoint;
+ char *html_junction;
+ char *html_roundabout;
+
+ char *html_title;
+ char *html_start[2];
+ char *html_segment[2];
+ char *html_node[2];
+ char *html_rbnode[2];
+ char *html_stop[2];
+ char *html_total[2];
+
+ char *gpx_desc;
+ char *gpx_name;
+ char *gpx_step;
+ char *gpx_final;
+
+ char *gpx_start;
+ char *gpx_inter;
+ char *gpx_trip;
+ char *gpx_finish;
+}
+ Translation;
+
+
+/* Global variable declaration */
+
+extern Translation *translation;
+
+
+/* Functions in translations.c */
+
+int ParseXMLTranslations(const char *filename,const char *language);
+
+void FreeXMLTranslations(void);
+
+
+#endif /* TRANSLATIONS_H */
diff --git a/3rdparty/Routino/src/types.c b/3rdparty/Routino/src/types.c
new file mode 100644
index 0000000..87d54a3
--- /dev/null
+++ b/3rdparty/Routino/src/types.c
@@ -0,0 +1,616 @@
+/***************************************
+ Functions for handling the data types.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <string.h>
+
+#include "types.h"
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Decide on the type of a way given the "highway" parameter.
+
+  Highway HighwayType Returns the highway type of the way.
+
+  const char *highway The string containing the type of the way.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Highway HighwayType(const char *highway)
+{
+ switch(*highway)
+   {
+   case 'c':
+    if(!strcmp(highway,"cycleway")) return(Highway_Cycleway);
+    break;
+
+   case 'f':
+    if(!strcmp(highway,"ferry")) return(Highway_Ferry);
+    break;
+
+   case 'm':
+    if(!strcmp(highway,"motorway")) return(Highway_Motorway);
+    break;
+
+   case 'p':
+    if(!strcmp(highway,"primary")) return(Highway_Primary);
+    if(!strcmp(highway,"path")) return(Highway_Path);
+    break;
+
+   case 'r':
+    if(!strcmp(highway,"residential")) return(Highway_Residential);
+    break;
+
+   case 's':
+    if(!strcmp(highway,"secondary")) return(Highway_Secondary);
+    if(!strcmp(highway,"service")) return(Highway_Service);
+    if(!strcmp(highway,"steps")) return(Highway_Steps);
+    break;
+
+   case 't':
+    if(!strcmp(highway,"trunk")) return(Highway_Trunk);
+    if(!strcmp(highway,"tertiary")) return(Highway_Tertiary);
+    if(!strcmp(highway,"track")) return(Highway_Track);
+    break;
+
+   case 'u':
+    if(!strcmp(highway,"unclassified")) return(Highway_Unclassified);
+    break;
+
+   default:
+    ;
+   }
+
+ return(Highway_None);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Decide on the type of transport given the name of it.
+
+  Transport TransportType Returns the type of the transport.
+
+  const char *transport The string containing the method of transport.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Transport TransportType(const char *transport)
+{
+ switch(*transport)
+   {
+   case 'b':
+    if(!strcmp(transport,"bicycle"))
+       return(Transport_Bicycle);
+    break;
+
+   case 'f':
+    if(!strcmp(transport,"foot"))
+       return(Transport_Foot);
+    break;
+
+   case 'g':
+    if(!strcmp(transport,"goods"))
+       return(Transport_Goods);
+    break;
+
+   case 'h':
+    if(!strcmp(transport,"horse"))
+       return(Transport_Horse);
+    if(!strcmp(transport,"hgv"))
+       return(Transport_HGV);
+    break;
+
+   case 'm':
+    if(!strcmp(transport,"moped"))
+       return(Transport_Moped);
+    if(!strcmp(transport,"motorcycle"))
+       return(Transport_Motorcycle);
+    if(!strcmp(transport,"motorcar"))
+       return(Transport_Motorcar);
+    break;
+
+   case 'p':
+    if(!strcmp(transport,"psv"))
+       return(Transport_PSV);
+    break;
+
+   case 'w':
+    if(!strcmp(transport,"wheelchair"))
+       return(Transport_Wheelchair);
+    break;
+
+   default:
+    return(Transport_None);
+   }
+
+ return(Transport_None);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Decide on the type of property given the name of it.
+
+  Property PropertyType Returns the type of the property.
+
+  const char *property The string containing the method of property.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Property PropertyType(const char *property)
+{
+ switch(*property)
+   {
+   case 'b':
+    if(!strcmp(property,"bicycleroute"))
+       return(Property_BicycleRoute);
+
+    if(!strcmp(property,"bridge"))
+       return(Property_Bridge);
+    break;
+
+   case 'f':
+    if(!strcmp(property,"footroute"))
+       return(Property_FootRoute);
+    break;
+
+   case 'm':
+    if(!strcmp(property,"multilane"))
+       return(Property_Multilane);
+    break;
+
+   case 'p':
+    if(!strcmp(property,"paved"))
+       return(Property_Paved);
+    break;
+
+   case 't':
+    if(!strcmp(property,"tunnel"))
+       return(Property_Tunnel);
+    break;
+
+   default:
+    return(Property_None);
+   }
+
+ return(Property_None);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  A string containing the name of a type of highway.
+
+  const char *HighwayName Returns the name.
+
+  Highway highway The highway type.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+const char *HighwayName(Highway highway)
+{
+ switch(highway)
+   {
+   case Highway_None:
+    return("NONE");
+
+   case Highway_Motorway:
+    return("motorway");
+   case Highway_Trunk:
+    return("trunk");
+   case Highway_Primary:
+    return("primary");
+   case Highway_Secondary:
+    return("secondary");
+   case Highway_Tertiary:
+    return("tertiary");
+   case Highway_Unclassified:
+    return("unclassified");
+   case Highway_Residential:
+    return("residential");
+   case Highway_Service:
+    return("service");
+   case Highway_Track:
+    return("track");
+   case Highway_Cycleway:
+    return("cycleway");
+   case Highway_Path:
+    return("path");
+   case Highway_Steps:
+    return("steps");
+   case Highway_Ferry:
+    return("ferry");
+
+   case Highway_Count:
+    ;
+
+   case Highway_CycleBothWays:
+    ;
+   case Highway_OneWay:
+    ;
+   case Highway_Roundabout:
+    ;
+   case Highway_Area:
+    ;
+   }
+
+ return(NULL);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  A string containing the name of a type of transport.
+
+  const char *TransportName Returns the name.
+
+  Transport transport The transport type.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+const char *TransportName(Transport transport)
+{
+ switch(transport)
+   {
+   case Transport_None:
+    return("NONE");
+
+   case Transport_Foot:
+    return("foot");
+   case Transport_Horse:
+    return("horse");
+   case Transport_Wheelchair:
+    return("wheelchair");
+   case Transport_Bicycle:
+    return("bicycle");
+   case Transport_Moped:
+    return("moped");
+   case Transport_Motorcycle:
+    return("motorcycle");
+   case Transport_Motorcar:
+    return("motorcar");
+   case Transport_Goods:
+    return("goods");
+   case Transport_HGV:
+    return("hgv");
+   case Transport_PSV:
+    return("psv");
+
+   case Transport_Count:
+    ;
+  }
+
+ return(NULL);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  A string containing the name of a highway property.
+
+  const char *PropertyName Returns the name.
+
+  Property property The property type.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+const char *PropertyName(Property property)
+{
+ switch(property)
+   {
+   case Property_None:
+    return("NONE");
+
+   case Property_Paved:
+    return("paved");
+
+   case Property_Multilane:
+    return("multilane");
+
+   case Property_Bridge:
+    return("bridge");
+
+   case Property_Tunnel:
+    return("tunnel");
+
+   case Property_FootRoute:
+    return("footroute");
+
+   case Property_BicycleRoute:
+    return("bicycleroute");
+
+   case Property_Count:
+    ;
+  }
+
+ return(NULL);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  A string containing the names of highways.
+
+  const char *HighwaysNameList Returns the list of names.
+
+  highways_t highways The highways type.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+const char *HighwaysNameList(highways_t highways)
+{
+ static char string[256]; /* static allocation of return value (set each call) */
+
+ string[0]=0;
+
+ if(highways & Highways_Motorway)
+    strcat(string,"motorway");
+
+ if(highways & Highways_Trunk)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"trunk");
+   }
+
+ if(highways & Highways_Primary)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"primary");
+   }
+
+ if(highways & Highways_Tertiary)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"tertiary");
+   }
+
+ if(highways & Highways_Unclassified)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"unclassified");
+   }
+
+ if(highways & Highways_Residential)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"residential");
+   }
+
+ if(highways & Highways_Service)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"service");
+   }
+
+ if(highways & Highways_Track)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"track");
+   }
+
+ if(highways & Highways_Cycleway)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"cycleway");
+   }
+
+ if(highways & Highways_Path)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"path");
+   }
+
+ if(highways & Highways_Steps)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"steps");
+   }
+
+ if(highways & Highways_Ferry)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"ferry");
+   }
+
+ return(string);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  A string containing the names of allowed transports on a way.
+
+  const char *AllowedNameList Returns the list of names.
+
+  transports_t allowed The allowed type.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+const char *AllowedNameList(transports_t allowed)
+{
+ static char string[256]; /* static allocation of return value (set each call) */
+
+ string[0]=0;
+
+ if(allowed & Transports_Foot)
+    strcat(string,"foot");
+
+ if(allowed & Transports_Horse)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"horse");
+   }
+
+ if(allowed & Transports_Wheelchair)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"wheelchair");
+   }
+
+ if(allowed & Transports_Bicycle)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"bicycle");
+   }
+
+ if(allowed & Transports_Moped)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"moped");
+   }
+
+ if(allowed & Transports_Motorcycle)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"motorcycle");
+   }
+
+ if(allowed & Transports_Motorcar)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"motorcar");
+   }
+
+ if(allowed & Transports_Goods)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"goods");
+   }
+
+ if(allowed & Transports_HGV)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"hgv");
+   }
+
+ if(allowed & Transports_PSV)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"psv");
+   }
+
+ return(string);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  A string containing the names of the properties of a way.
+
+  const char *PropertiesNameList Returns the list of names.
+
+  properties_t properties The properties of the way.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+const char *PropertiesNameList(properties_t properties)
+{
+ static char string[256]; /* static allocation of return value (set each call) */
+
+ string[0]=0;
+
+ if(properties & Properties_Paved)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"paved");
+   }
+
+ if(properties & Properties_Multilane)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"multilane");
+   }
+
+ if(properties & Properties_Bridge)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"bridge");
+   }
+
+ if(properties & Properties_Tunnel)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"tunnel");
+   }
+
+ if(properties & Properties_FootRoute)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"footroute");
+   }
+
+ if(properties & Properties_BicycleRoute)
+   {
+    if(*string) strcat(string,", ");
+    strcat(string,"bicycleroute");
+   }
+
+ return(string);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Returns a list of all the highway types.
+
+  const char *HighwayList Return a list of all the highway types.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+const char *HighwayList(void)
+{
+ return "    motorway     = Motorway\n"
+        "    trunk        = Trunk\n"
+        "    primary      = Primary\n"
+        "    secondary    = Secondary\n"
+        "    tertiary     = Tertiary\n"
+        "    unclassified = Unclassified\n"
+        "    residential  = Residential\n"
+        "    service      = Service\n"
+        "    track        = Track\n"
+        "    cycleway     = Cycleway\n"
+        "    path         = Path\n"
+        "    steps        = Steps\n"
+        "    ferry        = Ferry\n"
+        ;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Returns a list of all the transport types.
+
+  const char *TransportList Return a list of all the transport types.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+const char *TransportList(void)
+{
+ return "    foot       = Foot\n"
+        "    bicycle    = Bicycle\n"
+        "    wheelchair = Wheelchair\n"
+        "    horse      = Horse\n"
+        "    moped      = Moped     (Small motorcycle, limited speed)\n"
+        "    motorcycle = Motorcycle\n"
+        "    motorcar   = Motorcar\n"
+        "    goods      = Goods     (Small lorry, van)\n"
+        "    hgv        = HGV       (Heavy Goods Vehicle - large lorry)\n"
+        "    psv        = PSV       (Public Service Vehicle - bus, coach)\n"
+        ;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Returns a list of all the property types.
+
+  const char *PropertyList Return a list of all the highway proprties.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+const char *PropertyList(void)
+{
+ return "    paved        = Paved (suitable for normal wheels)\n"
+        "    multilane    = Multiple lanes\n"
+        "    bridge       = Bridge\n"
+        "    tunnel       = Tunnel\n"
+        "    footroute    = A route marked for foot travel\n"
+        "    bicycleroute = A route marked for bicycle travel\n"
+        ;
+}
diff --git a/3rdparty/Routino/src/types.h b/3rdparty/Routino/src/types.h
new file mode 100644
index 0000000..c3250b6
--- /dev/null
+++ b/3rdparty/Routino/src/types.h
@@ -0,0 +1,460 @@
+/***************************************
+ Type definitions
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2014 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef TYPES_H
+#define TYPES_H    /*+ To stop multiple inclusions. +*/
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <math.h>
+
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+
+/* Constants and macros for handling them */
+
+/*+ The number of waypoints allowed to be specified. +*/
+#define NWAYPOINTS 99
+
+
+/*+ An undefined waypoint index. +*/
+#define NO_WAYPOINT    ((waypoint_t)~0)
+
+/*+ An undefined node index. +*/
+#define NO_NODE        ((index_t)~0)
+
+/*+ An undefined segment index. +*/
+#define NO_SEGMENT     ((index_t)~0)
+
+/*+ An undefined way index. +*/
+#define NO_WAY         ((index_t)~0)
+
+/*+ An undefined relation index. +*/
+#define NO_RELATION    ((index_t)~0)
+
+/*+ An undefined location. +*/
+#define NO_LATLONG     ((latlong_t)0x80000000)
+
+
+/*+ The lowest number allowed for a fake node. +*/
+#define NODE_FAKE      ((index_t)0xffff0000)
+
+/*+ The lowest number allowed for a fake segment. +*/
+#define SEGMENT_FAKE   ((index_t)0xffff0000)
+
+
+/*+ The latitude and longitude conversion factor from floating point (radians) to integer. +*/
+#define LAT_LONG_SCALE (1024*65536)
+
+/*+ The latitude and longitude integer range within each bin. +*/
+#define LAT_LONG_BIN   65536
+
+
+/*+ A flag to mark a node as a super-node. +*/
+#define NODE_SUPER       ((nodeflags_t)0x8000)
+
+/*+ A flag to mark a node as suitable for a U-turn. +*/
+#define NODE_UTURN       ((nodeflags_t)0x4000)
+
+/*+ A flag to mark a node as a mini-roundabout. +*/
+#define NODE_MINIRNDBT   ((nodeflags_t)0x2000)
+
+/*+ A flag to mark a node as a turn relation via node. +*/
+#define NODE_TURNRSTRCT  ((nodeflags_t)0x1000)
+
+/*+ A flag to mark a node as adjacent to a turn relation via node. +*/
+#define NODE_TURNRSTRCT2 ((nodeflags_t)0x0800)
+
+/*+ A flag to mark a node as deleted. +*/
+#define NODE_DELETED     ((nodeflags_t)0x0400)
+
+
+/*+ A flag to mark a segment as being part of an area (must be the highest valued flag). +*/
+#define SEGMENT_AREA   ((distance_t)0x80000000)
+
+/*+ A flag to mark a segment as one-way from node1 to node2. +*/
+#define ONEWAY_1TO2    ((distance_t)0x40000000)
+
+/*+ A flag to mark a segment as one-way from node2 to node1. +*/
+#define ONEWAY_2TO1    ((distance_t)0x20000000)
+
+/*+ A flag to mark a segment as a super-segment. +*/
+#define SEGMENT_SUPER  ((distance_t)0x10000000)
+
+/*+ A flag to mark a segment as a normal segment. +*/
+#define SEGMENT_NORMAL ((distance_t)0x08000000)
+
+/*+ The real distance ignoring the other flags. +*/
+#define DISTANCE(xx)   ((distance_t)((xx)&(~(SEGMENT_AREA|ONEWAY_1TO2|ONEWAY_2TO1|SEGMENT_SUPER|SEGMENT_NORMAL))))
+
+/*+ The distance flags selecting only the flags. +*/
+#define DISTFLAG(xx)   ((distance_t)((xx)&(SEGMENT_AREA|ONEWAY_1TO2|ONEWAY_2TO1|SEGMENT_SUPER|SEGMENT_NORMAL)))
+
+
+/*+ A very large almost infinite distance. +*/
+#define INF_DISTANCE   DISTANCE(~0)
+
+/*+ A very large almost infinite score. +*/
+#define INF_SCORE      (score_t)1E30
+
+
+/*+ A flag to mark a deleted way. +*/
+#define WAY_DELETED ((highway_t)~0)
+
+
+/*+ A flag to mark a deleted relation. +*/
+#define RELATION_DELETED ((transports_t)~0)
+
+
+/* Simple Types */
+
+
+/*+ A waypoint index. +*/
+typedef uint16_t waypoint_t;
+
+
+/*+ A node, segment, way or relation index. +*/
+typedef uint32_t index_t;
+
+/*+ A printf formatting string for an index_t type (this should match the index_t definition above). +*/
+#define Pindex_t PRIu32         /* PRIu32 and PRIu64 are defined in intypes.h */
+
+
+/*+ A node latitude or longitude (range: +/-pi*LAT_LONG_SCALE = +/-3.14*1024*65536 = ~29 bits). +*/
+typedef int32_t  latlong_t;
+
+/*+ A node latitude or longitude bin number (range: +/-pi*LAT_LONG_SCALE/LAT_LONG_BIN = +/-3.14*1024 = ~13 bits). +*/
+typedef int16_t  ll_bin_t;
+
+/*+ A node latitude and longitude bin number (range: +/-(pi*LAT_LONG_SCALE/LAT_LONG_BIN)^2 = +/-(3.14*1024)^2 = ~26 bits). +*/
+typedef int32_t  ll_bin2_t;
+
+/*+ A node latitude or longitude offset (range: 0 -> LAT_LONG_BIN-1 = 0 -> 65535 = 16 bits). +*/
+typedef uint16_t ll_off_t;
+
+
+/*+ Conversion from a latlong (integer latitude or longitude) to a bin number. +*/
+#define latlong_to_bin(xxx) (ll_bin_t)((latlong_t)((xxx)&~(LAT_LONG_BIN-1))/LAT_LONG_BIN)
+
+/*+ Conversion from a bin number to a latlong (integer latitude or longitude). +*/
+#define bin_to_latlong(xxx) ((latlong_t)(xxx)*LAT_LONG_BIN)
+
+
+/*+ Conversion from a latlong (integer latitude or longitude) to a bin offset. +*/
+#define latlong_to_off(xxx) (ll_off_t)((latlong_t)(xxx)&(LAT_LONG_BIN-1))
+
+/*+ Conversion from a bin offset to a latlong (integer latitude or longitude). +*/
+#define off_to_latlong(xxx) ((latlong_t)(xxx))
+
+
+/*+ Conversion from a latitude or longitude in radians to a latlong (integer latitude or longitude). +*/
+#define radians_to_latlong(xxx) ((latlong_t)floor((xxx)*LAT_LONG_SCALE+0.5))
+
+/*+ Conversion from a latlong (integer latitude or longitude) to a latitude or longitude in radians. +*/
+#define latlong_to_radians(xxx) ((double)(xxx)/LAT_LONG_SCALE)
+
+
+/*+ Conversion from radians to degrees. +*/
+#define radians_to_degrees(xxx) ((xxx)*(180.0/M_PI))
+
+/*+ Conversion from degrees to radians. +*/
+#define degrees_to_radians(xxx) ((xxx)*(M_PI/180.0))
+
+
+/*+ Node flags. +*/
+typedef uint16_t nodeflags_t;
+
+/*+ A distance, measured in metres (will not overflow for any earth-based distance). +*/
+typedef uint32_t distance_t;
+
+/*+ A duration, measured in 1/10th seconds (will not overflow for 13 years). +*/
+typedef uint32_t duration_t;
+
+/*+ A routing optimisation score. +*/
+typedef float score_t;
+
+
+/*+ Conversion from distance_t to kilometres. +*/
+#define distance_to_km(xx) ((double)(xx)/1000.0)
+
+/*+ Conversion from kilometres to distance_t. +*/
+#define km_to_distance(xx) ((distance_t)((double)(xx)*1000.0))
+
+/*+ Conversion from duration_t to minutes. +*/
+#define duration_to_minutes(xx) ((double)(xx)/600.0)
+
+/*+ Conversion from duration_t to hours. +*/
+#define duration_to_hours(xx)   ((double)(xx)/36000.0)
+
+/*+ Conversion from hours to duration_t. +*/
+#define hours_to_duration(xx)   ((duration_t)((double)(xx)*36000.0))
+
+/*+ Conversion from distance_t and speed_t to duration_t. +*/
+#define distance_speed_to_duration(xx,yy) ((duration_t)(((double)(xx)/(double)(yy))*(36000.0/1000.0)))
+
+
+/*+ The type of a highway. +*/
+typedef uint8_t highway_t;
+
+/*+ The different types of a highway. +*/
+typedef enum _Highway
+ {
+  Highway_None         =  0,
+
+  Highway_Motorway     =  1,
+  Highway_Trunk        =  2,
+  Highway_Primary      =  3,
+  Highway_Secondary    =  4,
+  Highway_Tertiary     =  5,
+  Highway_Unclassified =  6,
+  Highway_Residential  =  7,
+  Highway_Service      =  8,
+  Highway_Track        =  9,
+  Highway_Cycleway     = 10,
+  Highway_Path         = 11,
+  Highway_Steps        = 12,
+  Highway_Ferry        = 13,
+
+  Highway_Count        = 14,       /* One more than the number of highway types. */
+
+  Highway_CycleBothWays =  16,
+  Highway_OneWay        =  32,
+  Highway_Roundabout    =  64,
+  Highway_Area          = 128
+ }
+ Highway;
+
+#define HIGHWAY(xx) ((xx)&0x0f)
+
+/*+ A bitmask of multiple highway types. +*/
+typedef uint16_t highways_t;
+
+#define HIGHWAYS(xx)  (1<<(HIGHWAY(xx)-1))
+
+/*+ The different types of a highway as a bitmask. +*/
+typedef enum _Highways
+ {
+  Highways_None         = 0,
+
+  Highways_Motorway     = HIGHWAYS(Highway_Motorway    ),
+  Highways_Trunk        = HIGHWAYS(Highway_Trunk       ),
+  Highways_Primary      = HIGHWAYS(Highway_Primary     ),
+  Highways_Secondary    = HIGHWAYS(Highway_Secondary   ),
+  Highways_Tertiary     = HIGHWAYS(Highway_Tertiary    ),
+  Highways_Unclassified = HIGHWAYS(Highway_Unclassified),
+  Highways_Residential  = HIGHWAYS(Highway_Residential ),
+  Highways_Service      = HIGHWAYS(Highway_Service     ),
+  Highways_Track        = HIGHWAYS(Highway_Track       ),
+  Highways_Cycleway     = HIGHWAYS(Highway_Cycleway    ),
+  Highways_Path         = HIGHWAYS(Highway_Path        ),
+  Highways_Steps        = HIGHWAYS(Highway_Steps       ),
+  Highways_Ferry        = HIGHWAYS(Highway_Ferry       )
+ }
+ Highways;
+
+
+/*+ The type of a transport. +*/
+typedef uint8_t transport_t;
+
+/*+ The different types of transport. +*/
+typedef enum _Transport
+ {
+  Transport_None       =  0,
+
+  Transport_Foot       =  1,
+  Transport_Horse      =  2,
+  Transport_Wheelchair =  3,
+  Transport_Bicycle    =  4,
+  Transport_Moped      =  5,
+  Transport_Motorcycle =  6,
+  Transport_Motorcar   =  7,
+  Transport_Goods      =  8,
+  Transport_HGV        =  9,
+  Transport_PSV        = 10,
+
+  Transport_Count      = 11     /*+ One more than the number of transport types. +*/
+ }
+ Transport;
+
+
+/*+ A bitmask of multiple transport types. +*/
+typedef uint16_t transports_t;
+
+#define TRANSPORTS(xx)  (1<<((xx)-1))
+
+/*+ The different types of transport as a bitmask. +*/
+typedef enum _Transports
+ {
+  Transports_None       = 0,
+
+  Transports_Foot       = TRANSPORTS(Transport_Foot      ),
+  Transports_Horse      = TRANSPORTS(Transport_Horse     ),
+  Transports_Wheelchair = TRANSPORTS(Transport_Wheelchair),
+  Transports_Bicycle    = TRANSPORTS(Transport_Bicycle   ),
+  Transports_Moped      = TRANSPORTS(Transport_Moped     ),
+  Transports_Motorcycle = TRANSPORTS(Transport_Motorcycle),
+  Transports_Motorcar   = TRANSPORTS(Transport_Motorcar  ),
+  Transports_Goods      = TRANSPORTS(Transport_Goods     ),
+  Transports_HGV        = TRANSPORTS(Transport_HGV       ),
+  Transports_PSV        = TRANSPORTS(Transport_PSV       ),
+
+  Transports_ALL        = TRANSPORTS(Transport_Count     )-1
+ }
+ Transports;
+
+
+/*+ The type of a property. +*/
+typedef uint8_t property_t;
+
+/*+ The different types of property. +*/
+typedef enum _Property
+ {
+  Property_None         = 0,
+
+  Property_Paved        = 1,
+  Property_Multilane    = 2,
+  Property_Bridge       = 3,
+  Property_Tunnel       = 4,
+  Property_FootRoute    = 5,
+  Property_BicycleRoute = 6,
+
+  Property_Count        = 7       /* One more than the number of property types. */
+ }
+ Property;
+
+
+/*+ A bitmask of multiple properties. +*/
+typedef uint8_t properties_t;
+
+#define PROPERTIES(xx)  (1<<((xx)-1))
+
+/*+ The different properties as a bitmask. +*/
+typedef enum _Properties
+ {
+  Properties_None         = 0,
+
+  Properties_Paved        = PROPERTIES(Property_Paved        ),
+  Properties_Multilane    = PROPERTIES(Property_Multilane    ),
+  Properties_Bridge       = PROPERTIES(Property_Bridge       ),
+  Properties_Tunnel       = PROPERTIES(Property_Tunnel       ),
+  Properties_FootRoute    = PROPERTIES(Property_FootRoute    ),
+  Properties_BicycleRoute = PROPERTIES(Property_BicycleRoute ),
+
+  Properties_ALL          = PROPERTIES(Property_Count        )-1
+ }
+ Properties;
+
+
+/*+ The speed limit of a way, measured in km/hour. +*/
+typedef uint8_t speed_t;
+
+/*+ The maximum weight of a way, measured in multiples of 0.2 tonnes. +*/
+typedef uint8_t weight_t;
+
+/*+ The maximum height of a way, measured in multiples of 0.1 metres. +*/
+typedef uint8_t height_t;
+
+/*+ The maximum width of a way, measured in multiples of 0.1 metres. +*/
+typedef uint8_t width_t;
+
+/*+ The maximum length of a way, measured in multiples of 0.1 metres. +*/
+typedef uint8_t length_t;
+
+
+/*+ Conversion of km/hr to speed_t - simple inline function with error checking. +*/
+inline static speed_t kph_to_speed(double xxx);
+inline static speed_t kph_to_speed(double xxx) { if(xxx>255) return(255); if(xxx<0) return(0); return((speed_t)xxx); }
+
+/*+ Conversion of speed_t to km/hr. +*/
+#define speed_to_kph(xxx)      (int)(xxx)
+
+/*+ Conversion of tonnes to weight_t - simple inline function with error checking. +*/
+inline static weight_t tonnes_to_weight(double xxx);
+inline static weight_t tonnes_to_weight(double xxx) { if(xxx>51) return(255); if(xxx<0) return(0); return((weight_t)(xxx*5)); }
+
+/*+ Conversion of weight_t to tonnes. +*/
+#define weight_to_tonnes(xxx)  ((double)(xxx)/5.0)
+
+/*+ Conversion of metres to height_t - simple inline function with error checking. +*/
+inline static height_t metres_to_height(double xxx);
+inline static height_t metres_to_height(double xxx) { if(xxx>25.5) return(255); if(xxx<0) return(0); return((height_t)(xxx*10)); }
+
+/*+ Conversion of height_t to metres. +*/
+#define height_to_metres(xxx)  ((double)(xxx)/10.0)
+
+/*+ Conversion of metres to width_t - simple inline function with error checking. +*/
+inline static width_t metres_to_width(double xxx);
+inline static width_t metres_to_width(double xxx) { if(xxx>25.5) return(255); if(xxx<0) return(0); return((width_t)(xxx*10)); }
+
+/*+ Conversion of width_t to metres. +*/
+#define width_to_metres(xxx)   ((double)(xxx)/10.0)
+
+/*+ Conversion of metres to length_t - simple inline function with error checking. +*/
+inline static length_t metres_to_length(double xxx);
+inline static length_t metres_to_length(double xxx) { if(xxx>25.5) return(255); if(xxx<0) return(0); return((length_t)(xxx*10)); }
+
+/*+ Conversion of length_t to metres. +*/
+#define length_to_metres(xxx)  ((double)(xxx)/10.0)
+
+
+/* Data structures */
+
+typedef struct _Node Node;
+
+typedef struct _Nodes Nodes;
+
+typedef struct _Segment Segment;
+
+typedef struct _Segments Segments;
+
+typedef struct _Way Way;
+
+typedef struct _Ways Ways;
+
+typedef struct _TurnRelation TurnRelation;
+
+typedef struct _Relations Relations;
+
+
+/* Functions in types.c */
+
+Highway HighwayType(const char *highway);
+Transport TransportType(const char *transport);
+Property PropertyType(const char *property);
+
+const char *HighwayName(Highway highway);
+const char *TransportName(Transport transport);
+const char *PropertyName(Property property);
+
+const char *HighwaysNameList(highways_t highways);
+const char *AllowedNameList(transports_t allowed);
+const char *PropertiesNameList(properties_t properties);
+
+const char *HighwayList(void);
+const char *TransportList(void);
+const char *PropertyList(void);
+
+
+#endif /* TYPES_H */
diff --git a/3rdparty/Routino/src/typesx.h b/3rdparty/Routino/src/typesx.h
new file mode 100644
index 0000000..2febbd2
--- /dev/null
+++ b/3rdparty/Routino/src/typesx.h
@@ -0,0 +1,125 @@
+/***************************************
+ Type definitions for eXtended types.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2014 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef TYPESX_H
+#define TYPESX_H    /*+ To stop multiple inclusions. +*/
+
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+/* Constants and macros for handling them */
+
+/*+ An undefined node ID. +*/
+#define NO_NODE_ID     ((node_t)~0)
+
+/*+ An undefined way ID. +*/
+#define NO_WAY_ID      ((way_t)~0)
+
+/*+ An undefined relation ID. +*/
+#define NO_RELATION_ID ((relation_t)~0)
+
+/*+ The maximum number of segments per node (used to size temporary storage). +*/
+#define MAX_SEG_PER_NODE 64
+
+
+/* Bit mask macro types and functions */
+
+#define BitMask uint32_t
+
+#define LengthBitMask(xx)   (1+(xx)/32)
+
+#define AllocBitMask(xx)    (BitMask*)calloc(LengthBitMask(xx),sizeof(BitMask))
+
+#define ClearAllBits(xx,yy) memset((xx), 0,(1+(yy)/32)*sizeof(BitMask))
+#define SetAllBits(xx,yy)   memset((xx),~0,(1+(yy)/32)*sizeof(BitMask))
+
+#define ClearBit(xx,yy)     (xx)[(yy)/32]&=~(((BitMask)1)<<((yy)%32))
+#define SetBit(xx,yy)       (xx)[(yy)/32]|= (((BitMask)1)<<((yy)%32))
+
+#define IsBitSet(xx,yy)    ((xx)[(yy)/32]&  (((BitMask)1)<<((yy)%32)))
+
+
+/* Simple Types */
+
+/*+ A node identifier - must be at least as large as index_t. +*/
+typedef uint32_t node_t;
+
+/*+ A way identifier - must be at least as large as index_t. +*/
+typedef uint32_t way_t;
+
+/*+ A relation identifier - must be at least as large as index_t. +*/
+typedef uint32_t relation_t;
+
+
+/*+ A printf formatting string for a node_t type (this should match the node_t definition above). +*/
+#define Pnode_t PRIu32          /* PRIu32 and PRIu64 are defined in intypes.h */
+
+/*+ A printf formatting string for a way_t type (this should match the way_t definition above). +*/
+#define Pway_t PRIu32           /* PRIu32 and PRIu64 are defined in intypes.h */
+
+/*+ A printf formatting string for a relation_t type (this should match the relation_t definition above). +*/
+#define Prelation_t PRIu32      /* PRIu32 and PRIu64 are defined in intypes.h */
+
+
+/* Enumerated types */
+
+/*+ Turn restrictions. +*/
+typedef enum _TurnRestriction
+ {
+  TurnRestrict_None              =0,
+  TurnRestrict_no_right_turn,
+  TurnRestrict_no_left_turn,
+  TurnRestrict_no_u_turn,
+  TurnRestrict_no_straight_on,
+  TurnRestrict_only_right_turn,
+  TurnRestrict_only_left_turn,
+  TurnRestrict_only_straight_on
+ }
+ TurnRestriction;
+
+
+/* Data structures */
+
+typedef struct _NodeX NodeX;
+
+typedef struct _NodesX NodesX;
+
+typedef struct _SegmentX SegmentX;
+
+typedef struct _SegmentsX SegmentsX;
+
+typedef struct _WayX WayX;
+
+typedef struct _WaysX WaysX;
+
+typedef struct _RouteRelX RouteRelX;
+
+typedef struct _TurnRelX TurnRelX;
+
+typedef struct _RelationsX RelationsX;
+
+
+#endif /* TYPESX_H */
diff --git a/3rdparty/Routino/src/uncompress.c b/3rdparty/Routino/src/uncompress.c
new file mode 100644
index 0000000..329c8ff
--- /dev/null
+++ b/3rdparty/Routino/src/uncompress.c
@@ -0,0 +1,473 @@
+/***************************************
+ File uncompression.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2012-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+
+#if defined(_MSC_VER)
+#include <io.h>
+#define read(fd,address,length)  _read(fd,address,(unsigned int)(length))
+#define write(fd,address,length) _write(fd,address,(unsigned int)(length))
+#define close                    _close
+#else
+#include <unistd.h>
+#endif
+
+#include <signal.h>
+
+#if defined(USE_BZIP2) && USE_BZIP2
+#define BZ_NO_STDIO
+#include <bzlib.h>
+#endif
+
+#if defined(USE_GZIP) && USE_GZIP
+#include <zlib.h>
+#endif
+
+#if defined(USE_XZ) && USE_XZ
+#include <lzma.h>
+#endif
+
+#include "logging.h"
+#include "uncompress.h"
+
+
+/* Local functions */
+
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+
+#if (defined(USE_BZIP2) && USE_BZIP2) || (defined(USE_GZIP) && USE_GZIP) || (defined(USE_XZ) && USE_XZ)
+static int pipe_and_fork(int filefd,int *pipefd);
+#endif
+
+#if defined(USE_BZIP2) && USE_BZIP2
+static void uncompress_bzip2_pipe(int filefd,int pipefd);
+#endif
+
+#if defined(USE_GZIP) && USE_GZIP
+static void uncompress_gzip_pipe(int filefd,int pipefd);
+#endif
+
+#if defined(USE_XZ) && USE_XZ
+static void uncompress_xz_pipe(int filefd,int pipefd);
+#endif
+
+#endif /* !defined(_MSC_VER) && !defined(__MINGW32__) */
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create a child process to uncompress data on a file descriptor as if it were a pipe.
+
+  int Uncompress_Bzip2 Returns the file descriptor of the uncompressed end of the pipe.
+
+  int filefd The file descriptor of the compressed end of the pipe.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int Uncompress_Bzip2(int filefd)
+{
+#if defined(USE_BZIP2) && USE_BZIP2 && !defined(_MSC_VER) && !defined(__MINGW32__)
+
+ int pipefd=-1;
+
+ if(pipe_and_fork(filefd,&pipefd))
+    return(pipefd);
+
+ uncompress_bzip2_pipe(filefd,pipefd);
+
+ exit(EXIT_SUCCESS);
+
+#else /* USE_BZIP2 */
+
+ logassert(0,"No bzip2 compression support available (re-compile and try again)");
+
+ return(0);
+
+#endif /* USE_BZIP2 */
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create a child process to uncompress data on a file descriptor as if it were a pipe.
+
+  int Uncompress_Gzip Returns the file descriptor of the uncompressed end of the pipe.
+
+  int filefd The file descriptor of the compressed end of the pipe.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int Uncompress_Gzip(int filefd)
+{
+#if defined(USE_GZIP) && USE_GZIP && !defined(_MSC_VER) && !defined(__MINGW32__)
+
+ int pipefd=-1;
+
+ if(pipe_and_fork(filefd,&pipefd))
+    return(pipefd);
+
+ uncompress_gzip_pipe(filefd,pipefd);
+
+ exit(EXIT_SUCCESS);
+
+#else /* USE_GZIP */
+
+ logassert(0,"No gzip compression support available (re-compile and try again)");
+
+ return(0);
+
+#endif /* USE_GZIP */
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create a child process to uncompress data on a file descriptor as if it were a pipe.
+
+  int Uncompress_Xz Returns the file descriptor of the uncompressed end of the pipe.
+
+  int filefd The file descriptor of the compressed end of the pipe.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int Uncompress_Xz(int filefd)
+{
+#if defined(USE_XZ) && USE_XZ && !defined(_MSC_VER) && !defined(__MINGW32__)
+
+ int pipefd=-1;
+
+ if(pipe_and_fork(filefd,&pipefd))
+    return(pipefd);
+
+ uncompress_xz_pipe(filefd,pipefd);
+
+ exit(EXIT_SUCCESS);
+
+#else /* USE_XZ */
+
+ logassert(0,"No xz compression support available (re-compile and try again)");
+
+ return(0);
+
+#endif /* USE_XZ */
+}
+
+
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+
+#if (defined(USE_BZIP2) && USE_BZIP2) || (defined(USE_GZIP) && USE_GZIP) || (defined(USE_XZ) && USE_XZ)
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create a pipe and then fork returning in the parent and child with a different end of the pipe.
+
+  int pipe_and_fork Returns 1 for the reading (parent) end of the pipe and 0 for the writing (child) end.
+
+  int filefd The file descriptor of the file.
+
+  int *pipefd Returns the file descriptor for the end of the pipe.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int pipe_and_fork(int filefd,int *pipefd)
+{
+ int pipe_fd[2]={-1,-1};
+ pid_t childpid;
+
+#define PIPE_READER 0
+#define PIPE_WRITER 1
+
+ if(pipe(pipe_fd))
+   {
+    logassert(0,"Cannot create pipe for uncompressor (try without using a compressed file)");
+    return(1);
+   }
+
+ if((childpid=fork()) == -1)
+   {
+    logassert(0,"Cannot create new process for uncompressor (try without using a compressed file)");
+    return(1);
+   }
+
+ if(childpid==0)   /* The child */
+   {
+    int i;
+
+    *pipefd=pipe_fd[PIPE_WRITER];
+
+    /* Close all unneeded file descriptors */
+
+    for(i=0;i<255;i++)
+       if(i!=filefd && i!=*pipefd)
+          close(i);
+
+    return(0);    
+   }
+ else   /* The parent */
+   {
+    struct sigaction action;
+
+    *pipefd=pipe_fd[PIPE_READER];
+
+    /* Close all unneeded file descriptors */
+
+    close(pipe_fd[PIPE_WRITER]);
+    close(filefd);
+
+    /* Ignore child exiting and pipe signals */
+
+    /* SIGCHLD */
+    action.sa_handler=SIG_IGN;
+    sigemptyset(&action.sa_mask);
+    action.sa_flags=0;
+    sigaction(SIGCHLD,&action,NULL);
+
+    /* SIGPIPE */
+    action.sa_handler=SIG_IGN;
+    sigemptyset(&action.sa_mask);
+    action.sa_flags=0;
+    sigaction(SIGPIPE,&action,NULL);
+
+    return(1);
+   }
+}
+
+#endif /* (defined(USE_BZIP2) && USE_BZIP2) || (defined(USE_GZIP) && USE_GZIP) || (defined(USE_XZ) && USE_XZ) */
+
+
+#if defined(USE_BZIP2) && USE_BZIP2
+
+/*++++++++++++++++++++++++++++++++++++++
+  Uncompress a file using bzip2 as a pipeline.
+
+  int filefd The incoming, compressed, data.
+
+  int pipefd The outgoing, uncompressed, data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void uncompress_bzip2_pipe(int filefd,int pipefd)
+{
+ bz_stream bz={0};
+ char inbuffer[16384],outbuffer[16384];
+ int infinished=0;
+ int state;
+
+ if(BZ2_bzDecompressInit(&bz,0,0)!=BZ_OK)
+    exit(EXIT_FAILURE);
+
+ do
+   {
+    if(bz.avail_in==0 && !infinished)
+      {
+       ssize_t n=read(filefd,inbuffer,sizeof(inbuffer));
+
+       if(n<=0)
+          infinished=1;
+       else
+         {
+          bz.next_in=inbuffer;
+          bz.avail_in=n;
+         }
+      }
+
+    bz.next_out=outbuffer;
+    bz.avail_out=sizeof(outbuffer);
+
+    state=BZ2_bzDecompress(&bz);
+
+    if(state!=BZ_OK && state!=BZ_STREAM_END)
+       exit(EXIT_FAILURE);
+
+    if(bz.avail_out<sizeof(outbuffer))
+      {
+       char *p;
+       ssize_t m,n;
+
+       p=outbuffer;
+       n=sizeof(outbuffer)-bz.avail_out;
+
+       while(n>0)
+         {
+          m=write(pipefd,p,n);
+
+          if(m<=0)
+             exit(EXIT_FAILURE);
+
+          p+=m;
+          n-=m;
+         }
+      }
+   }
+ while(state!=BZ_STREAM_END);
+
+ if(BZ2_bzDecompressEnd(&bz)!=BZ_OK)
+    exit(EXIT_FAILURE);
+
+ exit(EXIT_SUCCESS);
+}
+
+#endif /* USE_BZIP2 */
+
+
+#if defined(USE_GZIP) && USE_GZIP
+
+/*++++++++++++++++++++++++++++++++++++++
+  Uncompress a file using gzip as a pipeline.
+
+  int filefd The incoming, compressed, data.
+
+  int pipefd The outgoing, uncompressed, data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void uncompress_gzip_pipe(int filefd,int pipefd)
+{
+ z_stream z={0};
+ unsigned char inbuffer[16384],outbuffer[16384];
+ int infinished=0;
+ int state;
+
+ if(inflateInit2(&z,15+32)!=Z_OK)
+    exit(EXIT_FAILURE);
+
+ do
+   {
+    if(z.avail_in==0 && !infinished)
+      {
+       ssize_t n=read(filefd,inbuffer,sizeof(inbuffer));
+
+       if(n<=0)
+          infinished=1;
+       else
+         {
+          z.next_in=inbuffer;
+          z.avail_in=n;
+         }
+      }
+
+    z.next_out=outbuffer;
+    z.avail_out=sizeof(outbuffer);
+
+    state=inflate(&z,Z_NO_FLUSH);
+
+    if(state!=Z_OK && state!=Z_STREAM_END)
+      {
+       exit(EXIT_FAILURE);
+      }
+
+    if(z.avail_out<sizeof(outbuffer))
+      {
+       unsigned char *p;
+       ssize_t n,m;
+
+       p=outbuffer;
+       n=sizeof(outbuffer)-z.avail_out;
+
+       while(n>0)
+         {
+          m=write(pipefd,p,n);
+
+          if(m<=0)
+             exit(EXIT_FAILURE);
+
+          p+=m;
+          n-=m;
+         }
+      }
+   }
+ while(state!=Z_STREAM_END);
+
+ if(inflateEnd(&z)!=Z_OK)
+    exit(EXIT_FAILURE);
+
+ exit(EXIT_SUCCESS);
+}
+
+#endif /* USE_GZIP */
+
+
+#if defined(USE_XZ) && USE_XZ
+
+/*++++++++++++++++++++++++++++++++++++++
+  Uncompress a file using xz as a pipeline.
+
+  int filefd The incoming, compressed, data.
+
+  int pipefd The outgoing, uncompressed, data.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void uncompress_xz_pipe(int filefd,int pipefd)
+{
+ lzma_stream lzma=LZMA_STREAM_INIT;
+ unsigned char inbuffer[16384],outbuffer[16384];
+ int infinished=0;
+ lzma_ret retval;
+
+ if(lzma_stream_decoder(&lzma,UINT64_MAX,0)!=LZMA_OK)
+    exit(EXIT_FAILURE);
+
+ do
+   {
+    if(lzma.avail_in==0 && !infinished)
+      {
+       ssize_t n=read(filefd,inbuffer,sizeof(inbuffer));
+
+       if(n<=0)
+          infinished=1;
+       else
+         {
+          lzma.next_in=inbuffer;
+          lzma.avail_in=n;
+         }
+      }
+
+    lzma.next_out=outbuffer;
+    lzma.avail_out=sizeof(outbuffer);
+
+    retval=lzma_code(&lzma,LZMA_RUN);
+
+    if(retval!=LZMA_OK && retval!=LZMA_STREAM_END)
+      {
+       exit(EXIT_FAILURE);
+      }
+
+    if(lzma.avail_out<sizeof(outbuffer))
+      {
+       unsigned char *p;
+       ssize_t n,m;
+
+       p=outbuffer;
+       n=sizeof(outbuffer)-lzma.avail_out;
+
+       while(n>0)
+         {
+          m=write(pipefd,p,n);
+
+          if(m<=0)
+             exit(EXIT_FAILURE);
+
+          p+=m;
+          n-=m;
+         }
+      }
+   }
+ while(retval!=LZMA_STREAM_END);
+
+ lzma_end(&lzma);
+
+ exit(EXIT_SUCCESS);
+}
+
+#endif /* USE_XZ */
+
+#endif /* !defined(_MSC_VER) && !defined(__MINGW32__) */
diff --git a/3rdparty/Routino/src/uncompress.h b/3rdparty/Routino/src/uncompress.h
new file mode 100644
index 0000000..5c850ca
--- /dev/null
+++ b/3rdparty/Routino/src/uncompress.h
@@ -0,0 +1,32 @@
+/***************************************
+ Function prototypes for file uncompression.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2012-2014 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef UNCOMPRESS_H
+#define UNCOMPRESS_H    /*+ To stop multiple inclusions. +*/
+
+int Uncompress_Bzip2(int filefd);
+
+int Uncompress_Gzip(int filefd);
+
+int Uncompress_Xz(int filefd);
+
+#endif /* UNCOMPRESS_H */
diff --git a/3rdparty/Routino/src/visualiser.c b/3rdparty/Routino/src/visualiser.c
new file mode 100644
index 0000000..cd79ec1
--- /dev/null
+++ b/3rdparty/Routino/src/visualiser.c
@@ -0,0 +1,1154 @@
+/***************************************
+ Extract data from Routino.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "types.h"
+#include "nodes.h"
+#include "segments.h"
+#include "ways.h"
+#include "relations.h"
+#include "errorlog.h"
+
+#include "typesx.h"
+
+#include "visualiser.h"
+
+
+/* Limit types */
+
+#define SPEED_LIMIT  1
+#define WEIGHT_LIMIT 2
+#define HEIGHT_LIMIT 3
+#define WIDTH_LIMIT  4
+#define LENGTH_LIMIT 5
+
+/* Local types */
+
+typedef void (*callback_t)(index_t node,double latitude,double longitude);
+
+/* Local variables (intialised by entry-point function before later use) */
+
+static Nodes     *OSMNodes;
+static Segments  *OSMSegments;
+static Ways      *OSMWays;
+static Relations *OSMRelations;
+
+static double LatMin;
+static double LatMax;
+static double LonMin;
+static double LonMax;
+
+static int limit_type=0;
+static Highway highways=Highway_None;
+static Transports transports=Transports_None;
+static Properties properties=Properties_None;
+static highway_t waytype=0;
+
+/* Local functions */
+
+static void find_all_nodes(Nodes *nodes,callback_t callback);
+
+static void output_junctions(index_t node,double latitude,double longitude);
+static void output_super(index_t node,double latitude,double longitude);
+static void output_waytype(index_t node,double latitude,double longitude);
+static void output_highway(index_t node,double latitude,double longitude);
+static void output_transport(index_t node,double latitude,double longitude);
+static void output_barrier(index_t node,double latitude,double longitude);
+static void output_turnrestriction(index_t node,double latitude,double longitude);
+static void output_limits(index_t node,double latitude,double longitude);
+static void output_property(index_t node,double latitude,double longitude);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Output the data for junctions (--data=junctions).
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void OutputJunctions(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax)
+{
+ /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
+
+ OSMNodes=nodes;
+ OSMSegments=segments;
+ OSMWays=ways;
+ OSMRelations=relations;
+
+ LatMin=latmin;
+ LatMax=latmax;
+ LonMin=lonmin;
+ LonMax=lonmax;
+
+ /* Iterate through the nodes and process them */
+
+ find_all_nodes(nodes,(callback_t)output_junctions);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process a single node and output all those that are junctions (called as a callback).
+
+  index_t node The node to output.
+
+  double latitude The latitude of the node.
+
+  double longitude The longitude of the node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void output_junctions(index_t node,double latitude,double longitude)
+{
+ Node *nodep=LookupNode(OSMNodes,node,1);
+ Segment *segmentp;
+ Way *firstwayp;
+ int count=0,difference=0;
+
+ segmentp=FirstSegment(OSMSegments,nodep,1);
+ firstwayp=LookupWay(OSMWays,segmentp->way,1);
+
+ do
+   {
+    Way *wayp=LookupWay(OSMWays,segmentp->way,2);
+
+    if(IsNormalSegment(segmentp))
+       count++;
+
+    if(WaysCompare(firstwayp,wayp))
+       difference=1;
+
+    segmentp=NextSegment(OSMSegments,segmentp,node);
+   }
+ while(segmentp);
+
+ if(count!=2 || difference)
+    printf("node%"Pindex_t" %.6f %.6f %d\n",node,radians_to_degrees(latitude),radians_to_degrees(longitude),count);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Output the data for super-nodes and super-segments (--data=super).
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void OutputSuper(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax)
+{
+ /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
+
+ OSMNodes=nodes;
+ OSMSegments=segments;
+ OSMWays=ways;
+ OSMRelations=relations;
+
+ LatMin=latmin;
+ LatMax=latmax;
+ LonMin=lonmin;
+ LonMax=lonmax;
+
+ /* Iterate through the nodes and process them */
+
+ find_all_nodes(nodes,(callback_t)output_super);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process a single node and output all that are super-nodes and all connected super-segments (called as a callback).
+
+  index_t node The node to output.
+
+  double latitude The latitude of the node.
+
+  double longitude The longitude of the node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void output_super(index_t node,double latitude,double longitude)
+{
+ Node *nodep=LookupNode(OSMNodes,node,1);
+ Segment *segmentp;
+
+ if(!IsSuperNode(nodep))
+    return;
+
+ printf("node%"Pindex_t" %.6f %.6f\n",node,radians_to_degrees(latitude),radians_to_degrees(longitude));
+
+ segmentp=FirstSegment(OSMSegments,nodep,1);
+
+ do
+   {
+    if(IsSuperSegment(segmentp))
+      {
+       index_t othernode=OtherNode(segmentp,node);
+       double lat,lon;
+
+       GetLatLong(OSMNodes,othernode,NULL,&lat,&lon);
+
+       if(node>othernode || (lat<LatMin || lat>LatMax || lon<LonMin || lon>LonMax))
+          printf("segment%"Pindex_t" %.6f %.6f\n",IndexSegment(OSMSegments,segmentp),radians_to_degrees(lat),radians_to_degrees(lon));
+      }
+
+    segmentp=NextSegment(OSMSegments,segmentp,node);
+   }
+ while(segmentp);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Output the data for segments of special highway types (--data=waytype-oneway etc).
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+
+  highway_t mask A bit mask that must match the highway type.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void OutputWaytype(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax,highway_t mask)
+{
+ /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
+
+ OSMNodes=nodes;
+ OSMSegments=segments;
+ OSMWays=ways;
+ OSMRelations=relations;
+
+ LatMin=latmin;
+ LatMax=latmax;
+ LonMin=lonmin;
+ LonMax=lonmax;
+
+ /* Iterate through the nodes and process them */
+
+ waytype=mask;
+
+ find_all_nodes(nodes,(callback_t)output_waytype);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process a single node and output all connected segments of a particular special highway type (called as a callback).
+
+  index_t node The node to output.
+
+  double latitude The latitude of the node.
+
+  double longitude The longitude of the node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void output_waytype(index_t node,double latitude,double longitude)
+{
+ Node *nodep=LookupNode(OSMNodes,node,1);
+ Segment *segmentp;
+
+ segmentp=FirstSegment(OSMSegments,nodep,1);
+
+ do
+   {
+    if(IsNormalSegment(segmentp))
+      {
+       Way *wayp=LookupWay(OSMWays,segmentp->way,1);
+
+       if(wayp->type&waytype)
+         {
+          index_t othernode=OtherNode(segmentp,node);
+          double lat,lon;
+
+          GetLatLong(OSMNodes,othernode,NULL,&lat,&lon);
+
+          if(node>othernode || (lat<LatMin || lat>LatMax || lon<LonMin || lon>LonMax))
+            {
+             if(IsOnewayFrom(segmentp,node))
+                printf("segment%"Pindex_t" %.6f %.6f %.6f %.6f\n",IndexSegment(OSMSegments,segmentp),radians_to_degrees(latitude),radians_to_degrees(longitude),radians_to_degrees(lat),radians_to_degrees(lon));
+             else if(IsOnewayFrom(segmentp,othernode))
+                printf("segment%"Pindex_t" %.6f %.6f %.6f %.6f\n",IndexSegment(OSMSegments,segmentp),radians_to_degrees(lat),radians_to_degrees(lon),radians_to_degrees(latitude),radians_to_degrees(longitude));
+            }
+         }
+      }
+
+    segmentp=NextSegment(OSMSegments,segmentp,node);
+   }
+ while(segmentp);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Output the data for segments of a particular highway type (--data=highway-primary etc).
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+
+  Highway highway The type of highway.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void OutputHighway(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax,Highway highway)
+{
+ /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
+
+ OSMNodes=nodes;
+ OSMSegments=segments;
+ OSMWays=ways;
+ OSMRelations=relations;
+
+ LatMin=latmin;
+ LatMax=latmax;
+ LonMin=lonmin;
+ LonMax=lonmax;
+
+ /* Iterate through the nodes and process them */
+
+ highways=highway;
+
+ find_all_nodes(nodes,(callback_t)output_highway);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process a single node and output all connected segments that are of a particular highway type (called as a callback).
+
+  index_t node The node to output.
+
+  double latitude The latitude of the node.
+
+  double longitude The longitude of the node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void output_highway(index_t node,double latitude,double longitude)
+{
+ Node *nodep=LookupNode(OSMNodes,node,1);
+ Segment *segmentp;
+
+ segmentp=FirstSegment(OSMSegments,nodep,1);
+
+ do
+   {
+    if(IsNormalSegment(segmentp))
+      {
+       Way *wayp=LookupWay(OSMWays,segmentp->way,1);
+
+       if(HIGHWAY(wayp->type)==highways)
+         {
+          index_t othernode=OtherNode(segmentp,node);
+          double lat,lon;
+
+          GetLatLong(OSMNodes,othernode,NULL,&lat,&lon);
+
+          if(node>othernode || (lat<LatMin || lat>LatMax || lon<LonMin || lon>LonMax))
+             printf("segment%"Pindex_t" %.6f %.6f %.6f %.6f\n",IndexSegment(OSMSegments,segmentp),radians_to_degrees(latitude),radians_to_degrees(longitude),radians_to_degrees(lat),radians_to_degrees(lon));
+         }
+      }
+
+    segmentp=NextSegment(OSMSegments,segmentp,node);
+   }
+ while(segmentp);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Output the data for segments allowed for a particular type of traffic (--data=transport-motorcar etc).
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+
+  Transport transport The type of transport.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void OutputTransport(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax,Transport transport)
+{
+ /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
+
+ OSMNodes=nodes;
+ OSMSegments=segments;
+ OSMWays=ways;
+ OSMRelations=relations;
+
+ LatMin=latmin;
+ LatMax=latmax;
+ LonMin=lonmin;
+ LonMax=lonmax;
+
+ /* Iterate through the nodes and process them */
+
+ transports=TRANSPORTS(transport);
+
+ find_all_nodes(nodes,(callback_t)output_transport);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process a single node and output all connected segments for a particular traffic type (called as a callback).
+
+  index_t node The node to output.
+
+  double latitude The latitude of the node.
+
+  double longitude The longitude of the node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void output_transport(index_t node,double latitude,double longitude)
+{
+ Node *nodep=LookupNode(OSMNodes,node,1);
+ Segment *segmentp;
+
+ segmentp=FirstSegment(OSMSegments,nodep,1);
+
+ do
+   {
+    if(IsNormalSegment(segmentp))
+      {
+       Way *wayp=LookupWay(OSMWays,segmentp->way,1);
+
+       if(wayp->allow&transports)
+         {
+          index_t othernode=OtherNode(segmentp,node);
+          double lat,lon;
+
+          GetLatLong(OSMNodes,othernode,NULL,&lat,&lon);
+
+          if(node>othernode || (lat<LatMin || lat>LatMax || lon<LonMin || lon>LonMax))
+             printf("segment%"Pindex_t" %.6f %.6f %.6f %.6f\n",IndexSegment(OSMSegments,segmentp),radians_to_degrees(latitude),radians_to_degrees(longitude),radians_to_degrees(lat),radians_to_degrees(lon));
+         }
+      }
+
+    segmentp=NextSegment(OSMSegments,segmentp,node);
+   }
+ while(segmentp);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Output the data for nodes disallowed for a particular type of traffic (--data=barrier).
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+
+  Transport transport The type of transport.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void OutputBarrier(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax,Transport transport)
+{
+ /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
+
+ OSMNodes=nodes;
+ OSMSegments=segments;
+ OSMWays=ways;
+ OSMRelations=relations;
+
+ LatMin=latmin;
+ LatMax=latmax;
+ LonMin=lonmin;
+ LonMax=lonmax;
+
+ /* Iterate through the nodes and process them */
+
+ transports=TRANSPORTS(transport);
+
+ find_all_nodes(nodes,(callback_t)output_barrier);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process a single node and output those that are barriers (called as a callback).
+
+  index_t node The node to output.
+
+  double latitude The latitude of the node.
+
+  double longitude The longitude of the node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void output_barrier(index_t node,double latitude,double longitude)
+{
+ Node *nodep=LookupNode(OSMNodes,node,1);
+
+ if(!(nodep->allow&transports))
+    printf("node%"Pindex_t" %.6f %.6f\n",node,radians_to_degrees(latitude),radians_to_degrees(longitude));
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Output the data for turn restrictions (--data=turns).
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void OutputTurnRestrictions(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax)
+{
+ /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
+
+ OSMNodes=nodes;
+ OSMSegments=segments;
+ OSMWays=ways;
+ OSMRelations=relations;
+
+ LatMin=latmin;
+ LatMax=latmax;
+ LonMin=lonmin;
+ LonMax=lonmax;
+
+ /* Iterate through the nodes and process them */
+
+ find_all_nodes(nodes,(callback_t)output_turnrestriction);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process a single node and output those that are 'via' nodes for a turn restriction and the associated segments (called as a callback).
+
+  index_t node The node to output.
+
+  double latitude The latitude of the node.
+
+  double longitude The longitude of the node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void output_turnrestriction(index_t node,double latitude,double longitude)
+{
+ Node *nodep=LookupNode(OSMNodes,node,1);
+ index_t turnrelation=NO_RELATION;
+
+ if(!IsTurnRestrictedNode(nodep))
+    return;
+
+ turnrelation=FindFirstTurnRelation1(OSMRelations,node);
+
+ do
+   {
+    TurnRelation *relation;
+    Segment *from_segmentp,*to_segmentp;
+    index_t from_node,to_node;
+    double from_lat,from_lon,to_lat,to_lon;
+
+    relation=LookupTurnRelation(OSMRelations,turnrelation,1);
+
+    from_segmentp=LookupSegment(OSMSegments,relation->from,1);
+    to_segmentp  =LookupSegment(OSMSegments,relation->to  ,2);
+
+    from_node=OtherNode(from_segmentp,node);
+    to_node  =OtherNode(to_segmentp  ,node);
+
+    GetLatLong(OSMNodes,from_node,NULL,&from_lat,&from_lon);
+    GetLatLong(OSMNodes,to_node  ,NULL,&to_lat  ,&to_lon);
+
+    printf("turn-relation%"Pindex_t" %.6f %.6f %.6f %.6f %.6f %.6f\n",
+           turnrelation,
+           radians_to_degrees(from_lat),radians_to_degrees(from_lon),
+           radians_to_degrees(latitude),radians_to_degrees(longitude),
+           radians_to_degrees(to_lat),radians_to_degrees(to_lon));
+
+    turnrelation=FindNextTurnRelation1(OSMRelations,turnrelation);
+   }
+ while(turnrelation!=NO_RELATION);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Output the data for speed limits (--data=speed).
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void OutputSpeedLimits(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax)
+{
+ /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
+
+ OSMNodes=nodes;
+ OSMSegments=segments;
+ OSMWays=ways;
+ OSMRelations=relations;
+
+ LatMin=latmin;
+ LatMax=latmax;
+ LonMin=lonmin;
+ LonMax=lonmax;
+
+ /* Iterate through the nodes and process them */
+
+ limit_type=SPEED_LIMIT;
+
+ find_all_nodes(nodes,(callback_t)output_limits);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Output the data for weight limits (--data=weight).
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void OutputWeightLimits(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax)
+{
+ /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
+
+ OSMNodes=nodes;
+ OSMSegments=segments;
+ OSMWays=ways;
+ OSMRelations=relations;
+
+ LatMin=latmin;
+ LatMax=latmax;
+ LonMin=lonmin;
+ LonMax=lonmax;
+
+ /* Iterate through the nodes and process them */
+
+ limit_type=WEIGHT_LIMIT;
+
+ find_all_nodes(nodes,(callback_t)output_limits);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Output the data for height limits (--data=height).
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void OutputHeightLimits(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax)
+{
+ /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
+
+ OSMNodes=nodes;
+ OSMSegments=segments;
+ OSMWays=ways;
+ OSMRelations=relations;
+
+ LatMin=latmin;
+ LatMax=latmax;
+ LonMin=lonmin;
+ LonMax=lonmax;
+
+ /* Iterate through the nodes and process them */
+
+ limit_type=HEIGHT_LIMIT;
+
+ find_all_nodes(nodes,(callback_t)output_limits);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Output the data for width limits (--data=width).
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void OutputWidthLimits(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax)
+{
+ /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
+
+ OSMNodes=nodes;
+ OSMSegments=segments;
+ OSMWays=ways;
+ OSMRelations=relations;
+
+ LatMin=latmin;
+ LatMax=latmax;
+ LonMin=lonmin;
+ LonMax=lonmax;
+
+ /* Iterate through the nodes and process them */
+
+ limit_type=WIDTH_LIMIT;
+
+ find_all_nodes(nodes,(callback_t)output_limits);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Output the data for length limits (--data=length).
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void OutputLengthLimits(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax)
+{
+ /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
+
+ OSMNodes=nodes;
+ OSMSegments=segments;
+ OSMWays=ways;
+ OSMRelations=relations;
+
+ LatMin=latmin;
+ LatMax=latmax;
+ LonMin=lonmin;
+ LonMax=lonmax;
+
+ /* Iterate through the nodes and process them */
+
+ limit_type=LENGTH_LIMIT;
+
+ find_all_nodes(nodes,(callback_t)output_limits);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process a single node and output those and connected segments that have a speed, weight, height, width or length limit change (called as a callback).
+
+  index_t node The node to output.
+
+  double latitude The latitude of the node.
+
+  double longitude The longitude of the node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void output_limits(index_t node,double latitude,double longitude)
+{
+ Node *nodep=LookupNode(OSMNodes,node,1);
+ Segment *segmentp,segmentps[MAX_SEG_PER_NODE];
+ index_t segments[MAX_SEG_PER_NODE];
+ int limits[MAX_SEG_PER_NODE];
+ int count=0;
+ int i,j,same=0;
+
+ segmentp=FirstSegment(OSMSegments,nodep,1);
+
+ do
+   {
+    if(IsNormalSegment(segmentp) && count<MAX_SEG_PER_NODE)
+      {
+       Way *wayp=LookupWay(OSMWays,segmentp->way,1);
+
+       segmentps[count]=*segmentp;
+       segments [count]=IndexSegment(OSMSegments,segmentp);
+
+       switch(limit_type)
+         {
+         case SPEED_LIMIT:  limits[count]=wayp->speed;  break;
+         case WEIGHT_LIMIT: limits[count]=wayp->weight; break;
+         case HEIGHT_LIMIT: limits[count]=wayp->height; break;
+         case WIDTH_LIMIT:  limits[count]=wayp->width;  break;
+         case LENGTH_LIMIT: limits[count]=wayp->length; break;
+         }
+
+       if(limits[count] || HIGHWAY(wayp->type)<Highway_Track)
+          count++;
+      }
+
+    segmentp=NextSegment(OSMSegments,segmentp,node);
+   }
+ while(segmentp);
+
+ /* Nodes with only one limit are not interesting */
+
+ if(count==1)
+    return;
+
+ /* Nodes with all segments the same limit are not interesting */
+
+ same=0;
+ for(j=0;j<count;j++)
+    if(limits[0]==limits[j])
+       same++;
+
+ if(same==count)
+    return;
+
+ /* Display the interesting limits */
+
+ printf("node%"Pindex_t" %.6f %.6f\n",node,radians_to_degrees(latitude),radians_to_degrees(longitude));
+
+ for(i=0;i<count;i++)
+   {
+    same=0;
+    for(j=0;j<count;j++)
+       if(limits[i]==limits[j])
+          same++;
+
+    if(count==2 || same!=(count-1))
+      {
+       double lat,lon;
+
+       GetLatLong(OSMNodes,OtherNode(&segmentps[i],node),NULL,&lat,&lon);
+
+       switch(limit_type)
+         {
+         case SPEED_LIMIT:
+          printf("segment%"Pindex_t" %.6f %.6f %d\n",segments[i],radians_to_degrees(lat),radians_to_degrees(lon),speed_to_kph(limits[i]));
+          break;
+         case WEIGHT_LIMIT:
+          printf("segment%"Pindex_t" %.6f %.6f %.1f\n",segments[i],radians_to_degrees(lat),radians_to_degrees(lon),weight_to_tonnes(limits[i]));
+          break;
+         case HEIGHT_LIMIT:
+          printf("segment%"Pindex_t" %.6f %.6f %.1f\n",segments[i],radians_to_degrees(lat),radians_to_degrees(lon),height_to_metres(limits[i]));
+          break;
+         case WIDTH_LIMIT:
+          printf("segment%"Pindex_t" %.6f %.6f %.1f\n",segments[i],radians_to_degrees(lat),radians_to_degrees(lon),width_to_metres(limits[i]));
+          break;
+         case LENGTH_LIMIT:
+          printf("segment%"Pindex_t" %.6f %.6f %.1f\n",segments[i],radians_to_degrees(lat),radians_to_degrees(lon),length_to_metres(limits[i]));
+          break;
+         }
+      }
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Output the data for segments that have a particular property (--data=property-paved etc).
+
+  Nodes *nodes The set of nodes to use.
+
+  Segments *segments The set of segments to use.
+
+  Ways *ways The set of ways to use.
+
+  Relations *relations The set of relations to use.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+
+  Property property The type of property.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void OutputProperty(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax,Property property)
+{
+ /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
+
+ OSMNodes=nodes;
+ OSMSegments=segments;
+ OSMWays=ways;
+ OSMRelations=relations;
+
+ LatMin=latmin;
+ LatMax=latmax;
+ LonMin=lonmin;
+ LonMax=lonmax;
+
+ /* Iterate through the nodes and process them */
+
+ properties=PROPERTIES(property);
+
+ find_all_nodes(nodes,(callback_t)output_property);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Process a single node and output all connected segments with a particular property (called as a callback).
+
+  index_t node The node to output.
+
+  double latitude The latitude of the node.
+
+  double longitude The longitude of the node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void output_property(index_t node,double latitude,double longitude)
+{
+ Node *nodep=LookupNode(OSMNodes,node,1);
+ Segment *segmentp;
+
+ segmentp=FirstSegment(OSMSegments,nodep,1);
+
+ do
+   {
+    if(IsNormalSegment(segmentp))
+      {
+       Way *wayp=LookupWay(OSMWays,segmentp->way,1);
+
+       if(wayp->props&properties)
+         {
+          index_t othernode=OtherNode(segmentp,node);
+          double lat,lon;
+
+          GetLatLong(OSMNodes,othernode,NULL,&lat,&lon);
+
+          if(node>othernode || (lat<LatMin || lat>LatMax || lon<LonMin || lon>LonMax))
+             printf("segment%"Pindex_t" %.6f %.6f %.6f %.6f\n",IndexSegment(OSMSegments,segmentp),radians_to_degrees(latitude),radians_to_degrees(longitude),radians_to_degrees(lat),radians_to_degrees(lon));
+         }
+      }
+
+    segmentp=NextSegment(OSMSegments,segmentp,node);
+   }
+ while(segmentp);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  A function to iterate through all nodes and call a callback function for each one.
+
+  Nodes *nodes The set of nodes to use.
+
+  callback_t callback The callback function for each node.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static void find_all_nodes(Nodes *nodes,callback_t callback)
+{
+ ll_bin_t latminbin=latlong_to_bin(radians_to_latlong(LatMin))-nodes->file.latzero;
+ ll_bin_t latmaxbin=latlong_to_bin(radians_to_latlong(LatMax))-nodes->file.latzero;
+ ll_bin_t lonminbin=latlong_to_bin(radians_to_latlong(LonMin))-nodes->file.lonzero;
+ ll_bin_t lonmaxbin=latlong_to_bin(radians_to_latlong(LonMax))-nodes->file.lonzero;
+ ll_bin_t latb,lonb;
+ index_t i,index1,index2;
+
+ /* Loop through all of the nodes. */
+
+ if(latminbin<0)                   latminbin=0;
+ if(latmaxbin>nodes->file.latbins) latmaxbin=nodes->file.latbins-1;
+
+ if(lonminbin<0)                   lonminbin=0;
+ if(lonmaxbin>nodes->file.lonbins) lonmaxbin=nodes->file.lonbins-1;
+
+ for(latb=latminbin;latb<=latmaxbin;latb++)
+    for(lonb=lonminbin;lonb<=lonmaxbin;lonb++)
+      {
+       ll_bin2_t llbin=lonb*nodes->file.latbins+latb;
+
+       if(llbin<0 || llbin>(nodes->file.latbins*nodes->file.lonbins))
+          continue;
+
+       index1=LookupNodeOffset(nodes,llbin);
+       index2=LookupNodeOffset(nodes,llbin+1);
+
+       for(i=index1;i<index2;i++)
+         {
+          Node *nodep=LookupNode(nodes,i,1);
+
+          double lat=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb)+off_to_latlong(nodep->latoffset));
+          double lon=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb)+off_to_latlong(nodep->lonoffset));
+
+          if(lat>LatMin && lat<LatMax && lon>LonMin && lon<LonMax)
+             (*callback)(i,lat,lon);
+         }
+      }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Output the data for error logs within the region (--data=errorlogs).
+
+  ErrorLogs *errorlogs The set of error logs to use.
+
+  double latmin The minimum latitude.
+
+  double latmax The maximum latitude.
+
+  double lonmin The minimum longitude.
+
+  double lonmax The maximum longitude.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void OutputErrorLog(ErrorLogs *errorlogs,double latmin,double latmax,double lonmin,double lonmax)
+{
+ ll_bin_t latminbin=latlong_to_bin(radians_to_latlong(latmin))-errorlogs->file.latzero;
+ ll_bin_t latmaxbin=latlong_to_bin(radians_to_latlong(latmax))-errorlogs->file.latzero;
+ ll_bin_t lonminbin=latlong_to_bin(radians_to_latlong(lonmin))-errorlogs->file.lonzero;
+ ll_bin_t lonmaxbin=latlong_to_bin(radians_to_latlong(lonmax))-errorlogs->file.lonzero;
+ ll_bin_t latb,lonb;
+ index_t i,index1,index2;
+
+ /* Loop through all of the error logs. */
+
+ for(latb=latminbin;latb<=latmaxbin;latb++)
+    for(lonb=lonminbin;lonb<=lonmaxbin;lonb++)
+      {
+       ll_bin2_t llbin=lonb*errorlogs->file.latbins+latb;
+
+       if(llbin<0 || llbin>(errorlogs->file.latbins*errorlogs->file.lonbins))
+          continue;
+
+       index1=LookupErrorLogOffset(errorlogs,llbin);
+       index2=LookupErrorLogOffset(errorlogs,llbin+1);
+
+       if(index2>errorlogs->file.number_geo)
+          index2=errorlogs->file.number_geo;
+
+       for(i=index1;i<index2;i++)
+         {
+          ErrorLog *errorlogp=LookupErrorLog(errorlogs,i,1);
+
+          double lat=latlong_to_radians(bin_to_latlong(errorlogs->file.latzero+latb)+off_to_latlong(errorlogp->latoffset));
+          double lon=latlong_to_radians(bin_to_latlong(errorlogs->file.lonzero+lonb)+off_to_latlong(errorlogp->lonoffset));
+
+          if(lat>latmin && lat<latmax && lon>lonmin && lon<lonmax)
+             printf("errorlog%"Pindex_t" %.6f %.6f\n",i,radians_to_degrees(lat),radians_to_degrees(lon));
+         }
+      }
+}
diff --git a/3rdparty/Routino/src/visualiser.h b/3rdparty/Routino/src/visualiser.h
new file mode 100644
index 0000000..2979d91
--- /dev/null
+++ b/3rdparty/Routino/src/visualiser.h
@@ -0,0 +1,59 @@
+/***************************************
+ Header file for visualiser functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2014 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef VISUALISER_H
+#define VISUALISER_H    /*+ To stop multiple inclusions. +*/
+
+#include "types.h"
+#include "errorlog.h"
+
+
+/* Functions in visualiser.c */
+
+void OutputJunctions(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax);
+
+void OutputSuper(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax);
+
+void OutputWaytype(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax,highway_t mask);
+
+void OutputHighway(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax,Highway highway);
+
+void OutputTransport(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax,Transport transport);
+
+void OutputBarrier(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax,Transport transport);
+
+void OutputTurnRestrictions(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax);
+
+void OutputSpeedLimits(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax);
+
+void OutputWeightLimits(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax);
+
+void OutputHeightLimits(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax);
+void OutputWidthLimits(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax);
+void OutputLengthLimits(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax);
+
+void OutputProperty(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,double latmin,double latmax,double lonmin,double lonmax,Property property);
+
+void OutputErrorLog(ErrorLogs *errorlogs,double latmin,double latmax,double lonmin,double lonmax);
+
+
+#endif /* VISUALISER_H */
diff --git a/3rdparty/Routino/src/ways.c b/3rdparty/Routino/src/ways.c
new file mode 100644
index 0000000..a9d42f6
--- /dev/null
+++ b/3rdparty/Routino/src/ways.c
@@ -0,0 +1,148 @@
+/***************************************
+ Way data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+
+#include "ways.h"
+
+#include "files.h"
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Load in a way list from a file.
+
+  Ways *LoadWayList Returns the way list.
+
+  const char *filename The name of the file to load.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+Ways *LoadWayList(const char *filename)
+{
+ Ways *ways;
+
+ ways=(Ways*)malloc(sizeof(Ways));
+
+#if !SLIM
+
+ ways->data=MapFile(filename);
+
+ /* Copy the WaysFile structure from the loaded data */
+
+ ways->file=*((WaysFile*)ways->data);
+
+ /* Set the pointers in the Ways structure. */
+
+ ways->ways =(Way *)(ways->data+sizeof(WaysFile));
+ ways->names=(char*)(ways->data+sizeof(WaysFile)+ways->file.number*sizeof(Way));
+
+#else
+
+ ways->fd=SlimMapFile(filename);
+
+ /* Copy the WaysFile header structure from the loaded data */
+
+ SlimFetch(ways->fd,&ways->file,sizeof(WaysFile),0);
+
+ ways->namesoffset=sizeof(WaysFile)+ways->file.number*sizeof(Way);
+
+ memset(ways->ncached,0,sizeof(ways->ncached));
+
+ ways->cache=NewWayCache();
+#ifndef LIBROUTINO
+ log_malloc(ways->cache,sizeof(*ways->cache));
+#endif
+
+#endif
+
+ return(ways);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Destroy the way list.
+
+  Ways *ways The way list to destroy.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void DestroyWayList(Ways *ways)
+{
+#if !SLIM
+
+ ways->data=UnmapFile(ways->data);
+
+#else
+
+ ways->fd=SlimUnmapFile(ways->fd);
+
+#ifndef LIBROUTINO
+ log_free(ways->cache);
+#endif
+ DeleteWayCache(ways->cache);
+
+#endif
+
+ free(ways);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Return 0 if the two ways are the same (in respect of their types and limits),
+           otherwise return positive or negative to allow sorting.
+
+  int WaysCompare Returns a comparison.
+
+  Way *way1p The first way.
+
+  Way *way2p The second way.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int WaysCompare(Way *way1p,Way *way2p)
+{
+ if(way1p==way2p)
+    return(0);
+
+ if(way1p->type!=way2p->type)
+    return((int)way1p->type - (int)way2p->type);
+
+ if(way1p->allow!=way2p->allow)
+    return((int)way1p->allow - (int)way2p->allow);
+
+ if(way1p->props!=way2p->props)
+    return((int)way1p->props - (int)way2p->props);
+
+ if(way1p->speed!=way2p->speed)
+    return((int)way1p->speed - (int)way2p->speed);
+
+ if(way1p->weight!=way2p->weight)
+    return((int)way1p->weight - (int)way2p->weight);
+
+ if(way1p->height!=way2p->height)
+    return((int)way1p->height - (int)way2p->height);
+
+ if(way1p->width!=way2p->width)
+    return((int)way1p->width - (int)way2p->width);
+
+ if(way1p->length!=way2p->length)
+    return((int)way1p->length - (int)way2p->length);
+
+ return(0);
+}
diff --git a/3rdparty/Routino/src/ways.h b/3rdparty/Routino/src/ways.h
new file mode 100644
index 0000000..4c4c55a
--- /dev/null
+++ b/3rdparty/Routino/src/ways.h
@@ -0,0 +1,196 @@
+/***************************************
+ A header file for the ways.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef WAYS_H
+#define WAYS_H    /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "types.h"
+
+#include "cache.h"
+#include "files.h"
+
+
+/* Data structures */
+
+
+/*+ A structure containing a single way (members ordered to minimise overall size). +*/
+struct _Way
+{
+ index_t      name;             /*+ The offset of the name of the way in the names array. +*/
+
+ transports_t allow;            /*+ The type of traffic allowed on the way. +*/
+
+ highway_t    type;             /*+ The highway type of the way. +*/
+
+ properties_t props;            /*+ The properties of the way. +*/
+
+ speed_t      speed;            /*+ The defined maximum speed limit of the way. +*/
+
+ weight_t     weight;           /*+ The defined maximum weight of traffic on the way. +*/
+ height_t     height;           /*+ The defined maximum height of traffic on the way. +*/
+ width_t      width;            /*+ The defined maximum width of traffic on the way. +*/
+ length_t     length;           /*+ The defined maximum length of traffic on the way. +*/
+};
+
+
+/*+ A structure containing the header from the file. +*/
+typedef struct _WaysFile
+{
+ index_t      number;           /*+ The number of ways. +*/
+
+ highways_t   highways;         /*+ The types of highways that were seen when parsing. +*/
+ transports_t allow;            /*+ The types of traffic that were seen when parsing. +*/
+ properties_t props;            /*+ The properties that were seen when parsing. +*/
+}
+ WaysFile;
+
+
+/*+ A structure containing a set of ways (and pointers to mmap file). +*/
+struct _Ways
+{
+ WaysFile file;                 /*+ The header data from the file. +*/
+
+#if !SLIM
+
+ char      *data;               /*+ The memory mapped data. +*/
+
+ Way       *ways;               /*+ An array of ways. +*/
+ char      *names;              /*+ An array of characters containing the names. +*/
+
+#else
+
+ int        fd;                 /*+ The file descriptor for the file. +*/
+ off_t      namesoffset;        /*+ The offset of the names within the file. +*/
+
+ Way        cached[3];          /*+ Two cached nodes read from the file in slim mode. +*/
+
+ char      *ncached[3];         /*+ The cached way name. +*/
+
+ WayCache  *cache;              /*+ A RAM cache of ways read from the file. +*/
+
+#endif
+};
+
+
+/* Functions in ways.c */
+
+Ways *LoadWayList(const char *filename);
+
+void DestroyWayList(Ways *ways);
+
+int WaysCompare(Way *way1p,Way *way2p);
+
+
+/* Macros and inline functions */
+
+#if !SLIM
+
+/*+ Return a Way* pointer given a set of ways and an index. +*/
+#define LookupWay(xxx,yyy,zzz)     (&(xxx)->ways[yyy])
+
+/*+ Return the name of a way given the Way pointer and a set of ways. +*/
+#define WayName(xxx,yyy)           (&(xxx)->names[(yyy)->name])
+
+#else
+
+static inline Way *LookupWay(Ways *ways,index_t index,int position);
+
+static inline char *WayName(Ways *ways,Way *wayp);
+
+CACHE_NEWCACHE_PROTO(Way)
+CACHE_DELETECACHE_PROTO(Way)
+CACHE_FETCHCACHE_PROTO(Way)
+CACHE_INVALIDATECACHE_PROTO(Way)
+
+
+/* Inline functions */
+
+CACHE_STRUCTURE(Way)
+CACHE_NEWCACHE(Way)
+CACHE_DELETECACHE(Way)
+CACHE_FETCHCACHE(Way)
+CACHE_INVALIDATECACHE(Way)
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the Way information for a particular way.
+
+  Way *LookupWay Returns a pointer to the cached way information.
+
+  Ways *ways The set of ways to use.
+
+  index_t index The index of the way.
+
+  int position The position in the cache to store the value.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline Way *LookupWay(Ways *ways,index_t index,int position)
+{
+ ways->cached[position-1]=*FetchCachedWay(ways->cache,index,ways->fd,sizeof(WaysFile));
+
+ return(&ways->cached[position-1]);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find the name of a way.
+
+  char *WayName Returns a pointer to the name of the way.
+
+  Ways *ways The set of ways to use.
+
+  Way *wayp The Way pointer.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline char *WayName(Ways *ways,Way *wayp)
+{
+ int position=(int)(wayp-&ways->cached[-1]);
+ int n=0;
+
+ if(!ways->ncached[position-1])
+    ways->ncached[position-1]=(char*)malloc(64);
+
+ while(!SlimFetch(ways->fd,ways->ncached[position-1]+n,64,ways->namesoffset+wayp->name+n))
+   {
+    int i;
+
+    for(i=n;i<n+64;i++)
+       if(ways->ncached[position-1][i]==0)
+          goto exitloop;
+
+    n+=64;
+
+    ways->ncached[position-1]=(char*)realloc((void*)ways->ncached[position-1],n+64);
+   }
+
+ exitloop:
+
+ return(ways->ncached[position-1]);
+}
+
+#endif
+
+
+#endif /* WAYS_H */
diff --git a/3rdparty/Routino/src/waysx.c b/3rdparty/Routino/src/waysx.c
new file mode 100644
index 0000000..734c595
--- /dev/null
+++ b/3rdparty/Routino/src/waysx.c
@@ -0,0 +1,898 @@
+/***************************************
+ Extended Way data type functions.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "types.h"
+#include "ways.h"
+
+#include "typesx.h"
+#include "nodesx.h"
+#include "segmentsx.h"
+#include "waysx.h"
+
+#include "files.h"
+#include "logging.h"
+#include "sorting.h"
+
+
+/* Global variables */
+
+/*+ The command line '--tmpdir' option or its default value. +*/
+extern char *option_tmpdirname;
+
+/* Local variables */
+
+/*+ Temporary file-local variables for use by the sort functions (re-initialised for each sort). +*/
+static WaysX *sortwaysx;
+static SegmentsX *sortsegmentsx;
+
+/* Local functions */
+
+static int sort_by_id(WayX *a,WayX *b);
+static int deduplicate_and_index_by_id(WayX *wayx,index_t index);
+
+static int sort_by_name(char *a,char *b);
+
+static int delete_unused(WayX *wayx,index_t index);
+static int sort_by_name_and_prop_and_id(WayX *a,WayX *b);
+static int deduplicate_and_index_by_compact_id(WayX *wayx,index_t index);
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Allocate a new way list (create a new file or open an existing one).
+
+  WaysX *NewWayList Returns the way list.
+
+  int append Set to 1 if the file is to be opened for appending.
+
+  int readonly Set to 1 if the file is to be opened for reading.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+WaysX *NewWayList(int append,int readonly)
+{
+ WaysX *waysx;
+
+ waysx=(WaysX*)calloc(1,sizeof(WaysX));
+
+ logassert(waysx,"Failed to allocate memory (try using slim mode?)"); /* Check calloc() worked */
+
+ waysx->filename    =(char*)malloc(strlen(option_tmpdirname)+32);
+ waysx->filename_tmp=(char*)malloc(strlen(option_tmpdirname)+32); /* allow %p to be up to 20 bytes */
+
+ sprintf(waysx->filename    ,"%s/waysx.parsed.mem",option_tmpdirname);
+ sprintf(waysx->filename_tmp,"%s/waysx.%p.tmp"    ,option_tmpdirname,(void*)waysx);
+
+ if(append || readonly)
+    if(ExistsFile(waysx->filename))
+      {
+       FILESORT_VARINT waysize;
+       int fd;
+
+       fd=ReOpenFileBuffered(waysx->filename);
+
+       while(!ReadFileBuffered(fd,&waysize,FILESORT_VARSIZE))
+         {
+          SkipFileBuffered(fd,waysize);
+
+          waysx->number++;
+         }
+
+       CloseFileBuffered(fd);
+
+       RenameFile(waysx->filename,waysx->filename_tmp);
+      }
+
+ if(append)
+    waysx->fd=OpenFileBufferedAppend(waysx->filename_tmp);
+ else if(!readonly)
+    waysx->fd=OpenFileBufferedNew(waysx->filename_tmp);
+ else
+    waysx->fd=-1;
+
+#if SLIM
+ waysx->cache=NewWayXCache();
+ log_malloc(waysx->cache,sizeof(*waysx->cache));
+#endif
+
+
+ waysx->nfilename_tmp=(char*)malloc(strlen(option_tmpdirname)+40); /* allow %p to be up to 20 bytes */
+
+ sprintf(waysx->nfilename_tmp,"%s/waynames.%p.tmp",option_tmpdirname,(void*)waysx);
+
+ return(waysx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Free a way list.
+
+  WaysX *waysx The set of ways to be freed.
+
+  int keep If set then the results file is to be kept.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FreeWayList(WaysX *waysx,int keep)
+{
+ if(keep)
+    RenameFile(waysx->filename_tmp,waysx->filename);
+ else
+    DeleteFile(waysx->filename_tmp);
+
+ free(waysx->filename);
+ free(waysx->filename_tmp);
+
+ if(waysx->idata)
+   {
+    log_free(waysx->idata);
+    free(waysx->idata);
+   }
+
+ if(waysx->odata)
+   {
+    log_free(waysx->odata);
+    free(waysx->odata);
+   }
+
+ if(waysx->cdata)
+   {
+    log_free(waysx->cdata);
+    free(waysx->cdata);
+   }
+
+ DeleteFile(waysx->nfilename_tmp);
+
+ free(waysx->nfilename_tmp);
+
+#if SLIM
+ log_free(waysx->cache);
+ DeleteWayXCache(waysx->cache);
+#endif
+
+ free(waysx);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Append a single way to an unsorted way list.
+
+  WaysX *waysx The set of ways to process.
+
+  way_t id The ID of the way.
+
+  Way *way The way data itself.
+
+  node_t *nodes The list of nodes for this way.
+
+  int nnodes The number of nodes for this way.
+
+  const char *name The name or reference of the way.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void AppendWayList(WaysX *waysx,way_t id,Way *way,node_t *nodes,int nnodes,const char *name)
+{
+ WayX wayx;
+ FILESORT_VARINT size;
+ node_t nonode=NO_NODE_ID;
+
+ wayx.id=id;
+ wayx.way=*way;
+
+ size=sizeof(WayX)+(nnodes+1)*sizeof(node_t)+strlen(name)+1;
+
+ WriteFileBuffered(waysx->fd,&size,FILESORT_VARSIZE);
+ WriteFileBuffered(waysx->fd,&wayx,sizeof(WayX));
+
+ WriteFileBuffered(waysx->fd,nodes  ,nnodes*sizeof(node_t));
+ WriteFileBuffered(waysx->fd,&nonode,       sizeof(node_t));
+
+ WriteFileBuffered(waysx->fd,name,strlen(name)+1);
+
+ waysx->number++;
+
+ logassert(waysx->number!=0,"Too many ways (change index_t to 64-bits?)"); /* Zero marks the high-water mark for ways. */
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Finish appending ways and change the filename over.
+
+  WaysX *waysx The ways that have been appended.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void FinishWayList(WaysX *waysx)
+{
+ if(waysx->fd!=-1)
+    waysx->fd=CloseFileBuffered(waysx->fd);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Find a particular way index.
+
+  index_t IndexWayX Returns the index of the extended way with the specified id.
+
+  WaysX *waysx The set of ways to process.
+
+  way_t id The way id to look for.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+index_t IndexWayX(WaysX *waysx,way_t id)
+{
+ index_t start=0;
+ index_t end=waysx->number-1;
+ index_t mid;
+
+ if(waysx->number==0)           /* There are no ways */
+    return(NO_WAY);
+
+ if(id<waysx->idata[start])     /* Key is before start */
+    return(NO_WAY);
+
+ if(id>waysx->idata[end])       /* Key is after end */
+    return(NO_WAY);
+
+ /* Binary search - search key exact match only is required.
+  *
+  *  # <- start  |  Check mid and move start or end if it doesn't match
+  *  #           |
+  *  #           |  Since an exact match is wanted we can set end=mid-1
+  *  # <- mid    |  or start=mid+1 because we know that mid doesn't match.
+  *  #           |
+  *  #           |  Eventually either end=start or end=start+1 and one of
+  *  # <- end    |  start or end is the wanted one.
+  */
+
+ do
+   {
+    mid=(start+end)/2;            /* Choose mid point */
+
+    if(waysx->idata[mid]<id)      /* Mid point is too low */
+       start=mid+1;
+    else if(waysx->idata[mid]>id) /* Mid point is too high */
+       end=mid?(mid-1):mid;
+    else                          /* Mid point is correct */
+       return(mid);
+   }
+ while((end-start)>1);
+
+ if(waysx->idata[start]==id)      /* Start is correct */
+    return(start);
+
+ if(waysx->idata[end]==id)        /* End is correct */
+    return(end);
+
+ return(NO_WAY);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the list of ways.
+
+  WaysX *waysx The set of ways to process.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SortWayList(WaysX *waysx)
+{
+ index_t xnumber;
+ int fd;
+
+ /* Print the start message */
+
+ printf_first("Sorting Ways");
+
+ /* Re-open the file read-only and a new file writeable */
+
+ fd=ReplaceFileBuffered(waysx->filename_tmp,&waysx->fd);
+
+ /* Allocate the array of indexes */
+
+ waysx->idata=(way_t*)malloc(waysx->number*sizeof(way_t));
+ log_malloc(waysx->idata,waysx->number*sizeof(way_t));
+
+ logassert(waysx->idata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
+
+ /* Sort the ways by ID and index them */
+
+ sortwaysx=waysx;
+
+ xnumber=waysx->number;
+
+ waysx->number=filesort_vary(waysx->fd,fd,NULL,
+                                          (int (*)(const void*,const void*))sort_by_id,
+                                          (int (*)(void*,index_t))deduplicate_and_index_by_id);
+
+ waysx->knumber=waysx->number;
+
+ /* Close the files */
+
+ waysx->fd=CloseFileBuffered(waysx->fd);
+ CloseFileBuffered(fd);
+
+ /* Print the final message */
+
+ printf_last("Sorted Ways: Ways=%"Pindex_t" Duplicates=%"Pindex_t,xnumber,xnumber-waysx->number);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the ways into id order.
+
+  int sort_by_id Returns the comparison of the id fields.
+
+  WayX *a The first extended way.
+
+  WayX *b The second extended way.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int sort_by_id(WayX *a,WayX *b)
+{
+ way_t a_id=a->id;
+ way_t b_id=b->id;
+
+ if(a_id<b_id)
+    return(-1);
+ else if(a_id>b_id)
+    return(1);
+ else
+    return(-FILESORT_PRESERVE_ORDER(a,b)); /* latest version first */
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Discard duplicate ways and create and index of ids.
+
+  int deduplicate_and_index_by_id Return 1 if the value is to be kept, otherwise 0.
+
+  WayX *wayx The extended way.
+
+  index_t index The number of sorted ways that have already been written to the output file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int deduplicate_and_index_by_id(WayX *wayx,index_t index)
+{
+ static way_t previd; /* internal variable (reset by first call in each sort; index==0) */
+
+ if(index==0 || wayx->id!=previd)
+   {
+    previd=wayx->id;
+
+    if(wayx->way.type==WAY_DELETED)
+       return(0);
+    else
+      {
+       sortwaysx->idata[index]=wayx->id;
+
+       return(1);
+      }
+   }
+ else
+    return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Split the ways into segments and way names.
+
+  SegmentsX *SplitWays Returns the set of segments that have been created.
+
+  WaysX *waysx The set of ways to process.
+
+  NodesX *nodesx The set of nodes to use.
+
+  int keep If set to 1 then keep the old data file otherwise delete it.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+SegmentsX *SplitWays(WaysX *waysx,NodesX *nodesx,int keep)
+{
+ SegmentsX *segmentsx;
+ index_t i;
+ int fd,nfd;
+ char *name=NULL;
+ int namelen=0;
+
+ /* Print the start message */
+
+ printf_first("Splitting Ways: Ways=0 Segments=0");
+
+ segmentsx=NewSegmentList();
+
+ /* Re-open the file read-only and a new file writeable */
+
+ if(keep)
+   {
+    RenameFile(waysx->filename_tmp,waysx->filename);
+
+    waysx->fd=ReOpenFileBuffered(waysx->filename);
+
+    fd=OpenFileBufferedNew(waysx->filename_tmp);
+   }
+ else
+    fd=ReplaceFileBuffered(waysx->filename_tmp,&waysx->fd);
+
+ nfd=OpenFileBufferedNew(waysx->nfilename_tmp);
+
+ /* Loop through the ways and create the segments and way names */
+
+ for(i=0;i<waysx->number;i++)
+   {
+    WayX wayx;
+    FILESORT_VARINT size;
+    node_t node,prevnode=NO_NODE_ID;
+    index_t index,previndex=NO_NODE;
+
+    ReadFileBuffered(waysx->fd,&size,FILESORT_VARSIZE);
+
+    ReadFileBuffered(waysx->fd,&wayx,sizeof(WayX));
+
+    waysx->allow|=wayx.way.allow;
+
+    while(!ReadFileBuffered(waysx->fd,&node,sizeof(node_t)) && node!=NO_NODE_ID)
+      {
+       index=IndexNodeX(nodesx,node);
+
+       if(prevnode==node)
+         {
+          logerror("Way %"Pway_t" contains node %"Pnode_t" that is connected to itself.\n",logerror_way(waysx->idata[i]),logerror_node(node));
+         }
+       else if(index==NO_NODE)
+         {
+          logerror("Way %"Pway_t" contains node %"Pnode_t" that does not exist in the Routino database.\n",logerror_way(waysx->idata[i]),logerror_node(node));
+         }
+       else if(previndex==NO_NODE)
+          ;
+       else
+         {
+          distance_t segment_flags=0;
+
+          if(wayx.way.type&Highway_OneWay)
+             segment_flags|=ONEWAY_1TO2;
+
+          if(wayx.way.type&Highway_Area)
+             segment_flags|=SEGMENT_AREA;
+
+          AppendSegmentList(segmentsx,i,previndex,index,segment_flags);
+         }
+
+       prevnode=node;
+       previndex=index;
+
+       size-=sizeof(node_t);
+      }
+
+    size-=sizeof(node_t)+sizeof(WayX);
+
+    if(namelen<size)
+       name=(char*)realloc((void*)name,namelen=size);
+
+    ReadFileBuffered(waysx->fd,name,size);
+
+    WriteFileBuffered(fd,&wayx,sizeof(WayX));
+
+    size+=sizeof(index_t);
+
+    WriteFileBuffered(nfd,&size,FILESORT_VARSIZE);
+    WriteFileBuffered(nfd,&i,sizeof(index_t));
+    WriteFileBuffered(nfd,name,size-sizeof(index_t));
+
+    if(!((i+1)%1000))
+       printf_middle("Splitting Ways: Ways=%"Pindex_t" Segments=%"Pindex_t,i+1,segmentsx->number);
+   }
+
+ FinishSegmentList(segmentsx);
+
+ if(name) free(name);
+
+ /* Close the files */
+
+ waysx->fd=CloseFileBuffered(waysx->fd);
+ CloseFileBuffered(fd);
+
+ CloseFileBuffered(nfd);
+
+ /* Print the final message */
+
+ printf_last("Split Ways: Ways=%"Pindex_t" Segments=%"Pindex_t,waysx->number,segmentsx->number);
+
+ return(segmentsx);
+}
+
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the way names and assign the offsets to the ways.
+
+  WaysX *waysx The set of ways to process.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SortWayNames(WaysX *waysx)
+{
+ index_t i;
+ int nfd;
+ char *names[2]={NULL,NULL};
+ int namelen[2]={0,0};
+ int nnames=0;
+ uint32_t lastlength=0;
+
+ /* Print the start message */
+
+ printf_first("Sorting Way Names");
+
+ /* Re-open the file read-only and new file writeable */
+
+ nfd=ReplaceFileBuffered(waysx->nfilename_tmp,&waysx->nfd);
+
+ /* Sort the way names */
+
+ waysx->nlength=0;
+
+ filesort_vary(waysx->nfd,nfd,NULL,
+                              (int (*)(const void*,const void*))sort_by_name,
+                              NULL);
+
+ /* Close the files */
+
+ waysx->nfd=CloseFileBuffered(waysx->nfd);
+ CloseFileBuffered(nfd);
+
+ /* Print the final message */
+
+ printf_last("Sorted Way Names: Ways=%"Pindex_t,waysx->number);
+
+
+ /* Print the start message */
+
+ printf_first("Updating Ways with Names: Ways=0 Names=0");
+
+ /* Map into memory /  open the file */
+
+#if !SLIM
+ waysx->data=MapFileWriteable(waysx->filename_tmp);
+#else
+ waysx->fd=SlimMapFileWriteable(waysx->filename_tmp);
+#endif
+
+ /* Re-open the file read-only and new file writeable */
+
+ nfd=ReplaceFileBuffered(waysx->nfilename_tmp,&waysx->nfd);
+
+ /* Update the ways and de-duplicate the names */
+
+ for(i=0;i<waysx->number;i++)
+   {
+    WayX *wayx;
+    index_t index;
+    FILESORT_VARINT size;
+
+    ReadFileBuffered(waysx->nfd,&size,FILESORT_VARSIZE);
+
+    if(namelen[nnames%2]<size)
+       names[nnames%2]=(char*)realloc((void*)names[nnames%2],namelen[nnames%2]=size);
+
+    ReadFileBuffered(waysx->nfd,&index,sizeof(index_t));
+    ReadFileBuffered(waysx->nfd,names[nnames%2],size-sizeof(index_t));
+
+    if(nnames==0 || strcmp(names[0],names[1]))
+      {
+       WriteFileBuffered(nfd,names[nnames%2],size-sizeof(index_t));
+
+       lastlength=waysx->nlength;
+       waysx->nlength+=size-sizeof(index_t);
+
+       nnames++;
+      }
+
+    wayx=LookupWayX(waysx,index,1);
+
+    wayx->way.name=lastlength;
+
+    PutBackWayX(waysx,wayx);
+
+    if(!((i+1)%1000))
+       printf_middle("Updating Ways with Names: Ways=%"Pindex_t" Names=%"Pindex_t,i+1,nnames);
+   }
+
+ if(names[0]) free(names[0]);
+ if(names[1]) free(names[1]);
+
+ /* Close the files */
+
+ waysx->nfd=CloseFileBuffered(waysx->nfd);
+ CloseFileBuffered(nfd);
+
+ /* Unmap from memory / close the files */
+
+#if !SLIM
+ waysx->data=UnmapFile(waysx->data);
+#else
+ waysx->fd=SlimUnmapFile(waysx->fd);
+#endif
+
+ /* Print the final message */
+
+ printf_last("Updated Ways with Names: Ways=%"Pindex_t" Names=%"Pindex_t,waysx->number,nnames);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the ways into name order.
+
+  int sort_by_name Returns the comparison of the name fields.
+
+  char *a The first way name.
+
+  char *b The second way name.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int sort_by_name(char *a,char *b)
+{
+ int compare;
+ char *a_name=a+sizeof(index_t);
+ char *b_name=b+sizeof(index_t);
+
+ compare=strcmp(a_name,b_name);
+
+ if(compare)
+    return(compare);
+ else
+    return(FILESORT_PRESERVE_ORDER(a,b));
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Compact the way list, removing duplicated ways and unused ways.
+
+  WaysX *waysx The set of ways to process.
+
+  SegmentsX *segmentsx The set of segments to check.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void CompactWayList(WaysX *waysx,SegmentsX *segmentsx)
+{
+ int fd;
+ index_t cnumber;
+
+ if(waysx->number==0)
+    return;
+
+ /* Print the start message */
+
+ printf_first("Sorting Ways and Compacting");
+
+ /* Allocate the array of indexes */
+
+ waysx->cdata=(index_t*)malloc(waysx->number*sizeof(index_t));
+ log_malloc(waysx->cdata,waysx->number*sizeof(index_t));
+
+ logassert(waysx->cdata,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
+
+ /* Re-open the file read-only and a new file writeable */
+
+ fd=ReplaceFileBuffered(waysx->filename_tmp,&waysx->fd);
+
+ /* Sort the ways to allow compacting according to the properties */
+
+ sortwaysx=waysx;
+ sortsegmentsx=segmentsx;
+
+ cnumber=filesort_fixed(waysx->fd,fd,sizeof(WayX),(int (*)(void*,index_t))delete_unused,
+                                                  (int (*)(const void*,const void*))sort_by_name_and_prop_and_id,
+                                                  (int (*)(void*,index_t))deduplicate_and_index_by_compact_id);
+
+ /* Close the files */
+
+ waysx->fd=CloseFileBuffered(waysx->fd);
+ CloseFileBuffered(fd);
+
+ /* Free the data */
+
+ log_free(segmentsx->usedway);
+ free(segmentsx->usedway);
+ segmentsx->usedway=NULL;
+
+ /* Print the final message */
+
+ printf_last("Sorted and Compacted Ways: Ways=%"Pindex_t" Unique=%"Pindex_t,waysx->number,cnumber);
+ waysx->number=cnumber;
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Delete the ways that are no longer being used.
+
+  int delete_unused Return 1 if the value is to be kept, otherwise 0.
+
+  WayX *wayx The extended way.
+
+  index_t index The number of unsorted ways that have been read from the input file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int delete_unused(WayX *wayx,index_t index)
+{
+ if(sortsegmentsx && !IsBitSet(sortsegmentsx->usedway,index))
+   {
+    sortwaysx->cdata[index]=NO_WAY;
+
+    return(0);
+   }
+ else
+   {
+    wayx->id=index;
+
+    return(1);
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Sort the ways into name, properties and id order.
+
+  int sort_by_name_and_prop_and_id Returns the comparison of the name, properties and id fields.
+
+  WayX *a The first extended Way.
+
+  WayX *b The second extended Way.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int sort_by_name_and_prop_and_id(WayX *a,WayX *b)
+{
+ int compare;
+ index_t a_name=a->way.name;
+ index_t b_name=b->way.name;
+
+ if(a_name<b_name)
+    return(-1);
+ else if(a_name>b_name)
+    return(1);
+
+ compare=WaysCompare(&a->way,&b->way);
+
+ if(compare)
+    return(compare);
+
+ return(sort_by_id(a,b));
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Create the index of compacted Way identifiers and ignore Ways with duplicated properties.
+
+  int deduplicate_and_index_by_compact_id Return 1 if the value is to be kept, otherwise 0.
+
+  WayX *wayx The extended way.
+
+  index_t index The number of sorted ways that have already been written to the output file.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int deduplicate_and_index_by_compact_id(WayX *wayx,index_t index)
+{
+ static Way lastway; /* internal variable (reset by first call in each sort; index==0) */
+
+ if(index==0 || wayx->way.name!=lastway.name || WaysCompare(&lastway,&wayx->way))
+   {
+    lastway=wayx->way;
+
+    sortwaysx->cdata[wayx->id]=index;
+
+    wayx->id=index;
+
+    return(1);
+   }
+ else
+   {
+    sortwaysx->cdata[wayx->id]=index-1;
+
+    return(0);
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Save the way list to a file.
+
+  WaysX *waysx The set of ways to save.
+
+  const char *filename The name of the file to save.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void SaveWayList(WaysX *waysx,const char *filename)
+{
+ index_t i;
+ int fd;
+ index_t position=0;
+ WayX wayx;
+ WaysFile waysfile={0};
+ highways_t   highways=0;
+ transports_t allow=0;
+ properties_t props=0;
+
+ /* Print the start message */
+
+ printf_first("Writing Ways: Ways=0");
+
+ /* Re-open the files */
+
+ waysx->fd=ReOpenFileBuffered(waysx->filename_tmp);
+ waysx->nfd=ReOpenFileBuffered(waysx->nfilename_tmp);
+
+ /* Write out the ways data */
+
+ fd=OpenFileBufferedNew(filename);
+
+ SeekFileBuffered(fd,sizeof(WaysFile));
+
+ for(i=0;i<waysx->number;i++)
+   {
+    ReadFileBuffered(waysx->fd,&wayx,sizeof(WayX));
+
+    highways|=HIGHWAYS(wayx.way.type);
+    allow   |=wayx.way.allow;
+    props   |=wayx.way.props;
+
+    WriteFileBuffered(fd,&wayx.way,sizeof(Way));
+
+    if(!((i+1)%1000))
+       printf_middle("Writing Ways: Ways=%"Pindex_t,i+1);
+   }
+
+ /* Write out the ways names */
+
+ SeekFileBuffered(fd,sizeof(WaysFile)+(off_t)waysx->number*sizeof(Way));
+
+ while(position<waysx->nlength)
+   {
+    size_t len=1024;
+    char temp[1024];
+
+    if((waysx->nlength-position)<1024)
+       len=waysx->nlength-position;
+
+    ReadFileBuffered(waysx->nfd,temp,len);
+
+    WriteFileBuffered(fd,temp,len);
+
+    position+=len;
+   }
+
+ /* Close the files */
+
+ waysx->fd=CloseFileBuffered(waysx->fd);
+ waysx->nfd=CloseFileBuffered(waysx->nfd);
+
+ /* Write out the header structure */
+
+ waysfile.number =waysx->number;
+
+ waysfile.highways=highways;
+ waysfile.allow   =allow;
+ waysfile.props   =props;
+
+ SeekFileBuffered(fd,0);
+ WriteFileBuffered(fd,&waysfile,sizeof(WaysFile));
+
+ CloseFileBuffered(fd);
+
+ /* Print the final message */
+
+ printf_last("Wrote Ways: Ways=%"Pindex_t,waysx->number);
+}
diff --git a/3rdparty/Routino/src/waysx.h b/3rdparty/Routino/src/waysx.h
new file mode 100644
index 0000000..24cab2a
--- /dev/null
+++ b/3rdparty/Routino/src/waysx.h
@@ -0,0 +1,183 @@
+/***************************************
+ A header file for the extended Ways structure.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2008-2014 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef WAYSX_H
+#define WAYSX_H    /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+
+#include "types.h"
+#include "ways.h"
+
+#include "typesx.h"
+
+#include "cache.h"
+#include "files.h"
+
+
+/* Data structures */
+
+
+/*+ An extended structure containing a single way. +*/
+struct _WayX
+{
+ way_t    id;                   /*+ The way identifier; initially the OSM value, later the Way index. +*/
+
+ Way      way;                  /*+ The real way data. +*/
+};
+
+
+/*+ A structure containing a set of ways (memory format). +*/
+struct _WaysX
+{
+ char    *filename;             /*+ The name of the intermediate file (for the WaysX). +*/
+ char    *filename_tmp;         /*+ The name of the temporary file (for the WaysX). +*/
+
+ int      fd;                   /*+ The file descriptor of the open file (for the WaysX). +*/
+
+ index_t  number;               /*+ The number of extended ways still being considered. +*/
+ index_t  knumber;              /*+ The number of extended ways kept for next time. +*/
+
+ transports_t allow;            /*+ The types of traffic that were seen when parsing. +*/
+
+#if !SLIM
+
+ WayX    *data;                 /*+ The extended ways data (when mapped into memory). +*/
+
+#else
+
+ WayX     cached[3];            /*+ Three cached extended ways read from the file in slim mode. +*/
+ index_t  incache[3];           /*+ The indexes of the cached extended ways. +*/
+
+ WayXCache *cache;              /*+ A RAM cache of extended ways read from the file. +*/
+
+#endif
+
+ way_t   *idata;                /*+ The extended way IDs (sorted by ID). +*/
+ off_t   *odata;                /*+ The offset of the way in the file (used for error log). +*/
+
+ index_t *cdata;                /*+ The compacted way IDs (same order as sorted ways). +*/
+
+ char    *nfilename_tmp;        /*+ The name of the temporary file (for the WaysX names). +*/
+
+ int      nfd;                  /*+ The file descriptor of the temporary file (for the WaysX names). +*/
+
+ uint32_t nlength;              /*+ The length of the string of name entries. +*/
+};
+
+
+/* Functions in waysx.c */
+
+
+WaysX *NewWayList(int append,int readonly);
+void FreeWayList(WaysX *waysx,int keep);
+
+void AppendWayList(WaysX *waysx,way_t id,Way *way,node_t *nodes,int nnodes,const char *name);
+void FinishWayList(WaysX *waysx);
+
+index_t IndexWayX(WaysX *waysx,way_t id);
+
+void SortWayList(WaysX *waysx);
+
+SegmentsX *SplitWays(WaysX *waysx,NodesX *nodesx,int keep);
+
+void SortWayNames(WaysX *waysx);
+
+void CompactWayList(WaysX *waysx,SegmentsX *segmentsx);
+
+void SaveWayList(WaysX *waysx,const char *filename);
+
+
+/* Macros / inline functions */
+
+#if !SLIM
+
+#define LookupWayX(waysx,index,position)  &(waysx)->data[index]
+  
+#define PutBackWayX(waysx,wayx)           while(0) { /* nop */ }
+
+#else
+
+/* Prototypes */
+
+static inline WayX *LookupWayX(WaysX *waysx,index_t index,int position);
+
+static inline void PutBackWayX(WaysX *waysx,WayX *wayx);
+
+CACHE_NEWCACHE_PROTO(WayX)
+CACHE_DELETECACHE_PROTO(WayX)
+CACHE_FETCHCACHE_PROTO(WayX)
+CACHE_REPLACECACHE_PROTO(WayX)
+CACHE_INVALIDATECACHE_PROTO(WayX)
+
+
+/* Inline functions */
+
+CACHE_STRUCTURE(WayX)
+CACHE_NEWCACHE(WayX)
+CACHE_DELETECACHE(WayX)
+CACHE_FETCHCACHE(WayX)
+CACHE_REPLACECACHE(WayX)
+CACHE_INVALIDATECACHE(WayX)
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Lookup a particular extended way with the specified id from the file on disk.
+
+  WayX *LookupWayX Returns a pointer to a cached copy of the extended way.
+
+  WaysX *waysx The set of ways to use.
+
+  index_t index The way index to look for.
+
+  int position The position in the cache to use.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline WayX *LookupWayX(WaysX *waysx,index_t index,int position)
+{
+ waysx->cached[position-1]=*FetchCachedWayX(waysx->cache,index,waysx->fd,0);
+
+ waysx->incache[position-1]=index;
+
+ return(&waysx->cached[position-1]);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Put back an extended way's data into the file on disk.
+
+  WaysX *waysx The set of ways to use.
+
+  WayX *wayx The extended way to be put back.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline void PutBackWayX(WaysX *waysx,WayX *wayx)
+{
+ int position1=wayx-&waysx->cached[0];
+
+ ReplaceCachedWayX(waysx->cache,wayx,waysx->incache[position1],waysx->fd,0);
+}
+
+#endif /* SLIM */
+
+
+#endif /* WAYSX_H */
diff --git a/3rdparty/Routino/src/xml/Makefile b/3rdparty/Routino/src/xml/Makefile
new file mode 100644
index 0000000..60b9dc2
--- /dev/null
+++ b/3rdparty/Routino/src/xml/Makefile
@@ -0,0 +1,119 @@
+# XML test programs Makefile
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2010-2015 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# All configuration is in the top-level Makefile.conf
+
+include ../../Makefile.conf
+
+# Compilation targets
+
+XMLDIR=../../xml
+
+X=$(notdir $(wildcard $(XMLDIR)/*.xsd))
+C=$(foreach f,$(X),$(addsuffix -skeleton.c,$(basename $f)))
+D=$(wildcard .deps/*.d)
+O=$(foreach f,$(C),$(addsuffix .o,$(basename $f)))
+E=$(foreach f,$(C),$(basename $f))
+
+EXE=xsd-to-xmlparser
+
+########
+
+all: $(EXE) $(C) $(E)
+
+########
+
+xsd-to-xmlparser : xsd-to-xmlparser.o ../xmlparse.o
+	$(LD) xsd-to-xmlparser.o ../xmlparse.o -o $@ $(LDFLAGS)
+
+########
+
+%-skeleton.c : $(XMLDIR)/%.xsd xsd-to-xmlparser
+	-./xsd-to-xmlparser < $< > $@
+	@test -s $@ || rm $@
+
+%-skeleton : %-skeleton.o ../xmlparse.o
+	$(LD) $< ../xmlparse.o -o $@ $(LDFLAGS)
+
+.SECONDARY : $(O)
+
+########
+
+../xmlparse.o : ../xmlparse.c ../xmlparse.h
+	cd .. && $(MAKE) xmlparse.o
+
+########
+
+%.o : %.c
+	@[ -d .deps ] || mkdir .deps
+	$(CC) -c $(CFLAGS) -I.. $< -o $@ -MMD -MP -MF $(addprefix .deps/,$(addsuffix .d,$(basename $@)))
+
+########
+
+test: test-skeleton
+	@status=true ;\
+	echo "" ;\
+	for good in test/good*.xml; do \
+	   echo "Testing: $$good ... " ;\
+	   if ./test-skeleton < $$good > /dev/null; then echo "... passed"; else echo "... FAILED"; status=false; fi ;\
+	   echo "" ;\
+	done ;\
+	for bad in test/bad*.xml; do \
+	   echo "Testing: $$bad ... " ;\
+	   if ./test-skeleton < $$bad > /dev/null; then echo "... FAILED"; status=false; else echo "... passed"; fi ;\
+	   echo "" ;\
+	done ;\
+	if $$status; then echo "Success: all tests passed"; else echo "Warning: Some tests FAILED"; fi ;\
+	$$status
+
+test-skeleton : test-skeleton.o
+	$(LD) $< ../xmlparse.o -o $@ $(LDFLAGS)
+
+test-skeleton.c : test/test.xsd xsd-to-xmlparser
+	./xsd-to-xmlparser < $< | sed -e 's/XMLPARSE_UNKNOWN_ATTR_WARN/XMLPARSE_UNKNOWN_ATTR_ERROR/' > $@
+
+########
+
+install:
+
+########
+
+clean:
+	rm -f *~
+	rm -f *.o
+	rm -f $(EXE) *.exe
+	rm -f $(E) test-skeleton
+	rm -f $(D) .deps/test-skeleton.d
+	rm -f $(C) test-skeleton.c
+	rm -fr .deps
+	rm -f core
+	rm -f *.gcda *.gcno *.gcov gmon.out
+
+########
+
+distclean: clean
+
+########
+
+include $(D)
+
+########
+
+.PHONY:: all test install clean distclean
diff --git a/3rdparty/Routino/src/xml/test/bad-attr-entity-ref.xml b/3rdparty/Routino/src/xml/test/bad-attr-entity-ref.xml
new file mode 100644
index 0000000..7a3a5ba
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-attr-entity-ref.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1="value1 & value2 &tl;  ">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-comment-ends-triple-dash.xml b/3rdparty/Routino/src/xml/test/bad-comment-ends-triple-dash.xml
new file mode 100644
index 0000000..17a105a
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-comment-ends-triple-dash.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- bad comment --->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-comment-extra-double-dash.xml b/3rdparty/Routino/src/xml/test/bad-comment-extra-double-dash.xml
new file mode 100644
index 0000000..36a9959
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-comment-extra-double-dash.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- bad -- comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-double-quote-attr-amp.xml b/3rdparty/Routino/src/xml/test/bad-double-quote-attr-amp.xml
new file mode 100644
index 0000000..fd58f46
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-double-quote-attr-amp.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1="value1 & value2">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-double-quote-attr-invalid-ascii.xml b/3rdparty/Routino/src/xml/test/bad-double-quote-attr-invalid-ascii.xml
new file mode 100644
index 0000000..ead749e
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-double-quote-attr-invalid-ascii.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1="value1  value2">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-double-quote-attr-invalid-utf8.xml b/3rdparty/Routino/src/xml/test/bad-double-quote-attr-invalid-utf8.xml
new file mode 100644
index 0000000..b93b398
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-double-quote-attr-invalid-utf8.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1="value1 � value2">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-double-quote-attr-left-angle.xml b/3rdparty/Routino/src/xml/test/bad-double-quote-attr-left-angle.xml
new file mode 100644
index 0000000..c6dc80b
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-double-quote-attr-left-angle.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1="value1 < value2">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-double-quote-attr-right-angle.xml b/3rdparty/Routino/src/xml/test/bad-double-quote-attr-right-angle.xml
new file mode 100644
index 0000000..f4c0428
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-double-quote-attr-right-angle.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1="value1 > value2">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-early-end-of-file.xml b/3rdparty/Routino/src/xml/test/bad-early-end-of-file.xml
new file mode 100644
index 0000000..7990b44
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-early-end-of-file.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level1>
+
diff --git a/3rdparty/Routino/src/xml/test/bad-end-tag-space-at-begin1.xml b/3rdparty/Routino/src/xml/test/bad-end-tag-space-at-begin1.xml
new file mode 100644
index 0000000..ca9f42a
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-end-tag-space-at-begin1.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </ level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-end-tag-space-at-begin2.xml b/3rdparty/Routino/src/xml/test/bad-end-tag-space-at-begin2.xml
new file mode 100644
index 0000000..aeae822
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-end-tag-space-at-begin2.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  < /level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-end-tag-space-at-end.xml b/3rdparty/Routino/src/xml/test/bad-end-tag-space-at-end.xml
new file mode 100644
index 0000000..b060674
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-end-tag-space-at-end.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level1 >
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-end-tag-with-attr.xml b/3rdparty/Routino/src/xml/test/bad-end-tag-with-attr.xml
new file mode 100644
index 0000000..dab05b1
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-end-tag-with-attr.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level1 attr1="value">
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-single-quote-attr-amp.xml b/3rdparty/Routino/src/xml/test/bad-single-quote-attr-amp.xml
new file mode 100644
index 0000000..30200c5
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-single-quote-attr-amp.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1='value1 & value2'>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-single-quote-attr-invalid-ascii.xml b/3rdparty/Routino/src/xml/test/bad-single-quote-attr-invalid-ascii.xml
new file mode 100644
index 0000000..5855b65
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-single-quote-attr-invalid-ascii.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1='value1  value2'>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-single-quote-attr-invalid-utf8.xml b/3rdparty/Routino/src/xml/test/bad-single-quote-attr-invalid-utf8.xml
new file mode 100644
index 0000000..33f967b
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-single-quote-attr-invalid-utf8.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1='value1 � value2'>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-single-quote-attr-left-angle.xml b/3rdparty/Routino/src/xml/test/bad-single-quote-attr-left-angle.xml
new file mode 100644
index 0000000..10c8ba0
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-single-quote-attr-left-angle.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1='value1 < value2'>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-single-quote-attr-right-angle.xml b/3rdparty/Routino/src/xml/test/bad-single-quote-attr-right-angle.xml
new file mode 100644
index 0000000..d043b8a
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-single-quote-attr-right-angle.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1='value1 > value2'>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-start-tag-space-at-begin.xml b/3rdparty/Routino/src/xml/test/bad-start-tag-space-at-begin.xml
new file mode 100644
index 0000000..02e81bb
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-start-tag-space-at-begin.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  < level1>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-tag-attr-no-quotes.xml b/3rdparty/Routino/src/xml/test/bad-tag-attr-no-quotes.xml
new file mode 100644
index 0000000..bdc476e
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-tag-attr-no-quotes.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1=value>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-tag-attr-space-after-equal.xml b/3rdparty/Routino/src/xml/test/bad-tag-attr-space-after-equal.xml
new file mode 100644
index 0000000..1ba6847
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-tag-attr-space-after-equal.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1= "value">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-tag-attr-space-before-equal.xml b/3rdparty/Routino/src/xml/test/bad-tag-attr-space-before-equal.xml
new file mode 100644
index 0000000..06236c6
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-tag-attr-space-before-equal.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1 ="value">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-tag-level-nesting.xml b/3rdparty/Routino/src/xml/test/bad-tag-level-nesting.xml
new file mode 100644
index 0000000..dba5592
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-tag-level-nesting.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level2>
+    <level1>
+    </level1>
+  </level2>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-text-outside.xml b/3rdparty/Routino/src/xml/test/bad-text-outside.xml
new file mode 100644
index 0000000..8af1f35
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-text-outside.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1="value1">
+    <level2>
+      text
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-unbalanced-tag-start-end.xml b/3rdparty/Routino/src/xml/test/bad-unbalanced-tag-start-end.xml
new file mode 100644
index 0000000..e375475
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-unbalanced-tag-start-end.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level2>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-unexpected-attribute-name.xml b/3rdparty/Routino/src/xml/test/bad-unexpected-attribute-name.xml
new file mode 100644
index 0000000..9b17fdd
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-unexpected-attribute-name.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attribute="value">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-unexpected-end-tag.xml b/3rdparty/Routino/src/xml/test/bad-unexpected-end-tag.xml
new file mode 100644
index 0000000..219d79b
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-unexpected-end-tag.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  </level1>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-unexpected-left-angle.xml b/3rdparty/Routino/src/xml/test/bad-unexpected-left-angle.xml
new file mode 100644
index 0000000..d8ecbea
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-unexpected-left-angle.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+      <
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-unexpected-right-angle.xml b/3rdparty/Routino/src/xml/test/bad-unexpected-right-angle.xml
new file mode 100644
index 0000000..358524e
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-unexpected-right-angle.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+      >
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-xml-header-at-begin.xml b/3rdparty/Routino/src/xml/test/bad-xml-header-at-begin.xml
new file mode 100644
index 0000000..e19fc5f
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-xml-header-at-begin.xml
@@ -0,0 +1,12 @@
+<? xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-xml-header-at-end.xml b/3rdparty/Routino/src/xml/test/bad-xml-header-at-end.xml
new file mode 100644
index 0000000..2a3857d
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-xml-header-at-end.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" >
+
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/bad-xml-header-not-first.xml b/3rdparty/Routino/src/xml/test/bad-xml-header-not-first.xml
new file mode 100644
index 0000000..cdabc6b
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/bad-xml-header-not-first.xml
@@ -0,0 +1,12 @@
+<!-- good comment -->
+
+<test>
+
+  <level1>
+    <level2>
+    </level2>
+  </level1>
+
+</test>
+
+<?xml version="1.0" encoding="utf-8" ?>
diff --git a/3rdparty/Routino/src/xml/test/good.xml b/3rdparty/Routino/src/xml/test/good.xml
new file mode 100644
index 0000000..8c5bb2d
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/good.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- good comment -->
+
+<test>
+
+  <level1 attr1="value1 & value2 <  ">
+    <level2>
+    </level2>
+  </level1>
+
+</test>
diff --git a/3rdparty/Routino/src/xml/test/test.xsd b/3rdparty/Routino/src/xml/test/test.xsd
new file mode 100644
index 0000000..fce04ee
--- /dev/null
+++ b/3rdparty/Routino/src/xml/test/test.xsd
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- ============================================================
+     An XML Schema Definition for a test XML file
+     ============================================================
+     This file Copyright 2010 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+  <!-- The top level -->
+
+  <xsd:element name="test" type="schemaType"/>
+
+  <!-- The first level element -->
+
+  <xsd:complexType name="schemaType">
+    <xsd:sequence>
+      <xsd:element name="level1"    type="level1Type"/>
+    </xsd:sequence>
+    <xsd:attribute name="attr1"     type="xsd:string"/>
+    <xsd:attribute name="attr2"     type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The second level element -->
+
+  <xsd:complexType name="level1Type">
+    <xsd:sequence>
+      <xsd:element name="level2"    type="level2Type"   minOccurs="0"/>
+    </xsd:sequence>
+    <xsd:attribute name="attr1"     type="xsd:string"/>
+  </xsd:complexType>
+
+</xsd:schema>
diff --git a/3rdparty/Routino/src/xml/xsd-to-xmlparser.c b/3rdparty/Routino/src/xml/xsd-to-xmlparser.c
new file mode 100644
index 0000000..18a38e1
--- /dev/null
+++ b/3rdparty/Routino/src/xml/xsd-to-xmlparser.c
@@ -0,0 +1,515 @@
+/***************************************
+ $Header: /home/amb/CVS/routino/src/xml/xsd-to-xmlparser.c,v 1.10 2010-04-23 18:41:20 amb Exp $
+
+ An XML parser for simplified XML Schema Definitions to create XML parser skeletons.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+#if !defined(_MSC_VER)
+#include <unistd.h>
+#endif
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xmlparse.h"
+
+
+/*+ A forward definition of the xmltagx +*/
+typedef struct _xmltagx xmltagx;
+
+
+/*+ A structure to hold the extended definition of a tag. +*/
+struct _xmltagx
+{
+ char *name;                              /*+ The name of the tag. +*/
+ char *type;                              /*+ The type of the tag. +*/
+
+ int  nattributes;                        /*+ The number of valid attributes for the tag. +*/
+ char *attributes[XMLPARSE_MAX_ATTRS];    /*+ The valid attributes for the tag. +*/
+
+ int nsubtagsx;                           /*+ The number of valid attributes for the tag. +*/
+ xmltagx *subtagsx[XMLPARSE_MAX_SUBTAGS]; /*+ The list of types for the subtags contained within this one. +*/
+};
+
+
+/* The local variables and functions */
+
+int ntagsx=0;
+xmltagx **tagsx=NULL;
+char *currenttype=NULL;
+
+static char *safe(const char *name);
+
+
+/* The XML tag processing function prototypes */
+
+static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding);
+static int schemaType_function(const char *_tag_,int _type_,const char *elementFormDefault,const char *xmlns_xsd);
+static int elementType_function(const char *_tag_,int _type_,const char *name,const char *type,const char *minOccurs,const char *maxOccurs);
+static int complexType_function(const char *_tag_,int _type_,const char *name);
+static int sequenceType_function(const char *_tag_,int _type_);
+static int attributeType_function(const char *_tag_,int _type_,const char *name,const char *type);
+
+
+/* The XML tag definitions (forward declarations) */
+
+static const xmltag xmlDeclaration_tag;
+static const xmltag schemaType_tag;
+static const xmltag elementType_tag;
+static const xmltag complexType_tag;
+static const xmltag sequenceType_tag;
+static const xmltag attributeType_tag;
+
+
+/* The XML tag definition values */
+
+/*+ The complete set of tags at the top level. +*/
+static const xmltag * const xml_toplevel_tags[]={&xmlDeclaration_tag,&schemaType_tag,NULL};
+
+/*+ The xmlDeclaration type tag. +*/
+static const xmltag xmlDeclaration_tag=
+              {"xml",
+               2, {"version","encoding"},
+               xmlDeclaration_function,
+               {NULL}};
+
+/*+ The schemaType type tag. +*/
+static const xmltag schemaType_tag=
+              {"xsd:schema",
+               2, {"elementFormDefault","xmlns:xsd"},
+               schemaType_function,
+               {&elementType_tag,&complexType_tag,NULL}};
+
+/*+ The elementType type tag. +*/
+static const xmltag elementType_tag=
+              {"xsd:element",
+               4, {"name","type","minOccurs","maxOccurs"},
+               elementType_function,
+               {NULL}};
+
+/*+ The complexType type tag. +*/
+static const xmltag complexType_tag=
+              {"xsd:complexType",
+               1, {"name"},
+               complexType_function,
+               {&sequenceType_tag,&attributeType_tag,NULL}};
+
+/*+ The sequenceType type tag. +*/
+static const xmltag sequenceType_tag=
+              {"xsd:sequence",
+               0, {NULL},
+               sequenceType_function,
+               {&elementType_tag,NULL}};
+
+/*+ The attributeType type tag. +*/
+static const xmltag attributeType_tag=
+              {"xsd:attribute",
+               2, {"name","type"},
+               attributeType_function,
+               {NULL}};
+
+
+/* The XML tag processing functions */
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the XML declaration is seen
+
+  int xmlDeclaration_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *version The contents of the 'version' attribute (or NULL if not defined).
+
+  const char *encoding The contents of the 'encoding' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding)
+{
+ /* Add the XML declaration as a tag. */
+
+ currenttype=NULL;
+ elementType_function("xsd:element",XMLPARSE_TAG_START|XMLPARSE_TAG_END,"xml","xmlDeclaration",NULL,NULL);
+ complexType_function("xsd:complexType",XMLPARSE_TAG_START,"xmlDeclaration");
+ attributeType_function("xsd:attribute",XMLPARSE_TAG_START|XMLPARSE_TAG_END,"version",NULL);
+ attributeType_function("xsd:attribute",XMLPARSE_TAG_START|XMLPARSE_TAG_END,"encoding",NULL);
+ complexType_function("xsd:complexType",XMLPARSE_TAG_END,NULL);
+ currenttype=NULL;
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the schemaType XSD type is seen
+
+  int schemaType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *elementFormDefault The contents of the 'elementFormDefault' attribute (or NULL if not defined).
+
+  const char *xmlns_xsd The contents of the 'xmlns:xsd' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int schemaType_function(const char *_tag_,int _type_,const char *elementFormDefault,const char *xmlns_xsd)
+{
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the elementType XSD type is seen
+
+  int elementType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *name The contents of the 'name' attribute (or NULL if not defined).
+
+  const char *type The contents of the 'type' attribute (or NULL if not defined).
+
+  const char *minOccurs The contents of the 'minOccurs' attribute (or NULL if not defined).
+
+  const char *maxOccurs The contents of the 'maxOccurs' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int elementType_function(const char *_tag_,int _type_,const char *name,const char *type,const char *minOccurs,const char *maxOccurs)
+{
+ xmltagx *tagx=NULL;
+ int i;
+
+ if(_type_==XMLPARSE_TAG_END)
+    return(0);
+
+ for(i=0;i<ntagsx;i++)
+    if(!strcmp(type,tagsx[i]->type) && !strcmp(name,tagsx[i]->name))
+       tagx=tagsx[i];
+
+ if(!tagx)
+   {
+    ntagsx++;
+    tagsx=(xmltagx**)realloc((void*)tagsx,ntagsx*sizeof(xmltagx*));
+
+    tagsx[ntagsx-1]=(xmltagx*)calloc(1,sizeof(xmltagx));
+    tagsx[ntagsx-1]->name=strcpy(malloc(strlen(name)+1),name);
+    tagsx[ntagsx-1]->type=strcpy(malloc(strlen(type)+1),type);
+
+    tagx=tagsx[ntagsx-1];
+   }
+
+ if(!currenttype)
+    return(0);
+
+ for(i=0;i<ntagsx;i++)
+    if(!strcmp(tagsx[i]->type,currenttype))
+      {
+       tagsx[i]->subtagsx[tagsx[i]->nsubtagsx]=tagx;
+       tagsx[i]->nsubtagsx++;
+
+       if(tagsx[i]->nsubtagsx==XMLPARSE_MAX_SUBTAGS)
+         {fprintf(stderr,"Too many subtags seen for type '%s'.\n",currenttype); exit(1);}
+      }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the complexType XSD type is seen
+
+  int complexType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *name The contents of the 'name' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int complexType_function(const char *_tag_,int _type_,const char *name)
+{
+ if(_type_==XMLPARSE_TAG_END)
+    return(0);
+
+ currenttype=strcpy(realloc(currenttype,strlen(name)+1),name);
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the sequenceType XSD type is seen
+
+  int sequenceType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int sequenceType_function(const char *_tag_,int _type_)
+{
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The function that is called when the attributeType XSD type is seen
+
+  int attributeType_function Returns 0 if no error occured or something else otherwise.
+
+  const char *_tag_ Set to the name of the element tag that triggered this function call.
+
+  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
+
+  const char *name The contents of the 'name' attribute (or NULL if not defined).
+
+  const char *type The contents of the 'type' attribute (or NULL if not defined).
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static int attributeType_function(const char *_tag_,int _type_,const char *name,const char *type)
+{
+ int i;
+
+ if(_type_==XMLPARSE_TAG_END)
+    return(0);
+
+ for(i=0;i<ntagsx;i++)
+    if(!strcmp(tagsx[i]->type,currenttype))
+      {
+       tagsx[i]->attributes[tagsx[i]->nattributes]=strcpy(malloc(strlen(name)+1),name);
+       tagsx[i]->nattributes++;
+
+       if(tagsx[i]->nattributes==XMLPARSE_MAX_ATTRS)
+         {fprintf(stderr,"Too many attributes seen for type '%s'.\n",currenttype); exit(1);}
+      }
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  The XML Schema Definition XML parser and C program generator.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int main(int argc,char **argv)
+{
+ int i,j;
+
+ /* Parse the XSD file */
+
+ if(ParseXML(STDIN_FILENO,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_IGNORE))
+   {
+    fprintf(stderr,"Cannot parse XML file - exiting.\n");
+    exit(1);
+   }
+
+ /* Print the header */
+
+ printf("/***************************************\n");
+ printf(" An automatically generated skeleton XML parser.\n");
+ printf("\n");
+ printf(" Automatically generated by xsd-to-xmlparser.\n");
+ printf(" ***************************************/\n");
+ printf("\n");
+ printf("\n");
+ printf("#include <stdio.h>\n");
+ printf("#if !defined(_MSC_VER)\n");
+ printf("#include <unistd.h>\n");
+ printf("#endif\n");
+ printf("\n");
+ printf("#include \"xmlparse.h\"\n");
+
+ /* Print the function prototypes */
+
+ printf("\n");
+ printf("\n");
+ printf("/* The XML tag processing function prototypes */\n");
+ printf("\n");
+
+ for(i=0;i<ntagsx;i++)
+   {
+    printf("static int %s_function(const char *_tag_,int _type_",safe(tagsx[i]->type));
+
+    for(j=0;j<tagsx[i]->nattributes;j++)
+       printf(",const char *%s",safe(tagsx[i]->attributes[j]));
+
+    printf(");\n");
+   }
+
+ /* Print the xmltag variables */
+
+ printf("\n");
+ printf("\n");
+ printf("/* The XML tag definitions (forward declarations) */\n");
+
+ printf("\n");
+
+ for(i=0;i<ntagsx;i++)
+    printf("static const xmltag %s_tag;\n",safe(tagsx[i]->type));
+
+ printf("\n");
+ printf("\n");
+ printf("/* The XML tag definition values */\n");
+
+ printf("\n");
+ printf("/*+ The complete set of tags at the top level. +*/\n");
+ printf("static const xmltag * const xml_toplevel_tags[]={");
+ printf("&%s_tag,",safe(tagsx[0]->type));
+ printf("&%s_tag,",safe(tagsx[1]->type));
+ printf("NULL};\n");
+
+ for(i=0;i<ntagsx;i++)
+   {
+    printf("\n");
+    printf("/*+ The %s type tag. +*/\n",tagsx[i]->type);
+    printf("static const xmltag %s_tag=\n",safe(tagsx[i]->type));
+    printf("              {\"%s\",\n",tagsx[i]->name);
+
+    printf("               %d, {",tagsx[i]->nattributes);
+    for(j=0;j<tagsx[i]->nattributes;j++)
+       printf("%s\"%s\"",(j?",":""),tagsx[i]->attributes[j]);
+    printf("%s},\n",(tagsx[i]->nattributes?"":"NULL"));
+
+    printf("               %s_function,\n",safe(tagsx[i]->type));
+
+    printf("               {");
+    for(j=0;j<tagsx[i]->nsubtagsx;j++)
+       printf("&%s_tag,",safe(tagsx[i]->subtagsx[j]->type));
+    printf("NULL}};\n");
+   }
+
+ /* Print the functions */
+
+ printf("\n");
+ printf("\n");
+ printf("/* The XML tag processing functions */\n");
+
+ for(i=0;i<ntagsx;i++)
+   {
+    printf("\n");
+    printf("\n");
+    printf("/*++++++++++++++++++++++++++++++++++++++\n");
+    if(i==0) /* XML tag */
+       printf("  The function that is called when the XML declaration is seen\n");
+    else
+       printf("  The function that is called when the %s XSD type is seen\n",tagsx[i]->type);
+    printf("\n");
+    printf("  int %s_function Returns 0 if no error occured or something else otherwise.\n",safe(tagsx[i]->type));
+    printf("\n");
+    printf("  const char *_tag_ Set to the name of the element tag that triggered this function call.\n");
+    printf("\n");
+    printf("  int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.\n");
+    for(j=0;j<tagsx[i]->nattributes;j++)
+      {
+       printf("\n");
+       printf("  const char *%s The contents of the '%s' attribute (or NULL if not defined).\n",safe(tagsx[i]->attributes[j]),tagsx[i]->attributes[j]);
+      }
+    printf("  ++++++++++++++++++++++++++++++++++++++*/\n");
+    printf("\n");
+
+    printf("static int %s_function(const char *_tag_,int _type_",safe(tagsx[i]->type));
+
+    for(j=0;j<tagsx[i]->nattributes;j++)
+       printf(",const char *%s",safe(tagsx[i]->attributes[j]));
+
+    printf(")\n");
+
+    printf("{\n");
+
+    if(i==(ntagsx-1))            /* XML tag */
+      {
+       printf(" printf(\"<?%%s\",_tag_);\n");
+       for(j=0;j<tagsx[i]->nattributes;j++)
+         {
+          char *safename=safe(tagsx[i]->attributes[j]);
+          printf(" if(%s) printf(\" %s=\\\"%%s\\\"\",ParseXML_Encode_Safe_XML(%s));\n",safename,tagsx[i]->attributes[j],safename);
+         }
+       printf(" printf(\" ?>\\n\");\n");
+      }
+    else
+      {
+       printf(" printf(\"<%%s%%s\",(_type_==XMLPARSE_TAG_END)?\"/\":\"\",_tag_);\n");
+       for(j=0;j<tagsx[i]->nattributes;j++)
+         {
+          char *safename=safe(tagsx[i]->attributes[j]);
+          printf(" if(%s) printf(\" %s=\\\"%%s\\\"\",ParseXML_Encode_Safe_XML(%s));\n",safename,tagsx[i]->attributes[j],safename);
+         }
+       printf(" printf(\"%%s>\\n\",(_type_==(XMLPARSE_TAG_START|XMLPARSE_TAG_END))?\" /\":\"\");\n");
+      }
+
+    printf(" return(0);\n");
+    printf("}\n");
+   }
+
+ /* Print the main function */
+
+ printf("\n");
+ printf("\n");
+ printf("/*++++++++++++++++++++++++++++++++++++++\n");
+ printf("  A skeleton XML parser.\n");
+ printf("  ++++++++++++++++++++++++++++++++++++++*/\n");
+ printf("\n");
+ printf("int main(int argc,char **argv)\n");
+ printf("{\n");
+ printf(" if(ParseXML(STDIN_FILENO,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_WARN))\n");
+ printf("    return(1);\n");
+ printf(" else\n");
+ printf("    return(0);\n");
+ printf("}\n");
+
+ return(0);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  A function to return a safe C identifier from an XML tag or attribute name.
+
+  char *safe Returns the safe name in a private string (only use once).
+
+  const char *name The name to convert.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static char *safe(const char *name)
+{
+ static char *safe=NULL; /* static allocation of return value */
+ int i;
+
+ safe=realloc(safe,strlen(name)+1);
+
+ for(i=0;name[i];i++)
+    if(isalnum(name[i]))
+       safe[i]=name[i];
+    else
+       safe[i]='_';
+
+ safe[i]=0;
+
+ return(safe);
+}
diff --git a/3rdparty/Routino/src/xmlparse.c b/3rdparty/Routino/src/xmlparse.c
new file mode 100644
index 0000000..23cc3df
--- /dev/null
+++ b/3rdparty/Routino/src/xmlparse.c
@@ -0,0 +1,1788 @@
+/***************************************
+ A simple generic XML parser where the structure comes from the function parameters.
+ Not intended to be fully conforming to XML standard or a validating parser but
+ sufficient to parse OSM XML and simple program configuration files.
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#include <stdio.h>
+
+#if defined(_MSC_VER)
+#include <io.h>
+#include <stdint.h>
+#define read(fd,address,length)  _read(fd,address,(unsigned int)(length))
+typedef uint64_t ssize_t;
+#else
+#include <unistd.h>
+#endif
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <string.h>
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define strcasecmp _stricmp
+#else
+#include <strings.h>
+#endif
+
+#include <ctype.h>
+
+#include "xmlparse.h"
+
+
+/* Parser states */
+
+#define LEX_EOF                    0
+
+#define LEX_FUNC_TAG_BEGIN         1
+#define LEX_FUNC_XML_DECL_BEGIN    2
+#define LEX_FUNC_TAG_POP           3
+#define LEX_FUNC_TAG_PUSH          4
+#define LEX_FUNC_XML_DECL_FINISH   5
+#define LEX_FUNC_TAG_FINISH        6
+#define LEX_FUNC_ATTR_KEY          7
+#define LEX_FUNC_ATTR_VAL          8
+
+#define LEX_STATE_INITIAL         10
+#define LEX_STATE_BANGTAG         11
+#define LEX_STATE_COMMENT         12
+#define LEX_STATE_XML_DECL_START  13
+#define LEX_STATE_XML_DECL        14
+#define LEX_STATE_TAG_START       15
+#define LEX_STATE_TAG             16
+#define LEX_STATE_ATTR_KEY        17
+#define LEX_STATE_ATTR_VAL        18
+#define LEX_STATE_END_TAG1        19
+#define LEX_STATE_END_TAG2        20
+#define LEX_STATE_DQUOTED         21
+#define LEX_STATE_SQUOTED         22
+
+#define LEX_ERROR_TAG_START      101
+#define LEX_ERROR_XML_DECL_START 102
+#define LEX_ERROR_TAG            103
+#define LEX_ERROR_XML_DECL       104
+#define LEX_ERROR_ATTR           105
+#define LEX_ERROR_END_TAG        106
+#define LEX_ERROR_COMMENT        107
+#define LEX_ERROR_CLOSE          108
+#define LEX_ERROR_ATTR_VAL       109
+#define LEX_ERROR_ENTITY_REF     110
+#define LEX_ERROR_CHAR_REF       111
+#define LEX_ERROR_TEXT_OUTSIDE   112
+
+#define LEX_ERROR_UNEXP_TAG      201
+#define LEX_ERROR_UNBALANCED     202
+#define LEX_ERROR_NO_START       203
+#define LEX_ERROR_UNEXP_ATT      204
+#define LEX_ERROR_UNEXP_EOF      205
+#define LEX_ERROR_XML_NOT_FIRST  206
+
+#define LEX_ERROR_CALLBACK       255
+
+
+/* Parsing variables and functions (re-initialised for each file) */
+
+static uint64_t lineno;
+
+static unsigned char buffer[2][16384];
+static unsigned char *buffer_token,*buffer_end,*buffer_ptr;
+static int buffer_active=0;
+
+static char *stored_message=NULL;
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Refill the data buffer making sure that the string starting at buffer_token is contiguous.
+
+  int buffer_refill Return 0 if everything is OK or 1 for EOF.
+
+  int fd The file descriptor to read from.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline int buffer_refill(int fd)
+{
+ ssize_t n;
+ size_t m=0;
+
+ m=(buffer_end-buffer[buffer_active])+1;
+
+ if(m>(sizeof(buffer[0])/2))    /* more than half full */
+   {
+    m=0;
+
+    buffer_active=!buffer_active;
+
+    if(buffer_token)
+      {
+       m=(buffer_end-buffer_token)+1;
+
+       memcpy(buffer[buffer_active],buffer_token,m);
+
+       buffer_token=buffer[buffer_active];
+      }
+   }
+
+ n=read(fd,buffer[buffer_active]+m,sizeof(buffer[0])-m);
+
+ buffer_ptr=buffer[buffer_active]+m;
+ buffer_end=buffer[buffer_active]+m+n-1;
+
+ if(n<=0)
+    return(1);
+ else
+    return(0);
+}
+
+
+/* Macros to simplify the parser (and make it look more like lex) */
+
+#define BEGIN(xx) do{ state=(xx); goto new_state; } while(0)
+#define NEXT(xx)  next_state=(xx)
+
+#define START_TOKEN buffer_token=buffer_ptr
+#define END_TOKEN   buffer_token=NULL
+
+#define NEXT_CHAR                                                       \
+ do{                                                                    \
+  if(buffer_ptr==buffer_end)                                            \
+    { if(buffer_refill(fd)) BEGIN(LEX_EOF); }                           \
+    else                                                                \
+       buffer_ptr++;                                                    \
+   } while(0)
+
+
+ /* -------- equivalent flex definition --------
+
+    S               [ \t\r]
+    N               (\n)
+
+    U1              [\x09\x0A\x0D\x20-\x7F]
+    U2              [\xC2-\xDF][\x80-\xBF]
+    U3a             \xE0[\xA0-\xBF][\x80-\xBF]
+    U3b             [\xE1-\xEC][\x80-\xBF][\x80-\xBF]
+    U3c             \xED[\x80-\x9F][\x80-\xBF]
+    U3d             [\xEE-\xEF][\x80-\xBF][\x80-\xBF]
+    U3              {U3a}|{U3b}|{U3c}|{U3d}
+    U4a             \xF0[\x90-\xBF][\x80-\xBF][\x80-\xBF]
+    U4b             [\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]
+    U4c             \xF4[\x80-\x8F][\x80-\xBF][\x80-\xBF]
+    U4              {U4a}|{U4b}|{U4c}
+
+    U               ({U1}|{U2}|{U3}|{U4})
+
+    U1_xml          ([\x09\x0A\x0D\x20-\x25\x27-\x3B\x3D\x3F-\x7F])
+
+    U1quotedS_xml   ([\x09\x0A\x0D\x20-\x25\x28-\x3B\x3D\x3F-\x7F])
+    U1quotedD_xml   ([\x09\x0A\x0D\x20-\x21\x23-\x25\x27-\x3B\x3D\x3F-\x7F])
+
+    UquotedS        ({U1quotedS_xml}|{U2}|{U3}|{U4})
+    UquotedD        ({U1quotedD_xml}|{U2}|{U3}|{U4})
+
+    letter          [a-zA-Z]
+    digit           [0-9]
+    xdigit          [a-fA-F0-9]
+
+    namechar        ({letter}|{digit}|[-._:])
+    namestart       ({letter}|[_:])
+    name            ({namestart}{namechar}*)
+
+    entityref       (&{name};)
+    charref         (&#({digit}+|x{xdigit}+);)
+
+    -------- equivalent flex definition -------- */
+
+/* Tables containing character class defintions (advance declaration for data at end of file). */
+static const unsigned char quotedD[256],quotedS[256];
+static const unsigned char *U2[1],*U3a[2],*U3b[2],*U3c[2],*U3d[2],*U4a[3],*U4b[3],*U4c[3];
+static const unsigned char namestart[256],namechar[256],whitespace[256],digit[256],xdigit[256];
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  A function to call the callback function with the parameters needed.
+
+  int call_callback Returns 1 if the callback returned with an error.
+
+  const char *name The name of the tag.
+
+  int (*callback)() The callback function.
+
+  int type The type of tag (start and/or end).
+
+  int nattributes The number of attributes collected.
+
+  unsigned char *attributes[XMLPARSE_MAX_ATTRS] The list of attributes.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+static inline int call_callback(const char *name,int (*callback)(),int type,int nattributes,unsigned char *attributes[XMLPARSE_MAX_ATTRS])
+{
+ switch(nattributes)
+   {
+   case  0: return (*callback)(name,type);
+   case  1: return (*callback)(name,type,attributes[0]);
+   case  2: return (*callback)(name,type,attributes[0],attributes[1]);
+   case  3: return (*callback)(name,type,attributes[0],attributes[1],attributes[2]);
+   case  4: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3]);
+   case  5: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4]);
+   case  6: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5]);
+   case  7: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6]);
+   case  8: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7]);
+   case  9: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8]);
+   case 10: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9]);
+   case 11: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10]);
+   case 12: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11]);
+   case 13: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11],attributes[12]);
+   case 14: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11],attributes[12],attributes[13]);
+   case 15: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11],attributes[12],attributes[13],attributes[14]);
+   case 16: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11],attributes[12],attributes[13],attributes[14],attributes[15]);
+
+   default:
+    ParseXML_SetError("Too many attributes for tag '%s' source code needs changing.",name);
+    return(1);
+   }
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Parse the XML and call the functions for each tag as seen.
+
+  int ParseXML Returns 0 if OK or something else in case of an error.
+
+  int fd The file descriptor of the file to parse.
+
+  const xmltag *const *tags The array of pointers to tags for the top level.
+
+  int options A list of XML Parser options OR-ed together.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int ParseXML(int fd,const xmltag *const *tags,int options)
+{
+ int i;
+ int state,next_state,after_attr;
+ unsigned char saved_buffer_ptr=0;
+ const unsigned char *quoted;
+
+ unsigned char *attributes[XMLPARSE_MAX_ATTRS]={NULL};
+ int attribute=0;
+
+ int stackdepth=0,stackused=0;
+ const xmltag * const **tags_stack=NULL;
+ const xmltag **tag_stack=NULL;
+ const xmltag *tag=NULL;
+// const xmltag * const *tags=alltags;
+
+ /* The actual parser. */
+
+ lineno=1;
+
+ if(stored_message)
+    free(stored_message);
+ stored_message=NULL;
+
+ buffer_end=buffer[buffer_active]+sizeof(buffer[0])-1;
+ buffer_token=NULL;
+
+ buffer_refill(fd);
+
+ BEGIN(LEX_STATE_INITIAL);
+
+ new_state:
+
+ switch(state)
+   {
+    /* ================ Parsing states ================ */
+
+
+    /* -------- equivalent flex definition --------
+
+       <INITIAL>"<!"                        { BEGIN(BANGTAG); }
+       <INITIAL>"</"                        { BEGIN(END_TAG1); }
+       <INITIAL>"<?"                        { BEGIN(XML_DECL_START); }
+       <INITIAL>"<"                         { BEGIN(TAG_START); }
+
+       <INITIAL>">"                         { return(LEX_ERROR_CLOSE); }
+
+       <INITIAL>{N}                         { lineno++; }
+       <INITIAL>{S}+                        { }
+       <INITIAL>.                           { return(LEX_ERROR_TEXT_OUTSIDE); }
+
+       -------- equivalent flex definition -------- */
+
+   case LEX_STATE_INITIAL:
+
+    while(1)
+      {
+       while(whitespace[(int)*buffer_ptr])
+          NEXT_CHAR;
+
+       if(*buffer_ptr=='\n')
+         {
+          NEXT_CHAR;
+
+          lineno++;
+         }
+       else if(*buffer_ptr=='<')
+         {
+          NEXT_CHAR;
+
+          if(*buffer_ptr=='/')
+            {
+             NEXT_CHAR;
+             BEGIN(LEX_STATE_END_TAG1);
+            }
+          else if(*buffer_ptr=='!')
+            {
+             NEXT_CHAR;
+             BEGIN(LEX_STATE_BANGTAG);
+            }
+          else if(*buffer_ptr=='?')
+            {
+             NEXT_CHAR;
+             BEGIN(LEX_STATE_XML_DECL_START);
+            }
+          else
+             BEGIN(LEX_STATE_TAG_START);
+         }
+       else if(*buffer_ptr=='>')
+          BEGIN(LEX_ERROR_CLOSE);
+       else
+          BEGIN(LEX_ERROR_TEXT_OUTSIDE);
+      }
+
+    break;
+
+    /* -------- equivalent flex definition --------
+
+       <BANGTAG>"--"               { BEGIN(COMMENT); }
+       <BANGTAG>{N}                { return(LEX_ERROR_TAG_START); }
+       <BANGTAG>.                  { return(LEX_ERROR_TAG_START); }
+
+       -------- equivalent flex definition -------- */
+
+   case LEX_STATE_BANGTAG:
+
+    if(*buffer_ptr!='-')
+       BEGIN(LEX_ERROR_TAG_START);
+
+    NEXT_CHAR;
+
+    if(*buffer_ptr!='-')
+       BEGIN(LEX_ERROR_TAG_START);
+
+    NEXT_CHAR;
+    BEGIN(LEX_STATE_COMMENT);
+
+    break;
+
+    /* -------- equivalent flex definition --------
+
+       <COMMENT>"-->"              { BEGIN(INITIAL); }
+       <COMMENT>"--"[^>]           { return(LEX_ERROR_COMMENT); }
+       <COMMENT>"-"                { }
+       <COMMENT>{N}                { lineno++; }
+       <COMMENT>[^-\n]+            { }
+
+       -------- equivalent flex definition -------- */
+
+   case LEX_STATE_COMMENT:
+
+    while(1)
+      {
+       while(*buffer_ptr!='-' && *buffer_ptr!='\n')
+          NEXT_CHAR;
+
+       if(*buffer_ptr=='-')
+         {
+          NEXT_CHAR;
+
+          if(*buffer_ptr!='-')
+             continue;
+
+          NEXT_CHAR;
+          if(*buffer_ptr=='>')
+            {
+             NEXT_CHAR;
+             BEGIN(LEX_STATE_INITIAL);
+            }
+
+          BEGIN(LEX_ERROR_COMMENT);
+         }
+       else /* if(*buffer_ptr=='\n') */
+         {
+          NEXT_CHAR;
+
+          lineno++;
+         }
+      }
+
+    break;
+
+    /* -------- equivalent flex definition --------
+
+       <XML_DECL_START>xml         { BEGIN(XML_DECL); return(LEX_XML_DECL_BEGIN); }
+       <XML_DECL_START>{N}         { return(LEX_ERROR_XML_DECL_START); }
+       <XML_DECL_START>.           { return(LEX_ERROR_XML_DECL_START); }
+
+       -------- equivalent flex definition -------- */
+
+   case LEX_STATE_XML_DECL_START:
+
+    START_TOKEN;
+
+    if(*buffer_ptr=='x')
+      {
+       NEXT_CHAR;
+       if(*buffer_ptr=='m')
+         {
+          NEXT_CHAR;
+          if(*buffer_ptr=='l')
+            {
+             NEXT_CHAR;
+
+             saved_buffer_ptr=*buffer_ptr;
+             *buffer_ptr=0;
+
+             NEXT(LEX_STATE_XML_DECL);
+             BEGIN(LEX_FUNC_XML_DECL_BEGIN);
+            }
+         }
+      }
+
+    BEGIN(LEX_ERROR_XML_DECL_START);
+
+    /* -------- equivalent flex definition --------
+
+       <XML_DECL>"?>"              { BEGIN(INITIAL); return(LEX_XML_DECL_FINISH); }
+       <XML_DECL>{S}+              { }
+       <XML_DECL>{N}               { lineno++; }
+       <XML_DECL>{name}            { after_attr=XML_DECL; BEGIN(ATTR_KEY); return(LEX_ATTR_KEY); }
+       <XML_DECL>.                 { return(LEX_ERROR_XML_DECL); }
+
+       -------- equivalent flex definition -------- */
+
+   case LEX_STATE_XML_DECL:
+
+    while(1)
+      {
+       while(whitespace[(int)*buffer_ptr])
+          NEXT_CHAR;
+
+       if(namestart[(int)*buffer_ptr])
+         {
+          START_TOKEN;
+
+          NEXT_CHAR;
+          while(namechar[(int)*buffer_ptr])
+             NEXT_CHAR;
+
+          saved_buffer_ptr=*buffer_ptr;
+          *buffer_ptr=0;
+
+          after_attr=LEX_STATE_XML_DECL;
+          NEXT(LEX_STATE_ATTR_KEY);
+          BEGIN(LEX_FUNC_ATTR_KEY);
+         }
+       else if(*buffer_ptr=='?')
+         {
+          NEXT_CHAR;
+          if(*buffer_ptr=='>')
+            {
+             NEXT_CHAR;
+             NEXT(LEX_STATE_INITIAL);
+             BEGIN(LEX_FUNC_XML_DECL_FINISH);
+            }
+
+          BEGIN(LEX_ERROR_XML_DECL);
+         }
+       else if(*buffer_ptr=='\n')
+         {
+          NEXT_CHAR;
+          lineno++;
+         }
+       else
+          BEGIN(LEX_ERROR_XML_DECL);
+      }
+
+    break;
+
+    /* -------- equivalent flex definition --------
+
+       <TAG_START>{name}           { BEGIN(TAG); return(LEX_TAG_BEGIN); }
+       <TAG_START>{N}              { return(LEX_ERROR_TAG_START); }
+       <TAG_START>.                { return(LEX_ERROR_TAG_START); }
+
+       -------- equivalent flex definition -------- */
+
+   case LEX_STATE_TAG_START:
+
+    if(namestart[(int)*buffer_ptr])
+      {
+       START_TOKEN;
+
+       NEXT_CHAR;
+       while(namechar[(int)*buffer_ptr])
+          NEXT_CHAR;
+
+       saved_buffer_ptr=*buffer_ptr;
+       *buffer_ptr=0;
+
+       NEXT(LEX_STATE_TAG);
+       BEGIN(LEX_FUNC_TAG_BEGIN);
+      }
+
+    BEGIN(LEX_ERROR_TAG_START);
+
+    /* -------- equivalent flex definition --------
+
+       <END_TAG1>{name}            { BEGIN(END_TAG2); return(LEX_TAG_POP); }
+       <END_TAG1>{N}               { return(LEX_ERROR_END_TAG); }
+       <END_TAG1>.                 { return(LEX_ERROR_END_TAG); }
+
+       -------- equivalent flex definition -------- */
+
+   case LEX_STATE_END_TAG1:
+
+    if(namestart[(int)*buffer_ptr])
+      {
+       START_TOKEN;
+
+       NEXT_CHAR;
+       while(namechar[(int)*buffer_ptr])
+          NEXT_CHAR;
+
+       saved_buffer_ptr=*buffer_ptr;
+       *buffer_ptr=0;
+
+       NEXT(LEX_STATE_END_TAG2);
+       BEGIN(LEX_FUNC_TAG_POP);
+      }
+
+    BEGIN(LEX_ERROR_END_TAG);
+
+    /* -------- equivalent flex definition --------
+
+       <END_TAG2>">"               { BEGIN(INITIAL); }
+       <END_TAG2>{N}               { return(LEX_ERROR_END_TAG); }
+       <END_TAG2>.                 { return(LEX_ERROR_END_TAG); }
+
+       -------- equivalent flex definition -------- */
+
+   case LEX_STATE_END_TAG2:
+
+    if(*buffer_ptr=='>')
+      {
+       NEXT_CHAR;
+
+       BEGIN(LEX_STATE_INITIAL);
+      }
+
+    BEGIN(LEX_ERROR_END_TAG);
+
+    /* -------- equivalent flex definition --------
+
+       <TAG>"/>"                   { BEGIN(INITIAL); return(LEX_TAG_FINISH); }
+       <TAG>">"                    { BEGIN(INITIAL); return(LEX_TAG_PUSH); }
+       <TAG>{S}+                   { }
+       <TAG>{N}                    { lineno++; }
+       <TAG>{name}                 { after_attr=TAG; BEGIN(ATTR_KEY); return(LEX_ATTR_KEY); }
+       <TAG>.                      { return(LEX_ERROR_TAG); }
+
+       -------- equivalent flex definition -------- */
+
+   case LEX_STATE_TAG:
+
+    while(1)
+      {
+       while(whitespace[(int)*buffer_ptr])
+          NEXT_CHAR;
+
+       if(namestart[(int)*buffer_ptr])
+         {
+          START_TOKEN;
+
+          NEXT_CHAR;
+          while(namechar[(int)*buffer_ptr])
+             NEXT_CHAR;
+
+          saved_buffer_ptr=*buffer_ptr;
+          *buffer_ptr=0;
+
+          after_attr=LEX_STATE_TAG;
+          NEXT(LEX_STATE_ATTR_KEY);
+          BEGIN(LEX_FUNC_ATTR_KEY);
+         }
+       else if(*buffer_ptr=='/')
+         {
+          NEXT_CHAR;
+          if(*buffer_ptr=='>')
+            {
+             NEXT_CHAR;
+             NEXT(LEX_STATE_INITIAL);
+             BEGIN(LEX_FUNC_TAG_FINISH);
+            }
+
+          BEGIN(LEX_ERROR_TAG);
+         }
+       else if(*buffer_ptr=='>')
+         {
+          NEXT_CHAR;
+          NEXT(LEX_STATE_INITIAL);
+          BEGIN(LEX_FUNC_TAG_PUSH);
+         }
+       else if(*buffer_ptr=='\n')
+         {
+          NEXT_CHAR;
+          lineno++;
+         }
+       else
+          BEGIN(LEX_ERROR_TAG);
+      }
+
+    break;
+
+    /* -------- equivalent flex definition --------
+
+       <ATTR_KEY>=                 { BEGIN(ATTR_VAL); }
+       <ATTR_KEY>{N}               { return(LEX_ERROR_ATTR); }
+       <ATTR_KEY>.                 { return(LEX_ERROR_ATTR); }
+
+       -------- equivalent flex definition -------- */
+
+   case LEX_STATE_ATTR_KEY:
+
+    if(*buffer_ptr=='=')
+      {
+       NEXT_CHAR;
+       BEGIN(LEX_STATE_ATTR_VAL);
+      }
+
+    BEGIN(LEX_ERROR_ATTR);
+
+    /* -------- equivalent flex definition --------
+
+       <ATTR_VAL>\"                { BEGIN(DQUOTED); }
+       <ATTR_VAL>\'                { BEGIN(SQUOTED); }
+       <ATTR_VAL>{N}               { return(LEX_ERROR_ATTR); }
+       <ATTR_VAL>.                 { return(LEX_ERROR_ATTR); }
+
+       -------- equivalent flex definition -------- */
+
+   case LEX_STATE_ATTR_VAL:
+
+    if(*buffer_ptr=='"')
+      {
+       NEXT_CHAR;
+       BEGIN(LEX_STATE_DQUOTED);
+      }
+    else if(*buffer_ptr=='\'')
+      {
+       NEXT_CHAR;
+       BEGIN(LEX_STATE_SQUOTED);
+      }
+
+    BEGIN(LEX_ERROR_ATTR);
+
+    /* -------- equivalent flex definition --------
+
+       <DQUOTED>\"                 { BEGIN(after_attr); return(LEX_ATTR_VAL); }
+       <DQUOTED>{entityref}        { if(options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);}
+                                     else { const char *str=ParseXML_Decode_Entity_Ref(yytext); if(str) {append_string(str);} else {return(LEX_ERROR_ENTITY_REF);} } }
+       <DQUOTED>{charref}          { if(options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);}
+                                     else { const char *str=ParseXML_Decode_Char_Ref(yytext);   if(str) {append_string(str);} else {return(LEX_ERROR_CHAR_REF);} } }
+       <DQUOTED>{UquotedD}         { }
+       <DQUOTED>[<>&]              { return(LEX_ERROR_ATTR_VAL); }
+       <DQUOTED>.                  { return(LEX_ERROR_ATTR_VAL); }
+
+       <SQUOTED>\'                 { BEGIN(after_attr); return(LEX_ATTR_VAL); }
+       <SQUOTED>{entityref}        { if(options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);}
+                                     else { const char *str=ParseXML_Decode_Entity_Ref(yytext); if(str) {append_string(str);} else {return(LEX_ERROR_ENTITY_REF);} } }
+       <SQUOTED>{charref}          { if(options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);}
+                                     else { const char *str=ParseXML_Decode_Char_Ref(yytext);   if(str) {append_string(str);} else {return(LEX_ERROR_CHAR_REF);} } }
+       <SQUOTED>{UquotedS}         { append_string(yytext); }
+       <SQUOTED>[<>&]              { return(LEX_ERROR_ATTR_VAL); }
+       <SQUOTED>.                  { return(LEX_ERROR_ATTR_VAL); }
+
+       -------- equivalent flex definition -------- */
+
+   case LEX_STATE_DQUOTED:
+   case LEX_STATE_SQUOTED:
+
+    if(state==LEX_STATE_DQUOTED)
+       quoted=quotedD;
+    else
+       quoted=quotedS;
+
+    START_TOKEN;
+
+    while(1)
+      {
+       switch(quoted[(int)*buffer_ptr])
+         {
+         case 10:            /* U1 - used by all tag keys and many values */
+          do
+            {
+             NEXT_CHAR;
+            }
+          while(quoted[(int)*buffer_ptr]==10);
+          break;
+
+         case 20:            /* U2 */
+          NEXT_CHAR;
+          if(!U2[0][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          break;
+
+         case 31:            /* U3a */
+          NEXT_CHAR;
+          if(!U3a[0][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          if(!U3a[1][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          break;
+
+         case 32:            /* U3b */
+          NEXT_CHAR;
+          if(!U3b[0][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          if(!U3b[1][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          break;
+
+         case 33:            /* U3c */
+          NEXT_CHAR;
+          if(!U3c[0][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          if(!U3c[1][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          break;
+
+         case 34:            /* U3d */
+          NEXT_CHAR;
+          if(!U3d[0][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          if(!U3d[1][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          break;
+
+         case 41:            /* U4a */
+          NEXT_CHAR;
+          if(!U4a[0][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          if(!U4a[1][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          if(!U4a[2][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          break;
+
+         case 42:            /* U4b */
+          NEXT_CHAR;
+          if(!U4b[0][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          if(!U4b[1][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          if(!U4b[2][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          break;
+
+         case 43:            /* U4c */
+          NEXT_CHAR;
+          if(!U4c[0][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          if(!U4c[1][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          if(!U4c[2][(int)*buffer_ptr])
+             BEGIN(LEX_ERROR_ATTR_VAL);
+          NEXT_CHAR;
+          break;
+
+         case 50:            /* entityref or charref */
+          NEXT_CHAR;
+
+          if(*buffer_ptr=='#') /* charref */
+            {
+             int charref_len=3;
+
+             NEXT_CHAR;
+             if(digit[(int)*buffer_ptr]) /* decimal */
+               {
+                NEXT_CHAR;
+                charref_len++;
+
+                while(digit[(int)*buffer_ptr])
+                  {
+                   NEXT_CHAR;
+                   charref_len++;
+                  }
+
+                if(*buffer_ptr!=';')
+                   BEGIN(LEX_ERROR_ATTR_VAL);
+               }
+             else if(*buffer_ptr=='x') /* hex */
+               {
+                NEXT_CHAR;
+                charref_len++;
+
+                while(xdigit[(int)*buffer_ptr])
+                  {
+                   NEXT_CHAR;
+                   charref_len++;
+                  }
+
+                if(*buffer_ptr!=';')
+                   BEGIN(LEX_ERROR_ATTR_VAL);
+               }
+             else            /* other */
+                BEGIN(LEX_ERROR_ATTR_VAL);
+
+             NEXT_CHAR;
+
+             if(!(options&XMLPARSE_RETURN_ATTR_ENCODED))
+               {
+                const char *str;
+
+                saved_buffer_ptr=*buffer_ptr;
+                *buffer_ptr=0;
+
+                str=ParseXML_Decode_Char_Ref((char*)(buffer_ptr-charref_len));
+
+                if(!str)
+                  {
+                   buffer_ptr-=charref_len;
+                   BEGIN(LEX_ERROR_CHAR_REF);
+                  }
+
+                buffer_token=memmove(buffer_token+(charref_len-strlen(str)),buffer_token,buffer_ptr-buffer_token-charref_len);
+                memcpy(buffer_ptr-strlen(str),str,strlen(str));
+
+                *buffer_ptr=saved_buffer_ptr;
+               }
+            }
+          else if(namestart[(int)*buffer_ptr]) /* entityref */
+            {
+             int entityref_len=3;
+
+             NEXT_CHAR;
+             while(namechar[(int)*buffer_ptr])
+               {
+                NEXT_CHAR;
+                entityref_len++;
+               }
+
+             if(*buffer_ptr!=';')
+                BEGIN(LEX_ERROR_ATTR_VAL);
+
+             NEXT_CHAR;
+
+             if(!(options&XMLPARSE_RETURN_ATTR_ENCODED))
+               {
+                const char *str;
+
+                saved_buffer_ptr=*buffer_ptr;
+                *buffer_ptr=0;
+
+                str=ParseXML_Decode_Entity_Ref((char*)(buffer_ptr-entityref_len));
+
+                if(!str)
+                  {
+                   buffer_ptr-=entityref_len;
+                   BEGIN(LEX_ERROR_ENTITY_REF);
+                  }
+
+                buffer_token=memmove(buffer_token+(entityref_len-strlen(str)),buffer_token,buffer_ptr-buffer_token-entityref_len);
+                memcpy(buffer_ptr-strlen(str),str,strlen(str));
+
+                *buffer_ptr=saved_buffer_ptr;
+               }
+            }
+          else               /* other */
+             BEGIN(LEX_ERROR_ATTR_VAL);
+
+          break;
+
+         case 99:            /* quote */
+          *buffer_ptr=0;
+          NEXT_CHAR;
+
+          NEXT(after_attr);
+          BEGIN(LEX_FUNC_ATTR_VAL);
+
+         default:            /* other */
+          BEGIN(LEX_ERROR_ATTR_VAL);
+         }
+      }
+
+    break;
+
+
+    /* ================ Functional states ================ */
+
+
+    /* The start of a tag for an XML declaration */
+
+   case LEX_FUNC_XML_DECL_BEGIN:
+
+    if(tag_stack)
+       BEGIN(LEX_ERROR_XML_NOT_FIRST);
+
+    /* The start of a tag for an element */
+
+   case LEX_FUNC_TAG_BEGIN:
+
+    tag=NULL;
+
+    for(i=0;tags[i];i++)
+       if(buffer_token[0]==tags[i]->name[0] || tolower(buffer_token[0])==tags[i]->name[0])
+          if(!strcasecmp((char*)buffer_token+1,tags[i]->name+1))
+            {
+             tag=tags[i];
+
+             for(i=0;i<tag->nattributes;i++)
+                attributes[i]=NULL;
+
+             break;
+            }
+
+    if(tag==NULL)
+       BEGIN(LEX_ERROR_UNEXP_TAG);
+
+    END_TOKEN;
+
+    *buffer_ptr=saved_buffer_ptr;
+    BEGIN(next_state);
+
+    /* The end of the start-tag for an element */
+
+   case LEX_FUNC_TAG_PUSH:
+
+    if(stackused==stackdepth)
+      {
+       tag_stack =realloc(tag_stack ,(stackdepth+=8)*sizeof(xmltag*));
+       tags_stack=realloc(tags_stack,(stackdepth+=8)*sizeof(xmltag**));
+      }
+
+    tag_stack [stackused]=tag;
+    tags_stack[stackused]=tags;
+    stackused++;
+
+    if(tag->callback)
+       if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_START,tag->nattributes,attributes))
+          BEGIN(LEX_ERROR_CALLBACK);
+
+    tags=tag->subtags;
+
+    BEGIN(next_state);
+
+    /* The end of the empty-element-tag for an XML declaration */
+
+   case LEX_FUNC_XML_DECL_FINISH:
+
+    /* The end of the empty-element-tag for an element */
+
+   case LEX_FUNC_TAG_FINISH:
+
+    if(tag->callback)
+       if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_START|XMLPARSE_TAG_END,tag->nattributes,attributes))
+          BEGIN(LEX_ERROR_CALLBACK);
+
+    if(stackused>0)
+       tag=tag_stack[stackused-1];
+    else
+       tag=NULL;
+
+    BEGIN(next_state);
+
+    /* The end of the end-tag for an element */
+
+   case LEX_FUNC_TAG_POP:
+
+    stackused--;
+    tags=tags_stack[stackused];
+    tag =tag_stack [stackused];
+
+    if(strcmp((char*)buffer_token,tag->name))
+       BEGIN(LEX_ERROR_UNBALANCED);
+
+    if(stackused<0)
+       BEGIN(LEX_ERROR_NO_START);
+
+    for(i=0;i<tag->nattributes;i++)
+       attributes[i]=NULL;
+
+    if(tag->callback)
+       if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_END,tag->nattributes,attributes))
+          BEGIN(LEX_ERROR_CALLBACK);
+
+    if(stackused>0)
+       tag=tag_stack[stackused-1];
+    else
+       tag=NULL;
+
+    END_TOKEN;
+
+    *buffer_ptr=saved_buffer_ptr;
+    BEGIN(next_state);
+
+    /* An attribute key */
+
+   case LEX_FUNC_ATTR_KEY:
+
+    attribute=-1;
+
+    for(i=0;i<tag->nattributes;i++)
+       if(buffer_token[0]==tag->attributes[i][0] || tolower(buffer_token[0])==tag->attributes[i][0])
+          if(!strcasecmp((char*)buffer_token+1,tag->attributes[i]+1))
+            {
+             attribute=i;
+
+             break;
+            }
+
+    if(attribute==-1)
+      {
+       if((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_ERROR ||
+          ((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_ERRNONAME && !strchr((char*)buffer_token,':')))
+          BEGIN(LEX_ERROR_UNEXP_ATT);
+#ifndef LIBROUTINO
+       else if((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_WARN)
+          ParseXML_SetError("Warning on line %"PRIu64": unexpected attribute '%s' for tag '%s'.",lineno,buffer_token,tag->name);
+#endif
+      }
+
+    END_TOKEN;
+
+    *buffer_ptr=saved_buffer_ptr;
+    BEGIN(next_state);
+
+    /* An attribute value */
+
+   case LEX_FUNC_ATTR_VAL:
+
+    if(tag->callback && attribute!=-1)
+       attributes[attribute]=buffer_token;
+
+    END_TOKEN;
+
+    BEGIN(next_state);
+
+    /* End of file */
+
+   case LEX_EOF:
+
+    if(tag)
+       BEGIN(LEX_ERROR_UNEXP_EOF);
+
+    break;
+
+
+    /* ================ Error states ================ */
+
+
+   case LEX_ERROR_TAG_START:
+    ParseXML_SetError("Character '<' seen not at start of tag.");
+    break;
+
+   case LEX_ERROR_XML_DECL_START:
+    ParseXML_SetError("Characters '<?' seen not at start of XML declaration.");
+    break;
+
+   case LEX_ERROR_TAG:
+    ParseXML_SetError("Invalid character seen inside tag '<%s...>'.",tag->name);
+    break;
+
+   case LEX_ERROR_XML_DECL:
+    ParseXML_SetError("Invalid character seen inside XML declaration '<?xml...>'.");
+    break;
+
+   case LEX_ERROR_ATTR:
+    ParseXML_SetError("Invalid attribute definition seen in tag.");
+    break;
+    
+   case LEX_ERROR_END_TAG:
+    ParseXML_SetError("Invalid character seen in end-tag.");
+    break;
+
+   case LEX_ERROR_COMMENT:
+    ParseXML_SetError("Invalid comment seen.");
+    break;
+
+   case LEX_ERROR_CLOSE:
+    ParseXML_SetError("Character '>' seen not at end of tag.");
+    break;
+
+   case LEX_ERROR_ATTR_VAL:
+    ParseXML_SetError("Invalid character '%c' seen in attribute value.",*buffer_ptr);
+    break;
+
+   case LEX_ERROR_ENTITY_REF:
+    ParseXML_SetError("Invalid entity reference '%s' seen in attribute value.",buffer_ptr);
+    break;
+
+   case LEX_ERROR_CHAR_REF:
+    ParseXML_SetError("Invalid character reference '%s' seen in attribute value.",buffer_ptr);
+    break;
+
+   case LEX_ERROR_TEXT_OUTSIDE:
+    ParseXML_SetError("Non-whitespace '%c' seen outside tag.",*buffer_ptr);
+    break;
+
+   case LEX_ERROR_UNEXP_TAG:
+    ParseXML_SetError("Unexpected tag '%s'.",buffer_token);
+    break;
+
+   case LEX_ERROR_UNBALANCED:
+    ParseXML_SetError("End tag '</%s>' doesn't match start tag '<%s ...>'.",buffer_token,tag->name);
+    break;
+
+   case LEX_ERROR_NO_START:
+    ParseXML_SetError("End tag '</%s>' seen but there was no start tag '<%s ...>'.",buffer_token,buffer_token);
+    break;
+
+   case LEX_ERROR_UNEXP_ATT:
+    ParseXML_SetError("Unexpected attribute '%s' for tag '%s'.",buffer_token,tag->name);
+    break;
+
+   case LEX_ERROR_UNEXP_EOF:
+    ParseXML_SetError("End of file seen without end tag '</%s>'.",tag->name);
+    break;
+
+   case LEX_ERROR_XML_NOT_FIRST:
+    ParseXML_SetError("XML declaration '<?xml...>' not before all other tags.");
+    break;
+
+   case LEX_ERROR_CALLBACK:
+    /* The error message should have been set by the callback function, have a fallback just in case */
+    if(!stored_message)
+       ParseXML_SetError("Unknown error from tag callback function.");
+    break;
+   }
+
+ /* Print the error message */
+
+#ifndef LIBROUTINO
+ if(state)
+    fprintf(stderr,"XML Parser: %s\n",stored_message);
+#endif
+
+ /* Delete the tagdata */
+
+ if(stackdepth)
+   {
+    free(tag_stack);
+    free(tags_stack);
+   }
+
+ return(state);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Return the current parser line number.
+
+  uint64_t ParseXML_LineNumber Returns the line number.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+uint64_t ParseXML_LineNumber(void)
+{
+ return(lineno);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Store an error message for later.
+
+  const char *format The format string.
+
+  ... The other arguments.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+void ParseXML_SetError(const char *format, ...)
+{
+ va_list ap;
+ char temp[2];
+ int line_length,error_length;
+
+ line_length=snprintf(temp,1,"Error on line %" PRIu64 ": ",lineno);
+
+ va_start(ap,format);
+ error_length=vsnprintf(temp,1,format,ap);
+ va_end(ap);
+
+ if(stored_message)
+    free(stored_message);
+
+ stored_message=malloc(error_length+line_length+1);
+
+ line_length=sprintf(stored_message,"Error on line %" PRIu64 ": ",lineno);
+
+ va_start(ap,format);
+ vsprintf(stored_message+line_length,format,ap);
+ va_end(ap);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Return a stored error message.
+
+  char *ParseXML_GetError Returns the most recent stored error.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+char *ParseXML_GetError(void)
+{
+ return(stored_message);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Convert an XML entity reference into an ASCII string.
+
+  char *ParseXML_Decode_Entity_Ref Returns a pointer to the replacement decoded string.
+
+  const char *string The entity reference string.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+char *ParseXML_Decode_Entity_Ref(const char *string)
+{
+ if(!strcmp(string,"&"))  return("&");
+ if(!strcmp(string,"<"))   return("<");
+ if(!strcmp(string,">"))   return(">");
+ if(!strcmp(string,"'")) return("'");
+ if(!strcmp(string,""")) return("\"");
+ return(NULL);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Convert an XML character reference into an ASCII string.
+
+  char *ParseXML_Decode_Char_Ref Returns a pointer to the replacement decoded string.
+
+  const char *string The character reference string.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+char *ParseXML_Decode_Char_Ref(const char *string)
+{
+ static char result[5]=""; /* static allocation of return value (set each call) */
+ long int unicode;
+
+ if(string[2]=='x') unicode=strtol(string+3,NULL,16);
+ else               unicode=strtol(string+2,NULL,10);
+
+ if(unicode<0x80)
+   {
+    /* 0000 0000-0000 007F  =>  0xxxxxxx */
+    result[0]=(char)unicode;
+    result[1]=0;
+   }
+ else if(unicode<0x07FF)
+   {
+    /* 0000 0080-0000 07FF  =>  110xxxxx 10xxxxxx */
+    result[0]=(char)(0xC0+((unicode&0x07C0)>>6));
+    result[1]=(char)(0x80+ (unicode&0x003F));
+    result[2]=0;
+   }
+ else if(unicode<0xFFFF)
+   {
+    /* 0000 0800-0000 FFFF  =>  1110xxxx 10xxxxxx 10xxxxxx */
+    result[0]=(char)(0xE0+((unicode&0xF000)>>12));
+    result[1]=(char)(0x80+((unicode&0x0FC0)>>6));
+    result[2]=(char)(0x80+ (unicode&0x003F));
+    result[3]=0;
+   }
+ else if(unicode<0x1FFFFF)
+   {
+    /* 0001 0000-001F FFFF  =>  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+    result[0]=(char)(0xF0+((unicode&0x1C0000)>>18));
+    result[1]=(char)(0x80+((unicode&0x03F000)>>12));
+    result[2]=(char)(0x80+((unicode&0x000FC0)>>6));
+    result[3]=(char)(0x80+ (unicode&0x00003F));
+    result[4]=0;
+   }
+ else
+   {
+    result[0]=(char)0xFF;
+    result[1]=(char)0xFD;
+    result[2]=0;
+   }
+
+ return(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Convert a string into something that is safe to output in an XML file.
+
+  char *ParseXML_Encode_Safe_XML Returns a pointer to a static replacement encoded string (or the original if no change needed).
+
+  const char *string The string to convert.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+char *ParseXML_Encode_Safe_XML(const char *string)
+{
+ static const char hexstring[17]="0123456789ABCDEF"; /* local lookup table */
+ static char *result=NULL;                           /* static allocation of return value */
+ int i=0,j=0,len;
+
+ for(i=0;string[i];i++)
+    if(string[i]=='<' || string[i]=='>' || string[i]=='&' || string[i]=='\'' || string[i]=='"' || string[i]<32 || (unsigned char)string[i]>127)
+       break;
+
+ if(!string[i])
+    return((char*)string);
+
+ len=i+256-6;
+
+ result=(char*)realloc((void*)result,len+7);
+ strncpy(result,string,j=i);
+
+ do
+   {
+    for(;j<len && string[i];i++)
+       if(string[i]=='\'')
+         {
+          /* XML, HTML5 and XHTML1 allow ' but HTML4 doesn't. */
+          result[j++]='&';
+          result[j++]='#';
+          result[j++]='3';
+          result[j++]='9';
+          result[j++]=';';
+         }
+       else if(string[i]=='&')
+         {
+          result[j++]='&';
+          result[j++]='a';
+          result[j++]='m';
+          result[j++]='p';
+          result[j++]=';';
+         }
+       else if(string[i]=='"')
+         {
+          result[j++]='&';
+          result[j++]='q';
+          result[j++]='u';
+          result[j++]='o';
+          result[j++]='t';
+          result[j++]=';';
+         }
+       else if(string[i]=='<')
+         {
+          result[j++]='&';
+          result[j++]='l';
+          result[j++]='t';
+          result[j++]=';';
+         }
+       else if(string[i]=='>')
+         {
+          result[j++]='&';
+          result[j++]='g';
+          result[j++]='t';
+          result[j++]=';';
+         }
+       else if(string[i]>=32 && (unsigned char)string[i]<=127)
+          result[j++]=string[i];
+       else
+         {
+          unsigned int unicode;
+
+          /* Decode the UTF-8 */
+
+          if((string[i]&0x80)==0)
+            {
+             /* 0000 0000-0000 007F  =>  0xxxxxxx */
+             unicode=string[i];
+            }
+          else if((string[i]&0xE0)==0xC0 && (string[i]&0x1F)>=2 && (string[i+1]&0xC0)==0x80)
+            {
+             /* 0000 0080-0000 07FF  =>  110xxxxx 10xxxxxx */
+             unicode =(string[i++]&0x1F)<<6;
+             unicode|= string[i  ]&0x3F;
+            }
+          else if((string[i]&0xF0)==0xE0 && (string[i+1]&0xC0)==0x80 && (string[i+2]&0xC0)==0x80)
+            {
+             /* 0000 0800-0000 FFFF  =>  1110xxxx 10xxxxxx 10xxxxxx */
+             unicode =(string[i++]&0x0F)<<12;
+             unicode|=(string[i++]&0x3F)<<6;
+             unicode|= string[i  ]&0x3F;
+            }
+          else if((string[i]&0xF8)==0xF0 && (string[i+1]&0xC0)==0x80 && (string[i+2]&0xC0)==0x80 && (string[i+3]&0xC0)==0x80)
+            {
+             /* 0001 0000-001F FFFF  =>  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+             unicode =(string[i++]&0x07)<<18;
+             unicode|=(string[i++]&0x3F)<<12;
+             unicode|=(string[i++]&0x3F)<<6;
+             unicode|= string[i  ]&0x3F;
+            }
+          else
+             unicode=0xFFFD;
+
+          /* Output the character entity */
+
+          result[j++]='&';
+          result[j++]='#';
+          result[j++]='x';
+
+          if(unicode&0x00FF0000)
+            {
+             result[j++]=hexstring[((unicode>>16)&0xf0)>>4];
+             result[j++]=hexstring[((unicode>>16)&0x0f)   ];
+            }
+          if(unicode&0x00FFFF00)
+            {
+             result[j++]=hexstring[((unicode>>8)&0xf0)>>4];
+             result[j++]=hexstring[((unicode>>8)&0x0f)   ];
+            }
+          result[j++]=hexstring[(unicode&0xf0)>>4];
+          result[j++]=hexstring[(unicode&0x0f)   ];
+
+          result[j++]=';';
+         }
+
+    if(string[i])                  /* Not finished */
+      {
+       len+=256;
+       result=(char*)realloc((void*)result,len+7);
+      }
+   }
+ while(string[i]);
+
+ result[j]=0;
+
+ return(result);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Check that a string really is an integer.
+
+  int ParseXML_IsInteger Returns 1 if an integer could be found or 0 otherwise.
+
+  const char *string The string to be parsed.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int ParseXML_IsInteger(const char *string)
+{
+ const unsigned char *p=(unsigned char*)string;
+
+ if(*p=='-' || *p=='+')
+    p++;
+
+ while(digit[(int)*p])
+    p++;
+
+ if(*p)
+    return(0);
+ else
+    return(1);
+}
+
+
+/*++++++++++++++++++++++++++++++++++++++
+  Check that a string really is a floating point number.
+
+  int ParseXML_IsFloating Returns 1 if a floating point number could be found or 0 otherwise.
+
+  const char *string The string to be parsed.
+  ++++++++++++++++++++++++++++++++++++++*/
+
+int ParseXML_IsFloating(const char *string)
+{
+ const unsigned char *p=(unsigned char*)string;
+
+ if(*p=='-' || *p=='+')
+    p++;
+
+ while(digit[(int)*p] || *p=='.')
+    p++;
+
+ if(*p=='e' || *p=='E')
+   {
+    p++;
+
+    if(*p=='-' || *p=='+')
+       p++;
+
+    while(digit[*p])
+       p++;
+   }
+
+ if(*p)
+    return(0);
+ else
+    return(1);
+}
+
+
+/* Table for checking for double-quoted characters. */
+static const unsigned char quotedD[256]={ 0, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, 0,10, 0, 0,  /* 0x00-0x0f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x10-0x1f "                " */
+                                         10,10,99,10,10,10,50,10,10,10,10,10,10,10,10,10,  /* 0x20-0x2f " !"#$%&'()*+,-./" */
+                                         10,10,10,10,10,10,10,10,10,10,10,10, 0,10, 0,10,  /* 0x30-0x3f "0123456789:;<=>?" */
+                                         10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,  /* 0x40-0x4f "@ABCDEFGHIJKLMNO" */
+                                         10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,  /* 0x50-0x5f "PQRSTUVWXYZ[\]^_" */
+                                         10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,  /* 0x60-0x6f "`abcdefghijklmno" */
+                                         10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,  /* 0x70-0x7f "pqrstuvwxyz{|}~ " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x80-0x8f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x90-0x9f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xa0-0xaf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xb0-0xbf "                " */
+                                          0, 0,20,20,20,20,20,20,20,20,20,20,20,20,20,20,  /* 0xc0-0xcf "                " */
+                                         20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,  /* 0xd0-0xdf "                " */
+                                         31,32,32,32,32,32,32,32,32,32,32,32,32,33,34,34,  /* 0xe0-0xef "                " */
+                                         41,42,42,42,43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* 0xf0-0xff "                " */
+
+/* Table for checking for single-quoted characters. */
+static const unsigned char quotedS[256]={ 0, 0, 0, 0, 0, 0, 0, 0, 0,10,10, 0, 0,10, 0, 0,  /* 0x00-0x0f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x10-0x1f "                " */
+                                         10,10,10,10,10,10,50,99,10,10,10,10,10,10,10,10,  /* 0x20-0x2f " !"#$%&'()*+,-./" */
+                                         10,10,10,10,10,10,10,10,10,10,10,10, 0,10, 0,10,  /* 0x30-0x3f "0123456789:;<=>?" */
+                                         10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,  /* 0x40-0x4f "@ABCDEFGHIJKLMNO" */
+                                         10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,  /* 0x50-0x5f "PQRSTUVWXYZ[\]^_" */
+                                         10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,  /* 0x60-0x6f "`abcdefghijklmno" */
+                                         10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,  /* 0x70-0x7f "pqrstuvwxyz{|}~ " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x80-0x8f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x90-0x9f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xa0-0xaf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xb0-0xbf "                " */
+                                          0, 0,20,20,20,20,20,20,20,20,20,20,20,20,20,20,  /* 0xc0-0xcf "                " */
+                                         20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,  /* 0xd0-0xdf "                " */
+                                         31,32,32,32,32,32,32,32,32,32,32,32,32,33,34,34,  /* 0xe0-0xef "                " */
+                                         41,42,42,42,43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* 0xf0-0xff "                " */
+
+/* Table for checking for characters between 0x80 and 0x8f. */
+static const unsigned char U_80_8F[256]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x00-0x0f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x10-0x1f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x20-0x2f " !"#$%&'()*+,-./" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x30-0x3f "0123456789:;<=>?" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x40-0x4f "@ABCDEFGHIJKLMNO" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x50-0x5f "PQRSTUVWXYZ[\]^_" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x60-0x6f "`abcdefghijklmno" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x70-0x7f "pqrstuvwxyz{|}~ " */
+                                          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0x80-0x8f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x90-0x9f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xa0-0xaf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xb0-0xbf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xc0-0xcf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xd0-0xdf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xe0-0xef "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* 0xf0-0xff "                " */
+
+/* Table for checking for characters between 0x80 and 0x9f. */
+static const unsigned char U_80_9F[256]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x00-0x0f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x10-0x1f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x20-0x2f " !"#$%&'()*+,-./" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x30-0x3f "0123456789:;<=>?" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x40-0x4f "@ABCDEFGHIJKLMNO" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x50-0x5f "PQRSTUVWXYZ[\]^_" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x60-0x6f "`abcdefghijklmno" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x70-0x7f "pqrstuvwxyz{|}~ " */
+                                          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0x80-0x8f "                " */
+                                          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0x90-0x9f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xa0-0xaf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xb0-0xbf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xc0-0xcf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xd0-0xdf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xe0-0xef "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* 0xf0-0xff "                " */
+
+/* Table for checking for characters between 0x80 and 0xbf. */
+static const unsigned char U_80_BF[256]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x00-0x0f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x10-0x1f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x20-0x2f " !"#$%&'()*+,-./" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x30-0x3f "0123456789:;<=>?" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x40-0x4f "@ABCDEFGHIJKLMNO" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x50-0x5f "PQRSTUVWXYZ[\]^_" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x60-0x6f "`abcdefghijklmno" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x70-0x7f "pqrstuvwxyz{|}~ " */
+                                          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0x80-0x8f "                " */
+                                          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0x90-0x9f "                " */
+                                          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0xa0-0xaf "                " */
+                                          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0xb0-0xbf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xc0-0xcf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xd0-0xdf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xe0-0xef "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* 0xf0-0xff "                " */
+
+/* Table for checking for characters between 0x90 and 0xbf. */
+static const unsigned char U_90_BF[256]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x00-0x0f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x10-0x1f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x20-0x2f " !"#$%&'()*+,-./" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x30-0x3f "0123456789:;<=>?" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x40-0x4f "@ABCDEFGHIJKLMNO" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x50-0x5f "PQRSTUVWXYZ[\]^_" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x60-0x6f "`abcdefghijklmno" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x70-0x7f "pqrstuvwxyz{|}~ " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x80-0x8f "                " */
+                                          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0x90-0x9f "                " */
+                                          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0xa0-0xaf "                " */
+                                          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0xb0-0xbf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xc0-0xcf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xd0-0xdf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xe0-0xef "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* 0xf0-0xff "                " */
+
+/* Table for checking for characters between 0xa0 and 0xbf. */
+static const unsigned char U_A0_BF[256]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x00-0x0f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x10-0x1f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x20-0x2f " !"#$%&'()*+,-./" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x30-0x3f "0123456789:;<=>?" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x40-0x4f "@ABCDEFGHIJKLMNO" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x50-0x5f "PQRSTUVWXYZ[\]^_" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x60-0x6f "`abcdefghijklmno" */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x70-0x7f "pqrstuvwxyz{|}~ " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x80-0x8f "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x90-0x9f "                " */
+                                          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0xa0-0xaf "                " */
+                                          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0xb0-0xbf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xc0-0xcf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xd0-0xdf "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xe0-0xef "                " */
+                                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* 0xf0-0xff "                " */
+
+/* Table for checking for U2 characters = C2-DF,80-BF = U+0080-U+07FF. */
+static const unsigned char *U2[1]={ U_80_BF };
+
+/* Table for checking for U3a characters = E0,A0-BF,80-BF = U+0800-U+0FFF. */
+static const unsigned char *U3a[2]={ U_A0_BF, U_80_BF };
+
+/* Table for checking for U3b characters = E1-EC,80-BF,80-BF = U+1000-U+CFFF. */
+static const unsigned char *U3b[2]={ U_80_BF, U_80_BF };
+
+/* Table for checking for U3c characters = ED,80-9F,80-BF = U+D000-U+D7FF (U+D800-U+DFFF are not legal in XML). */
+static const unsigned char *U3c[2]={ U_80_9F, U_80_BF };
+
+/* Table for checking for U3d characters = EE-EF,80-BF,80-BF = U+E000-U+FFFF (U+FFFE-U+FFFF are not legal in XML but handled). */
+static const unsigned char *U3d[2]={ U_80_BF, U_80_BF };
+
+/* Table for checking for U4a characters = F0,90-BF,80-BF,80-BF = U+10000-U+3FFFF. */
+static const unsigned char *U4a[3]={ U_90_BF, U_80_BF, U_80_BF };
+
+/* Table for checking for U4b characters = F1-F3,80-BF,80-BF,80-BF = U+40000-U+FFFFF. */
+static const unsigned char *U4b[3]={ U_80_BF, U_80_BF, U_80_BF };
+
+/* Table for checking for U4c characters = F4,80-8F,80-BF,80-BF = U+100000-U+10FFFF (U+110000- are not legal in XML). */
+static const unsigned char *U4c[3]={ U_80_8F, U_80_BF, U_80_BF };
+
+/* Table for checking for namestart characters. */
+static const unsigned char namestart[256]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x00-0x0f "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x10-0x1f "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x20-0x2f " !"#$%&'()*+,-./" */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,  /* 0x30-0x3f "0123456789:;<=>?" */
+                                            0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0x40-0x4f "@ABCDEFGHIJKLMNO" */
+                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,  /* 0x50-0x5f "PQRSTUVWXYZ[\]^_" */
+                                            0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0x60-0x6f "`abcdefghijklmno" */
+                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  /* 0x70-0x7f "pqrstuvwxyz{|}~ " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x80-0x8f "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x90-0x9f "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xa0-0xaf "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xb0-0xbf "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xc0-0xcf "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xd0-0xdf "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xe0-0xef "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* 0xf0-0xff "                " */
+
+/* Table for checking for namechar characters. */
+static const unsigned char namechar[256] ={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x00-0x0f "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x10-0x1f "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,  /* 0x20-0x2f " !"#$%&'()*+,-./" */
+                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  /* 0x30-0x3f "0123456789:;<=>?" */
+                                            0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0x40-0x4f "@ABCDEFGHIJKLMNO" */
+                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,  /* 0x50-0x5f "PQRSTUVWXYZ[\]^_" */
+                                            0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0x60-0x6f "`abcdefghijklmno" */
+                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  /* 0x70-0x7f "pqrstuvwxyz{|}~ " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x80-0x8f "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x90-0x9f "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xa0-0xaf "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xb0-0xbf "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xc0-0xcf "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xd0-0xdf "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xe0-0xef "                " */
+                                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* 0xf0-0xff "                " */
+
+/* Table for checking for whitespace characters. */
+static const unsigned char whitespace[256]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,  /* 0x00-0x0f "                " */
+                                             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x10-0x1f "                " */
+                                             1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x20-0x2f " !"#$%&'()*+,-./" */
+                                             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x30-0x3f "0123456789:;<=>?" */
+                                             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x40-0x4f "@ABCDEFGHIJKLMNO" */
+                                             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x50-0x5f "PQRSTUVWXYZ[\]^_" */
+                                             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x60-0x6f "`abcdefghijklmno" */
+                                             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x70-0x7f "pqrstuvwxyz{|}~ " */
+                                             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x80-0x8f "                " */
+                                             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x90-0x9f "                " */
+                                             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xa0-0xaf "                " */
+                                             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xb0-0xbf "                " */
+                                             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xc0-0xcf "                " */
+                                             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xd0-0xdf "                " */
+                                             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xe0-0xef "                " */
+                                             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* 0xf0-0xff "                " */
+
+/* Table for checking for digit characters. */
+static const unsigned char digit[256]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x00-0x0f "                " */
+                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x10-0x1f "                " */
+                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x20-0x2f " !"#$%&'()*+,-./" */
+                                        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  /* 0x30-0x3f "0123456789:;<=>?" */
+                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x40-0x4f "@ABCDEFGHIJKLMNO" */
+                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x50-0x5f "PQRSTUVWXYZ[\]^_" */
+                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x60-0x6f "`abcdefghijklmno" */
+                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x70-0x7f "pqrstuvwxyz{|}~ " */
+                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x80-0x8f "                " */
+                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x90-0x9f "                " */
+                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xa0-0xaf "                " */
+                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xb0-0xbf "                " */
+                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xc0-0xcf "                " */
+                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xd0-0xdf "                " */
+                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xe0-0xef "                " */
+                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* 0xf0-0xff "                " */
+
+/* Table for checking for xdigit characters. */
+static const unsigned char xdigit[256]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x00-0x0f "                " */
+                                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x10-0x1f "                " */
+                                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x20-0x2f " !"#$%&'()*+,-./" */
+                                         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  /* 0x30-0x3f "0123456789:;<=>?" */
+                                         0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x40-0x4f "@ABCDEFGHIJKLMNO" */
+                                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x50-0x5f "PQRSTUVWXYZ[\]^_" */
+                                         0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x60-0x6f "`abcdefghijklmno" */
+                                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x70-0x7f "pqrstuvwxyz{|}~ " */
+                                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x80-0x8f "                " */
+                                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x90-0x9f "                " */
+                                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xa0-0xaf "                " */
+                                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xb0-0xbf "                " */
+                                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xc0-0xcf "                " */
+                                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xd0-0xdf "                " */
+                                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0xe0-0xef "                " */
+                                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* 0xf0-0xff "                " */
diff --git a/3rdparty/Routino/src/xmlparse.h b/3rdparty/Routino/src/xmlparse.h
new file mode 100644
index 0000000..ec8119f
--- /dev/null
+++ b/3rdparty/Routino/src/xmlparse.h
@@ -0,0 +1,138 @@
+/***************************************
+ A simple XML parser
+
+ Part of the Routino routing software.
+ ******************/ /******************
+ This file Copyright 2010-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ***************************************/
+
+
+#ifndef XMLPARSE_H
+#define XMLPARSE_H    /*+ To stop multiple inclusions. +*/
+
+#include <stdint.h>
+#include <inttypes.h>
+
+
+/*+ The maximum number of attributes per tag. +*/
+#define XMLPARSE_MAX_ATTRS   16
+
+/*+ The maximum number of subtags per tag. +*/
+#define XMLPARSE_MAX_SUBTAGS 16
+
+/*+ A flag to indicate the start and/or end of a tag. +*/
+#define XMLPARSE_TAG_START    1
+#define XMLPARSE_TAG_END      2
+
+
+/*+ A forward definition of the xmltag +*/
+typedef struct _xmltag xmltag;
+
+
+/*+ A structure to hold the definition of a tag. +*/
+struct _xmltag
+{
+ const char * const name;                            /*+ The name of the tag - must be in lower case. +*/
+
+ const int  nattributes;                             /*+ The number of valid attributes for the tag. +*/
+ const char * const attributes[XMLPARSE_MAX_ATTRS];  /*+ The valid attributes for the tag. +*/
+
+ int  (*callback)();                                 /*+ The callback function when the tag is seen. +*/
+
+ const xmltag * const subtags[XMLPARSE_MAX_SUBTAGS]; /*+ The list of valid tags contained within this one (null terminated). +*/
+};
+
+
+/* XML Parser options */
+
+#define XMLPARSE_UNKNOWN_ATTRIBUTES     0x0003
+#define XMLPARSE_UNKNOWN_ATTR_ERROR     0x0000 /* Flag an error and exit. */
+#define XMLPARSE_UNKNOWN_ATTR_ERRNONAME 0x0001 /* Flag an error and exit unless a namespace is specified. */
+#define XMLPARSE_UNKNOWN_ATTR_WARN      0x0002 /* Warn about the problem and continue. */
+#define XMLPARSE_UNKNOWN_ATTR_IGNORE    0x0003 /* Ignore the potential problem. */
+
+#define XMLPARSE_RETURN_ATTR_ENCODED    0x0004 /* Return the XML attribute strings without decoding them. */
+
+
+/* XML parser functions */
+
+int ParseXML(int fd,const xmltag * const *tags,int options);
+
+uint64_t ParseXML_LineNumber(void);
+
+void ParseXML_SetError(const char *format, ...);
+char *ParseXML_GetError(void);
+
+char *ParseXML_Decode_Entity_Ref(const char *string);
+char *ParseXML_Decode_Char_Ref(const char *string);
+char *ParseXML_Encode_Safe_XML(const char *string);
+
+int ParseXML_IsInteger(const char *string);
+int ParseXML_IsFloating(const char *string);
+
+/* Macros to simplify the callback functions */
+
+#define XMLPARSE_MESSAGE(tag,message) \
+ do \
+   { \
+    ParseXML_SetError(message " in <%s> tag.",tag); \
+    return(1); \
+   } \
+    while(0)
+
+#define XMLPARSE_INVALID(tag,attribute) \
+ do \
+   { \
+    ParseXML_SetError("Invalid value for '" #attribute "' attribute in <%s> tag.",tag); \
+    return(1); \
+   } \
+    while(0)
+
+#define XMLPARSE_ASSERT_STRING(tag,attribute) \
+ do \
+   { \
+    if(!attribute) \
+      { \
+       ParseXML_SetError("'" #attribute "' attribute must be specified in <%s> tag.",tag); \
+       return(1); \
+      } \
+   } \
+    while(0)
+
+#define XMLPARSE_ASSERT_INTEGER(tag,attribute)  \
+ do \
+   { \
+    if(!attribute || !*attribute || !ParseXML_IsInteger(attribute)) \
+      { \
+       ParseXML_SetError("'" #attribute "' attribute must be a integer in <%s> tag.",tag); \
+       return(1); \
+      } \
+   } \
+    while(0)
+
+#define XMLPARSE_ASSERT_FLOATING(tag,attribute)  \
+ do \
+   { \
+    if(!attribute || !*attribute || !ParseXML_IsFloating(attribute)) \
+      { \
+       ParseXML_SetError("'" #attribute "' attribute must be a number in <%s> tag.",tag); \
+       return(1); \
+      } \
+   } \
+    while(0)
+
+
+#endif /* XMLPARSE_H */
diff --git a/3rdparty/Routino/web/INSTALL.txt b/3rdparty/Routino/web/INSTALL.txt
new file mode 120000
index 0000000..4c0523b
--- /dev/null
+++ b/3rdparty/Routino/web/INSTALL.txt
@@ -0,0 +1 @@
+../doc/INSTALL.txt
\ No newline at end of file
diff --git a/3rdparty/Routino/web/Makefile b/3rdparty/Routino/web/Makefile
new file mode 100644
index 0000000..81563a2
--- /dev/null
+++ b/3rdparty/Routino/web/Makefile
@@ -0,0 +1,232 @@
+# web directory Makefile
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2010-2015 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# All configuration is in the top-level Makefile.conf
+
+include ../Makefile.conf
+
+# Web file paths and other paths
+
+WEBBINDIR=bin
+WEBDATADIR=data
+WEBTRANSDIR=translations
+WEBWWWDIR=www/routino
+WEBICONDIR=www/routino/icons
+WEBDOCDIR=www/routino/documentation
+
+XMLDIR=../xml
+DOCDIR=../doc
+SRCDIR=../src
+
+# Files to install
+
+STANDARD_XML_FILES=profiles.xml \
+	           translations.xml \
+	           tagging.xml
+
+SPECIAL_XML_FILES=tagging-drive.xml \
+	          tagging-ride.xml \
+	          tagging-walk.xml
+
+PROFILE_FILES=profiles.pl \
+	      profiles.js
+
+TRANS_FILES=$(wildcard $(WEBTRANSDIR)/translation.*.txt)
+
+DOC_FILES=$(notdir $(wildcard $(DOCDIR)/html/*.html)) $(notdir $(wildcard $(DOCDIR)/html/*.css))
+
+EXE_FILES=planetsplitter planetsplitter-slim router router-slim filedumperx filedumper filedumper-slim
+
+########
+
+all: all-bin all-data all-doc all-profiles all-translations all-icons
+
+####
+
+all-bin: all-exe
+	@[ -d $(WEBBINDIR) ] || mkdir -p $(WEBBINDIR)
+	@for file in $(EXE_FILES); do \
+	    if [ -f $(SRCDIR)/$$file -a ! -f $(WEBBINDIR)/$$file ] || [ $(SRCDIR)/$$file -nt $(WEBBINDIR)/$$file ]; then \
+	       echo cp $(SRCDIR)/$$file $(WEBBINDIR) ;\
+	       cp -f $(SRCDIR)/$$file $(WEBBINDIR) ;\
+	    fi ;\
+	    if [ -f $(SRCDIR)/$$file.exe -a ! -f $(WEBBINDIR)/$$file.exe ] || [ $(SRCDIR)/$$file.exe -nt $(WEBBINDIR)/$$file.exe ]; then \
+	       echo cp $(SRCDIR)/$$file.exe $(WEBBINDIR) ;\
+	       cp -f $(SRCDIR)/$$file.exe $(WEBBINDIR) ;\
+	    fi ;\
+	 done
+
+####
+
+all-data: all-xml
+	@[ -d $(WEBDATADIR) ] || mkdir -p $(WEBDATADIR)
+	@for file in $(STANDARD_XML_FILES); do \
+	    if [ ! -f $(WEBDATADIR)/$$file ] || [ $(XMLDIR)/routino-$$file -nt $(WEBDATADIR)/$$file ]; then \
+	       echo cp $(XMLDIR)/routino-$$file $(WEBDATADIR)/$$file ;\
+	       cp -f $(XMLDIR)/routino-$$file $(WEBDATADIR)/$$file ;\
+	    fi ;\
+	 done
+	@for file in $(SPECIAL_XML_FILES); do \
+	    if [ ! -f $(WEBDATADIR)/$$file ] || [ $(XMLDIR)/$$file -nt $(WEBDATADIR)/$$file ]; then \
+	       echo cp $(XMLDIR)/$$file $(WEBDATADIR)/$$file ;\
+	       cp -f $(XMLDIR)/$$file $(WEBDATADIR)/$$file ;\
+	    fi ;\
+	 done
+
+####
+
+all-doc:
+	@[ -d $(WEBDOCDIR) ] || mkdir -p $(WEBDOCDIR)
+	@for file in $(DOC_FILES); do \
+	    if [ ! -f $(WEBDOCDIR)/$$file ] || [ $(DOCDIR)/html/$$file -nt $(WEBDOCDIR)/$$file ]; then \
+	       echo cp $(DOCDIR)/html/$$file $(WEBDOCDIR) ;\
+	       cp -f $(DOCDIR)/html/$$file $(WEBDOCDIR) ;\
+	    fi ;\
+	 done
+
+####
+
+all-profiles: all-exe all-data
+	@if [ ! -f $(WEBWWWDIR)/profiles.js ] || [ ! -f $(WEBWWWDIR)/profiles.pl ] || \
+	     [ $(WEBDATADIR)/profiles.xml -nt $(WEBWWWDIR)/profiles.pl ] || \
+	     [ $(WEBDATADIR)/profiles.xml -nt $(WEBWWWDIR)/profiles.js ]; then \
+	    echo update-profiles.pl ;\
+	    ( cd $(WEBWWWDIR) ; perl update-profiles.pl ) ;\
+	 fi
+
+####
+
+all-translations: $(WEBWWWDIR)/router.html    $(WEBWWWDIR)/visualiser.html \
+	          $(WEBWWWDIR)/router.html.en $(WEBWWWDIR)/visualiser.html.en \
+	          $(XMLDIR)/routino-translations.xml
+
+ifdef MINGW
+
+$(WEBWWWDIR)/router.html: $(WEBWWWDIR)/router.html.en
+	@echo cp $< $@
+	@cp -f $< $@
+
+$(WEBWWWDIR)/visualiser.html: $(WEBWWWDIR)/visualiser.html.en
+	@echo cp $< $@
+	@cp -f $< $@
+
+else
+
+$(WEBWWWDIR)/router.html: $(WEBWWWDIR)/router.html.en
+	@echo ln -s `basename $<` $@
+	@ln -s -f `basename $<` $@
+
+$(WEBWWWDIR)/visualiser.html: $(WEBWWWDIR)/visualiser.html.en
+	@echo ln -s `basename $<` $@
+	@ln -s -f `basename $<` $@
+
+endif
+
+$(WEBWWWDIR)/router.html.en: $(WEBTRANSDIR)/router.html $(TRANS_FILES) $(WEBTRANSDIR)/translate.pl
+	@echo translate.pl
+	@cd $(WEBTRANSDIR) && perl translate.pl
+
+$(WEBWWWDIR)/visualiser.html.en: $(WEBTRANSDIR)/visualiser.html $(TRANS_FILES) $(WEBTRANSDIR)/translate.pl
+	@echo translate.pl
+	@cd $(WEBTRANSDIR) && perl translate.pl
+
+$(XMLDIR)/routino-translations.xml: $(WEBTRANSDIR)/translations-head.xml $(WEBTRANSDIR)/translations-body.xml $(WEBTRANSDIR)/translations-tail.xml $(TRANS_FILES) $(WEBTRANSDIR)/translate.pl
+	@echo translate.pl
+	@cd $(WEBTRANSDIR) && perl translate.pl
+
+####
+
+all-icons: $(WEBICONDIR)/ball-0.png
+
+$(WEBICONDIR)/ball-0.png: $(WEBICONDIR)/create-icons.pl
+	@echo create-icons.pl
+	@cd $(WEBICONDIR) && perl create-icons.pl
+
+####
+
+all-exe:
+	cd $(SRCDIR) && $(MAKE) $(EXE_FILES)
+
+####
+
+all-xml: $(XMLDIR)/routino-translations.xml
+	cd $(XMLDIR) && $(MAKE) all
+
+########
+
+test:
+
+########
+
+install: all
+	@echo "******************************************************"
+	@echo "* Note: web directory is not installed automatically *"
+	@echo "******************************************************"
+
+########
+
+clean: clean clean-all-bin clean-all-data clean-all-doc clean-all-profiles clean-all-translations clean-all-icons
+	rm -f *~
+
+clean-all-bin:
+	-cd $(WEBBINDIR)  && rm -f $(EXE_FILES) *.exe
+
+clean-all-data:
+	-cd $(WEBDATADIR) && rm -f $(STANDARD_XML_FILES)
+	-cd $(WEBDATADIR) && rm -f $(SPECIAL_XML_FILES)
+
+clean-all-doc:
+	-cd $(WEBDOCDIR)  && rm -f $(DOC_FILES)
+
+clean-all-profiles:
+
+clean-all-translations:
+
+clean-all-icons:
+
+########
+
+distclean: distclean-all-bin distclean-all-data distclean-all-doc distclean-all-profiles distclean-all-translations distclean-all-icons
+
+distclean-all-bin: clean-all-bin
+
+distclean-all-data: clean-all-data
+
+distclean-all-doc: clean-all-doc
+
+distclean-all-profiles: clean-all-profiles
+	-cd $(WEBWWWDIR)  && rm -f $(PROFILE_FILES)
+
+distclean-all-translations: clean-all-translations
+	-cd $(WEBWWWDIR)  && rm -f router.html*
+	-cd $(WEBWWWDIR)  && rm -f visualiser.html*
+
+distclean-all-icons: clean-all-icons
+	-cd $(WEBICONDIR) && rm -f ball-*.png limit-*.png marker-*.png
+
+########
+
+.PHONY:: all test install clean distclean
+
+.PHONY:: all-bin all-data all-doc all-profiles all-icons all-translations all-exe all-xml
+
+.PHONY:: clean-all-bin clean-all-data clean-all-doc clean-all-profiles clean-all-translations clean-all-icons
+
+.PHONY:: distclean-all-bin distclean-all-data distclean-all-doc distclean-all-profiles distclean-all-translations distclean-all-icons
diff --git a/3rdparty/Routino/web/data/create.sh b/3rdparty/Routino/web/data/create.sh
new file mode 100755
index 0000000..19d5a8e
--- /dev/null
+++ b/3rdparty/Routino/web/data/create.sh
@@ -0,0 +1,20 @@
+#!/bin/sh -x
+
+# This script can download from the GeoFabrik server.
+
+
+# EDIT THIS to set the names of the files to download from GeoFabrik.
+files="europe/great-britain-latest.osm.bz2 europe/ireland-and-northern-ireland-latest.osm.bz2"
+server="download.geofabrik.de"
+
+
+# Download the files
+
+for file in $files; do
+   wget -N http://$server/$file
+done
+
+
+# Process the data
+
+../bin/planetsplitter --errorlog *.osm.bz2
diff --git a/3rdparty/Routino/web/translations/router.html b/3rdparty/Routino/web/translations/router.html
new file mode 100644
index 0000000..125d3e6
--- /dev/null
+++ b/3rdparty/Routino/web/translations/router.html
@@ -0,0 +1,390 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="keywords" content="openstreetmap routing route planner">
+<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, user-scalable=no">
+
+<title>Routino : @@ROUTER-TITLE@@</title>
+
+<!--
+ Routino router web page.
+
+ Part of the Routino routing software.
+
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see http://www.gnu.org/licenses/.
+-->
+
+<!-- Page elements -->
+<script src="page-elements.js" type="text/javascript"></script>
+<link href="page-elements.css" type="text/css" rel="stylesheet">
+
+<!-- Router and visualiser shared features -->
+<link href="maplayout.css" type="text/css" rel="stylesheet">
+
+<!-- Router specific features -->
+<script src="profiles.js" type="text/javascript"></script>
+<link href="router.css" type="text/css" rel="stylesheet">
+
+<!-- Map parameters -->
+<script src="mapprops.js" type="text/javascript"></script>
+
+<!-- Map loader -->
+<script src="maploader.js" type="text/javascript"></script>
+
+</head>
+<body onload="map_load('html_init();map_init();form_init();');">
+
+<!-- Left hand side of window - data panel -->
+
+<div class="left_panel">
+
+  <div class="tab_box">
+    <span id="tab_options" onclick="tab_select('options');" class="tab_selected"   title="@@OPTION-TAB-HELP@@">@@OPTION-TAB@@</span>
+    <span id="tab_results" onclick="tab_select('results');" class="tab_unselected" title="@@RESULTS-TAB-HELP@@">@@RESULTS-TAB@@</span>
+    <span id="tab_data"    onclick="tab_select('data');"    class="tab_unselected" title="@@DATA-TAB-HELP@@">@@DATA-TAB@@</span>
+  </div>
+
+  <div class="tab_content" id="tab_options_div">
+
+    <form name="form" id="form" action="#" method="get" onsubmit="return false;">
+      <div class="hideshow_box">
+        <span class="hideshow_title">@@ROUTINO-ROUTER@@</span>
+        $$ROUTER-INFO$$
+        <div class="center">
+          <a target="other" href="http://www.routino.org/">@@ROUTINO-WEBSITE@@</a>
+          |
+          <a target="other" href="documentation/">@@DOCUMENTATION@@</a>
+        </div>
+      </div>
+
+      <div class="hideshow_box">
+        <span id="hideshow_language_show" onclick="hideshow_show('language');" class="hideshow_show">+</span>
+        <span id="hideshow_language_hide" onclick="hideshow_hide('language');" class="hideshow_hide">-</span>
+        <span class="hideshow_title">@@LANGUAGE-BOX@@</span>
+
+        <div id="hideshow_language_div" style="display: none;">
+          <table>
+           **LANGUAGES-META**
+            <tr>
+              <td><a id="lang_~~lang~~_url" href="router.html.~~lang~~" title="@@LANGUAGE-WEBPAGE@@">@@LANGUAGE@@</a>
+              <td>(~~LANG~~)
+              <td><input name="language" type="radio" value="~~lang~~" onchange="formSetLanguage();" ~~CHECKED~~>
+           **LANGUAGES-META**
+          </table>
+          <a target="translation" href="http://www.routino.org/translations/">Routino Translations</a>
+        </div>
+      </div>
+
+      <div class="hideshow_box">
+        <span id="hideshow_waypoint_show" onclick="hideshow_show('waypoint');" class="hideshow_hide">+</span>
+        <span id="hideshow_waypoint_hide" onclick="hideshow_hide('waypoint');" class="hideshow_show">-</span>
+        <span class="hideshow_title">@@WAYPOINTS-BOX@@</span>
+        <div id="hideshow_waypoint_div">
+          <div id="waypoints">
+            <div id="waypointXXX" class="waypoint" style="display: none;">
+              <img id="iconXXX" class="waypoint-icon" src="icons/marker-XXX-grey.png" title="@@WAYPOINT-POSITION@@" alt="Waypoint XXX" onmouseup="markerToggleMap(XXX);" draggable="true">
+              <span id="coordsXXX">
+                <input name="lonXXX" type="text" size="7" title="@@WAYPOINT-LONGITUDE@@" onchange="formSetCoords(XXX);">E
+                <input name="latXXX" type="text" size="7" title="@@WAYPOINT-LATITUDE@@"  onchange="formSetCoords(XXX);">N
+              </span>
+              <span id="searchXXX" style="display: none;">
+                <input name="searchXXX" type="text" size="18" title="@@WAYPOINT-LOCATION@@"> <!-- uses Javascript event for triggering -->
+              </span>
+              <div class="waypoint-buttons" style="display: inline-block;">
+                <img alt="?" src="icons/waypoint-search.png"   title="@@WAYPOINT-SEARCH@@"  onmousedown="markerSearch(XXX);"  >
+                <img alt="G" src="icons/waypoint-locate.png"   title="@@WAYPOINT-GET@@"     onmousedown="markerLocate(XXX);"  >
+                <img alt="O" src="icons/waypoint-recentre.png" title="@@WAYPOINT-CENTRE1@@" onmousedown="markerRecentre(XXX);">
+                <img alt="^" src="icons/waypoint-up.png"       title="@@WAYPOINT-UP@@"      onmousedown="markerMoveUp(XXX);"  >
+                <img alt="+" src="icons/waypoint-add.png"      title="@@WAYPOINT-ADD@@"     onmousedown="markerAddAfter(XXX);">
+                <br>
+                <img alt="#" src="icons/waypoint-coords.png"   title="@@WAYPOINT-COORDS@@"  onmousedown="markerCoords(XXX);"  >
+                <img alt="~" src="icons/waypoint-home.png"     title="@@WAYPOINT-HOME@@"    onmousedown="markerHome(XXX);"    >
+                <img alt="o" src="icons/waypoint-centre.png"   title="@@WAYPOINT-CENTRE2@@" onmousedown="markerCentre(XXX);"  >
+                <img alt="v" src="icons/waypoint-down.png"     title="@@WAYPOINT-DOWN@@"    onmousedown="markerMoveDown(XXX);">
+                <img alt="-" src="icons/waypoint-remove.png"   title="@@WAYPOINT-REMOVE@@"  onmousedown="markerRemove(XXX);"  >
+              </div>
+              <div id="searchresultsXXX" style="display: none;">
+              </div>
+            </div>
+          </div>
+          <div id="waypoints-buttons" class="center">
+            <input type="button" title="@@WAYPOINT-REVERSE@@" value="@@WAYPOINT-REVERSE-BUTTON@@" onmousedown="markersReverse();">
+            <input type="button" title="@@WAYPOINT-LOOP@@"    value="@@WAYPOINT-LOOP-BUTTON@@"    onmousedown="markersLoop();">
+          </div>
+        </div>
+      </div>
+
+      <div class="hideshow_box">
+        <span id="hideshow_transport_show" onclick="hideshow_show('transport');" class="hideshow_hide">+</span>
+        <span id="hideshow_transport_hide" onclick="hideshow_hide('transport');" class="hideshow_show">-</span>
+        <span class="hideshow_title">@@TRANSPORT-TYPE-BOX@@</span>
+        <div id="hideshow_transport_div">
+          <table>
+            <tr><td>@@TRANSPORT-FOOT@@:      <td><input name="transport" type="radio" value="foot"       onchange="formSetTransport('foot'      );">
+            <tr><td>@@TRANSPORT-HORSE@@:     <td><input name="transport" type="radio" value="horse"      onchange="formSetTransport('horse'     );">
+            <tr><td>@@TRANSPORT-WHEELCHAIR@@:<td><input name="transport" type="radio" value="wheelchair" onchange="formSetTransport('wheelchair');">
+            <tr><td>@@TRANSPORT-BICYCLE@@:   <td><input name="transport" type="radio" value="bicycle"    onchange="formSetTransport('bicycle'   );">
+            <tr><td>@@TRANSPORT-MOPED@@:     <td><input name="transport" type="radio" value="moped"      onchange="formSetTransport('moped'     );">
+            <tr><td>@@TRANSPORT-MOTORCYCLE@@:<td><input name="transport" type="radio" value="motorcycle" onchange="formSetTransport('motorcycle');">
+            <tr><td>@@TRANSPORT-MOTORCAR@@:  <td><input name="transport" type="radio" value="motorcar"   onchange="formSetTransport('motorcar'  );">
+            <tr><td>@@TRANSPORT-GOODS@@:     <td><input name="transport" type="radio" value="goods"      onchange="formSetTransport('goods'     );">
+            <tr><td>@@TRANSPORT-HGV@@:       <td><input name="transport" type="radio" value="hgv"        onchange="formSetTransport('hgv'       );">
+            <tr><td>@@TRANSPORT-PSV@@:       <td><input name="transport" type="radio" value="psv"        onchange="formSetTransport('psv'       );">
+          </table>
+        </div>
+      </div>
+
+      <div class="hideshow_box">
+        <span id="hideshow_highway_show" onclick="hideshow_show('highway');" class="hideshow_show">+</span>
+        <span id="hideshow_highway_hide" onclick="hideshow_hide('highway');" class="hideshow_hide">-</span>
+        <span class="hideshow_title">@@HIGHWAY-PREFERENCES-BOX@@</span>
+        <div id="hideshow_highway_div" style="display: none;">
+          <table>
+            <tr><td>@@HIGHWAY-MOTORWAY@@:    <td><input name="highway-motorway"     type="text" size="3" onchange="formSetHighway('motorway'    ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetHighway('motorway'    ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetHighway('motorway'    ,'+');">
+            <tr><td>@@HIGHWAY-TRUNK@@:       <td><input name="highway-trunk"        type="text" size="3" onchange="formSetHighway('trunk'       ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetHighway('trunk'       ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetHighway('trunk'       ,'+');">
+            <tr><td>@@HIGHWAY-PRIMARY@@:     <td><input name="highway-primary"      type="text" size="3" onchange="formSetHighway('primary'     ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetHighway('primary'     ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetHighway('primary'     ,'+');">
+            <tr><td>@@HIGHWAY-SECONDARY@@:   <td><input name="highway-secondary"    type="text" size="3" onchange="formSetHighway('secondary'   ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetHighway('secondary'   ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetHighway('secondary'   ,'+');">
+            <tr><td>@@HIGHWAY-TERTIARY@@:    <td><input name="highway-tertiary"     type="text" size="3" onchange="formSetHighway('tertiary'    ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetHighway('tertiary'    ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetHighway('tertiary'    ,'+');">
+            <tr><td>@@HIGHWAY-UNCLASSIFIED@@:<td><input name="highway-unclassified" type="text" size="3" onchange="formSetHighway('unclassified','=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetHighway('unclassified','-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetHighway('unclassified','+');">
+            <tr><td>@@HIGHWAY-RESIDENTIAL@@: <td><input name="highway-residential"  type="text" size="3" onchange="formSetHighway('residential' ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetHighway('residential' ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetHighway('residential' ,'+');">
+            <tr><td>@@HIGHWAY-SERVICE@@:     <td><input name="highway-service"      type="text" size="3" onchange="formSetHighway('service'     ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetHighway('service'     ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetHighway('service'     ,'+');">
+            <tr><td>@@HIGHWAY-TRACK@@:       <td><input name="highway-track"        type="text" size="3" onchange="formSetHighway('track'       ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetHighway('track'       ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetHighway('track'       ,'+');">
+            <tr><td>@@HIGHWAY-CYCLEWAY@@:    <td><input name="highway-cycleway"     type="text" size="3" onchange="formSetHighway('cycleway'    ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetHighway('cycleway'    ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetHighway('cycleway'    ,'+');">
+            <tr><td>@@HIGHWAY-PATH@@:        <td><input name="highway-path"         type="text" size="3" onchange="formSetHighway('path'        ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetHighway('path'        ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetHighway('path'        ,'+');">
+            <tr><td>@@HIGHWAY-STEPS@@:       <td><input name="highway-steps"        type="text" size="3" onchange="formSetHighway('steps'       ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetHighway('steps'       ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetHighway('steps'       ,'+');">
+            <tr><td>@@HIGHWAY-FERRY@@:       <td><input name="highway-ferry"        type="text" size="3" onchange="formSetHighway('ferry'       ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetHighway('ferry'       ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetHighway('ferry'       ,'+');">
+          </table>
+        </div>
+      </div>
+
+      <div class="hideshow_box">
+        <span id="hideshow_speed_show" onclick="hideshow_show('speed');" class="hideshow_show">+</span>
+        <span id="hideshow_speed_hide" onclick="hideshow_hide('speed');" class="hideshow_hide">-</span>
+        <span class="hideshow_title">@@SPEED-LIMITS-BOX@@</span>
+        <div id="hideshow_speed_div" style="display: none;">
+          <table>
+            <tr><td>@@HIGHWAY-MOTORWAY@@:    <td><input name="speed-motorway"     type="text" size="3" onchange="formSetSpeed('motorway'    ,'=');"><td>km/hr<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetSpeed('motorway'    ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetSpeed('motorway'    ,'+');">
+            <tr><td>@@HIGHWAY-TRUNK@@:       <td><input name="speed-trunk"        type="text" size="3" onchange="formSetSpeed('trunk'       ,'=');"><td>km/hr<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetSpeed('trunk'       ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetSpeed('trunk'       ,'+');">
+            <tr><td>@@HIGHWAY-PRIMARY@@:     <td><input name="speed-primary"      type="text" size="3" onchange="formSetSpeed('primary'     ,'=');"><td>km/hr<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetSpeed('primary'     ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetSpeed('primary'     ,'+');">
+            <tr><td>@@HIGHWAY-SECONDARY@@:   <td><input name="speed-secondary"    type="text" size="3" onchange="formSetSpeed('secondary'   ,'=');"><td>km/hr<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetSpeed('secondary'   ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetSpeed('secondary'   ,'+');">
+            <tr><td>@@HIGHWAY-TERTIARY@@:    <td><input name="speed-tertiary"     type="text" size="3" onchange="formSetSpeed('tertiary'    ,'=');"><td>km/hr<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetSpeed('tertiary'    ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetSpeed('tertiary'    ,'+');">
+            <tr><td>@@HIGHWAY-UNCLASSIFIED@@:<td><input name="speed-unclassified" type="text" size="3" onchange="formSetSpeed('unclassified','=');"><td>km/hr<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetSpeed('unclassified','-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetSpeed('unclassified','+');">
+            <tr><td>@@HIGHWAY-RESIDENTIAL@@: <td><input name="speed-residential"  type="text" size="3" onchange="formSetSpeed('residential' ,'=');"><td>km/hr<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetSpeed('residential' ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetSpeed('residential' ,'+');">
+            <tr><td>@@HIGHWAY-SERVICE@@:     <td><input name="speed-service"      type="text" size="3" onchange="formSetSpeed('service'     ,'=');"><td>km/hr<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetSpeed('service'     ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetSpeed('service'     ,'+');">
+            <tr><td>@@HIGHWAY-TRACK@@:       <td><input name="speed-track"        type="text" size="3" onchange="formSetSpeed('track'       ,'=');"><td>km/hr<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetSpeed('track'       ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetSpeed('track'       ,'+');">
+            <tr><td>@@HIGHWAY-CYCLEWAY@@:    <td><input name="speed-cycleway"     type="text" size="3" onchange="formSetSpeed('cycleway'    ,'=');"><td>km/hr<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetSpeed('cycleway'    ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetSpeed('cycleway'    ,'+');">
+            <tr><td>@@HIGHWAY-PATH@@:        <td><input name="speed-path"         type="text" size="3" onchange="formSetSpeed('path'        ,'=');"><td>km/hr<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetSpeed('path'        ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetSpeed('path'        ,'+');">
+            <tr><td>@@HIGHWAY-STEPS@@:       <td><input name="speed-steps"        type="text" size="3" onchange="formSetSpeed('steps'       ,'=');"><td>km/hr<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetSpeed('steps'       ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetSpeed('steps'       ,'+');">
+            <tr><td>@@HIGHWAY-FERRY@@:       <td><input name="speed-ferry"        type="text" size="3" onchange="formSetSpeed('ferry'       ,'=');"><td>km/hr<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetSpeed('ferry'       ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetSpeed('ferry'       ,'+');">
+          </table>
+        </div>
+      </div>
+
+      <div class="hideshow_box">
+        <span id="hideshow_property_show" onclick="hideshow_show('property');" class="hideshow_show">+</span>
+        <span id="hideshow_property_hide" onclick="hideshow_hide('property');" class="hideshow_hide">-</span>
+        <span class="hideshow_title">@@PROPERTY-PREFERENCES-BOX@@</span>
+        <div id="hideshow_property_div" style="display: none;">
+          <table>
+            <tr><td>@@PROPERTY-PAVED@@:       <td><input name="property-paved"        type="text" size="3" onchange="formSetProperty('paved'       ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetProperty('paved'       ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetProperty('paved'       ,'+');">
+            <tr><td>@@PROPERTY-MULTILANE@@:   <td><input name="property-multilane"    type="text" size="3" onchange="formSetProperty('multilane'   ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetProperty('multilane'   ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetProperty('multilane'   ,'+');">
+            <tr><td>@@PROPERTY-BRIDGE@@:      <td><input name="property-bridge"       type="text" size="3" onchange="formSetProperty('bridge'      ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetProperty('bridge'      ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetProperty('bridge'      ,'+');">
+            <tr><td>@@PROPERTY-TUNNEL@@:      <td><input name="property-tunnel"       type="text" size="3" onchange="formSetProperty('tunnel'      ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetProperty('tunnel'      ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetProperty('tunnel'      ,'+');">
+            <tr><td>@@PROPERTY-WALKINGROUTE@@:<td><input name="property-footroute"    type="text" size="3" onchange="formSetProperty('footroute'   ,'=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetProperty('footroute'   ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetProperty('footroute'   ,'+');">
+            <tr><td>@@PROPERTY-BICYCLEROUTE@@:<td><input name="property-bicycleroute" type="text" size="3" onchange="formSetProperty('bicycleroute','=');"><td>%<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetProperty('bicycleroute','-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetProperty('bicycleroute','+');">
+          </table>
+        </div>
+      </div>
+
+      <div class="hideshow_box">
+        <span id="hideshow_restriction_show" onclick="hideshow_show('restriction');" class="hideshow_show">+</span>
+        <span id="hideshow_restriction_hide" onclick="hideshow_hide('restriction');" class="hideshow_hide">-</span>
+        <span class="hideshow_title">@@OTHER-RESTRICTIONS-BOX@@</span>
+        <div id="hideshow_restriction_div" style="display: none;">
+          <table>
+            <tr><td>@@RESTRICT-ONEWAY@@:<td><input name="restrict-oneway" type="checkbox" onchange="formSetRestriction('oneway');">
+            <tr><td>@@RESTRICT-TURNS@@: <td><input name="restrict-turns"  type="checkbox" onchange="formSetRestriction('turns' );">
+          </table>
+          <table>
+            <tr><td>@@RESTRICT-WEIGHT@@:<td><input name="restrict-weight" type="text" size="3" onchange="formSetRestriction('weight','=');"><td>tonnes<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetRestriction('weight','-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetRestriction('weight','+');">
+            <tr><td>@@RESTRICT-HEIGHT@@:<td><input name="restrict-height" type="text" size="3" onchange="formSetRestriction('height','=');"><td>metres<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetRestriction('height','-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetRestriction('height','+');">
+            <tr><td>@@RESTRICT-WIDTH@@: <td><input name="restrict-width"  type="text" size="3" onchange="formSetRestriction('width' ,'=');"><td>metres<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetRestriction('width' ,'-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetRestriction('width' ,'+');">
+            <tr><td>@@RESTRICT-LENGTH@@:<td><input name="restrict-length" type="text" size="3" onchange="formSetRestriction('length','=');"><td>metres<td><img alt="<" src="icons/waypoint-left.png" title="-" onmousedown="formSetRestriction('length','-');">–/+<img alt=">" src="icons/waypoint-right.png" title="+" onmousedown="formSetRestriction('length','+');">
+          </table>
+        </div>
+      </div>
+
+      <div class="hideshow_box">
+        <span class="hideshow_title">@@FIND-BOX@@</span>
+        <input type="button" title="@@FIND-SHORTEST-ROUTE@@" id="shortest" value="@@SHORTEST-ROUTE@@" onclick="findRoute('shortest');" disabled="disabled">
+        <input type="button" title="@@FIND-QUICKEST-ROUTE@@" id="quickest" value="@@QUICKEST-ROUTE@@" onclick="findRoute('quickest');" disabled="disabled">
+      </div>
+
+      <div class="hideshow_box">
+        <span class="hideshow_title">@@LINKS-BOX@@</span>
+        <a id="permalink_url" href="router.html">@@MAP-VIEW-LINK@@</a>
+        <br>
+        <a id="edit_url" target="edit" style="display: none;">@@EDIT-OSM-DATA@@</a>
+      </div>
+
+      <div class="hideshow_box">
+        <span id="hideshow_help_options_show" onclick="hideshow_show('help_options');" class="hideshow_hide">+</span>
+        <span id="hideshow_help_options_hide" onclick="hideshow_hide('help_options');" class="hideshow_show">-</span>
+        <span class="hideshow_title">@@HELP-BOX@@</span>
+        <div id="hideshow_help_options_div">
+          <div class="scrollable">
+            $$ROUTER-OPTIONS-HELP$$
+          </div>
+        </div>
+      </div>
+    </form>
+  </div>
+
+
+  <div class="tab_content" id="tab_results_div" style="display: none;">
+
+    <div class="hideshow_box">
+      <span class="hideshow_title">@@STATUS-BOX@@</span>
+      <div id="result_status">
+        <div id="result_status_not_run">
+          <b><i>@@ROUTER-NOT-RUN@@</i></b>
+        </div>
+        <div id="result_status_running"  style="display: none;">
+          <b>@@ROUTER-RUNNING@@</b>
+        </div>
+        <div id="result_status_complete" style="display: none;">
+          <b>@@ROUTER-COMPLETED@@</b>
+          <br>
+          <a id="router_log_complete" target="router_log" href="#">@@VIEW-DETAILS@@</a>
+        </div>
+        <div id="result_status_error"    style="display: none;">
+          <b>@@ROUTER-ERROR@@</b>
+          <br>
+          <a id="router_log_error" target="router_log" href="#">@@VIEW-DETAILS@@</a>
+        </div>
+        <div id="result_status_failed"   style="display: none;">
+          <b>@@ROUTER-FAILED@@</b>
+        </div>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_shortest_show" onclick="hideshow_show('shortest');" class="hideshow_show">+</span>
+      <span id="hideshow_shortest_hide" onclick="hideshow_hide('shortest');" class="hideshow_hide">-</span>
+      <span class="hideshow_title">@@SHORTEST-ROUTE@@</span>
+      <div id="shortest_status">
+        <div id="shortest_status_no_info">
+          <b><i>@@NO-INFORMATION@@</i></b>
+        </div>
+        <div id="shortest_status_info" style="display: none;">
+        </div>
+      </div>
+      <div id="hideshow_shortest_div" style="display: none;">
+        <div id="shortest_links" style="display: none;">
+          <table>
+            <tr><td>@@HTML-ROUTE@@:      <td><a id="shortest_html"      target="shortest_html"      href="#">@@OPEN-POPUP@@</a>
+            <tr><td>@@GPX-TRACK-ROUTE@@: <td><a id="shortest_gpx_track" target="shortest_gpx_track" href="#">@@OPEN-POPUP@@</a>
+            <tr><td>@@GPX-ROUTE@@:       <td><a id="shortest_gpx_route" target="shortest_gpx_route" href="#">@@OPEN-POPUP@@</a>
+            <tr><td>@@FULL-TEXT-ROUTE@@: <td><a id="shortest_text_all"  target="shortest_text_all"  href="#">@@OPEN-POPUP@@</a>
+            <tr><td>@@TEXT-ROUTE@@:      <td><a id="shortest_text"      target="shortest_text"      href="#">@@OPEN-POPUP@@</a>
+          </table>
+          <hr>
+        </div>
+        <div id="shortest_route">
+        </div>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_quickest_show" onclick="hideshow_show('quickest');" class="hideshow_show">+</span>
+      <span id="hideshow_quickest_hide" onclick="hideshow_hide('quickest');" class="hideshow_hide">-</span>
+      <span class="hideshow_title">@@QUICKEST-ROUTE@@</span>
+      <div id="quickest_status">
+        <div id="quickest_status_no_info">
+          <b><i>@@NO-INFORMATION@@</i></b>
+        </div>
+        <div id="quickest_status_info" style="display: none;">
+        </div>
+      </div>
+      <div id="hideshow_quickest_div" style="display: none;">
+        <div id="quickest_links" style="display: none;">
+          <table>
+            <tr><td>@@HTML-ROUTE@@:      <td><a id="quickest_html"      target="quickest_html"      href="#">@@OPEN-POPUP@@</a>
+            <tr><td>@@GPX-TRACK-ROUTE@@: <td><a id="quickest_gpx_track" target="quickest_gpx_track" href="#">@@OPEN-POPUP@@</a>
+            <tr><td>@@GPX-ROUTE@@:       <td><a id="quickest_gpx_route" target="quickest_gpx_route" href="#">@@OPEN-POPUP@@</a>
+            <tr><td>@@FULL-TEXT-ROUTE@@: <td><a id="quickest_text_all"  target="quickest_text_all"  href="#">@@OPEN-POPUP@@</a>
+            <tr><td>@@TEXT-ROUTE@@:      <td><a id="quickest_text"      target="quickest_text"      href="#">@@OPEN-POPUP@@</a>
+          </table>
+          <hr>
+        </div>
+        <div id="quickest_route">
+        </div>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_help_route_show" onclick="hideshow_show('help_route');" class="hideshow_hide">+</span>
+      <span id="hideshow_help_route_hide" onclick="hideshow_hide('help_route');" class="hideshow_show">-</span>
+      <span class="hideshow_title">@@HELP-BOX@@</span>
+      <div id="hideshow_help_route_div">
+        <div class="scrollable">
+          $$ROUTER-RESULTS-HELP$$
+        </div>
+      </div>
+    </div>
+  </div>
+
+
+  <div class="tab_content" id="tab_data_div" style="display: none;">
+    <div class="hideshow_box">
+      <span class="hideshow_title">@@STATISTICS-BOX@@</span>
+      <div id="statistics_data"></div>
+      <a id="statistics_link" href="statistics.cgi" onclick="displayStatistics();return(false);">@@DISPLAY-STATISTICS@@</a>
+    </div>
+
+    <div class="hideshow_box">
+      <span class="hideshow_title">@@VISUALISER-BOX@@</span>
+      $$ROUTER-VISUALISER-INFO$$
+      <br>
+      <a id="visualiser_url" href="visualiser.html" target="visualiser">@@MAP-VIEW-LINK@@</a>
+    </div>
+  </div>
+
+</div>
+
+<!-- Right hand side of window - map -->
+
+<div class="right_panel">
+  <div class="map" id="map">
+    <noscript>
+      <p>
+        @@JAVASCRIPT-REQUIRED@@
+    </noscript>
+  </div>
+  <div class="attribution">
+    @@ROUTER@@: <a href="http://www.routino.org/" target="routino">Routino</a>
+    |
+    @@GEO-DATA@@: <span id="attribution_data"></span>
+    |
+    @@TILES@@: <span id="attribution_tile"></span>
+  </div>
+</div>
+
+</body>
+
+</html>
diff --git a/3rdparty/Routino/web/translations/translate.pl b/3rdparty/Routino/web/translations/translate.pl
new file mode 100755
index 0000000..d579660
--- /dev/null
+++ b/3rdparty/Routino/web/translations/translate.pl
@@ -0,0 +1,404 @@
+#!/usr/bin/perl
+#
+# Routino translation replacement Perl script
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+
+# Constants
+
+my @translation_files=(<translation.*.txt>);
+my $xml_output_file="../../xml/routino-translations.xml";
+my $html_output_dir="../www/routino";
+
+my @html_template_files=(<*.html>);
+
+my %languages=();
+my %translations=();
+
+
+# Read in the translations
+
+foreach my $translation_file (@translation_files)
+  {
+   $translation_file =~ m%translation.([^.]+).txt%;
+
+   # Add to list of languages
+
+   my $language=$1;
+
+   if(! defined $languages{$language})
+     {
+      $languages{$language}=1;
+
+      $translations{$language}={};
+      $translations{$language}->{codes}={};
+      $translations{$language}->{html}=0;
+      $translations{$language}->{xml}=0;
+     }
+
+   # Process the file
+
+   open(FILE,"<$translation_file");
+
+   while(<FILE>)
+     {
+      s%\r*\n%%;
+
+      next if(m%^#%);
+      next if(m%^$%);
+
+      # Single line HTML entries
+
+      if(m%\@\@%)
+        {
+         my($code,$text)=split("\t");
+
+         if(defined $translations{$language}->{codes}->{$code})
+           {
+            print STDERR "Language: $language DUPLICATED codeword '$code'\n";
+           }
+         else
+           {
+            $translations{$language}->{html}++;
+            $translations{$language}->{codes}->{$code}={};
+            $translations{$language}->{codes}->{$code}->{text}=$text;
+            $translations{$language}->{codes}->{$code}->{usedX}=0;
+            $translations{$language}->{codes}->{$code}->{usedR}=0;
+            $translations{$language}->{codes}->{$code}->{usedV}=0;
+           }
+        }
+
+      # Multi-line HTML entries
+
+      if(m%(\$\$[^\$]+\$\$)%)
+        {
+         my($code,$text)=($1,"");
+
+         while(<FILE>)
+           {
+            last if(m%\$\$%);
+
+            $text=$text.$_;
+           }
+
+         $text =~ s%\r*\n$%%;
+
+         if(defined $translations{$language}->{codes}->{$code})
+           {
+            print STDERR "Language: $language DUPLICATED codeword '$code'\n";
+           }
+         else
+           {
+            $translations{$language}->{html}++;
+            $translations{$language}->{codes}->{$code}={};
+            $translations{$language}->{codes}->{$code}->{text}=$text;
+            $translations{$language}->{codes}->{$code}->{usedX}=0;
+            $translations{$language}->{codes}->{$code}->{usedR}=0;
+            $translations{$language}->{codes}->{$code}->{usedV}=0;
+           }
+        }
+
+      # Single line XML entries
+
+      if(m%\%\%%)
+        {
+         my($code,$text)=split("\t");
+
+         if(defined $translations{$language}->{codes}->{$code})
+           {
+            print STDERR "Language: $language DUPLICATED codeword '$code'\n";
+           }
+         else
+           {
+            $translations{$language}->{xml}++;
+            $translations{$language}->{codes}->{$code}={};
+            $translations{$language}->{codes}->{$code}->{text}=$text;
+            $translations{$language}->{codes}->{$code}->{usedX}=0;
+            $translations{$language}->{codes}->{$code}->{usedR}=0;
+            $translations{$language}->{codes}->{$code}->{usedV}=0;
+           }
+        }
+     }
+
+   close(FILE);
+  }
+
+
+# Sort out the languages
+
+my @languages=();
+
+push(@languages,"en");
+
+foreach my $language (sort (keys %languages))
+  {
+   push(@languages,$language) if($language ne "en");
+  }
+
+
+# Create the HTML files
+
+foreach my $html_template_file (@html_template_files)
+  {
+   my $usedtype="";
+
+   $usedtype="R" if($html_template_file =~ m%router%);
+   $usedtype="V" if($html_template_file =~ m%visualiser%);
+
+   foreach my $language (@languages)
+     {
+      next if(!$translations{$language}->{html});
+
+      print "Language: $language File: $html_template_file\n";
+
+      my $language_meta=0;
+      my $language_meta_string="";
+
+      open(HTML_IN ,"<$html_template_file");
+      open(HTML_OUT,">$html_output_dir/$html_template_file.$language");
+
+      while(<HTML_IN>)
+        {
+         my $line=$_;
+
+         # Language selection - special handling
+
+         if($line =~ m%\*\*LANGUAGES-META\*\*%)
+           {
+            $language_meta=1-$language_meta;
+
+            if($language_meta==0)
+              {
+               foreach my $language2 (@languages)
+                 {
+                  my $LANGUAGE2=$language2;
+                  $LANGUAGE2 =~ tr%a-z%A-Z%;
+
+                  $line=$language_meta_string;
+
+                  if($language eq $language2)
+                    {
+                     $line =~ s%~~CHECKED~~%checked%g;
+                    }
+                  else
+                    {
+                     $line =~ s%~~CHECKED~~%%g;
+                    }
+
+                  $line =~ s%~~lang~~%$language2%g;
+                  $line =~ s%~~LANG~~%$LANGUAGE2%g;
+
+                  if(!$translations{$language2}->{html})
+                    {
+                     $line =~ s%<a.+</a>%%;
+                    }
+
+                  if(!$translations{$language2}->{xml})
+                    {
+                     $line =~ s%<input .+>%%;
+                    }
+
+                  foreach my $code (keys %{$translations{$language2}->{codes}})
+                    {
+                     if($line =~ s%$code%$translations{$language2}->{codes}->{$code}->{text}%g)
+                       {$translations{$language2}->{codes}->{$code}->{"used$usedtype"} = 1;}
+                    }
+
+                  if($line =~ m%((\@\@|\$\$|\*\*|\~\~)[^\@\$*~]+(\@\@|\$\$|\*\*|\~\~))%)
+                    {
+                     print STDERR "   Unmatched codeword '$1' in line: $line";
+                    }
+
+                  # Remove un-needed spaces
+
+                  $line =~ s%[\t ]+% %g;
+                  $line =~ s%\n %\n%g;
+                  $line =~ s%^ %%g;
+
+                  print HTML_OUT $line;
+                 }
+              }
+
+            next;
+           }
+
+         if($language_meta)
+           {
+            $language_meta_string.=$line;
+            next;
+           }
+
+         # Replace with translated phrases
+
+         foreach my $code (keys %{$translations{$language}->{codes}})
+           {
+            if($line =~ s%\Q$code\E%$translations{$language}->{codes}->{$code}->{text}%g)
+              {$translations{$language}->{codes}->{$code}->{"used$usedtype"} = 1;}
+           }
+
+         # Replace what is left with English phrases
+
+         foreach my $code (keys %{$translations{$languages[0]}->{codes}})
+           {
+            $line =~ s%\Q$code\E%$translations{$languages[0]}->{codes}->{$code}->{text}%g;
+           }
+
+         if($line =~ m%((\@\@|\$\$|\*\*|\~\~)[^\@\$*~]+(\@\@|\$\$|\*\*|\~\~))%)
+           {
+            print STDERR "   Unmatched codeword '$1' in line: $line";
+           }
+
+         # Remove un-needed spaces
+
+         $line =~ s%[\t ]+% %g;
+         $line =~ s%\n %\n%g;
+         $line =~ s%^ %%g;
+
+         print HTML_OUT $line;
+        }
+
+      close(HTML_IN);
+      close(HTML_OUT);
+     }
+  }
+
+
+# Create the XML file
+
+open(XML_OUT,">$xml_output_file");
+
+open(XML_IN ,"<translations-head.xml");
+
+while(<XML_IN>)
+  {
+   print XML_OUT;
+  }
+
+close(XML_IN);
+
+foreach my $language (@languages)
+  {
+   next if(!$translations{$language}->{xml});
+
+   print "Language: $language File: translations.xml\n";
+
+   open(XML_IN ,"<translations-body.xml");
+
+   while(<XML_IN>)
+     {
+      my $line=$_;
+
+      $line =~ s%~~lang~~%$language%g;
+
+      # Replace with translated phrases
+
+      foreach my $code (keys %{$translations{$language}->{codes}})
+        {
+         if($line =~ s%$code%$translations{$language}->{codes}->{$code}->{text}%g)
+           {$translations{$language}->{codes}->{$code}->{usedX} = 1;}
+        }
+
+      # Replace what is left with a note about missing translations
+
+      if($line =~ m%\%\%%)
+        {
+         foreach my $code (keys %{$translations{$languages[0]}->{codes}})
+           {
+            $line =~ s%$code%$translations{$languages[0]}->{codes}->{$code}->{text}%g;
+           }
+
+         $line =~ s%<%<!-- TRANSLATION REQUIRED: %;
+         $line =~ s%>% -->%;
+
+         if($line =~ m%((\%\%|\~\~)[^\%~]+(\%\%|\~\~))%)
+           {
+            print STDERR "   Unmatched codeword '$1' in line: $line";
+           }
+        }
+
+      print XML_OUT $line;
+     }
+
+   close(XML_IN);
+  }
+
+open(XML_IN ,"<translations-tail.xml");
+
+while(<XML_IN>)
+  {
+   print XML_OUT;
+  }
+
+close(XML_IN);
+
+close(XML_OUT);
+
+
+# Check the languages and usage
+
+my %usedX=();
+my %usedR=();
+my %usedV=();
+
+foreach my $language (@languages)
+  {
+   $usedX{$language}=0;
+   $usedR{$language}=0;
+   $usedV{$language}=0;
+
+   foreach my $code (keys %{$translations{$language}->{codes}})
+     {
+      $usedX{$language}+=$translations{$language}->{codes}->{$code}->{usedX};
+      $usedR{$language}+=$translations{$language}->{codes}->{$code}->{usedR};
+      $usedV{$language}+=$translations{$language}->{codes}->{$code}->{usedV};
+
+      if(! $translations{$language}->{codes}->{$code}->{usedX} &&
+         ! $translations{$language}->{codes}->{$code}->{usedR} &&
+         ! $translations{$language}->{codes}->{$code}->{usedV})
+        {
+         print STDERR "Language: $language UNUSED codeword: $code\n";
+        }
+     }
+  }
+
+
+# Print the translation coverage
+
+print "\n";
+
+print "Translation Coverage\n";
+print "====================\n";
+
+print "\n";
+print "           Number      Percentage Complete\n";
+print "Language  XML HTML    XML router visualiser\n";
+print "--------  --- ----    --- ------ ----------\n";
+
+foreach my $language (@languages)
+  {
+   printf("%-6s    %3d  %3d  %4.0f%%  %4.0f%%  %4.0f%%\n",
+          $language,
+          $translations{$language}->{xml},
+          $translations{$language}->{html},
+          100.0*$usedX{$language}/$usedX{$languages[0]},
+          100.0*$usedR{$language}/$usedR{$languages[0]},
+          100.0*$usedV{$language}/$usedV{$languages[0]})
+  }
diff --git a/3rdparty/Routino/web/translations/translation.de.txt b/3rdparty/Routino/web/translations/translation.de.txt
new file mode 100644
index 0000000..daaca83
--- /dev/null
+++ b/3rdparty/Routino/web/translations/translation.de.txt
@@ -0,0 +1,359 @@
+#
+# German language translation phrases
+#
+
+#
+# Router output XML definition
+#
+
+%%copyright_creator_string%%	Urheber
+%%copyright_source_string%%	Quelle
+%%copyright_source_text%%	Basierend auf OpenStreetMap-Daten, erhältlich via http://www.openstreetmap.org/
+%%copyright_license_string%%	Lizenz
+
+%%turn_-4%%	Sehr scharf links
+%%turn_-3%%	Scharf links
+%%turn_-2%%	Links
+%%turn_-1%%	Halb links
+%%turn_0%%	Geradeaus
+%%turn_1%%	Halb rechts
+%%turn_2%%	Rechts
+%%turn_3%%	Scharf rechts
+%%turn_4%%	Sehr scharf rechts
+
+%%heading_-4%%	Süd
+%%heading_-3%%	Süd-West
+%%heading_-2%%	West
+%%heading_-1%%	Nord-West
+%%heading_0%%	Nord
+%%heading_1%%	Nord-Ost
+%%heading_2%%	Ost
+%%heading_3%%	Süd-Ost
+%%heading_4%%	Süd
+
+%%ordinal_1%%	Erste
+%%ordinal_2%%	Zweite
+%%ordinal_3%%	Dritte
+%%ordinal_4%%	Vierte
+%%ordinal_5%%	Fünfte
+%%ordinal_6%%	Sechste
+%%ordinal_7%%	Siebte
+%%ordinal_8%%	Achte
+%%ordinal_9%%	Neunte
+%%ordinal_10%%	Zehnte
+
+%%highway_motorway%%	Autobahn
+%%highway_trunk%%	Schnellstraße
+%%highway_primary%%	Bundesstraße
+%%highway_secondary%%	Landesstraße
+%%highway_tertiary%%	Kreisstraße
+%%highway_unclassified%%	Nebenstraße
+%%highway_residential%%	Wohngebietsstraße
+%%highway_service%%	Erschließungsweg
+%%highway_track%%	Feld-/Waldweg
+%%highway_cycleway%%	Radweg
+%%highway_path%%	Weg/Pfad
+%%highway_steps%%	Treppe
+%%highway_ferry%%	Fähre
+
+%%route_shortest%%	Kürzeste
+%%route_quickest%%	Schnellste
+
+%%output-html_waypoint_waypoint%%	Wegpunkt
+%%output-html_waypoint_junction%%	Anschlussstelle
+%%output-html_waypoint_roundabout%%	Kreisverkehr
+%%output-html_title%%	%s Route
+%%output-html_start_string%%	Start
+%%output-html_start_text%%	Bei %s halten Sie sich Richtung %s
+%%output-html_node_string%%	Bei
+%%output-html_node_text%%	Bei %s wenden Sie sich nach %s Richtung %s
+%%output-html_rbnode_string%%	Verlassen Sie
+%%output-html_rbnode_text%%	%s, nehmen Sie die %s Ausfahrt Richtung %s
+%%output-html_segment_string%%	Folgen
+%%output-html_segment_text%%	Folgen Sie der %s für %.3f km bzw. %.1f min
+%%output-html_stop_string%%	Stop
+%%output-html_stop_text%%	Sie sind bei %s angekommen
+%%output-html_total_string%%	Gesamt
+%%output-html_total_text%%	%.1f km, %.0f minuten
+
+%%output-gpx_waypoint_start%%	START
+%%output-gpx_waypoint_inter%%	INTER
+%%output-gpx_waypoint_trip%%	TRIP
+%%output-gpx_waypoint_finish%%	FINISH
+
+%%output-gpx_desc%%	%s Strecke zwischen 'Start' und 'Ziel'
+%%output-gpx_name%%	%s Strecke
+%%output-gpx_step%%	%s auf '%s' für %.3f km, %.1f min
+%%output-gpx_final%%	Gesamtstrecke %.1f km, %.0f minuten
+
+#
+# Router (and some shared) translations
+#
+
+@@LANGUAGE@@	Deutsch
+@@LANGUAGE-WEBPAGE@@	Deutsche Webseite
+
+@@ROUTER-TITLE@@	Routen Planer für OpenStreetMap Daten
+
+@@OPTION-TAB@@	Optionen
+@@OPTION-TAB-HELP@@	Setze Routing-Optionen
+
+@@RESULTS-TAB@@	Ergebnisse
+@@RESULTS-TAB-HELP@@	Sieh die Ergebnisse
+
+@@DATA-TAB@@	Daten
+@@DATA-TAB-HELP@@	Sieh die Datenbankinformationen
+
+@@ROUTINO-ROUTER@@	Routino OpenStreetMap Router
+@@ROUTINO-WEBSITE@@	Routino Website
+@@DOCUMENTATION@@	Dokumentation
+
+@@LANGUAGE-BOX@@	Sprache
+@@WAYPOINTS-BOX@@	Wegpunkte
+@@TRANSPORT-TYPE-BOX@@	Fortbewegungsart
+@@HIGHWAY-PREFERENCES-BOX@@	Vorgaben zur Wegnutzung
+@@SPEED-LIMITS-BOX@@	Geschwindigkeitsvorgaben
+@@PROPERTY-PREFERENCES-BOX@@	Vorgaben zur Wegbeschaffenheit
+@@OTHER-RESTRICTIONS-BOX@@	andere Vorgaben
+@@FIND-BOX@@	Suche
+@@LINKS-BOX@@	Links
+@@HELP-BOX@@	Hilfe
+
+@@STATUS-BOX@@	Status
+@@SHORTEST-ROUTE@@	kürzester Weg
+@@QUICKEST-ROUTE@@	schnellste Route
+
+@@STATISTICS-BOX@@	Routino Statistik
+@@VISUALISER-BOX@@	Routino Ansichten
+
+@@WAYPOINT-POSITION@@	Wegpunkt XXX Position
+@@WAYPOINT-LONGITUDE@@	Wegpunkt XXX geografische Länge
+@@WAYPOINT-LATITUDE@@	Wegpunkt XXX geografische Breite
+@@WAYPOINT-LOCATION@@	Wegpunkt XXX Ort
+@@WAYPOINT-SEARCH@@	Nach Ort suchen
+@@WAYPOINT-GET@@	Aktuellen Ort bestimmen
+@@WAYPOINT-CENTRE1@@	Karte auf Wegpunkt zentrieren
+@@WAYPOINT-UP@@	wegpunkt nach oben verschieben
+@@WAYPOINT-ADD@@	Neuer Wegpunkt nach diesem
+@@WAYPOINT-COORDS@@	Koordinaten des Orts
+@@WAYPOINT-HOME@@	Umschalten auf den Standort des Zuhauses
+@@WAYPOINT-CENTRE2@@	Wegpunkt auf Karte zentrieren
+@@WAYPOINT-DOWN@@	Wegpunkt nach unten verschieben
+@@WAYPOINT-REMOVE@@	Wegpunkt entfernen
+@@WAYPOINT-REVERSE@@	Rückwärts
+@@WAYPOINT-REVERSE-BUTTON@@	Rückwärts
+@@WAYPOINT-LOOP@@	Einen Wegpunkt hinzufügen um eine Schlaufe zu machen
+@@WAYPOINT-LOOP-BUTTON@@	Schleife schließen
+
+@@TRANSPORT-FOOT@@	Fußgänger
+@@TRANSPORT-HORSE@@	Reiter
+@@TRANSPORT-WHEELCHAIR@@	Rollstuhl
+@@TRANSPORT-BICYCLE@@	Fahrrad
+@@TRANSPORT-MOPED@@	Moped
+@@TRANSPORT-MOTORCYCLE@@	Motorrad
+@@TRANSPORT-MOTORCAR@@	Auto
+@@TRANSPORT-GOODS@@	LKW
+@@TRANSPORT-HGV@@	Schwertransport/LKW
+@@TRANSPORT-PSV@@	Öffentlicher Personenverkehr
+
+@@HIGHWAY-MOTORWAY@@	Autobahn
+@@HIGHWAY-TRUNK@@	Schnellstraße
+@@HIGHWAY-PRIMARY@@	Bundesstraße
+@@HIGHWAY-SECONDARY@@	Landesstraße
+@@HIGHWAY-TERTIARY@@	Hauptstraße
+@@HIGHWAY-UNCLASSIFIED@@	Straße
+@@HIGHWAY-RESIDENTIAL@@	Wohnstraße
+@@HIGHWAY-SERVICE@@	Zufahrtsweg
+@@HIGHWAY-TRACK@@	Feld-(Wald-)weg
+@@HIGHWAY-CYCLEWAY@@	Fahrradweg
+@@HIGHWAY-PATH@@	Weg
+@@HIGHWAY-STEPS@@	Fußweg
+@@HIGHWAY-FERRY@@	Fähre
+
+@@PROPERTY-PAVED@@	befestigt
+@@PROPERTY-MULTILANE@@	mehrspurig
+@@PROPERTY-BRIDGE@@	Brücken
+@@PROPERTY-TUNNEL@@	Tunnel
+@@PROPERTY-WALKINGROUTE@@	Wanderweg
+@@PROPERTY-BICYCLEROUTE@@	Radweg
+
+@@RESTRICT-ONEWAY@@	beachte Einbahnstraßen
+@@RESTRICT-TURNS@@	beachte Abbiegeverbot
+@@RESTRICT-WEIGHT@@	Gewicht
+@@RESTRICT-HEIGHT@@	Höhe
+@@RESTRICT-WIDTH@@	Breite
+@@RESTRICT-LENGTH@@	Länge
+
+@@FIND-SHORTEST-ROUTE@@	Kürzeste Route finden
+@@FIND-QUICKEST-ROUTE@@	Schnellste Route finden
+
+@@MAP-VIEW-LINK@@	anpassen dieser Kartenansicht
+@@EDIT-OSM-DATA@@	Bearbeitet die OSM-Daten
+
+@@ROUTER-NOT-RUN@@	Router läuft nicht
+@@ROUTER-RUNNING@@	Router läuft...
+@@ROUTER-COMPLETED@@	Routing fertig
+@@ROUTER-ERROR@@	Router Fehler
+@@ROUTER-FAILED@@	Router funktioniert nicht
+@@VIEW-DETAILS@@	zeige Details
+
+@@NO-INFORMATION@@	keine Information
+@@HTML-ROUTE@@	HTML
+@@GPX-TRACK-ROUTE@@	GPX Track-Datei
+@@GPX-ROUTE@@	GPX Routen-Datei
+@@FULL-TEXT-ROUTE@@	Volltext-Datei
+@@TEXT-ROUTE@@	Text-Datei
+@@OPEN-POPUP@@	öffne Popup
+
+@@DISPLAY-STATISTICS@@	zeige die Statistik
+
+@@JAVASCRIPT-REQUIRED@@	Um die interaktive Karte zu nutzen iWork Javascript benötigt. 
+@@ROUTER@@	Router
+@@GEO-DATA@@	Geodaten
+@@TILES@@	Kacheln
+
+#
+# Visualiser specific translations
+#
+
+@@VISUALISER-TITLE@@	Visualisierung der Routing-Daten
+
+@@INSTRUCTIONS-BOX@@	Anweisungen
+@@ROUTER-BOX@@	Routino Router
+
+@@NO-DATA-DISPLAYED@@	Keine Daten angezeigt
+
+@@VISUALISER-FAILED@@	Fehler bei der Erstellung der visuellen Daten!
+@@VISUALISER-NUM-JUNCTIONS@@	# Kreuzungen verarbeitet
+@@VISUALISER-NUM-SUPER@@	# Super-Knoten/Segmente verarbeitet
+@@VISUALISER-NUM-WAYTYPE@@	# Wegtypen Segmente verarbeitet
+@@VISUALISER-NUM-SEGMENTS@@	# Segmente verarbeitet
+@@VISUALISER-NUM-NODES@@	# Knoten verarbeitet
+@@VISUALISER-NUM-TURNS@@	# Abbiegebeschrängkungen verarbeitet
+@@VISUALISER-NUM-LIMITS@@	# Limit-Änderungen verarbeitet
+@@VISUALISER-NUM-ERRORS@@	# Error Logs erstellt
+
+@@JUNCTIONS-BUTTON@@	Kreuzungen anzeigen
+@@JUNCTIONS-2@@	Aufeinandertreffen zweier Wege unterschiedlichen Typs.
+@@JUNCTIONS-3@@	Aufeinandertreffen von drei Wegen.
+@@JUNCTIONS-4@@	Aufeinandertreffen von vier Wegen.
+@@JUNCTIONS-5@@	Aufeinandertreffen von fünf Wegen.
+@@JUNCTIONS-6@@	Aufeinandertreffen von sechs Wegen.
+@@JUNCTIONS-MORE@@	Aufeinandertreffen von sieben oder mehr Wegen.
+
+@@SUPER-BUTTON@@	Super-Segments anzeigen
+
+@@TURNS-BUTTON@@	Zeige Abbiegebeschränkungen
+
+@@SPEED-BUTTON@@	Zeige Geschwindigkeitsbeschränkungen
+
+@@SPEED-LIMIT-80@@	80 km/Stunde Geschwindigkeitsbegrenzung
+
+@@WEIGHT-BUTTON@@	Gewichtswegbeschränkungen anzeigen
+
+@@WEIGHT-LIMIT-8@@	8 Tonnen Wegbeschränkung
+
+@@HEIGHT-BUTTON@@	Maximale Höhe anzeigen 
+
+@@HEIGHT-LIMIT-4@@	4.0 m Höhenbeschränkung
+
+@@WIDTH-BUTTON@@	Maximale Breite anzeigen
+
+@@CLEAR-DATA-BUTTON@@	Daten zurücksetzen
+
+#
+# Multi-line descriptive translations (router)
+#
+
+$$ROUTER-INFO$$
+Diese Website erlaubt Routing mit den Daten, die OpenStreetMap gesammelt hat.
+Wähle Start- und Endpunkt (klicke auf die Marker-Symbole unten), wähle die Routing-Vorgaben und dann finde den Weg.
+$$ROUTER-INFO$$
+
+$$ROUTER-OPTIONS-HELP$$
+<b>Schnellanleitung</b>
+<br>
+Klicke auf die Marker-Bildchen (oben), um sie in der Mitte der Karte (rechts) zu positionieren. Dann
+ziehe das Bildchen auf die genaue Position. Das Zoomen der Karte vor der Patzierung ist vermutlich am einfachsten.
+Alternativ kann man die geografische Breite und Länge in den Kästchen eintragen.
+<p>
+Wähle die Fortbewegungsart, die Vorgaben zur Wegnutzung, die Geschwindigkeitsvorgaben,
+die Vorgaben zur Wegbeschaffenheit und die anderen Vorgaben von den obigen Auswahlfeldern.
+Ein Klick auf "kürzeste" oder "schnellste" ermittelt die entsprechende Verbindung und zeigt sie in der Karte an.
+<p>
+<b>Wegpunkte</b>
+<br>
+Ein Klick auf das Marker-Bildchen (oben) schaltet die Sichbarkeit in der Karte ein bzw. aus.
+Die Berechnung Route erfolgt in der Reihenfolge der Wegpunkte (so gut, wie es für die
+gewählte Fortbewegungsart möglich ist).
+<p>
+<b>Fortbewegungsart</b>
+<br>
+Die Auswahl der Fortbewegungsart bestimmt die bei der Routenberechnung erlaubten Wegtypen und die
+Vorgabeeinstellungen aller anderen Parameter.
+<p>
+<b>Vorgaben zur Wegnutzung</b>
+<br>
+Die Vorgaben zur Wegnutzung bestimmen die Priorisierung von Wegarten.
+Wenn z. B. Schnellstraßen mit 110% und Bundesstraßen mit 100% angegeben werden, wird
+bei zwei möglichen Wegwahlen die Schnellstraße solange bevorzugt wird, wie der
+Längen(oder Zeit-)unterschied 10% nicht überschreitet.
+<p>
+<b>Geschwindigkeitsvorgaben</b>
+<br>
+Die hier geannten Geschwindigkeiten werden für den jeweiligen Wegtyp finden Anwendung wenn keine
+andere Geschwindkeitsbegrenzung mit geringerem Wert bekannt ist.
+<p>
+<b>Vorgaben zur Wegbeschaffenheit</b>
+<br>
+Die Vorgaben zur Wegbeschaffenheit werden als Prozentangaben verwendet, um die Verhältnisse
+der Wegbenutzung zu steuern.
+Wenn z. B. befestigte Wege mit 75% angegeben sind, werden unbefestigte automatisch mit 25% angenommen, so
+werden Wege ausgewählt, die mindestens drei mal länger auf befestigten Wegen verlaufen.
+<p>
+<b>andere Vorgaben</b>
+<br>
+Die Berücksichtigung von Benutzungs-Begrenzungen durch Gewicht, Höhe, Länge und
+Breite ist möglich. Genauso können Einbahnstraßenbeschräkungen ignoriert werden
+(z. B. als Fußgänger).
+$$ROUTER-OPTIONS-HELP$$
+
+$$ROUTER-RESULTS-HELP$$
+<b>Schnellanleitung</b>
+<br>
+Nach der Routenberechnung kann man eine GPX oder eine einfache Textdatei (Kurz- oder Langfassung)
+herunterladen. Ebenso kann man die Routenbeschreibung ansehen und in ausgewälte Bereiche zoomen.
+<p>
+<b>Problemlösung</b>
+<br>
+Wenn der Router einen Fehler meldet liegt es meistens daran, dass kein Weg zwischen den gewälten Punkten unter
+Beachtung der Vorgaben gefunden werden kann. Das Bewegen eines oder mehrere Punkte oder das verändern von
+Vorgaben sollte es erlauben eine Route zu finden.
+<p>
+<b>Ausgabe-Formate</b>
+<br>
+<dl>
+  <dt>HTMLs
+  <dd>Eine Beschreibung der Route mit Anweisungen für jede wichtige Abzweigung.
+  <dt>GPX Track-Datei
+  <dd>Die gleichen Informationen, die in der Karte angezeigt werden mit Punkten für jeden Abzweig
+  und Linien für jedes Teilstück.
+  <dt>GPX Routen-Datei
+  <dd>Die gleichen Informationen, die im Text angezeigt werden mit einem Wegpunkt für
+  jede wichtige Richtungsänderung.
+  <dt>Volltext-Datei
+  <dd>Eine aller Knoten und die Abstände zwischen ihnen, sowie die Gesamtentfernung vom i
+      Startpunkt zum jeweiligen Konten.
+  <dt>Text-Datei
+  <dd>Die gleiche Information, die als Text angezeigt wird.
+</dl>
+$$ROUTER-RESULTS-HELP$$
+
+$$ROUTER-VISUALISER-INFO$$
+Die Anzeige der Daten kann auf verschiedene Weise angepasst werden.
+$$ROUTER-VISUALISER-INFO$$
+
+#
+# Multi-line descriptive translations (visualiser)
+#
+
diff --git a/3rdparty/Routino/web/translations/translation.en.txt b/3rdparty/Routino/web/translations/translation.en.txt
new file mode 100644
index 0000000..69cc274
--- /dev/null
+++ b/3rdparty/Routino/web/translations/translation.en.txt
@@ -0,0 +1,477 @@
+#
+# English language translation phrases
+#
+
+#
+# Router output XML definition
+#
+
+%%copyright_creator_string%%	Creator
+%%copyright_source_string%%	Source
+%%copyright_source_text%%	Based on OpenStreetMap data from http://www.openstreetmap.org/
+%%copyright_license_string%%	License
+
+%%turn_-4%%	Very sharp left
+%%turn_-3%%	Sharp left
+%%turn_-2%%	Left
+%%turn_-1%%	Slight left
+%%turn_0%%	Straight on
+%%turn_1%%	Slight right
+%%turn_2%%	Right
+%%turn_3%%	Sharp right
+%%turn_4%%	Very sharp right
+
+%%heading_-4%%	South
+%%heading_-3%%	South-West
+%%heading_-2%%	West
+%%heading_-1%%	North-West
+%%heading_0%%	North
+%%heading_1%%	North-East
+%%heading_2%%	East
+%%heading_3%%	South-East
+%%heading_4%%	South
+
+%%ordinal_1%%	First
+%%ordinal_2%%	Second
+%%ordinal_3%%	Third
+%%ordinal_4%%	Fourth
+%%ordinal_5%%	Fifth
+%%ordinal_6%%	Sixth
+%%ordinal_7%%	Seventh
+%%ordinal_8%%	Eighth
+%%ordinal_9%%	Ninth
+%%ordinal_10%%	Tenth
+
+%%highway_motorway%%	motorway
+%%highway_trunk%%	trunk road
+%%highway_primary%%	primary road
+%%highway_secondary%%	secondary road
+%%highway_tertiary%%	tertiary road
+%%highway_unclassified%%	unclassified road
+%%highway_residential%%	residential road
+%%highway_service%%	service road
+%%highway_track%%	track
+%%highway_cycleway%%	cycleway
+%%highway_path%%	path
+%%highway_steps%%	steps
+%%highway_ferry%%	ferry
+
+%%route_shortest%%	Shortest
+%%route_quickest%%	Quickest
+
+%%output-html_waypoint_waypoint%%	Waypoint
+%%output-html_waypoint_junction%%	Junction
+%%output-html_waypoint_roundabout%%	Roundabout
+%%output-html_title%%	%s Route
+%%output-html_start_string%%	Start
+%%output-html_start_text%%	At %s, head %s
+%%output-html_node_string%%	At
+%%output-html_node_text%%	%s, go %s heading %s
+%%output-html_rbnode_string%%	Leave
+%%output-html_rbnode_text%%	%s, take the %s exit heading %s
+%%output-html_segment_string%%	Follow
+%%output-html_segment_text%%	%s for %.3f km, %.1f min
+%%output-html_stop_string%%	Stop
+%%output-html_stop_text%%	At %s
+%%output-html_total_string%%	Total
+%%output-html_total_text%%	%.1f km, %.0f minutes
+
+%%output-gpx_waypoint_start%%	START
+%%output-gpx_waypoint_inter%%	INTER
+%%output-gpx_waypoint_trip%%	TRIP
+%%output-gpx_waypoint_finish%%	FINISH
+
+%%output-gpx_desc%%	%s route between 'start' and 'finish' waypoints
+%%output-gpx_name%%	%s route
+%%output-gpx_step%%	%s on '%s' for %.3f km, %.1f min
+%%output-gpx_final%%	Total Journey %.1f km, %.0f minutes
+
+#
+# Router (and some shared) translations
+#
+
+@@LANGUAGE@@	English
+@@LANGUAGE-WEBPAGE@@	English language webpage
+
+@@ROUTER-TITLE@@	Route Planner for OpenStreetMap Data
+
+@@OPTION-TAB@@	Options
+@@OPTION-TAB-HELP@@	Set routing options
+
+@@RESULTS-TAB@@	Results
+@@RESULTS-TAB-HELP@@	See routing results
+
+@@DATA-TAB@@	Data
+@@DATA-TAB-HELP@@	View database information
+
+@@ROUTINO-ROUTER@@	Routino OpenStreetMap Router
+@@ROUTINO-WEBSITE@@	Routino Website
+@@DOCUMENTATION@@	Documentation
+
+@@LANGUAGE-BOX@@	Language
+@@WAYPOINTS-BOX@@	Waypoints
+@@TRANSPORT-TYPE-BOX@@	Transport Type
+@@HIGHWAY-PREFERENCES-BOX@@	Highway Preferences
+@@SPEED-LIMITS-BOX@@	Speed Limits
+@@PROPERTY-PREFERENCES-BOX@@	Property Preferences
+@@OTHER-RESTRICTIONS-BOX@@	Other Restrictions
+@@FIND-BOX@@	Find
+@@LINKS-BOX@@	Links
+@@HELP-BOX@@	Help
+
+@@STATUS-BOX@@	Status
+@@SHORTEST-ROUTE@@	Shortest Route
+@@QUICKEST-ROUTE@@	Quickest Route
+
+@@STATISTICS-BOX@@	Routino Statistics
+@@VISUALISER-BOX@@	Routino Visualiser
+
+@@WAYPOINT-POSITION@@	Waypoint XXX Position
+@@WAYPOINT-LONGITUDE@@	Waypoint XXX Longitude
+@@WAYPOINT-LATITUDE@@	Waypoint XXX Latitude
+@@WAYPOINT-LOCATION@@	Waypoint XXX Location
+@@WAYPOINT-SEARCH@@	Search for location
+@@WAYPOINT-GET@@	Get current location
+@@WAYPOINT-CENTRE1@@	Centre map on this waypoint
+@@WAYPOINT-UP@@	Move this waypoint up
+@@WAYPOINT-ADD@@	Add waypoint after this one
+@@WAYPOINT-COORDS@@	Coordinates for location
+@@WAYPOINT-HOME@@	Toggle as home location
+@@WAYPOINT-CENTRE2@@	Centre this waypoint on map
+@@WAYPOINT-DOWN@@	Move this waypoint down
+@@WAYPOINT-REMOVE@@	Remove this waypoint
+@@WAYPOINT-REVERSE@@	Reverse order of waypoints
+@@WAYPOINT-REVERSE-BUTTON@@	Reverse order
+@@WAYPOINT-LOOP@@	Add a new waypoint to make a loop
+@@WAYPOINT-LOOP-BUTTON@@	Close loop
+
+@@TRANSPORT-FOOT@@	Foot
+@@TRANSPORT-HORSE@@	Horse
+@@TRANSPORT-WHEELCHAIR@@	Wheelchair
+@@TRANSPORT-BICYCLE@@	Bicycle
+@@TRANSPORT-MOPED@@	Moped
+@@TRANSPORT-MOTORCYCLE@@	Motorcycle
+@@TRANSPORT-MOTORCAR@@	Motorcar
+@@TRANSPORT-GOODS@@	Goods
+@@TRANSPORT-HGV@@	HGV
+@@TRANSPORT-PSV@@	PSV
+
+@@HIGHWAY-MOTORWAY@@	Motorway
+@@HIGHWAY-TRUNK@@	Trunk
+@@HIGHWAY-PRIMARY@@	Primary
+@@HIGHWAY-SECONDARY@@	Secondary
+@@HIGHWAY-TERTIARY@@	Tertiary
+@@HIGHWAY-UNCLASSIFIED@@	Unclassified
+@@HIGHWAY-RESIDENTIAL@@	Residential
+@@HIGHWAY-SERVICE@@	Service
+@@HIGHWAY-TRACK@@	Track
+@@HIGHWAY-CYCLEWAY@@	Cycleway
+@@HIGHWAY-PATH@@	Path
+@@HIGHWAY-STEPS@@	Steps
+@@HIGHWAY-FERRY@@	Ferry
+
+@@PROPERTY-PAVED@@	Paved
+@@PROPERTY-MULTILANE@@	Multiple Lanes
+@@PROPERTY-BRIDGE@@	Bridge
+@@PROPERTY-TUNNEL@@	Tunnel
+@@PROPERTY-WALKINGROUTE@@	Walking Route
+@@PROPERTY-BICYCLEROUTE@@	Bicycle Route
+
+@@RESTRICT-ONEWAY@@	Obey oneway streets
+@@RESTRICT-TURNS@@	Obey turn restrictions
+@@RESTRICT-WEIGHT@@	Weight
+@@RESTRICT-HEIGHT@@	Height
+@@RESTRICT-WIDTH@@	Width
+@@RESTRICT-LENGTH@@	Length
+
+@@FIND-SHORTEST-ROUTE@@	Find shortest route
+@@FIND-QUICKEST-ROUTE@@	Find quickest route
+
+@@MAP-VIEW-LINK@@	Link to this map view
+@@EDIT-OSM-DATA@@	Edit this OSM data
+
+@@ROUTER-NOT-RUN@@	Router not run
+@@ROUTER-RUNNING@@	Router running...
+@@ROUTER-COMPLETED@@	Routing completed
+@@ROUTER-ERROR@@	Router error
+@@ROUTER-FAILED@@	Router failed to run
+@@VIEW-DETAILS@@	View Details
+
+@@NO-INFORMATION@@	No Information
+@@HTML-ROUTE@@	HTML directions
+@@GPX-TRACK-ROUTE@@	GPX track file
+@@GPX-ROUTE@@	GPX route file
+@@FULL-TEXT-ROUTE@@	Full text file
+@@TEXT-ROUTE@@	Text file
+@@OPEN-POPUP@@	Open Popup
+
+@@DISPLAY-STATISTICS@@	Display data statistics
+
+@@JAVASCRIPT-REQUIRED@@	Javascript is <em>required</em> to use this web page because of the interactive map.
+@@ROUTER@@	Router
+@@GEO-DATA@@	Geo Data
+@@TILES@@	Tiles
+
+#
+# Visualiser specific translations
+#
+
+@@VISUALISER-TITLE@@	Data Visualiser for Routing Data
+
+@@INSTRUCTIONS-BOX@@	Instructions
+@@ROUTER-BOX@@	Routino Router
+
+@@NO-DATA-DISPLAYED@@	No data displayed
+
+@@VISUALISER-FAILED@@	Failed to get visualiser data!
+@@VISUALISER-NUM-JUNCTIONS@@	Processed # junctions
+@@VISUALISER-NUM-SUPER@@	Processed # super-nodes/segments
+@@VISUALISER-NUM-WAYTYPE@@	Processed # way type segments
+@@VISUALISER-NUM-SEGMENTS@@	Processed # segments
+@@VISUALISER-NUM-NODES@@	Processed # nodes
+@@VISUALISER-NUM-TURNS@@	Processed # turn restrictions
+@@VISUALISER-NUM-LIMITS@@	Processed # limit changes
+@@VISUALISER-NUM-ERRORS@@	Processed # error logs
+
+@@JUNCTIONS-BUTTON@@	Display Junctions
+$$JUNCTIONS-INFO$$
+Each node that is a dead-end, a junction of two highways of different
+types (or different properties) or a junction where more than two segments
+join are shown colour-coded.
+$$JUNCTIONS-INFO$$
+@@JUNCTIONS-1@@	only one highway - a dead-end.
+@@JUNCTIONS-2@@	two highways of different types meet.
+@@JUNCTIONS-3@@	three highways meet.
+@@JUNCTIONS-4@@	four highways meet.
+@@JUNCTIONS-5@@	five highways meet.
+@@JUNCTIONS-6@@	six highways meet.
+@@JUNCTIONS-MORE@@	seven (or more) highways meet.
+
+@@SUPER-BUTTON@@	Display Super Segments
+$$SUPER-INFO$$
+Each super-node and the associated super-segments are shown (see
+algorithm page for description).
+$$SUPER-INFO$$
+
+@@WAYTYPE-BUTTON@@	Display Way Type Segments
+$$WAYTYPE-INFO$$
+Each highway segment of special types (one-way, cycle-both-ways and roundabout) are
+shown.  For one-way segments a coloured triangle indicates the allowed direction.
+The colours of the triangles depend on the bearing of the highway segment.
+$$WAYTYPE-INFO$$
+
+@@WAYTYPE-ONEWAY@@	One-way segments
+@@WAYTYPE-CYCLE-BOTH-WAYS@@	Cycle-both-way segments
+@@WAYTYPE-ROUNDABOUT@@	Roundabout segments
+
+@@HIGHWAY-BUTTON@@	Display Highway Segments
+$$HIGHWAY-INFO$$
+Each segment of the chosen type of highway is drawn.
+$$HIGHWAY-INFO$$
+
+@@TRANSPORT-BUTTON@@	Display Transport Segments
+$$TRANSPORT-INFO$$
+Each segment allowed for the chosen type of transport is drawn.
+$$TRANSPORT-INFO$$
+
+@@BARRIER-BUTTON@@	Display Barrier Nodes
+$$BARRIER-INFO$$
+Each barrier blocking the chosen type of transport is drawn.
+$$BARRIER-INFO$$
+
+@@TURNS-BUTTON@@	Display Turn Restrictions
+$$TURNS-INFO$$
+Each turn restrictions is shown with a line indicating the disallowed turn.
+$$TURNS-INFO$$
+
+@@SPEED-BUTTON@@	Display Speed Limits
+$$SPEED-INFO$$
+Each node that joins segments with different speed limits is shown
+along with the speed limit on relevant segments.
+$$SPEED-INFO$$
+
+@@LIMIT-CHANGE@@	Change of limit
+@@LIMIT-NONE@@	No specified limit
+@@SPEED-LIMIT-80@@	80 km/hour speed limit
+
+@@WEIGHT-BUTTON@@	Display Weight Limits
+$$WEIGHT-INFO$$
+Each node that joins segments with different weight limits is shown
+along with the weight limit on relevant segments.
+$$WEIGHT-INFO$$
+
+@@WEIGHT-LIMIT-8@@	8.0 tonnes weight limit
+
+@@HEIGHT-BUTTON@@	Display Height Limits
+$$HEIGHT-INFO$$
+Each node that joins segments with different height limits is shown
+along with the height limit on relevant segments.
+$$HEIGHT-INFO$$
+
+@@HEIGHT-LIMIT-4@@	4.0 m height limit
+
+@@WIDTH-BUTTON@@	Display Width Limits
+$$WIDTH-INFO$$
+Each node that joins segments with different width limits is shown
+along with the width limit on relevant segments.
+$$WIDTH-INFO$$
+
+@@WIDTH-LIMIT-3@@	3.0 m width limit
+
+@@LENGTH-BUTTON@@	Display Length Limits
+$$LENGTH-INFO$$
+Each node that joins segments with different length limits is shown
+along with the length limit on relevant segments.
+$$LENGTH-INFO$$
+
+@@LENGTH-LIMIT-9@@	9.0 m length limit
+
+@@PROPERTY-BUTTON@@	Display Highway Properties
+$$PROPERTY-INFO$$
+Each segment of the highways with a particular property is drawn.
+$$PROPERTY-INFO$$
+
+@@ERROR-LOG-BUTTON@@	Display Error Logs
+$$ERROR-LOG-INFO$$
+Potential problems found by Routino when processing the input data.
+$$ERROR-LOG-INFO$$
+
+@@CLEAR-DATA-BUTTON@@	Clear data
+
+#
+# Multi-line descriptive translations (router)
+#
+
+$$ROUTER-INFO$$
+This web page allows routing within the data collected by OpenStreetMap.
+Select start and end points (click on the marker icons below), select routing preferences then find a route.
+$$ROUTER-INFO$$
+
+$$ROUTER-OPTIONS-HELP$$
+<b>Quick Start</b>
+<br>
+Click on marker icons (above) to place them on the map (right).  Then
+drag them to the correct position.  Zooming the map before placing the
+markers is probably easiest.  Alternatively type the latitude and
+longitude into the boxes above.
+<p>
+Select the transport type, allowed highway types, speed limits, highway
+properties and other restrictions from the options above.
+Select "Shortest" or "Quickest" to calculate the route and display it
+on the map.
+<p>
+<b>Waypoints</b>
+<br>
+Clicking on the marker icons will toggle the display of them on the map.
+When a route is calculated it will visit (as close as possible
+for the selected transport type) each of the waypoints that have
+markers on the map in the order given.
+<p>
+<b>Transport Type</b>
+<br>
+Selecting a transport type will restrict the chosen route to
+those on which it is allowed and set default values for the
+other parameters.
+<p>
+<b>Highway Preferences</b>
+<br>
+The highway preference is selected as a percentage and routes are chosen that
+try to follow the preferred highways.
+For example if a "Primary" road is given a "110%" preference and a "Secondary"
+road is given a "100%" preference then it means that a route on a Primary road
+can be up to 10% longer than on a secondary road and still be selected.
+<p>
+<b>Speed Limits</b>
+<br>
+The speed limits chosen here for the different types of highway apply if the
+highway has no other speed limit marked or it is higher than the chosen one.
+<p>
+<b>Property Preferences</b>
+<br>
+The property preference is selected as a percentage and routes are chosen that
+try to follow highways with the preferred property.
+For example if a "Paved" highway is given a "75%" preference then it means that
+an unpaved highway is automatically given a "25%" preference so that a route on
+a paved highway can be 3 times the length of an unpaved one and still be
+selected.
+<p>
+<b>Other Restrictions</b>
+<br>
+These allow a route to be found that avoids marked limits on
+weight, height, width or length.  It is also possible to ignore
+one-way restrictions (e.g. if walking).
+$$ROUTER-OPTIONS-HELP$$
+
+$$ROUTER-RESULTS-HELP$$
+<b>Quick Start</b>
+<br>
+After calculating a route you can download the GPX file or plain
+text route description (summary or detailed version). Also you
+can view the route description and zoom in to selected parts.
+<p>
+<b>Problem Solving</b>
+<br>
+If the router completes with an error then the most likely cause is
+that it is not possible to find a route between the selected points.
+Moving one or more markers or changing the routing options should
+allow a route to be found.
+<p>
+<b>Output Formats</b>
+<br>
+<dl>
+  <dt>HTML instructions
+  <dd>A description of the route to take with directions at each
+    important junction.
+  <dt>GPX track file
+  <dd>The same information that is displayed on the map with points
+    for every node and lines for every segment.
+  <dt>GPX route file
+  <dd>The same information that is displayed in text for the route
+    with a waypoint for each important junction in the route.
+  <dt>Full text file
+  <dd>A list of all of the nodes visited as well as the distance
+    between them and the cumulative distance for each step of the
+    route.
+  <dt>Text file
+  <dd>The same information that is displayed in text for the route.
+</dl>
+$$ROUTER-RESULTS-HELP$$
+
+$$ROUTER-VISUALISER-INFO$$
+To see Routino's view of the data there is a data visualiser that allows
+displaying of the underlying data in various ways.
+$$ROUTER-VISUALISER-INFO$$
+
+#
+# Multi-line descriptive translations (visualiser)
+#
+
+$$VISUALISER-INFO$$
+This web page allows visualisation of the data that Routino uses for routing.
+Only data relevant for routing is displayed and some will therefore be excluded.
+$$VISUALISER-INFO$$
+
+$$VISUALISER-INSTRUCTIONS$$
+Zoom in and then use the buttons below to download the data.  The
+server will only return data if the selected area is small enough.
+$$VISUALISER-INSTRUCTIONS$$
+
+$$VISUALISER-HELP$$
+<b>Quick Start</b>
+<br>
+Zoom to an area and select one of the buttons to display that type of
+data.
+<br>
+More data options can be found by expanding the details below each
+button.
+<p>
+<b>Data Failure</b>
+<br>
+If the area selected is too large (depends on the data type) then the
+status will say "Failed to get visualiser data" - zoom in and try
+again.
+$$VISUALISER-HELP$$
+
+$$VISUALISER-ROUTER-INFO$$
+To perform routing on the map use the link below.
+$$VISUALISER-ROUTER-INFO$$
diff --git a/3rdparty/Routino/web/translations/translation.fr.txt b/3rdparty/Routino/web/translations/translation.fr.txt
new file mode 100644
index 0000000..9ddc6ee
--- /dev/null
+++ b/3rdparty/Routino/web/translations/translation.fr.txt
@@ -0,0 +1,324 @@
+#
+# French language translation phrases
+#
+
+#
+# Router output XML definition
+#
+
+%%copyright_creator_string%%	Créateur
+%%copyright_source_string%%	Source
+%%copyright_source_text%%	Basé sur les données OpenStreetMap de http://www.openstreetmap.org/
+%%copyright_license_string%%	License
+
+%%turn_-4%%	demi-tour à gauche
+%%turn_-3%%	Très à gauche
+%%turn_-2%%	à gauche
+%%turn_-1%%	Légèrement à gauche
+%%turn_0%%	Tout droit
+%%turn_1%%	légèrement à droite
+%%turn_2%%	à droite
+%%turn_3%%	très à droite
+%%turn_4%%	demi-tour à droite
+
+%%heading_-4%%	Sud
+%%heading_-3%%	Dud-Ouest
+%%heading_-2%%	Ouest
+%%heading_-1%%	Nord-Ouest
+%%heading_0%%	Nord
+%%heading_1%%	Nord-Est
+%%heading_2%%	Est
+%%heading_3%%	Sud-Est
+%%heading_4%%	Sud
+
+%%ordinal_1%%	Premier
+%%ordinal_2%%	Second
+%%ordinal_3%%	Troisième
+%%ordinal_4%%	Quatrième
+%%ordinal_5%%	Cinquième
+%%ordinal_6%%	Sixième
+%%ordinal_7%%	Septième
+%%ordinal_8%%	huitième
+%%ordinal_9%%	Neuvième
+%%ordinal_10%%	Dixième
+
+%%highway_motorway%%	autoroute
+%%highway_trunk%%	route de jonction
+%%highway_primary%%	route nationale
+%%highway_secondary%%	route départementale
+%%highway_tertiary%%	route locale
+%%highway_unclassified%%	route non classifiée
+%%highway_residential%%	rue résidentielle
+%%highway_service%%	rue de service
+%%highway_track%%	chemin
+%%highway_cycleway%%	voie cyclable
+%%highway_path%%	sentier
+%%highway_steps%%	escalier
+%%highway_ferry%%	ferry
+
+%%route_shortest%%	le plus court
+%%route_quickest%%	le plus rapide
+
+%%output-html_waypoint_waypoint%%	Etape
+%%output-html_waypoint_junction%%	Croisement
+%%output-html_waypoint_roundabout%%	rond-point
+%%output-html_title%%	Itinéraire %s
+%%output-html_start_string%%	Débute
+%%output-html_start_text%%	à %s, direction %s
+%%output-html_node_string%%	à
+%%output-html_node_text%%	%s, aller %s direction %s
+%%output-html_rbnode_string%%	Quitter
+%%output-html_rbnode_text%%	%s, prendre le %s sortir direction %s
+%%output-html_segment_string%%	Suivre
+%%output-html_segment_text%%	%s pendant %.3f km, %.1f min
+%%output-html_stop_string%%	S'arrêter
+%%output-html_stop_text%%	à %s
+%%output-html_total_string%%	Total
+%%output-html_total_text%%	%.1f km, %.0f minutes
+
+%%output-gpx_waypoint_start%%	DEBUT
+%%output-gpx_waypoint_inter%%	INTER
+%%output-gpx_waypoint_trip%%	POINT
+%%output-gpx_waypoint_finish%%	FINAL
+
+%%output-gpx_desc%%	Itinéraire %s entre les étapes 'début' et 'fin'
+%%output-gpx_name%%	Itinéraire %s
+%%output-gpx_step%%	%s sur '%s' pendant %.3f km, %.1f min
+%%output-gpx_final%%	Trajet total %.1f km, %.0f minutes
+
+#
+# Router (and some shared) translations
+#
+
+@@LANGUAGE@@	Francais
+@@LANGUAGE-WEBPAGE@@	Francais
+
+@@ROUTER-TITLE@@	Calculateur d'itinéraire pour OpenStreetMap
+
+@@OPTION-TAB@@	Options
+@@OPTION-TAB-HELP@@	définir les options
+
+@@RESULTS-TAB@@	Résultats
+@@RESULTS-TAB-HELP@@	Voir les resultats
+
+@@DATA-TAB@@	Données
+@@DATA-TAB-HELP@@	Voir les informations de la base de donnée
+
+@@ROUTINO-ROUTER@@	Itinéraires pour Openstreetmap Routino
+@@ROUTINO-WEBSITE@@	site web Routino
+@@DOCUMENTATION@@	Documentation
+
+@@LANGUAGE-BOX@@	Langue
+@@WAYPOINTS-BOX@@	Etapes de l'itinéraire
+@@TRANSPORT-TYPE-BOX@@	Mode de déplacement
+@@HIGHWAY-PREFERENCES-BOX@@	Préférences routières
+@@SPEED-LIMITS-BOX@@	Limitations de vitesse
+@@PROPERTY-PREFERENCES-BOX@@	Préférences des propriétés
+@@OTHER-RESTRICTIONS-BOX@@	Autres Restrictions
+@@FIND-BOX@@	Rechercher
+@@LINKS-BOX@@	Liens
+@@HELP-BOX@@	Aide
+
+@@SHORTEST-ROUTE@@	Le plus court
+@@QUICKEST-ROUTE@@	Le plus rapide
+
+@@STATISTICS-BOX@@	Routino Statistiques
+@@VISUALISER-BOX@@	Routino Visualiser
+
+@@WAYPOINT-POSITION@@	Etape XXX de l'itinéraire
+@@WAYPOINT-LONGITUDE@@	Etape XXX Longitude
+@@WAYPOINT-LATITUDE@@	Etape XXX Latitude
+@@WAYPOINT-LOCATION@@	position de l'étape XXX
+@@WAYPOINT-SEARCH@@	Rechercher la position
+@@WAYPOINT-GET@@	obtenir la position actuelle
+@@WAYPOINT-CENTRE1@@	Centrer la carte sur cette étape
+@@WAYPOINT-UP@@	Placer cette étape avant
+@@WAYPOINT-ADD@@	Ajouter une étape après celle-ci
+@@WAYPOINT-COORDS@@	Coordonnées de position
+@@WAYPOINT-HOME@@	Changer en position de départ
+@@WAYPOINT-CENTRE2@@	Centrer cette étape sur la carte
+@@WAYPOINT-DOWN@@	Placer cette étape après
+@@WAYPOINT-REMOVE@@	supprimer cette étape
+@@WAYPOINT-REVERSE@@	Inverser l'ordre des étapes
+@@WAYPOINT-REVERSE-BUTTON@@	Inverser l'ordre
+@@WAYPOINT-LOOP@@	Ajouter une nouvelle étape pour faire une boucle
+@@WAYPOINT-LOOP-BUTTON@@	Faire une boucle
+
+@@TRANSPORT-FOOT@@	À pied
+@@TRANSPORT-HORSE@@	À cheval
+@@TRANSPORT-WHEELCHAIR@@	Fauteuil roulant
+@@TRANSPORT-BICYCLE@@	Bicyclette
+@@TRANSPORT-MOPED@@	Mobilette
+@@TRANSPORT-MOTORCYCLE@@	Moto
+@@TRANSPORT-MOTORCAR@@	Voiture
+@@TRANSPORT-GOODS@@	Camionette
+@@TRANSPORT-HGV@@	Camion(15t)
+@@TRANSPORT-PSV@@	Camion(10t)
+
+@@HIGHWAY-MOTORWAY@@	Autoroute
+@@HIGHWAY-TRUNK@@	Trunk
+@@HIGHWAY-PRIMARY@@	Primaire
+@@HIGHWAY-SECONDARY@@	Secondaire
+@@HIGHWAY-TERTIARY@@	Tertiaire
+@@HIGHWAY-UNCLASSIFIED@@	Non classée
+@@HIGHWAY-RESIDENTIAL@@	Résidentiel
+@@HIGHWAY-SERVICE@@	Service
+@@HIGHWAY-TRACK@@	Chemin
+@@HIGHWAY-CYCLEWAY@@	Voie cyclable
+@@HIGHWAY-PATH@@	Sentier
+@@HIGHWAY-STEPS@@	Escaliers
+@@HIGHWAY-FERRY@@	Ferry
+
+@@PROPERTY-PAVED@@	Pavée
+@@PROPERTY-MULTILANE@@	Voies multiples
+@@PROPERTY-BRIDGE@@	Pont
+@@PROPERTY-TUNNEL@@	Tunnel
+@@PROPERTY-WALKINGROUTE@@	Itinér. piéton
+@@PROPERTY-BICYCLEROUTE@@	Itinér. cycle
+
+@@RESTRICT-ONEWAY@@	Respecter les sens uniques
+@@RESTRICT-TURNS@@	Respecter les obligations de tourner
+@@RESTRICT-WEIGHT@@	Poids
+@@RESTRICT-HEIGHT@@	Hauteur
+@@RESTRICT-WIDTH@@	Largeur
+@@RESTRICT-LENGTH@@	Longueur
+
+@@FIND-SHORTEST-ROUTE@@	Chercher l'itinéraire le plus court
+@@FIND-QUICKEST-ROUTE@@	Chercher l'itinéraire le plus rapide
+
+@@MAP-VIEW-LINK@@	Lien vers cet outil de visualisation
+@@EDIT-OSM-DATA@@	Editer cette donnée OSM
+
+@@ROUTER-NOT-RUN@@	Routage non lancé
+@@ROUTER-RUNNING@@	Routage en cours...
+@@ROUTER-COMPLETED@@	Routage terminé
+@@ROUTER-ERROR@@	Erreur de Routage
+@@ROUTER-FAILED@@	Le Routage n'a pas été lancé correctement
+@@VIEW-DETAILS@@	Voir les Détails
+
+@@NO-INFORMATION@@	Pas d'information
+@@HTML-ROUTE@@	Itinéraire HTML
+@@GPX-TRACK-ROUTE@@	Fichier chemin GPX
+@@GPX-ROUTE@@	Fichier route GPX
+@@FULL-TEXT-ROUTE@@	Fichier texte complet
+@@TEXT-ROUTE@@	Fichier texte
+@@OPEN-POPUP@@	Ouvrir Popup
+
+@@DISPLAY-STATISTICS@@	Afficher les données statistiques
+
+@@JAVASCRIPT-REQUIRED@@	Javascript est <em>nécessaire</em> pour cette page web à cause de la carte intéractive.
+@@ROUTER@@	Routeur
+@@GEO-DATA@@	Geo Data
+@@TILES@@	Tuiles
+
+#
+# Visualiser specific translations
+#
+
+#
+# Multi-line descriptive translations (router)
+#
+
+$$ROUTER-INFO$$
+Cette page web permet de calculer des itinéraires à l'aide des données collectées par OpenStreetMap.
+Sélectionner les points de départ et d'arrivée (cliquer sur les icones ci-dessous), sélectionner les préférences, puis rechercher un itinéraire.
+$$ROUTER-INFO$$
+
+$$ROUTER-OPTIONS-HELP$$
+<b>Aide simplifiée</b>
+<br>
+Cliquer sur les icones de balises (ci-dessus) pour les placer sur la carte (droite).  Puis
+les déplacer à la position choisie. Il sera sûrement plus facile de zoomer sur la carte
+avant de placer les balises.  Autre solution, taper la latitude et
+la longitude dans les cases ci-dessus.
+<p>
+Selectionner le mode de déplacement, les types de voies autorisées, les limitations de vitesse,
+les propriétés des voies et les autres restrictions dans les options ci-dessus.
+Selectionner "Le plus court" ou "Le plus rapide" pour calculer l'itinéraire et le visualiser
+sur la carte.
+<p>
+<b>Etapes</b>
+<br>
+Cliquer sur les balises affichera ou supprimera leur apparition sur la carte.
+Quand un itinéraire est calculé, il affichera (le plus près possible
+pour le mode de déplacement sélectionné) chacune des étapes qui ont une
+balise sur la carte dans l'ordre défini.
+<p>
+<b>Mode de déplacement</b>
+<br>
+Selectionner un mode de déplacement restreindra l'itinéraire choisi aux
+voies sur lesquelles il est autorisé et définira les valeurs par défaut pour
+les autres paramètres.
+<p>
+<b>Préferences des voies</b>
+<br>
+La préférence de voies est définie par un pourcentage et des itinéraires sont choisis
+qui essaient de suivre les voies préferrées.
+Par exemple, si une voie "Primaire" a une préférence de "110%" et une voie "Secondaire"
+une préférence de "100%", alors cela signifie qu'un itinéraire sur une voie primaire
+peut être jusqu'à 10% plus long que sur une voie secondaire et être sélectionné.
+<p>
+<b>Limites de vitesse</b>
+<br>
+Les limites de vitesse choisies ici pour les differents types de voies s'appliquent si la
+voie n'a pas d'autre limite de vitesse définie ou si celle-ci est supérieure à celle choisie.
+<p>
+<b>Préférences de propriétés</b>
+<br>
+La préférence de propriété est définie par un pourcentage et des itinéraires sont choisis
+qui essaient de suivre les voies ayant cette propriété préférée.
+Par exemple, si une voie goudronnée a une préférence de "75%", alors cela signifie que
+une voie non goudronnée obtient automatiquement une préférence de "25%" ce qui fait que
+un itinéraire sur une voie goudronnée peut avoir 3 fois la longueur d'une non goudronnée
+et être sélectionnée.
+<p>
+<b>Autres restrictions</b>
+<br>
+Celles-ci permettent de touver un itinéraire qui respecte les limites définies pour
+le poids, la hauteur, la largeur ou la longueur.  Il est également possible d'ignorer
+les restrictions de sens unique (e. pour la marche).
+$$ROUTER-OPTIONS-HELP$$
+
+$$ROUTER-RESULTS-HELP$$
+<b>Aide rapide</b>
+<br>
+Après le calcul de l'itinéraire, vous pouvez télécharger le fichier GPX ou
+la description au format texte (résumé ou version détaillée). Vous pouvez également
+visualiser la description de l'itinéraire et zoomer sur des tronçons sélectionnés.
+<p>
+<b>Résoudre un problème</b>
+<br>
+Si le calculateur aboutie à une erreur, la cause la plus probable est que
+il n'est pas possible de trouver un itinéraire entre les points sélectionnés.
+Por permettre de trouver un itinéraire, déplacer une ou des balises
+ou changer les options de recherche.
+<p>
+<b>Formats d'affichage</b>
+<br>
+<dl>
+  <dt>Instructions HTML
+  <dd>une description de l'itinéraire à prendre
+    à chaque intersection importante.
+  <dt>Fichier chemin GPX
+  <dd>La même information qui est affichée sur la carte avec des points
+    pour chaque noeud et des lignes pour tous les sègments.
+  <dt>Fichier route GPX
+  <dd>La même information qui est affichée en texte pour l'itinéraire
+    avec une étape pour chaque intersection importante.
+  <dt>Fichier texte complet
+  <dd>Une liste de tous les noeuds traversés ainsi que la distance
+    entre eux et la distance cumulée pour chaque étape de l'itinéraire.
+  <dt>Fichier texte
+  <dd>La même information qui est affichée en texte pour l'itinéraire.
+</dl>
+$$ROUTER-RESULTS-HELP$$
+
+$$ROUTER-VISUALISER-INFO$$
+Pour comprendre comment Routino voit les données, il y a un outil de visualisation
+qui permet d'afficher les données soujacentes de multiples manières.
+$$ROUTER-VISUALISER-INFO$$
+
+#
+# Multi-line descriptive translations (visualiser)
+#
+
diff --git a/3rdparty/Routino/web/translations/translation.hu.txt b/3rdparty/Routino/web/translations/translation.hu.txt
new file mode 100644
index 0000000..49d1128
--- /dev/null
+++ b/3rdparty/Routino/web/translations/translation.hu.txt
@@ -0,0 +1,276 @@
+#
+# Hungarian language translation phrases
+#
+
+#
+# Router output XML definition
+#
+
+%%copyright_creator_string%%	Készítő
+%%copyright_source_string%%	Forrás
+%%copyright_source_text%%	Openstreetmap adatok alapján http://www.openstreetmap.org/
+%%copyright_license_string%%	Liszenc
+
+%%turn_-4%%	Nagyon élesen balra
+%%turn_-3%%	Élesen balra
+%%turn_-2%%	Balra
+%%turn_-1%%	Balra tarts
+%%turn_0%%	Egyenesen
+%%turn_1%%	Jobbra tarts
+%%turn_2%%	Jobbra
+%%turn_3%%	Élesen jobbra
+%%turn_4%%	Nagyon élesen jobbra
+
+%%heading_-4%%	dél
+%%heading_-3%%	délnyugat
+%%heading_-2%%	nyugat
+%%heading_-1%%	északnyugat
+%%heading_0%%	észak
+%%heading_1%%	északkelet
+%%heading_2%%	kelet
+%%heading_3%%	délkelet
+%%heading_4%%	dél
+
+%%ordinal_1%%	első
+%%ordinal_2%%	második
+%%ordinal_3%%	harmadik
+%%ordinal_4%%	negyedik
+%%ordinal_5%%	ötödik
+%%ordinal_6%%	hatodik
+%%ordinal_7%%	hetedik
+%%ordinal_8%%	nyolcadik
+%%ordinal_9%%	kilencedik
+%%ordinal_10%%	tizedik
+
+%%highway_motorway%%	autópálya
+%%highway_trunk%%	autóút
+%%highway_primary%%	főút
+%%highway_secondary%%	összekötőút
+%%highway_tertiary%%	bekötőút
+%%highway_unclassified%%	egyéb közút
+%%highway_residential%%	lakóút
+%%highway_service%%	szervízút
+%%highway_track%%	földút
+%%highway_cycleway%%	kerékpárút
+%%highway_path%%	ösvény
+%%highway_steps%%	lépcső
+%%highway_ferry%%	komp
+
+%%route_shortest%%	Legrövidebb
+%%route_quickest%%	Leggyorsabb
+
+%%output-html_waypoint_waypoint%%	Útpont
+%%output-html_waypoint_junction%%	Kereszteződés
+%%output-html_waypoint_roundabout%%	Körforgalom
+%%output-html_title%%	%s útvonal
+%%output-html_start_string%%	Indulás
+%%output-html_start_text%%	%s, %s felé
+%%output-html_node_string%%	Itt
+%%output-html_node_text%%	%s, menj %s %s felé
+%%output-html_rbnode_string%%	Kijárat
+%%output-html_rbnode_text%%	%s, %s kijárat %s felé
+%%output-html_segment_string%%	Erre
+%%output-html_segment_text%%	%s, %.3f km, %.1f perc
+%%output-html_stop_string%%	Cél
+%%output-html_total_string%%	Összesen
+%%output-html_total_text%%	%.1f km, %.0f perc
+
+%%output-gpx_waypoint_start%%	Indulás
+%%output-gpx_waypoint_trip%%	Utazás
+
+%%output-gpx_desc%%	%s útvonal a kezdő és utolsó pont között
+%%output-gpx_final%%	Az egész út %.1f km, %.0f perc
+
+#
+# Router (and some shared) translations
+#
+
+@@LANGUAGE@@	Magyar
+@@LANGUAGE-WEBPAGE@@	Magyar weblap
+
+@@ROUTER-TITLE@@	Openstreetmap alapú útvonaltervező
+
+@@OPTION-TAB@@	Beállítások
+@@OPTION-TAB-HELP@@	Útvonaltervező beállítások
+
+@@RESULTS-TAB@@	Eredmény
+@@RESULTS-TAB-HELP@@	Útvonaltervező eredmények
+
+@@DATA-TAB@@	Adatok
+@@DATA-TAB-HELP@@	Adatbázis információk
+
+@@ROUTINO-ROUTER@@	Routino openstreetmap útvonaltervező
+@@ROUTINO-WEBSITE@@	Routino weboldal
+@@DOCUMENTATION@@	Dokumentáció
+
+@@LANGUAGE-BOX@@	Nyelv
+@@WAYPOINTS-BOX@@	Útpontok
+@@TRANSPORT-TYPE-BOX@@	Közlekedési mód
+@@HIGHWAY-PREFERENCES-BOX@@	Út preferencia
+@@SPEED-LIMITS-BOX@@	Sebességkorlát
+@@PROPERTY-PREFERENCES-BOX@@	Út tulajdonságok
+@@OTHER-RESTRICTIONS-BOX@@	Kizáró tényezők
+@@LINKS-BOX@@	Linkek
+@@HELP-BOX@@	Súgó
+
+@@STATUS-BOX@@	Állapot
+@@SHORTEST-ROUTE@@	Legrövidebb út
+@@QUICKEST-ROUTE@@	Leggyorsabb út
+
+@@STATISTICS-BOX@@	Routino statisztika
+@@VISUALISER-BOX@@	Routino vizualizáció
+
+@@WAYPOINT-SEARCH@@	Hely keresése
+@@WAYPOINT-GET@@	Aktuális helyzet
+@@WAYPOINT-CENTRE1@@	Legyen ez a pont a térkép közepe
+@@WAYPOINT-UP@@	Mozgasd feljebb ezt a pontot
+@@WAYPOINT-ADD@@	Új pont ezután a pont után
+@@WAYPOINT-COORDS@@	Hely koordinátája
+@@WAYPOINT-CENTRE2@@	Ez legyen a térkép középpontja
+@@WAYPOINT-DOWN@@	Mozgasd ezt a pontot lejjebb
+@@WAYPOINT-REMOVE@@	Pont törlése
+@@WAYPOINT-REVERSE@@	Útirány megfordítása
+@@WAYPOINT-REVERSE-BUTTON@@	Ellenkező irány
+@@WAYPOINT-LOOP@@	Új pont létrehozása a kezdőpontban
+@@WAYPOINT-LOOP-BUTTON@@	Kör bezárása
+
+@@TRANSPORT-FOOT@@	Gyalog
+@@TRANSPORT-HORSE@@	Lovas
+@@TRANSPORT-WHEELCHAIR@@	Kerekesszékes
+@@TRANSPORT-BICYCLE@@	Kerékpáros
+@@TRANSPORT-MOPED@@	Robogós
+@@TRANSPORT-MOTORCYCLE@@	Motoros
+@@TRANSPORT-MOTORCAR@@	Autós
+@@TRANSPORT-GOODS@@	Kisteherautós
+@@TRANSPORT-HGV@@	Kamionos
+@@TRANSPORT-PSV@@	Buszos
+
+@@HIGHWAY-MOTORWAY@@	Autópálya
+@@HIGHWAY-TRUNK@@	Autóút
+@@HIGHWAY-PRIMARY@@	Főút
+@@HIGHWAY-SECONDARY@@	Összekötőút
+@@HIGHWAY-TERTIARY@@	Bekötőút
+@@HIGHWAY-UNCLASSIFIED@@	Egyéb közút
+@@HIGHWAY-RESIDENTIAL@@	Lakóövezeti út
+@@HIGHWAY-SERVICE@@	Szervízút
+@@HIGHWAY-TRACK@@	Földút
+@@HIGHWAY-CYCLEWAY@@	Kerékpárút
+@@HIGHWAY-PATH@@	Ösvény
+@@HIGHWAY-STEPS@@	Lépcső
+@@HIGHWAY-FERRY@@	Komp
+
+@@PROPERTY-PAVED@@	Burkolt
+@@PROPERTY-MULTILANE@@	Többsávos
+@@PROPERTY-BRIDGE@@	Híd
+@@PROPERTY-TUNNEL@@	Alagút
+@@PROPERTY-WALKINGROUTE@@	Gyalogút
+@@PROPERTY-BICYCLEROUTE@@	Kijelölt kerékpárút
+
+@@RESTRICT-ONEWAY@@	Egyirányúsítás mellőzése
+@@RESTRICT-TURNS@@	Kanyarodási tilalmak mellőzése
+@@RESTRICT-WEIGHT@@	Súly
+@@RESTRICT-HEIGHT@@	Magasság
+@@RESTRICT-WIDTH@@	Szélesség
+@@RESTRICT-LENGTH@@	Hosszúság
+
+@@FIND-SHORTEST-ROUTE@@	A legrövidebb út keresése
+@@FIND-QUICKEST-ROUTE@@	A leggyorsabb út keresése
+
+@@MAP-VIEW-LINK@@	Link erre a nézetre
+@@EDIT-OSM-DATA@@	OSM adatok szerkesztése
+
+@@ROUTER-NOT-RUN@@	Az útvonaltervező nem fut
+@@ROUTER-RUNNING@@	Az útvonaltervező számol ...
+@@ROUTER-COMPLETED@@	Az útvonaltervezés kész
+@@ROUTER-ERROR@@	Útvonaltervezési hiba
+@@ROUTER-FAILED@@	Az útvonaltervezőt nem sikerült futtatni
+@@VIEW-DETAILS@@	Részletek
+
+@@NO-INFORMATION@@	Nincs információ
+@@HTML-ROUTE@@	HTML irányok
+@@GPX-TRACK-ROUTE@@	GPX file
+@@FULL-TEXT-ROUTE@@	Teljes szöveges file
+@@TEXT-ROUTE@@	Szöveges file
+@@OPEN-POPUP@@	Új ablak
+
+@@DISPLAY-STATISTICS@@	Statisztika mutatása
+
+@@ROUTER@@	Útvonaltervező
+@@TILES@@	Térképszeletek
+
+#
+# Visualiser specific translations
+#
+
+@@VISUALISER-TITLE@@	Útvonaltervező adatok vizuálisan
+
+@@INSTRUCTIONS-BOX@@	Útmutatók
+@@ROUTER-BOX@@	Routino Útvonaltervező
+
+@@NO-DATA-DISPLAYED@@	Nincs megjelenítendő adat
+
+@@VISUALISER-FAILED@@	Sikertelen az adatok betöltése
+@@VISUALISER-NUM-JUNCTIONS@@	Feldolgozva # kereszteződés
+@@VISUALISER-NUM-SUPER@@	Feldolgozva # szuper-pont/szegmens
+@@VISUALISER-NUM-WAYTYPE@@	Feldolgozva # út típus szegmens
+@@VISUALISER-NUM-SEGMENTS@@	Feldolgozva # szegmens
+@@VISUALISER-NUM-NODES@@	Feldolgozva # pont
+@@VISUALISER-NUM-TURNS@@	Feldolgozva # kanyarodási korlátozás
+
+@@JUNCTIONS-BUTTON@@	Kereszteződések mutatása
+@@JUNCTIONS-3@@	három út talákozása
+@@JUNCTIONS-4@@	négy út találkozása
+@@JUNCTIONS-5@@	öt út találkozása
+@@JUNCTIONS-6@@	hat út találkozása
+@@JUNCTIONS-MORE@@	hét, vagy több út találkozása
+
+@@SUPER-BUTTON@@	Szuper szegmens mutatása
+
+@@WAYTYPE-BUTTON@@	Út típus szakaszok megjelenítese
+
+@@WAYTYPE-ONEWAY@@	Egyirányú szakaszok
+@@WAYTYPE-ROUNDABOUT@@	Körforgalmi szakaszok
+
+@@HIGHWAY-BUTTON@@	Út szakaszok megjelenítése
+
+@@TURNS-BUTTON@@	Kanyarodási korlátozások
+
+@@SPEED-BUTTON@@	Sebességhatárok
+
+@@LIMIT-CHANGE@@	Korlátozás változása
+@@LIMIT-NONE@@	Nincs korlátozás
+@@SPEED-LIMIT-80@@	80 km/óra sebességkorlátozás
+
+@@WEIGHT-BUTTON@@	Súlykorlátozások
+
+@@WEIGHT-LIMIT-8@@	8 tonnás súlykorlátozás
+
+@@HEIGHT-BUTTON@@	Magasságkorlátozások
+
+@@HEIGHT-LIMIT-4@@	4 méter magasságkorlátozás
+
+@@WIDTH-BUTTON@@	Szélességkorlátozások
+
+@@WIDTH-LIMIT-3@@	3 méter szélességkorlátozás
+
+@@LENGTH-BUTTON@@	Hosszúságkorlátozások
+
+@@LENGTH-LIMIT-9@@	9 méter hosszúságkorlátozás
+
+@@PROPERTY-BUTTON@@	Út tulajdonságok megjelenítése
+
+@@ERROR-LOG-BUTTON@@	Hiba logok megmutatása
+$$ERROR-LOG-INFO$$
+Lehetséges hibák fordultak elő az adatok feldolgozása során
+$$ERROR-LOG-INFO$$
+
+@@CLEAR-DATA-BUTTON@@	Adatok törlése
+
+#
+# Multi-line descriptive translations (router)
+#
+
+#
+# Multi-line descriptive translations (visualiser)
+#
+
diff --git a/3rdparty/Routino/web/translations/translation.nl.txt b/3rdparty/Routino/web/translations/translation.nl.txt
new file mode 100644
index 0000000..89ba913
--- /dev/null
+++ b/3rdparty/Routino/web/translations/translation.nl.txt
@@ -0,0 +1,309 @@
+#
+# Dutch language translation phrases
+#
+
+#
+# Router output XML definition
+#
+
+%%copyright_creator_string%%	Creator
+%%copyright_source_string%%	Source
+%%copyright_source_text%%	Gebouwd op OpenStreetMap data van http://www.openstreetmap.org/
+%%copyright_license_string%%	License
+
+%%turn_-4%%	Haarspeld naar links
+%%turn_-3%%	Scherp links
+%%turn_-2%%	Links
+%%turn_-1%%	Half links
+%%turn_0%%	Rechtdoor
+%%turn_1%%	Half rechts
+%%turn_2%%	Rechts
+%%turn_3%%	Scherp rechts
+%%turn_4%%	Haarspeld naar rechts
+
+%%heading_-4%%	Zuid
+%%heading_-3%%	Zuid-West
+%%heading_-2%%	West
+%%heading_-1%%	Noord-West
+%%heading_0%%	Noord
+%%heading_1%%	Noord-Oost
+%%heading_2%%	Oost
+%%heading_3%%	Zuid-Oost
+%%heading_4%%	Zuid
+
+%%ordinal_1%%	Eerste
+%%ordinal_2%%	Tweede
+%%ordinal_3%%	Derde
+%%ordinal_4%%	Vierde
+%%ordinal_5%%	Vijfde
+%%ordinal_6%%	Zesde
+%%ordinal_7%%	Zevende
+%%ordinal_8%%	Achtste
+%%ordinal_9%%	Negende
+%%ordinal_10%%	Tiende
+
+%%highway_motorway%%	Autostrade
+%%highway_trunk%%	Autoweg
+%%highway_primary%%	Provinciale weg
+%%highway_secondary%%	Nationale weg
+%%highway_tertiary%%	Doorgangsweg
+%%highway_unclassified%%	Niet geclassificeerd
+%%highway_residential%%	Woongebied
+%%highway_service%%	Toegangsweg
+%%highway_track%%	Veldweg
+%%highway_cycleway%%	Fietspad
+%%highway_path%%	Pad
+%%highway_steps%%	Trap
+%%highway_ferry%%	Veerboot
+
+%%route_shortest%%	Kortste
+%%route_quickest%%	Snelste
+
+%%output-html_waypoint_waypoint%%	Punt
+%%output-html_waypoint_junction%%	de splitsing
+%%output-html_waypoint_roundabout%%	rotonde
+%%output-html_title%%	%s Route
+%%output-html_start_string%%	Start
+%%output-html_start_text%%	Bij %s neemt u de richting %s
+%%output-html_node_string%%	Bij
+%%output-html_node_text%%	Bij %s gaat u %s richting %s
+%%output-html_rbnode_string%%	Leave
+%%output-html_rbnode_text%%	Aan de %s, neem de %s afslag richting %s
+%%output-html_segment_string%%	Volg
+%%output-html_segment_text%%	Volgt u de %s voor %.3f km %.1f min
+%%output-html_stop_string%%	Stop
+%%output-html_stop_text%%	U bent bij  %s aangekomen
+%%output-html_total_string%%	Totaal
+%%output-html_total_text%%	%.1f km, %.0f minuten
+
+%%output-gpx_waypoint_start%%	START
+%%output-gpx_waypoint_inter%%	INTER
+%%output-gpx_waypoint_trip%%	TRIP
+%%output-gpx_waypoint_finish%%	FINISH
+
+%%output-gpx_desc%%	%s Route tussen 'Start' und 'Finish'
+%%output-gpx_name%%	%s Route
+%%output-gpx_step%%	%s op '%s' voor %.3f km, %.1f min
+%%output-gpx_final%%	Totaal trip  %.1f km, %.0f minuten
+
+#
+# Router (and some shared) translations
+#
+
+@@LANGUAGE@@	Nederlands
+@@LANGUAGE-WEBPAGE@@	Nederlandse web pagina
+
+@@OPTION-TAB@@	Opties
+
+@@RESULTS-TAB@@	Resultaten
+
+@@DATA-TAB@@	Data
+
+@@LANGUAGE-BOX@@	Taal
+@@WAYPOINTS-BOX@@	Coordinaten
+@@TRANSPORT-TYPE-BOX@@	Transport Type
+@@HIGHWAY-PREFERENCES-BOX@@	Voorkeur Wegtype
+@@SPEED-LIMITS-BOX@@	Snelheidslimieten
+@@PROPERTY-PREFERENCES-BOX@@	Weg Eigenschappen
+@@OTHER-RESTRICTIONS-BOX@@	Andere Beperkingen
+@@FIND-BOX@@	Zoek Route
+@@LINKS-BOX@@	Links
+@@HELP-BOX@@	Help
+
+@@STATUS-BOX@@	Status
+@@SHORTEST-ROUTE@@	Kortste Route
+@@QUICKEST-ROUTE@@	Snelste Route
+
+@@WAYPOINT-POSITION@@	Waypoint XXX Position
+@@WAYPOINT-UP@@	Beweeg dit punt naar boven
+@@WAYPOINT-ADD@@	Voeg hierna punt toe
+@@WAYPOINT-HOME@@	Toggle als thuis locatie
+@@WAYPOINT-CENTRE2@@	Centreer dit punt op map
+@@WAYPOINT-DOWN@@	Beweeg dit punt naar beneden
+@@WAYPOINT-REMOVE@@	Verwijder dit punt
+@@WAYPOINT-REVERSE@@	Keer volgorde punten om
+@@WAYPOINT-REVERSE-BUTTON@@	Keer volgorde punten om
+
+@@TRANSPORT-FOOT@@	Te voet
+@@TRANSPORT-HORSE@@	Paard
+@@TRANSPORT-WHEELCHAIR@@	Rolstoel
+@@TRANSPORT-BICYCLE@@	Fiets
+@@TRANSPORT-MOPED@@	Brommer
+@@TRANSPORT-MOTORCYCLE@@	Motorfiets
+@@TRANSPORT-MOTORCAR@@	Auto
+@@TRANSPORT-GOODS@@	Goederen
+@@TRANSPORT-HGV@@	Zwaar transport
+@@TRANSPORT-PSV@@	Publiek transport
+
+@@HIGHWAY-MOTORWAY@@	Autostrade
+@@HIGHWAY-TRUNK@@	Autoweg
+@@HIGHWAY-PRIMARY@@	Provinciale wegen
+@@HIGHWAY-SECONDARY@@	Nationale wegen
+@@HIGHWAY-TERTIARY@@	Doorgangsweg
+@@HIGHWAY-UNCLASSIFIED@@	Niet geclassificeerd
+@@HIGHWAY-RESIDENTIAL@@	Woongebied
+@@HIGHWAY-SERVICE@@	Toegangsweg
+@@HIGHWAY-TRACK@@	Veldweg
+@@HIGHWAY-CYCLEWAY@@	Fietspad
+@@HIGHWAY-PATH@@	Pad
+@@HIGHWAY-STEPS@@	Trap
+@@HIGHWAY-FERRY@@	Ferry
+
+@@PROPERTY-PAVED@@	Verhard
+@@PROPERTY-MULTILANE@@	Meerdere Stroken
+@@PROPERTY-BRIDGE@@	Brug
+@@PROPERTY-TUNNEL@@	Tunnel
+
+@@RESTRICT-ONEWAY@@	Volg Eenrichtingsverkeer
+@@RESTRICT-WEIGHT@@	Gewicht
+@@RESTRICT-HEIGHT@@	Hoogte
+@@RESTRICT-WIDTH@@	Breedte
+@@RESTRICT-LENGTH@@	Lengte
+
+@@FIND-SHORTEST-ROUTE@@	Zoek de kortste route
+@@FIND-QUICKEST-ROUTE@@	Zoek de snelste route
+
+@@EDIT-OSM-DATA@@	Lees hoe je OSM data kan inbrengen
+
+@@ROUTER-NOT-RUN@@	Router niet in gebruik
+@@ROUTER-RUNNING@@	Router werkt...
+@@ROUTER-COMPLETED@@	Routing voltooid
+@@ROUTER-ERROR@@	Router error
+@@ROUTER-FAILED@@	Router werkt niet
+
+@@HTML-ROUTE@@	HTML directions
+@@GPX-TRACK-ROUTE@@	GPX track bestand
+@@GPX-ROUTE@@	GPX route bestand
+@@FULL-TEXT-ROUTE@@	Volledig tekst bestand
+@@TEXT-ROUTE@@	Tekst bestand
+
+#
+# Visualiser specific translations
+#
+
+@@INSTRUCTIONS-BOX@@	Instructies
+
+@@NO-DATA-DISPLAYED@@	Geen data getoond
+
+@@SPEED-BUTTON@@	Toon snelheidslimieten
+
+@@WEIGHT-BUTTON@@	Toon massa limieten
+
+@@WEIGHT-LIMIT-8@@	8.0 ton massa limiet
+
+@@HEIGHT-BUTTON@@	Toon hoogte limieten
+
+@@HEIGHT-LIMIT-4@@	4.0 m hoogte limiet
+
+@@WIDTH-BUTTON@@	Toon breedte limieten
+
+@@WIDTH-LIMIT-3@@	3.0 m breedte limiet
+
+#
+# Multi-line descriptive translations (router)
+#
+
+$$ROUTER-INFO$$
+Zoom naar straatniveau.
+Selecteer start- and eindpunten onder Coordinaten. (click op het marker
+icoon links, schuif het op map naar gewenste positie).
+$$ROUTER-INFO$$
+
+$$ROUTER-OPTIONS-HELP$$
+<b>Quick Start</b>
+<br>
+Click op marker-icoontje (Waypoints) om ze op de map te plaatsen (rechts).
+Sleep ze vervolgens naar de gewenste positie.
+Het is best om eerst naar straat niveau te zoomen op de kaart.
+Selecteer het transport type, toegestane weg-types,
+snelheidslimieten, wegeigenschappen en andere restricties uit de
+opties.
+Selecteer  "Kortste" of "Snelste" om de route te berekenen en te tekenen op de map.
+<p>
+<b>Coordinaten (Waypoints)</b>
+<br>
+Click op het marker icoontje, nog eens clicken voor aan/uit.
+Wanneer de route berekend wordt, zal dit nauwkeurig aansluiten bij de volgorde van deze punten. (rekening houdend met transport type)
+<p>
+<b>Transport Type</b>
+<br>
+Wanneer je een bepaald transport type kiest wordt bij berekenen
+route hiermede rekening gehouden.
+Het transport type bestaat uit een lijst met default waarden voor
+ieder wegtype.
+Deze percentages kunnen ook nog eens manueel aangepast worden.
+<p>
+<b>Voorkeur Wegtype</b>
+<br>
+De voorkeur voor een bepaald type weg wordt uitgedrukt in een percentage.
+Bijvoorbeeld wanneer u het Transport Type "Fiets" kiest, dan zal er
+voor Autostrade 0% staan, en voor Fietspad 100%.
+Wanneer u Autowegen, Nationale wegen wil vermijden of beperken bij
+het maken van een fietsroute, kan u percentage naar beneden
+aanpassen.
+<p>
+<b>Snelheid limieten</b>
+<br>
+De snelheidslimieten worden afgeleid van het type weg. Het is
+mogelijk dat er voor een bepaalde weg andere beperkingen gelden. In
+dat geval worden die gekoezen. (het geval dat deze lager zijn dan de
+default)
+<p>
+<b>Weg Eigenschappen</b>
+<br>
+Voor het berekenen van de route, kan de de voorkeur gegeven worden
+aan een bepaalde wegeigenschap.
+Wanneer u kiest voor 25% verhard, zal er automatisch de voorkeur aan
+75% onverhard worden gegeven.
+Ook al is het onverharde stuk 3 X langer, toch kan er dan de
+voorkeur aan gegeven worden.
+<p>
+<b>Andere Beperkingen</b>
+<br>
+Deze zullen toelaten dat er een route berekend wordt die rekening
+houdt met gewicht, hoogte, breedte of lengte.
+Het is ook mogelijk geen rekening te houden met eenrichtingsverkeer
+(bijvoorbeeld als voetganger of fietser)
+$$ROUTER-OPTIONS-HELP$$
+
+$$ROUTER-RESULTS-HELP$$
+<b>Quick Start</b>
+<br>
+Na het berekenen van een route, kan het GPX bestand, of de beschrijving als tekstbestand downloaden.
+Door met muis over de beschrijving te bewegen, ziet u die ook op de kaart gesitueerd.
+<p>
+<b>Problem Solving</b>
+<br>
+Als de router eindigt met een fout, dan is de meest waarschijnlijke
+oorzaak, dat er geen route mogelijk is tussen de gekozen punten.
+Het verplaatsen van de punten, of het aanpassen van weg-eigenschappen
+of voertuigtype kan een oplossing bieden.
+<p>
+<b>Output Formats</b>
+<br>
+<dl>
+  <dt>HTML instructies
+  <dd>Een beschrijving van de route, met de te nemen afslag aan iedere splitsing.
+  <dt>GPX track bestand
+  <dd>Dezelfde informatie die op de kaart wordt weergegeven. Met
+    coordinaten voor ieder knooppunt, en een track voor ieder segment.
+  <dt>GPX route bestand
+  <dd>Dezelfde informatie dat is opgenomen in de tekst van de route,
+    met een coordinaat voor iedere belangrijke splitsing.
+  <dt>Full text bestand
+  <dd>Een lijst met alle coordinaten, met de afstand hier tussen. En
+    een cumulatieve afstand voor iedere stap op de route.
+  <dt>Text bestand
+  <dd>Dezelfde informatie als wordt weergegeven in de tekst voor de route.
+</dl>
+$$ROUTER-RESULTS-HELP$$
+
+$$ROUTER-VISUALISER-INFO$$
+Om te kijken hoe Routino omgaat met de basisdata,
+is er een tooltje dat de onderliggende data toont op verschillende manieren.
+$$ROUTER-VISUALISER-INFO$$
+
+#
+# Multi-line descriptive translations (visualiser)
+#
+
diff --git a/3rdparty/Routino/web/translations/translation.ru.txt b/3rdparty/Routino/web/translations/translation.ru.txt
new file mode 100644
index 0000000..4cf4fbf
--- /dev/null
+++ b/3rdparty/Routino/web/translations/translation.ru.txt
@@ -0,0 +1,168 @@
+#
+# Russian language translation phrases
+#
+
+#
+# Router output XML definition
+#
+
+%%copyright_creator_string%%	Автор
+%%copyright_source_string%%	Источник
+%%copyright_source_text%%	Использованы данные OpenStreetMap http://www.openstreetmap.org/
+%%copyright_license_string%%	Лицензия
+
+%%turn_-4%%	очень крутой поворот налево
+%%turn_-3%%	крутой поворот налево
+%%turn_-2%%	налево
+%%turn_-1%%	плавно налево
+%%turn_0%%	прямо
+%%turn_1%%	плавно направо
+%%turn_2%%	направо
+%%turn_3%%	крутой поворот направо
+%%turn_4%%	очень крутой поворот направо
+
+%%heading_-4%%	юг
+%%heading_-3%%	юго-запад
+%%heading_-2%%	запад
+%%heading_-1%%	северо-запад
+%%heading_0%%	север
+%%heading_1%%	северо-восток
+%%heading_2%%	восток
+%%heading_3%%	юго-восток
+%%heading_4%%	юг
+
+%%ordinal_1%%	Первый
+%%ordinal_2%%	Второй
+%%ordinal_3%%	Третий
+%%ordinal_4%%	Четвертый
+%%ordinal_5%%	Пятый
+%%ordinal_6%%	Шестой
+%%ordinal_7%%	Седьмой
+%%ordinal_8%%	Восьмой
+%%ordinal_9%%	Девятый
+%%ordinal_10%%	Десятый
+
+%%highway_motorway%%	автомагистраль
+%%highway_trunk%%	международная трасса
+%%highway_primary%%	дорога регионального значения
+%%highway_secondary%%	дорога областного значения
+%%highway_tertiary%%	дорога районного значения
+%%highway_unclassified%%	дорога местного значения
+%%highway_residential%%	улица
+%%highway_service%%	проезд
+%%highway_track%%	дорога с/х назначения
+%%highway_cycleway%%	велодорожка
+%%highway_path%%	тропинка
+%%highway_steps%%	лестница
+%%highway_ferry%%	паром
+
+%%route_shortest%%	Короткий
+%%route_quickest%%	Быстрый
+
+%%output-html_waypoint_waypoint%%	путевая точка
+%%output-html_waypoint_junction%%	перекрестке
+%%output-html_title%%	%s маршрут
+%%output-html_start_string%%	Старт
+%%output-html_start_text%%	 %s, на %s
+%%output-html_node_string%%	на
+%%output-html_node_text%%	%s, %s,  на %s
+%%output-html_rbnode_string%%	Покинуть
+%%output-html_segment_string%%	Следуйте
+%%output-html_segment_text%%	по %s %.3f км, %.1f мин
+%%output-html_stop_string%%	Стоп
+%%output-html_stop_text%%	 %s
+%%output-html_total_string%%	Всего
+%%output-html_total_text%%	%.1f км, %.0f минут
+
+%%output-gpx_waypoint_start%%	Старт
+%%output-gpx_waypoint_inter%%	INTER
+%%output-gpx_waypoint_trip%%	TRIP
+%%output-gpx_waypoint_finish%%	Финиш
+
+%%output-gpx_desc%%	%s маршрут от 'Старта' до 'Финиша'
+%%output-gpx_name%%	%s маршрут
+%%output-gpx_step%%	на %s по '%s' %.3f км, %.1f мин
+%%output-gpx_final%%	Всего - %.1f км, продолжительность - %.0f минут
+
+#
+# Router (and some shared) translations
+#
+
+@@LANGUAGE@@	Русский
+@@LANGUAGE-WEBPAGE@@	Русский
+
+@@OPTION-TAB-HELP@@	Задать настройки маршрутизации
+
+@@DOCUMENTATION@@	Документация
+
+@@LANGUAGE-BOX@@	Язык
+@@TRANSPORT-TYPE-BOX@@	Тип транспорта
+@@SPEED-LIMITS-BOX@@	Ограничения скорости
+@@OTHER-RESTRICTIONS-BOX@@	Другие ограничения
+@@HELP-BOX@@	Помощь
+
+@@STATUS-BOX@@	Статус
+@@SHORTEST-ROUTE@@	Кратчайший маршрут
+@@QUICKEST-ROUTE@@	Быстрейший маршрут
+
+@@TRANSPORT-HORSE@@	Лошадь
+@@TRANSPORT-WHEELCHAIR@@	Инвалидное кресло
+@@TRANSPORT-BICYCLE@@	Велосипед
+@@TRANSPORT-MOPED@@	Мопед
+@@TRANSPORT-MOTORCYCLE@@	Мотоцикл
+@@TRANSPORT-GOODS@@	Товары
+
+@@HIGHWAY-MOTORWAY@@	Автомагистраль
+
+@@PROPERTY-BRIDGE@@	Мост
+@@PROPERTY-TUNNEL@@	Туннель
+@@PROPERTY-WALKINGROUTE@@	Пеший маршрут
+@@PROPERTY-BICYCLEROUTE@@	Велодорожка
+
+@@RESTRICT-ONEWAY@@	Односторонняя улица
+@@RESTRICT-WEIGHT@@	Вес
+@@RESTRICT-HEIGHT@@	Высота
+@@RESTRICT-WIDTH@@	Ширина
+@@RESTRICT-LENGTH@@	Длина
+
+@@FIND-SHORTEST-ROUTE@@	Найти кратчайший маршрут
+@@FIND-QUICKEST-ROUTE@@	Найти быстрейший маршут
+
+@@TILES@@	Тайлы
+
+#
+# Visualiser specific translations
+#
+
+@@INSTRUCTIONS-BOX@@	Инструкции
+
+@@NO-DATA-DISPLAYED@@	Нет данных для отображения
+
+@@VISUALISER-NUM-NODES@@	Обработано # нод
+@@VISUALISER-NUM-TURNS@@	Обработано # ограничений поворотов
+
+@@TURNS-BUTTON@@	Показывать ограничения поворотов
+
+@@SPEED-BUTTON@@	Показывать ограничения скорости
+
+@@LIMIT-CHANGE@@	Изменить ограничения
+@@SPEED-LIMIT-80@@	Ограничение скорости 80 км/ч
+
+@@WEIGHT-BUTTON@@	Показывать ограничения по весу
+
+@@WEIGHT-LIMIT-8@@	Ограничение веса 8 тонн
+
+@@HEIGHT-BUTTON@@	Показывать ограничение по высоте
+
+@@HEIGHT-LIMIT-4@@	Ограничение высоты 4.0 метра
+
+@@WIDTH-BUTTON@@	Показывать ограничение ширины
+
+#
+# Multi-line descriptive translations (router)
+#
+
+#
+# Multi-line descriptive translations (visualiser)
+#
+
diff --git a/3rdparty/Routino/web/translations/translations-body.xml b/3rdparty/Routino/web/translations/translations-body.xml
new file mode 100644
index 0000000..7e0c153
--- /dev/null
+++ b/3rdparty/Routino/web/translations/translations-body.xml
@@ -0,0 +1,93 @@
+  <language lang="~~lang~~">
+
+    <!-- Copyright of the data being routed, not of this file  -->
+    <copyright>
+      <creator string="%%copyright_creator_string%%" text="Routino - http://www.routino.org/" />
+      <source  string="%%copyright_source_string%%" text="%%copyright_source_text%%" />
+      <license string="%%copyright_license_string%%" text="http://www.openstreetmap.org/copyright" />
+    </copyright>
+
+    <!-- Turn directions, 0 = ahead, -2 = left, +/-4 = behind, +2 = right -->
+    <turn direction="-4" string="%%turn_-4%%" />
+    <turn direction="-3" string="%%turn_-3%%" />
+    <turn direction="-2" string="%%turn_-2%%" />
+    <turn direction="-1" string="%%turn_-1%%" />
+    <turn direction="0"  string="%%turn_0%%" />
+    <turn direction="1"  string="%%turn_1%%" />
+    <turn direction="2"  string="%%turn_2%%" />
+    <turn direction="3"  string="%%turn_3%%" />
+    <turn direction="4"  string="%%turn_4%%" />
+
+    <!-- Heading directions, 0 = North, -2 = West, +/-4 = South, +2 = East -->
+    <heading direction="-4" string="%%heading_-4%%" />
+    <heading direction="-3" string="%%heading_-3%%" />
+    <heading direction="-2" string="%%heading_-2%%" />
+    <heading direction="-1" string="%%heading_-1%%" />
+    <heading direction="0"  string="%%heading_0%%" />
+    <heading direction="1"  string="%%heading_1%%" />
+    <heading direction="2"  string="%%heading_2%%" />
+    <heading direction="3"  string="%%heading_3%%" />
+    <heading direction="4"  string="%%heading_4%%" />
+
+    <!-- Ordinals, 1 = first, 2 = second ... -->
+    <ordinal number="1"  string="%%ordinal_1%%" />
+    <ordinal number="2"  string="%%ordinal_2%%" />
+    <ordinal number="3"  string="%%ordinal_3%%" />
+    <ordinal number="4"  string="%%ordinal_4%%" />
+    <ordinal number="5"  string="%%ordinal_5%%" />
+    <ordinal number="6"  string="%%ordinal_6%%" />
+    <ordinal number="7"  string="%%ordinal_7%%" />
+    <ordinal number="8"  string="%%ordinal_8%%" />
+    <ordinal number="9"  string="%%ordinal_9%%" />
+    <ordinal number="10" string="%%ordinal_10%%" />
+
+    <!-- Highway names -->
+    <highway type="motorway"     string="%%highway_motorway%%" />
+    <highway type="trunk"        string="%%highway_trunk%%" />
+    <highway type="primary"      string="%%highway_primary%%" />
+    <highway type="secondary"    string="%%highway_secondary%%" />
+    <highway type="tertiary"     string="%%highway_tertiary%%" />
+    <highway type="unclassified" string="%%highway_unclassified%%" />
+    <highway type="residential"  string="%%highway_residential%%" />
+    <highway type="service"      string="%%highway_service%%" />
+    <highway type="track"        string="%%highway_track%%" />
+    <highway type="cycleway"     string="%%highway_cycleway%%" />
+    <highway type="path"         string="%%highway_path%%" />
+    <highway type="steps"        string="%%highway_steps%%" />
+    <highway type="ferry"        string="%%highway_ferry%%" />
+
+    <!-- The type of route -->
+    <route type="shortest" string="%%route_shortest%%" /> <!-- For the description and route name -->
+    <route type="quickest" string="%%route_quickest%%" /> <!-- For the description and route name -->
+
+    <!-- HTML output -->
+    <output-html>
+      <waypoint type="waypoint"   string="%%output-html_waypoint_waypoint%%" /> <!-- For the chosen waypoints -->
+      <waypoint type="junction"   string="%%output-html_waypoint_junction%%" /> <!-- For the interesting junctions -->
+      <waypoint type="roundabout" string="%%output-html_waypoint_roundabout%%" /> <!-- For roundabouts -->
+
+      <title text="%%output-html_title%%" /> <!-- %s = [shortest|quickest] -->
+
+      <start   string="%%output-html_start_string%%" text="%%output-html_start_text%%" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [heading] -->
+      <node    string="%%output-html_node_string%%" text="%%output-html_node_text%%" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [turn], 3rd %s = [heading] -->
+      <rbnode  string="%%output-html_rbnode_string%%" text="%%output-html_rbnode_text%%" /> <!-- 1st %s = [roundabout], 2nd %s = [first|second|...], 3rd %s = [heading] -->
+      <segment string="%%output-html_segment_string%%" text="%%output-html_segment_text%%" /> <!-- 1st %s = street name -->
+      <stop    string="%%output-html_stop_string%%" text="%%output-html_stop_text%%" /> <!-- 1st %s = [waypoint|junction] -->
+      <total   string="%%output-html_total_string%%" text="%%output-html_total_text%%" />
+    </output-html>
+
+    <!-- GPX output -->
+    <output-gpx>
+      <waypoint type="start" string="%%output-gpx_waypoint_start%%" /> <!-- For the first route waypoint -->
+      <waypoint type="inter" string="%%output-gpx_waypoint_inter%%" /> <!-- For the intermediate route waypoints -->
+      <waypoint type="trip" string="%%output-gpx_waypoint_trip%%" /> <!-- For the other route points -->
+      <waypoint type="finish" string="%%output-gpx_waypoint_finish%%"/> <!-- For the last route waypoint -->
+
+      <desc  text="%%output-gpx_desc%%" /> <!-- %s = [shortest|quickest] -->
+      <name  text="%%output-gpx_name%%" /> <!-- %s = [shortest|quickest] -->
+      <step  text="%%output-gpx_step%%" /> <!-- 1st %s = [turn], 2nd %s = street name -->
+      <final text="%%output-gpx_final%%" />
+    </output-gpx>
+
+  </language>
+
diff --git a/3rdparty/Routino/web/translations/translations-head.xml b/3rdparty/Routino/web/translations/translations-head.xml
new file mode 100644
index 0000000..2c0e8d4
--- /dev/null
+++ b/3rdparty/Routino/web/translations/translations-head.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- ============================================================
+     An XML format file containing Routino output translations.
+
+     Part of the Routino routing software.
+     ============================================================
+     This file Copyright 2010-2014 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<routino-translations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                      xsi:noNamespaceSchemaLocation="http://www.routino.org/xml/routino-translations.xsd">
+
diff --git a/3rdparty/Routino/web/translations/translations-tail.xml b/3rdparty/Routino/web/translations/translations-tail.xml
new file mode 100644
index 0000000..7b07541
--- /dev/null
+++ b/3rdparty/Routino/web/translations/translations-tail.xml
@@ -0,0 +1 @@
+</routino-translations>
diff --git a/3rdparty/Routino/web/translations/visualiser.html b/3rdparty/Routino/web/translations/visualiser.html
new file mode 100644
index 0000000..8531e37
--- /dev/null
+++ b/3rdparty/Routino/web/translations/visualiser.html
@@ -0,0 +1,430 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="keywords" content="openstreetmap routino verifier">
+<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, user-scalable=no">
+
+<title>Routino : @@VISUALISER-TITLE@@</title>
+
+<!--
+ Routino data visualiser web page.
+
+ Part of the Routino routing software.
+
+ This file Copyright 2008-2014 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see http://www.gnu.org/licenses/.
+-->
+
+<!-- Page elements -->
+<script src="page-elements.js" type="text/javascript"></script>
+<link href="page-elements.css" type="text/css" rel="stylesheet">
+
+<!-- Router and visualiser shared features -->
+<link href="maplayout.css" type="text/css" rel="stylesheet">
+
+<!-- Visualiser specific features -->
+<script src="mapprops.js" type="text/javascript"></script>
+<link href="visualiser.css" type="text/css" rel="stylesheet">
+
+<!-- Map parameters -->
+<script src="mapprops.js" type="text/javascript"></script>
+
+<!-- Map loader -->
+<script src="maploader.js" type="text/javascript"></script>
+
+</head>
+<body onload="map_load('map_init();');">
+
+<!-- Left hand side of window - data panel -->
+
+<div class="left_panel">
+
+  <div class="tab_box">
+    <span id="tab_visualiser" onclick="tab_select('visualiser');" class="tab_selected"   title="Select data options">Visualiser</span>
+    <span id="tab_router"     onclick="tab_select('router');"     class="tab_unselected" title="Plan a route">Router</span>
+    <span id="tab_data"       onclick="tab_select('data');"       class="tab_unselected" title="View database information">Data</span>
+  </div>
+
+  <div class="tab_content" id="tab_visualiser_div">
+
+    <div class="hideshow_box">
+      <span class="hideshow_title">@@VISUALISER-BOX@@</span>
+      $$VISUALISER-INFO$$
+      <div class="center">
+        <a target="other" href="http://www.routino.org/">@@ROUTINO-WEBSITE@@</a>
+        |
+        <a target="other" href="documentation/">@@DOCUMENTATION@@</a>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_language_show" onclick="hideshow_show('language');" class="hideshow_show">+</span>
+      <span id="hideshow_language_hide" onclick="hideshow_hide('language');" class="hideshow_hide">-</span>
+      <span class="hideshow_title">@@LANGUAGE-BOX@@</span>
+
+      <div id="hideshow_language_div" style="display: none;">
+        <table>
+          **LANGUAGES-META**
+          <tr>
+            <td><a id="lang_~~lang~~_url" href="visualiser.html.~~lang~~" title="@@LANGUAGE-WEBPAGE@@">@@LANGUAGE@@</a>
+            <td>(~~LANG~~)
+          **LANGUAGES-META**
+        </table>
+        <a target="translation" href="http://www.routino.org/translations/">Routino Translations</a>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span class="hideshow_title">@@INSTRUCTIONS-BOX@@</span>
+      $$VISUALISER-INSTRUCTIONS$$
+    </div>
+
+    <div class="hideshow_box">
+      <span class="hideshow_title">@@STATUS-BOX@@</span>
+      <div id="result_status">
+        <div id="result_status_no_data">
+          <b><i>@@NO-DATA-DISPLAYED@@</i></b>
+        </div>
+        <div id="result_status_data"      style="display: none;">
+        </div>
+        <div id="result_status_failed"    style="display: none;">
+          <b>@@VISUALISER-FAILED@@</b>
+        </div>
+        <div id="result_status_junctions" style="display: none;">
+          <b>@@VISUALISER-NUM-JUNCTIONS@@</b>
+        </div>
+        <div id="result_status_super"     style="display: none;">
+          <b>@@VISUALISER-NUM-SUPER@@</b>
+        </div>
+        <div id="result_status_waytype"   style="display: none;">
+          <b>@@VISUALISER-NUM-WAYTYPE@@</b>
+        </div>
+        <div id="result_status_highway"   style="display: none;">
+          <b>@@VISUALISER-NUM-SEGMENTS@@</b>
+        </div>
+        <div id="result_status_transport" style="display: none;">
+          <b>@@VISUALISER-NUM-SEGMENTS@@</b>
+        </div>
+        <div id="result_status_barrier"   style="display: none;">
+          <b>@@VISUALISER-NUM-NODES@@</b>
+        </div>
+        <div id="result_status_turns"     style="display: none;">
+          <b>@@VISUALISER-NUM-TURNS@@</b>
+        </div>
+        <div id="result_status_limit"     style="display: none;">
+          <b>@@VISUALISER-NUM-LIMITS@@</b>
+        </div>
+        <div id="result_status_property"  style="display: none;">
+          <b>@@VISUALISER-NUM-SEGMENTS@@</b>
+        </div>
+        <div id="result_status_errorlogs" style="display: none;">
+          <b>@@VISUALISER-NUM-ERRORS@@</b>
+        </div>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_junctions_show" onclick="hideshow_show('junctions');" class="hideshow_show">+</span>
+      <span id="hideshow_junctions_hide" onclick="hideshow_hide('junctions');" class="hideshow_hide">-</span>
+      <input type="button" id="junctions" onclick="displayData('junctions');" value="@@JUNCTIONS-BUTTON@@">
+      <div id="hideshow_junctions_div" style="display: none;">
+        $$JUNCTIONS-INFO$$
+        <br>
+        <table>
+          <tr><td><img src="icons/ball-1.png" alt="1" ><td>@@JUNCTIONS-1@@
+          <tr><td><img src="icons/ball-2.png" alt="2" ><td>@@JUNCTIONS-2@@
+          <tr><td><img src="icons/ball-3.png" alt="3" ><td>@@JUNCTIONS-3@@
+          <tr><td><img src="icons/ball-4.png" alt="4" ><td>@@JUNCTIONS-4@@
+          <tr><td><img src="icons/ball-5.png" alt="5" ><td>@@JUNCTIONS-5@@
+          <tr><td><img src="icons/ball-6.png" alt="6" ><td>@@JUNCTIONS-6@@
+          <tr><td><img src="icons/ball-7.png" alt="7+"><td>@@JUNCTIONS-MORE@@
+        </table>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_super_show" onclick="hideshow_show('super');" class="hideshow_show">+</span>
+      <span id="hideshow_super_hide" onclick="hideshow_hide('super');" class="hideshow_hide">-</span>
+      <input type="button" id="super" onclick="displayData('super');" value="@@SUPER-BUTTON@@">
+      <div id="hideshow_super_div" style="display: none;">
+        $$SUPER-INFO$$
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_waytype_show" onclick="hideshow_show('waytype');" class="hideshow_show">+</span>
+      <span id="hideshow_waytype_hide" onclick="hideshow_hide('waytype');" class="hideshow_hide">-</span>
+      <input type="button" id="waytype" onclick="displayData('waytype');" value="@@WAYTYPE-BUTTON@@">
+      <div id="hideshow_waytype_div" style="display: none;">
+        $$WAYTYPE-INFO$$
+        <form name="waytypes" id="waytypes" action="#" method="get" onsubmit="return false;">
+          <table>
+            <tr><td>@@WAYTYPE-ONEWAY@@:         <td><input name="waytype" type="radio" value="oneway"        onchange="displayData('waytype');" checked>
+            <tr><td>@@WAYTYPE-CYCLE-BOTH-WAYS@@:<td><input name="waytype" type="radio" value="cyclebothways" onchange="displayData('waytype');">
+            <tr><td>@@WAYTYPE-ROUNDABOUT@@:     <td><input name="waytype" type="radio" value="roundabout"    onchange="displayData('waytype');">
+          </table>
+        </form>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_highway_show" onclick="hideshow_show('highway');" class="hideshow_show">+</span>
+      <span id="hideshow_highway_hide" onclick="hideshow_hide('highway');" class="hideshow_hide">-</span>
+      <input type="button" id="highway" onclick="displayData('highway');" value="@@HIGHWAY-BUTTON@@">
+      <div id="hideshow_highway_div" style="display: none;">
+        $$HIGHWAY-INFO$$
+        <form name="highways" id="highways" action="#" method="get" onsubmit="return false;">
+          <table>
+            <tr><td>@@HIGHWAY-MOTORWAY@@:    <td><input name="highway" type="radio" value="motorway"     onchange="displayData('highway');">
+            <tr><td>@@HIGHWAY-TRUNK@@:       <td><input name="highway" type="radio" value="trunk"        onchange="displayData('highway');">
+            <tr><td>@@HIGHWAY-PRIMARY@@:     <td><input name="highway" type="radio" value="primary"      onchange="displayData('highway');" checked>
+            <tr><td>@@HIGHWAY-SECONDARY@@:   <td><input name="highway" type="radio" value="secondary"    onchange="displayData('highway');">
+            <tr><td>@@HIGHWAY-TERTIARY@@:    <td><input name="highway" type="radio" value="tertiary"     onchange="displayData('highway');">
+            <tr><td>@@HIGHWAY-UNCLASSIFIED@@:<td><input name="highway" type="radio" value="unclassified" onchange="displayData('highway');">
+            <tr><td>@@HIGHWAY-RESIDENTIAL@@: <td><input name="highway" type="radio" value="residential"  onchange="displayData('highway');">
+            <tr><td>@@HIGHWAY-SERVICE@@:     <td><input name="highway" type="radio" value="service"      onchange="displayData('highway');">
+            <tr><td>@@HIGHWAY-TRACK@@:       <td><input name="highway" type="radio" value="track"        onchange="displayData('highway');">
+            <tr><td>@@HIGHWAY-CYCLEWAY@@:    <td><input name="highway" type="radio" value="cycleway"     onchange="displayData('highway');">
+            <tr><td>@@HIGHWAY-PATH@@:        <td><input name="highway" type="radio" value="path"         onchange="displayData('highway');">
+            <tr><td>@@HIGHWAY-STEPS@@:       <td><input name="highway" type="radio" value="steps"        onchange="displayData('highway');">
+            <tr><td>@@HIGHWAY-FERRY@@:       <td><input name="highway" type="radio" value="ferry"        onchange="displayData('highway');">
+          </table>
+        </form>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_transport_show" onclick="hideshow_show('transport');" class="hideshow_show">+</span>
+      <span id="hideshow_transport_hide" onclick="hideshow_hide('transport');" class="hideshow_hide">-</span>
+      <input type="button" id="transport" onclick="displayData('transport');" value="@@TRANSPORT-BUTTON@@">
+      <div id="hideshow_transport_div" style="display: none;">
+        $$TRANSPORT-INFO$$
+        <form name="transports" id="transports" action="#" method="get" onsubmit="return false;">
+          <table>
+            <tr><td>@@TRANSPORT-FOOT@@:      <td><input name="transport" type="radio" value="foot"       onchange="displayData('transport');">
+            <tr><td>@@TRANSPORT-HORSE@@:     <td><input name="transport" type="radio" value="horse"      onchange="displayData('transport');">
+            <tr><td>@@TRANSPORT-WHEELCHAIR@@:<td><input name="transport" type="radio" value="wheelchair" onchange="displayData('transport');">
+            <tr><td>@@TRANSPORT-BICYCLE@@:   <td><input name="transport" type="radio" value="bicycle"    onchange="displayData('transport');">
+            <tr><td>@@TRANSPORT-MOPED@@:     <td><input name="transport" type="radio" value="moped"      onchange="displayData('transport');">
+            <tr><td>@@TRANSPORT-MOTORCYCLE@@:<td><input name="transport" type="radio" value="motorcycle" onchange="displayData('transport');">
+            <tr><td>@@TRANSPORT-MOTORCAR@@:  <td><input name="transport" type="radio" value="motorcar"   onchange="displayData('transport');" checked>
+            <tr><td>@@TRANSPORT-GOODS@@:     <td><input name="transport" type="radio" value="goods"      onchange="displayData('transport');">
+            <tr><td>@@TRANSPORT-HGV@@:       <td><input name="transport" type="radio" value="hgv"        onchange="displayData('transport');">
+            <tr><td>@@TRANSPORT-PSV@@:       <td><input name="transport" type="radio" value="psv"        onchange="displayData('transport');">
+          </table>
+        </form>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_barrier_show" onclick="hideshow_show('barrier');" class="hideshow_show">+</span>
+      <span id="hideshow_barrier_hide" onclick="hideshow_hide('barrier');" class="hideshow_hide">-</span>
+      <input type="button" id="barrier" onclick="displayData('barrier');" value="@@BARRIER-BUTTON@@">
+      <div id="hideshow_barrier_div" style="display: none;">
+        $$BARRIER-INFO$$
+        <form name="barriers" id="barriers" action="#" method="get" onsubmit="return false;">
+          <table>
+            <tr><td>@@TRANSPORT-FOOT@@:      <td><input name="barrier" type="radio" value="foot"       onchange="displayData('barrier');">
+            <tr><td>@@TRANSPORT-HORSE@@:     <td><input name="barrier" type="radio" value="horse"      onchange="displayData('barrier');">
+            <tr><td>@@TRANSPORT-WHEELCHAIR@@:<td><input name="barrier" type="radio" value="wheelchair" onchange="displayData('barrier');">
+            <tr><td>@@TRANSPORT-BICYCLE@@:   <td><input name="barrier" type="radio" value="bicycle"    onchange="displayData('barrier');">
+            <tr><td>@@TRANSPORT-MOPED@@:     <td><input name="barrier" type="radio" value="moped"      onchange="displayData('barrier');">
+            <tr><td>@@TRANSPORT-MOTORCYCLE@@:<td><input name="barrier" type="radio" value="motorcycle" onchange="displayData('barrier');">
+            <tr><td>@@TRANSPORT-MOTORCAR@@:  <td><input name="barrier" type="radio" value="motorcar"   onchange="displayData('barrier');" checked>
+            <tr><td>@@TRANSPORT-GOODS@@:     <td><input name="barrier" type="radio" value="goods"      onchange="displayData('barrier');">
+            <tr><td>@@TRANSPORT-HGV@@:       <td><input name="barrier" type="radio" value="hgv"        onchange="displayData('barrier');">
+            <tr><td>@@TRANSPORT-PSV@@:       <td><input name="barrier" type="radio" value="psv"        onchange="displayData('barrier');">
+          </table>
+        </form>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_turns_show" onclick="hideshow_show('turns');" class="hideshow_show">+</span>
+      <span id="hideshow_turns_hide" onclick="hideshow_hide('turns');" class="hideshow_hide">-</span>
+      <input type="button" id="turns" onclick="displayData('turns');" value="@@TURNS-BUTTON@@">
+      <div id="hideshow_turns_div" style="display: none;">
+        $$TURNS-INFO$$
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_speed_show" onclick="hideshow_show('speed');" class="hideshow_show">+</span>
+      <span id="hideshow_speed_hide" onclick="hideshow_hide('speed');" class="hideshow_hide">-</span>
+      <input type="button" id="speed" onclick="displayData('speed');" value="@@SPEED-BUTTON@@">
+      <div id="hideshow_speed_div" style="display: none;">
+        $$SPEED-INFO$$
+        <br>
+        <table>
+          <tr><td><img src="icons/ball-1.png"   alt="."   ><td>@@LIMIT-CHANGE@@
+          <tr><td><img src="icons/limit-no.png" alt="()"  ><td>@@LIMIT-NONE@@
+          <tr><td><img src="icons/limit-80.png" alt="(80)"><td>@@SPEED-LIMIT-80@@
+        </table>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_weight_show" onclick="hideshow_show('weight');" class="hideshow_show">+</span>
+      <span id="hideshow_weight_hide" onclick="hideshow_hide('weight');" class="hideshow_hide">-</span>
+      <input type="button" id="weight" onclick="displayData('weight');" value="@@WEIGHT-BUTTON@@">
+      <div id="hideshow_weight_div" style="display: none;">
+        $$WEIGHT-INFO$$
+        <br>
+        <table>
+          <tr><td><img src="icons/ball-1.png"    alt="."    ><td>@@LIMIT-CHANGE@@
+          <tr><td><img src="icons/limit-no.png"  alt="()"   ><td>@@LIMIT-NONE@@
+          <tr><td><img src="icons/limit-8.0.png" alt="(8.0)"><td>@@WEIGHT-LIMIT-8@@
+        </table>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_height_show" onclick="hideshow_show('height');" class="hideshow_show">+</span>
+      <span id="hideshow_height_hide" onclick="hideshow_hide('height');" class="hideshow_hide">-</span>
+      <input type="button" id="height" onclick="displayData('height');" value="@@HEIGHT-BUTTON@@">
+      <div id="hideshow_height_div" style="display: none;">
+        $$HEIGHT-INFO$$
+        <br>
+        <table>
+          <tr><td><img src="icons/ball-1.png"    alt="."    ><td>@@LIMIT-CHANGE@@
+          <tr><td><img src="icons/limit-no.png"  alt="()"   ><td>@@LIMIT-NONE@@
+          <tr><td><img src="icons/limit-4.0.png" alt="(4.0)"><td>@@HEIGHT-LIMIT-4@@
+        </table>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_width_show" onclick="hideshow_show('width');" class="hideshow_show">+</span>
+      <span id="hideshow_width_hide" onclick="hideshow_hide('width');" class="hideshow_hide">-</span>
+      <input type="button" id="width" onclick="displayData('width');" value="@@WIDTH-BUTTON@@">
+      <div id="hideshow_width_div" style="display: none;">
+        $$WIDTH-INFO$$
+        <br>
+        <table>
+          <tr><td><img src="icons/ball-1.png"    alt="."    ><td>@@LIMIT-CHANGE@@
+          <tr><td><img src="icons/limit-no.png"  alt="()"   ><td>@@LIMIT-NONE@@
+          <tr><td><img src="icons/limit-3.0.png" alt="(3.0)"><td>@@WIDTH-LIMIT-3@@
+        </table>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_length_show" onclick="hideshow_show('length');" class="hideshow_show">+</span>
+      <span id="hideshow_length_hide" onclick="hideshow_hide('length');" class="hideshow_hide">-</span>
+      <input type="button" id="length" onclick="displayData('length');" value="@@LENGTH-BUTTON@@">
+      <div id="hideshow_length_div" style="display: none;">
+        $$LENGTH-INFO$$
+        <br>
+        <table>
+          <tr><td><img src="icons/ball-1.png"    alt="."    ><td>@@LIMIT-CHANGE@@
+          <tr><td><img src="icons/limit-no.png"  alt="()"   ><td>@@LIMIT-NONE@@
+          <tr><td><img src="icons/limit-9.0.png" alt="(9.0)"><td>@@LENGTH-LIMIT-9@@
+        </table>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_property_show" onclick="hideshow_show('property');" class="hideshow_show">+</span>
+      <span id="hideshow_property_hide" onclick="hideshow_hide('property');" class="hideshow_hide">-</span>
+      <input type="button" id="property" onclick="displayData('property');" value="@@PROPERTY-BUTTON@@">
+      <div id="hideshow_property_div" style="display: none;">
+        $$PROPERTY-INFO$$
+        <form name="properties" id="properties" action="#" method="get" onsubmit="return false;">
+          <table>
+            <tr><td>@@PROPERTY-PAVED@@:         <td><input name="property" type="radio" value="paved"         onchange="displayData('property');" checked>
+            <tr><td>@@PROPERTY-MULTILANE@@:     <td><input name="property" type="radio" value="multilane"     onchange="displayData('property');">
+            <tr><td>@@PROPERTY-BRIDGE@@:        <td><input name="property" type="radio" value="bridge"        onchange="displayData('property');">
+            <tr><td>@@PROPERTY-TUNNEL@@:        <td><input name="property" type="radio" value="tunnel"        onchange="displayData('property');">
+            <tr><td>@@PROPERTY-WALKINGROUTE@@:  <td><input name="property" type="radio" value="footroute"     onchange="displayData('property');">
+            <tr><td>@@PROPERTY-BICYCLEROUTE@@:  <td><input name="property" type="radio" value="bicycleroute"  onchange="displayData('property');">
+          </table>
+        </form>
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_errorlogs_show" onclick="hideshow_show('errorlogs');" class="hideshow_show">+</span>
+      <span id="hideshow_errorlogs_hide" onclick="hideshow_hide('errorlogs');" class="hideshow_hide">-</span>
+      <input type="button" id="errorlogs" onclick="displayData('errorlogs');" value="@@ERROR-LOG-BUTTON@@">
+      <div id="hideshow_errorlogs_div" style="display: none;">
+        $$ERROR-LOG-INFO$$
+      </div>
+    </div>
+
+    <div class="hideshow_box">
+      <input type="button" id="clear" onclick="displayData('');" value="@@CLEAR-DATA-BUTTON@@">
+    </div>
+
+    <div class="hideshow_box">
+      <span class="hideshow_title">@@LINKS-BOX@@</span>
+      <a id="permalink_url" href="visualiser.html">@@MAP-VIEW-LINK@@</a>
+      <br>
+      <a id="edit_url" target="edit" style="display: none;">@@EDIT-OSM-DATA@@</a>
+    </div>
+
+    <div class="hideshow_box">
+      <span id="hideshow_help_options_show" onclick="hideshow_show('help_options');" class="hideshow_hide">+</span>
+      <span id="hideshow_help_options_hide" onclick="hideshow_hide('help_options');" class="hideshow_show">-</span>
+      <span class="hideshow_title">@@HELP-BOX@@</span>
+      <div id="hideshow_help_options_div">
+        <div class="scrollable">
+          $$VISUALISER-HELP$$
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <div class="tab_content" id="tab_router_div" style="display: none;">
+    <div class="hideshow_box">
+      <span class="hideshow_title">@@ROUTER-BOX@@</span>
+      $$VISUALISER-ROUTER-INFO$$
+      <br>
+      <a id="router_url" href="router.html" target="router">@@MAP-VIEW-LINK@@</a>
+    </div>
+  </div>
+
+  <div class="tab_content" id="tab_data_div" style="display: none;">
+    <div class="hideshow_box">
+      <span class="hideshow_title">@@STATISTICS-BOX@@</span>
+      <div id="statistics_data"></div>
+      <a id="statistics_link" href="statistics.cgi" onclick="displayStatistics();return(false);">@@DISPLAY-STATISTICS@@</a>
+    </div>
+  </div>
+
+</div>
+
+<!-- Right hand side of window - map -->
+
+<div class="right_panel">
+  <div class="map" id="map">
+    <noscript>
+      <p>
+        @@JAVASCRIPT-REQUIRED@@
+    </noscript>
+  </div>
+  <div class="attribution">
+    @@ROUTER@@: <a href="http://www.routino.org/" target="routino">Routino</a>
+    |
+    @@GEO-DATA@@: <span id="attribution_data"></span>
+    |
+    @@TILES@@: <span id="attribution_tile"></span>
+  </div>
+</div>
+
+</body>
+
+</html>
diff --git a/3rdparty/Routino/web/www/leaflet/install.sh b/3rdparty/Routino/web/www/leaflet/install.sh
new file mode 100755
index 0000000..1361ad0
--- /dev/null
+++ b/3rdparty/Routino/web/www/leaflet/install.sh
@@ -0,0 +1,11 @@
+#!/bin/sh -x
+
+version=0.7.3
+
+# Download the file.
+
+wget http://leaflet-cdn.s3.amazonaws.com/build/leaflet-$version.zip
+
+# Uncompress it.
+
+unzip leaflet-$version.zip
diff --git a/3rdparty/Routino/web/www/openlayers/install.sh b/3rdparty/Routino/web/www/openlayers/install.sh
new file mode 100755
index 0000000..01cc302
--- /dev/null
+++ b/3rdparty/Routino/web/www/openlayers/install.sh
@@ -0,0 +1,25 @@
+#!/bin/sh -x
+
+version=2.13.1
+
+# Download the file.
+
+wget http://openlayers.org/download/OpenLayers-$version.tar.gz
+
+# Uncompress it.
+
+tar -xzf OpenLayers-$version.tar.gz
+
+# Create a custom OpenLayers file
+
+(cd OpenLayers-$version/build && python build.py ../../routino.cfg && cp OpenLayers.js ..)
+
+# Copy the files.
+
+cp -p  OpenLayers-$version/OpenLayers.js .
+cp -pr OpenLayers-$version/img .
+cp -pr OpenLayers-$version/theme .
+
+# Delete the remainder
+
+rm -rf OpenLayers-$version
diff --git a/3rdparty/Routino/web/www/openlayers/routino.cfg b/3rdparty/Routino/web/www/openlayers/routino.cfg
new file mode 100644
index 0000000..278e0c6
--- /dev/null
+++ b/3rdparty/Routino/web/www/openlayers/routino.cfg
@@ -0,0 +1,45 @@
+# This is a configuration file to allow building an optimised OpenLayers
+# Javascript file that contains all of the features required for Routino.
+
+[first]
+OpenLayers/SingleFile.js
+OpenLayers.js
+OpenLayers/BaseTypes.js
+OpenLayers/BaseTypes/Class.js
+OpenLayers/Util.js
+
+[last]
+
+[include]
+OpenLayers/BaseTypes/LonLat.js
+OpenLayers/BaseTypes/Bounds.js
+OpenLayers/Control/DragFeature.js
+OpenLayers/Control/LayerSwitcher.js
+OpenLayers/Control/Navigation.js
+OpenLayers/Control/PanZoomBar.js
+OpenLayers/Control/PinchZoom.js
+OpenLayers/Control/SelectFeature.js
+OpenLayers/Control/ScaleLine.js
+OpenLayers/Feature/Vector.js
+OpenLayers/Format/GPX.js
+OpenLayers/Geometry/LineString.js
+OpenLayers/Geometry/Point.js
+OpenLayers/Geometry/Polygon.js
+OpenLayers/Layer/Boxes.js
+OpenLayers/Layer/SphericalMercator.js
+OpenLayers/Layer/TMS.js
+OpenLayers/Layer/Vector.js
+OpenLayers/Map.js
+OpenLayers/Marker/Box.js
+OpenLayers/Projection.js
+OpenLayers/Protocol/HTTP.js
+OpenLayers/Renderer/Elements.js
+OpenLayers/Renderer/Canvas.js
+OpenLayers/Renderer/SVG.js
+OpenLayers/Renderer/VML.js
+OpenLayers/Request/XMLHttpRequest.js
+OpenLayers/Strategy/Fixed.js
+OpenLayers/Rule.js
+OpenLayers/Style.js
+
+[exclude]
diff --git a/3rdparty/Routino/web/www/routino/.htaccess b/3rdparty/Routino/web/www/routino/.htaccess
new file mode 100644
index 0000000..29ea962
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/.htaccess
@@ -0,0 +1,40 @@
+##
+## Options for Apache web server for language specific web pages and to run
+## Routino CGI scripts.
+##
+
+# The translated router pages use the MultiViews option to serve up a version of
+# the web page depending on the client language preference.  If the line below
+# is used in a .htaccess file like this one and the "AllowOverride none" option
+# is set in the main Apache configuration file then the entry in the .htaccess
+# file will not work.
+
+#Options +MultiViews
+
+# The English language option will be served if there is no other version
+# present and no errors will be returned to the user in case of problems
+
+LanguagePriority en
+ForceLanguagePriority Prefer Fallback
+
+# The Routino CGI scripts are stored in this directory and use the filename
+# extension ".cgi".  This filename extension needs to be registered with Apache
+# for the scripts to be executed.
+
+AddHandler cgi-script .cgi
+
+# The ExecCGI option must be set for the CGIs in this directory to be executed
+# by Apache.  If the line below is used in a .htaccess file like this one and
+# the "AllowOverride none" option is set in the main Apache configuration file
+# then the entry in the .htaccess file will not work.
+
+#Options +ExecCGI
+
+# The CGI scripts that are used by Routino also call some other Perl scripts, to
+# stop these scripts from being seen by web users they can be denied by the
+# following entry.
+
+<FilesMatch .*\.pl$>
+   Order deny,allow
+   Deny from all
+</FilesMatch>
diff --git a/3rdparty/Routino/web/www/routino/icons/create-icons.pl b/3rdparty/Routino/web/www/routino/icons/create-icons.pl
new file mode 100755
index 0000000..f0f6364
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/icons/create-icons.pl
@@ -0,0 +1,179 @@
+#!/usr/bin/perl
+#
+# Routino icons Perl script
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2012 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use Graphics::Magick;
+
+# Markers for routing
+
+ at names=("red","grey");
+ at borders=("black","grey");
+ at letters=("red","grey");
+
+foreach $character (1..99,'home','XXX')
+  {
+   foreach $colour (0..$#names)
+     {
+      $image=Graphics::Magick->new;
+      $image->Set(size => "63x75");
+
+      $image->ReadImage('xc:white');
+      $image->Transparent('white');
+
+      $image->Draw(primitive => polygon, points => '1,32 32,73 61,32 32,10',
+                   stroke => $borders[$colour], fill => 'white', strokewidth => 6,
+                   antialias => 'false');
+
+      $image->Draw(primitive => arc,     points => '1,1 61,61 -180,0',
+                   stroke => $borders[$colour], fill => 'white', strokewidth => 6,
+                   antialias => 'false');
+
+      if($character eq 'home')
+        {
+         $home=Graphics::Magick->new;
+
+         $home->ReadImage("home.png");
+
+         $home->Opaque(fill => $names[$colour], color => 'black');
+
+         $image->Composite(image => $home, compose => Over,
+                           x => 32-$home->Get('width')/2, y => 26-$home->Get('height')/2);
+        }
+      elsif($character eq 'XXX')
+        {
+         ($x_ppem, $y_ppem, $ascender, $descender, $width, $height, $max_advance) = 
+           $image->QueryFontMetrics(text => $character, font => 'Helvetica', pointsize => '36');
+
+         $image->Annotate(text => "X", font => 'Helvetica', pointsize => '36',
+                          stroke => $letters[$colour], fill => $letters[$colour],
+                          x => 32, y => 32-$descender, align => Center,
+                          antialias => 'false');
+        }
+      elsif($character>=0 && $character<=9)
+        {
+         ($x_ppem, $y_ppem, $ascender, $descender, $width, $height, $max_advance) = 
+           $image->QueryFontMetrics(text => $character, font => 'Helvetica', pointsize => '36');
+
+         $image->Annotate(text => $character, font => 'Helvetica', pointsize => '36',
+                          stroke => $letters[$colour], fill => $letters[$colour],
+                          x => 32, y => 32-$descender, align => Center,
+                          antialias => 'false');
+        }
+      else
+        {
+         ($x_ppem, $y_ppem, $ascender, $descender, $width, $height, $max_advance) = 
+           $image->QueryFontMetrics(text => $character, font => 'Helvetica', pointsize => '32');
+
+         $image->Annotate(text => $character, font => 'Helvetica', pointsize => '32',
+                          stroke => $letters[$colour], fill => $letters[$colour],
+                          x => 32, y => 32-$descender, align => Center,
+                          antialias => 'false');
+        }
+
+      $image->Resize(width => 21, height => 25);
+
+      $image->Write("marker-$character-$names[$colour].png");
+
+      undef $image;
+     }
+  }
+
+# Balls for visualiser descriptions
+
+ at colours=("#FFFFFF",
+          "#FF0000",
+          "#FFFF00",
+          "#00FF00",
+          "#8B4513",
+          "#00BFFF",
+          "#FF69B4",
+          "#000000",
+          "#000000",
+          "#000000");
+
+foreach $colour (0..9)
+  {
+   $image=Graphics::Magick->new;
+   $image->Set(size => "9x9");
+
+   $image->ReadImage('xc:white');
+   $image->Transparent('white');
+
+   $image->Draw(primitive => circle, points => '4,4 4,8',
+                fill => $colours[$colour], stroke => $colours[$colour],
+                antialias => 'false');
+
+   $image->Write("ball-$colour.png");
+
+   undef $image;
+  }
+
+# Limit signs
+
+foreach $limit (1..200)
+  {
+   &draw_limit($limit);
+  }
+
+foreach $limit (1..400)
+  {
+   &draw_limit(sprintf "%.1f",$limit/10);
+  }
+
+&draw_limit("no");
+
+unlink "limit-0.png";
+link "limit-no.png","limit-0.png";
+
+unlink "limit-0.0.png";
+link "limit-no.png","limit-0.0.png";
+
+sub draw_limit
+  {
+   ($limit)=@_;
+
+   $image=Graphics::Magick->new;
+   $image->Set(size => "57x57");
+
+   $image->ReadImage('xc:white');
+   $image->Transparent('white');
+
+   $image->Draw(primitive => circle, points => '28,28 28,55',
+                stroke => 'red', fill => 'white', strokewidth => 3,
+                antialias => 'false');
+
+   if($limit ne "no")
+     {
+      ($x_ppem, $y_ppem, $ascender, $descender, $width, $height, $max_advance) =
+        $image->QueryFontMetrics(text => "$limit", font => 'Helvetica', pointsize => '22');
+
+      $image->Annotate(text => "$limit", font => 'Helvetica', pointsize => '22',
+                       stroke => 'black', fill => 'black',
+                       x => 28, y => 28-$descender, align => Center,
+                       antialias => 'false');
+     }
+
+   $image->Resize(width => 19, height => 19);
+
+   $image->Write("limit-$limit.png");
+
+   undef $image;
+  }
diff --git a/3rdparty/Routino/web/www/routino/icons/home.png b/3rdparty/Routino/web/www/routino/icons/home.png
new file mode 100644
index 0000000..1a7c261
Binary files /dev/null and b/3rdparty/Routino/web/www/routino/icons/home.png differ
diff --git a/3rdparty/Routino/web/www/routino/icons/waypoint-add.png b/3rdparty/Routino/web/www/routino/icons/waypoint-add.png
new file mode 100644
index 0000000..d7f04d7
Binary files /dev/null and b/3rdparty/Routino/web/www/routino/icons/waypoint-add.png differ
diff --git a/3rdparty/Routino/web/www/routino/icons/waypoint-centre.png b/3rdparty/Routino/web/www/routino/icons/waypoint-centre.png
new file mode 100644
index 0000000..9454b5f
Binary files /dev/null and b/3rdparty/Routino/web/www/routino/icons/waypoint-centre.png differ
diff --git a/3rdparty/Routino/web/www/routino/icons/waypoint-coords.png b/3rdparty/Routino/web/www/routino/icons/waypoint-coords.png
new file mode 100644
index 0000000..0a65d81
Binary files /dev/null and b/3rdparty/Routino/web/www/routino/icons/waypoint-coords.png differ
diff --git a/3rdparty/Routino/web/www/routino/icons/waypoint-down.png b/3rdparty/Routino/web/www/routino/icons/waypoint-down.png
new file mode 100644
index 0000000..af32977
Binary files /dev/null and b/3rdparty/Routino/web/www/routino/icons/waypoint-down.png differ
diff --git a/3rdparty/Routino/web/www/routino/icons/waypoint-home.png b/3rdparty/Routino/web/www/routino/icons/waypoint-home.png
new file mode 100644
index 0000000..a052025
Binary files /dev/null and b/3rdparty/Routino/web/www/routino/icons/waypoint-home.png differ
diff --git a/3rdparty/Routino/web/www/routino/icons/waypoint-left.png b/3rdparty/Routino/web/www/routino/icons/waypoint-left.png
new file mode 100644
index 0000000..17c972f
Binary files /dev/null and b/3rdparty/Routino/web/www/routino/icons/waypoint-left.png differ
diff --git a/3rdparty/Routino/web/www/routino/icons/waypoint-locate.png b/3rdparty/Routino/web/www/routino/icons/waypoint-locate.png
new file mode 100644
index 0000000..b6a4ecd
Binary files /dev/null and b/3rdparty/Routino/web/www/routino/icons/waypoint-locate.png differ
diff --git a/3rdparty/Routino/web/www/routino/icons/waypoint-recentre.png b/3rdparty/Routino/web/www/routino/icons/waypoint-recentre.png
new file mode 100644
index 0000000..f3c6f0b
Binary files /dev/null and b/3rdparty/Routino/web/www/routino/icons/waypoint-recentre.png differ
diff --git a/3rdparty/Routino/web/www/routino/icons/waypoint-remove.png b/3rdparty/Routino/web/www/routino/icons/waypoint-remove.png
new file mode 100644
index 0000000..f51ba5b
Binary files /dev/null and b/3rdparty/Routino/web/www/routino/icons/waypoint-remove.png differ
diff --git a/3rdparty/Routino/web/www/routino/icons/waypoint-right.png b/3rdparty/Routino/web/www/routino/icons/waypoint-right.png
new file mode 100644
index 0000000..8a0f516
Binary files /dev/null and b/3rdparty/Routino/web/www/routino/icons/waypoint-right.png differ
diff --git a/3rdparty/Routino/web/www/routino/icons/waypoint-search.png b/3rdparty/Routino/web/www/routino/icons/waypoint-search.png
new file mode 100644
index 0000000..4ab5b69
Binary files /dev/null and b/3rdparty/Routino/web/www/routino/icons/waypoint-search.png differ
diff --git a/3rdparty/Routino/web/www/routino/icons/waypoint-up.png b/3rdparty/Routino/web/www/routino/icons/waypoint-up.png
new file mode 100644
index 0000000..8696488
Binary files /dev/null and b/3rdparty/Routino/web/www/routino/icons/waypoint-up.png differ
diff --git a/3rdparty/Routino/web/www/routino/index.html b/3rdparty/Routino/web/www/routino/index.html
new file mode 100644
index 0000000..4d41b24
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/index.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<meta http-equiv="refresh" content="1; URL=router.html">
+
+<title>Routino : Route Planner for OpenStreetMap Data</title>
+
+<!--
+ Routino redirect web page.
+
+ Part of the Routino routing software.
+
+ This file Copyright 2008-2015 Andrew M. Bishop
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see http://www.gnu.org/licenses/.
+-->
+
+<link href="documentation/style.css" type="text/css" rel="stylesheet">
+</head>
+
+<body>
+
+<!-- Header Start -->
+
+<div class="header">
+
+<h1>Routino : Route Planner for OpenStreetMap Data</h1>
+
+</div>
+
+<!-- Header End -->
+
+<!-- Content Start -->
+
+<div class="content">
+
+<h2><a href="router.html" title="Page Moved">Page Moved</a></h2>
+
+</div>
+
+<!-- Content End -->
+
+<!-- Footer Start -->
+
+<div class="footer">
+
+<address>
+© Andrew M. Bishop - <a href="http://www.routino.org/">http://www.routino.org/</a>
+</address>
+
+</div>
+
+<!-- Footer End -->
+
+</body>
+
+</html>
diff --git a/3rdparty/Routino/web/www/routino/maplayout.css b/3rdparty/Routino/web/www/routino/maplayout.css
new file mode 100644
index 0000000..511a9c4
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/maplayout.css
@@ -0,0 +1,111 @@
+/*
+// Routino map layout web page style sheet.
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2014 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*----------------------------------*/
+/* Body HTML formatting             */
+/*----------------------------------*/
+
+BODY
+{
+ /* fonts and text styles */
+
+ font-family: sans-serif;
+ font-size:   12px;
+
+ /* colours */
+
+ background-color: white;
+ color:            black;
+}
+
+
+/*------------*/
+/* Left panel */
+/*------------*/
+
+DIV.left_panel
+{
+ width:    23em;
+
+ position: absolute;
+ top:      0;
+ bottom:   0;
+ right:    auto;
+ left:     0;
+
+ padding: 3px;
+}
+
+
+/*-------------*/
+/* Right panel */
+/*-------------*/
+
+DIV.right_panel
+{
+ position: fixed;
+ top:      0;
+ bottom:   0;
+ right:    0;
+ left:     23.5em;
+}
+
+DIV.map
+{
+ position: absolute;
+ top:      0;
+ bottom:   1.5em;
+ right:    0;
+ left:     0;
+
+ border:  3px solid;
+
+ text-align:  center;
+}
+
+DIV.attribution
+{
+ position: absolute;
+ top:      auto;
+ bottom:   0;
+ right:    0;
+ left:     0;
+
+ margin:  0px;
+ border:  0px;
+ padding: 0px;
+
+ text-align: center;
+
+ white-space: nowrap;
+ overflow:    hidden;
+}
+
+
+/*-----------------------------*/
+/* Leaflet base layer selector */
+/*-----------------------------*/
+
+FORM.leaflet-control-layers-list
+{
+ text-align: left;
+}
diff --git a/3rdparty/Routino/web/www/routino/maploader.js b/3rdparty/Routino/web/www/routino/maploader.js
new file mode 100644
index 0000000..dba3c54
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/maploader.js
@@ -0,0 +1,63 @@
+////////////////////////////////////////////////////////////////////////////////
+///////////////////// Map loader (OpenLayers or Leaflet) ///////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+
+function map_load(callbacks)
+{
+ var pending=1;
+ var head = document.getElementsByTagName("head")[0];
+
+ /* Call the callbacks when everything is loaded. */
+
+ function call_callbacks()
+ {
+  if(!--pending)
+     eval(callbacks);
+ }
+
+ /* Javascript loader */
+
+ function load_js(url)
+ {
+  var script = document.createElement("script");
+  script.src = url;
+  script.type = "text/javascript";
+
+  script.onload = call_callbacks;
+
+  pending++;
+
+  head.appendChild(script);
+ }
+
+ /* CSS loader */
+
+ function load_css(url)
+ {
+  var link = document.createElement("link");
+  link.href = url;
+  link.type = "text/css";
+  link.rel = "stylesheet";
+
+  head.appendChild(link);
+ }
+
+ /* Load the external library and local code */
+
+ if(mapprops.library == "leaflet")
+   {
+    load_css("../leaflet/leaflet.css");
+    load_js("../leaflet/leaflet.js");
+
+    load_js(location.pathname.replace(/\.html.*/,".leaflet.js"));
+   }
+ else
+   {
+    load_js("../openlayers/OpenLayers.js");
+
+    load_js(location.pathname.replace(/\.html.*/,".openlayers.js"));
+   }
+
+ call_callbacks();
+}
diff --git a/3rdparty/Routino/web/www/routino/mapprops.js b/3rdparty/Routino/web/www/routino/mapprops.js
new file mode 100644
index 0000000..d2a19c9
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/mapprops.js
@@ -0,0 +1,83 @@
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////// Routino map properties /////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+var mapprops={ // contains all properties for the map to be displayed.
+
+ // EDIT THIS below to change the map library (either 'openlayers' or 'leaflet').
+
+  library: "openlayers",
+  //library: "leaflet",
+
+ // EDIT THIS above to change the map library (either 'openlayers' or 'leaflet').
+
+
+ // EDIT THIS below to change the visible map limits
+
+  westedge:  -11.0,          // Minimum longitude (degrees)
+  eastedge:    2.0,          // Maximum longitude (degrees)
+
+  southedge:  49.5,          // Minimum latitude (degrees)
+  northedge:  61.0,          // Maximum latitude (degrees)
+
+  zoomout:       4,          // Minimum zoom
+  zoomin:       15,          // Maximum zoom
+
+ // EDIT THIS above to change the visible map limits
+
+
+ // EDIT THIS below to change the map URL(s) and copyright notices
+
+  mapdata: [
+           {
+            label: "OpenStreetMap",
+            tiles: {
+                    url: "http://${s}.tile.openstreetmap.org/${z}/${x}/${y}.png",
+                    subdomains: ["a","b","c"]
+                   },
+            attribution: {
+                          data_url:  "http://www.openstreetmap.org/copyright",
+                          data_text: "© OpenStreetMap contributors",
+                          tile_url:  "http://www.openstreetmap.org/copyright",
+                          tile_text: "© OpenStreetMap"
+                         }
+           },
+           {
+            label: "MapQuest",
+            tiles: {
+                    url: "http://otile${s}.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.jpg",
+                    subdomains: ["1","2","3","4"]
+                   },
+            attribution: {
+                          data_url:  "http://www.openstreetmap.org/copyright",
+                          data_text: "© OpenStreetMap contributors",
+                          tile_url:  "http://www.mapquest.com/",
+                          tile_text: "© MapQuest <img src=\"http://developer.mapquest.com/content/osm/mq_logo.png\">"
+                         }
+           }
+           ],
+
+ // EDIT THIS above to change the map URL(s) and copyright notices
+
+
+ // EDIT THIS below to change the map source data editing URL (or leave blank for no link)
+
+  editurl: "http://www.openstreetmap.org/edit",
+
+ // EDIT THIS above to change the map source data editing URL (or leave blank for no link)
+
+
+ // EDIT THIS below to change the map source data browsing URL (or leave blank for no link)
+
+  browseurl: "http://www.openstreetmap.org/browse",
+
+ // EDIT THIS above to change the map source data browsing URL (or leave blank for no link)
+
+
+ // EDIT THIS below to change the maximum number of markers to include in the HTML
+
+  maxmarkers: 9
+
+ // EDIT THIS above to change the maximum number of markers to include in the HTML
+
+}; // end of map properties
diff --git a/3rdparty/Routino/web/www/routino/page-elements.css b/3rdparty/Routino/web/www/routino/page-elements.css
new file mode 100644
index 0000000..449593c
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/page-elements.css
@@ -0,0 +1,152 @@
+/*
+// Style sheet for page elements.
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2014 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*-------------*/
+/* Tabbed DIVs */
+/*-------------*/
+
+
+DIV.tab_box
+{
+ padding:    3px;
+ margin-top: 3px;
+
+ width: 100%;
+}
+
+DIV.tab_box SPAN.tab_selected
+{
+ border-top:    2px solid;
+ border-left:   2px solid;
+ border-right:  2px solid;
+ border-bottom: 1px solid white;
+
+ z-index: 5;
+
+ padding-top:    3px;
+ padding-bottom: 3px;
+ padding-right:  5px;
+ padding-left:   5px;
+
+ font-weight: bold;
+ font-variant: small-caps;
+
+ background: #FFF;
+}
+
+DIV.tab_box SPAN.tab_unselected
+{
+ border-top:   1px solid;
+ border-left:  1px solid;
+ border-right: 1px solid;
+
+ padding-top:    3px;
+ padding-bottom: 3px;
+ padding-right:  5px;
+ padding-left:   5px;
+
+ cursor: pointer;
+
+ font-variant: small-caps;
+
+ background: #CCC;
+}
+
+DIV.tab_box SPAN.tab_unselected:hover
+{
+ background: #DDD;
+}
+
+DIV.tab_content
+{
+ width:  auto;
+
+ padding: 3px;
+ border: thin solid;
+}
+
+
+/*----------------*/
+/* Show/Hide DIVs */
+/*----------------*/
+
+
+DIV.hideshow_box
+{
+ min-height: 1em;
+
+ border-top:   2px solid;
+ border-color: #AAA;
+
+ padding-bottom: 2px;
+
+ overflow: hidden;
+}
+
+DIV.hideshow_box:first-child
+{
+ border-top: none;
+}
+
+DIV.hideshow_box SPAN.hideshow_show
+{
+ float: right;
+ display: block;
+
+ font-weight: bold;
+
+ text-align: center;
+
+ width: 1em;
+
+ padding-right:  5px;
+ padding-left:   5px;
+ padding-top:    1px;
+ padding-bottom: 1px;
+
+ cursor: pointer;
+
+ background: #CCC;
+}
+
+DIV.hideshow_box SPAN.hideshow_show:hover
+{
+ background: #DDD;
+}
+
+DIV.hideshow_box SPAN.hideshow_hide
+{
+ display: none;
+}
+
+SPAN.hideshow_title
+{
+ display: block;
+
+ font-weight: bold;
+ text-decoration: underline;
+
+ padding-top:    1px;
+ padding-bottom: 1px;
+
+ background: #EEE;
+}
diff --git a/3rdparty/Routino/web/www/routino/page-elements.js b/3rdparty/Routino/web/www/routino/page-elements.js
new file mode 100644
index 0000000..427f9be
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/page-elements.js
@@ -0,0 +1,94 @@
+//
+// Javascript for page elements.
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2014 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+//
+// Display one of the tabs and associated DIV and hide the others
+//
+
+function tab_select(name)
+{
+ var tab=document.getElementById("tab_" + name);
+
+ if(tab.className=="tab_selected")
+    return;
+
+ // Hide the deslected tabs and DIVs
+
+ var parent=tab.parentNode;
+ var child=parent.firstChild;
+
+ do
+   {
+    if(String(child.id).substr(0,4)=="tab_")
+      {
+       var div=document.getElementById(child.id + "_div");
+
+       child.className="tab_unselected";
+       div.style.display="none";
+      }
+
+    child=child.nextSibling;
+   }
+ while(child!==null);
+
+ // Display the newly selected tab and DIV
+
+ tab.className="tab_selected";
+ document.getElementById(tab.id + "_div").style.display="";
+}
+
+
+//
+// Show the associated DIV
+//
+
+function hideshow_show(name)
+{
+ document.getElementById("hideshow_" + name + "_show").className="hideshow_hide";
+ document.getElementById("hideshow_" + name + "_hide").className="hideshow_show";
+ document.getElementById("hideshow_" + name + "_div").style.display="";
+}
+
+
+//
+// Hide the associated DIV
+//
+
+function hideshow_hide(name)
+{
+ document.getElementById("hideshow_" + name + "_show").className="hideshow_show";
+ document.getElementById("hideshow_" + name + "_hide").className="hideshow_hide";
+ document.getElementById("hideshow_" + name + "_div").style.display="none";
+}
+
+
+//
+// Toggle the associated DIV
+//
+
+function hideshow_toggle(name)
+{
+ if(document.getElementById("hideshow_" + name + "_div").style.display=="none")
+    hideshow_show(name);
+ else
+    hideshow_hide(name);
+}
diff --git a/3rdparty/Routino/web/www/routino/paths.pl b/3rdparty/Routino/web/www/routino/paths.pl
new file mode 100644
index 0000000..33e9893
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/paths.pl
@@ -0,0 +1,43 @@
+#
+# Routino CGI paths Perl script
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2012 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# Directory path parameters
+
+# EDIT THIS to set the root directory for the non-web data files.
+$root_dir="../..";
+
+# EDIT THIS to change the location of the individual directories.
+$bin_dir="$root_dir/bin";
+$data_dir="$root_dir/data";
+$results_dir="$root_dir/results";
+
+# EDIT THIS to set the filename prefix for the routing database files.
+$data_prefix="";
+
+# EDIT THIS to change the names of the executables (enables easy selection of slim mode).
+$router_exe="router";
+$filedumper_exe="filedumper";
+
+# EDIT THIS to change the search type and base URL (must be a type recognised by search.pl).
+$search_type="nominatim";
+$search_baseurl="http://nominatim.openstreetmap.org/search";
+
+1;
diff --git a/3rdparty/Routino/web/www/routino/results.cgi b/3rdparty/Routino/web/www/routino/results.cgi
new file mode 100755
index 0000000..bbd564d
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/results.cgi
@@ -0,0 +1,76 @@
+#!/usr/bin/perl
+#
+# Routino router results retrieval CGI
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+
+# Use the generic router script
+require "router.pl";
+
+# Use the perl CGI module
+use CGI ':cgi';
+
+
+# Create the query and get the parameters
+
+my $query=new CGI;
+
+my @rawparams=$query->param;
+
+# Legal CGI parameters with regexp validity check
+
+my %legalparams=(
+              "type"   => "(shortest|quickest|router)",
+              "format" => "(html|gpx-route|gpx-track|text|text-all|log)",
+
+              "uuid"   => "[0-9a-f]{32}"
+             );
+
+# Validate the CGI parameters, ignore invalid ones
+
+my %cgiparams=();
+
+foreach my $key (@rawparams)
+  {
+   foreach my $test (keys (%legalparams))
+     {
+      if($key =~ m%^$test$%)
+        {
+         my $value=$query->param($key);
+
+         if($value =~ m%^$legalparams{$test}$%)
+           {
+            $cgiparams{$key}=$value;
+            last;
+           }
+        }
+     }
+  }
+
+# Parse the parameters
+
+my $uuid  =$cgiparams{"uuid"};
+my $type  =$cgiparams{"type"};
+my $format=$cgiparams{"format"};
+
+# Return the file
+
+ReturnOutput($uuid,$type,$format);
diff --git a/3rdparty/Routino/web/www/routino/router.cgi b/3rdparty/Routino/web/www/routino/router.cgi
new file mode 100755
index 0000000..f92a210
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/router.cgi
@@ -0,0 +1,118 @@
+#!/usr/bin/perl
+#
+# Routino interactive router CGI
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+
+# Use the generic router script
+require "router.pl";
+
+# Use the perl CGI module
+use CGI ':cgi';
+
+
+# Create the query and get the parameters
+
+my $query=new CGI;
+
+my @rawparams=$query->param;
+
+# Legal CGI parameters with regexp validity check
+
+my %legalparams=(
+              "lon[1-9][0-9]*"  => "[-0-9.]+",
+              "lat[1-9][0-9]*"  => "[-0-9.]+",
+              "heading"         => "[-0-9.]+",
+              "transport"       => "[a-z]+",
+              "highway-[a-z]+"  => "[0-9.]+",
+              "speed-[a-z]+"    => "[0-9.]+",
+              "property-[a-z]+" => "[0-9.]+",
+              "oneway"          => "(1|0|true|false|on|off)",
+              "turns"           => "(1|0|true|false|on|off)",
+              "weight"          => "[0-9.]+",
+              "height"          => "[0-9.]+",
+              "width"           => "[0-9.]+",
+              "length"          => "[0-9.]+",
+              "length"          => "[0-9.]+",
+
+              "language"        => "[-a-zA-Z]+",
+              "type"            => "(shortest|quickest)",
+              "format"          => "(html|gpx-route|gpx-track|text|text-all)",
+
+              "reverse"         => "(1|0|true|false|on|off)",
+              "loop"            => "(1|0|true|false|on|off)"
+             );
+
+# Validate the CGI parameters, ignore invalid ones
+
+my %cgiparams=();
+
+foreach my $key (@rawparams)
+  {
+   foreach my $test (keys (%legalparams))
+     {
+      if($key =~ m%^$test$%)
+        {
+         my $value=$query->param($key);
+
+         if($value =~ m%^$legalparams{$test}$%)
+           {
+            $cgiparams{$key}=$value;
+            last;
+           }
+        }
+     }
+  }
+
+# Get the important parameters
+
+my $type;
+my $format;
+
+$type=$cgiparams{type};
+delete $cgiparams{type};
+
+$type="shortest" if(!$type);
+
+$format=$cgiparams{format};
+delete $cgiparams{format};
+
+# Fill in the default parameters
+
+my %fullparams=FillInDefaults(%cgiparams);
+
+# Run the router
+
+my($router_uuid,$router_success)=RunRouter($type,%fullparams);
+
+# Return the output
+
+if($format)
+  {
+   ReturnOutput($router_uuid,$type,$format);
+  }
+else
+  {
+   print header('text/plain');
+
+   print "$router_uuid\n";
+   print "$router_success\n";
+  }
diff --git a/3rdparty/Routino/web/www/routino/router.css b/3rdparty/Routino/web/www/routino/router.css
new file mode 100644
index 0000000..cba1b6a
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/router.css
@@ -0,0 +1,237 @@
+/*
+// Routino router web page style sheet.
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2015 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*--------------------------------*/
+/* Left panel - override defaults */
+/*--------------------------------*/
+
+DIV.hideshow_box
+{
+ overflow-x: auto;
+}
+
+
+/*------------------------------*/
+/* Left panel - generic options */
+/*------------------------------*/
+
+DIV.scrollable
+{
+ overflow: auto;
+
+ height: 20em;
+}
+
+
+/*-----------------------------------*/
+/* Left panel - specific tab options */
+/*-----------------------------------*/
+
+DIV#tab_options_div DIV.waypoint
+{
+ clear: both;
+}
+
+DIV#tab_options_div DIV.waypoint SPAN
+{
+ vertical-align: 50%;
+}
+
+DIV#tab_options_div DIV.waypoint DIV.waypoint-buttons
+{
+ float: right;
+}
+
+DIV#tab_options_div DIV.waypoint IMG
+{
+ cursor: pointer;
+}
+
+DIV#tab_options_div DIV.waypoint IMG.waypoint-icon
+{
+ cursor: move;
+}
+
+DIV#tab_options_div DIV.waypoint IMG:hover
+{
+ background: #F0F000;
+}
+
+DIV#tab_options_div DIV#waypoints-buttons
+{
+ clear: both;
+}
+
+DIV#tab_options_div TABLE
+{
+ padding: 0;
+ border:  0 hidden;
+ margin:  0;
+}
+
+DIV#tab_options_div TABLE TD
+{
+ padding: 0;
+ border:  0;
+ margin:  0;
+}
+
+DIV#tab_options_div DIV.center
+{
+ text-align: center;
+}
+
+DIV#tab_options_div A:hover
+{
+ background: #F0F000;
+}
+
+DIV#tab_options_div INPUT
+{
+ padding: 0;
+ border:  1px solid;
+ margin:  0;
+}
+
+DIV#tab_options_div INPUT[type="text"]
+{
+ text-align: right;
+}
+
+DIV#tab_options_div INPUT[size="18"]
+{
+ text-align: left;
+}
+
+DIV#tab_options_div INPUT:hover
+{
+ background: #F0F0C0;
+}
+
+DIV#tab_options_div INPUT#shortest
+{
+ margin: 3px;
+ border: 3px solid;
+
+ border-color: #00FF00;
+
+ background: #C0F0C0;
+
+ text-align: center;
+}
+
+DIV#tab_options_div INPUT#shortest:hover
+{
+ background: #F0F000;
+}
+
+DIV#tab_options_div INPUT[disabled]#shortest
+{
+ border-color: #004000;
+
+ background: #E0F0E0;
+}
+
+DIV#tab_options_div INPUT#quickest
+{
+ margin: 3px;
+ border: 3px solid;
+
+ border-color: #0000FF;
+
+ background: #C0C0F0;
+
+ text-align: center;
+}
+
+DIV#tab_options_div INPUT#quickest:hover
+{
+ background: #F0F000;
+}
+
+DIV#tab_options_div INPUT[disabled]#quickest
+{
+ border-color: #000040;
+
+ background: #E0E0F0;
+}
+
+DIV#tab_results_div TABLE
+{
+ border-collapse: collapse;
+ border: hidden;
+}
+
+DIV#tab_results_div TD.distance
+{
+ text-align: left;
+}
+
+DIV#tab_results_div TD.highway
+{
+ text-align: left;
+ padding-left: 10px;
+}
+
+DIV#tab_results_div DIV#shortest_links A:hover
+{
+ background: #C0F0C0;
+}
+
+DIV#tab_results_div DIV#shortest_route TR:hover
+{
+ cursor: pointer;
+
+ background: #C0F0C0;
+}
+
+DIV#tab_results_div DIV#quickest_links A:hover
+{
+ background: #C0C0F0;
+}
+
+DIV#tab_results_div DIV#quickest_route TR:hover
+{
+ cursor: pointer;
+
+ background: #C0C0F0;
+}
+
+
+/*-------------------------------------------------*/
+/* Popup - using the styles defined in HTML output */
+/*-------------------------------------------------*/
+
+DIV.popup table  {table-layout: fixed; border: none; border-collapse: collapse;}
+DIV.popup tr     {border: 0px;}
+DIV.popup tr.c   {display: none;} /* coords */
+DIV.popup tr.n   {} /* node */
+DIV.popup tr.s   {} /* segment */
+DIV.popup tr.t   {font-weight: bold;} /* total */
+DIV.popup td.l   {font-weight: bold;}
+DIV.popup td.r   {}
+DIV.popup span.w {font-weight: bold;} /* waypoint */
+DIV.popup span.h {text-decoration: underline;} /* highway */
+DIV.popup span.d {} /* segment distance */
+DIV.popup span.j {font-style: italic;} /* total journey distance */
+DIV.popup span.t {font-variant: small-caps;} /* turn */
+DIV.popup span.b {font-variant: small-caps;} /* bearing */
diff --git a/3rdparty/Routino/web/www/routino/router.leaflet.js b/3rdparty/Routino/web/www/routino/router.leaflet.js
new file mode 100644
index 0000000..0f5ffcc
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/router.leaflet.js
@@ -0,0 +1,2230 @@
+//
+// Routino router web page Javascript
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2015 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+var vismarkers, markers, icons, markersmoved, paramschanged;
+var homelat=null, homelon=null;
+
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Initialisation /////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+// Make a deep copy of the routino profile.
+
+var routino_default={};
+for(var l1 in routino)
+   if(typeof(routino[l1])!="object")
+      routino_default[l1]=routino[l1];
+   else
+     {
+      routino_default[l1]={};
+      for(var l2 in routino[l1])
+         if(typeof(routino[l1][l2])!="object")
+            routino_default[l1][l2]=Number(routino[l1][l2]);
+         else
+           {
+            routino_default[l1][l2]={};
+            for(var l3 in routino[l1][l2])
+               routino_default[l1][l2][l3]=Number(routino[l1][l2][l3]);
+           }
+     }
+
+// Store the latitude and longitude in the routino variable
+
+routino.point=[];
+for(var marker=1;marker<=mapprops.maxmarkers;marker++)
+  {
+   routino.point[marker]={};
+
+   routino.point[marker].lon="";
+   routino.point[marker].lat="";
+   routino.point[marker].search="";
+   routino.point[marker].active=false;
+   routino.point[marker].used=false;
+   routino.point[marker].home=false;
+  }
+
+// Process the URL query string and extract the arguments
+
+var legal={"^lon"             : "^[-0-9.]+$",
+           "^lat"             : "^[-0-9.]+$",
+           "^zoom"            : "^[0-9]+$",
+
+           "^lon[1-9]"        : "^[-0-9.]+$",
+           "^lat[1-9]"        : "^[-0-9.]+$",
+           "^search[1-9]"     : "^.+$",
+           "^transport"       : "^[a-z]+$",
+           "^highway-[a-z]+"  : "^[0-9.]+$",
+           "^speed-[a-z]+"    : "^[0-9.]+$",
+           "^property-[a-z]+" : "^[0-9.]+$",
+           "^oneway"          : "^(1|0|true|false|on|off)$",
+           "^turns"           : "^(1|0|true|false|on|off)$",
+           "^weight"          : "^[0-9.]+$",
+           "^height"          : "^[0-9.]+$",
+           "^width"           : "^[0-9.]+$",
+           "^length"          : "^[0-9.]+$",
+
+           "^language"        : "^[-a-zA-Z]+$"};
+
+var args={};
+
+if(location.search.length>1)
+  {
+   var query,queries;
+
+   query=location.search.replace(/^\?/,"");
+   query=query.replace(/;/g,"&");
+   queries=query.split("&");
+
+   for(var i=0;i<queries.length;i++)
+     {
+      queries[i].match(/^([^=]+)(=(.*))?$/);
+
+      var k=RegExp.$1;
+      var v=decodeURIComponent(RegExp.$3);
+
+      for(var l in legal)
+        {
+         if(k.match(RegExp(l)) && v.match(RegExp(legal[l])))
+            args[k]=v;
+        }
+     }
+  }
+
+
+//
+// Fill in the HTML - add the missing waypoints
+//
+
+function html_init()            // called from router.html
+{
+ var waypoints=document.getElementById("waypoints");
+
+ var waypoint_html=waypoints.firstElementChild.outerHTML.split("XXX");
+
+ waypoints.removeChild(waypoints.firstElementChild);
+
+ for(var marker=1;marker<=mapprops.maxmarkers;marker++)
+   {
+    var waypoint=document.createElement('div');
+
+    waypoints.appendChild(waypoint);
+
+    waypoint.outerHTML=waypoint_html.join(marker);
+   }
+
+ waypoints.addEventListener('dragstart',dragWaypointStart,false);
+ waypoints.addEventListener('dragend'  ,dragWaypointEnd  ,false);
+ waypoints.addEventListener('dragenter',dragWaypointEnter,false);
+ waypoints.addEventListener('dragover' ,dragWaypointOver ,false);
+ waypoints.addEventListener('dragleave',dragWaypointLeave,false);
+ waypoints.addEventListener('drop'     ,dragWaypointDrop ,false);
+
+
+ var map=document.getElementById("map");
+
+ map.addEventListener('dragenter',dragWaypointMapEnter,false);
+ map.addEventListener('dragover' ,dragWaypointMapOver ,false);
+ map.addEventListener('dragleave',dragWaypointMapLeave,false);
+ map.addEventListener('drop'     ,dragWaypointMapDrop ,false);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////// Form handling /////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+//
+// Form initialisation - fill in the uninitialised parts
+//
+
+function form_init()            // called from router.html
+{
+ // Fill in the waypoints
+
+ vismarkers=0;
+
+ for(var marker=mapprops.maxmarkers;marker>=1;marker--)
+   {
+    var lon=args["lon" + marker];
+    var lat=args["lat" + marker];
+    var search=args["search" + marker];
+
+    if(lon !== undefined && lat !== undefined && search !== undefined && lon !== "" && lat !== "" && search !== "")
+      {
+       markerAddForm(marker);
+
+       formSetSearch(marker,search);
+       formSetCoords(marker,lon,lat);
+
+       markerAddMap(marker);
+
+       markerSearch(marker);
+
+       vismarkers++;
+      }
+    else if(lon !== undefined && lat !== undefined && lon !== "" && lat !== "")
+      {
+       markerAddForm(marker);
+
+       formSetCoords(marker,lon,lat);
+
+       markerAddMap(marker);
+
+       markerCoords(marker);
+
+       vismarkers++;
+      }
+    else if(search !== undefined && search !== "")
+      {
+       markerAddForm(marker);
+
+       formSetSearch(marker,search);
+
+       markerSearch(marker);
+
+       DoSearch(marker);
+
+       vismarkers++;
+      }
+    else if(vismarkers || marker<=2)
+      {
+       markerAddForm(marker);
+
+       vismarkers++;
+      }
+
+    var searchfield=document.forms["form"].elements["search" + marker];
+
+    if(searchfield.addEventListener)
+       searchfield.addEventListener("keyup", searchOnReturnKey, false);
+    else if(searchfield.attachEvent)
+       searchfield.attachEvent("keyup", searchOnReturnKey); // Internet Explorer
+   }
+
+ // Update the transport type with the URL settings which updates all HTML forms to defaults.
+
+ var transport=routino.transport;
+
+ if(args["transport"] !== undefined)
+    transport=args["transport"];
+
+ formSetTransport(transport);
+
+ // Update the HTML with the URL settings
+
+ if(args["language"] !== undefined)
+    formSetLanguage(args["language"]);
+
+ for(var key in routino.profile_highway)
+    if(args["highway-" + key] !== undefined)
+       formSetHighway(key,args["highway-" + key]);
+
+ for(var key in routino.profile_speed)
+    if(args["speed-" + key] !== undefined)
+       formSetSpeed(key,args["speed-" + key]);
+
+ for(var key in routino.profile_property)
+    if(args["property-" + key] !== undefined)
+       formSetProperty(key,args["property-" + key]);
+
+ for(var key in routino.restrictions)
+   {
+    if(key=="oneway" || key=="turns")
+      {
+       if(args[key] !== undefined)
+          formSetRestriction(key,args[key]);
+      }
+    else
+      {
+       if(args["restrict-" + key] !== undefined)
+          formSetRestriction(key,args["restrict-" + key]);
+      }
+   }
+
+ // Get the home location cookie and compare to each waypoint
+
+ var cookies=document.cookie.split("; ");
+
+ for(var cookie=0;cookie<cookies.length;cookie++)
+    if(cookies[cookie].substr(0,"Routino-home".length)=="Routino-home")
+      {
+       var data=cookies[cookie].split(/[=:;]/);
+
+       if(data[1]=="lon") homelon=Number(data[2]);
+       if(data[3]=="lat") homelat=Number(data[4]);
+      }
+
+ if(homelon!==null && homelat!==null)
+   {
+    for(var m=1;m<=vismarkers;m++)
+       markerCheckHome(m);
+
+    // If the first location is empty and the cookie is set then fill it.
+
+    if(!routino.point[1].used)
+       markerMoveHome(1);
+   }
+
+ updateURLs();
+
+ updateSearchButtons();
+}
+
+
+//
+// Function to perform the search if the return key is pressed.
+// (using 'onchange' only triggers once and is confusing when clicking outside the field).
+//
+
+function searchOnReturnKey(ev)
+{
+ if(ev.keyCode==13)
+    if(this.name.match(/^search([0-9]+)$/))
+       formSetSearch(RegExp.$1);
+
+ return(true);
+}
+
+
+//
+// Change of language in the form
+//
+
+function formSetLanguage(value) // called from router.html (with no arguments)
+{
+ if(value === undefined)
+   {
+    for(var lang=0;lang<document.forms["form"].elements["language"].length;lang++)
+       if(document.forms["form"].elements["language"][lang].checked)
+          routino.language=document.forms["form"].elements["language"][lang].value;
+   }
+ else
+   {
+    for(var lang=0;lang<document.forms["form"].elements["language"].length;lang++)
+       if(document.forms["form"].elements["language"][lang].value==value)
+          document.forms["form"].elements["language"][lang].checked=true;
+       else
+          document.forms["form"].elements["language"][lang].checked=false;
+
+    routino.language=value;
+   }
+
+ updateURLs();
+}
+
+
+//
+// Change of transport in the form
+//
+
+function formSetTransport(value) // called from router.html
+{
+ routino.transport=value;
+
+ for(var key in routino.transports)
+    document.forms["form"].elements["transport"][routino.transports[key]-1].checked=(key==routino.transport);
+
+ for(var key in routino.profile_highway)
+    document.forms["form"].elements["highway-" + key].value=routino.profile_highway[key][routino.transport];
+
+ for(var key in routino.profile_speed)
+    document.forms["form"].elements["speed-" + key].value=routino.profile_speed[key][routino.transport];
+
+ for(var key in routino.profile_property)
+    document.forms["form"].elements["property-" + key].value=routino.profile_property[key][routino.transport];
+
+ for(var key in routino.restrictions)
+   {
+    if(key=="oneway" || key=="turns")
+       document.forms["form"].elements["restrict-" + key].checked=routino.profile_restrictions[key][routino.transport];
+    else
+       document.forms["form"].elements["restrict-" + key].value=routino.profile_restrictions[key][routino.transport];
+   }
+
+ paramschanged=true;
+
+ updateURLs();
+}
+
+
+//
+// Change of highway in the form
+//
+
+function formSetHighway(type,value) // called from router.html (with one argument)
+{
+ if(value == "+")
+   {
+    value=routino.profile_highway[type][routino.transport];
+    value=10*Math.floor(value/10)+10;
+   }
+ else if(value == "-")
+   {
+    value=routino.profile_highway[type][routino.transport]-10;
+    value=10*Math.ceil(value/10)-10;
+   }
+ else if(value == "=")
+    value=document.forms["form"].elements["highway-" + type].value;
+
+ value=Number(value);
+ if(isNaN(value)) value= 50;
+ if(value>100)    value=100;
+ if(value<  0)    value=  0;
+
+ document.forms["form"].elements["highway-" + type].value=value;
+ routino.profile_highway[type][routino.transport]=value;
+
+ paramschanged=true;
+
+ updateURLs();
+}
+
+
+//
+// Change of Speed in the form
+//
+
+function formSetSpeed(type,value) // called from router.html (with one argument)
+{
+ if(value == "+")
+   {
+    value=routino.profile_speed[type][routino.transport];
+    if(value<10) value=2*Math.floor(value/2)+2;
+    else if(value<30) value=5*Math.floor(value/5)+5;
+    else value=10*Math.floor(value/10)+10;
+   }
+ else if(value == "-")
+   {
+    value=routino.profile_speed[type][routino.transport];
+    if(value<=10) value=2*Math.ceil(value/2)-2;
+    else if(value<=30) value=5*Math.ceil(value/5)-5;
+    else value=10*Math.ceil(value/10)-10;
+   }
+ else if(value == "=")
+    value=document.forms["form"].elements["speed-" + type].value;
+
+ value=Number(value);
+ if(isNaN(value)) value= 60;
+ if(value>150)    value=150;
+ if(value<  0)    value=  0;
+
+ document.forms["form"].elements["speed-" + type].value=value;
+ routino.profile_speed[type][routino.transport]=value;
+
+ paramschanged=true;
+
+ updateURLs();
+}
+
+
+//
+// Change of Property in the form
+//
+
+function formSetProperty(type,value) // called from router.html (with one argument)
+{
+ if(value == "+")
+   {
+    value=routino.profile_property[type][routino.transport];
+    if(value>=40 && value<60) value=2*Math.floor(value/2)+2;
+    else value=5*Math.floor(value/5)+5;
+   }
+ else if(value == "-")
+   {
+    value=routino.profile_property[type][routino.transport];
+    if(value>40 && value<=60) value=2*Math.ceil(value/2)-2;
+    else value=5*Math.ceil(value/5)-5;
+   }
+ else if(value == "=")
+    value=document.forms["form"].elements["property-" + type].value;
+
+ value=Number(value);
+ if(isNaN(value)) value= 50;
+ if(value>100)    value=100;
+ if(value<  0)    value=  0;
+
+ document.forms["form"].elements["property-" + type].value=value;
+ routino.profile_property[type][routino.transport]=value;
+
+ paramschanged=true;
+
+ updateURLs();
+}
+
+
+//
+// Change of Restriction rule in the form
+//
+
+function formSetRestriction(type,value) // called from router.html (with one argument)
+{
+ if(type=="oneway" || type=="turns")
+   {
+    if(value === undefined)
+       routino.profile_restrictions[type][routino.transport]=document.forms["form"].elements["restrict-" + type].checked;
+    else
+       document.forms["form"].elements["restrict-" + type].checked=value;
+
+    routino.profile_restrictions[type][routino.transport]=value;
+   }
+ else if(type=="weight")
+   {
+    if(value == "+")
+       value=routino.profile_restrictions[type][routino.transport]+5;
+    else if(value == "-")
+       value=routino.profile_restrictions[type][routino.transport]-5;
+    else if(value == "=")
+       value=document.forms["form"].elements["restrict-" + type].value;
+
+    value=Number(value);
+    if(isNaN(value)) value= 0;
+    if(value>50)     value=50;
+    if(value< 0)     value= 0;
+
+    document.forms["form"].elements["restrict-" + type].value=value;
+    routino.profile_restrictions[type][routino.transport]=value;
+   }
+ else /* if(type=="height" || type=="width" || type=="length") */
+   {
+    if(value == "+")
+       value=routino.profile_restrictions[type][routino.transport]+1;
+    else if(value == "-")
+       value=routino.profile_restrictions[type][routino.transport]-1;
+    else if(value == "=")
+       value=document.forms["form"].elements["restrict-" + type].value;
+
+    value=Number(value);
+    if(isNaN(value)) value= 0;
+    if(value>25)     value=25;
+    if(value< 0)     value= 0;
+
+    document.forms["form"].elements["restrict-" + type].value=value;
+    routino.profile_restrictions[type][routino.transport]=value;
+   }
+
+ paramschanged=true;
+
+ updateURLs();
+}
+
+
+//
+// Set the feature coordinates from the form when the form changes.
+//
+
+function formSetCoords(marker,lon,lat) // called from router.html (with one argument)
+{
+ clearSearchResult(marker);
+
+ if(lon === undefined && lat === undefined)
+   {
+    lon=document.forms["form"].elements["lon" + marker].value;
+    lat=document.forms["form"].elements["lat" + marker].value;
+   }
+
+ if(lon === "" && lat === "")
+   {
+    document.forms["form"].elements["lon" + marker].value="";
+    document.forms["form"].elements["lat" + marker].value="";
+
+    routino.point[marker].lon="";
+    routino.point[marker].lat="";
+
+    updateURLs();
+   }
+ else
+   {
+    var lonlat;
+
+    if(lon==="")
+      {
+       lonlat=map.getCenter();
+
+       lon=lonlat.lon;
+      }
+
+    if(lon<-180) lon=-180;
+    if(lon>+180) lon=+180;
+
+    if(lat==="")
+      {
+       lonlat=map.getCenter();
+
+       lat=lonlat.lat;
+      }
+
+    if(lat<-90 ) lat=-90 ;
+    if(lat>+90 ) lat=+90 ;
+
+    lonlat = L.latLng(lat,lon);
+
+    markers[marker].setLatLng(lonlat);
+
+    markersmoved=true;
+
+    document.forms["form"].elements["lon" + marker].value=format5f(lon);
+    document.forms["form"].elements["lat" + marker].value=format5f(lat);
+
+    routino.point[marker].lon=lon;
+    routino.point[marker].lat=lat;
+    routino.point[marker].used=true;
+
+    markerCheckHome(marker);
+   }
+}
+
+
+//
+// Set the search field from the form when the form changes.
+//
+
+function formSetSearch(marker,search) // called from event handler linked to router.html (with one argument)
+{
+ clearSearchResult(marker);
+
+ if(search === undefined)
+   {
+    routino.point[marker].search=document.forms["form"].elements["search" + marker].value;
+
+    DoSearch(marker);
+   }
+ else
+   {
+    document.forms["form"].elements["search" + marker].value=search;
+
+    routino.point[marker].search=search;
+   }
+}
+
+
+//
+// Format a number in printf("%.5f") format.
+//
+
+function format5f(number)
+{
+ var newnumber=Math.floor(number*100000+0.5);
+ var delta=0;
+
+ if(newnumber>=0 && newnumber<100000) delta= 100000;
+ if(newnumber<0 && newnumber>-100000) delta=-100000;
+
+ var string=String(newnumber+delta);
+
+ var intpart =string.substring(0,string.length-5);
+ var fracpart=string.substring(string.length-5,string.length);
+
+ if(delta>0) intpart="0";
+ if(delta<0) intpart="-0";
+
+ return(intpart + "." + fracpart);
+}
+
+
+//
+// Build a set of URL arguments
+//
+
+function buildURLArguments(lang)
+{
+ var url= "transport=" + routino.transport;
+
+ for(var marker=1;marker<=vismarkers;marker++)
+    if(routino.point[marker].active)
+      {
+       url=url + ";lon" + marker + "=" + routino.point[marker].lon;
+       url=url + ";lat" + marker + "=" + routino.point[marker].lat;
+       if(routino.point[marker].search !== "")
+          url=url + ";search" + marker + "=" + encodeURIComponent(routino.point[marker].search);
+      }
+
+ for(var key in routino.profile_highway)
+    if(routino.profile_highway[key][routino.transport]!=routino_default.profile_highway[key][routino.transport])
+       url=url + ";highway-" + key + "=" + routino.profile_highway[key][routino.transport];
+
+ for(var key in routino.profile_speed)
+    if(routino.profile_speed[key][routino.transport]!=routino_default.profile_speed[key][routino.transport])
+       url=url + ";speed-" + key + "=" + routino.profile_speed[key][routino.transport];
+
+ for(var key in routino.profile_property)
+    if(routino.profile_property[key][routino.transport]!=routino_default.profile_property[key][routino.transport])
+       url=url + ";property-" + key + "=" + routino.profile_property[key][routino.transport];
+
+ for(var key in routino.restrictions)
+    if(routino.profile_restrictions[key][routino.transport]!=routino_default.profile_restrictions[key][routino.transport])
+       url=url + ";" + key + "=" + routino.profile_restrictions[key][routino.transport];
+
+ if(lang && routino.language)
+    url=url + ";language=" + routino.language;
+
+ return(url);
+}
+
+
+//
+// Build a set of URL arguments for the map location
+//
+
+function buildMapArguments()
+{
+ var lonlat = map.getCenter();
+
+ var zoom = map.getZoom();
+
+ return "lat=" + format5f(lonlat.lat) + ";lon=" + format5f(lonlat.lng) + ";zoom=" + zoom;
+}
+
+
+//
+// Update the URLs
+//
+
+function updateURLs()
+{
+ var urlargs1=buildURLArguments(true);
+ var urlargs2=buildURLArguments(false);
+ var mapargs=buildMapArguments();
+
+ var links=document.getElementsByTagName("a");
+
+ for(var i=0; i<links.length; i++)
+   {
+    var element=links[i];
+
+    if(element.id == "permalink_url")
+       element.href=location.pathname + "?" + urlargs1 + ";" + mapargs;
+
+    if(element.id == "visualiser_url")
+       element.href="visualiser.html" + "?" + mapargs;
+
+    if(element.id == "edit_url")
+       element.href=mapprops.editurl + "?" + mapargs;
+
+    if(element.id.match(/^lang_([a-zA-Z-]+)_url$/))
+       element.href="router.html" + "." + RegExp.$1 + "?" + urlargs2 + ";" + mapargs;
+   }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////// Map handling /////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+var map;
+var layerMap=[], layerVectors, layerGPX;
+var routing_type;
+
+//
+// Initialise the 'map' object
+//
+
+function map_init()             // called from router.html
+{
+ // Create the map (Map URLs and limits are in mapprops.js)
+
+ map = L.map("map",
+             {
+              attributionControl: false,
+              zoomControl: false,
+
+              minZoom: mapprops.zoomout,
+              maxZoom: mapprops.zoomin,
+
+              maxBounds: L.latLngBounds(L.latLng(mapprops.southedge,mapprops.westedge),L.latLng(mapprops.northedge,mapprops.eastedge))
+              });
+
+ // Add map tile layers
+
+ var baselayers={};
+
+ for(var l=0; l<mapprops.mapdata.length; l++)
+   {
+    var urls=mapprops.mapdata[l].tiles.url.replace(/\${/g,"{");
+
+    if(mapprops.mapdata[l].tiles.subdomains===undefined)
+       layerMap[l] = L.tileLayer(urls);
+    else
+       layerMap[l] = L.tileLayer(urls, {subdomains: mapprops.mapdata[l].tiles.subdomains});
+
+    baselayers[mapprops.mapdata[l].label]=layerMap[l];
+
+    if(l===0)
+       map.addLayer(layerMap[l]);
+   }
+
+ // Add the controls
+
+ map.addControl(L.control.zoom());
+ map.addControl(L.control.scale());
+ map.addControl(L.control.layers(baselayers));
+
+ // Update the attribution if the layer changes
+
+ function change_attribution_event(event)
+ {
+  for(var l=0; l<mapprops.mapdata.length; l++)
+     if(layerMap[l] == event.layer)
+        change_attribution(l);
+ }
+
+ map.on("baselayerchange",change_attribution_event);
+
+ function change_attribution(l)
+ {
+  var data_url =mapprops.mapdata[l].attribution.data_url;
+  var data_text=mapprops.mapdata[l].attribution.data_text;
+  var tile_url =mapprops.mapdata[l].attribution.tile_url;
+  var tile_text=mapprops.mapdata[l].attribution.tile_text;
+
+  document.getElementById("attribution_data").innerHTML="<a href=\"" + data_url + "\" target=\"data_attribution\">" + data_text + "</a>";
+  document.getElementById("attribution_tile").innerHTML="<a href=\"" + tile_url + "\" target=\"tile_attribution\">" + tile_text + "</a>";
+ }
+
+ change_attribution(0);
+
+ // Define a GPX layer but don't add it yet
+
+ layerGPX={shortest: null, quickest: null};
+
+ // Add a markers vectors layer
+
+ layerVectors = L.layerGroup();
+ map.addLayer(layerVectors);
+
+ // A set of markers
+
+ markers={};
+ icons={};
+ markersmoved=false;
+ paramschanged=false;
+
+ for(var marker=1;marker<=mapprops.maxmarkers;marker++)
+   {
+    icons[marker]=L.icon({iconUrl: "icons/marker-" + marker + "-red.png",
+                          iconSize: L.point(21,25),
+                          iconAnchor: L.point(10,25)});
+
+    markers[marker]=L.marker(L.point(0,0), {clickable: true, draggable: true, icon: icons[marker]});
+
+    markers[marker].on("drag"   , (function(m) { return function(evt) { dragMarkerMove    (m,evt); }; }(marker)));
+    markers[marker].on("dragend", (function(m) { return function(evt) { dragMarkerComplete(m,evt); }; }(marker)));
+   }
+
+ icons.home=L.icon({iconUrl: "icons/marker-home-red.png",
+                    iconSize: L.point(21,25),
+                    iconAnchor: L.point(11,-25)});
+
+ // Markers to highlight a selected point
+
+ for(var highlight in highlights)
+   {
+    highlights[highlight]=L.circleMarker(L.latLng(0,0), {radius: 10, stroke: true, weight: 4, color: route_dark_colours[highlight], opacity: 1.0,
+                                                         fill: false});
+   }
+
+ // A popup for routing results
+
+ for(var popup in popups)
+    popups[popup] = createPopup(popup);
+
+ // Move the map
+
+ map.on("moveend", updateURLs);
+
+ var lon =args["lon"];
+ var lat =args["lat"];
+ var zoom=args["zoom"];
+
+ if(lon !== undefined && lat !== undefined && zoom !== undefined)
+   {
+    if(lon<mapprops.westedge) lon=mapprops.westedge;
+    if(lon>mapprops.eastedge) lon=mapprops.eastedge;
+
+    if(lat<mapprops.southedge) lat=mapprops.southedge;
+    if(lat>mapprops.northedge) lat=mapprops.northedge;
+
+    if(zoom<mapprops.zoomout) zoom=mapprops.zoomout;
+    if(zoom>mapprops.zoomin)  zoom=mapprops.zoomin;
+
+    map.setView(L.latLng(lat,lon),zoom);
+   }
+ else
+    map.fitBounds(map.options.maxBounds);
+
+ // Unhide editing URL if variable set
+
+ if(mapprops.editurl !== undefined && mapprops.editurl !== "")
+   {
+    var edit_url=document.getElementById("edit_url");
+
+    edit_url.style.display="";
+    edit_url.href=mapprops.editurl;
+   }
+
+ updateURLs();
+}
+
+
+//
+// Callback for a marker drag occuring on the map.
+//
+
+function dragMarkerMove(marker,event)
+{
+ dragMarkerSetForm(marker);
+}
+
+
+//
+// Callback for completing a drag occuring on the map.
+//
+
+function dragMarkerComplete(marker,event)
+{
+ dragMarkerSetForm(marker);
+
+ updateURLs();
+}
+
+
+//
+// Set the feature coordinates in the form after dragging it on the map.
+//
+
+function dragMarkerSetForm(marker)
+{
+ var lonlat = markers[marker].getLatLng();
+
+ formSetCoords(marker,lonlat.lng,lonlat.lat);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Marker dragging ////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+var dragged_waypoint=null,dragged_marker=null;
+var dragged_waypoint_over=null,dragged_marker_over=null;
+ var dragged_icon_x,dragged_icon_y;
+
+//
+// Drag a waypoint up or down the list.
+//
+
+function dragWaypointStart(e)
+{
+ var w=e.target;
+
+ while(w!=null && w.className != "waypoint")
+    w=w.parentElement;
+
+ if(w===null)
+    return;
+
+ w.style.opacity = "0.5";
+
+ dragged_waypoint=w;
+ dragged_marker=Number.parseInt(dragged_waypoint.id.substring(8));
+
+ dragged_icon_x=e.clientX-e.target.offsetLeft;
+ dragged_icon_y=e.clientY-e.target.offsetTop;
+}
+
+function dragWaypointEnd(e)
+{
+ e.preventDefault();
+
+ if(dragged_waypoint===null)
+    return;
+
+ dragged_waypoint.style.opacity = "";
+
+ dragged_waypoint=null;
+ dragged_marker=null;
+
+ if(dragged_waypoint_over===null)
+    return;
+
+ dragged_waypoint_over.style.border = "";
+
+ dragged_waypoint_over=null;
+ dragged_marker_over=null;
+}
+
+
+//
+// Drag a waypoint over another one up or down the list.
+//
+
+function dragWaypointEnter(e)
+{
+ var w=e.target;
+
+ while(w!=null && w.className != "waypoint")
+    w=w.parentElement;
+
+ if(w===null)
+    return;
+
+ if(dragged_waypoint_over!==null)
+    dragged_waypoint_over.style.border = "";
+
+ if(w==dragged_waypoint)
+    return;
+
+ dragged_waypoint_over=w;
+ dragged_marker_over=Number.parseInt(dragged_waypoint_over.id.substring(8));
+
+ if(dragged_marker>dragged_marker_over)
+    w.style.borderTop = "3px solid black";
+ else
+    w.style.borderBottom = "3px solid black";
+}
+
+function dragWaypointOver(e)
+{
+ e.preventDefault();
+}
+
+function dragWaypointLeave(e)
+{
+ var w=e.target;
+
+ while(w!=null && w.className != "waypoint")
+    w=w.parentElement;
+
+ if(w===null)
+    return;
+
+ if(w==dragged_waypoint_over)
+    return;
+
+ w.style.border = "";
+}
+
+
+//
+// Drop the waypoint after dragging up or down the list.
+//
+
+function dragWaypointDrop(e)
+{
+ e.preventDefault();
+
+ if(dragged_marker_over===null)
+    return;
+
+ if(dragged_marker_over>dragged_marker)
+    for(var m=dragged_marker;m<dragged_marker_over;m++)
+       markerSwap(m,m+1);
+
+ if(dragged_marker_over<dragged_marker)
+    for(var m=dragged_marker;m>dragged_marker_over;m--)
+       markerSwap(m,m-1);
+}
+
+
+//
+// Drag a waypoint over the map.
+//
+
+function dragWaypointMapEnter(e)
+{
+ e.preventDefault();
+
+ if(dragged_waypoint_over!==null)
+    dragged_waypoint_over.style.border = "";
+}
+
+function dragWaypointMapOver(e)
+{
+ e.preventDefault();
+}
+
+function dragWaypointMapLeave(e)
+{
+ e.preventDefault();
+}
+
+
+//
+// Drop the waypoint after dragging it over the map.
+//
+
+function dragWaypointMapDrop(e)
+{
+ e.preventDefault();
+
+ var rect = document.getElementById("map").getBoundingClientRect();
+
+ var lonlat=map.containerPointToLatLng(L.point(e.clientX-rect.left-dragged_icon_x+8,e.clientY-rect.top-dragged_icon_y+21));
+
+ formSetCoords(dragged_marker,lonlat.lng,lonlat.lat);
+
+ if(!routino.point[dragged_marker].active)
+    markerToggleMap(dragged_marker);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Marker handling ////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+//
+// Toggle a marker on the map.
+//
+
+function markerToggleMap(marker) // called from router.html
+{
+ if(!routino.point[marker].used)
+   {
+    routino.point[marker].used=true;
+    markerCentre(marker);
+    markerCoords(marker);
+   }
+
+ markerAddRemoveMap(marker,!routino.point[marker].active);
+
+ updateSearchButtons();
+}
+
+
+//
+// Show or hide a marker on the map.
+//
+
+function markerAddRemoveMap(marker,active)
+{
+ if(active)
+    markerAddMap(marker);
+ else
+    markerRemoveMap(marker);
+}
+
+
+//
+// Show a marker on the map.
+//
+
+function markerAddMap(marker)
+{
+ clearSearchResult(marker);
+
+ layerVectors.addLayer(markers[marker]);
+ routino.point[marker].active=true;
+ routino.point[marker].used=true;
+
+ updateIcon(marker);
+
+ markersmoved=true;
+
+ updateURLs();
+}
+
+
+//
+// Remove a marker from the map.
+//
+
+function markerRemoveMap(marker)
+{
+ clearSearchResult(marker);
+
+ layerVectors.removeLayer(markers[marker]);
+ routino.point[marker].active=false;
+
+ updateIcon(marker);
+
+ markersmoved=true;
+
+ updateURLs();
+}
+
+
+//
+// Display search string for the marker
+//
+
+function markerSearch(marker)   // called from router.html
+{
+ clearSearchResult(marker);
+
+ document.getElementById("coords" + marker).style.display="none";
+ document.getElementById("search" + marker).style.display="";
+}
+
+
+//
+// Display coordinates for the marker
+//
+
+function markerCoords(marker)   // called from router.html
+{
+ clearSearchResult(marker);
+
+ document.getElementById("search" + marker).style.display="none";
+ document.getElementById("coords" + marker).style.display="";
+}
+
+
+//
+// Centre the marker on the map
+//
+
+function markerCentre(marker)   // called from router.html
+{
+ if(!routino.point[marker].used)
+    return;
+
+ clearSearchResult(marker);
+
+ var lonlat=map.getCenter();
+
+ formSetCoords(marker,lonlat.lng,lonlat.lat);
+}
+
+
+//
+// Centre the map on the marker
+//
+
+function markerRecentre(marker) // called from router.html
+{
+ if(!routino.point[marker].used)
+    return;
+
+ clearSearchResult(marker);
+
+ var lon=routino.point[marker].lon;
+ var lat=routino.point[marker].lat;
+
+ var lonlat = L.latLng(lat,lon);
+
+ map.panTo(lonlat);
+}
+
+
+//
+// Clear the current marker.
+//
+
+function markerRemove(marker)   // called from router.html
+{
+ clearSearchResult(marker);
+
+ for(var m=marker;m<vismarkers;m++)
+    markerCopy(m,m+1);
+
+ markerRemoveForm(vismarkers--);
+
+ if(vismarkers==1)
+    markerAddAfter(1);
+
+ updateSearchButtons();
+}
+
+
+//
+// Add a marker before the current one.
+//
+
+function markerAddBefore(marker)
+{
+ if(vismarkers==mapprops.maxmarkers || marker==1)
+    return false;
+
+ clearSearchResult(marker);
+
+ markerAddForm(++vismarkers);
+
+ for(var m=vismarkers;m>marker;m--)
+    markerCopy(m,m-1);
+
+ markerClearForm(marker-1);
+}
+
+
+//
+// Add a marker after the current one.
+//
+
+function markerAddAfter(marker) // called from router.html
+{
+ if(vismarkers==mapprops.maxmarkers)
+    return false;
+
+ clearSearchResult(marker);
+
+ markerAddForm(++vismarkers);
+
+ for(var m=vismarkers;m>(marker+1);m--)
+    markerCopy(m,m-1);
+
+ markerClearForm(marker+1);
+}
+
+
+//
+// Set this marker as the home location.
+//
+
+function markerHome(marker)     // called from router.html
+{
+ if(!routino.point[marker].used)
+   {
+    markerMoveHome(marker);
+   }
+ else
+   {
+    clearSearchResult(marker);
+
+    markerSetClearHome(marker,!routino.point[marker].home);
+   }
+}
+
+
+//
+// Set this marker as the current location.
+//
+
+function markerLocate(marker)   // called from router.html
+{
+ clearSearchResult(marker);
+
+ if(navigator.geolocation)
+    navigator.geolocation.getCurrentPosition(
+                                             function(position) {
+                                              formSetCoords(marker,position.coords.longitude,position.coords.latitude);
+                                              markerAddMap(marker);
+                                             });
+}
+
+
+//
+// Update the search buttons enable/disable.
+//
+
+function updateSearchButtons()
+{
+ var markersactive=0;
+
+ for(var m=1;m<=vismarkers;m++)
+    if(routino.point[m].active)
+       markersactive++;
+
+ if(markersactive<2)
+   {
+    document.getElementById("shortest").disabled="disabled";
+    document.getElementById("quickest").disabled="disabled";
+   }
+ else
+   {
+    document.getElementById("shortest").disabled="";
+    document.getElementById("quickest").disabled="";
+   }
+}
+
+
+//
+// Update an icon to set colours and home or normal marker.
+//
+
+function updateIcon(marker)
+{
+ if(routino.point[marker].home)
+   {
+    if(routino.point[marker].active)
+       document.getElementById("icon" + marker).src="icons/marker-home-red.png";
+    else
+       document.getElementById("icon" + marker).src="icons/marker-home-grey.png";
+
+    markers[marker].setIcon(icons.home);
+   }
+ else
+   {
+    if(routino.point[marker].active)
+       document.getElementById("icon" + marker).src="icons/marker-" + marker + "-red.png";
+    else
+       document.getElementById("icon" + marker).src="icons/marker-" + marker + "-grey.png";
+
+    markers[marker].setIcon(icons[marker]);
+   }
+
+ markers[marker].update();
+}
+
+
+//
+// Move the marker to the home location
+//
+
+function markerMoveHome(marker)
+{
+ if(homelon===null || homelat===null)
+    return;
+
+ routino.point[marker].home=true;
+ routino.point[marker].used=true;
+
+ formSetCoords(marker,homelon,homelat);
+ markerAddMap(marker);
+}
+
+
+//
+// Set or clear the home marker icon
+//
+
+function markerSetClearHome(marker,home)
+{
+ var cookie;
+ var date = new Date();
+
+ if(home)
+   {
+    homelat=routino.point[marker].lat;
+    homelon=routino.point[marker].lon;
+
+    cookie="Routino-home=lon:" + homelon + ":lat:" + homelat;
+
+    date.setUTCFullYear(date.getUTCFullYear()+5);
+
+    routino.point[marker].home=true;
+   }
+ else
+   {
+    homelat=null;
+    homelon=null;
+
+    cookie="Routino-home=unset";
+
+    date.setUTCFullYear(date.getUTCFullYear()-1);
+
+    routino.point[marker].home=false;
+   }
+
+ document.cookie=cookie + ";expires=" + date.toGMTString();
+
+ updateIcon(marker);
+
+ for(var m=1;m<=mapprops.maxmarkers;m++)
+    markerCheckHome(m);
+}
+
+
+//
+// Check if a marker is the home marker
+//
+
+function markerCheckHome(marker)
+{
+ var home=routino.point[marker].home;
+
+ if(routino.point[marker].lon==homelon && routino.point[marker].lat==homelat)
+    routino.point[marker].home=true;
+ else
+    routino.point[marker].home=false;
+
+ if(home!=routino.point[marker].home)
+    updateIcon(marker);
+}
+
+
+//
+// Move this marker up.
+//
+
+function markerMoveUp(marker)   // called from router.html
+{
+ if(marker==1)
+   {
+    for(var m=1;m<vismarkers;m++)
+       markerSwap(m,m+1);
+   }
+ else
+    markerSwap(marker,marker-1);
+}
+
+
+//
+// Move this marker down.
+//
+
+function markerMoveDown(marker) // called from router.html
+{
+ if(marker==vismarkers)
+   {
+    for(var m=vismarkers;m>1;m--)
+       markerSwap(m,m-1);
+   }
+ else
+    markerSwap(marker,marker+1);
+}
+
+
+//
+// Copy a marker from one place to another.
+//
+
+function markerCopy(marker1,marker2)
+{
+ for(var element in routino.point[marker2])
+    routino.point[marker1][element]=routino.point[marker2][element];
+
+ document.getElementById("search" + marker1).style.display=document.getElementById("search" + marker2).style.display;
+
+ document.getElementById("coords" + marker1).style.display=document.getElementById("coords" + marker2).style.display;
+
+ document.forms["form"].elements["search" + marker1].value=document.forms["form"].elements["search" + marker2].value;
+
+ formSetCoords(marker1,routino.point[marker1].lon,routino.point[marker1].lat);
+
+ markerAddRemoveMap(marker1,routino.point[marker1].active);
+}
+
+
+//
+// Swap a pair of markers.
+//
+
+function markerSwap(marker1,marker2)
+{
+ for(var element in routino.point[marker2])
+   {
+    var temp=routino.point[marker1][element];
+    routino.point[marker1][element]=routino.point[marker2][element];
+    routino.point[marker2][element]=temp;
+   }
+
+ var search_display=document.getElementById("search" + marker1).style.display;
+ document.getElementById("search" + marker1).style.display=document.getElementById("search" + marker2).style.display;
+ document.getElementById("search" + marker2).style.display=search_display;
+
+ var coords_display=document.getElementById("coords" + marker1).style.display;
+ document.getElementById("coords" + marker1).style.display=document.getElementById("coords" + marker2).style.display;
+ document.getElementById("coords" + marker2).style.display=coords_display;
+
+ var search_value=document.forms["form"].elements["search" + marker1].value;
+ document.forms["form"].elements["search" + marker1].value=document.forms["form"].elements["search" + marker2].value;
+ document.forms["form"].elements["search" + marker2].value=search_value;
+
+ formSetCoords(marker1,routino.point[marker1].lon,routino.point[marker1].lat);
+ formSetCoords(marker2,routino.point[marker2].lon,routino.point[marker2].lat);
+
+ markerAddRemoveMap(marker1,routino.point[marker1].active);
+ markerAddRemoveMap(marker2,routino.point[marker2].active);
+}
+
+
+//
+// Reverse the markers.
+//
+
+function markersReverse()       // called from router.html
+{
+ for(var marker=1;marker<=vismarkers/2;marker++)
+    markerSwap(marker,vismarkers+1-marker);
+
+ markersmoved=true;
+
+ updateURLs();
+}
+
+
+//
+// Close the loop.
+//
+
+function markersLoop()          // called from router.html
+{
+ if(vismarkers==mapprops.maxmarkers)
+    return false;
+
+ if(routino.point[vismarkers].lon==routino.point[1].lon && routino.point[vismarkers].lat==routino.point[1].lat)
+   {
+    if(routino.point[vismarkers].active)
+       return false;
+    else
+      {
+       markerToggleMap(vismarkers);
+       return true;
+      }
+   }
+
+ if(routino.point[vismarkers].used)
+    markerAddForm(++vismarkers);
+
+ markerCopy(vismarkers,1);
+
+ markersmoved=true;
+
+ updateURLs();
+
+ updateSearchButtons();
+}
+
+
+//
+// Display the form for a marker
+//
+
+function markerAddForm(marker)
+{
+ document.getElementById("waypoint" + marker).style.display="";
+}
+
+
+//
+// Hide the form for a marker
+//
+
+function markerRemoveForm(marker)
+{
+ document.getElementById("waypoint" + marker).style.display="none";
+
+ markerClearForm(marker);
+}
+
+
+//
+// Clear the form for a marker
+//
+
+function markerClearForm(marker)
+{
+ markerRemoveMap(marker);
+ markerCoords(marker);
+
+ formSetCoords(marker,"","");
+ formSetSearch(marker,"");
+
+ updateIcon(marker);
+
+ routino.point[marker].used=false;
+ routino.point[marker].home=false;
+ routino.point[marker].active=false;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//////////////////////////// Route results handling ////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+var route_light_colours={shortest: "#60C060", quickest: "#6060C0"};
+var route_dark_colours ={shortest: "#408040", quickest: "#404080"};
+
+var highlights={shortest: null, quickest: null};
+var popups={shortest: null, quickest: null};
+var routepoints={shortest: {}, quickest: {}};
+
+//
+// Highlight a specific item in the route
+//
+
+function highlight(type,line,action)
+{
+ if(action == "clear")
+   {
+    layerVectors.removeLayer(highlights[type]);
+
+    drawPopup(type,null);
+   }
+ else if(action == "zoom")
+   {
+    var lonlat = L.latLng(routepoints[type][line].lat,routepoints[type][line].lon);
+
+    map.setView(lonlat,mapprops.zoomin-2);
+   }
+ else
+   {
+    // Marker
+
+    var lonlat = L.latLng(routepoints[type][line].lat,routepoints[type][line].lon);
+
+    highlights[type].setLatLng(lonlat);
+
+    layerVectors.addLayer(highlights[type]);
+
+    // Popup
+
+    drawPopup(type,"<table>" + routepoints[type][line].html + "</table>");
+   }
+
+ highlights[type].redraw();
+}
+
+
+//
+// Create a popup - independent of map because want it fixed on screen not fixed on map.
+//
+
+function createPopup(type)
+{
+ var popup=document.createElement("div");
+
+ popup.className = "popup";
+
+ popup.innerHTML = "<span></span>";
+
+ popup.style.display = "none";
+
+ popup.style.position = "fixed";
+ popup.style.top = "-4000px";
+ popup.style.left = "-4000px";
+ popup.style.zIndex = "100";
+
+ popup.style.padding = "5px";
+
+ popup.style.opacity=0.85;
+ popup.style.backgroundColor=route_light_colours[type];
+ popup.style.border="4px solid " + route_dark_colours[type];
+
+ document.body.appendChild(popup);
+
+ return(popup);
+}
+
+
+//
+// Draw a popup - independent of map because want it fixed on screen not fixed on map.
+//
+
+function drawPopup(type,html)
+{
+ var popup=popups[type];
+
+ if(html===null)
+   {
+    popup.style.display="none";
+    return;
+   }
+
+ if(popup.style.display=="none")
+   {
+    var map_div=document.getElementById("map");
+
+    popup.style.left  =map_div.offsetParent.offsetLeft+map_div.offsetLeft+60 + "px";
+    popup.style.top   =                                map_div.offsetTop +30 + "px";
+    popup.style.width =map_div.clientWidth-120 + "px";
+
+    popup.style.display="";
+   }
+
+ var close="<span style='float: right; cursor: pointer;' onclick='highlight(\""+type+"\",-1,\"clear\")'>X</span>";
+
+ popup.innerHTML=close+html;
+}
+
+
+//
+// Remove a GPX trace
+//
+
+function removeGPXTrace(type)
+{
+ map.removeLayer(layerGPX[type]);
+ layerGPX[type]=null;
+
+ displayStatus(type,"no_info");
+
+ document.getElementById(type + "_links").style.display = "none";
+
+ document.getElementById(type + "_route").innerHTML = "";
+
+ hideshow_hide(type);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Server handling ////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+//
+// Define an AJAX request object
+//
+
+function ajaxGET(url,success,failure,state)
+{
+ var ajaxRequest=new XMLHttpRequest();
+
+ function ajaxGOT(options) {
+  if(this.readyState==4)
+     if(this.status==200)
+       { if(typeof(options.success)=="function") options.success(this,options.state); }
+     else
+       { if(typeof(options.failure)=="function") options.failure(this,options.state); }
+ }
+
+ ajaxRequest.onreadystatechange = function(){ ajaxGOT.call(ajaxRequest,{success: success, failure: failure, state: state}); };
+ ajaxRequest.open("GET", url, true);
+ ajaxRequest.send(null);
+}
+
+
+//
+// Display data statistics
+//
+
+function displayStatistics() // called from router.html
+{
+ // Use AJAX to get the statistics
+
+ ajaxGET("statistics.cgi", runStatisticsSuccess);
+}
+
+
+//
+// Success in running data statistics generation.
+//
+
+function runStatisticsSuccess(response)
+{
+ document.getElementById("statistics_data").innerHTML="<pre>" + response.responseText + "</pre>";
+ document.getElementById("statistics_link").style.display="none";
+}
+
+
+//
+// Submit form - perform the routing
+//
+
+function findRoute(type) // called from router.html
+{
+ tab_select("results");
+
+ hideshow_hide("help_options");
+ hideshow_hide("shortest");
+ hideshow_hide("quickest");
+
+ displayStatus("result","running");
+
+ var url="router.cgi" + "?" + buildURLArguments(true) + ";type=" + type;
+
+ // Destroy the existing layer(s)
+
+ highlight("shortest",-1,"clear");
+ highlight("quickest",-1,"clear");
+
+ if(markersmoved || paramschanged)
+   {
+    if(layerGPX.shortest!==null)
+       removeGPXTrace("shortest");
+    if(layerGPX.quickest!==null)
+       removeGPXTrace("quickest");
+    markersmoved=false;
+    paramschanged=false;
+   }
+ else if(layerGPX[type]!==null)
+    removeGPXTrace(type);
+
+ // Use AJAX to run the router
+
+ routing_type=type;
+
+ ajaxGET(url, runRouterSuccess, runRouterFailure);
+}
+
+
+//
+// Success in running router.
+//
+
+function runRouterSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var uuid=lines[0];
+ var success=lines[1];
+
+ var link;
+
+ // Update the status message
+
+ if(success=="ERROR")
+   {
+    displayStatus("result","error");
+    hideshow_show("help_route");
+
+    link=document.getElementById("router_log_error");
+    link.href="results.cgi?uuid=" + uuid + ";type=router;format=log";
+
+    return;
+   }
+ else
+   {
+    displayStatus("result","complete");
+    hideshow_hide("help_route");
+
+    link=document.getElementById("router_log_complete");
+    link.href="results.cgi?uuid=" + uuid + ";type=router;format=log";
+   }
+
+ // Update the routing result message
+
+ link=document.getElementById(routing_type + "_html");
+ link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=html";
+
+ link=document.getElementById(routing_type + "_gpx_track");
+ link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-track";
+
+ link=document.getElementById(routing_type + "_gpx_route");
+ link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-route";
+
+ link=document.getElementById(routing_type + "_text_all");
+ link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=text-all";
+
+ link=document.getElementById(routing_type + "_text");
+ link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=text";
+
+ document.getElementById(routing_type + "_links").style.display = "";
+
+ // Add a GPX layer
+
+ var url="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-track";
+
+ ajaxGET(url, runGPXSuccess);
+ 
+ hideshow_show(routing_type);
+
+ displayResult(routing_type,uuid);
+}
+
+
+//
+// Success in getting GPX.
+//
+
+function runGPXSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var coords=[];
+ var segment=-1;
+
+ for(var line=0;line<lines.length;line++)
+   {
+    if(lines[line].match(/^<trkseg>/))
+       {
+        segment++;
+        coords[segment]=[];
+       }
+    if(lines[line].match(/^<trkpt lat="([-0-9.]+)" lon="([-0-9.]+)"/))
+      {
+       var lat=RegExp.$1;
+       var lon=RegExp.$2;
+
+       coords[segment].push(L.latLng(lat,lon));
+      }
+   }
+
+ var colour;
+
+ if(routing_type == "shortest")
+    colour="#00FF00";
+ else
+    colour="#0000FF";
+
+ layerGPX[routing_type] = L.multiPolyline(coords,{weight: 3, stroke: true, color: colour, opacity: 1.0,
+                                                  fill: false});
+
+ map.addLayer(layerGPX[routing_type]);
+}
+
+
+//
+// Failure in running router.
+//
+
+function runRouterFailure(response)
+{
+ displayStatus("result","failed");
+}
+
+
+//
+// Display the status
+//
+
+function displayStatus(type,subtype,content)
+{
+ var child=document.getElementById(type + "_status").firstChild;
+
+ do
+   {
+    if(child.id !== undefined)
+       child.style.display="none";
+
+    child=child.nextSibling;
+   }
+ while(child !== null);
+
+ var chosen_status=document.getElementById(type + "_status_" + subtype);
+
+ chosen_status.style.display="";
+
+ if(content !== undefined)
+    chosen_status.innerHTML=content;
+}
+
+
+//
+// Display the route
+//
+
+function displayResult(type,uuid)
+{
+ routing_type = type;
+
+ // Add the route
+
+ var url="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=html";
+
+ // Use AJAX to get the route
+
+ ajaxGET(url, getRouteSuccess, getRouteFailure);
+}
+
+
+//
+// Success in getting route.
+//
+
+function getRouteSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ routepoints[routing_type]=[];
+
+ var points=routepoints[routing_type];
+
+ var table=0;
+ var point=0;
+ var total_table,total_word;
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var thisline=lines[line];
+
+    if(table===0)
+      {
+       if(thisline.match("<table>"))
+          table=1;
+       else
+          continue;
+      }
+
+    if(thisline.match("</table>"))
+       break;
+
+    if(thisline.match("<tr class='([a-z])'>"))
+      {
+       var rowtype=RegExp.$1;
+
+       if(rowtype=="c")
+         {
+          thisline.match("<td class='r'> *([-0-9.]+) *([-0-9.]+)");
+          points[point]={lat: Number(RegExp.$1), lon: Number(RegExp.$2), html: "", highway: "", distance: "", total: ""};
+
+          point++;
+         }
+       else if(rowtype=="n")
+         {
+          points[point-1].html += thisline;
+         }
+       else if(rowtype=="s")
+         {
+          thisline.match("<span class='h'>([^<]+)</span>");
+          points[point-1].highway = RegExp.$1;
+
+          thisline.match("<span class='d'>([^<]+)</span>");
+          points[point-1].distance = RegExp.$1;
+
+          thisline.match("(<span class='j'>[^<]+</span>)");
+          points[point-1].total = RegExp.$1;
+
+          thisline.match("^(.*).<span class='j'>");
+
+          points[point-1].html += RegExp.$1;
+         }
+       else if(rowtype=="t")
+         {
+          points[point-1].html += thisline;
+
+          thisline.match("^(.*<td class='r'>)");
+          total_table = RegExp.$1;
+
+          thisline.match("<td class='l'>([^<]+)<");
+          total_word = RegExp.$1;
+
+          thisline.match("<span class='j'>([^<]+)</span>");
+          points[point-1].total = RegExp.$1;
+         }
+      }
+   }
+
+ displayStatus(routing_type,"info",points[point-1].total.bold());
+
+ var result="<table onmouseout='highlight(\"" + routing_type + "\",-1,\"clear\")'>";
+
+ for(var p=0;p<point-1;p++)
+   {
+    points[p].html += total_table + points[p].total;
+
+    result=result + "<tr onmouseover='highlight(\"" + routing_type + "\"," + p + ",\"show\")'>" +
+                    "<td onclick='highlight(\"" + routing_type + "\"," + p + ",\"zoom\")'" +
+                    " class='distance' title='" + points[p].distance + "'>#" + (p+1) +
+                    "<td class='highway'>" + points[p].highway;
+   }
+
+ result=result + "<tr onmouseover='highlight(\"" + routing_type + "\"," + p + ",\"show\")'>" +
+                 "<td onclick='highlight(\"" + routing_type + "\"," + p + ",\"zoom\")'" +
+                 " class='distance'>#" + (p+1) +
+                 "<td class='highway'>" + total_word + " " + points[p].total;
+
+ result=result + "</table>";
+
+ document.getElementById(routing_type + "_route").innerHTML=result;
+}
+
+
+//
+// Failure in getting route.
+//
+
+function getRouteFailure(response)
+{
+ document.getElementById(routing_type + "_route").innerHTML = "";
+}
+
+
+//
+// Perform a search
+//
+
+function DoSearch(marker)
+{
+ // Use AJAX to get the search result
+
+ var search=routino.point[marker].search;
+
+ var mapbounds=map.getBounds();
+
+ var url="search.cgi";
+
+ url=url + "?marker=" + marker;
+ url=url + ";lonmin=" + format5f(mapbounds.getWest());
+ url=url + ";latmin=" + format5f(mapbounds.getSouth());
+ url=url + ";lonmax=" + format5f(mapbounds.getEast());
+ url=url + ";latmax=" + format5f(mapbounds.getNorth());
+ url=url + ";search=" + encodeURIComponent(search);
+
+ ajaxGET(url,runSearchSuccess);
+}
+
+
+var searchresults=[];
+
+//
+// Success in running search.
+//
+
+function runSearchSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var marker=lines[0];
+ var cpuinfo=lines[1];  // not used
+ var message=lines[2];
+
+ if(message !== "")
+   {
+    alert(message);
+    return;
+   }
+
+ searchresults[marker]=[];
+
+ for(var line=3;line<lines.length;line++)
+   {
+    var thisline=lines[line];
+
+    if(thisline==="")
+       break;
+
+    thisline.match("([-.0-9]+) ([-.0-9]+) (.*)");
+
+    searchresults[marker][searchresults[marker].length]={lat: Number(RegExp.$1), lon: Number(RegExp.$2), name: RegExp.$3};
+   }
+
+ if(searchresults[marker].length==1)
+   {
+    formSetSearch(marker,searchresults[marker][0].name);
+    formSetCoords(marker,searchresults[marker][0].lon,searchresults[marker][0].lat);
+    markerAddMap(marker);
+   }
+ else
+   {
+    var results=document.getElementById("searchresults" + marker);
+
+    var innerHTML="<td colspan=\"3\">";
+
+    for(var n=0;n<searchresults[marker].length;n++)
+      {
+       if(n>0)
+          innerHTML+="<br>";
+
+       innerHTML+="<a href=\"#\" onclick=\"choseSearchResult(" + marker + "," + n + ")\">" +
+                  searchresults[marker][n].name +
+                  "</a>";
+      }
+
+    results.innerHTML=innerHTML;
+
+    results.style.display="";
+   }
+}
+
+
+//
+// Display search results.
+//
+
+function choseSearchResult(marker,n)
+{
+ if(n>=0)
+   {
+    formSetSearch(marker,searchresults[marker][n].name);
+    formSetCoords(marker,searchresults[marker][n].lon,searchresults[marker][n].lat);
+    markerAddMap(marker);
+   }
+}
+
+
+//
+// Clear search results.
+//
+
+function clearSearchResult(marker)
+{
+ document.getElementById("searchresults" + marker).style.display="none";
+}
diff --git a/3rdparty/Routino/web/www/routino/router.openlayers.js b/3rdparty/Routino/web/www/routino/router.openlayers.js
new file mode 100644
index 0000000..bb3ca27
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/router.openlayers.js
@@ -0,0 +1,2275 @@
+//
+// Routino router web page Javascript
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2015 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+var vismarkers, markers, markersmoved, paramschanged;
+var homelat=null, homelon=null;
+
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Initialisation /////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+// Make a deep copy of the routino profile.
+
+var routino_default={};
+for(var l1 in routino)
+   if(typeof(routino[l1])!="object")
+      routino_default[l1]=routino[l1];
+   else
+     {
+      routino_default[l1]={};
+      for(var l2 in routino[l1])
+         if(typeof(routino[l1][l2])!="object")
+            routino_default[l1][l2]=Number(routino[l1][l2]);
+         else
+           {
+            routino_default[l1][l2]={};
+            for(var l3 in routino[l1][l2])
+               routino_default[l1][l2][l3]=Number(routino[l1][l2][l3]);
+           }
+     }
+
+// Store the latitude and longitude in the routino variable
+
+routino.point=[];
+for(var marker=1;marker<=mapprops.maxmarkers;marker++)
+  {
+   routino.point[marker]={};
+
+   routino.point[marker].lon="";
+   routino.point[marker].lat="";
+   routino.point[marker].search="";
+   routino.point[marker].active=false;
+   routino.point[marker].used=false;
+   routino.point[marker].home=false;
+  }
+
+// Process the URL query string and extract the arguments
+
+var legal={"^lon"             : "^[-0-9.]+$",
+           "^lat"             : "^[-0-9.]+$",
+           "^zoom"            : "^[0-9]+$",
+
+           "^lon[1-9]"        : "^[-0-9.]+$",
+           "^lat[1-9]"        : "^[-0-9.]+$",
+           "^search[1-9]"     : "^.+$",
+           "^transport"       : "^[a-z]+$",
+           "^highway-[a-z]+"  : "^[0-9.]+$",
+           "^speed-[a-z]+"    : "^[0-9.]+$",
+           "^property-[a-z]+" : "^[0-9.]+$",
+           "^oneway"          : "^(1|0|true|false|on|off)$",
+           "^turns"           : "^(1|0|true|false|on|off)$",
+           "^weight"          : "^[0-9.]+$",
+           "^height"          : "^[0-9.]+$",
+           "^width"           : "^[0-9.]+$",
+           "^length"          : "^[0-9.]+$",
+
+           "^language"        : "^[-a-zA-Z]+$"};
+
+var args={};
+
+if(location.search.length>1)
+  {
+   var query,queries;
+
+   query=location.search.replace(/^\?/,"");
+   query=query.replace(/;/g,"&");
+   queries=query.split("&");
+
+   for(var i=0;i<queries.length;i++)
+     {
+      queries[i].match(/^([^=]+)(=(.*))?$/);
+
+      var k=RegExp.$1;
+      var v=decodeURIComponent(RegExp.$3);
+
+      for(var l in legal)
+        {
+         if(k.match(RegExp(l)) && v.match(RegExp(legal[l])))
+            args[k]=v;
+        }
+     }
+  }
+
+
+//
+// Fill in the HTML - add the missing waypoints
+//
+
+function html_init()            // called from router.html
+{
+ var waypoints=document.getElementById("waypoints");
+
+ var waypoint_html=waypoints.firstElementChild.outerHTML.split("XXX");
+
+ waypoints.removeChild(waypoints.firstElementChild);
+
+ for(var marker=1;marker<=mapprops.maxmarkers;marker++)
+   {
+    var waypoint=document.createElement('div');
+
+    waypoints.appendChild(waypoint);
+
+    waypoint.outerHTML=waypoint_html.join(marker);
+   }
+
+ waypoints.addEventListener('dragstart',dragWaypointStart,false);
+ waypoints.addEventListener('dragend'  ,dragWaypointEnd  ,false);
+ waypoints.addEventListener('dragenter',dragWaypointEnter,false);
+ waypoints.addEventListener('dragover' ,dragWaypointOver ,false);
+ waypoints.addEventListener('dragleave',dragWaypointLeave,false);
+ waypoints.addEventListener('drop'     ,dragWaypointDrop ,false);
+
+
+ var map=document.getElementById("map");
+
+ map.addEventListener('dragenter',dragWaypointMapEnter,false);
+ map.addEventListener('dragover' ,dragWaypointMapOver ,false);
+ map.addEventListener('dragleave',dragWaypointMapLeave,false);
+ map.addEventListener('drop'     ,dragWaypointMapDrop ,false);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////// Form handling /////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+//
+// Form initialisation - fill in the uninitialised parts
+//
+
+function form_init()            // called from router.html
+{
+ // Fill in the waypoints
+
+ vismarkers=0;
+
+ for(var marker=mapprops.maxmarkers;marker>=1;marker--)
+   {
+    var lon=args["lon" + marker];
+    var lat=args["lat" + marker];
+    var search=args["search" + marker];
+
+    if(lon !== undefined && lat !== undefined && search !== undefined && lon !== "" && lat !== "" && search !== "")
+      {
+       markerAddForm(marker);
+
+       formSetSearch(marker,search);
+       formSetCoords(marker,lon,lat);
+
+       markerAddMap(marker);
+
+       markerSearch(marker);
+
+       vismarkers++;
+      }
+    else if(lon !== undefined && lat !== undefined && lon !== "" && lat !== "")
+      {
+       markerAddForm(marker);
+
+       formSetCoords(marker,lon,lat);
+
+       markerAddMap(marker);
+
+       markerCoords(marker);
+
+       vismarkers++;
+      }
+    else if(search !== undefined && search !== "")
+      {
+       markerAddForm(marker);
+
+       formSetSearch(marker,search);
+
+       markerSearch(marker);
+
+       DoSearch(marker);
+
+       vismarkers++;
+      }
+    else if(vismarkers || marker<=2)
+      {
+       markerAddForm(marker);
+
+       vismarkers++;
+      }
+
+    var searchfield=document.forms["form"].elements["search" + marker];
+
+    if(searchfield.addEventListener)
+       searchfield.addEventListener("keyup", searchOnReturnKey, false);
+    else if(searchfield.attachEvent)
+       searchfield.attachEvent("keyup", searchOnReturnKey); // Internet Explorer
+   }
+
+ // Update the transport type with the URL settings which updates all HTML forms to defaults.
+
+ var transport=routino.transport;
+
+ if(args["transport"] !== undefined)
+    transport=args["transport"];
+
+ formSetTransport(transport);
+
+ // Update the HTML with the URL settings
+
+ if(args["language"] !== undefined)
+    formSetLanguage(args["language"]);
+
+ for(var key in routino.profile_highway)
+    if(args["highway-" + key] !== undefined)
+       formSetHighway(key,args["highway-" + key]);
+
+ for(var key in routino.profile_speed)
+    if(args["speed-" + key] !== undefined)
+       formSetSpeed(key,args["speed-" + key]);
+
+ for(var key in routino.profile_property)
+    if(args["property-" + key] !== undefined)
+       formSetProperty(key,args["property-" + key]);
+
+ for(var key in routino.restrictions)
+   {
+    if(key=="oneway" || key=="turns")
+      {
+       if(args[key] !== undefined)
+          formSetRestriction(key,args[key]);
+      }
+    else
+      {
+       if(args["restrict-" + key] !== undefined)
+          formSetRestriction(key,args["restrict-" + key]);
+      }
+   }
+
+ // Get the home location cookie and compare to each waypoint
+
+ var cookies=document.cookie.split("; ");
+
+ for(var cookie=0;cookie<cookies.length;cookie++)
+    if(cookies[cookie].substr(0,"Routino-home".length)=="Routino-home")
+      {
+       var data=cookies[cookie].split(/[=:;]/);
+
+       if(data[1]=="lon") homelon=Number(data[2]);
+       if(data[3]=="lat") homelat=Number(data[4]);
+      }
+
+ if(homelon!==null && homelat!==null)
+   {
+    for(var m=1;m<=vismarkers;m++)
+       markerCheckHome(m);
+
+    // If the first location is empty and the cookie is set then fill it.
+
+    if(!routino.point[1].used)
+       markerMoveHome(1);
+   }
+
+ updateURLs();
+
+ updateSearchButtons();
+}
+
+
+//
+// Function to perform the search if the return key is pressed.
+// (using 'onchange' only triggers once and is confusing when clicking outside the field).
+//
+
+function searchOnReturnKey(ev)
+{
+ if(ev.keyCode==13)
+    if(this.name.match(/^search([0-9]+)$/))
+       formSetSearch(RegExp.$1);
+
+ return(true);
+}
+
+
+//
+// Change of language in the form
+//
+
+function formSetLanguage(value) // called from router.html (with no arguments)
+{
+ if(value === undefined)
+   {
+    for(var lang=0;lang<document.forms["form"].elements["language"].length;lang++)
+       if(document.forms["form"].elements["language"][lang].checked)
+          routino.language=document.forms["form"].elements["language"][lang].value;
+   }
+ else
+   {
+    for(var lang=0;lang<document.forms["form"].elements["language"].length;lang++)
+       if(document.forms["form"].elements["language"][lang].value==value)
+          document.forms["form"].elements["language"][lang].checked=true;
+       else
+          document.forms["form"].elements["language"][lang].checked=false;
+
+    routino.language=value;
+   }
+
+ updateURLs();
+}
+
+
+//
+// Change of transport in the form
+//
+
+function formSetTransport(value) // called from router.html
+{
+ routino.transport=value;
+
+ for(var key in routino.transports)
+    document.forms["form"].elements["transport"][routino.transports[key]-1].checked=(key==routino.transport);
+
+ for(var key in routino.profile_highway)
+    document.forms["form"].elements["highway-" + key].value=routino.profile_highway[key][routino.transport];
+
+ for(var key in routino.profile_speed)
+    document.forms["form"].elements["speed-" + key].value=routino.profile_speed[key][routino.transport];
+
+ for(var key in routino.profile_property)
+    document.forms["form"].elements["property-" + key].value=routino.profile_property[key][routino.transport];
+
+ for(var key in routino.restrictions)
+   {
+    if(key=="oneway" || key=="turns")
+       document.forms["form"].elements["restrict-" + key].checked=routino.profile_restrictions[key][routino.transport];
+    else
+       document.forms["form"].elements["restrict-" + key].value=routino.profile_restrictions[key][routino.transport];
+   }
+
+ paramschanged=true;
+
+ updateURLs();
+}
+
+
+//
+// Change of highway in the form
+//
+
+function formSetHighway(type,value) // called from router.html (with one argument)
+{
+ if(value == "+")
+   {
+    value=routino.profile_highway[type][routino.transport];
+    value=10*Math.floor(value/10)+10;
+   }
+ else if(value == "-")
+   {
+    value=routino.profile_highway[type][routino.transport]-10;
+    value=10*Math.ceil(value/10)-10;
+   }
+ else if(value == "=")
+    value=document.forms["form"].elements["highway-" + type].value;
+
+ value=Number(value);
+ if(isNaN(value)) value= 50;
+ if(value>100)    value=100;
+ if(value<  0)    value=  0;
+
+ document.forms["form"].elements["highway-" + type].value=value;
+ routino.profile_highway[type][routino.transport]=value;
+
+ paramschanged=true;
+
+ updateURLs();
+}
+
+
+//
+// Change of Speed in the form
+//
+
+function formSetSpeed(type,value) // called from router.html (with one argument)
+{
+ if(value == "+")
+   {
+    value=routino.profile_speed[type][routino.transport];
+    if(value<10) value=2*Math.floor(value/2)+2;
+    else if(value<30) value=5*Math.floor(value/5)+5;
+    else value=10*Math.floor(value/10)+10;
+   }
+ else if(value == "-")
+   {
+    value=routino.profile_speed[type][routino.transport];
+    if(value<=10) value=2*Math.ceil(value/2)-2;
+    else if(value<=30) value=5*Math.ceil(value/5)-5;
+    else value=10*Math.ceil(value/10)-10;
+   }
+ else if(value == "=")
+    value=document.forms["form"].elements["speed-" + type].value;
+
+ value=Number(value);
+ if(isNaN(value)) value= 60;
+ if(value>150)    value=150;
+ if(value<  0)    value=  0;
+
+ document.forms["form"].elements["speed-" + type].value=value;
+ routino.profile_speed[type][routino.transport]=value;
+
+ paramschanged=true;
+
+ updateURLs();
+}
+
+
+//
+// Change of Property in the form
+//
+
+function formSetProperty(type,value) // called from router.html (with one argument)
+{
+ if(value == "+")
+   {
+    value=routino.profile_property[type][routino.transport];
+    if(value>=40 && value<60) value=2*Math.floor(value/2)+2;
+    else value=5*Math.floor(value/5)+5;
+   }
+ else if(value == "-")
+   {
+    value=routino.profile_property[type][routino.transport];
+    if(value>40 && value<=60) value=2*Math.ceil(value/2)-2;
+    else value=5*Math.ceil(value/5)-5;
+   }
+ else if(value == "=")
+    value=document.forms["form"].elements["property-" + type].value;
+
+ value=Number(value);
+ if(isNaN(value)) value= 50;
+ if(value>100)    value=100;
+ if(value<  0)    value=  0;
+
+ document.forms["form"].elements["property-" + type].value=value;
+ routino.profile_property[type][routino.transport]=value;
+
+ paramschanged=true;
+
+ updateURLs();
+}
+
+
+//
+// Change of Restriction rule in the form
+//
+
+function formSetRestriction(type,value) // called from router.html (with one argument)
+{
+ if(type=="oneway" || type=="turns")
+   {
+    if(value === undefined)
+       routino.profile_restrictions[type][routino.transport]=document.forms["form"].elements["restrict-" + type].checked;
+    else
+       document.forms["form"].elements["restrict-" + type].checked=value;
+
+    routino.profile_restrictions[type][routino.transport]=value;
+   }
+ else if(type=="weight")
+   {
+    if(value == "+")
+       value=routino.profile_restrictions[type][routino.transport]+5;
+    else if(value == "-")
+       value=routino.profile_restrictions[type][routino.transport]-5;
+    else if(value == "=")
+       value=document.forms["form"].elements["restrict-" + type].value;
+
+    value=Number(value);
+    if(isNaN(value)) value= 0;
+    if(value>50)     value=50;
+    if(value< 0)     value= 0;
+
+    document.forms["form"].elements["restrict-" + type].value=value;
+    routino.profile_restrictions[type][routino.transport]=value;
+   }
+ else /* if(type=="height" || type=="width" || type=="length") */
+   {
+    if(value == "+")
+       value=routino.profile_restrictions[type][routino.transport]+1;
+    else if(value == "-")
+       value=routino.profile_restrictions[type][routino.transport]-1;
+    else if(value == "=")
+       value=document.forms["form"].elements["restrict-" + type].value;
+
+    value=Number(value);
+    if(isNaN(value)) value= 0;
+    if(value>25)     value=25;
+    if(value< 0)     value= 0;
+
+    document.forms["form"].elements["restrict-" + type].value=value;
+    routino.profile_restrictions[type][routino.transport]=value;
+   }
+
+ paramschanged=true;
+
+ updateURLs();
+}
+
+
+//
+// Set the feature coordinates from the form when the form changes.
+//
+
+function formSetCoords(marker,lon,lat) // called from router.html (with one argument)
+{
+ clearSearchResult(marker);
+
+ if(lon === undefined && lat === undefined)
+   {
+    lon=document.forms["form"].elements["lon" + marker].value;
+    lat=document.forms["form"].elements["lat" + marker].value;
+   }
+
+ if(lon === "" && lat === "")
+   {
+    document.forms["form"].elements["lon" + marker].value="";
+    document.forms["form"].elements["lat" + marker].value="";
+
+    routino.point[marker].lon="";
+    routino.point[marker].lat="";
+
+    updateURLs();
+   }
+ else
+   {
+    var lonlat;
+
+    if(lon==="")
+      {
+       lonlat=map.getCenter().clone();
+       lonlat.transform(epsg900913,epsg4326);
+
+       lon=lonlat.lon;
+      }
+
+    if(lon<-180) lon=-180;
+    if(lon>+180) lon=+180;
+
+    if(lat==="")
+      {
+       lonlat=map.getCenter().clone();
+       lonlat.transform(epsg900913,epsg4326);
+
+       lat=lonlat.lat;
+      }
+
+    if(lat<-90 ) lat=-90 ;
+    if(lat>+90 ) lat=+90 ;
+
+    lonlat = new OpenLayers.LonLat(lon,lat);
+    lonlat.transform(epsg4326,epsg900913);
+
+    markers[marker].move(lonlat);
+
+    markersmoved=true;
+
+    document.forms["form"].elements["lon" + marker].value=format5f(lon);
+    document.forms["form"].elements["lat" + marker].value=format5f(lat);
+
+    routino.point[marker].lon=lon;
+    routino.point[marker].lat=lat;
+    routino.point[marker].used=true;
+
+    markerCheckHome(marker);
+   }
+}
+
+
+//
+// Set the search field from the form when the form changes.
+//
+
+function formSetSearch(marker,search) // called from event handler linked to router.html (with one argument)
+{
+ clearSearchResult(marker);
+
+ if(search === undefined)
+   {
+    routino.point[marker].search=document.forms["form"].elements["search" + marker].value;
+
+    DoSearch(marker);
+   }
+ else
+   {
+    document.forms["form"].elements["search" + marker].value=search;
+
+    routino.point[marker].search=search;
+   }
+}
+
+
+//
+// Format a number in printf("%.5f") format.
+//
+
+function format5f(number)
+{
+ var newnumber=Math.floor(number*100000+0.5);
+ var delta=0;
+
+ if(newnumber>=0 && newnumber<100000) delta= 100000;
+ if(newnumber<0 && newnumber>-100000) delta=-100000;
+
+ var string=String(newnumber+delta);
+
+ var intpart =string.substring(0,string.length-5);
+ var fracpart=string.substring(string.length-5,string.length);
+
+ if(delta>0) intpart="0";
+ if(delta<0) intpart="-0";
+
+ return(intpart + "." + fracpart);
+}
+
+
+//
+// Build a set of URL arguments
+//
+
+function buildURLArguments(lang)
+{
+ var url= "transport=" + routino.transport;
+
+ for(var marker=1;marker<=vismarkers;marker++)
+    if(routino.point[marker].active)
+      {
+       url=url + ";lon" + marker + "=" + routino.point[marker].lon;
+       url=url + ";lat" + marker + "=" + routino.point[marker].lat;
+       if(routino.point[marker].search !== "")
+          url=url + ";search" + marker + "=" + encodeURIComponent(routino.point[marker].search);
+      }
+
+ for(var key in routino.profile_highway)
+    if(routino.profile_highway[key][routino.transport]!=routino_default.profile_highway[key][routino.transport])
+       url=url + ";highway-" + key + "=" + routino.profile_highway[key][routino.transport];
+
+ for(var key in routino.profile_speed)
+    if(routino.profile_speed[key][routino.transport]!=routino_default.profile_speed[key][routino.transport])
+       url=url + ";speed-" + key + "=" + routino.profile_speed[key][routino.transport];
+
+ for(var key in routino.profile_property)
+    if(routino.profile_property[key][routino.transport]!=routino_default.profile_property[key][routino.transport])
+       url=url + ";property-" + key + "=" + routino.profile_property[key][routino.transport];
+
+ for(var key in routino.restrictions)
+    if(routino.profile_restrictions[key][routino.transport]!=routino_default.profile_restrictions[key][routino.transport])
+       url=url + ";" + key + "=" + routino.profile_restrictions[key][routino.transport];
+
+ if(lang && routino.language)
+    url=url + ";language=" + routino.language;
+
+ return(url);
+}
+
+
+//
+// Build a set of URL arguments for the map location
+//
+
+function buildMapArguments()
+{
+ var lonlat = map.getCenter().clone();
+ lonlat.transform(epsg900913,epsg4326);
+
+ var zoom = map.getZoom() + map.minZoomLevel;
+
+ return "lat=" + format5f(lonlat.lat) + ";lon=" + format5f(lonlat.lon) + ";zoom=" + zoom;
+}
+
+
+//
+// Update the URLs
+//
+
+function updateURLs()
+{
+ var urlargs1=buildURLArguments(true);
+ var urlargs2=buildURLArguments(false);
+ var mapargs=buildMapArguments();
+
+ var links=document.getElementsByTagName("a");
+
+ for(var i=0; i<links.length; i++)
+   {
+    var element=links[i];
+
+    if(element.id == "permalink_url")
+       element.href=location.pathname + "?" + urlargs1 + ";" + mapargs;
+
+    if(element.id == "visualiser_url")
+       element.href="visualiser.html" + "?" + mapargs;
+
+    if(element.id == "edit_url")
+       element.href=mapprops.editurl + "?" + mapargs;
+
+    if(element.id.match(/^lang_([a-zA-Z-]+)_url$/))
+       element.href="router.html" + "." + RegExp.$1 + "?" + urlargs2 + ";" + mapargs;
+   }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////// Map handling /////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+var map;
+var layerMap=[], layerVectors, layerGPX;
+var epsg4326, epsg900913;
+var routing_type;
+
+//
+// Initialise the 'map' object
+//
+
+function map_init()             // called from router.html
+{
+ // Create the map (Map URLs and limits are in mapprops.js)
+
+ epsg4326=new OpenLayers.Projection("EPSG:4326");
+ epsg900913=new OpenLayers.Projection("EPSG:900913");
+
+ map = new OpenLayers.Map ("map",
+                           {
+                            controls:[
+                                      new OpenLayers.Control.Navigation(),
+                                      new OpenLayers.Control.PanZoomBar(),
+                                      new OpenLayers.Control.ScaleLine(),
+                                      new OpenLayers.Control.LayerSwitcher()
+                                      ],
+
+                            projection: epsg900913,
+                            displayProjection: epsg4326,
+
+                            minZoomLevel: mapprops.zoomout,
+                            numZoomLevels: mapprops.zoomin-mapprops.zoomout+1,
+                            maxResolution: 156543.03390625 / Math.pow(2,mapprops.zoomout),
+
+                            restrictedExtent: new OpenLayers.Bounds(mapprops.westedge,mapprops.southedge,mapprops.eastedge,mapprops.northedge).transform(epsg4326,epsg900913)
+                           });
+
+ // Get a URL for the tile (mostly copied from OpenLayers/Layer/XYZ.js).
+
+ function limitedUrl(bounds)
+ {
+  var res = this.map.getResolution();
+
+  var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
+  var y = Math.round((this.maxExtent.top - bounds.top) / (res * this.tileSize.h));
+  var z = this.map.getZoom() + this.map.minZoomLevel;
+
+  var limit = Math.pow(2, z);
+  x = ((x % limit) + limit) % limit;
+
+  var xyz = {"x": x, "y": y, "z": z};
+  var url = this.url;
+
+  if (OpenLayers.Util.isArray(url))
+    {
+     var s = "" + xyz.x + xyz.y + xyz.z;
+     url = this.selectUrl(s, url);
+    }
+
+  return OpenLayers.String.format(url, xyz);
+ }
+
+ // Add map tile layers
+
+ for(var l=0; l<mapprops.mapdata.length; l++)
+   {
+    var urls;
+
+    if(OpenLayers.Util.isArray(mapprops.mapdata[l].tiles.subdomains))
+      {
+       urls=[];
+
+       for(var s=0; s<mapprops.mapdata[l].tiles.subdomains.length; s++)
+          urls.push(mapprops.mapdata[l].tiles.url.replace(/\${s}/,mapprops.mapdata[l].tiles.subdomains[s]));
+      }
+    else
+       urls=mapprops.mapdata[l].tiles.url;
+
+    layerMap[l] = new OpenLayers.Layer.TMS(mapprops.mapdata[l].label,
+                                           urls,
+                                           {
+                                            getURL: limitedUrl,
+                                            displayOutsideMaxExtent: true,
+                                            buffer: 1
+                                           });
+    map.addLayer(layerMap[l]);
+   }
+
+ // Update the attribution if the layer changes
+
+ function change_attribution_event(event)
+ {
+  for(var l=0; l<mapprops.mapdata.length; l++)
+     if(layerMap[l] == event.layer)
+        change_attribution(l);
+ }
+
+ map.events.register("changelayer",layerMap,change_attribution_event);
+
+ function change_attribution(l)
+ {
+  var data_url =mapprops.mapdata[l].attribution.data_url;
+  var data_text=mapprops.mapdata[l].attribution.data_text;
+  var tile_url =mapprops.mapdata[l].attribution.tile_url;
+  var tile_text=mapprops.mapdata[l].attribution.tile_text;
+
+  document.getElementById("attribution_data").innerHTML="<a href=\"" + data_url + "\" target=\"data_attribution\">" + data_text + "</a>";
+  document.getElementById("attribution_tile").innerHTML="<a href=\"" + tile_url + "\" target=\"tile_attribution\">" + tile_text + "</a>";
+ }
+
+ change_attribution(0);
+
+ // Define a GPX layer but don't add it yet
+
+ layerGPX={shortest: null, quickest: null};
+
+ gpx_style={shortest: new OpenLayers.Style({},{strokeWidth: 3, strokeColor: "#00FF00"}),
+            quickest: new OpenLayers.Style({},{strokeWidth: 3, strokeColor: "#0000FF"})};
+
+ // Add a vectors layer
+
+ layerVectors = new OpenLayers.Layer.Vector("Markers",{displayInLayerSwitcher: false});
+ map.addLayer(layerVectors);
+
+ // A set of markers
+
+ markers={};
+ markersmoved=false;
+ paramschanged=false;
+
+ for(var marker=1;marker<=mapprops.maxmarkers;marker++)
+   {
+    markers[marker] = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0),{},
+                                                    new OpenLayers.Style({},{externalGraphic: "icons/marker-" + marker + "-red.png",
+                                                                             fillColor: "white",
+                                                                             graphicYOffset: -25,
+                                                                             graphicWidth: 21,
+                                                                             graphicHeight: 25,
+                                                                             display: "none"}));
+
+    layerVectors.addFeatures([markers[marker]]);
+   }
+
+ // A function to drag the markers
+
+ var drag = new OpenLayers.Control.DragFeature(layerVectors,
+                                               {onDrag:     dragMarkerMove,
+                                                onComplete: dragMarkerComplete });
+ map.addControl(drag);
+ drag.activate();
+
+ // Markers to highlight a selected point
+
+ for(var highlight in highlights)
+   {
+    highlights[highlight] = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0),{},
+                                                          new OpenLayers.Style({},{strokeColor: route_dark_colours[highlight],
+                                                                                   fillColor: "white",
+                                                                                   pointRadius: 10,
+                                                                                   strokeWidth: 4,
+                                                                                   fillOpacity: 0,
+                                                                                   display: "none"}));
+
+    layerVectors.addFeatures([highlights[highlight]]);
+   }
+
+ // A popup for routing results
+
+ for(var popup in popups)
+    popups[popup] = createPopup(popup);
+
+ // Move the map
+
+ map.events.register("moveend", map, updateURLs);
+
+ var lon =args["lon"];
+ var lat =args["lat"];
+ var zoom=args["zoom"];
+
+ if(lon !== undefined && lat !== undefined && zoom !== undefined)
+   {
+    if(lon<mapprops.westedge) lon=mapprops.westedge;
+    if(lon>mapprops.eastedge) lon=mapprops.eastedge;
+
+    if(lat<mapprops.southedge) lat=mapprops.southedge;
+    if(lat>mapprops.northedge) lat=mapprops.northedge;
+
+    if(zoom<mapprops.zoomout) zoom=mapprops.zoomout;
+    if(zoom>mapprops.zoomin)  zoom=mapprops.zoomin;
+
+    var lonlat = new OpenLayers.LonLat(lon,lat);
+    lonlat.transform(epsg4326,epsg900913);
+
+    map.moveTo(lonlat,zoom-map.minZoomLevel);
+   }
+ else
+   {
+    map.setCenter(map.restrictedExtent.getCenterLonLat(), map.getZoomForExtent(map.restrictedExtent,true));
+    map.maxResolution = map.getResolution();
+   }
+
+ // Unhide editing URL if variable set
+
+ if(mapprops.editurl !== undefined && mapprops.editurl !== "")
+   {
+    var edit_url=document.getElementById("edit_url");
+
+    edit_url.style.display="";
+    edit_url.href=mapprops.editurl;
+   }
+
+ updateURLs();
+}
+
+
+//
+// Callback for a marker drag occuring on the map.
+//
+
+function dragMarkerMove(feature,pixel)
+{
+ for(var marker in markers)
+    if(feature==markers[marker])
+       dragMarkerSetForm(marker);
+}
+
+
+//
+// Callback for completing a marker drag on the map.
+//
+
+function dragMarkerComplete(feature,pixel)
+{
+ for(var marker in markers)
+    if(feature==markers[marker])
+       dragMarkerSetForm(marker);
+
+ updateURLs();
+}
+
+
+//
+// Set the feature coordinates in the form after dragging it on the map.
+//
+
+function dragMarkerSetForm(marker)
+{
+ var lonlat = new OpenLayers.LonLat(markers[marker].geometry.x, markers[marker].geometry.y);
+ lonlat.transform(epsg900913,epsg4326);
+
+ formSetCoords(marker,lonlat.lon,lonlat.lat);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Marker dragging ////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+var dragged_waypoint=null,dragged_marker=null;
+var dragged_waypoint_over=null,dragged_marker_over=null;
+var dragged_icon_x,dragged_icon_y;
+
+//
+// Drag a waypoint up or down the list.
+//
+
+function dragWaypointStart(e)
+{
+ var w=e.target;
+
+ while(w!=null && w.className != "waypoint")
+    w=w.parentElement;
+
+ if(w===null)
+    return;
+
+ w.style.opacity = "0.5";
+
+ dragged_waypoint=w;
+ dragged_marker=Number.parseInt(dragged_waypoint.id.substring(8));
+
+ dragged_icon_x=e.clientX-e.target.offsetLeft;
+ dragged_icon_y=e.clientY-e.target.offsetTop;
+}
+
+function dragWaypointEnd(e)
+{
+ e.preventDefault();
+
+ if(dragged_waypoint===null)
+    return;
+
+ dragged_waypoint.style.opacity = "";
+
+ dragged_waypoint=null;
+ dragged_marker=null;
+
+ if(dragged_waypoint_over===null)
+    return;
+
+ dragged_waypoint_over.style.border = "";
+
+ dragged_waypoint_over=null;
+ dragged_marker_over=null;
+}
+
+
+//
+// Drag a waypoint over another one up or down the list.
+//
+
+function dragWaypointEnter(e)
+{
+ var w=e.target;
+
+ while(w!=null && w.className != "waypoint")
+    w=w.parentElement;
+
+ if(w===null)
+    return;
+
+ if(dragged_waypoint_over!==null)
+    dragged_waypoint_over.style.border = "";
+
+ if(w==dragged_waypoint)
+    return;
+
+ dragged_waypoint_over=w;
+ dragged_marker_over=Number.parseInt(dragged_waypoint_over.id.substring(8));
+
+ if(dragged_marker>dragged_marker_over)
+    w.style.borderTop = "3px solid black";
+ else
+    w.style.borderBottom = "3px solid black";
+}
+
+function dragWaypointOver(e)
+{
+ e.preventDefault();
+}
+
+function dragWaypointLeave(e)
+{
+ var w=e.target;
+
+ while(w!=null && w.className != "waypoint")
+    w=w.parentElement;
+
+ if(w===null)
+    return;
+
+ if(w==dragged_waypoint_over)
+    return;
+
+ w.style.border = "";
+}
+
+
+//
+// Drop the waypoint after dragging up or down the list.
+//
+
+function dragWaypointDrop(e)
+{
+ e.preventDefault();
+
+ if(dragged_marker_over===null)
+    return;
+
+ if(dragged_marker_over>dragged_marker)
+    for(var m=dragged_marker;m<dragged_marker_over;m++)
+       markerSwap(m,m+1);
+
+ if(dragged_marker_over<dragged_marker)
+    for(var m=dragged_marker;m>dragged_marker_over;m--)
+       markerSwap(m,m-1);
+}
+
+
+//
+// Drag a waypoint over the map.
+//
+
+function dragWaypointMapEnter(e)
+{
+ e.preventDefault();
+
+ if(dragged_waypoint_over!==null)
+    dragged_waypoint_over.style.border = "";
+}
+
+function dragWaypointMapOver(e)
+{
+ e.preventDefault();
+}
+
+function dragWaypointMapLeave(e)
+{
+ e.preventDefault();
+}
+
+
+//
+// Drop the waypoint after dragging it over the map.
+//
+
+function dragWaypointMapDrop(e)
+{
+ e.preventDefault();
+
+ var rect = document.getElementById("map").getBoundingClientRect();
+
+ var lonlat = map.getLonLatFromViewPortPx(new OpenLayers.Pixel(e.clientX-rect.left-dragged_icon_x+8,e.clientY-rect.top-dragged_icon_y+21));
+ lonlat.transform(epsg900913,epsg4326);
+
+ formSetCoords(dragged_marker,lonlat.lon,lonlat.lat);
+
+ if(!routino.point[dragged_marker].active)
+    markerToggleMap(dragged_marker);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Marker handling ////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+//
+// Toggle a marker on the map.
+//
+
+function markerToggleMap(marker) // called from router.html
+{
+ if(!routino.point[marker].used)
+   {
+    routino.point[marker].used=true;
+    markerCentre(marker);
+    markerCoords(marker);
+   }
+
+ markerAddRemoveMap(marker,!routino.point[marker].active);
+
+ updateSearchButtons();
+}
+
+
+//
+// Show or hide a marker on the map.
+//
+
+function markerAddRemoveMap(marker,active)
+{
+ if(active)
+    markerAddMap(marker);
+ else
+    markerRemoveMap(marker);
+}
+
+
+//
+// Show a marker on the map.
+//
+
+function markerAddMap(marker)
+{
+ clearSearchResult(marker);
+
+ markers[marker].style.display = "";
+ routino.point[marker].active=true;
+ routino.point[marker].used=true;
+
+ updateIcon(marker);
+
+ markersmoved=true;
+
+ updateURLs();
+}
+
+
+//
+// Remove a marker from the map.
+//
+
+function markerRemoveMap(marker)
+{
+ clearSearchResult(marker);
+
+ markers[marker].style.display = "none";
+ routino.point[marker].active=false;
+
+ updateIcon(marker);
+
+ markersmoved=true;
+
+ updateURLs();
+}
+
+
+//
+// Display search string for the marker
+//
+
+function markerSearch(marker)   // called from router.html
+{
+ clearSearchResult(marker);
+
+ document.getElementById("coords" + marker).style.display="none";
+ document.getElementById("search" + marker).style.display="";
+}
+
+
+//
+// Display coordinates for the marker
+//
+
+function markerCoords(marker)   // called from router.html
+{
+ clearSearchResult(marker);
+
+ document.getElementById("search" + marker).style.display="none";
+ document.getElementById("coords" + marker).style.display="";
+}
+
+
+//
+// Centre the marker on the map
+//
+
+function markerCentre(marker)   // called from router.html
+{
+ if(!routino.point[marker].used)
+    return;
+
+ clearSearchResult(marker);
+
+ var lonlat=map.getCenter().clone();
+ lonlat.transform(epsg900913,epsg4326);
+
+ formSetCoords(marker,lonlat.lon,lonlat.lat);
+}
+
+
+//
+// Centre the map on the marker
+//
+
+function markerRecentre(marker) // called from router.html
+{
+ if(!routino.point[marker].used)
+    return;
+
+ clearSearchResult(marker);
+
+ var lon=routino.point[marker].lon;
+ var lat=routino.point[marker].lat;
+
+ var lonlat = new OpenLayers.LonLat(lon,lat);
+ lonlat.transform(epsg4326,epsg900913);
+
+ map.panTo(lonlat);
+}
+
+
+//
+// Clear the current marker.
+//
+
+function markerRemove(marker)   // called from router.html
+{
+ clearSearchResult(marker);
+
+ for(var m=marker;m<vismarkers;m++)
+    markerCopy(m,m+1);
+
+ markerRemoveForm(vismarkers--);
+
+ if(vismarkers==1)
+    markerAddAfter(1);
+
+ updateSearchButtons();
+}
+
+
+//
+// Add a marker before the current one.
+//
+
+function markerAddBefore(marker)
+{
+ if(vismarkers==mapprops.maxmarkers || marker==1)
+    return false;
+
+ clearSearchResult(marker);
+
+ markerAddForm(++vismarkers);
+
+ for(var m=vismarkers;m>marker;m--)
+    markerCopy(m,m-1);
+
+ markerClearForm(marker-1);
+}
+
+
+//
+// Add a marker after the current one.
+//
+
+function markerAddAfter(marker) // called from router.html
+{
+ if(vismarkers==mapprops.maxmarkers)
+    return false;
+
+ clearSearchResult(marker);
+
+ markerAddForm(++vismarkers);
+
+ for(var m=vismarkers;m>(marker+1);m--)
+    markerCopy(m,m-1);
+
+ markerClearForm(marker+1);
+}
+
+
+//
+// Set this marker as the home location.
+//
+
+function markerHome(marker)     // called from router.html
+{
+ if(!routino.point[marker].used)
+   {
+    markerMoveHome(marker);
+   }
+ else
+   {
+    clearSearchResult(marker);
+
+    markerSetClearHome(marker,!routino.point[marker].home);
+   }
+}
+
+
+//
+// Set this marker as the current location.
+//
+
+function markerLocate(marker)   // called from router.html
+{
+ clearSearchResult(marker);
+
+ if(navigator.geolocation)
+    navigator.geolocation.getCurrentPosition(
+                                             function(position) {
+                                              formSetCoords(marker,position.coords.longitude,position.coords.latitude);
+                                              markerAddMap(marker);
+                                             });
+}
+
+
+//
+// Update the search buttons enable/disable.
+//
+
+function updateSearchButtons()
+{
+ var markersactive=0;
+
+ for(var m=1;m<=vismarkers;m++)
+    if(routino.point[m].active)
+       markersactive++;
+
+ if(markersactive<2)
+   {
+    document.getElementById("shortest").disabled="disabled";
+    document.getElementById("quickest").disabled="disabled";
+   }
+ else
+   {
+    document.getElementById("shortest").disabled="";
+    document.getElementById("quickest").disabled="";
+   }
+}
+
+
+//
+// Update an icon to set colours and home or normal marker.
+//
+
+function updateIcon(marker)
+{
+ if(routino.point[marker].home)
+   {
+    if(routino.point[marker].active)
+       document.getElementById("icon" + marker).src="icons/marker-home-red.png";
+    else
+       document.getElementById("icon" + marker).src="icons/marker-home-grey.png";
+
+    markers[marker].style.externalGraphic="icons/marker-home-red.png";
+   }
+ else
+   {
+    if(routino.point[marker].active)
+       document.getElementById("icon" + marker).src="icons/marker-" + marker + "-red.png";
+    else
+       document.getElementById("icon" + marker).src="icons/marker-" + marker + "-grey.png";
+
+    markers[marker].style.externalGraphic="icons/marker-" + marker + "-red.png";
+   }
+
+ layerVectors.drawFeature(markers[marker]);
+}
+
+
+//
+// Move the marker to the home location
+//
+
+function markerMoveHome(marker)
+{
+ if(homelon===null || homelat===null)
+    return;
+
+ routino.point[marker].home=true;
+ routino.point[marker].used=true;
+
+ formSetCoords(marker,homelon,homelat);
+ markerAddMap(marker);
+}
+
+
+//
+// Set or clear the home marker icon
+//
+
+function markerSetClearHome(marker,home)
+{
+ var cookie;
+ var date = new Date();
+
+ if(home)
+   {
+    homelat=routino.point[marker].lat;
+    homelon=routino.point[marker].lon;
+
+    cookie="Routino-home=lon:" + homelon + ":lat:" + homelat;
+
+    date.setUTCFullYear(date.getUTCFullYear()+5);
+
+    routino.point[marker].home=true;
+   }
+ else
+   {
+    homelat=null;
+    homelon=null;
+
+    cookie="Routino-home=unset";
+
+    date.setUTCFullYear(date.getUTCFullYear()-1);
+
+    routino.point[marker].home=false;
+   }
+
+ document.cookie=cookie + ";expires=" + date.toGMTString();
+
+ updateIcon(marker);
+
+ for(var m=1;m<=mapprops.maxmarkers;m++)
+    markerCheckHome(m);
+}
+
+
+//
+// Check if a marker is the home marker
+//
+
+function markerCheckHome(marker)
+{
+ var home=routino.point[marker].home;
+
+ if(routino.point[marker].lon==homelon && routino.point[marker].lat==homelat)
+    routino.point[marker].home=true;
+ else
+    routino.point[marker].home=false;
+
+ if(home!=routino.point[marker].home)
+    updateIcon(marker);
+}
+
+
+//
+// Move this marker up.
+//
+
+function markerMoveUp(marker)   // called from router.html
+{
+ if(marker==1)
+   {
+    for(var m=1;m<vismarkers;m++)
+       markerSwap(m,m+1);
+   }
+ else
+    markerSwap(marker,marker-1);
+}
+
+
+//
+// Move this marker down.
+//
+
+function markerMoveDown(marker) // called from router.html
+{
+ if(marker==vismarkers)
+   {
+    for(var m=vismarkers;m>1;m--)
+       markerSwap(m,m-1);
+   }
+ else
+    markerSwap(marker,marker+1);
+}
+
+
+//
+// Copy a marker from one place to another.
+//
+
+function markerCopy(marker1,marker2)
+{
+ for(var element in routino.point[marker2])
+    routino.point[marker1][element]=routino.point[marker2][element];
+
+ document.getElementById("search" + marker1).style.display=document.getElementById("search" + marker2).style.display;
+
+ document.getElementById("coords" + marker1).style.display=document.getElementById("coords" + marker2).style.display;
+
+ document.forms["form"].elements["search" + marker1].value=document.forms["form"].elements["search" + marker2].value;
+
+ formSetCoords(marker1,routino.point[marker1].lon,routino.point[marker1].lat);
+
+ markerAddRemoveMap(marker1,routino.point[marker1].active);
+}
+
+
+//
+// Swap a pair of markers.
+//
+
+function markerSwap(marker1,marker2)
+{
+ for(var element in routino.point[marker2])
+   {
+    var temp=routino.point[marker1][element];
+    routino.point[marker1][element]=routino.point[marker2][element];
+    routino.point[marker2][element]=temp;
+   }
+
+ var search_display=document.getElementById("search" + marker1).style.display;
+ document.getElementById("search" + marker1).style.display=document.getElementById("search" + marker2).style.display;
+ document.getElementById("search" + marker2).style.display=search_display;
+
+ var coords_display=document.getElementById("coords" + marker1).style.display;
+ document.getElementById("coords" + marker1).style.display=document.getElementById("coords" + marker2).style.display;
+ document.getElementById("coords" + marker2).style.display=coords_display;
+
+ var search_value=document.forms["form"].elements["search" + marker1].value;
+ document.forms["form"].elements["search" + marker1].value=document.forms["form"].elements["search" + marker2].value;
+ document.forms["form"].elements["search" + marker2].value=search_value;
+
+ formSetCoords(marker1,routino.point[marker1].lon,routino.point[marker1].lat);
+ formSetCoords(marker2,routino.point[marker2].lon,routino.point[marker2].lat);
+
+ markerAddRemoveMap(marker1,routino.point[marker1].active);
+ markerAddRemoveMap(marker2,routino.point[marker2].active);
+}
+
+
+//
+// Reverse the markers.
+//
+
+function markersReverse()       // called from router.html
+{
+ for(var marker=1;marker<=vismarkers/2;marker++)
+    markerSwap(marker,vismarkers+1-marker);
+
+ markersmoved=true;
+
+ updateURLs();
+}
+
+
+//
+// Close the loop.
+//
+
+function markersLoop()          // called from router.html
+{
+ if(vismarkers==mapprops.maxmarkers)
+    return false;
+
+ if(routino.point[vismarkers].lon==routino.point[1].lon && routino.point[vismarkers].lat==routino.point[1].lat)
+   {
+    if(routino.point[vismarkers].active)
+       return false;
+    else
+      {
+       markerToggleMap(vismarkers);
+       return true;
+      }
+   }
+
+ if(routino.point[vismarkers].used)
+    markerAddForm(++vismarkers);
+
+ markerCopy(vismarkers,1);
+
+ markersmoved=true;
+
+ updateURLs();
+
+ updateSearchButtons();
+}
+
+
+//
+// Display the form for a marker
+//
+
+function markerAddForm(marker)
+{
+ document.getElementById("waypoint" + marker).style.display="";
+}
+
+
+//
+// Hide the form for a marker
+//
+
+function markerRemoveForm(marker)
+{
+ document.getElementById("waypoint" + marker).style.display="none";
+
+ markerClearForm(marker);
+}
+
+
+//
+// Clear the form for a marker
+//
+
+function markerClearForm(marker)
+{
+ markerRemoveMap(marker);
+ markerCoords(marker);
+
+ formSetCoords(marker,"","");
+ formSetSearch(marker,"");
+
+ updateIcon(marker);
+
+ routino.point[marker].used=false;
+ routino.point[marker].home=false;
+ routino.point[marker].active=false;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//////////////////////////// Route results handling ////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+var route_light_colours={shortest: "#60C060", quickest: "#6060C0"};
+var route_dark_colours ={shortest: "#408040", quickest: "#404080"};
+
+var highlights={shortest: null, quickest: null};
+var popups={shortest: null, quickest: null};
+var routepoints={shortest: {}, quickest: {}};
+var gpx_style={shortest: null, quickest: null};
+
+
+//
+// Highlight a specific item in the route
+//
+
+function highlight(type,line,action)
+{
+ if(action == "clear")
+   {
+    highlights[type].style.display = "none";
+
+    drawPopup(type,null);
+   }
+ else if(action == "zoom")
+   {
+    var lonlat = new OpenLayers.LonLat(routepoints[type][line].lon,routepoints[type][line].lat);
+    lonlat.transform(epsg4326,epsg900913);
+
+    map.moveTo(lonlat,map.numZoomLevels-2);
+   }
+ else
+   {
+    // Marker
+
+    var lonlat = new OpenLayers.LonLat(routepoints[type][line].lon,routepoints[type][line].lat);
+    lonlat.transform(epsg4326,epsg900913);
+
+    highlights[type].move(lonlat);
+
+    if(highlights[type].style.display == "none")
+       highlights[type].style.display = "";
+
+    // Popup
+
+    drawPopup(type,"<table>" + routepoints[type][line].html + "</table>");
+   }
+
+ layerVectors.drawFeature(highlights[type]);
+}
+
+
+//
+// Create a popup - independent of map because want it fixed on screen not fixed on map.
+//
+
+function createPopup(type)
+{
+ var popup=document.createElement("div");
+
+ popup.className = "popup";
+
+ popup.innerHTML = "<span></span>";
+
+ popup.style.display = "none";
+
+ popup.style.position = "fixed";
+ popup.style.top = "-4000px";
+ popup.style.left = "-4000px";
+ popup.style.zIndex = "100";
+
+ popup.style.padding = "5px";
+
+ popup.style.opacity=0.85;
+ popup.style.backgroundColor=route_light_colours[type];
+ popup.style.border="4px solid " + route_dark_colours[type];
+
+ document.body.appendChild(popup);
+
+ return(popup);
+}
+
+
+//
+// Draw a popup - independent of map because want it fixed on screen not fixed on map.
+//
+
+function drawPopup(type,html)
+{
+ var popup=popups[type];
+
+ if(html===null)
+   {
+    popup.style.display="none";
+    return;
+   }
+
+ if(popup.style.display=="none")
+   {
+    var map_div=document.getElementById("map");
+
+    popup.style.left  =map_div.offsetParent.offsetLeft+map_div.offsetLeft+60 + "px";
+    popup.style.top   =                                map_div.offsetTop +30 + "px";
+    popup.style.width =map_div.clientWidth-120 + "px";
+
+    popup.style.display="";
+   }
+
+ var close="<span style='float: right; cursor: pointer;' onclick='highlight(\""+type+"\",-1,\"clear\")'>X</span>";
+
+ popup.innerHTML=close+html;
+}
+
+
+//
+// Remove a GPX trace
+//
+
+function removeGPXTrace(type)
+{
+ map.removeLayer(layerGPX[type]);
+ layerGPX[type].destroy();
+ layerGPX[type]=null;
+
+ displayStatus(type,"no_info");
+
+ document.getElementById(type + "_links").style.display = "none";
+
+ document.getElementById(type + "_route").innerHTML = "";
+
+ hideshow_hide(type);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Server handling ////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+//
+// Define an AJAX request object
+//
+
+function ajaxGET(url,success,failure,state)
+{
+ var ajaxRequest=new XMLHttpRequest();
+
+ function ajaxGOT(options) {
+  if(this.readyState==4)
+     if(this.status==200)
+       { if(typeof(options.success)=="function") options.success(this,options.state); }
+     else
+       { if(typeof(options.failure)=="function") options.failure(this,options.state); }
+ }
+
+ ajaxRequest.onreadystatechange = function(){ ajaxGOT.call(ajaxRequest,{success: success, failure: failure, state: state}); };
+ ajaxRequest.open("GET", url, true);
+ ajaxRequest.send(null);
+}
+
+
+//
+// Display data statistics
+//
+
+function displayStatistics() // called from router.html
+{
+ // Use AJAX to get the statistics
+
+ ajaxGET("statistics.cgi", runStatisticsSuccess);
+}
+
+
+//
+// Success in running data statistics generation.
+//
+
+function runStatisticsSuccess(response)
+{
+ document.getElementById("statistics_data").innerHTML="<pre>" + response.responseText + "</pre>";
+ document.getElementById("statistics_link").style.display="none";
+}
+
+
+//
+// Submit form - perform the routing
+//
+
+function findRoute(type) // called from router.html
+{
+ tab_select("results");
+
+ hideshow_hide("help_options");
+ hideshow_hide("shortest");
+ hideshow_hide("quickest");
+
+ displayStatus("result","running");
+
+ var url="router.cgi" + "?" + buildURLArguments(true) + ";type=" + type;
+
+ // Destroy the existing layer(s)
+
+ highlight("shortest",-1,"clear");
+ highlight("quickest",-1,"clear");
+
+ if(markersmoved || paramschanged)
+   {
+    if(layerGPX.shortest!==null)
+       removeGPXTrace("shortest");
+    if(layerGPX.quickest!==null)
+       removeGPXTrace("quickest");
+    markersmoved=false;
+    paramschanged=false;
+   }
+ else if(layerGPX[type]!==null)
+    removeGPXTrace(type);
+
+ // Use AJAX to run the router
+
+ routing_type=type;
+
+ ajaxGET(url, runRouterSuccess, runRouterFailure);
+}
+
+
+//
+// Success in running router.
+//
+
+function runRouterSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var uuid=lines[0];
+ var success=lines[1];
+
+ var link;
+
+ // Update the status message
+
+ if(success=="ERROR")
+   {
+    displayStatus("result","error");
+    hideshow_show("help_route");
+
+    link=document.getElementById("router_log_error");
+    link.href="results.cgi?uuid=" + uuid + ";type=router;format=log";
+
+    return;
+   }
+ else
+   {
+    displayStatus("result","complete");
+    hideshow_hide("help_route");
+
+    link=document.getElementById("router_log_complete");
+    link.href="results.cgi?uuid=" + uuid + ";type=router;format=log";
+   }
+
+ // Update the routing result message
+
+ link=document.getElementById(routing_type + "_html");
+ link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=html";
+
+ link=document.getElementById(routing_type + "_gpx_track");
+ link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-track";
+
+ link=document.getElementById(routing_type + "_gpx_route");
+ link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-route";
+
+ link=document.getElementById(routing_type + "_text_all");
+ link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=text-all";
+
+ link=document.getElementById(routing_type + "_text");
+ link.href="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=text";
+
+ document.getElementById(routing_type + "_links").style.display = "";
+
+ // Add a GPX layer
+
+ var url="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=gpx-track";
+
+ layerGPX[routing_type] = new OpenLayers.Layer.Vector("GPX (" + routing_type + ")",
+                                                      {
+                                                       displayInLayerSwitcher: false,
+                                                       protocol:   new OpenLayers.Protocol.HTTP({url: url, format: new OpenLayers.Format.GPX()}),
+                                                       strategies: [new OpenLayers.Strategy.Fixed()],
+                                                       style:      gpx_style[routing_type],
+                                                       projection: map.displayProjection
+                                                      });
+
+ map.addLayer(layerGPX[routing_type]);
+
+ hideshow_show(routing_type);
+
+ displayResult(routing_type,uuid);
+}
+
+
+//
+// Failure in running router.
+//
+
+function runRouterFailure(response)
+{
+ displayStatus("result","failed");
+}
+
+
+//
+// Display the status
+//
+
+function displayStatus(type,subtype,content)
+{
+ var child=document.getElementById(type + "_status").firstChild;
+
+ do
+   {
+    if(child.id !== undefined)
+       child.style.display="none";
+
+    child=child.nextSibling;
+   }
+ while(child !== null);
+
+ var chosen_status=document.getElementById(type + "_status_" + subtype);
+
+ chosen_status.style.display="";
+
+ if(content !== undefined)
+    chosen_status.innerHTML=content;
+}
+
+
+//
+// Display the route
+//
+
+function displayResult(type,uuid)
+{
+ routing_type = type;
+
+ // Add the route
+
+ var url="results.cgi?uuid=" + uuid + ";type=" + routing_type + ";format=html";
+
+ // Use AJAX to get the route
+
+ ajaxGET(url, getRouteSuccess, getRouteFailure);
+}
+
+
+//
+// Success in getting route.
+//
+
+function getRouteSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ routepoints[routing_type]=[];
+
+ var points=routepoints[routing_type];
+
+ var table=0;
+ var point=0;
+ var total_table,total_word;
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var thisline=lines[line];
+
+    if(table===0)
+      {
+       if(thisline.match("<table>"))
+          table=1;
+       else
+          continue;
+      }
+
+    if(thisline.match("</table>"))
+       break;
+
+    if(thisline.match("<tr class='([a-z])'>"))
+      {
+       var rowtype=RegExp.$1;
+
+       if(rowtype=="c")
+         {
+          thisline.match("<td class='r'> *([-0-9.]+) *([-0-9.]+)");
+          points[point]={lat: Number(RegExp.$1), lon: Number(RegExp.$2), html: "", highway: "", distance: "", total: ""};
+
+          point++;
+         }
+       else if(rowtype=="n")
+         {
+          points[point-1].html += thisline;
+         }
+       else if(rowtype=="s")
+         {
+          thisline.match("<span class='h'>([^<]+)</span>");
+          points[point-1].highway = RegExp.$1;
+
+          thisline.match("<span class='d'>([^<]+)</span>");
+          points[point-1].distance = RegExp.$1;
+
+          thisline.match("(<span class='j'>[^<]+</span>)");
+          points[point-1].total = RegExp.$1;
+
+          thisline.match("^(.*).<span class='j'>");
+
+          points[point-1].html += RegExp.$1;
+         }
+       else if(rowtype=="t")
+         {
+          points[point-1].html += thisline;
+
+          thisline.match("^(.*<td class='r'>)");
+          total_table = RegExp.$1;
+
+          thisline.match("<td class='l'>([^<]+)<");
+          total_word = RegExp.$1;
+
+          thisline.match("<span class='j'>([^<]+)</span>");
+          points[point-1].total = RegExp.$1;
+         }
+      }
+   }
+
+ displayStatus(routing_type,"info",points[point-1].total.bold());
+
+ var result="<table onmouseout='highlight(\"" + routing_type + "\",-1,\"clear\")'>";
+
+ for(var p=0;p<point-1;p++)
+   {
+    points[p].html += total_table + points[p].total;
+
+    result=result + "<tr onmouseover='highlight(\"" + routing_type + "\"," + p + ",\"show\")'>" +
+                    "<td onclick='highlight(\"" + routing_type + "\"," + p + ",\"zoom\")'" +
+                    " class='distance' title='" + points[p].distance + "'>#" + (p+1) +
+                    "<td class='highway'>" + points[p].highway;
+   }
+
+ result=result + "<tr onmouseover='highlight(\"" + routing_type + "\"," + p + ",\"show\")'>" +
+                 "<td onclick='highlight(\"" + routing_type + "\"," + p + ",\"zoom\")'" +
+                 " class='distance'>#" + (p+1) +
+                 "<td class='highway'>" + total_word + " " + points[p].total;
+
+ result=result + "</table>";
+
+ document.getElementById(routing_type + "_route").innerHTML=result;
+}
+
+
+//
+// Failure in getting route.
+//
+
+function getRouteFailure(response)
+{
+ document.getElementById(routing_type + "_route").innerHTML = "";
+}
+
+
+//
+// Perform a search
+//
+
+function DoSearch(marker)
+{
+ // Use AJAX to get the search result
+
+ var search=routino.point[marker].search;
+
+ var mapbounds=map.getExtent().clone();
+ mapbounds.transform(epsg900913,epsg4326);
+
+ var url="search.cgi";
+
+ url=url + "?marker=" + marker;
+ url=url + ";lonmin=" + format5f(mapbounds.left);
+ url=url + ";latmin=" + format5f(mapbounds.bottom);
+ url=url + ";lonmax=" + format5f(mapbounds.right);
+ url=url + ";latmax=" + format5f(mapbounds.top);
+ url=url + ";search=" + encodeURIComponent(search);
+
+ ajaxGET(url,runSearchSuccess);
+}
+
+
+var searchresults=[];
+
+//
+// Success in running search.
+//
+
+function runSearchSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var marker=lines[0];
+ var cpuinfo=lines[1];  // not used
+ var message=lines[2];
+
+ if(message !== "")
+   {
+    alert(message);
+    return;
+   }
+
+ searchresults[marker]=[];
+
+ for(var line=3;line<lines.length;line++)
+   {
+    var thisline=lines[line];
+
+    if(thisline==="")
+       break;
+
+    thisline.match("([-.0-9]+) ([-.0-9]+) (.*)");
+
+    searchresults[marker][searchresults[marker].length]={lat: Number(RegExp.$1), lon: Number(RegExp.$2), name: RegExp.$3};
+   }
+
+ if(searchresults[marker].length==1)
+   {
+    formSetSearch(marker,searchresults[marker][0].name);
+    formSetCoords(marker,searchresults[marker][0].lon,searchresults[marker][0].lat);
+    markerAddMap(marker);
+   }
+ else
+   {
+    var results=document.getElementById("searchresults" + marker);
+
+    var innerHTML="<td colspan=\"3\">";
+
+    for(var n=0;n<searchresults[marker].length;n++)
+      {
+       if(n>0)
+          innerHTML+="<br>";
+
+       innerHTML+="<a href=\"#\" onclick=\"choseSearchResult(" + marker + "," + n + ")\">" +
+                  searchresults[marker][n].name +
+                  "</a>";
+      }
+
+    results.innerHTML=innerHTML;
+
+    results.style.display="";
+   }
+}
+
+
+//
+// Display search results.
+//
+
+function choseSearchResult(marker,n)
+{
+ if(n>=0)
+   {
+    formSetSearch(marker,searchresults[marker][n].name);
+    formSetCoords(marker,searchresults[marker][n].lon,searchresults[marker][n].lat);
+    markerAddMap(marker);
+   }
+}
+
+
+//
+// Clear search results.
+//
+
+function clearSearchResult(marker)
+{
+ document.getElementById("searchresults" + marker).style.display="none";
+}
diff --git a/3rdparty/Routino/web/www/routino/router.pl b/3rdparty/Routino/web/www/routino/router.pl
new file mode 100644
index 0000000..b2d39ba
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/router.pl
@@ -0,0 +1,211 @@
+#
+# Routino generic router Perl script
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+
+# Use the directory paths script
+require "paths.pl";
+
+# Load the profiles variables
+require "profiles.pl";
+
+# Use the perl Time::HiRes module
+use Time::HiRes qw(gettimeofday tv_interval);
+
+my $t0 = [gettimeofday];
+
+
+#
+# Fill in the default parameters using the ones above (don't use executable compiled in defaults)
+#
+
+sub FillInDefaults
+  {
+   my(%params)=@_;
+
+   $params{transport}=$main::routino->{transport} if(!defined $params{transport});
+
+   my $transport=$params{transport};
+
+   foreach my $highway (keys %{$main::routino->{highways}})
+     {
+      my $key="highway-$highway";
+      my $value=$main::routino->{profile_highway}->{$highway}->{$transport};
+      $params{$key}=$value if(!defined $params{$key});
+
+      $key="speed-$highway";
+      $value=$main::routino->{profile_speed}->{$highway}->{$transport};
+      $params{$key}=$value if(!defined $params{$key});
+     }
+
+   foreach my $property (keys %{$main::routino->{properties}})
+     {
+      my $key="property-$property";
+      my $value=$main::routino->{profile_property}->{$property}->{$transport};
+      $params{$key}=$value if(!defined $params{$key});
+     }
+
+   $params{oneway} =~ s/(true|on)/1/;
+   $params{oneway} =~ s/(false|off)/0/;
+
+   $params{turns} =~ s/(true|on)/1/;
+   $params{turns} =~ s/(false|off)/0/;
+
+   foreach my $restriction (keys %{$main::routino->{restrictions}})
+     {
+      my $key="$restriction";
+      my $value=$main::routino->{profile_restrictions}->{$restriction}->{$transport};
+      $params{$key}=$value if(!defined $params{$key});
+     }
+
+   return %params;
+  }
+
+
+#
+# Run the router
+#
+
+sub RunRouter
+  {
+   my($optimise,%params)=@_;
+
+   # Combine all of the parameters together
+
+   my $params="--$optimise";
+
+   foreach my $key (keys %params)
+     {
+      $params.=" --$key=$params{$key}";
+     }
+
+   # Change directory
+
+   mkdir $main::results_dir,0755 if(! -d $main::results_dir);
+   chdir $main::results_dir;
+
+   # Create a unique output directory
+
+   my $uuid;
+
+   if($^O eq "darwin")
+     {
+      chomp($uuid=`echo '$params' $$ | md5    | cut -f1 '-d '`);
+     }
+   else
+     {
+      chomp($uuid=`echo '$params' $$ | md5sum | cut -f1 '-d '`);
+     }
+
+   mkdir $uuid;
+   chmod 0775, $uuid;
+   chdir $uuid;
+
+   # Run the router
+
+   my $safe_params ="";
+   if($main::data_dir)
+     {
+      my @pathparts=split('/',$main::data_dir);
+      $safe_params.=" --dir=".pop(@pathparts);
+     }
+   # This works in newer Perl versions, but not older ones.
+   #$safe_params.=" --dir=".pop([split('/',$main::data_dir)]) if($main::data_dir);
+   $safe_params.=" --prefix=$main::data_prefix" if($main::data_prefix);
+
+   open(LOG,">router.log");
+   print LOG "$main::router_exe $params$safe_params\n\n"; # Don't put the full pathnames in the logfile.
+   close(LOG);
+
+   $params.=" --dir=$main::data_dir" if($main::data_dir);
+   $params.=" --prefix=$main::data_prefix" if($main::data_prefix);
+   $params.=" --loggable";
+
+   system "$main::bin_dir/$main::router_exe $params >> router.log 2>&1";
+
+   my $status="OK";
+   $status="ERROR" if($? != 0);
+
+   my(undef,undef,$cuser,$csystem) = times;
+
+   open(LOG,">>router.log");
+   printf LOG "\nTime: %.3f CPU / %.3f elapsed\n",$cuser+$csystem,tv_interval($t0);
+   close(LOG);
+
+   # Return the results
+
+   return($uuid,$status);
+  }
+
+
+#
+# Return the output file
+#
+
+# Possible file formats
+
+my %suffixes=(
+           "html"      => ".html",
+           "gpx-route" => "-route.gpx",
+           "gpx-track" => "-track.gpx",
+           "text"      => ".txt",
+           "text-all"  => "-all.txt",
+           "log"       => ".log"
+          );
+
+# Possible MIME types
+
+my %mimetypes=(
+            "html"      => "text/html",
+            "gpx-route" => "text/xml",
+            "gpx-track" => "text/xml",
+            "text"      => "text/plain",
+            "text-all"  => "text/plain",
+            "log"       => "text/plain"
+           );
+
+sub ReturnOutput
+  {
+   my($uuid,$type,$format)=@_;
+
+   if($type eq "router") { $format="log" }
+
+   my $suffix=$suffixes{$format};
+   my $mime  =$mimetypes{$format};
+
+   my $file="$main::results_dir/$uuid/$type$suffix";
+
+   # Return the output
+
+   if(!$type || !$uuid || !$format || ! -f $file)
+     {
+      print header('text/plain','404 Not found');
+      print "Not Found!\n";
+     }
+   else
+     {
+      print header($mime);
+
+      system "cat $file";
+     }
+  }
+
+1;
diff --git a/3rdparty/Routino/web/www/routino/search.cgi b/3rdparty/Routino/web/www/routino/search.cgi
new file mode 100755
index 0000000..95b40c1
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/search.cgi
@@ -0,0 +1,96 @@
+#!/usr/bin/perl
+#
+# Routino search results retrieval CGI
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2012-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+
+# Use the generic search script
+require "search.pl";
+
+# Use the perl CGI module
+use CGI ':cgi';
+
+
+# Create the query and get the parameters
+
+my $query=new CGI;
+
+my @rawparams=$query->param;
+
+# Legal CGI parameters with regexp validity check
+
+my %legalparams=(
+              "marker"  => "[0-9]+",
+
+              "lonmin"  => "[-0-9.]+",
+              "lonmax"  => "[-0-9.]+",
+              "latmax"  => "[-0-9.]+",
+              "latmin"  => "[-0-9.]+",
+
+              "search"  => ".+"
+             );
+
+# Validate the CGI parameters, ignore invalid ones
+
+my %cgiparams=();
+
+foreach my $key (@rawparams)
+  {
+   foreach my $test (keys (%legalparams))
+     {
+      if($key =~ m%^$test$%)
+        {
+         my $value=$query->param($key);
+
+         if($value =~ m%^$legalparams{$test}$%)
+           {
+            $cgiparams{$key}=$value;
+            last;
+           }
+        }
+     }
+  }
+
+# Parse the parameters
+
+my $marker=$cgiparams{marker};
+my $search=$cgiparams{search};
+
+my $lonmin=$cgiparams{lonmin};
+my $lonmax=$cgiparams{lonmax};
+my $latmax=$cgiparams{latmax};
+my $latmin=$cgiparams{latmin};
+
+# Run the search
+
+my($search_time,$search_message, at places)=RunSearch($search,$lonmin,$lonmax,$latmax,$latmin);
+
+# Return the output
+
+print header(-type=>'text/plain',-charset=>'utf-8');
+
+print "$marker\n";
+print "$search_time\n";
+print "$search_message\n";
+foreach my $place (@places)
+  {
+   print "$place\n";
+  }
diff --git a/3rdparty/Routino/web/www/routino/search.pl b/3rdparty/Routino/web/www/routino/search.pl
new file mode 100644
index 0000000..1f4dbb4
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/search.pl
@@ -0,0 +1,123 @@
+#
+# Routino generic Search Perl script
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2012-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+
+# Use the directory paths script
+require "paths.pl";
+
+# Use the perl encoding/decoding functions
+use Encode qw(decode encode);
+
+# Use the perl URI module
+use URI::Escape;
+
+# Use the perl LWP module
+use LWP::UserAgent;
+
+# Use the perl JSON module
+use JSON::PP;
+
+# Use the perl Time::HiRes module
+use Time::HiRes qw(gettimeofday tv_interval);
+
+my $t0 = [gettimeofday];
+
+
+#
+# Run the search
+#
+
+sub RunSearch
+  {
+   my($search,$lonmin,$lonmax,$latmax,$latmin)=@_;
+
+   # Perform the search based on the type
+
+   my $message="";
+   my @places=[];
+
+   if($main::search_type eq "nominatim")
+     {
+      ($message, at places)=DoNominatimSearch($search,$lonmin,$lonmax,$latmax,$latmin);
+     }
+   else
+     {
+      $message="Unknown search type '$main::search_type'";
+     }
+
+   my(undef,undef,$cuser,$csystem) = times;
+   my $time=sprintf "time: %.3f CPU / %.3f elapsed",$cuser+$csystem,tv_interval($t0);
+
+   # Return the results
+
+   return($time,$message, at places);
+  }
+
+
+#
+# Fetch the search URL from Nominatim
+#
+
+sub DoNominatimSearch
+  {
+   my($search,$lonmin,$lonmax,$latmax,$latmin)=@_;
+
+   $search = uri_escape($search);
+
+   my $url;
+
+   if($lonmin && $lonmax && $latmax && $latmin)
+     {
+      $url="$main::search_baseurl?format=json&viewbox=$lonmin,$latmax,$lonmax,$latmin&q=$search";
+     }
+   else
+     {
+      $url="$main::search_baseurl?format=json&q=$search";
+     }
+
+   my $ua=LWP::UserAgent->new;
+
+   my $res=$ua->get($url);
+
+   if(!$res->is_success)
+     {
+      return($res->status_line);
+     }
+
+   my $result=decode_json($res->content);
+
+   my @places=();
+
+   foreach my $place (@$result)
+     {
+      my $lat=$place->{"lat"};
+      my $lon=$place->{"lon"};
+      my $name=encode('utf8',$place->{"display_name"});
+
+      push(@places,"$lat $lon $name");
+     }
+
+   return("", at places);
+  }
+
+
+1;
diff --git a/3rdparty/Routino/web/www/routino/statistics.cgi b/3rdparty/Routino/web/www/routino/statistics.cgi
new file mode 100755
index 0000000..991adee
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/statistics.cgi
@@ -0,0 +1,44 @@
+#!/usr/bin/perl
+#
+# Routino data statistics
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+
+# Use the directory paths script
+require "paths.pl";
+
+# Use the perl CGI module
+use CGI ':cgi';
+
+
+# Print the output
+
+print header('text/plain');
+
+# Run the filedumper
+
+my $params="";
+
+$params.=" --dir=$main::data_dir" if($main::data_dir);
+$params.=" --prefix=$main::data_prefix" if($main::data_prefix);
+$params.=" --statistics";
+
+system "$main::bin_dir/$main::filedumper_exe $params 2>&1";
diff --git a/3rdparty/Routino/web/www/routino/update-profiles.pl b/3rdparty/Routino/web/www/routino/update-profiles.pl
new file mode 100755
index 0000000..48e06d3
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/update-profiles.pl
@@ -0,0 +1,79 @@
+#!/usr/bin/perl
+#
+# Update the Routino profile files
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2011-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+
+# Use the directory paths script
+require "paths.pl";
+
+
+# The parameters for the execution
+
+my $params="";
+
+$params.=" --dir=$main::data_dir" if($main::data_dir);
+$params.=" --prefix=$main::data_prefix" if($main::data_prefix);
+
+
+# Generate the Perl profiles.
+
+open(PROFILE,">profiles.pl") || die "Cannot open 'profiles.pl' to write.\n";
+
+print PROFILE "################################################################################\n";
+print PROFILE "########################### Routino default profile ############################\n";
+print PROFILE "################################################################################\n";
+print PROFILE "\n";
+
+open(EXECUTE,"$main::bin_dir/$main::router_exe $params --help-profile-perl |") || die "Failed to execute router to generate profiles.\n";
+
+while(<EXECUTE>)
+  {
+   print PROFILE;
+  }
+
+close(EXECUTE);
+
+print PROFILE "\n";
+print PROFILE "1;\n";
+
+close(PROFILE);
+
+
+# Generate the Javascript profiles.
+
+open(PROFILE,">profiles.js") || die "Cannot open 'profiles.js' to write.\n";
+
+print PROFILE "////////////////////////////////////////////////////////////////////////////////\n";
+print PROFILE "/////////////////////////// Routino default profile ////////////////////////////\n";
+print PROFILE "////////////////////////////////////////////////////////////////////////////////\n";
+print PROFILE "\n";
+
+open(EXECUTE,"$main::bin_dir/$main::router_exe $params --help-profile-json |") || die "Failed to execute router to generate profiles.\n";
+
+while(<EXECUTE>)
+  {
+   print PROFILE;
+  }
+
+close(EXECUTE);
+
+close(PROFILE);
diff --git a/3rdparty/Routino/web/www/routino/visualiser.cgi b/3rdparty/Routino/web/www/routino/visualiser.cgi
new file mode 100755
index 0000000..d287947
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/visualiser.cgi
@@ -0,0 +1,157 @@
+#!/usr/bin/perl
+#
+# Routino data visualiser CGI
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2008-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+
+# Use the directory paths script
+require "paths.pl";
+
+# Use the perl CGI module
+use CGI ':cgi';
+
+
+# Create the query and get the parameters
+
+my $query=new CGI;
+
+my @rawparams=$query->param;
+
+# Legal CGI parameters with regexp validity check
+
+my %legalparams=(
+                 "latmin" => "[-0-9.]+",
+                 "latmax" => "[-0-9.]+",
+                 "lonmin" => "[-0-9.]+",
+                 "lonmax" => "[-0-9.]+",
+                 "data"   => "(junctions|super|waytype-.*|highway-.*|transport-.*|barrier-.*|turns|speed|weight|height|width|length|property-.*|errorlogs)",
+                 "dump"   => "(node|segment|turn-relation|errorlog)[0-9]+"
+                );
+
+# Validate the CGI parameters, ignore invalid ones
+
+my %cgiparams=();
+
+foreach my $key (@rawparams)
+  {
+   foreach my $test (keys (%legalparams))
+     {
+      if($key =~ m%^$test$%)
+        {
+         my $value=$query->param($key);
+
+         if($value =~ m%^$legalparams{$test}$%)
+           {
+            $cgiparams{$key}=$value;
+            last;
+           }
+        }
+     }
+  }
+
+# Data or dump?
+
+my $params="";
+
+my $data=$cgiparams{"data"};
+my $dump=$cgiparams{"dump"};
+
+if(!defined $data && !defined $dump)
+  {
+   print header(-status => '500 Invalid CGI parameters');
+   exit;
+  }
+
+if(defined $data)
+  {
+   # Parameters to limit range selected
+
+   my %limits=(
+               "junctions" => 0.2,
+               "super"     => 0.2,
+               "waytype"   => 0.2,
+               "highway"   => 0.2,
+               "transport" => 0.2,
+               "barrier"   => 0.3,
+               "turns"     => 0.3,
+               "speed"     => 0.3,
+               "weight"    => 0.3,
+               "height"    => 0.3,
+               "width"     => 0.3,
+               "length"    => 0.3,
+               "property"  => 0.3,
+               "errorlogs" => 0.5
+              );
+
+   # Check the parameters
+
+   my $latmin=$cgiparams{"latmin"};
+   my $latmax=$cgiparams{"latmax"};
+   my $lonmin=$cgiparams{"lonmin"};
+   my $lonmax=$cgiparams{"lonmax"};
+
+   if($latmin eq "" || $latmax eq "" || $lonmin eq "" || $lonmax eq "" || $data eq "")
+     {
+      print header(-status => '500 Invalid CGI parameters');
+      exit;
+     }
+
+   my $subdata=$data;
+   $subdata="waytype"   if($data =~ m%waytype-%);
+   $subdata="highway"   if($data =~ m%highway-%);
+   $subdata="transport" if($data =~ m%transport-%);
+   $subdata="barrier"   if($data =~ m%barrier-%);
+   $subdata="property"  if($data =~ m%property-%);
+
+   if(($latmax-$latmin)>$limits{$subdata} || ($lonmax-$lonmin)>$limits{$subdata})
+     {
+      print header(-status => '500 Selected area too large');
+      exit;
+     }
+
+   # Print the output
+
+   print header('text/plain');
+
+   print "$latmin $lonmin $latmax $lonmax\n";
+
+   # Set the parameters
+
+   $params.=" --visualiser --data=$data";
+   $params.=" --latmin=$latmin --latmax=$latmax --lonmin=$lonmin --lonmax=$lonmax";
+  }
+else
+  {
+   # Print the output
+
+   print header('text/plain');
+
+   # Set the parameters
+
+   $params.=" --dump-visualiser --data=$dump";
+  }
+
+# Run the filedumper
+
+$params.=" --dir=$main::data_dir" if($main::data_dir);
+$params.=" --prefix=$main::data_prefix" if($main::data_prefix);
+
+system "$main::bin_dir/$main::filedumper_exe $params 2>&1";
diff --git a/3rdparty/Routino/web/www/routino/visualiser.css b/3rdparty/Routino/web/www/routino/visualiser.css
new file mode 100644
index 0000000..aca80c3
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/visualiser.css
@@ -0,0 +1,86 @@
+/*
+// Routino visualiser web page style sheet.
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2013 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*--------------------------------*/
+/* Left panel - override defaults */
+/*--------------------------------*/
+
+DIV.hideshow_box
+{
+ overflow-x: auto;
+}
+
+
+/*-----------------------------------*/
+/* Left panel - specific tab options */
+/*-----------------------------------*/
+
+DIV#tab_visualiser_div INPUT
+{
+ padding: 0;
+ border:  1px solid;
+ margin:  0;
+
+ text-align: center;
+}
+
+DIV#tab_visualiser_div INPUT:hover
+{
+ background: #F0F0C0;
+}
+
+DIV#tab_visualiser_div TABLE
+{
+ padding: 0;
+ border:  0 hidden;
+ margin:  0;
+}
+
+DIV#tab_visualiser_div DIV.center
+{
+ text-align: center;
+}
+
+DIV#tab_visualiser_div TABLE TD
+{
+ padding: 0;
+ border:  0;
+ margin:  0;
+}
+
+DIV#tab_visualiser_div INPUT
+{
+ padding: 0;
+ border:  1px solid;
+ margin:  0;
+}
+
+
+/*-------*/
+/* Popup */
+/*-------*/
+
+DIV.popup
+{
+ font-family: monospace;
+ font-size:   10px;
+}
diff --git a/3rdparty/Routino/web/www/routino/visualiser.leaflet.js b/3rdparty/Routino/web/www/routino/visualiser.leaflet.js
new file mode 100644
index 0000000..d6d2ed6
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/visualiser.leaflet.js
@@ -0,0 +1,1232 @@
+//
+// Routino data visualiser web page Javascript
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2014 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+//
+// Data types
+//
+
+var data_types=[
+                "junctions",
+                "super",
+                "waytype",
+                "highway",
+                "transport",
+                "barrier",
+                "turns",
+                "speed",
+                "weight",
+                "height",
+                "width",
+                "length",
+                "property",
+                "errorlogs"
+               ];
+
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Initialisation /////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+// Process the URL query string and extract the arguments
+
+var legal={"^lon"  : "^[-0-9.]+$",
+           "^lat"  : "^[-0-9.]+$",
+           "^zoom" : "^[0-9]+$"};
+
+var args={};
+
+if(location.search.length>1)
+  {
+   var query,queries;
+
+   query=location.search.replace(/^\?/,"");
+   query=query.replace(/;/g,"&");
+   queries=query.split("&");
+
+   for(var i=0;i<queries.length;i++)
+     {
+      queries[i].match(/^([^=]+)(=(.*))?$/);
+
+      var k=RegExp.$1;
+      var v=decodeURIComponent(RegExp.$3);
+
+      for(var l in legal)
+        {
+         if(k.match(RegExp(l)) && v.match(RegExp(legal[l])))
+            args[k]=v;
+        }
+     }
+  }
+
+
+////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////// Map handling /////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+var map;
+var layerMap=[], layerHighlights, layerVectors, layerBoxes;
+var box;
+
+//
+// Initialise the 'map' object
+//
+
+function map_init()             // called from visualiser.html
+{
+ // Create the map (Map URLs and limits are in mapprops.js)
+
+ map = L.map("map",
+             {
+              attributionControl: false,
+              zoomControl: false,
+
+              minZoom: mapprops.zoomout,
+              maxZoom: mapprops.zoomin,
+
+              maxBounds: L.latLngBounds(L.latLng(mapprops.southedge,mapprops.westedge),L.latLng(mapprops.northedge,mapprops.eastedge))
+              });
+
+ // Add map tile layers
+
+ var baselayers={};
+
+ for(var l=0; l<mapprops.mapdata.length; l++)
+   {
+    var urls=mapprops.mapdata[l].tiles.url.replace(/\${/g,"{");
+
+    if(mapprops.mapdata[l].tiles.subdomains===undefined)
+       layerMap[l] = L.tileLayer(urls);
+    else
+       layerMap[l] = L.tileLayer(urls, {subdomains: mapprops.mapdata[l].tiles.subdomains});
+
+    baselayers[mapprops.mapdata[l].label]=layerMap[l];
+
+    if(l===0)
+       map.addLayer(layerMap[l]);
+   }
+
+ // Add the controls
+
+ map.addControl(L.control.zoom());
+ map.addControl(L.control.scale());
+ map.addControl(L.control.layers(baselayers));
+
+ // Update the attribution if the layer changes
+
+ function change_attribution_event(event)
+ {
+  for(var l=0; l<mapprops.mapdata.length; l++)
+     if(layerMap[l] == event.layer)
+        change_attribution(l);
+ }
+
+ map.on("baselayerchange",change_attribution_event);
+
+ function change_attribution(l)
+ {
+  var data_url =mapprops.mapdata[l].attribution.data_url;
+  var data_text=mapprops.mapdata[l].attribution.data_text;
+  var tile_url =mapprops.mapdata[l].attribution.tile_url;
+  var tile_text=mapprops.mapdata[l].attribution.tile_text;
+
+  document.getElementById("attribution_data").innerHTML="<a href=\"" + data_url + "\" target=\"data_attribution\">" + data_text + "</a>";
+  document.getElementById("attribution_tile").innerHTML="<a href=\"" + tile_url + "\" target=\"tile_attribution\">" + tile_text + "</a>";
+ }
+
+ change_attribution(0);
+
+ // Add two vectors layers (one for highlights that display behind the vectors)
+
+ layerVectors = L.layerGroup();
+ map.addLayer(layerVectors);
+
+ layerHighlights = L.layerGroup();
+ map.addLayer(layerHighlights);
+
+ // Handle popup
+
+ createPopup();
+
+ // Add a boxes layer
+
+ layerBoxes = L.rectangle(map.options.maxBounds,{stroke: false, color: "#f00", weight: 1, opacity: 1.0,
+                                                 fill: false});
+
+ map.addLayer(layerBoxes);
+
+ box=false;
+
+ // Move the map
+
+ map.on("moveend", updateURLs);
+
+ var lon =args["lon"];
+ var lat =args["lat"];
+ var zoom=args["zoom"];
+
+ if(lon !== undefined && lat !== undefined && zoom !== undefined)
+   {
+    if(lon<mapprops.westedge) lon=mapprops.westedge;
+    if(lon>mapprops.eastedge) lon=mapprops.eastedge;
+
+    if(lat<mapprops.southedge) lat=mapprops.southedge;
+    if(lat>mapprops.northedge) lat=mapprops.northedge;
+
+    if(zoom<mapprops.zoomout) zoom=mapprops.zoomout;
+    if(zoom>mapprops.zoomin)  zoom=mapprops.zoomin;
+
+    map.setView(L.latLng(lat,lon),zoom);
+   }
+ else
+    map.fitBounds(map.options.maxBounds);
+
+ // Unhide editing URL if variable set
+
+ if(mapprops.editurl !== undefined && mapprops.editurl !== "")
+   {
+    var edit_url=document.getElementById("edit_url");
+
+    edit_url.style.display="";
+    edit_url.href=mapprops.editurl;
+   }
+
+ updateURLs();
+}
+
+
+//
+// Format a number in printf("%.5f") format.
+//
+
+function format5f(number)
+{
+ var newnumber=Math.floor(number*100000+0.5);
+ var delta=0;
+
+ if(newnumber>=0 && newnumber<100000) delta= 100000;
+ if(newnumber<0 && newnumber>-100000) delta=-100000;
+
+ var string=String(newnumber+delta);
+
+ var intpart =string.substring(0,string.length-5);
+ var fracpart=string.substring(string.length-5,string.length);
+
+ if(delta>0) intpart="0";
+ if(delta<0) intpart="-0";
+
+ return(intpart + "." + fracpart);
+}
+
+
+//
+// Build a set of URL arguments for the map location
+//
+
+function buildMapArguments()
+{
+ var lonlat = map.getCenter();
+
+ var zoom = map.getZoom();
+
+ return "lat=" + format5f(lonlat.lat) + ";lon=" + format5f(lonlat.lng) + ";zoom=" + zoom;
+}
+
+
+//
+// Update the URLs
+//
+
+function updateURLs()
+{
+ var mapargs=buildMapArguments();
+
+ var links=document.getElementsByTagName("a");
+
+ for(var i=0; i<links.length; i++)
+   {
+    var element=links[i];
+
+    if(element.id == "permalink_url")
+       element.href=location.pathname + "?" + mapargs;
+
+    if(element.id == "router_url")
+       element.href="router.html" + "?" + mapargs;
+
+    if(element.id == "edit_url")
+       element.href=mapprops.editurl + "?" + mapargs;
+
+    if(element.id.match(/^lang_([a-zA-Z-]+)_url$/))
+       element.href="visualiser.html" + "." + RegExp.$1 + "?" + mapargs;
+   }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+///////////////////////// Popup and selection handling /////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+var popup=null;
+
+//
+// Create a popup - independent of map because want it fixed on screen not fixed on map.
+//
+
+function createPopup()
+{
+ popup=document.createElement("div");
+
+ popup.className = "popup";
+
+ popup.innerHTML = "<span></span>";
+
+ popup.style.display = "none";
+
+ popup.style.position = "fixed";
+ popup.style.top = "-4000px";
+ popup.style.left = "-4000px";
+ popup.style.zIndex = "100";
+
+ popup.style.padding = "5px";
+
+ popup.style.opacity=0.85;
+ popup.style.backgroundColor="#C0C0C0";
+ popup.style.border="4px solid #404040";
+
+ document.body.appendChild(popup);
+}
+
+
+//
+// Draw a popup - independent of map because want it fixed on screen not fixed on map.
+//
+
+function drawPopup(html)
+{
+ if(html===null)
+   {
+    popup.style.display="none";
+    return;
+   }
+
+ if(popup.style.display=="none")
+   {
+    var map_div=document.getElementById("map");
+
+    popup.style.left  =map_div.offsetParent.offsetLeft+map_div.offsetLeft+60 + "px";
+    popup.style.top   =                                map_div.offsetTop +30 + "px";
+    popup.style.width =map_div.clientWidth-120 + "px";
+
+    popup.style.display="";
+   }
+
+ var close="<span style='float: right; cursor: pointer;' onclick='drawPopup(null)'>X</span>";
+
+ popup.innerHTML=close+html;
+}
+
+
+//
+// Select a circleMarker feature
+//
+
+function selectCircleMarkerFeature(feature,dump,event)
+{
+ if(dump)
+    ajaxGET("visualiser.cgi?dump=" + dump, runDumpSuccess);
+
+ layerHighlights.clearLayers();
+
+ var highlight = L.circleMarker(feature.getLatLng(),{radius: 2*feature.getRadius(), fill: true, fillColor: "#F0F000", fillOpacity: 1.0,
+                                                     stroke: false});
+
+ layerHighlights.addLayer(highlight);
+
+ highlight.bringToBack();
+}
+
+
+//
+// Select a Polyline feature
+//
+
+function selectPolylineFeature(feature,dump,event)
+{
+ if(dump)
+    ajaxGET("visualiser.cgi?dump=" + dump, runDumpSuccess);
+
+ layerHighlights.clearLayers();
+
+ var highlight = L.polyline(feature.getLatLngs(),{weight: 8, stroke: true, color: "#F0F000", opacity: 1.0,
+                                                  fill: false});
+
+ layerHighlights.addLayer(highlight);
+
+ highlight.bringToBack();
+}
+
+
+//
+// Select a Polygon feature
+//
+
+function selectPolygonFeature(feature,dump,event)
+{
+ if(dump)
+    ajaxGET("visualiser.cgi?dump=" + dump, runDumpSuccess);
+
+ layerHighlights.clearLayers();
+
+ var highlight = L.polygon(feature.getLatLngs(),{weight: 8, stroke: true, color: "#F0F000", opacity: 1.0,
+                                                 fill: false});
+
+ layerHighlights.addLayer(highlight);
+
+ highlight.bringToBack();
+}
+
+
+//
+// Un-select a feature
+//
+
+function unselectFeature(feature)
+{
+ layerHighlights.clearLayers();
+
+ drawPopup(null);
+}
+
+
+//
+// Display the dump data
+//
+
+function runDumpSuccess(response)
+{
+ var string=response.responseText;
+
+ if(mapprops.editurl !== undefined && mapprops.editurl !== "")
+   {
+    var types=["node", "way", "relation"];
+    var Types=["Node", "Way", "Relation"];
+
+    for(var t in types)
+      {
+       var Type=Types[t];
+       var type=types[t];
+
+       var regexp=RegExp(Type + " [0-9]+");
+
+       var match;
+
+       while((match=string.match(regexp)) !== null)
+         {
+          match=String(match);
+
+          var id=match.slice(1+type.length,match.length);
+
+          string=string.replace(regexp,Type + " <a href='" + mapprops.browseurl + "/" + type + "/" + id + "' target='" + type + id + "'>" + id + "</a>");
+         }
+      }
+   }
+
+ drawPopup(string.split("\n").join("<br>"));
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Server handling ////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+//
+// Define an AJAX request object
+//
+
+function ajaxGET(url,success,failure,state)
+{
+ var ajaxRequest=new XMLHttpRequest();
+
+ function ajaxGOT(options) {
+  if(this.readyState==4)
+     if(this.status==200)
+       { if(typeof(options.success)=="function") options.success(this,options.state); }
+     else
+       { if(typeof(options.failure)=="function") options.failure(this,options.state); }
+ }
+
+ ajaxRequest.onreadystatechange = function(){ ajaxGOT.call(ajaxRequest,{success: success, failure: failure, state: state}); };
+ ajaxRequest.open("GET", url, true);
+ ajaxRequest.send(null);
+}
+
+
+//
+// Display the status
+//
+
+function displayStatus(type,subtype,content)
+{
+ var child=document.getElementById("result_status").firstChild;
+
+ do
+   {
+    if(child.id !== undefined)
+       child.style.display="none";
+
+    child=child.nextSibling;
+   }
+ while(child !== null);
+
+ var chosen_status=document.getElementById("result_status_" + type);
+
+ chosen_status.style.display="";
+
+ if(subtype !== undefined)
+   {
+    var format_status=document.getElementById("result_status_" + subtype).innerHTML;
+
+    chosen_status.innerHTML=format_status.replace("#",String(content));
+   }
+}
+
+
+//
+// Display data statistics
+//
+
+function displayStatistics()
+{
+ // Use AJAX to get the statistics
+
+ ajaxGET("statistics.cgi", runStatisticsSuccess);
+}
+
+
+//
+// Success in running data statistics generation.
+//
+
+function runStatisticsSuccess(response)
+{
+ document.getElementById("statistics_data").innerHTML="<pre>" + response.responseText + "</pre>";
+ document.getElementById("statistics_link").style.display="none";
+}
+
+
+//
+// Get the requested data
+//
+
+function displayData(datatype)  // called from visualiser.html
+{
+ for(var data in data_types)
+    hideshow_hide(data_types[data]);
+
+ if(datatype !== "")
+    hideshow_show(datatype);
+
+ // Delete the old data
+
+ unselectFeature();
+
+ layerVectors.clearLayers();
+ layerHighlights.clearLayers();
+
+ layerBoxes.setStyle({stroke:false});
+ box=false;
+
+ // Print the status
+
+ displayStatus("no_data");
+
+ // Return if just here to clear the data
+
+ if(datatype === "")
+    return;
+
+ // Get the new data
+
+ var mapbounds=map.getBounds();
+
+ var url="visualiser.cgi";
+
+ url=url + "?lonmin=" + format5f(mapbounds.getWest());
+ url=url + ";latmin=" + format5f(mapbounds.getSouth());
+ url=url + ";lonmax=" + format5f(mapbounds.getEast());
+ url=url + ";latmax=" + format5f(mapbounds.getNorth());
+ url=url + ";data=" + datatype;
+
+ // Use AJAX to get the data
+
+ switch(datatype)
+   {
+   case "junctions":
+    ajaxGET(url, runJunctionsSuccess, runFailure);
+    break;
+   case "super":
+    ajaxGET(url, runSuperSuccess, runFailure);
+    break;
+   case "waytype":
+    var waytype;
+    var waytypes=document.forms["waytypes"].elements["waytype"];
+    for(var h in waytypes)
+       if(waytypes[h].checked)
+          waytype=waytypes[h].value;
+    url+="-" + waytype;
+    ajaxGET(url, runWaytypeSuccess, runFailure);
+    break;
+   case "highway":
+    var highway;
+    var highways=document.forms["highways"].elements["highway"];
+    for(var h in highways)
+       if(highways[h].checked)
+          highway=highways[h].value;
+    url+="-" + highway;
+    ajaxGET(url, runHighwaySuccess, runFailure);
+    break;
+   case "transport":
+    var transport;
+    var transports=document.forms["transports"].elements["transport"];
+    for(var t in transports)
+       if(transports[t].checked)
+          transport=transports[t].value;
+    url+="-" + transport;
+    ajaxGET(url, runTransportSuccess, runFailure);
+    break;
+   case "barrier":
+    var transport;
+    var transports=document.forms["barriers"].elements["barrier"];
+    for(var t in transports)
+       if(transports[t].checked)
+          transport=transports[t].value;
+    url+="-" + transport;
+    ajaxGET(url, runBarrierSuccess, runFailure);
+    break;
+   case "turns":
+    ajaxGET(url, runTurnsSuccess, runFailure);
+    break;
+   case "speed":
+   case "weight":
+   case "height":
+   case "width":
+   case "length":
+    ajaxGET(url, runLimitSuccess, runFailure);
+    break;
+   case "property":
+    var property;
+    var properties=document.forms["properties"].elements["property"];
+    for(var p in properties)
+       if(properties[p].checked)
+          property=properties[p].value;
+    url+="-" + property;
+    ajaxGET(url, runPropertySuccess, runFailure);
+    break;
+   case "errorlogs":
+    ajaxGET(url, runErrorlogSuccess, runFailure);
+    break;
+   }
+}
+
+
+//
+// Success in getting the junctions.
+//
+
+function runJunctionsSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var junction_colours={
+                       0: "#FFFFFF",
+                       1: "#FF0000",
+                       2: "#FFFF00",
+                       3: "#00FF00",
+                       4: "#8B4513",
+                       5: "#00BFFF",
+                       6: "#FF69B4",
+                       7: "#000000",
+                       8: "#000000",
+                       9: "#000000"
+                      };
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = L.latLngBounds(L.latLng(lat1,lon1),L.latLng(lat2,lon2));
+
+       layerBoxes.setBounds(bounds);
+
+       layerBoxes.setStyle({stroke: true});
+       box=true;
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat=words[1];
+       var lon=words[2];
+       var count=words[3];
+
+       var lonlat = L.latLng(lat,lon);
+
+       var feature = L.circleMarker(lonlat,{radius: 2, fill: true, fillColor: junction_colours[count], fillOpacity: 1.0,
+                                            stroke: false});
+
+       feature.on("click", (function(f,d) { return function(evt) { selectCircleMarkerFeature(f,d,evt); }; }(feature,dump)));
+
+       layerVectors.addLayer(feature);
+      }
+   }
+
+ displayStatus("data","junctions",lines.length-2);
+}
+
+
+//
+// Success in getting the super-node and super-segments
+//
+
+function runSuperSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var nodelonlat;
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = L.latLngBounds(L.latLng(lat1,lon1),L.latLng(lat2,lon2));
+
+       layerBoxes.setBounds(bounds);
+
+       layerBoxes.setStyle({stroke: true});
+       box=true;
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat=words[1];
+       var lon=words[2];
+
+       var lonlat = L.latLng(lat,lon);
+
+       if(dump.charAt(0) == "n")
+         {
+          nodelonlat=lonlat;
+
+          var feature = L.circleMarker(lonlat,{radius: 4, fill: true, fillColor: "#FF0000", fillOpacity: 1.0,
+                                               stroke: false});
+
+          feature.on("click", (function(f,d) { return function(evt) { selectCircleMarkerFeature(f,d,evt); }; }(feature,dump)));
+
+          layerVectors.addLayer(feature);
+         }
+       else
+         {
+          var feature = L.polyline([nodelonlat,lonlat],{weight: 2, stroke: true, color: "#FF0000", opacity: 1.0,
+                                                        fill: false});
+
+          feature.on("click", (function(f,d) { return function(evt) { selectPolylineFeature(f,d,evt); }; }(feature,dump)));
+
+          layerVectors.addLayer(feature);
+         }
+      }
+   }
+
+ displayStatus("data","super",lines.length-2);
+}
+
+
+//
+// Success in getting the waytype data
+//
+
+function runWaytypeSuccess(response)
+{
+ var hex={0: "00", 1: "11",  2: "22",  3: "33",  4: "44",  5: "55",  6: "66",  7: "77",
+          8: "88", 9: "99", 10: "AA", 11: "BB", 12: "CC", 13: "DD", 14: "EE", 15: "FF"};
+
+ var lines=response.responseText.split("\n");
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = L.latLngBounds(L.latLng(lat1,lon1),L.latLng(lat2,lon2));
+
+       layerBoxes.setBounds(bounds);
+
+       layerBoxes.setStyle({stroke: true});
+       box=true;
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat1=words[1];
+       var lon1=words[2];
+       var lat2=words[3];
+       var lon2=words[4];
+
+       var lonlat1 = L.latLng(lat1,lon1);
+       var lonlat2 = L.latLng(lat2,lon2);
+
+       var point1 = map.options.crs.latLngToPoint(lonlat1,15);
+       var point2 = map.options.crs.latLngToPoint(lonlat2,15);
+
+       var dy = point2.y-point1.y;
+       var dx = point2.x-point1.x;
+       var dist = Math.sqrt(dx*dx+dy*dy)/2;
+       var ang  = Math.atan2(-dy,dx);
+
+       var point3 = L.point(point1.x-dy/dist,point1.y+dx/dist);
+       var point4 = L.point(point1.x+dy/dist,point1.y-dx/dist);
+
+       var lonlat3 = map.options.crs.pointToLatLng(point3,15);
+       var lonlat4 = map.options.crs.pointToLatLng(point4,15);
+
+       var r=Math.round(7.5+7.9*Math.cos(ang));
+       var g=Math.round(7.5+7.9*Math.cos(ang+2.0943951));
+       var b=Math.round(7.5+7.9*Math.cos(ang-2.0943951));
+       var colour = "#" + hex[r] + hex[g] + hex[b];
+
+       var feature = L.polygon([lonlat2,lonlat3,lonlat4],{weight: 2, stroke: true, color: colour, opacity: 1.0,
+                                                          fill: false});
+
+       feature.on("click", (function(f,d) { return function(evt) { selectPolygonFeature(f,d,evt); }; }(feature,dump)));
+
+       layerVectors.addLayer(feature);
+      }
+   }
+
+ displayStatus("data","waytype",lines.length-2);
+}
+
+
+//
+// Success in getting the highway data
+//
+
+function runHighwaySuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = L.latLngBounds(L.latLng(lat1,lon1),L.latLng(lat2,lon2));
+
+       layerBoxes.setBounds(bounds);
+
+       layerBoxes.setStyle({stroke: true});
+       box=true;
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat1=words[1];
+       var lon1=words[2];
+       var lat2=words[3];
+       var lon2=words[4];
+
+       var lonlat1 = L.latLng(lat1,lon1);
+       var lonlat2 = L.latLng(lat2,lon2);
+
+       var feature = L.polyline([lonlat1,lonlat2],{weight: 2, stroke: true, color: "#FF0000", opacity: 1.0,
+                                                   fill: false});
+
+       feature.on("click", (function(f,d) { return function(evt) { selectPolylineFeature(f,d,evt); }; }(feature,dump)));
+
+       layerVectors.addLayer(feature);
+      }
+   }
+
+ displayStatus("data","highway",lines.length-2);
+}
+
+
+//
+// Success in getting the transport data
+//
+
+function runTransportSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = L.latLngBounds(L.latLng(lat1,lon1),L.latLng(lat2,lon2));
+
+       layerBoxes.setBounds(bounds);
+
+       layerBoxes.setStyle({stroke: true});
+       box=true;
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat1=words[1];
+       var lon1=words[2];
+       var lat2=words[3];
+       var lon2=words[4];
+
+       var lonlat1 = L.latLng(lat1,lon1);
+       var lonlat2 = L.latLng(lat2,lon2);
+
+       var feature = L.polyline([lonlat1,lonlat2],{weight: 2, stroke: true, color: "#FF0000", opacity: 1.0,
+                                                   fill: false});
+
+       feature.on("click", (function(f,d) { return function(evt) { selectPolylineFeature(f,d,evt); }; }(feature,dump)));
+
+       layerVectors.addLayer(feature);
+      }
+   }
+
+ displayStatus("data","transport",lines.length-2);
+}
+
+
+//
+// Success in getting the barrier data
+//
+
+function runBarrierSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = L.latLngBounds(L.latLng(lat1,lon1),L.latLng(lat2,lon2));
+
+       layerBoxes.setBounds(bounds);
+
+       layerBoxes.setStyle({stroke: true});
+       box=true;
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat=words[1];
+       var lon=words[2];
+
+       var lonlat = L.latLng(lat,lon);
+
+       var feature = L.circleMarker(lonlat,{radius: 2, fill: true, fillColor: "#FF0000", fillOpacity: 1.0,
+                                            stroke: false});
+
+       feature.on("click", (function(f,d) { return function(evt) { selectCircleMarkerFeature(f,d,evt); }; }(feature,dump)));
+
+       layerVectors.addLayer(feature);
+      }
+   }
+
+ displayStatus("data","barrier",lines.length-2);
+}
+
+
+//
+// Success in getting the turn restrictions data
+//
+
+function runTurnsSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = L.latLngBounds(L.latLng(lat1,lon1),L.latLng(lat2,lon2));
+
+       layerBoxes.setBounds(bounds);
+
+       layerBoxes.setStyle({stroke: true});
+       box=true;
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat1=words[1];
+       var lon1=words[2];
+       var lat2=words[3];
+       var lon2=words[4];
+       var lat3=words[5];
+       var lon3=words[6];
+
+       var lonlat1 = L.latLng(lat1,lon1);
+       var lonlat2 = L.latLng(lat2,lon2);
+       var lonlat3 = L.latLng(lat3,lon3);
+
+       var feature = L.polygon([lonlat1,lonlat2,lonlat3],{weight: 2, stroke: true, color: "#FF0000", opacity: 1.0,
+                                                          fill: false});
+
+       feature.on("click", (function(f,d) { return function(evt) { selectPolygonFeature(f,d,evt); }; }(feature,dump)));
+
+       layerVectors.addLayer(feature);
+      }
+   }
+
+ displayStatus("data","turns",lines.length-2);
+}
+
+
+//
+// Success in getting the speed/weight/height/width/length limits
+//
+
+function runLimitSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var nodelonlat;
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = L.latLngBounds(L.latLng(lat1,lon1),L.latLng(lat2,lon2));
+
+       layerBoxes.setBounds(bounds);
+
+       layerBoxes.setStyle({stroke: true});
+       box=true;
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat=words[1];
+       var lon=words[2];
+       var number=words[3];
+
+       var lonlat = L.latLng(lat,lon);
+
+       if(number === undefined)
+         {
+          nodelonlat=lonlat;
+
+          var feature = L.circleMarker(lonlat,{radius: 3, fill: true, fillColor: "#FF0000", fillOpacity: 1.0,
+                                               stroke: false});
+
+          feature.on("click", (function(f,d) { return function(evt) { selectCircleMarkerFeature(f,d,evt); }; }(feature,dump)));
+
+          layerVectors.addLayer(feature);
+         }
+       else
+         {
+          var lonlat = L.latLng(lat,lon);
+
+          var feature = L.polyline([nodelonlat,lonlat],{weight: 2, stroke: true, color: "#FF0000", opacity: 1.0,
+                                                        fill: false});
+
+          feature.on("click", (function(f,d) { return function(evt) { selectPolylineFeature(f,d,evt); }; }(feature,dump)));
+
+          layerVectors.addLayer(feature);
+
+          var point1 = map.options.crs.latLngToPoint(nodelonlat,15);
+          var point2 = map.options.crs.latLngToPoint(lonlat    ,15);
+
+          var dy = point2.y-point1.y;
+          var dx = point2.x-point1.x;
+          var dist = Math.sqrt(dx*dx+dy*dy)/24;
+
+          var point = L.point(point1.x+dx/dist,point1.y+dy/dist);
+
+          feature=L.marker(map.options.crs.pointToLatLng(point,15), {clickable: false,
+                                                                     icon: L.icon({iconUrl: "icons/limit-" + number + ".png",
+                                                                                   iconSize: L.point(19,19),
+                                                                                   iconAnchor: L.point(9,10)})});
+
+          layerVectors.addLayer(feature);
+         }
+      }
+   }
+
+ displayStatus("data","limit",lines.length-2);
+}
+
+
+//
+// Success in getting the property data
+//
+
+function runPropertySuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = L.latLngBounds(L.latLng(lat1,lon1),L.latLng(lat2,lon2));
+
+       layerBoxes.setBounds(bounds);
+
+       layerBoxes.setStyle({stroke: true});
+       box=true;
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat1=words[1];
+       var lon1=words[2];
+       var lat2=words[3];
+       var lon2=words[4];
+
+       var lonlat1 = L.latLng(lat1,lon1);
+       var lonlat2 = L.latLng(lat2,lon2);
+
+       var feature = L.polyline([lonlat1,lonlat2],{weight: 2, stroke: true, color: "#FF0000", opacity: 1.0,
+                                                   fill: false});
+
+       feature.on("click", (function(f,d) { return function(evt) { selectPolylineFeature(f,d,evt); }; }(feature,dump)));
+
+       layerVectors.addLayer(feature);
+      }
+   }
+
+ displayStatus("data","property",lines.length-2);
+}
+
+
+//
+// Success in getting the error log data
+//
+
+function runErrorlogSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = L.latLngBounds(L.latLng(lat1,lon1),L.latLng(lat2,lon2));
+
+       layerBoxes.setBounds(bounds);
+
+       layerBoxes.setStyle({stroke: true});
+       box=true;
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat=words[1];
+       var lon=words[2];
+
+       var lonlat = L.latLng(lat,lon);
+
+       var feature = L.circleMarker(lonlat,{radius: 3, fill: true, fillColor: "#FF0000", fillOpacity: 1.0,
+                                            stroke: false});
+
+       feature.on("click", (function(f,d) { return function(evt) { selectCircleMarkerFeature(f,d,evt); }; }(feature,dump)));
+
+       layerVectors.addLayer(feature);
+      }
+   }
+
+ displayStatus("data","errorlogs",lines.length-2);
+}
+
+
+//
+// Failure in getting data.
+//
+
+function runFailure(response)
+{
+ displayStatus("failed");
+}
diff --git a/3rdparty/Routino/web/www/routino/visualiser.openlayers.js b/3rdparty/Routino/web/www/routino/visualiser.openlayers.js
new file mode 100644
index 0000000..49be815
--- /dev/null
+++ b/3rdparty/Routino/web/www/routino/visualiser.openlayers.js
@@ -0,0 +1,1315 @@
+//
+// Routino data visualiser web page Javascript
+//
+// Part of the Routino routing software.
+//
+// This file Copyright 2008-2014 Andrew M. Bishop
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+//
+// Data types
+//
+
+var data_types=[
+                "junctions",
+                "super",
+                "waytype",
+                "highway",
+                "transport",
+                "barrier",
+                "turns",
+                "speed",
+                "weight",
+                "height",
+                "width",
+                "length",
+                "property",
+                "errorlogs"
+               ];
+
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Initialisation /////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+// Process the URL query string and extract the arguments
+
+var legal={"^lon"  : "^[-0-9.]+$",
+           "^lat"  : "^[-0-9.]+$",
+           "^zoom" : "^[0-9]+$"};
+
+var args={};
+
+if(location.search.length>1)
+  {
+   var query,queries;
+
+   query=location.search.replace(/^\?/,"");
+   query=query.replace(/;/g,"&");
+   queries=query.split("&");
+
+   for(var i=0;i<queries.length;i++)
+     {
+      queries[i].match(/^([^=]+)(=(.*))?$/);
+
+      var k=RegExp.$1;
+      var v=decodeURIComponent(RegExp.$3);
+
+      for(var l in legal)
+        {
+         if(k.match(RegExp(l)) && v.match(RegExp(legal[l])))
+            args[k]=v;
+        }
+     }
+  }
+
+
+////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////// Map handling /////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+var map;
+var layerMap=[], layerHighlights, layerVectors, layerBoxes;
+var epsg4326, epsg900913;
+var box;
+var select;
+
+//
+// Initialise the 'map' object
+//
+
+function map_init()             // called from visualiser.html
+{
+ // Create the map (Map URLs and limits are in mapprops.js)
+
+ epsg4326=new OpenLayers.Projection("EPSG:4326");
+ epsg900913=new OpenLayers.Projection("EPSG:900913");
+
+ map = new OpenLayers.Map ("map",
+                           {
+                            controls:[
+                                      new OpenLayers.Control.Navigation(),
+                                      new OpenLayers.Control.PanZoomBar(),
+                                      new OpenLayers.Control.ScaleLine(),
+                                      new OpenLayers.Control.LayerSwitcher()
+                                      ],
+
+                            projection: epsg900913,
+                            displayProjection: epsg4326,
+
+                            minZoomLevel: mapprops.zoomout,
+                            numZoomLevels: mapprops.zoomin-mapprops.zoomout+1,
+                            maxResolution: 156543.03390625 / Math.pow(2,mapprops.zoomout),
+
+                            restrictedExtent: new OpenLayers.Bounds(mapprops.westedge,mapprops.southedge,mapprops.eastedge,mapprops.northedge).transform(epsg4326,epsg900913)
+                           });
+
+ // Get a URL for the tile (mostly copied from OpenLayers/Layer/XYZ.js).
+
+ function limitedUrl(bounds)
+ {
+  var res = this.map.getResolution();
+
+  var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
+  var y = Math.round((this.maxExtent.top - bounds.top) / (res * this.tileSize.h));
+  var z = this.map.getZoom() + this.map.minZoomLevel;
+
+  var limit = Math.pow(2, z);
+  x = ((x % limit) + limit) % limit;
+
+  var xyz = {"x": x, "y": y, "z": z};
+  var url = this.url;
+
+  if (OpenLayers.Util.isArray(url))
+    {
+     var s = "" + xyz.x + xyz.y + xyz.z;
+     url = this.selectUrl(s, url);
+    }
+
+  return OpenLayers.String.format(url, xyz);
+ }
+
+ // Add map tile layers
+
+ for(var l=0; l<mapprops.mapdata.length; l++)
+   {
+    var urls;
+
+    if(OpenLayers.Util.isArray(mapprops.mapdata[l].tiles.subdomains))
+      {
+       urls=[];
+
+       for(var s=0; s<mapprops.mapdata[l].tiles.subdomains.length; s++)
+          urls.push(mapprops.mapdata[l].tiles.url.replace(/\${s}/,mapprops.mapdata[l].tiles.subdomains[s]));
+      }
+    else
+       urls=mapprops.mapdata[l].tiles.url;
+
+    layerMap[l] = new OpenLayers.Layer.TMS(mapprops.mapdata[l].label,
+                                           urls,
+                                           {
+                                            getURL: limitedUrl,
+                                            displayOutsideMaxExtent: true,
+                                            buffer: 1
+                                           });
+    map.addLayer(layerMap[l]);
+   }
+
+ // Update the attribution if the layer changes
+
+ function change_attribution_event(event)
+ {
+  for(var l=0; l<mapprops.mapdata.length; l++)
+     if(layerMap[l] == event.layer)
+        change_attribution(l);
+ }
+
+ map.events.register("changelayer",layerMap,change_attribution_event);
+
+ function change_attribution(l)
+ {
+  var data_url =mapprops.mapdata[l].attribution.data_url;
+  var data_text=mapprops.mapdata[l].attribution.data_text;
+  var tile_url =mapprops.mapdata[l].attribution.tile_url;
+  var tile_text=mapprops.mapdata[l].attribution.tile_text;
+
+  document.getElementById("attribution_data").innerHTML="<a href=\"" + data_url + "\" target=\"data_attribution\">" + data_text + "</a>";
+  document.getElementById("attribution_tile").innerHTML="<a href=\"" + tile_url + "\" target=\"tile_attribution\">" + tile_text + "</a>";
+ }
+
+ change_attribution(0);
+
+ // Add two vectors layers (one for highlights that display behind the vectors)
+
+ layerHighlights = new OpenLayers.Layer.Vector("Highlights",{displayInLayerSwitcher: false});
+ map.addLayer(layerHighlights);
+
+ layerVectors = new OpenLayers.Layer.Vector("Markers",{displayInLayerSwitcher: false});
+ map.addLayer(layerVectors);
+
+ // Handle feature selection and popup
+
+ select = new OpenLayers.Control.SelectFeature(layerVectors,
+                                               {onSelect: selectFeature, onUnselect: unselectFeature});
+
+ map.addControl(select);
+ select.activate();
+
+ createPopup();
+
+ // Add a boxes layer
+
+ layerBoxes = new OpenLayers.Layer.Boxes("Boundary",{displayInLayerSwitcher: false});
+ map.addLayer(layerBoxes);
+
+ box=null;
+
+ // Move the map
+
+ map.events.register("moveend", map, updateURLs);
+
+ var lon =args["lon"];
+ var lat =args["lat"];
+ var zoom=args["zoom"];
+
+ if(lon !== undefined && lat !== undefined && zoom !== undefined)
+   {
+    if(lon<mapprops.westedge) lon=mapprops.westedge;
+    if(lon>mapprops.eastedge) lon=mapprops.eastedge;
+
+    if(lat<mapprops.southedge) lat=mapprops.southedge;
+    if(lat>mapprops.northedge) lat=mapprops.northedge;
+
+    if(zoom<mapprops.zoomout) zoom=mapprops.zoomout;
+    if(zoom>mapprops.zoomin)  zoom=mapprops.zoomin;
+
+    var lonlat = new OpenLayers.LonLat(lon,lat);
+    lonlat.transform(epsg4326,epsg900913);
+
+    map.moveTo(lonlat,zoom-map.minZoomLevel);
+   }
+ else
+   {
+    map.setCenter(map.restrictedExtent.getCenterLonLat(), map.getZoomForExtent(map.restrictedExtent,true));
+    map.maxResolution = map.getResolution();
+   }
+
+ // Unhide editing URL if variable set
+
+ if(mapprops.editurl !== undefined && mapprops.editurl !== "")
+   {
+    var edit_url=document.getElementById("edit_url");
+
+    edit_url.style.display="";
+    edit_url.href=mapprops.editurl;
+   }
+
+ updateURLs();
+}
+
+
+//
+// Format a number in printf("%.5f") format.
+//
+
+function format5f(number)
+{
+ var newnumber=Math.floor(number*100000+0.5);
+ var delta=0;
+
+ if(newnumber>=0 && newnumber<100000) delta= 100000;
+ if(newnumber<0 && newnumber>-100000) delta=-100000;
+
+ var string=String(newnumber+delta);
+
+ var intpart =string.substring(0,string.length-5);
+ var fracpart=string.substring(string.length-5,string.length);
+
+ if(delta>0) intpart="0";
+ if(delta<0) intpart="-0";
+
+ return(intpart + "." + fracpart);
+}
+
+
+//
+// Build a set of URL arguments for the map location
+//
+
+function buildMapArguments()
+{
+ var lonlat = map.getCenter().clone();
+ lonlat.transform(epsg900913,epsg4326);
+
+ var zoom = map.getZoom() + map.minZoomLevel;
+
+ return "lat=" + format5f(lonlat.lat) + ";lon=" + format5f(lonlat.lon) + ";zoom=" + zoom;
+}
+
+
+//
+// Update the URLs
+//
+
+function updateURLs()
+{
+ var mapargs=buildMapArguments();
+
+ var links=document.getElementsByTagName("a");
+
+ for(var i=0; i<links.length; i++)
+   {
+    var element=links[i];
+
+    if(element.id == "permalink_url")
+       element.href=location.pathname + "?" + mapargs;
+
+    if(element.id == "router_url")
+       element.href="router.html" + "?" + mapargs;
+
+    if(element.id == "edit_url")
+       element.href=mapprops.editurl + "?" + mapargs;
+
+    if(element.id.match(/^lang_([a-zA-Z-]+)_url$/))
+       element.href="visualiser.html" + "." + RegExp.$1 + "?" + mapargs;
+   }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+///////////////////////// Popup and selection handling /////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+var popup=null;
+
+//
+// Create a popup - independent of map because want it fixed on screen not fixed on map.
+//
+
+function createPopup()
+{
+ popup=document.createElement("div");
+
+ popup.className = "popup";
+
+ popup.innerHTML = "<span></span>";
+
+ popup.style.display = "none";
+
+ popup.style.position = "fixed";
+ popup.style.top = "-4000px";
+ popup.style.left = "-4000px";
+ popup.style.zIndex = "100";
+
+ popup.style.padding = "5px";
+
+ popup.style.opacity=0.85;
+ popup.style.backgroundColor="#C0C0C0";
+ popup.style.border="4px solid #404040";
+
+ document.body.appendChild(popup);
+}
+
+
+//
+// Draw a popup - independent of map because want it fixed on screen not fixed on map.
+//
+
+function drawPopup(html)
+{
+ if(html===null)
+   {
+    popup.style.display="none";
+    return;
+   }
+
+ if(popup.style.display=="none")
+   {
+    var map_div=document.getElementById("map");
+
+    popup.style.left  =map_div.offsetParent.offsetLeft+map_div.offsetLeft+60 + "px";
+    popup.style.top   =                                map_div.offsetTop +30 + "px";
+    popup.style.width =map_div.clientWidth-120 + "px";
+
+    popup.style.display="";
+   }
+
+ var close="<span style='float: right; cursor: pointer;' onclick='drawPopup(null)'>X</span>";
+
+ popup.innerHTML=close+html;
+}
+
+
+//
+// Select a feature
+//
+
+function selectFeature(feature)
+{
+ if(feature.attributes.dump)
+    ajaxGET("visualiser.cgi?dump=" + feature.attributes.dump, runDumpSuccess);
+
+ layerHighlights.destroyFeatures();
+
+ var highlight_style = new OpenLayers.Style({},{strokeColor: "#F0F000",strokeWidth: 8,
+                                                fillColor: "#F0F000",pointRadius: 4});
+
+ var highlight = new OpenLayers.Feature.Vector(feature.geometry.clone(),{},highlight_style);
+
+ layerHighlights.addFeatures([highlight]);
+}
+
+
+//
+// Un-select a feature
+//
+
+function unselectFeature(feature)
+{
+ layerHighlights.destroyFeatures();
+
+ drawPopup(null);
+}
+
+
+//
+// Display the dump data
+//
+
+function runDumpSuccess(response)
+{
+ var string=response.responseText;
+
+ if(mapprops.editurl !== undefined && mapprops.editurl !== "")
+   {
+    var types=["node", "way", "relation"];
+    var Types=["Node", "Way", "Relation"];
+
+    for(var t in types)
+      {
+       var Type=Types[t];
+       var type=types[t];
+
+       var regexp=RegExp(Type + " [0-9]+");
+
+       var match;
+
+       while((match=string.match(regexp)) !== null)
+         {
+          match=String(match);
+
+          var id=match.slice(1+type.length,match.length);
+
+          string=string.replace(regexp,Type + " <a href='" + mapprops.browseurl + "/" + type + "/" + id + "' target='" + type + id + "'>" + id + "</a>");
+         }
+      }
+   }
+
+ drawPopup(string.split("\n").join("<br>"));
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Server handling ////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+//
+// Define an AJAX request object
+//
+
+function ajaxGET(url,success,failure,state)
+{
+ var ajaxRequest=new XMLHttpRequest();
+
+ function ajaxGOT(options) {
+  if(this.readyState==4)
+     if(this.status==200)
+       { if(typeof(options.success)=="function") options.success(this,options.state); }
+     else
+       { if(typeof(options.failure)=="function") options.failure(this,options.state); }
+ }
+
+ ajaxRequest.onreadystatechange = function(){ ajaxGOT.call(ajaxRequest,{success: success, failure: failure, state: state}); };
+ ajaxRequest.open("GET", url, true);
+ ajaxRequest.send(null);
+}
+
+
+//
+// Display the status
+//
+
+function displayStatus(type,subtype,content)
+{
+ var child=document.getElementById("result_status").firstChild;
+
+ do
+   {
+    if(child.id !== undefined)
+       child.style.display="none";
+
+    child=child.nextSibling;
+   }
+ while(child !== null);
+
+ var chosen_status=document.getElementById("result_status_" + type);
+
+ chosen_status.style.display="";
+
+ if(subtype !== undefined)
+   {
+    var format_status=document.getElementById("result_status_" + subtype).innerHTML;
+
+    chosen_status.innerHTML=format_status.replace("#",String(content));
+   }
+}
+
+
+//
+// Display data statistics
+//
+
+function displayStatistics()
+{
+ // Use AJAX to get the statistics
+
+ ajaxGET("statistics.cgi", runStatisticsSuccess);
+}
+
+
+//
+// Success in running data statistics generation.
+//
+
+function runStatisticsSuccess(response)
+{
+ document.getElementById("statistics_data").innerHTML="<pre>" + response.responseText + "</pre>";
+ document.getElementById("statistics_link").style.display="none";
+}
+
+
+//
+// Get the requested data
+//
+
+function displayData(datatype)  // called from visualiser.html
+{
+ for(var data in data_types)
+    hideshow_hide(data_types[data]);
+
+ if(datatype !== "")
+    hideshow_show(datatype);
+
+ // Delete the old data
+
+ unselectFeature();
+
+ select.deactivate();
+
+ layerVectors.destroyFeatures();
+ layerHighlights.destroyFeatures();
+
+ if(box !== null)
+    layerBoxes.removeMarker(box);
+ box=null;
+
+ // Print the status
+
+ displayStatus("no_data");
+
+ // Return if just here to clear the data
+
+ if(datatype === "")
+    return;
+
+ // Get the new data
+
+ var mapbounds=map.getExtent().clone();
+ mapbounds.transform(epsg900913,epsg4326);
+
+ var url="visualiser.cgi";
+
+ url=url + "?lonmin=" + format5f(mapbounds.left);
+ url=url + ";latmin=" + format5f(mapbounds.bottom);
+ url=url + ";lonmax=" + format5f(mapbounds.right);
+ url=url + ";latmax=" + format5f(mapbounds.top);
+ url=url + ";data=" + datatype;
+
+ // Use AJAX to get the data
+
+ switch(datatype)
+   {
+   case "junctions":
+    ajaxGET(url, runJunctionsSuccess, runFailure);
+    break;
+   case "super":
+    ajaxGET(url, runSuperSuccess, runFailure);
+    break;
+   case "waytype":
+    var waytype;
+    var waytypes=document.forms["waytypes"].elements["waytype"];
+    for(var h in waytypes)
+       if(waytypes[h].checked)
+          waytype=waytypes[h].value;
+    url+="-" + waytype;
+    ajaxGET(url, runWaytypeSuccess, runFailure);
+    break;
+   case "highway":
+    var highway;
+    var highways=document.forms["highways"].elements["highway"];
+    for(var h in highways)
+       if(highways[h].checked)
+          highway=highways[h].value;
+    url+="-" + highway;
+    ajaxGET(url, runHighwaySuccess, runFailure);
+    break;
+   case "transport":
+    var transport;
+    var transports=document.forms["transports"].elements["transport"];
+    for(var t in transports)
+       if(transports[t].checked)
+          transport=transports[t].value;
+    url+="-" + transport;
+    ajaxGET(url, runTransportSuccess, runFailure);
+    break;
+   case "barrier":
+    var transport;
+    var transports=document.forms["barriers"].elements["barrier"];
+    for(var t in transports)
+       if(transports[t].checked)
+          transport=transports[t].value;
+    url+="-" + transport;
+    ajaxGET(url, runBarrierSuccess, runFailure);
+    break;
+   case "turns":
+    ajaxGET(url, runTurnsSuccess, runFailure);
+    break;
+   case "speed":
+   case "weight":
+   case "height":
+   case "width":
+   case "length":
+    ajaxGET(url, runLimitSuccess, runFailure);
+    break;
+   case "property":
+    var property;
+    var properties=document.forms["properties"].elements["property"];
+    for(var p in properties)
+       if(properties[p].checked)
+          property=properties[p].value;
+    url+="-" + property;
+    ajaxGET(url, runPropertySuccess, runFailure);
+    break;
+   case "errorlogs":
+    ajaxGET(url, runErrorlogSuccess, runFailure);
+    break;
+   }
+}
+
+
+//
+// Success in getting the junctions.
+//
+
+function runJunctionsSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var junction_colours={
+                       0: "#FFFFFF",
+                       1: "#FF0000",
+                       2: "#FFFF00",
+                       3: "#00FF00",
+                       4: "#8B4513",
+                       5: "#00BFFF",
+                       6: "#FF69B4",
+                       7: "#000000",
+                       8: "#000000",
+                       9: "#000000"
+                      };
+
+ var styles={};
+
+ for(var colour in junction_colours)
+    styles[colour]=new OpenLayers.Style({},{stroke: false,
+                                            pointRadius: 2,fillColor: junction_colours[colour],
+                                            cursor: "pointer"});
+
+ var features=[];
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,epsg900913);
+
+       box = new OpenLayers.Marker.Box(bounds);
+
+       layerBoxes.addMarker(box);
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat=words[1];
+       var lon=words[2];
+       var count=words[3];
+
+       var lonlat= new OpenLayers.LonLat(lon,lat).transform(epsg4326,epsg900913);
+
+       var point = new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);
+
+       features.push(new OpenLayers.Feature.Vector(point,{dump: dump},styles[count]));
+      }
+   }
+
+ select.activate();
+
+ layerVectors.addFeatures(features);
+
+ displayStatus("data","junctions",lines.length-2);
+}
+
+
+//
+// Success in getting the super-node and super-segments
+//
+
+function runSuperSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var node_style = new OpenLayers.Style({},{stroke: false,
+                                           pointRadius: 4,fillColor: "#FF0000",
+                                           cursor: "pointer"});
+
+ var segment_style = new OpenLayers.Style({},{fill: false,
+                                              strokeWidth: 2,strokeColor: "#FF0000",
+                                              cursor: "pointer"});
+
+ var features=[];
+
+ var nodepoint;
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,epsg900913);
+
+       box = new OpenLayers.Marker.Box(bounds);
+
+       layerBoxes.addMarker(box);
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat=words[1];
+       var lon=words[2];
+
+       var lonlat= new OpenLayers.LonLat(lon,lat).transform(epsg4326,epsg900913);
+
+       var point = new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);
+
+       if(dump.charAt(0) == "n")
+         {
+          nodepoint=point;
+
+          features.push(new OpenLayers.Feature.Vector(point,{dump: dump},node_style));
+         }
+       else
+         {
+          var segment = new OpenLayers.Geometry.LineString([nodepoint,point]);
+
+          features.push(new OpenLayers.Feature.Vector(segment,{dump: dump},segment_style));
+         }
+      }
+   }
+
+ select.activate();
+
+ layerVectors.addFeatures(features);
+
+ displayStatus("data","super",lines.length-2);
+}
+
+
+//
+// Success in getting the waytype data
+//
+
+function runWaytypeSuccess(response)
+{
+ var hex={0: "00", 1: "11",  2: "22",  3: "33",  4: "44",  5: "55",  6: "66",  7: "77",
+          8: "88", 9: "99", 10: "AA", 11: "BB", 12: "CC", 13: "DD", 14: "EE", 15: "FF"};
+
+ var lines=response.responseText.split("\n");
+
+ var features=[];
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,epsg900913);
+
+       box = new OpenLayers.Marker.Box(bounds);
+
+       layerBoxes.addMarker(box);
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat1=words[1];
+       var lon1=words[2];
+       var lat2=words[3];
+       var lon2=words[4];
+
+       var lonlat1 = new OpenLayers.LonLat(lon1,lat1).transform(epsg4326,epsg900913);
+       var lonlat2 = new OpenLayers.LonLat(lon2,lat2).transform(epsg4326,epsg900913);
+
+     //var point1 = new OpenLayers.Geometry.Point(lonlat1.lon,lonlat1.lat);
+       var point2 = new OpenLayers.Geometry.Point(lonlat2.lon,lonlat2.lat);
+
+       var dlat = lonlat2.lat-lonlat1.lat;
+       var dlon = lonlat2.lon-lonlat1.lon;
+       var dist = Math.sqrt(dlat*dlat+dlon*dlon)/10;
+       var ang  = Math.atan2(dlat,dlon);
+
+       var point3 = new OpenLayers.Geometry.Point(lonlat1.lon+dlat/dist,lonlat1.lat-dlon/dist);
+       var point4 = new OpenLayers.Geometry.Point(lonlat1.lon-dlat/dist,lonlat1.lat+dlon/dist);
+
+       var r=Math.round(7.5+7.9*Math.cos(ang));
+       var g=Math.round(7.5+7.9*Math.cos(ang+2.0943951));
+       var b=Math.round(7.5+7.9*Math.cos(ang-2.0943951));
+       var colour = "#" + hex[r] + hex[g] + hex[b];
+
+       var segment = new OpenLayers.Geometry.LineString([point2,point3,point4,point2]);
+
+       var style=new OpenLayers.Style({},{strokeWidth: 2,strokeColor: colour, cursor: "pointer"});
+
+       features.push(new OpenLayers.Feature.Vector(segment,{dump: dump},style));
+      }
+   }
+
+ select.activate();
+
+ layerVectors.addFeatures(features);
+
+ displayStatus("data","waytype",lines.length-2);
+}
+
+
+//
+// Success in getting the highway data
+//
+
+function runHighwaySuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var style = new OpenLayers.Style({},{fill: false,
+                                      strokeWidth: 2,strokeColor: "#FF0000",
+                                      cursor: "pointer"});
+
+ var features=[];
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,epsg900913);
+
+       box = new OpenLayers.Marker.Box(bounds);
+
+       layerBoxes.addMarker(box);
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat1=words[1];
+       var lon1=words[2];
+       var lat2=words[3];
+       var lon2=words[4];
+
+       var lonlat1= new OpenLayers.LonLat(lon1,lat1).transform(epsg4326,epsg900913);
+       var lonlat2= new OpenLayers.LonLat(lon2,lat2).transform(epsg4326,epsg900913);
+
+       var point1 = new OpenLayers.Geometry.Point(lonlat1.lon,lonlat1.lat);
+       var point2 = new OpenLayers.Geometry.Point(lonlat2.lon,lonlat2.lat);
+
+       var segment = new OpenLayers.Geometry.LineString([point1,point2]);
+
+       features.push(new OpenLayers.Feature.Vector(segment,{dump: dump},style));
+      }
+   }
+
+ select.activate();
+
+ layerVectors.addFeatures(features);
+
+ displayStatus("data","highway",lines.length-2);
+}
+
+
+//
+// Success in getting the transport data
+//
+
+function runTransportSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var style = new OpenLayers.Style({},{fill: false,
+                                      strokeWidth: 2,strokeColor: "#FF0000",
+                                      cursor: "pointer"});
+
+ var features=[];
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,epsg900913);
+
+       box = new OpenLayers.Marker.Box(bounds);
+
+       layerBoxes.addMarker(box);
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat1=words[1];
+       var lon1=words[2];
+       var lat2=words[3];
+       var lon2=words[4];
+
+       var lonlat1= new OpenLayers.LonLat(lon1,lat1).transform(epsg4326,epsg900913);
+       var lonlat2= new OpenLayers.LonLat(lon2,lat2).transform(epsg4326,epsg900913);
+
+       var point1 = new OpenLayers.Geometry.Point(lonlat1.lon,lonlat1.lat);
+       var point2 = new OpenLayers.Geometry.Point(lonlat2.lon,lonlat2.lat);
+
+       var segment = new OpenLayers.Geometry.LineString([point1,point2]);
+
+       features.push(new OpenLayers.Feature.Vector(segment,{dump: dump},style));
+      }
+   }
+
+ select.activate();
+
+ layerVectors.addFeatures(features);
+
+ displayStatus("data","transport",lines.length-2);
+}
+
+
+//
+// Success in getting the barrier data
+//
+
+function runBarrierSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var style = new OpenLayers.Style({},{stroke: false,
+                                      pointRadius: 3,fillColor: "#FF0000",
+                                      cursor: "pointer"});
+
+ var features=[];
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,epsg900913);
+
+       box = new OpenLayers.Marker.Box(bounds);
+
+       layerBoxes.addMarker(box);
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat=words[1];
+       var lon=words[2];
+
+       var lonlat= new OpenLayers.LonLat(lon,lat).transform(epsg4326,epsg900913);
+
+       var point = new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);
+
+       features.push(new OpenLayers.Feature.Vector(point,{dump: dump},style));
+      }
+   }
+
+ select.activate();
+
+ layerVectors.addFeatures(features);
+
+ displayStatus("data","barrier",lines.length-2);
+}
+
+
+//
+// Success in getting the turn restrictions data
+//
+
+function runTurnsSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var style = new OpenLayers.Style({},{fill: false,
+                                      strokeWidth: 2,strokeColor: "#FF0000",
+                                      cursor: "pointer"});
+
+ var features=[];
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,epsg900913);
+
+       box = new OpenLayers.Marker.Box(bounds);
+
+       layerBoxes.addMarker(box);
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat1=words[1];
+       var lon1=words[2];
+       var lat2=words[3];
+       var lon2=words[4];
+       var lat3=words[5];
+       var lon3=words[6];
+
+       var lonlat1= new OpenLayers.LonLat(lon1,lat1).transform(epsg4326,epsg900913);
+       var lonlat2= new OpenLayers.LonLat(lon2,lat2).transform(epsg4326,epsg900913);
+       var lonlat3= new OpenLayers.LonLat(lon3,lat3).transform(epsg4326,epsg900913);
+
+       var point1 = new OpenLayers.Geometry.Point(lonlat1.lon,lonlat1.lat);
+       var point2 = new OpenLayers.Geometry.Point(lonlat2.lon,lonlat2.lat);
+       var point3 = new OpenLayers.Geometry.Point(lonlat3.lon,lonlat3.lat);
+
+       var segments = new OpenLayers.Geometry.LineString([point1,point2,point3]);
+
+       features.push(new OpenLayers.Feature.Vector(segments,{dump: dump},style));
+      }
+   }
+
+ select.activate();
+
+ layerVectors.addFeatures(features);
+
+ displayStatus("data","turns",lines.length-2);
+}
+
+
+//
+// Success in getting the speed/weight/height/width/length limits
+//
+
+function runLimitSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var node_style = new OpenLayers.Style({},{stroke: false,
+                                           pointRadius: 3,fillColor: "#FF0000",
+                                           cursor: "pointer"});
+
+ var segment_style = new OpenLayers.Style({},{fill: false,
+                                              strokeWidth: 2,strokeColor: "#FF0000",
+                                              cursor: "pointer"});
+
+ var features=[];
+
+ var nodepoint;
+ var nodelonlat;
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,epsg900913);
+
+       box = new OpenLayers.Marker.Box(bounds);
+
+       layerBoxes.addMarker(box);
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat=words[1];
+       var lon=words[2];
+       var number=words[3];
+
+       var lonlat= new OpenLayers.LonLat(lon,lat).transform(epsg4326,epsg900913);
+
+       var point = new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);
+
+       if(number === undefined)
+         {
+          nodelonlat=lonlat;
+          nodepoint = point;
+
+          features.push(new OpenLayers.Feature.Vector(point,{dump: dump},node_style));
+         }
+       else
+         {
+          var segment = new OpenLayers.Geometry.LineString([nodepoint,point]);
+
+          features.push(new OpenLayers.Feature.Vector(segment,{dump: dump},segment_style));
+
+          var dlat = lonlat.lat-nodelonlat.lat;
+          var dlon = lonlat.lon-nodelonlat.lon;
+          var dist = Math.sqrt(dlat*dlat+dlon*dlon)/120;
+
+          point = new OpenLayers.Geometry.Point(nodelonlat.lon+dlon/dist,nodelonlat.lat+dlat/dist);
+
+          features.push(new OpenLayers.Feature.Vector(point,{dump: dump},
+                                                      new OpenLayers.Style({},{externalGraphic: "icons/limit-" + number + ".png",
+                                                                               graphicYOffset: -9,
+                                                                               graphicWidth: 19,
+                                                                               graphicHeight: 19})));
+         }
+      }
+   }
+
+ select.activate();
+
+ layerVectors.addFeatures(features);
+
+ displayStatus("data","limit",lines.length-2);
+}
+
+
+//
+// Success in getting the property data
+//
+
+function runPropertySuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var style = new OpenLayers.Style({},{fill: false,
+                                      strokeWidth: 2,strokeColor: "#FF0000",
+                                      cursor: "pointer"});
+
+ var features=[];
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,epsg900913);
+
+       box = new OpenLayers.Marker.Box(bounds);
+
+       layerBoxes.addMarker(box);
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat1=words[1];
+       var lon1=words[2];
+       var lat2=words[3];
+       var lon2=words[4];
+
+       var lonlat1= new OpenLayers.LonLat(lon1,lat1).transform(epsg4326,epsg900913);
+       var lonlat2= new OpenLayers.LonLat(lon2,lat2).transform(epsg4326,epsg900913);
+
+       var point1 = new OpenLayers.Geometry.Point(lonlat1.lon,lonlat1.lat);
+       var point2 = new OpenLayers.Geometry.Point(lonlat2.lon,lonlat2.lat);
+
+       var segment = new OpenLayers.Geometry.LineString([point1,point2]);
+
+       features.push(new OpenLayers.Feature.Vector(segment,{dump: dump},style));
+      }
+   }
+
+ select.activate();
+
+ layerVectors.addFeatures(features);
+
+ displayStatus("data","property",lines.length-2);
+}
+
+
+//
+// Success in getting the error log data
+//
+
+function runErrorlogSuccess(response)
+{
+ var lines=response.responseText.split("\n");
+
+ var style = new OpenLayers.Style({},{stroke: false,
+                                      pointRadius: 3,fillColor: "#FF0000",
+                                      cursor: "pointer"});
+
+ var features=[];
+
+ for(var line=0;line<lines.length;line++)
+   {
+    var words=lines[line].split(" ");
+
+    if(line === 0)
+      {
+       var lat1=words[0];
+       var lon1=words[1];
+       var lat2=words[2];
+       var lon2=words[3];
+
+       var bounds = new OpenLayers.Bounds(lon1,lat1,lon2,lat2).transform(epsg4326,epsg900913);
+
+       box = new OpenLayers.Marker.Box(bounds);
+
+       layerBoxes.addMarker(box);
+      }
+    else if(words[0] !== "")
+      {
+       var dump=words[0];
+       var lat=words[1];
+       var lon=words[2];
+
+       var lonlat = new OpenLayers.LonLat(lon,lat).transform(epsg4326,epsg900913);
+
+       var point = new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);
+
+       features.push(new OpenLayers.Feature.Vector(point,{dump: dump},style));
+      }
+   }
+
+ select.activate();
+
+ layerVectors.addFeatures(features);
+
+ displayStatus("data","errorlogs",lines.length-2);
+}
+
+
+//
+// Failure in getting data.
+//
+
+function runFailure(response)
+{
+ displayStatus("failed");
+}
diff --git a/3rdparty/Routino/xml/Makefile b/3rdparty/Routino/xml/Makefile
new file mode 100644
index 0000000..0e1d324
--- /dev/null
+++ b/3rdparty/Routino/xml/Makefile
@@ -0,0 +1,79 @@
+# XML directory Makefile
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2010-2015 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# All configuration is in the top-level Makefile.conf
+
+include ../Makefile.conf
+
+# Files to install
+
+STANDARD_FILES=profiles.xml \
+               translations.xml \
+               tagging.xml
+
+SPECIAL_FILES=tagging-drive.xml \
+	      tagging-ride.xml \
+              tagging-walk.xml
+
+########
+
+all: $(SPECIAL_FILES)
+
+####
+
+tagging-drive.xml : routino-tagging.xml scripts/drive.pl
+	perl scripts/drive.pl < routino-tagging.xml > tagging-drive.xml
+
+tagging-ride.xml : routino-tagging.xml scripts/ride.pl
+	perl scripts/ride.pl < routino-tagging.xml > tagging-ride.xml
+
+tagging-walk.xml : routino-tagging.xml scripts/walk.pl
+	perl scripts/walk.pl < routino-tagging.xml > tagging-walk.xml
+
+########
+
+test:
+
+########
+
+install: all
+	@[ -d $(DESTDIR)$(datadir) ] || mkdir -p $(DESTDIR)$(datadir)
+	@for file in $(STANDARD_FILES) ; do \
+	    echo cp routino-$$file $(DESTDIR)$(datadir)/$$file ;\
+	    cp -f routino-$$file $(DESTDIR)$(datadir)/$$file ;\
+	 done
+	@for file in $(SPECIAL_FILES); do \
+	    echo cp $$file $(DESTDIR)$(datadir)/$$file ;\
+	    cp -f $$file $(DESTDIR)$(datadir)/$$file ;\
+	 done
+
+########
+
+clean:
+	rm -f *~
+	rm -f $(SPECIAL_FILES)
+
+########
+
+distclean: clean
+
+########
+
+.PHONY:: all test install clean distclean
diff --git a/3rdparty/Routino/xml/osc.xsd b/3rdparty/Routino/xml/osc.xsd
new file mode 100644
index 0000000..de032b3
--- /dev/null
+++ b/3rdparty/Routino/xml/osc.xsd
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- ============================================================
+     An XML Schema Definition for the OSC (OsmChange) XML format
+
+     Created by reverse engineering an OSC file from the planet replication diffs;
+     not used in Routino but in a proof-of-concept parser created by xsd-to-xmlparser.
+     ============================================================
+     This file Copyright 2010-2012 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+  <!-- The top level osmChange element -->
+
+  <xsd:element name="osmChange" type="osmChangeType"/>
+
+  <xsd:complexType name="osmChangeType">
+    <xsd:sequence>
+      <xsd:element name="bounds"    type="boundsType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="modify"    type="modifyType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="create"    type="createType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="delete"    type="deleteType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="version"   type="xsd:string"/>
+    <xsd:attribute name="generator" type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The second level bounds, modify, create and delete elements -->
+
+  <xsd:complexType name="boundsType">
+    <xsd:attribute name="minlat"    type="xsd:string"/>
+    <xsd:attribute name="minlon"    type="xsd:string"/>
+    <xsd:attribute name="maxlat"    type="xsd:string"/>
+    <xsd:attribute name="maxlon"    type="xsd:string"/>
+    <xsd:attribute name="origin"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="modifyType">
+    <xsd:sequence>
+      <xsd:element name="node"     type="nodeType"     minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="way"      type="wayType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="relation" type="relationType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="createType">
+    <xsd:sequence>
+      <xsd:element name="node"     type="nodeType"     minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="way"      type="wayType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="relation" type="relationType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="deleteType">
+    <xsd:sequence>
+      <xsd:element name="node"     type="nodeType"     minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="way"      type="wayType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="relation" type="relationType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <!-- The third level node, way and relation elements -->
+
+  <xsd:complexType name="nodeType">
+    <xsd:sequence>
+      <xsd:element name="tag"       type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id"        type="xsd:string"/>
+    <xsd:attribute name="lat"       type="xsd:string"/>
+    <xsd:attribute name="lon"       type="xsd:string"/>
+    <xsd:attribute name="timestamp" type="xsd:string"/>
+    <xsd:attribute name="uid"       type="xsd:string"/>
+    <xsd:attribute name="user"      type="xsd:string"/>
+    <xsd:attribute name="visible"   type="xsd:string"/>
+    <xsd:attribute name="version"   type="xsd:string"/>
+    <xsd:attribute name="changeset" type="xsd:string"/>
+    <xsd:attribute name="action"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="wayType">
+    <xsd:sequence>
+      <xsd:element name="nd"        type="ndType"  minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="tag"       type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id"        type="xsd:string"/>
+    <xsd:attribute name="timestamp" type="xsd:string"/>
+    <xsd:attribute name="uid"       type="xsd:string"/>
+    <xsd:attribute name="user"      type="xsd:string"/>
+    <xsd:attribute name="visible"   type="xsd:string"/>
+    <xsd:attribute name="version"   type="xsd:string"/>
+    <xsd:attribute name="changeset" type="xsd:string"/>
+    <xsd:attribute name="action"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="relationType">
+    <xsd:sequence>
+      <xsd:element name="member"    type="memberType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="tag"       type="tagType"    minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id"        type="xsd:string"/>
+    <xsd:attribute name="timestamp" type="xsd:string"/>
+    <xsd:attribute name="uid"       type="xsd:string"/>
+    <xsd:attribute name="user"      type="xsd:string"/>
+    <xsd:attribute name="visible"   type="xsd:string"/>
+    <xsd:attribute name="version"   type="xsd:string"/>
+    <xsd:attribute name="changeset" type="xsd:string"/>
+    <xsd:attribute name="action"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The fourth level elements and their contents -->
+
+  <xsd:complexType name="tagType">
+    <xsd:attribute name="k"         type="xsd:string"/>
+    <xsd:attribute name="v"         type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="ndType">
+    <xsd:attribute name="ref"       type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="memberType">
+    <xsd:attribute name="type"      type="xsd:string"/>
+    <xsd:attribute name="ref"       type="xsd:string"/>
+    <xsd:attribute name="role"      type="xsd:string"/>
+  </xsd:complexType>
+
+</xsd:schema>
diff --git a/3rdparty/Routino/xml/osm.xsd b/3rdparty/Routino/xml/osm.xsd
new file mode 100644
index 0000000..a92f5ba
--- /dev/null
+++ b/3rdparty/Routino/xml/osm.xsd
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- ============================================================
+     An XML Schema Definition for the OSM XML format (including JOSM
+     specific additions such as 'bounds' tag and 'action' attribute).
+
+     Created by reverse engineering a JOSM saved file; not used in Routino
+     but in a proof-of-concept parser created by xsd-to-xmlparser.
+     ============================================================
+     This file Copyright 2010-2012 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+  <!-- The top level osm element -->
+
+  <xsd:element name="osm" type="osmType"/>
+
+  <xsd:complexType name="osmType">
+    <xsd:sequence>
+      <xsd:element name="bounds"    type="boundsType"    minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="bound"     type="boundType"     minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="changeset" type="changesetType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="node"      type="nodeType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="way"       type="wayType"       minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="relation"  type="relationType"  minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="version"   type="xsd:string"/>
+    <xsd:attribute name="generator" type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The second level bounds, bound, changeset, node, way and relation elements -->
+
+  <xsd:complexType name="boundsType">
+    <xsd:attribute name="minlat"    type="xsd:string"/>
+    <xsd:attribute name="minlon"    type="xsd:string"/>
+    <xsd:attribute name="maxlat"    type="xsd:string"/>
+    <xsd:attribute name="maxlon"    type="xsd:string"/>
+    <xsd:attribute name="origin"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="boundType">
+    <xsd:attribute name="box"       type="xsd:string"/>
+    <xsd:attribute name="origin"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="changesetType">
+    <xsd:sequence>
+      <xsd:element name="tag"        type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id"         type="xsd:string"/>
+    <xsd:attribute name="min_lat"    type="xsd:string"/>
+    <xsd:attribute name="min_lon"    type="xsd:string"/>
+    <xsd:attribute name="max_lat"    type="xsd:string"/>
+    <xsd:attribute name="max_lon"    type="xsd:string"/>
+    <xsd:attribute name="created_at" type="xsd:string"/>
+    <xsd:attribute name="closed_at"  type="xsd:string"/>
+    <xsd:attribute name="open"       type="xsd:string"/>
+    <xsd:attribute name="uid"        type="xsd:string"/>
+    <xsd:attribute name="user"       type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="nodeType">
+    <xsd:sequence>
+      <xsd:element name="tag"       type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id"        type="xsd:string"/>
+    <xsd:attribute name="lat"       type="xsd:string"/>
+    <xsd:attribute name="lon"       type="xsd:string"/>
+    <xsd:attribute name="timestamp" type="xsd:string"/>
+    <xsd:attribute name="uid"       type="xsd:string"/>
+    <xsd:attribute name="user"      type="xsd:string"/>
+    <xsd:attribute name="visible"   type="xsd:string"/>
+    <xsd:attribute name="version"   type="xsd:string"/>
+    <xsd:attribute name="changeset" type="xsd:string"/>
+    <xsd:attribute name="action"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="wayType">
+    <xsd:sequence>
+      <xsd:element name="nd"        type="ndType"  minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="tag"       type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id"        type="xsd:string"/>
+    <xsd:attribute name="timestamp" type="xsd:string"/>
+    <xsd:attribute name="uid"       type="xsd:string"/>
+    <xsd:attribute name="user"      type="xsd:string"/>
+    <xsd:attribute name="visible"   type="xsd:string"/>
+    <xsd:attribute name="version"   type="xsd:string"/>
+    <xsd:attribute name="changeset" type="xsd:string"/>
+    <xsd:attribute name="action"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="relationType">
+    <xsd:sequence>
+      <xsd:element name="member"    type="memberType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="tag"       type="tagType"    minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id"        type="xsd:string"/>
+    <xsd:attribute name="timestamp" type="xsd:string"/>
+    <xsd:attribute name="uid"       type="xsd:string"/>
+    <xsd:attribute name="user"      type="xsd:string"/>
+    <xsd:attribute name="visible"   type="xsd:string"/>
+    <xsd:attribute name="version"   type="xsd:string"/>
+    <xsd:attribute name="changeset" type="xsd:string"/>
+    <xsd:attribute name="action"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The third level elements and their contents -->
+
+  <xsd:complexType name="tagType">
+    <xsd:attribute name="k"         type="xsd:string"/>
+    <xsd:attribute name="v"         type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="ndType">
+    <xsd:attribute name="ref"       type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="memberType">
+    <xsd:attribute name="type"      type="xsd:string"/>
+    <xsd:attribute name="ref"       type="xsd:string"/>
+    <xsd:attribute name="role"      type="xsd:string"/>
+  </xsd:complexType>
+
+</xsd:schema>
diff --git a/3rdparty/Routino/xml/routino-osc.xsd b/3rdparty/Routino/xml/routino-osc.xsd
new file mode 100644
index 0000000..9c5f285
--- /dev/null
+++ b/3rdparty/Routino/xml/routino-osc.xsd
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- ============================================================
+     An XML Schema Definition for the part of the OSC XML format read by Routino.
+
+     Part of the Routino routing software (semi-automatically converted to create osmparse.c).
+     ============================================================
+     This file Copyright 2010-2012 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+  <!-- The top level osmChange element -->
+
+  <xsd:element name="osmChange" type="osmChangeType"/>
+
+  <xsd:complexType name="osmChangeType">
+    <xsd:sequence>
+      <xsd:element name="bounds"    type="boundsType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="modify"    type="modifyType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="create"    type="createType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="delete"    type="deleteType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="version"   type="xsd:string"/>
+    <!--
+    <xsd:attribute name="generator" type="xsd:string"/>
+    -->
+  </xsd:complexType>
+
+  <!-- The second level bounds, modify, create and delete elements -->
+
+  <xsd:complexType name="boundsType">
+    <!--
+    <xsd:attribute name="minlat"    type="xsd:string"/>
+    <xsd:attribute name="minlon"    type="xsd:string"/>
+    <xsd:attribute name="maxlat"    type="xsd:string"/>
+    <xsd:attribute name="maxlon"    type="xsd:string"/>
+    <xsd:attribute name="origin"    type="xsd:string"/>
+    -->
+  </xsd:complexType>
+
+  <xsd:complexType name="modifyType">
+    <xsd:sequence>
+      <xsd:element name="node"     type="nodeType"     minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="way"      type="wayType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="relation" type="relationType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="createType">
+    <xsd:sequence>
+      <xsd:element name="node"     type="nodeType"     minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="way"      type="wayType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="relation" type="relationType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="deleteType">
+    <xsd:sequence>
+      <xsd:element name="node"     type="nodeType"     minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="way"      type="wayType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="relation" type="relationType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <!-- The third level node, way and relation elements -->
+
+  <xsd:complexType name="nodeType">
+    <xsd:sequence>
+      <xsd:element name="tag"       type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id"        type="xsd:string"/>
+    <xsd:attribute name="lat"       type="xsd:string"/>
+    <xsd:attribute name="lon"       type="xsd:string"/>
+    <!--
+    <xsd:attribute name="timestamp" type="xsd:string"/>
+    <xsd:attribute name="uid"       type="xsd:string"/>
+    <xsd:attribute name="user"      type="xsd:string"/>
+    <xsd:attribute name="visible"   type="xsd:string"/>
+    <xsd:attribute name="version"   type="xsd:string"/>
+    <xsd:attribute name="changeset" type="xsd:string"/>
+    <xsd:attribute name="action"    type="xsd:string"/>
+    -->
+  </xsd:complexType>
+
+  <xsd:complexType name="wayType">
+    <xsd:sequence>
+      <xsd:element name="nd"        type="ndType"  minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="tag"       type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id"        type="xsd:string"/>
+    <!--
+    <xsd:attribute name="timestamp" type="xsd:string"/>
+    <xsd:attribute name="uid"       type="xsd:string"/>
+    <xsd:attribute name="user"      type="xsd:string"/>
+    <xsd:attribute name="visible"   type="xsd:string"/>
+    <xsd:attribute name="version"   type="xsd:string"/>
+    <xsd:attribute name="changeset" type="xsd:string"/>
+    <xsd:attribute name="action"    type="xsd:string"/>
+    -->
+  </xsd:complexType>
+
+  <xsd:complexType name="relationType">
+    <xsd:sequence>
+      <xsd:element name="member"    type="memberType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="tag"       type="tagType"    minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id"        type="xsd:string"/>
+    <!--
+    <xsd:attribute name="timestamp" type="xsd:string"/>
+    <xsd:attribute name="uid"       type="xsd:string"/>
+    <xsd:attribute name="user"      type="xsd:string"/>
+    <xsd:attribute name="visible"   type="xsd:string"/>
+    <xsd:attribute name="version"   type="xsd:string"/>
+    <xsd:attribute name="changeset" type="xsd:string"/>
+    <xsd:attribute name="action"    type="xsd:string"/>
+    -->
+  </xsd:complexType>
+
+  <!-- The fourth level elements and their contents -->
+
+  <xsd:complexType name="tagType">
+    <xsd:attribute name="k"         type="xsd:string"/>
+    <xsd:attribute name="v"         type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="ndType">
+    <xsd:attribute name="ref"       type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="memberType">
+    <xsd:attribute name="type"      type="xsd:string"/>
+    <xsd:attribute name="ref"       type="xsd:string"/>
+    <xsd:attribute name="role"      type="xsd:string"/>
+  </xsd:complexType>
+
+</xsd:schema>
diff --git a/3rdparty/Routino/xml/routino-osm.xsd b/3rdparty/Routino/xml/routino-osm.xsd
new file mode 100644
index 0000000..ca43c4a
--- /dev/null
+++ b/3rdparty/Routino/xml/routino-osm.xsd
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- ============================================================
+     An XML Schema Definition for the part of the OSM XML format read by Routino.
+
+     Part of the Routino routing software (semi-automatically converted to create osmparse.c).
+     ============================================================
+     This file Copyright 2010-2012 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+  <!-- The top level osm element -->
+
+  <xsd:element name="osm" type="osmType"/>
+
+  <xsd:complexType name="osmType">
+    <xsd:sequence>
+      <xsd:element name="bounds"    type="boundsType"    minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="bound"     type="boundType"     minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="changeset" type="changesetType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="node"      type="nodeType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="way"       type="wayType"       minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="relation"  type="relationType"  minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="version"   type="xsd:string"/>
+    <!--
+    <xsd:attribute name="generator" type="xsd:string"/>
+    -->
+  </xsd:complexType>
+
+  <!-- The second level bounds, bound, changeset, node, way and relation elements -->
+
+  <xsd:complexType name="boundsType">
+    <!--
+    <xsd:attribute name="minlat"    type="xsd:string"/>
+    <xsd:attribute name="minlon"    type="xsd:string"/>
+    <xsd:attribute name="maxlat"    type="xsd:string"/>
+    <xsd:attribute name="maxlon"    type="xsd:string"/>
+    <xsd:attribute name="origin"    type="xsd:string"/>
+    -->
+  </xsd:complexType>
+
+  <xsd:complexType name="boundType">
+    <!--
+    <xsd:attribute name="box"       type="xsd:string"/>
+    <xsd:attribute name="origin"    type="xsd:string"/>
+    -->
+  </xsd:complexType>
+
+  <xsd:complexType name="changesetType">
+    <xsd:sequence>
+      <xsd:element name="tag"        type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <!--
+    <xsd:attribute name="id"         type="xsd:string"/>
+    <xsd:attribute name="min_lat"    type="xsd:string"/>
+    <xsd:attribute name="min_lon"    type="xsd:string"/>
+    <xsd:attribute name="max_lat"    type="xsd:string"/>
+    <xsd:attribute name="max_lon"    type="xsd:string"/>
+    <xsd:attribute name="created_at" type="xsd:string"/>
+    <xsd:attribute name="closed_at"  type="xsd:string"/>
+    <xsd:attribute name="open"       type="xsd:string"/>
+    <xsd:attribute name="uid"        type="xsd:string"/>
+    <xsd:attribute name="user"       type="xsd:string"/>
+    -->
+  </xsd:complexType>
+
+  <xsd:complexType name="nodeType">
+    <xsd:sequence>
+      <xsd:element name="tag"       type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id"        type="xsd:string"/>
+    <xsd:attribute name="lat"       type="xsd:string"/>
+    <xsd:attribute name="lon"       type="xsd:string"/>
+    <!--
+    <xsd:attribute name="timestamp" type="xsd:string"/>
+    <xsd:attribute name="uid"       type="xsd:string"/>
+    <xsd:attribute name="user"      type="xsd:string"/>
+    <xsd:attribute name="visible"   type="xsd:string"/>
+    <xsd:attribute name="version"   type="xsd:string"/>
+    <xsd:attribute name="changeset" type="xsd:string"/>
+    <xsd:attribute name="action"    type="xsd:string"/>
+    -->
+  </xsd:complexType>
+
+  <xsd:complexType name="wayType">
+    <xsd:sequence>
+      <xsd:element name="nd"        type="ndType"  minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="tag"       type="tagType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id"        type="xsd:string"/>
+    <!--
+    <xsd:attribute name="timestamp" type="xsd:string"/>
+    <xsd:attribute name="uid"       type="xsd:string"/>
+    <xsd:attribute name="user"      type="xsd:string"/>
+    <xsd:attribute name="visible"   type="xsd:string"/>
+    <xsd:attribute name="version"   type="xsd:string"/>
+    <xsd:attribute name="changeset" type="xsd:string"/>
+    <xsd:attribute name="action"    type="xsd:string"/>
+    -->
+  </xsd:complexType>
+
+  <xsd:complexType name="relationType">
+    <xsd:sequence>
+      <xsd:element name="member"    type="memberType" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="tag"       type="tagType"    minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id"        type="xsd:string"/>
+    <!--
+    <xsd:attribute name="timestamp" type="xsd:string"/>
+    <xsd:attribute name="uid"       type="xsd:string"/>
+    <xsd:attribute name="user"      type="xsd:string"/>
+    <xsd:attribute name="visible"   type="xsd:string"/>
+    <xsd:attribute name="version"   type="xsd:string"/>
+    <xsd:attribute name="changeset" type="xsd:string"/>
+    <xsd:attribute name="action"    type="xsd:string"/>
+    -->
+  </xsd:complexType>
+
+  <!-- The third level elements and their contents -->
+
+  <xsd:complexType name="tagType">
+    <xsd:attribute name="k"         type="xsd:string"/>
+    <xsd:attribute name="v"         type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="ndType">
+    <xsd:attribute name="ref"       type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="memberType">
+    <xsd:attribute name="type"      type="xsd:string"/>
+    <xsd:attribute name="ref"       type="xsd:string"/>
+    <xsd:attribute name="role"      type="xsd:string"/>
+  </xsd:complexType>
+
+</xsd:schema>
diff --git a/3rdparty/Routino/xml/routino-profiles.xml b/3rdparty/Routino/xml/routino-profiles.xml
new file mode 100644
index 0000000..40c0aad
--- /dev/null
+++ b/3rdparty/Routino/xml/routino-profiles.xml
@@ -0,0 +1,509 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!-- ============================================================
+     An XML format file containing Routino routing profiles
+
+     Part of the Routino routing software.
+     ============================================================
+     This file Copyright 2010-2014 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<routino-profiles xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                  xsi:noNamespaceSchemaLocation="http://www.routino.org/xml/routino-profiles.xsd">
+
+  <profile name="foot" transport="foot">
+    <speeds>
+      <speed highway="motorway"      kph="0" />
+      <speed highway="trunk"         kph="4" />
+      <speed highway="primary"       kph="4" />
+      <speed highway="secondary"     kph="4" />
+      <speed highway="tertiary"      kph="4" />
+      <speed highway="unclassified"  kph="4" />
+      <speed highway="residential"   kph="4" />
+      <speed highway="service"       kph="4" />
+      <speed highway="track"         kph="4" />
+      <speed highway="cycleway"      kph="4" />
+      <speed highway="path"          kph="4" />
+      <speed highway="steps"         kph="4" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="0" />
+      <preference highway="trunk"         percent="40" />
+      <preference highway="primary"       percent="50" />
+      <preference highway="secondary"     percent="60" />
+      <preference highway="tertiary"      percent="70" />
+      <preference highway="unclassified"  percent="80" />
+      <preference highway="residential"   percent="90" />
+      <preference highway="service"       percent="90" />
+      <preference highway="track"         percent="95" />
+      <preference highway="cycleway"      percent="95" />
+      <preference highway="path"          percent="100" />
+      <preference highway="steps"         percent="80" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="50" />
+      <property type="multilane"     percent="25" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="55" />
+      <property type="bicycleroute"  percent="55" />
+    </properties>
+    <restrictions>
+      <oneway obey="0" /> 
+      <turns  obey="0" /> 
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="horse" transport="horse">
+    <speeds>
+      <speed highway="motorway"      kph="0" />
+      <speed highway="trunk"         kph="8" />
+      <speed highway="primary"       kph="8" />
+      <speed highway="secondary"     kph="8" />
+      <speed highway="tertiary"      kph="8" />
+      <speed highway="unclassified"  kph="8" />
+      <speed highway="residential"   kph="8" />
+      <speed highway="service"       kph="8" />
+      <speed highway="track"         kph="8" />
+      <speed highway="cycleway"      kph="8" />
+      <speed highway="path"          kph="8" />
+      <speed highway="steps"         kph="0" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="0" />
+      <preference highway="trunk"         percent="25" />
+      <preference highway="primary"       percent="50" />
+      <preference highway="secondary"     percent="50" />
+      <preference highway="tertiary"      percent="75" />
+      <preference highway="unclassified"  percent="75" />
+      <preference highway="residential"   percent="75" />
+      <preference highway="service"       percent="75" />
+      <preference highway="track"         percent="100" />
+      <preference highway="cycleway"      percent="90" />
+      <preference highway="path"          percent="100" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="20" />
+      <property type="multilane"     percent="25" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="50" />
+      <property type="bicycleroute"  percent="50" />
+    </properties>
+    <restrictions>
+      <oneway obey="1" /> 
+      <turns  obey="1" /> 
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="wheelchair" transport="wheelchair">
+    <speeds>
+      <speed highway="motorway"      kph="0" />
+      <speed highway="trunk"         kph="4" />
+      <speed highway="primary"       kph="4" />
+      <speed highway="secondary"     kph="4" />
+      <speed highway="tertiary"      kph="4" />
+      <speed highway="unclassified"  kph="4" />
+      <speed highway="residential"   kph="4" />
+      <speed highway="service"       kph="4" />
+      <speed highway="track"         kph="4" />
+      <speed highway="cycleway"      kph="4" />
+      <speed highway="path"          kph="4" />
+      <speed highway="steps"         kph="4" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="0" />
+      <preference highway="trunk"         percent="40" />
+      <preference highway="primary"       percent="50" />
+      <preference highway="secondary"     percent="60" />
+      <preference highway="tertiary"      percent="70" />
+      <preference highway="unclassified"  percent="80" />
+      <preference highway="residential"   percent="90" />
+      <preference highway="service"       percent="90" />
+      <preference highway="track"         percent="95" />
+      <preference highway="cycleway"      percent="95" />
+      <preference highway="path"          percent="100" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="90" />
+      <property type="multilane"     percent="25" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="55" />
+      <property type="bicycleroute"  percent="55" />
+    </properties>
+    <restrictions>
+      <oneway obey="0" /> 
+      <turns  obey="0" /> 
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="bicycle" transport="bicycle">
+    <speeds>
+      <speed highway="motorway"      kph="0" />
+      <speed highway="trunk"         kph="20" />
+      <speed highway="primary"       kph="20" />
+      <speed highway="secondary"     kph="20" />
+      <speed highway="tertiary"      kph="20" />
+      <speed highway="unclassified"  kph="20" />
+      <speed highway="residential"   kph="20" />
+      <speed highway="service"       kph="20" />
+      <speed highway="track"         kph="20" />
+      <speed highway="cycleway"      kph="20" />
+      <speed highway="path"          kph="20" />
+      <speed highway="steps"         kph="0" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="0" />
+      <preference highway="trunk"         percent="30" />
+      <preference highway="primary"       percent="70" />
+      <preference highway="secondary"     percent="80" />
+      <preference highway="tertiary"      percent="90" />
+      <preference highway="unclassified"  percent="90" />
+      <preference highway="residential"   percent="90" />
+      <preference highway="service"       percent="90" />
+      <preference highway="track"         percent="90" />
+      <preference highway="cycleway"      percent="100" />
+      <preference highway="path"          percent="90" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="50" />
+      <property type="multilane"     percent="25" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="50" />
+      <property type="bicycleroute"  percent="60" />
+    </properties>
+    <restrictions>
+      <oneway obey="1" /> 
+      <turns  obey="1" /> 
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="moped" transport="moped">
+    <speeds>
+      <speed highway="motorway"      kph="48" />
+      <speed highway="trunk"         kph="48" />
+      <speed highway="primary"       kph="48" />
+      <speed highway="secondary"     kph="48" />
+      <speed highway="tertiary"      kph="48" />
+      <speed highway="unclassified"  kph="48" />
+      <speed highway="residential"   kph="48" />
+      <speed highway="service"       kph="32" />
+      <speed highway="track"         kph="16" />
+      <speed highway="cycleway"      kph="0" />
+      <speed highway="path"          kph="0" />
+      <speed highway="steps"         kph="0" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="0" />
+      <preference highway="trunk"         percent="90" />
+      <preference highway="primary"       percent="100" />
+      <preference highway="secondary"     percent="90" />
+      <preference highway="tertiary"      percent="80" />
+      <preference highway="unclassified"  percent="70" />
+      <preference highway="residential"   percent="60" />
+      <preference highway="service"       percent="80" />
+      <preference highway="track"         percent="0" />
+      <preference highway="cycleway"      percent="0" />
+      <preference highway="path"          percent="0" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="100" />
+      <property type="multilane"     percent="35" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="50" />
+      <property type="bicycleroute"  percent="50" />
+    </properties>
+    <restrictions>
+      <oneway obey="1" /> 
+      <turns  obey="1" /> 
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="motorcycle" transport="motorcycle">
+    <speeds>
+      <speed highway="motorway"      kph="112" />
+      <speed highway="trunk"         kph="96" />
+      <speed highway="primary"       kph="96" />
+      <speed highway="secondary"     kph="88" />
+      <speed highway="tertiary"      kph="80" />
+      <speed highway="unclassified"  kph="64" />
+      <speed highway="residential"   kph="48" />
+      <speed highway="service"       kph="32" />
+      <speed highway="track"         kph="16" />
+      <speed highway="cycleway"      kph="0" />
+      <speed highway="path"          kph="0" />
+      <speed highway="steps"         kph="0" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="100" />
+      <preference highway="trunk"         percent="100" />
+      <preference highway="primary"       percent="90" />
+      <preference highway="secondary"     percent="80" />
+      <preference highway="tertiary"      percent="70" />
+      <preference highway="unclassified"  percent="60" />
+      <preference highway="residential"   percent="50" />
+      <preference highway="service"       percent="80" />
+      <preference highway="track"         percent="0" />
+      <preference highway="cycleway"      percent="0" />
+      <preference highway="path"          percent="0" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="100" />
+      <property type="multilane"     percent="60" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="50" />
+      <property type="bicycleroute"  percent="50" />
+    </properties>
+    <restrictions>
+      <oneway obey="1" /> 
+      <turns  obey="1" /> 
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="motorcar" transport="motorcar">
+    <speeds>
+      <speed highway="motorway"      kph="112" />
+      <speed highway="trunk"         kph="96" />
+      <speed highway="primary"       kph="96" />
+      <speed highway="secondary"     kph="88" />
+      <speed highway="tertiary"      kph="80" />
+      <speed highway="unclassified"  kph="64" />
+      <speed highway="residential"   kph="48" />
+      <speed highway="service"       kph="32" />
+      <speed highway="track"         kph="16" />
+      <speed highway="cycleway"      kph="0" />
+      <speed highway="path"          kph="0" />
+      <speed highway="steps"         kph="0" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="100" />
+      <preference highway="trunk"         percent="100" />
+      <preference highway="primary"       percent="90" />
+      <preference highway="secondary"     percent="80" />
+      <preference highway="tertiary"      percent="70" />
+      <preference highway="unclassified"  percent="60" />
+      <preference highway="residential"   percent="50" />
+      <preference highway="service"       percent="80" />
+      <preference highway="track"         percent="0" />
+      <preference highway="cycleway"      percent="0" />
+      <preference highway="path"          percent="0" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="100" />
+      <property type="multilane"     percent="60" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="45" />
+      <property type="bicycleroute"  percent="45" />
+    </properties>
+    <restrictions>
+      <oneway obey="1" /> 
+      <turns  obey="1" /> 
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="goods" transport="goods">
+    <speeds>
+      <speed highway="motorway"      kph="96" />
+      <speed highway="trunk"         kph="96" />
+      <speed highway="primary"       kph="96" />
+      <speed highway="secondary"     kph="88" />
+      <speed highway="tertiary"      kph="80" />
+      <speed highway="unclassified"  kph="64" />
+      <speed highway="residential"   kph="48" />
+      <speed highway="service"       kph="32" />
+      <speed highway="track"         kph="16" />
+      <speed highway="cycleway"      kph="0" />
+      <speed highway="path"          kph="0" />
+      <speed highway="steps"         kph="0" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="100" />
+      <preference highway="trunk"         percent="100" />
+      <preference highway="primary"       percent="90" />
+      <preference highway="secondary"     percent="80" />
+      <preference highway="tertiary"      percent="70" />
+      <preference highway="unclassified"  percent="60" />
+      <preference highway="residential"   percent="50" />
+      <preference highway="service"       percent="80" />
+      <preference highway="track"         percent="0" />
+      <preference highway="cycleway"      percent="0" />
+      <preference highway="path"          percent="0" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="100" />
+      <property type="multilane"     percent="60" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="45" />
+      <property type="bicycleroute"  percent="45" />
+    </properties>
+    <restrictions>
+      <oneway obey="1" /> 
+      <turns  obey="1" /> 
+      <weight limit="5.0" />
+      <height limit="2.5" />
+      <width  limit="2.0" />
+      <length limit="5.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="hgv" transport="hgv">
+    <speeds>
+      <speed highway="motorway"      kph="89" />
+      <speed highway="trunk"         kph="80" />
+      <speed highway="primary"       kph="80" />
+      <speed highway="secondary"     kph="80" />
+      <speed highway="tertiary"      kph="80" />
+      <speed highway="unclassified"  kph="64" />
+      <speed highway="residential"   kph="48" />
+      <speed highway="service"       kph="32" />
+      <speed highway="track"         kph="16" />
+      <speed highway="cycleway"      kph="0" />
+      <speed highway="path"          kph="0" />
+      <speed highway="steps"         kph="0" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="100" />
+      <preference highway="trunk"         percent="100" />
+      <preference highway="primary"       percent="90" />
+      <preference highway="secondary"     percent="80" />
+      <preference highway="tertiary"      percent="70" />
+      <preference highway="unclassified"  percent="60" />
+      <preference highway="residential"   percent="50" />
+      <preference highway="service"       percent="80" />
+      <preference highway="track"         percent="0" />
+      <preference highway="cycleway"      percent="0" />
+      <preference highway="path"          percent="0" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="100" />
+      <property type="multilane"     percent="60" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="45" />
+      <property type="bicycleroute"  percent="45" />
+    </properties>
+    <restrictions>
+      <oneway obey="1" /> 
+      <turns  obey="1" /> 
+      <weight limit="10.0" />
+      <height limit="3.0" />
+      <width  limit="2.5" />
+      <length limit="6.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="psv" transport="psv">
+    <speeds>
+      <speed highway="motorway"      kph="89" />
+      <speed highway="trunk"         kph="80" />
+      <speed highway="primary"       kph="80" />
+      <speed highway="secondary"     kph="80" />
+      <speed highway="tertiary"      kph="80" />
+      <speed highway="unclassified"  kph="64" />
+      <speed highway="residential"   kph="48" />
+      <speed highway="service"       kph="32" />
+      <speed highway="track"         kph="16" />
+      <speed highway="cycleway"      kph="0" />
+      <speed highway="path"          kph="0" />
+      <speed highway="steps"         kph="0" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="100" />
+      <preference highway="trunk"         percent="100" />
+      <preference highway="primary"       percent="90" />
+      <preference highway="secondary"     percent="80" />
+      <preference highway="tertiary"      percent="70" />
+      <preference highway="unclassified"  percent="60" />
+      <preference highway="residential"   percent="50" />
+      <preference highway="service"       percent="80" />
+      <preference highway="track"         percent="0" />
+      <preference highway="cycleway"      percent="0" />
+      <preference highway="path"          percent="0" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="100" />
+      <property type="multilane"     percent="60" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="45" />
+      <property type="bicycleroute"  percent="45" />
+    </properties>
+    <restrictions>
+      <oneway obey="1" /> 
+      <turns  obey="1" /> 
+      <weight limit="15.0" />
+      <height limit="3.0" />
+      <width  limit="2.5" />
+      <length limit="6.0" />
+    </restrictions>
+  </profile>
+
+</routino-profiles>
diff --git a/3rdparty/Routino/xml/routino-profiles.xsd b/3rdparty/Routino/xml/routino-profiles.xsd
new file mode 100644
index 0000000..6f8de26
--- /dev/null
+++ b/3rdparty/Routino/xml/routino-profiles.xsd
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- ============================================================
+     An XML Schema Definition for the Routino profile XML format
+
+     Part of the Routino routing software.
+     ============================================================
+     This file Copyright 2010-2011 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+  <!-- The top level Routino profiles -->
+
+  <xsd:element name="routino-profiles" type="RoutinoProfilesType"/>
+
+  <xsd:complexType name="RoutinoProfilesType">
+    <xsd:sequence>
+      <xsd:element name="profile" type="profileType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="profileType">
+    <xsd:sequence>
+      <xsd:element name="speeds"       type="speedsType"      />
+      <xsd:element name="preferences"  type="preferencesType" />
+      <xsd:element name="properties"   type="propertiesType"  />
+      <xsd:element name="restrictions" type="restrictionsType"/>
+    </xsd:sequence>
+    <xsd:attribute name="name"         type="xsd:string"/>
+    <xsd:attribute name="transport"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The second level preferences, speed, properties and restrictions -->
+
+  <xsd:complexType name="speedsType">
+    <xsd:sequence>
+      <xsd:element name="speed" type="speedType" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="preferencesType">
+    <xsd:sequence>
+      <xsd:element name="preference" type="preferenceType" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="propertiesType">
+    <xsd:sequence>
+      <xsd:element name="property" type="propertyType" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="restrictionsType">
+    <xsd:sequence>
+      <xsd:element name="oneway" type="onewayType"/>
+      <xsd:element name="turns"  type="turnsType"/>
+      <xsd:element name="weight" type="weightType"/>
+      <xsd:element name="height" type="heightType"/>
+      <xsd:element name="width"  type="widthType"/>
+      <xsd:element name="length" type="lengthType"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <!-- The lowest level elements containing the real information -->
+
+  <xsd:complexType name="speedType">
+    <xsd:attribute name="highway" type="xsd:string"/>
+    <xsd:attribute name="kph"     type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="preferenceType">
+    <xsd:attribute name="highway" type="xsd:string"/>
+    <xsd:attribute name="percent" type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="propertyType">
+    <xsd:attribute name="type"    type="xsd:string"/>
+    <xsd:attribute name="percent" type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="onewayType">
+    <xsd:attribute name="obey"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="turnsType">
+    <xsd:attribute name="obey"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="weightType">
+    <xsd:attribute name="limit"   type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="heightType">
+    <xsd:attribute name="limit"   type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="widthType">
+    <xsd:attribute name="limit"   type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="lengthType">
+    <xsd:attribute name="limit"   type="xsd:string"/>
+  </xsd:complexType>
+
+</xsd:schema>
diff --git a/3rdparty/Routino/xml/routino-tagging-nomodify.xml b/3rdparty/Routino/xml/routino-tagging-nomodify.xml
new file mode 100644
index 0000000..62f3bfe
--- /dev/null
+++ b/3rdparty/Routino/xml/routino-tagging-nomodify.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!-- ============================================================
+     An XML format file containing Routino tagging rules - copy the input file
+     directly to the output with no modifications (e.g. importing a file dumped
+     by filedumper).
+
+     Part of the Routino routing software.
+     ============================================================
+     This file Copyright 2010, 2011 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<routino-tagging xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xsi:noNamespaceSchemaLocation="http://www.routino.org/xml/routino-tagging.xsd">
+
+  <!-- - - - - - - - - - - Node rules - - - - - - - - - - -->
+
+  <node>
+
+    <!-- Copy everything from input to output -->
+
+    <if>
+      <output />
+    </if>
+
+  </node>
+
+  <!-- - - - - - - - - - - Way rules - - - - - - - - - - -->
+
+  <way>
+
+    <!-- Copy everything from input to output -->
+
+    <if>
+      <output />
+    </if>
+
+  </way>
+
+  <!-- - - - - - - - - - - Relation rules - - - - - - - - - - -->
+
+  <relation>
+
+    <!-- Copy everything from input to output -->
+
+    <if>
+      <output />
+    </if>
+
+  </relation>
+
+</routino-tagging>
diff --git a/3rdparty/Routino/xml/routino-tagging.xml b/3rdparty/Routino/xml/routino-tagging.xml
new file mode 100644
index 0000000..e2c4321
--- /dev/null
+++ b/3rdparty/Routino/xml/routino-tagging.xml
@@ -0,0 +1,1025 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!-- ============================================================
+     An XML format file containing Routino tagging rules
+
+     Part of the Routino routing software.
+     ============================================================
+     This file Copyright 2010-2015 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<routino-tagging xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xsi:noNamespaceSchemaLocation="http://www.routino.org/xml/routino-tagging.xsd">
+
+  <!-- - - - - - - - - - - Node rules - - - - - - - - - - -->
+
+  <node>
+
+    <!-- Note: The default is that all transport types are allowed past a barrier;
+               access must be specified to disallow each transport type. -->
+
+    <if k="barrier">
+
+      <!-- Not useful barrier types (too generic) -->
+
+      <if k="barrier" v="gate"      > <unset/> </if>
+      <if k="barrier" v="lift_gate" > <unset/> </if>
+      <if k="barrier" v="block"     > <unset/> </if>
+
+      <!-- Not useful barrier types (generic entrances through barrier ways) -->
+
+      <if k="barrier" v="entrance"  > <unset/> </if>
+      <if k="barrier" v="sally_port"> <unset/> </if>
+      <if k="barrier" v="toll_booth"> <unset/> </if>
+
+      <!-- Barrier types -->
+
+      <if k="barrier" v="kissing_gate">
+        <set v="foot_only"/>
+      </if>
+
+      <if k="barrier" v="footgate">
+        <set v="foot_only"/>
+      </if>
+
+      <if k="barrier" v="stile">
+        <set v="foot_only"/>
+      </if>
+
+      <if k="barrier" v="v_stile">
+        <set v="foot_only"/>
+      </if>
+
+      <if k="barrier" v="turnstile">
+        <set v="foot_only"/>
+      </if>
+
+      <if k="barrier" v="squeeze">
+        <set v="foot_only"/>
+      </if>
+
+      <if k="barrier" v="squeeze_stile">
+        <set v="foot_only"/>
+      </if>
+
+      <if k="barrier" v="foot_only">
+        <output k="horse"      v="no"/>
+        <output k="wheelchair" v="no"/>
+        <output k="bicycle"    v="no"/>
+        <output k="moped"      v="no"/>
+        <output k="motorcycle" v="no"/>
+        <output k="motorcar"   v="no"/>
+        <output k="goods"      v="no"/>
+        <output k="hgv"        v="no"/>
+        <output k="psv"        v="no"/>
+
+        <unset k="barrier"/>
+      </if>
+
+      <if k="barrier" v="horse_stile">
+        <set v="not_wheeled"/>
+      </if>
+
+      <if k="barrier" v="horse_jump">
+        <set v="not_wheeled"/>
+      </if>
+
+      <if k="barrier" v="step_over">
+        <set v="not_wheeled"/>
+      </if>
+
+      <if k="barrier" v="not_wheeled">
+        <output k="wheelchair" v="no"/>
+        <output k="bicycle"    v="no"/>
+        <output k="moped"      v="no"/>
+        <output k="motorcycle" v="no"/>
+        <output k="motorcar"   v="no"/>
+        <output k="goods"      v="no"/>
+        <output k="hgv"        v="no"/>
+        <output k="psv"        v="no"/>
+
+        <unset k="barrier"/>
+      </if>
+
+      <if k="barrier" v="horse_barrier">
+        <set v="no_horse"/>
+      </if>
+
+      <if k="barrier" v="cattle_grid">
+        <set v="no_horse"/>
+      </if>
+
+      <if k="barrier" v="no_horse">
+        <output k="horse"      v="no"/>
+
+        <unset k="barrier"/>
+      </if>
+
+      <if k="barrier" v="motorcycle_barrier">
+        <set v="no_motorised"/>
+      </if>
+
+      <if k="barrier" v="no_motorised">
+        <output k="moped"      v="no"/>
+        <output k="motorcycle" v="no"/>
+        <output k="motorcar"   v="no"/>
+        <output k="goods"      v="no"/>
+        <output k="hgv"        v="no"/>
+        <output k="psv"        v="no"/>
+
+        <unset k="barrier"/>
+      </if>
+
+      <if k="barrier" v="bollard">
+        <set v="not_2plus_wheels"/>
+      </if>
+
+      <if k="barrier" v="car_barrier">
+        <set v="not_2plus_wheels"/>
+      </if>
+
+      <if k="barrier" v="car_trap">
+        <set v="not_2plus_wheels"/>
+      </if>
+
+      <if k="barrier" v="not_2plus_wheels">
+        <output k="motorcar"   v="no"/>
+        <output k="goods"      v="no"/>
+        <output k="hgv"        v="no"/>
+        <output k="psv"        v="no"/>
+
+        <unset k="barrier"/>
+      </if>
+
+      <if k="barrier">
+        <logerror message="ignoring it"/>
+      </if>
+
+    </if> <!-- k="barrier" -->
+
+    <!-- Normalisation of access tags -->
+
+    <if v="designated"  > <set v="yes"/> </if>
+    <if v="permissive"  > <set v="yes"/> </if>
+    <if v="destination" > <set v="yes"/> </if>
+    <if v="true"        > <set v="yes"/> </if>
+    <if v="public"      > <set v="yes"/> </if>
+    <if v="official"    > <set v="yes"/> </if>
+                           
+    <if v="unsuitable"  > <set v="no"/> </if>
+    <if v="private"     > <set v="no"/> </if>
+    <if v="limited"     > <set v="no"/> </if>
+    <if v="restricted"  > <set v="no"/> </if>
+    <if v="agricultural"> <set v="no"/> </if>
+    <if v="forestry"    > <set v="no"/> </if>
+
+    <!-- Generic access permissions for all transport types (to override defaults) -->
+
+    <if k="access">
+
+      <ifnot k="access" v="yes">
+        <output k="foot"       v="no"/>
+        <output k="horse"      v="no"/>
+        <output k="wheelchair" v="no"/>
+        <output k="bicycle"    v="no"/>
+        <output k="moped"      v="no"/>
+        <output k="motorcycle" v="no"/>
+        <output k="motorcar"   v="no"/>
+        <output k="goods"      v="no"/>
+        <output k="hgv"        v="no"/>
+        <output k="psv"        v="no"/>
+
+        <if k="access" v="foot">
+          <set k="foot" v="yes"/>
+          <logerror k="access" message="using 'access' = 'no' ; 'foot' = 'yes'"/>
+          <set k="access" v="no"/>
+        </if>
+
+        <ifnot k="access" v="no">
+          <logerror k="access" message="using 'no'"/>
+        </ifnot>
+      </ifnot>
+
+    </if> <!-- k="access" -->
+
+    <!-- Generic access permissions for classes of transport types -->
+
+    <if k="vehicle">
+
+      <ifnot k="vehicle" v="yes">
+        <output k="bicycle"    v="no"/>
+        <output k="moped"      v="no"/>
+        <output k="motorcycle" v="no"/>
+        <output k="motorcar"   v="no"/>
+        <output k="goods"      v="no"/>
+        <output k="hgv"        v="no"/>
+        <output k="psv"        v="no"/>
+
+        <ifnot k="vehicle" v="no">
+          <logerror k="vehicle" message="using 'no'"/>
+        </ifnot>
+      </ifnot>
+
+    </if> <!-- k="vehicle" -->
+
+    <if k="motor_vehicle">
+
+      <ifnot k="motor_vehicle" v="yes">
+        <output k="moped"      v="no"/>
+        <output k="motorcycle" v="no"/>
+        <output k="motorcar"   v="no"/>
+        <output k="goods"      v="no"/>
+        <output k="hgv"        v="no"/>
+        <output k="psv"        v="no"/>
+
+        <ifnot k="motor_vehicle" v="no">
+          <logerror k="motor_vehicle" message="using 'no'"/>
+        </ifnot>
+      </ifnot>
+
+    </if> <!-- k="motor_vehicle" -->
+
+    <!-- Specific access rules (to override the generic ones) -->
+
+    <if k="foot"      > <output/> </if>
+    <if k="horse"     > <output/> </if>
+    <if k="wheelchair"> <output/> </if>
+    <if k="bicycle"   > <output/> </if>
+    <if k="moped"     > <output/> </if>
+    <if k="motorcycle"> <output/> </if>
+    <if k="motorcar"  > <output/> </if>
+    <if k="goods"     > <output/> </if>
+    <if k="hgv"       > <output/> </if>
+    <if k="psv"       > <output/> </if>
+
+    <!-- Mini-roundabouts  -->
+
+    <if k="highway" v="mini_roundabout">
+      <output k="roundabout" v="yes"/>
+    </if>
+
+    <if k="junction" v="roundabout">
+      <output k="roundabout" v="yes"/>
+    </if>
+
+  </node>
+
+  <!-- - - - - - - - - - - Way rules - - - - - - - - - - -->
+
+  <way>
+
+    <!-- Note: The default is that no transport type is allowed on any highway;
+               access must be specified to allow each transport type. -->
+
+    <if k="route" v="ferry">
+      <set k="highway" v="ferry"/>
+    </if>
+
+    <if k="highway">
+
+      <!-- Not useful highway types (future highways) -->
+
+      <if k="highway" v="construction"> <unset/> </if>
+      <if k="highway" v="planned"     > <unset/> </if>
+      <if k="highway" v="proposed"    > <unset/> </if>
+
+      <!-- Not useful highway types (previous highways) -->
+
+      <if k="highway" v="no"          > <unset/> </if>
+      <if k="highway" v="abandoned"   > <unset/> </if>
+      <if k="highway" v="disused"     > <unset/> </if>
+
+      <!-- Not useful highway types (limited use highways) -->
+
+      <if k="highway" v="raceway"     > <unset/> </if>
+
+      <!-- Highway types (includes default access and default properties) -->
+
+      <if k="highway" v="motorway_link">
+        <set v="motorway"/>
+      </if>
+
+      <if k="highway" v="motorway">
+        <output k="highway"/>
+
+        <output k="motorcycle" v="yes"/>
+        <output k="motorcar"   v="yes"/>
+        <output k="goods"      v="yes"/>
+        <output k="hgv"        v="yes"/>
+        <output k="psv"        v="yes"/>
+
+        <output k="paved"      v="yes"/>
+        <output k="multilane"  v="yes"/>
+        <output k="oneway"     v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="trunk_link">
+        <set v="trunk"/>
+      </if>
+
+      <if k="highway" v="trunk">
+        <output k="highway"/>
+
+        <output k="bicycle"    v="yes"/>
+        <output k="moped"      v="yes"/>
+        <output k="motorcycle" v="yes"/>
+        <output k="motorcar"   v="yes"/>
+        <output k="goods"      v="yes"/>
+        <output k="hgv"        v="yes"/>
+        <output k="psv"        v="yes"/>
+
+        <output k="paved"      v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="primary_link">
+        <set v="primary"/>
+      </if>
+
+      <if k="highway" v="primary">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="horse"      v="yes"/>
+        <output k="wheelchair" v="no"/>
+        <output k="bicycle"    v="yes"/>
+        <output k="moped"      v="yes"/>
+        <output k="motorcycle" v="yes"/>
+        <output k="motorcar"   v="yes"/>
+        <output k="goods"      v="yes"/>
+        <output k="hgv"        v="yes"/>
+        <output k="psv"        v="yes"/>
+
+        <output k="paved"      v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="secondary_link">
+        <set v="secondary"/>
+      </if>
+
+      <if k="highway" v="secondary">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="horse"      v="yes"/>
+        <output k="wheelchair" v="yes"/>
+        <output k="bicycle"    v="yes"/>
+        <output k="moped"      v="yes"/>
+        <output k="motorcycle" v="yes"/>
+        <output k="motorcar"   v="yes"/>
+        <output k="goods"      v="yes"/>
+        <output k="hgv"        v="yes"/>
+        <output k="psv"        v="yes"/>
+
+        <output k="paved"      v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="tertiary_link">
+        <set v="tertiary"/>
+      </if>
+
+      <if k="highway" v="tertiary">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="horse"      v="yes"/>
+        <output k="wheelchair" v="yes"/>
+        <output k="bicycle"    v="yes"/>
+        <output k="moped"      v="yes"/>
+        <output k="motorcycle" v="yes"/>
+        <output k="motorcar"   v="yes"/>
+        <output k="goods"      v="yes"/>
+        <output k="hgv"        v="yes"/>
+        <output k="psv"        v="yes"/>
+
+        <output k="paved"      v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="minor">
+        <set k="highway" v="unclassified"/>
+      </if>
+
+      <if k="highway" v="road">
+        <set k="highway" v="unclassified"/>
+      </if>
+
+      <if k="highway" v="unclassified">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="horse"      v="yes"/>
+        <output k="wheelchair" v="yes"/>
+        <output k="bicycle"    v="yes"/>
+        <output k="moped"      v="yes"/>
+        <output k="motorcycle" v="yes"/>
+        <output k="motorcar"   v="yes"/>
+        <output k="goods"      v="yes"/>
+        <output k="hgv"        v="yes"/>
+        <output k="psv"        v="yes"/>
+
+        <output k="paved"      v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="living_street">
+        <set k="highway" v="residential"/>
+      </if>
+
+      <if k="highway" v="residential">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="horse"      v="yes"/>
+        <output k="wheelchair" v="yes"/>
+        <output k="bicycle"    v="yes"/>
+        <output k="moped"      v="yes"/>
+        <output k="motorcycle" v="yes"/>
+        <output k="motorcar"   v="yes"/>
+        <output k="goods"      v="yes"/>
+        <output k="hgv"        v="yes"/>
+        <output k="psv"        v="yes"/>
+
+        <output k="paved"      v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="access">
+        <set k="highway" v="service"/>
+      </if>
+
+      <if k="highway" v="services">
+        <set k="highway" v="service"/>
+      </if>
+
+      <if k="highway" v="rest_area">
+        <set k="highway" v="service"/>
+      </if>
+
+      <if k="highway" v="layby">
+        <set k="highway" v="service"/>
+      </if>
+
+      <if k="highway" v="service">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="horse"      v="yes"/>
+        <output k="wheelchair" v="yes"/>
+        <output k="bicycle"    v="yes"/>
+        <output k="moped"      v="yes"/>
+        <output k="motorcycle" v="yes"/>
+        <output k="motorcar"   v="yes"/>
+        <output k="goods"      v="yes"/>
+        <output k="hgv"        v="yes"/>
+        <output k="psv"        v="yes"/>
+
+        <output k="paved"      v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="byway">
+        <set k="highway" v="track"/>
+      </if>
+
+      <if k="highway" v="unsurfaced">
+        <set k="highway" v="track"/>
+      </if>
+
+      <if k="highway" v="unpaved">
+        <set k="highway" v="track"/>
+      </if>
+
+      <if k="highway" v="track">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="horse"      v="yes"/>
+        <output k="bicycle"    v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="tracktype" v="grade1">
+        <output k="paved"      v="yes"/>
+      </if>
+
+      <if k="highway" v="cycleway">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="wheelchair" v="yes"/>
+        <output k="bicycle"    v="yes"/>
+
+        <output k="paved"      v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="footway">
+        <set k="highway" v="path"/>
+      </if>
+
+      <if k="highway" v="bridleway">
+        <set k="highway" v="path"/>
+
+        <output k="horse"      v="yes"/>
+        <output k="bicycle"    v="yes"/>
+      </if>
+
+      <if k="highway" v="pedestrian">
+        <set k="highway" v="path"/>
+
+        <output k="paved"      v="yes"/>
+      </if>
+
+      <if k="highway" v="walkway">
+        <set k="highway"  v="path"/>
+
+        <output k="paved"      v="yes"/>
+      </if>
+
+      <if k="highway" v="trail">
+        <set k="highway"  v="path"/>
+
+        <output k="paved"      v="no"/>
+      </if>
+
+      <if k="highway" v="path">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="wheelchair" v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="steps">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="ferry">
+        <output k="highway"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <!-- Unrecognised highway type -->
+
+      <if k="highway">
+        <logerror message="ignoring it"/>
+      </if>
+
+      <!-- Normalisation of access tags -->
+
+      <if v="designated"  > <set v="yes"/> </if>
+      <if v="permissive"  > <set v="yes"/> </if>
+      <if v="destination" > <set v="yes"/> </if>
+      <if v="true"        > <set v="yes"/> </if>
+      <if v="public"      > <set v="yes"/> </if>
+      <if v="customers"   > <set v="yes"/> </if>
+      <if v="customer"    > <set v="yes"/> </if>
+      <if v="official"    > <set v="yes"/> </if>
+                           
+      <if v="unsuitable"  > <set v="no"/> </if>
+      <if v="private"     > <set v="no"/> </if>
+      <if v="limited"     > <set v="no"/> </if>
+      <if v="restricted"  > <set v="no"/> </if>
+      <if v="agricultural"> <set v="no"/> </if>
+      <if v="forestry"    > <set v="no"/> </if>
+
+      <!-- Generic access restrictions for all transport types (to subtract from highway specific defaults) -->
+
+      <if k="access">
+
+        <ifnot k="access" v="yes">
+          <output k="foot"       v="no"/>
+          <output k="horse"      v="no"/>
+          <output k="wheelchair" v="no"/>
+          <output k="bicycle"    v="no"/>
+          <output k="moped"      v="no"/>
+          <output k="motorcycle" v="no"/>
+          <output k="motorcar"   v="no"/>
+          <output k="goods"      v="no"/>
+          <output k="hgv"        v="no"/>
+          <output k="psv"        v="no"/>
+
+          <if k="access" v="foot">
+            <set k="foot" v="yes"/>
+            <logerror k="access" message="using 'access' = 'no' ; 'foot' = 'yes'"/>
+            <set k="access" v="no"/>
+          </if>
+
+          <if k="access" v="wheelchair">
+            <set k="wheelchair" v="yes"/>
+            <logerror k="access" message="using 'access' = 'no' ; 'wheelchair' = 'yes'"/>
+            <set k="access" v="no"/>
+          </if>
+
+          <if k="access" v="motor_vehicle">
+            <set k="motor_vehicle" v="yes"/>
+            <logerror k="access" message="using 'access' = 'no' ; 'motor_vehicle' = 'yes'"/>
+            <set k="access" v="no"/>
+          </if>
+
+          <if k="access" v="hgv">
+            <set k="hgv" v="yes"/>
+            <logerror k="access" message="using 'access' = 'no' ; 'hgv' = 'yes'"/>
+            <set k="access" v="no"/>
+          </if>
+
+          <if k="access" v="bus">
+            <set v="psv" />
+          </if>
+
+          <if k="access" v="psv">
+            <set k="psv" v="yes"/>
+            <logerror k="access" message="using 'access' = 'no' ; 'psv' = 'yes'"/>
+            <set k="access" v="no"/>
+          </if>
+
+          <ifnot k="access" v="no">
+            <logerror k="access" message="using 'no'"/>
+          </ifnot>
+        </ifnot>
+
+      </if> <!-- k="access" -->
+
+      <!-- Access restrictions for classes of transport types (to subtract from highway specific defaults) -->
+
+      <if k="vehicle">
+
+        <ifnot k="vehicle" v="yes">
+          <output k="bicycle"    v="no"/>
+          <output k="moped"      v="no"/>
+          <output k="motorcycle" v="no"/>
+          <output k="motorcar"   v="no"/>
+          <output k="goods"      v="no"/>
+          <output k="hgv"        v="no"/>
+          <output k="psv"        v="no"/>
+
+          <ifnot k="vehicle" v="no">
+            <logerror k="vehicle" message="using 'no'"/>
+          </ifnot>
+        </ifnot>
+
+      </if> <!-- k="vehicle" -->
+
+      <if k="motor_vehicle">
+
+        <ifnot k="motor_vehicle" v="yes">
+          <output k="moped"      v="no"/>
+          <output k="motorcycle" v="no"/>
+          <output k="motorcar"   v="no"/>
+          <output k="goods"      v="no"/>
+          <output k="hgv"        v="no"/>
+          <output k="psv"        v="no"/>
+
+          <ifnot k="motor_vehicle" v="no">
+            <logerror k="motor_vehicle" message="using 'no'"/>
+          </ifnot>
+        </ifnot>
+
+      </if> <!-- k="motor_vehicle" -->
+
+      <!-- Other access permissions (to add to highway specific defaults with generic restrictions) -->
+
+      <if k="designation">
+
+        <if k="designation" v="restricted_byway">
+          <output k="foot"       v="yes"/>
+          <output k="horse"      v="yes"/>
+          <output k="wheelchair" v="yes"/>
+          <output k="bicycle"    v="yes"/>
+
+          <unset k="designation"/>
+        </if>
+
+        <if k="designation" v="public_byway">
+          <set v="byway_open_to_all_traffic"/>
+        </if>
+
+        <if k="designation" v="byway">
+          <set v="byway_open_to_all_traffic"/>
+        </if>
+
+        <if k="designation" v="byway_open_to_all_traffic">
+          <output k="foot"       v="yes"/>
+          <output k="horse"      v="yes"/>
+          <output k="wheelchair" v="yes"/>
+          <output k="bicycle"    v="yes"/>
+          <output k="moped"      v="yes"/>
+          <output k="motorcycle" v="yes"/>
+          <output k="motorcar"   v="yes"/>
+
+          <unset k="designation"/>
+        </if>
+
+        <if k="designation" v="permissive_bridleway">
+          <set v="bridleway"/>
+        </if>
+
+        <if k="designation" v="public_bridleway">
+          <set v="bridleway"/>
+        </if>
+
+        <if k="designation" v="bridleway">
+          <output k="foot"       v="yes"/>
+          <output k="horse"      v="yes"/>
+          <output k="wheelchair" v="yes"/>
+          <output k="bicycle"    v="yes"/>
+
+          <unset k="designation"/>
+        </if>
+
+        <if k="designation" v="public_cycleway">
+          <output k="foot"       v="yes"/>
+          <output k="wheelchair" v="yes"/>
+          <output k="bicycle"    v="yes"/>
+
+          <unset k="designation"/>
+        </if>
+
+        <if k="designation" v="permissive_footpath">
+          <set v="footpath"/>
+        </if>
+
+        <if k="designation" v="public_footpath">
+          <set v="footpath"/>
+        </if>
+
+        <if k="designation" v="footpath">
+          <output k="foot"       v="yes"/>
+          <output k="wheelchair" v="yes"/>
+
+          <unset k="designation"/>
+        </if>
+
+        <if k="designation">
+          <logerror message="ignoring it"/>
+        </if>
+
+      </if> <!-- k="designation" -->
+
+      <!-- Derived access rules (to override the generic ones) -->
+
+      <if k="motorroad" v="yes">
+        <output k="foot"       v="no"/>
+        <output k="horse"      v="no"/>
+        <output k="wheelchair" v="no"/>
+        <output k="bicycle"    v="no"/>
+        <output k="moped"      v="no"/>
+      </if>
+
+      <if k="footway">
+
+        <!-- Tags from http://taginfo.openstreetmap.org/keys/footway#values on 2013-02-09 -->
+
+        <if k="footway" v="sidewalk"> <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+        <if k="footway" v="both">     <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+        <if k="footway" v="left">     <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+        <if k="footway" v="right">    <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+        <if k="footway" v="yes">      <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+      </if>
+
+      <if k="sidewalk">
+
+        <!-- Tags from http://taginfo.openstreetmap.org/keys/sidewalk#values on 2013-02-09 -->
+
+        <if k="sidewalk" v="both">    <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+        <if k="sidewalk" v="left">    <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+        <if k="sidewalk" v="right">   <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+        <if k="sidewalk" v="yes">     <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+      </if>
+
+      <if k="cycleway">
+
+        <!-- Tags from http://taginfo.openstreetmap.org/keys/cycleway#values on 2013-02-09 -->
+
+        <if k="cycleway" v="lane">   <output k="bicycle" v="yes"/> </if>
+        <if k="cycleway" v="track">  <output k="bicycle" v="yes"/> </if>
+        <if k="cycleway" v="shared"> <output k="bicycle" v="yes"/> </if>
+        <if k="cycleway" v="yes">    <output k="bicycle" v="yes"/> </if>
+
+        <if k="cycleway" v="opposite_lane">
+          <output k="bicycle" v="yes"/>
+          <output k="cyclebothways" v="yes"/>
+        </if>
+
+        <if k="cycleway" v="opposite_track">
+          <output k="bicycle" v="yes"/>
+          <output k="cyclebothways" v="yes"/>
+        </if>
+
+        <if k="cycleway" v="opposite">
+          <output k="bicycle" v="yes"/>
+          <output k="cyclebothways" v="yes"/>
+        </if>
+      </if>
+
+      <if k="oneway:bicycle" v="no">
+        <output k="bicycle" v="yes"/>
+        <output k="cyclebothways" v="yes"/>
+      </if>
+
+      <!-- Specific access rules (to override the generic ones) -->
+
+      <if k="foot"      > <output/> </if>
+      <if k="horse"     > <output/> </if>
+      <if k="wheelchair"> <output/> </if>
+      <if k="bicycle"   > <output/> </if>
+      <if k="moped"     > <output/> </if>
+      <if k="motorcycle"> <output/> </if>
+      <if k="motorcar"  > <output/> </if>
+      <if k="goods"     > <output/> </if>
+      <if k="hgv"       > <output/> </if>
+      <if k="psv"       > <output/> </if>
+
+      <!-- Normalisation of property tags -->
+
+      <if k="surface">
+
+        <!-- Tags from http://wiki.openstreetmap.org/wiki/Key:surface on 2012-11-21 -->
+
+        <if k="surface" v="asphalt">               <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="cobblestone">           <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="cobblestone:flattened"> <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="compacted">             <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="concrete">              <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="concrete:lanes">        <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="concrete:plates">       <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="dirt">                  <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="earth">                 <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="fine_gravel">           <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="grass">                 <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="grass_paver">           <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="gravel">                <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="ground">                <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="metal">                 <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="mud">                   <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="paved">                 <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="paving_stones">         <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="paving_stones:20">      <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="paving_stones:30">      <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="pebblestone">           <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="sand">                  <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="unpaved">               <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="wood">                  <set k="paved" v="no"/>  <unset k="surface"/> </if>
+
+        <!-- Other tags -->
+
+        <if k="surface" v="sealed">       <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="cement">       <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="tarmac">       <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="tar_and_chip"> <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="metalled">     <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="bricks">       <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="brick">        <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="brick_weave">  <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="setts">        <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="sett">         <set k="paved" v="yes"/> <unset k="surface"/> </if>
+
+        <if k="surface" v="unsealed">     <set k="paved" v="no"/> <unset k="surface"/> </if>
+        <if k="surface" v="soil">         <set k="paved" v="no"/> <unset k="surface"/> </if>
+        <if k="surface" v="stones">       <set k="paved" v="no"/> <unset k="surface"/> </if>
+        <if k="surface" v="stone">        <set k="paved" v="no"/> <unset k="surface"/> </if>
+        <if k="surface" v="pebbles">      <set k="paved" v="no"/> <unset k="surface"/> </if>
+        <if k="surface" v="hardcore">     <set k="paved" v="no"/> <unset k="surface"/> </if>
+        <if k="surface" v="bark">         <set k="paved" v="no"/> <unset k="surface"/> </if>
+
+        <if k="surface">
+          <logerror message="ignoring it"/>
+        </if>
+
+      </if> <!-- k="surface" -->
+
+      <if k="bridge">
+        <ifnot k="bridge" v="no">
+          <set k="bridge" v="yes"/>
+        </ifnot>
+      </if>
+
+      <if k="tunnel">
+        <ifnot k="tunnel" v="no">
+          <set k="tunnel" v="yes"/>
+        </ifnot>
+      </if>
+
+      <if k="junction" v="roundabout">
+        <output k="oneway"     v="yes"/>
+        <output k="roundabout" v="yes"/>
+      </if>
+
+      <!-- Specific property rules (to override the default ones) -->
+
+      <if k="paved"> <output/> </if>
+
+      <if k="lanes"> <output/> </if>
+
+      <if k="bridge"> <output/> </if>
+
+      <if k="tunnel"> <output/> </if>
+
+      <!-- Output the restriction tags -->
+
+      <if k="oneway"> <output/> </if>
+
+      <if k="maxspeed"> <output/> </if>
+
+      <if k="maxweight"> <output/> </if>
+      <if k="maxheight"> <output/> </if>
+      <if k="maxwidth" > <output/> </if>
+      <if k="maxlength"> <output/> </if>
+
+      <!-- Output the name and reference tags -->
+
+      <if k="name"> <output/> </if>
+      <if k="ref" > <output/> </if>
+
+      <!-- Output the area tag -->
+
+      <if k="area"> <output/> </if>
+
+    </if> <!-- k="highway" -->
+
+  </way>
+
+  <!-- - - - - - - - - - - Relation rules - - - - - - - - - - -->
+
+  <relation>
+
+    <if k="type">
+      <output/>
+    </if>
+
+    <!-- Copy route relations -->
+
+    <if k="route">
+
+      <if k="route" v="foot">
+        <output k="footroute" v="yes"/>
+      </if>
+
+      <if k="route" v="walking">
+        <output k="footroute" v="yes"/>
+      </if>
+
+      <if k="route" v="hiking">
+        <output k="footroute" v="yes"/>
+      </if>
+
+      <if k="route" v="foot;bicycle">
+        <output k="footroute"    v="yes"/>
+        <output k="bicycleroute" v="yes"/>
+      </if>
+
+      <if k="route" v="bicycle;foot">
+        <output k="footroute"    v="yes"/>
+        <output k="bicycleroute" v="yes"/>
+      </if>
+
+      <if k="route" v="bicycle">
+        <output k="bicycleroute" v="yes"/>
+      </if>
+
+    </if> <!-- k="route" -->
+
+    <!-- Pass through turn relations -->
+
+    <if k="restriction">
+      <output/>
+    </if>
+
+    <if k="except">
+
+      <if k="except" v="bus"> <set v="psv"/> </if>
+
+      <if k="except">
+        <output/>
+      </if>
+
+    </if>
+
+  </relation>
+
+</routino-tagging>
diff --git a/3rdparty/Routino/xml/routino-tagging.xsd b/3rdparty/Routino/xml/routino-tagging.xsd
new file mode 100644
index 0000000..19962b5
--- /dev/null
+++ b/3rdparty/Routino/xml/routino-tagging.xsd
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- ============================================================
+     An XML Schema Definition for the Routino tagging rules XML format
+
+     Part of the Routino routing software.
+     ============================================================
+     This file Copyright 2010-2013 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+  <!-- The top level Routino tagging rules -->
+
+  <xsd:element name="routino-tagging" type="RoutinoTaggingType"/>
+
+  <xsd:complexType name="RoutinoTaggingType">
+    <xsd:sequence>
+      <xsd:element name="node"        type="NodeType"/>
+      <xsd:element name="way"         type="WayType"/>
+      <xsd:element name="relation"    type="RelationType"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <!-- The second level node, way and relation tagging rules -->
+
+  <xsd:complexType name="NodeType">
+    <xsd:sequence>
+      <xsd:element name="if"    type="IfType"    minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="ifnot" type="IfNotType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="WayType">
+    <xsd:sequence>
+      <xsd:element name="if"    type="IfType"    minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="ifnot" type="IfNotType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="RelationType">
+    <xsd:sequence>
+      <xsd:element name="if"    type="IfType"    minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="ifnot" type="IfNotType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <!-- The if tag and its contents -->
+
+  <xsd:complexType name="IfType">
+    <xsd:sequence>
+      <xsd:element name="if"       type="IfType"       minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="ifnot"    type="IfNotType"    minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="set"      type="SetType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="unset"    type="UnsetType"    minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="output"   type="OutputType"   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="logerror" type="LogErrorType" minOccurs="0" maxOccurs="1"/>
+    </xsd:sequence>
+    <xsd:attribute name="k" type="xsd:string"/>
+    <xsd:attribute name="v" type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="IfNotType">
+    <xsd:sequence>
+      <xsd:element name="if"       type="IfType"       minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="ifnot"    type="IfNotType"    minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="set"      type="SetType"      minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="unset"    type="UnsetType"    minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="output"   type="OutputType"   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="logerror" type="LogErrorType" minOccurs="0" maxOccurs="1"/>
+    </xsd:sequence>
+    <xsd:attribute name="k" type="xsd:string"/>
+    <xsd:attribute name="v" type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="SetType">
+    <xsd:attribute name="k" type="xsd:string"/>
+    <xsd:attribute name="v" type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="UnsetType">
+    <xsd:attribute name="k" type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="OutputType">
+    <xsd:attribute name="k" type="xsd:string"/>
+    <xsd:attribute name="v" type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="LogErrorType">
+    <xsd:attribute name="k"       type="xsd:string"/>
+    <xsd:attribute name="v"       type="xsd:string"/>
+    <xsd:attribute name="message" type="xsd:string"/>
+  </xsd:complexType>
+
+</xsd:schema>
diff --git a/3rdparty/Routino/xml/routino-translations.xml b/3rdparty/Routino/xml/routino-translations.xml
new file mode 100644
index 0000000..25fa2a9
--- /dev/null
+++ b/3rdparty/Routino/xml/routino-translations.xml
@@ -0,0 +1,577 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- ============================================================
+     An XML format file containing Routino output translations.
+
+     Part of the Routino routing software.
+     ============================================================
+     This file Copyright 2010-2014 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<routino-translations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                      xsi:noNamespaceSchemaLocation="http://www.routino.org/xml/routino-translations.xsd">
+
+  <language lang="en">
+
+    <!-- Copyright of the data being routed, not of this file  -->
+    <copyright>
+      <creator string="Creator" text="Routino - http://www.routino.org/" />
+      <source  string="Source" text="Based on OpenStreetMap data from http://www.openstreetmap.org/" />
+      <license string="License" text="http://www.openstreetmap.org/copyright" />
+    </copyright>
+
+    <!-- Turn directions, 0 = ahead, -2 = left, +/-4 = behind, +2 = right -->
+    <turn direction="-4" string="Very sharp left" />
+    <turn direction="-3" string="Sharp left" />
+    <turn direction="-2" string="Left" />
+    <turn direction="-1" string="Slight left" />
+    <turn direction="0"  string="Straight on" />
+    <turn direction="1"  string="Slight right" />
+    <turn direction="2"  string="Right" />
+    <turn direction="3"  string="Sharp right" />
+    <turn direction="4"  string="Very sharp right" />
+
+    <!-- Heading directions, 0 = North, -2 = West, +/-4 = South, +2 = East -->
+    <heading direction="-4" string="South" />
+    <heading direction="-3" string="South-West" />
+    <heading direction="-2" string="West" />
+    <heading direction="-1" string="North-West" />
+    <heading direction="0"  string="North" />
+    <heading direction="1"  string="North-East" />
+    <heading direction="2"  string="East" />
+    <heading direction="3"  string="South-East" />
+    <heading direction="4"  string="South" />
+
+    <!-- Ordinals, 1 = first, 2 = second ... -->
+    <ordinal number="1"  string="First" />
+    <ordinal number="2"  string="Second" />
+    <ordinal number="3"  string="Third" />
+    <ordinal number="4"  string="Fourth" />
+    <ordinal number="5"  string="Fifth" />
+    <ordinal number="6"  string="Sixth" />
+    <ordinal number="7"  string="Seventh" />
+    <ordinal number="8"  string="Eighth" />
+    <ordinal number="9"  string="Ninth" />
+    <ordinal number="10" string="Tenth" />
+
+    <!-- Highway names -->
+    <highway type="motorway"     string="motorway" />
+    <highway type="trunk"        string="trunk road" />
+    <highway type="primary"      string="primary road" />
+    <highway type="secondary"    string="secondary road" />
+    <highway type="tertiary"     string="tertiary road" />
+    <highway type="unclassified" string="unclassified road" />
+    <highway type="residential"  string="residential road" />
+    <highway type="service"      string="service road" />
+    <highway type="track"        string="track" />
+    <highway type="cycleway"     string="cycleway" />
+    <highway type="path"         string="path" />
+    <highway type="steps"        string="steps" />
+    <highway type="ferry"        string="ferry" />
+
+    <!-- The type of route -->
+    <route type="shortest" string="Shortest" /> <!-- For the description and route name -->
+    <route type="quickest" string="Quickest" /> <!-- For the description and route name -->
+
+    <!-- HTML output -->
+    <output-html>
+      <waypoint type="waypoint"   string="Waypoint" /> <!-- For the chosen waypoints -->
+      <waypoint type="junction"   string="Junction" /> <!-- For the interesting junctions -->
+      <waypoint type="roundabout" string="Roundabout" /> <!-- For roundabouts -->
+
+      <title text="%s Route" /> <!-- %s = [shortest|quickest] -->
+
+      <start   string="Start" text="At %s, head %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [heading] -->
+      <node    string="At" text="%s, go %s heading %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [turn], 3rd %s = [heading] -->
+      <rbnode  string="Leave" text="%s, take the %s exit heading %s" /> <!-- 1st %s = [roundabout], 2nd %s = [first|second|...], 3rd %s = [heading] -->
+      <segment string="Follow" text="%s for %.3f km, %.1f min" /> <!-- 1st %s = street name -->
+      <stop    string="Stop" text="At %s" /> <!-- 1st %s = [waypoint|junction] -->
+      <total   string="Total" text="%.1f km, %.0f minutes" />
+    </output-html>
+
+    <!-- GPX output -->
+    <output-gpx>
+      <waypoint type="start" string="START" /> <!-- For the first route waypoint -->
+      <waypoint type="inter" string="INTER" /> <!-- For the intermediate route waypoints -->
+      <waypoint type="trip" string="TRIP" /> <!-- For the other route points -->
+      <waypoint type="finish" string="FINISH"/> <!-- For the last route waypoint -->
+
+      <desc  text="%s route between 'start' and 'finish' waypoints" /> <!-- %s = [shortest|quickest] -->
+      <name  text="%s route" /> <!-- %s = [shortest|quickest] -->
+      <step  text="%s on '%s' for %.3f km, %.1f min" /> <!-- 1st %s = [turn], 2nd %s = street name -->
+      <final text="Total Journey %.1f km, %.0f minutes" />
+    </output-gpx>
+
+  </language>
+
+  <language lang="de">
+
+    <!-- Copyright of the data being routed, not of this file  -->
+    <copyright>
+      <creator string="Urheber" text="Routino - http://www.routino.org/" />
+      <source  string="Quelle" text="Basierend auf OpenStreetMap-Daten, erhältlich via http://www.openstreetmap.org/" />
+      <license string="Lizenz" text="http://www.openstreetmap.org/copyright" />
+    </copyright>
+
+    <!-- Turn directions, 0 = ahead, -2 = left, +/-4 = behind, +2 = right -->
+    <turn direction="-4" string="Sehr scharf links" />
+    <turn direction="-3" string="Scharf links" />
+    <turn direction="-2" string="Links" />
+    <turn direction="-1" string="Halb links" />
+    <turn direction="0"  string="Geradeaus" />
+    <turn direction="1"  string="Halb rechts" />
+    <turn direction="2"  string="Rechts" />
+    <turn direction="3"  string="Scharf rechts" />
+    <turn direction="4"  string="Sehr scharf rechts" />
+
+    <!-- Heading directions, 0 = North, -2 = West, +/-4 = South, +2 = East -->
+    <heading direction="-4" string="Süd" />
+    <heading direction="-3" string="Süd-West" />
+    <heading direction="-2" string="West" />
+    <heading direction="-1" string="Nord-West" />
+    <heading direction="0"  string="Nord" />
+    <heading direction="1"  string="Nord-Ost" />
+    <heading direction="2"  string="Ost" />
+    <heading direction="3"  string="Süd-Ost" />
+    <heading direction="4"  string="Süd" />
+
+    <!-- Ordinals, 1 = first, 2 = second ... -->
+    <ordinal number="1"  string="Erste" />
+    <ordinal number="2"  string="Zweite" />
+    <ordinal number="3"  string="Dritte" />
+    <ordinal number="4"  string="Vierte" />
+    <ordinal number="5"  string="Fünfte" />
+    <ordinal number="6"  string="Sechste" />
+    <ordinal number="7"  string="Siebte" />
+    <ordinal number="8"  string="Achte" />
+    <ordinal number="9"  string="Neunte" />
+    <ordinal number="10" string="Zehnte" />
+
+    <!-- Highway names -->
+    <highway type="motorway"     string="Autobahn" />
+    <highway type="trunk"        string="Schnellstraße" />
+    <highway type="primary"      string="Bundesstraße" />
+    <highway type="secondary"    string="Landesstraße" />
+    <highway type="tertiary"     string="Kreisstraße" />
+    <highway type="unclassified" string="Nebenstraße" />
+    <highway type="residential"  string="Wohngebietsstraße" />
+    <highway type="service"      string="Erschließungsweg" />
+    <highway type="track"        string="Feld-/Waldweg" />
+    <highway type="cycleway"     string="Radweg" />
+    <highway type="path"         string="Weg/Pfad" />
+    <highway type="steps"        string="Treppe" />
+    <highway type="ferry"        string="Fähre" />
+
+    <!-- The type of route -->
+    <route type="shortest" string="Kürzeste" /> <!-- For the description and route name -->
+    <route type="quickest" string="Schnellste" /> <!-- For the description and route name -->
+
+    <!-- HTML output -->
+    <output-html>
+      <waypoint type="waypoint"   string="Wegpunkt" /> <!-- For the chosen waypoints -->
+      <waypoint type="junction"   string="Anschlussstelle" /> <!-- For the interesting junctions -->
+      <waypoint type="roundabout" string="Kreisverkehr" /> <!-- For roundabouts -->
+
+      <title text="%s Route" /> <!-- %s = [shortest|quickest] -->
+
+      <start   string="Start" text="Bei %s halten Sie sich Richtung %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [heading] -->
+      <node    string="Bei" text="Bei %s wenden Sie sich nach %s Richtung %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [turn], 3rd %s = [heading] -->
+      <rbnode  string="Verlassen Sie" text="%s, nehmen Sie die %s Ausfahrt Richtung %s" /> <!-- 1st %s = [roundabout], 2nd %s = [first|second|...], 3rd %s = [heading] -->
+      <segment string="Folgen" text="Folgen Sie der %s für %.3f km bzw. %.1f min" /> <!-- 1st %s = street name -->
+      <stop    string="Stop" text="Sie sind bei %s angekommen" /> <!-- 1st %s = [waypoint|junction] -->
+      <total   string="Gesamt" text="%.1f km, %.0f minuten" />
+    </output-html>
+
+    <!-- GPX output -->
+    <output-gpx>
+      <waypoint type="start" string="START" /> <!-- For the first route waypoint -->
+      <waypoint type="inter" string="INTER" /> <!-- For the intermediate route waypoints -->
+      <waypoint type="trip" string="TRIP" /> <!-- For the other route points -->
+      <waypoint type="finish" string="FINISH"/> <!-- For the last route waypoint -->
+
+      <desc  text="%s Strecke zwischen 'Start' und 'Ziel'" /> <!-- %s = [shortest|quickest] -->
+      <name  text="%s Strecke" /> <!-- %s = [shortest|quickest] -->
+      <step  text="%s auf '%s' für %.3f km, %.1f min" /> <!-- 1st %s = [turn], 2nd %s = street name -->
+      <final text="Gesamtstrecke %.1f km, %.0f minuten" />
+    </output-gpx>
+
+  </language>
+
+  <language lang="fr">
+
+    <!-- Copyright of the data being routed, not of this file  -->
+    <copyright>
+      <creator string="Créateur" text="Routino - http://www.routino.org/" />
+      <source  string="Source" text="Basé sur les données OpenStreetMap de http://www.openstreetmap.org/" />
+      <license string="License" text="http://www.openstreetmap.org/copyright" />
+    </copyright>
+
+    <!-- Turn directions, 0 = ahead, -2 = left, +/-4 = behind, +2 = right -->
+    <turn direction="-4" string="demi-tour à gauche" />
+    <turn direction="-3" string="Très à gauche" />
+    <turn direction="-2" string="à gauche" />
+    <turn direction="-1" string="Légèrement à gauche" />
+    <turn direction="0"  string="Tout droit" />
+    <turn direction="1"  string="légèrement à droite" />
+    <turn direction="2"  string="à droite" />
+    <turn direction="3"  string="très à droite" />
+    <turn direction="4"  string="demi-tour à droite" />
+
+    <!-- Heading directions, 0 = North, -2 = West, +/-4 = South, +2 = East -->
+    <heading direction="-4" string="Sud" />
+    <heading direction="-3" string="Dud-Ouest" />
+    <heading direction="-2" string="Ouest" />
+    <heading direction="-1" string="Nord-Ouest" />
+    <heading direction="0"  string="Nord" />
+    <heading direction="1"  string="Nord-Est" />
+    <heading direction="2"  string="Est" />
+    <heading direction="3"  string="Sud-Est" />
+    <heading direction="4"  string="Sud" />
+
+    <!-- Ordinals, 1 = first, 2 = second ... -->
+    <ordinal number="1"  string="Premier" />
+    <ordinal number="2"  string="Second" />
+    <ordinal number="3"  string="Troisième" />
+    <ordinal number="4"  string="Quatrième" />
+    <ordinal number="5"  string="Cinquième" />
+    <ordinal number="6"  string="Sixième" />
+    <ordinal number="7"  string="Septième" />
+    <ordinal number="8"  string="huitième" />
+    <ordinal number="9"  string="Neuvième" />
+    <ordinal number="10" string="Dixième" />
+
+    <!-- Highway names -->
+    <highway type="motorway"     string="autoroute" />
+    <highway type="trunk"        string="route de jonction" />
+    <highway type="primary"      string="route nationale" />
+    <highway type="secondary"    string="route départementale" />
+    <highway type="tertiary"     string="route locale" />
+    <highway type="unclassified" string="route non classifiée" />
+    <highway type="residential"  string="rue résidentielle" />
+    <highway type="service"      string="rue de service" />
+    <highway type="track"        string="chemin" />
+    <highway type="cycleway"     string="voie cyclable" />
+    <highway type="path"         string="sentier" />
+    <highway type="steps"        string="escalier" />
+    <highway type="ferry"        string="ferry" />
+
+    <!-- The type of route -->
+    <route type="shortest" string="le plus court" /> <!-- For the description and route name -->
+    <route type="quickest" string="le plus rapide" /> <!-- For the description and route name -->
+
+    <!-- HTML output -->
+    <output-html>
+      <waypoint type="waypoint"   string="Etape" /> <!-- For the chosen waypoints -->
+      <waypoint type="junction"   string="Croisement" /> <!-- For the interesting junctions -->
+      <waypoint type="roundabout" string="rond-point" /> <!-- For roundabouts -->
+
+      <title text="Itinéraire %s" /> <!-- %s = [shortest|quickest] -->
+
+      <start   string="Débute" text="à %s, direction %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [heading] -->
+      <node    string="à" text="%s, aller %s direction %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [turn], 3rd %s = [heading] -->
+      <rbnode  string="Quitter" text="%s, prendre le %s sortir direction %s" /> <!-- 1st %s = [roundabout], 2nd %s = [first|second|...], 3rd %s = [heading] -->
+      <segment string="Suivre" text="%s pendant %.3f km, %.1f min" /> <!-- 1st %s = street name -->
+      <stop    string="S'arrêter" text="à %s" /> <!-- 1st %s = [waypoint|junction] -->
+      <total   string="Total" text="%.1f km, %.0f minutes" />
+    </output-html>
+
+    <!-- GPX output -->
+    <output-gpx>
+      <waypoint type="start" string="DEBUT" /> <!-- For the first route waypoint -->
+      <waypoint type="inter" string="INTER" /> <!-- For the intermediate route waypoints -->
+      <waypoint type="trip" string="POINT" /> <!-- For the other route points -->
+      <waypoint type="finish" string="FINAL"/> <!-- For the last route waypoint -->
+
+      <desc  text="Itinéraire %s entre les étapes 'début' et 'fin'" /> <!-- %s = [shortest|quickest] -->
+      <name  text="Itinéraire %s" /> <!-- %s = [shortest|quickest] -->
+      <step  text="%s sur '%s' pendant %.3f km, %.1f min" /> <!-- 1st %s = [turn], 2nd %s = street name -->
+      <final text="Trajet total %.1f km, %.0f minutes" />
+    </output-gpx>
+
+  </language>
+
+  <language lang="hu">
+
+    <!-- Copyright of the data being routed, not of this file  -->
+    <copyright>
+      <creator string="Készítő" text="Routino - http://www.routino.org/" />
+      <source  string="Forrás" text="Openstreetmap adatok alapján http://www.openstreetmap.org/" />
+      <license string="Liszenc" text="http://www.openstreetmap.org/copyright" />
+    </copyright>
+
+    <!-- Turn directions, 0 = ahead, -2 = left, +/-4 = behind, +2 = right -->
+    <turn direction="-4" string="Nagyon élesen balra" />
+    <turn direction="-3" string="Élesen balra" />
+    <turn direction="-2" string="Balra" />
+    <turn direction="-1" string="Balra tarts" />
+    <turn direction="0"  string="Egyenesen" />
+    <turn direction="1"  string="Jobbra tarts" />
+    <turn direction="2"  string="Jobbra" />
+    <turn direction="3"  string="Élesen jobbra" />
+    <turn direction="4"  string="Nagyon élesen jobbra" />
+
+    <!-- Heading directions, 0 = North, -2 = West, +/-4 = South, +2 = East -->
+    <heading direction="-4" string="dél" />
+    <heading direction="-3" string="délnyugat" />
+    <heading direction="-2" string="nyugat" />
+    <heading direction="-1" string="északnyugat" />
+    <heading direction="0"  string="észak" />
+    <heading direction="1"  string="északkelet" />
+    <heading direction="2"  string="kelet" />
+    <heading direction="3"  string="délkelet" />
+    <heading direction="4"  string="dél" />
+
+    <!-- Ordinals, 1 = first, 2 = second ... -->
+    <ordinal number="1"  string="első" />
+    <ordinal number="2"  string="második" />
+    <ordinal number="3"  string="harmadik" />
+    <ordinal number="4"  string="negyedik" />
+    <ordinal number="5"  string="ötödik" />
+    <ordinal number="6"  string="hatodik" />
+    <ordinal number="7"  string="hetedik" />
+    <ordinal number="8"  string="nyolcadik" />
+    <ordinal number="9"  string="kilencedik" />
+    <ordinal number="10" string="tizedik" />
+
+    <!-- Highway names -->
+    <highway type="motorway"     string="autópálya" />
+    <highway type="trunk"        string="autóút" />
+    <highway type="primary"      string="főút" />
+    <highway type="secondary"    string="összekötőút" />
+    <highway type="tertiary"     string="bekötőút" />
+    <highway type="unclassified" string="egyéb közút" />
+    <highway type="residential"  string="lakóút" />
+    <highway type="service"      string="szervízút" />
+    <highway type="track"        string="földút" />
+    <highway type="cycleway"     string="kerékpárút" />
+    <highway type="path"         string="ösvény" />
+    <highway type="steps"        string="lépcső" />
+    <highway type="ferry"        string="komp" />
+
+    <!-- The type of route -->
+    <route type="shortest" string="Legrövidebb" /> <!-- For the description and route name -->
+    <route type="quickest" string="Leggyorsabb" /> <!-- For the description and route name -->
+
+    <!-- HTML output -->
+    <output-html>
+      <waypoint type="waypoint"   string="Útpont" /> <!-- For the chosen waypoints -->
+      <waypoint type="junction"   string="Kereszteződés" /> <!-- For the interesting junctions -->
+      <waypoint type="roundabout" string="Körforgalom" /> <!-- For roundabouts -->
+
+      <title text="%s útvonal" /> <!-- %s = [shortest|quickest] -->
+
+      <start   string="Indulás" text="%s, %s felé" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [heading] -->
+      <node    string="Itt" text="%s, menj %s %s felé" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [turn], 3rd %s = [heading] -->
+      <rbnode  string="Kijárat" text="%s, %s kijárat %s felé" /> <!-- 1st %s = [roundabout], 2nd %s = [first|second|...], 3rd %s = [heading] -->
+      <segment string="Erre" text="%s, %.3f km, %.1f perc" /> <!-- 1st %s = street name -->
+      <!-- TRANSLATION REQUIRED: stop    string="Cél" text="At %s" / --> <!-- 1st %s = [waypoint|junction] -->
+      <total   string="Összesen" text="%.1f km, %.0f perc" />
+    </output-html>
+
+    <!-- GPX output -->
+    <output-gpx>
+      <waypoint type="start" string="Indulás" /> <!-- For the first route waypoint -->
+      <!-- TRANSLATION REQUIRED: waypoint type="inter" string="INTER" / --> <!-- For the intermediate route waypoints -->
+      <waypoint type="trip" string="Utazás" /> <!-- For the other route points -->
+      <!-- TRANSLATION REQUIRED: waypoint type="finish" string="FINISH"/ --> <!-- For the last route waypoint -->
+
+      <desc  text="%s útvonal a kezdő és utolsó pont között" /> <!-- %s = [shortest|quickest] -->
+      <!-- TRANSLATION REQUIRED: name  text="%s route" / --> <!-- %s = [shortest|quickest] -->
+      <!-- TRANSLATION REQUIRED: step  text="%s on '%s' for %.3f km, %.1f min" / --> <!-- 1st %s = [turn], 2nd %s = street name -->
+      <final text="Az egész út %.1f km, %.0f perc" />
+    </output-gpx>
+
+  </language>
+
+  <language lang="nl">
+
+    <!-- Copyright of the data being routed, not of this file  -->
+    <copyright>
+      <creator string="Creator" text="Routino - http://www.routino.org/" />
+      <source  string="Source" text="Gebouwd op OpenStreetMap data van http://www.openstreetmap.org/" />
+      <license string="License" text="http://www.openstreetmap.org/copyright" />
+    </copyright>
+
+    <!-- Turn directions, 0 = ahead, -2 = left, +/-4 = behind, +2 = right -->
+    <turn direction="-4" string="Haarspeld naar links" />
+    <turn direction="-3" string="Scherp links" />
+    <turn direction="-2" string="Links" />
+    <turn direction="-1" string="Half links" />
+    <turn direction="0"  string="Rechtdoor" />
+    <turn direction="1"  string="Half rechts" />
+    <turn direction="2"  string="Rechts" />
+    <turn direction="3"  string="Scherp rechts" />
+    <turn direction="4"  string="Haarspeld naar rechts" />
+
+    <!-- Heading directions, 0 = North, -2 = West, +/-4 = South, +2 = East -->
+    <heading direction="-4" string="Zuid" />
+    <heading direction="-3" string="Zuid-West" />
+    <heading direction="-2" string="West" />
+    <heading direction="-1" string="Noord-West" />
+    <heading direction="0"  string="Noord" />
+    <heading direction="1"  string="Noord-Oost" />
+    <heading direction="2"  string="Oost" />
+    <heading direction="3"  string="Zuid-Oost" />
+    <heading direction="4"  string="Zuid" />
+
+    <!-- Ordinals, 1 = first, 2 = second ... -->
+    <ordinal number="1"  string="Eerste" />
+    <ordinal number="2"  string="Tweede" />
+    <ordinal number="3"  string="Derde" />
+    <ordinal number="4"  string="Vierde" />
+    <ordinal number="5"  string="Vijfde" />
+    <ordinal number="6"  string="Zesde" />
+    <ordinal number="7"  string="Zevende" />
+    <ordinal number="8"  string="Achtste" />
+    <ordinal number="9"  string="Negende" />
+    <ordinal number="10" string="Tiende" />
+
+    <!-- Highway names -->
+    <highway type="motorway"     string="Autostrade" />
+    <highway type="trunk"        string="Autoweg" />
+    <highway type="primary"      string="Provinciale weg" />
+    <highway type="secondary"    string="Nationale weg" />
+    <highway type="tertiary"     string="Doorgangsweg" />
+    <highway type="unclassified" string="Niet geclassificeerd" />
+    <highway type="residential"  string="Woongebied" />
+    <highway type="service"      string="Toegangsweg" />
+    <highway type="track"        string="Veldweg" />
+    <highway type="cycleway"     string="Fietspad" />
+    <highway type="path"         string="Pad" />
+    <highway type="steps"        string="Trap" />
+    <highway type="ferry"        string="Veerboot" />
+
+    <!-- The type of route -->
+    <route type="shortest" string="Kortste" /> <!-- For the description and route name -->
+    <route type="quickest" string="Snelste" /> <!-- For the description and route name -->
+
+    <!-- HTML output -->
+    <output-html>
+      <waypoint type="waypoint"   string="Punt" /> <!-- For the chosen waypoints -->
+      <waypoint type="junction"   string="de splitsing" /> <!-- For the interesting junctions -->
+      <waypoint type="roundabout" string="rotonde" /> <!-- For roundabouts -->
+
+      <title text="%s Route" /> <!-- %s = [shortest|quickest] -->
+
+      <start   string="Start" text="Bij %s neemt u de richting %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [heading] -->
+      <node    string="Bij" text="Bij %s gaat u %s richting %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [turn], 3rd %s = [heading] -->
+      <rbnode  string="Leave" text="Aan de %s, neem de %s afslag richting %s" /> <!-- 1st %s = [roundabout], 2nd %s = [first|second|...], 3rd %s = [heading] -->
+      <segment string="Volg" text="Volgt u de %s voor %.3f km %.1f min" /> <!-- 1st %s = street name -->
+      <stop    string="Stop" text="U bent bij  %s aangekomen" /> <!-- 1st %s = [waypoint|junction] -->
+      <total   string="Totaal" text="%.1f km, %.0f minuten" />
+    </output-html>
+
+    <!-- GPX output -->
+    <output-gpx>
+      <waypoint type="start" string="START" /> <!-- For the first route waypoint -->
+      <waypoint type="inter" string="INTER" /> <!-- For the intermediate route waypoints -->
+      <waypoint type="trip" string="TRIP" /> <!-- For the other route points -->
+      <waypoint type="finish" string="FINISH"/> <!-- For the last route waypoint -->
+
+      <desc  text="%s Route tussen 'Start' und 'Finish'" /> <!-- %s = [shortest|quickest] -->
+      <name  text="%s Route" /> <!-- %s = [shortest|quickest] -->
+      <step  text="%s op '%s' voor %.3f km, %.1f min" /> <!-- 1st %s = [turn], 2nd %s = street name -->
+      <final text="Totaal trip  %.1f km, %.0f minuten" />
+    </output-gpx>
+
+  </language>
+
+  <language lang="ru">
+
+    <!-- Copyright of the data being routed, not of this file  -->
+    <copyright>
+      <creator string="Автор" text="Routino - http://www.routino.org/" />
+      <source  string="Источник" text="Использованы данные OpenStreetMap http://www.openstreetmap.org/" />
+      <license string="Лицензия" text="http://www.openstreetmap.org/copyright" />
+    </copyright>
+
+    <!-- Turn directions, 0 = ahead, -2 = left, +/-4 = behind, +2 = right -->
+    <turn direction="-4" string="очень крутой поворот налево" />
+    <turn direction="-3" string="крутой поворот налево" />
+    <turn direction="-2" string="налево" />
+    <turn direction="-1" string="плавно налево" />
+    <turn direction="0"  string="прямо" />
+    <turn direction="1"  string="плавно направо" />
+    <turn direction="2"  string="направо" />
+    <turn direction="3"  string="крутой поворот направо" />
+    <turn direction="4"  string="очень крутой поворот направо" />
+
+    <!-- Heading directions, 0 = North, -2 = West, +/-4 = South, +2 = East -->
+    <heading direction="-4" string="юг" />
+    <heading direction="-3" string="юго-запад" />
+    <heading direction="-2" string="запад" />
+    <heading direction="-1" string="северо-запад" />
+    <heading direction="0"  string="север" />
+    <heading direction="1"  string="северо-восток" />
+    <heading direction="2"  string="восток" />
+    <heading direction="3"  string="юго-восток" />
+    <heading direction="4"  string="юг" />
+
+    <!-- Ordinals, 1 = first, 2 = second ... -->
+    <ordinal number="1"  string="Первый" />
+    <ordinal number="2"  string="Второй" />
+    <ordinal number="3"  string="Третий" />
+    <ordinal number="4"  string="Четвертый" />
+    <ordinal number="5"  string="Пятый" />
+    <ordinal number="6"  string="Шестой" />
+    <ordinal number="7"  string="Седьмой" />
+    <ordinal number="8"  string="Восьмой" />
+    <ordinal number="9"  string="Девятый" />
+    <ordinal number="10" string="Десятый" />
+
+    <!-- Highway names -->
+    <highway type="motorway"     string="автомагистраль" />
+    <highway type="trunk"        string="международная трасса" />
+    <highway type="primary"      string="дорога регионального значения" />
+    <highway type="secondary"    string="дорога областного значения" />
+    <highway type="tertiary"     string="дорога районного значения" />
+    <highway type="unclassified" string="дорога местного значения" />
+    <highway type="residential"  string="улица" />
+    <highway type="service"      string="проезд" />
+    <highway type="track"        string="дорога с/х назначения" />
+    <highway type="cycleway"     string="велодорожка" />
+    <highway type="path"         string="тропинка" />
+    <highway type="steps"        string="лестница" />
+    <highway type="ferry"        string="паром" />
+
+    <!-- The type of route -->
+    <route type="shortest" string="Короткий" /> <!-- For the description and route name -->
+    <route type="quickest" string="Быстрый" /> <!-- For the description and route name -->
+
+    <!-- HTML output -->
+    <output-html>
+      <waypoint type="waypoint"   string="путевая точка" /> <!-- For the chosen waypoints -->
+      <waypoint type="junction"   string="перекрестке" /> <!-- For the interesting junctions -->
+      <!-- TRANSLATION REQUIRED: waypoint type="roundabout" string="Roundabout" / --> <!-- For roundabouts -->
+
+      <title text="%s маршрут" /> <!-- %s = [shortest|quickest] -->
+
+      <start   string="Старт" text=" %s, на %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [heading] -->
+      <node    string="на" text="%s, %s,  на %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [turn], 3rd %s = [heading] -->
+      <!-- TRANSLATION REQUIRED: rbnode  string="Покинуть" text="%s, take the %s exit heading %s" / --> <!-- 1st %s = [roundabout], 2nd %s = [first|second|...], 3rd %s = [heading] -->
+      <segment string="Следуйте" text="по %s %.3f км, %.1f мин" /> <!-- 1st %s = street name -->
+      <stop    string="Стоп" text=" %s" /> <!-- 1st %s = [waypoint|junction] -->
+      <total   string="Всего" text="%.1f км, %.0f минут" />
+    </output-html>
+
+    <!-- GPX output -->
+    <output-gpx>
+      <waypoint type="start" string="Старт" /> <!-- For the first route waypoint -->
+      <waypoint type="inter" string="INTER" /> <!-- For the intermediate route waypoints -->
+      <waypoint type="trip" string="TRIP" /> <!-- For the other route points -->
+      <waypoint type="finish" string="Финиш"/> <!-- For the last route waypoint -->
+
+      <desc  text="%s маршрут от 'Старта' до 'Финиша'" /> <!-- %s = [shortest|quickest] -->
+      <name  text="%s маршрут" /> <!-- %s = [shortest|quickest] -->
+      <step  text="на %s по '%s' %.3f км, %.1f мин" /> <!-- 1st %s = [turn], 2nd %s = street name -->
+      <final text="Всего - %.1f км, продолжительность - %.0f минут" />
+    </output-gpx>
+
+  </language>
+
+</routino-translations>
diff --git a/3rdparty/Routino/xml/routino-translations.xsd b/3rdparty/Routino/xml/routino-translations.xsd
new file mode 100644
index 0000000..1c5646e
--- /dev/null
+++ b/3rdparty/Routino/xml/routino-translations.xsd
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- ============================================================
+     An XML Schema Definition for the Routino translations XML format
+
+     Part of the Routino routing software.
+     ============================================================
+     This file Copyright 2010-2012 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+  <!-- The top level Routino translation -->
+
+  <xsd:element name="routino-translations" type="RoutinoTranslationsType"/>
+
+  <xsd:complexType name="RoutinoTranslationsType">
+    <xsd:sequence>
+      <xsd:element name="language" type="LanguageType" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="LanguageType">
+    <xsd:sequence>
+      <xsd:element name="copyright"   type="CopyrightType" minOccurs="0"/>
+      <xsd:element name="turn"        type="TurnType"      minOccurs="0" maxOccurs="9"/>
+      <xsd:element name="heading"     type="HeadingType"   minOccurs="0" maxOccurs="9"/>
+      <xsd:element name="ordinal"     type="OrdinalType"   minOccurs="0" maxOccurs="10"/>
+      <xsd:element name="highway"     type="HighwayType"   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="route"       type="RouteType"     minOccurs="0" maxOccurs="2"/>
+      <xsd:element name="output-html" type="HTMLType"      minOccurs="0"/>
+      <xsd:element name="output-gpx"  type="GPXType"       minOccurs="0"/>
+    </xsd:sequence>
+    <xsd:attribute name="lang"        type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The copyright information (of the generated output, not of this file) -->
+
+  <xsd:complexType name="CopyrightType">
+    <xsd:sequence>
+      <xsd:element name="creator"   type="CopyrightCreatorType" minOccurs="0"/>
+      <xsd:element name="source"    type="CopyrightSourceType"  minOccurs="0"/>
+      <xsd:element name="license"   type="CopyrightLicenseType" minOccurs="0"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="CopyrightCreatorType">
+    <xsd:attribute name="string"  type="xsd:string"/>
+    <xsd:attribute name="text"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="CopyrightSourceType">
+    <xsd:attribute name="string"  type="xsd:string"/>
+    <xsd:attribute name="text"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="CopyrightLicenseType">
+    <xsd:attribute name="string"  type="xsd:string"/>
+    <xsd:attribute name="text"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The turn, heading, ordinal, highway and route strings -->
+
+  <xsd:complexType name="TurnType">
+    <xsd:attribute name="direction" type="xsd:string"/>
+    <xsd:attribute name="string"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HeadingType">
+    <xsd:attribute name="direction" type="xsd:string"/>
+    <xsd:attribute name="string"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="OrdinalType">
+    <xsd:attribute name="number"    type="xsd:string"/>
+    <xsd:attribute name="string"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HighwayType">
+    <xsd:attribute name="type"      type="xsd:string"/>
+    <xsd:attribute name="string"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="RouteType">
+    <xsd:attribute name="type"      type="xsd:string"/>
+    <xsd:attribute name="string"    type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The HTML output strings -->
+
+  <xsd:complexType name="HTMLType">
+    <xsd:sequence>
+      <xsd:element name="waypoint" type="HTMLWaypointType" maxOccurs="3"/>
+      <xsd:element name="title"    type="HTMLTitleType"/>
+      <xsd:element name="start"    type="HTMLStartType"/>
+      <xsd:element name="node"     type="HTMLNodeType"/>
+      <xsd:element name="rbnode"   type="HTMLRBNodeType"/>
+      <xsd:element name="segment"  type="HTMLSegmentType"/>
+      <xsd:element name="stop"     type="HTMLStopType"/>
+      <xsd:element name="total"    type="HTMLTotalType"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="HTMLWaypointType">
+    <xsd:attribute name="type"   type="xsd:string"/>
+    <xsd:attribute name="string" type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HTMLTitleType">
+    <xsd:attribute name="text"  type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HTMLStartType">
+    <xsd:attribute name="string" type="xsd:string"/>
+    <xsd:attribute name="text"   type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HTMLNodeType">
+    <xsd:attribute name="string" type="xsd:string"/>
+    <xsd:attribute name="text"   type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HTMLRBNodeType">
+    <xsd:attribute name="string" type="xsd:string"/>
+    <xsd:attribute name="text"   type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HTMLSegmentType">
+    <xsd:attribute name="string" type="xsd:string"/>
+    <xsd:attribute name="text"   type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HTMLStopType">
+    <xsd:attribute name="string" type="xsd:string"/>
+    <xsd:attribute name="text"   type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="HTMLTotalType">
+    <xsd:attribute name="string" type="xsd:string"/>
+    <xsd:attribute name="text"   type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The GPX output strings -->
+
+  <xsd:complexType name="GPXType">
+    <xsd:sequence>
+      <xsd:element name="waypoint" type="GPXWaypointType" maxOccurs="4"/>
+      <xsd:element name="desc"     type="GPXDescType"/>
+      <xsd:element name="name"     type="GPXNameType"/>
+      <xsd:element name="step"     type="GPXStepType"/>
+      <xsd:element name="final"    type="GPXFinalType"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="GPXWaypointType">
+    <xsd:attribute name="type"   type="xsd:string"/>
+    <xsd:attribute name="string" type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="GPXDescType">
+    <xsd:attribute name="text"  type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="GPXNameType">
+    <xsd:attribute name="text"  type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="GPXStepType">
+    <xsd:attribute name="text"  type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="GPXFinalType">
+    <xsd:attribute name="text"  type="xsd:string"/>
+  </xsd:complexType>
+
+</xsd:schema>
diff --git a/3rdparty/Routino/xml/scripts/drive.pl b/3rdparty/Routino/xml/scripts/drive.pl
new file mode 100755
index 0000000..9a391b9
--- /dev/null
+++ b/3rdparty/Routino/xml/scripts/drive.pl
@@ -0,0 +1,60 @@
+#!/usr/bin/perl
+#
+# Special case tagging rule generator.
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2011-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+
+# Process the input
+
+while(<STDIN>)
+  {
+   if(m%</way>%)
+     {
+      print "    <!-- Special case for motor vehicles -->\n";
+      print "\n";
+      print "    <if>\n";
+      print "      <output k=\"foot\"       v=\"no\"/>\n";
+      print "      <output k=\"horse\"      v=\"no\"/>\n";
+      print "      <output k=\"wheelchair\" v=\"no\"/>\n";
+      print "      <output k=\"bicycle\"    v=\"no\"/>\n";
+      print "\n";
+      print "      <output k=\"bridge\"        v=\"no\"/>\n";
+      print "      <output k=\"tunnel\"        v=\"no\"/>\n";
+      print "      <output k=\"footroute\"     v=\"no\"/>\n";
+      print "      <output k=\"bicycleroute\"  v=\"no\"/>\n";
+      print "      <output k=\"cyclebothways\" v=\"no\"/>\n";
+      print "    </if>\n";
+      print "\n";
+     }
+
+   if(m%</relation>%)
+     {
+      print "    <!-- Special case for motor vehicles -->\n";
+      print "\n";
+      print "    <if>\n";
+      print "      <output k=\"footroute\"    v=\"no\"/>\n";
+      print "      <output k=\"bicycleroute\" v=\"no\"/>\n";
+      print "    </if>\n";
+      print "\n";
+     }
+
+   print;
+  }
diff --git a/3rdparty/Routino/xml/scripts/ride.pl b/3rdparty/Routino/xml/scripts/ride.pl
new file mode 100755
index 0000000..954aeaa
--- /dev/null
+++ b/3rdparty/Routino/xml/scripts/ride.pl
@@ -0,0 +1,62 @@
+#!/usr/bin/perl
+#
+# Special case tagging rule generator.
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2011-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+
+# Process the input
+
+while(<STDIN>)
+  {
+   if(m%</way>%)
+     {
+      print "    <!-- Special case for riding -->\n";
+      print "\n";
+      print "    <if>\n";
+      print "      <output k=\"foot\"       v=\"no\"/>\n";
+      print "      <output k=\"wheelchair\" v=\"no\"/>\n";
+      print "      <output k=\"moped\"      v=\"no\"/>\n";
+      print "      <output k=\"motorcycle\" v=\"no\"/>\n";
+      print "      <output k=\"motorcar\"   v=\"no\"/>\n";
+      print "      <output k=\"goods\"      v=\"no\"/>\n";
+      print "      <output k=\"hgv\"        v=\"no\"/>\n";
+      print "      <output k=\"psv\"        v=\"no\"/>\n";
+      print "\n";
+      print "      <output k=\"bridge\" v=\"no\"/>\n";
+      print "      <output k=\"tunnel\" v=\"no\"/>\n";
+      print "\n";
+      print "      <output k=\"footroute\" v=\"no\"/>\n";
+      print "    </if>\n";
+      print "\n";
+     }
+
+   if(m%</relation>%)
+     {
+      print "    <!-- Special case for riding -->\n";
+      print "\n";
+      print "    <if>\n";
+      print "      <output k=\"footroute\" v=\"no\"/>\n";
+      print "    </if>\n";
+      print "\n";
+     }
+
+   print;
+  }
diff --git a/3rdparty/Routino/xml/scripts/walk.pl b/3rdparty/Routino/xml/scripts/walk.pl
new file mode 100755
index 0000000..3ece70d
--- /dev/null
+++ b/3rdparty/Routino/xml/scripts/walk.pl
@@ -0,0 +1,67 @@
+#!/usr/bin/perl
+#
+# Special case tagging rule generator.
+#
+# Part of the Routino routing software.
+#
+# This file Copyright 2011-2014 Andrew M. Bishop
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+use strict;
+
+# Process the input
+
+while(<STDIN>)
+  {
+   if(m%</way>%)
+     {
+      print "    <!-- Special case for walking -->\n";
+      print "\n";
+      print "    <if>\n";
+      print "      <output k=\"horse\"      v=\"no\"/>\n";
+      print "      <output k=\"bicycle\"    v=\"no\"/>\n";
+      print "      <output k=\"moped\"      v=\"no\"/>\n";
+      print "      <output k=\"motorcycle\" v=\"no\"/>\n";
+      print "      <output k=\"motorcar\"   v=\"no\"/>\n";
+      print "      <output k=\"goods\"      v=\"no\"/>\n";
+      print "      <output k=\"hgv\"        v=\"no\"/>\n";
+      print "      <output k=\"psv\"        v=\"no\"/>\n";
+      print "\n";
+      print "      <output k=\"oneway\" v=\"no\"/>\n";
+      print "\n";
+      print "      <output k=\"bridge\" v=\"no\"/>\n";
+      print "      <output k=\"tunnel\" v=\"no\"/>\n";
+      print "\n";
+      print "      <output k=\"bicycleroute\"  v=\"no\"/>\n";
+      print "      <output k=\"cyclebothways\" v=\"no\"/>\n";
+      print "    </if>\n";
+      print "\n";
+     }
+
+   if(m%</relation>%)
+     {
+      print "    <!-- Special case for walking -->\n";
+      print "\n";
+      print "    <if>\n";
+      print "      <output k=\"restriction\" v=\"no\"/>\n";
+      print "\n";
+      print "      <output k=\"bicycleroute\" v=\"no\"/>\n";
+      print "    </if>\n";
+      print "\n";
+     }
+
+   print;
+  }
diff --git a/3rdparty/Routino/xml/xsd.xsd b/3rdparty/Routino/xml/xsd.xsd
new file mode 100644
index 0000000..5409524
--- /dev/null
+++ b/3rdparty/Routino/xml/xsd.xsd
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!-- ============================================================
+     $Header: /home/amb/CVS/routino/xml/xsd.xsd,v 1.1 2010-03-28 15:27:05 amb Exp $
+
+     An XML Schema Definition for the XML Schema Definition XML format
+
+     Not a full definition but sufficient to allow the xsd-to-xmlparser to
+     read it to bootstrap itself - a program to read in other files in the
+     same format to create more XML parsers for other useful things.
+     ============================================================
+     This file Copyright 2010 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+  <!-- The top level xsd:schema element -->
+
+  <xsd:element name="xsd:schema" type="schemaType"/>
+
+  <xsd:complexType name="schemaType">
+    <xsd:sequence>
+      <xsd:element name="xsd:element"        type="elementType"/>
+      <xsd:element name="xsd:complexType"    type="complexType"    minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="elementFormDefault" type="xsd:string"/>
+    <xsd:attribute name="xmlns:xsd"          type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The second level xsd:element and xsd:complexType elements -->
+
+  <xsd:complexType name="elementType">
+    <xsd:attribute name="name"               type="xsd:string"/>
+    <xsd:attribute name="type"               type="xsd:string"/>
+    <xsd:attribute name="minOccurs"          type="xsd:string"/>
+    <xsd:attribute name="maxOccurs"          type="xsd:string"/>
+  </xsd:complexType>
+
+  <xsd:complexType name="complexType">
+    <xsd:sequence>
+      <xsd:element name="xsd:sequence"       type="sequenceType"   minOccurs="0"/>
+      <xsd:element name="xsd:attribute"      type="attributeType"  minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="name"               type="xsd:string"/>
+  </xsd:complexType>
+
+  <!-- The third level elements and their contents -->
+
+  <xsd:complexType name="sequenceType">
+    <xsd:sequence>
+      <xsd:element name="xsd:element"        type="elementType"    minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
+  <xsd:complexType name="attributeType">
+    <xsd:attribute name="name"               type="xsd:string"/>
+    <xsd:attribute name="type"               type="xsd:string"/>
+  </xsd:complexType>
+
+</xsd:schema>
diff --git a/3rdparty/RoutinoLib/CMakeLists.txt b/3rdparty/RoutinoLib/CMakeLists.txt
new file mode 100644
index 0000000..e5582f0
--- /dev/null
+++ b/3rdparty/RoutinoLib/CMakeLists.txt
@@ -0,0 +1,186 @@
+
+option(ROUTINO_BUILD_SLIM_VERSION "Routino: Build slim version" OFF)
+
+include_directories(
+  ${CMAKE_BINARY_DIR}
+  ${CMAKE_CURRENT_BINARY_DIR}
+  ${CMAKE_SOURCE_DIR}/3rdparty/Routino/src
+)
+
+if(MSVC)
+  add_definitions(-D_CRT_SECURE_NO_DEPRECATE -Dinline=__inline)
+endif(MSVC)
+
+if(UNIX)
+add_definitions(-Wall -std=c99 -ffast-math -D_FILE_OFFSET_BITS=64 -D_POSIX_C_SOURCE=200809L -pedantic)
+endif(UNIX)
+
+add_definitions(-DROUTINO_DATADIR="./" -DLIBROUTINO -DUSE_GZIP)
+
+if(ROUTINO_BUILD_SLIM_VERSION)
+    add_definitions(-DSLIM=1)
+else(ROUTINO_BUILD_SLIM_VERSION)
+    add_definitions(-DSLIM=0)
+endif(ROUTINO_BUILD_SLIM_VERSION)
+
+########### routino library ###########
+set(APPNAME routino)
+
+set(SRCS_${APPNAME}
+    routino.c
+    binout.c
+    ../Routino/src/fakes.c
+    ../Routino/src/files.c
+    ../Routino/src/logging.c
+    ../Routino/src/nodes.c
+    ../Routino/src/optimiser.c
+    ../Routino/src/profiles.c
+    ../Routino/src/queue.c
+    ../Routino/src/relations.c   
+    ../Routino/src/results.c
+    ../Routino/src/segments.c
+    ../Routino/src/translations.c
+    ../Routino/src/types.c
+    ../Routino/src/ways.c
+    ../Routino/src/xmlparse.c
+)
+
+if(MSVC)
+set(SRCS_${APPNAME}
+    ${SRCS_${APPNAME}}
+    ../Routino/src/mman-win32.c
+)
+endif(MSVC)
+
+set(HDRS_${APPNAME}
+    routino.h
+    binout.h
+    ../Routino/src/cache.h
+    ../Routino/src/fakes.h
+    ../Routino/src/files.h
+    ../Routino/src/functions.h
+    ../Routino/src/logging.h
+    ../Routino/src/nodes.h
+    ../Routino/src/profiles.h    
+    ../Routino/src/relations.h    
+    ../Routino/src/results.h
+    ../Routino/src/segments.h
+    ../Routino/src/translations.h
+    ../Routino/src/types.h
+    ../Routino/src/ways.h
+    ../Routino/src/xmlparse.h
+)
+
+if(MSVC)
+set(HDRS_${APPNAME}
+    ${HDRS_${APPNAME}}
+    ../Routino/src/mman-win32.h
+)
+endif(MSVC)
+
+
+set(ALLINP_${APPNAME}
+    ${SRCS_${APPNAME}}
+    ${HDRS_${APPNAME}}
+)
+
+add_library(${APPNAME} STATIC ${ALLINP_${APPNAME}})
+if(UNIX)
+target_link_libraries(${APPNAME} m)
+endif(UNIX)
+
+
+########### planet splitter ###########
+
+set(APPNAME planetsplitter)
+
+set(SRCS_${APPNAME}
+    ../Routino/src/planetsplitter.c
+    ../Routino/src/errorlog.c
+    ../Routino/src/errorlogx.c
+    ../Routino/src/logerror.c
+    ../Routino/src/nodesx.c
+    ../Routino/src/osmo5mparse.c
+    ../Routino/src/osmparser.c
+    ../Routino/src/osmpbfparse.c
+    ../Routino/src/osmxmlparse.c
+    ../Routino/src/prunex.c
+    ../Routino/src/relationsx.c
+    ../Routino/src/segmentsx.c
+    ../Routino/src/sorting.c
+    ../Routino/src/superx.c
+    ../Routino/src/tagging.c
+    ../Routino/src/uncompress.c
+    ../Routino/src/visualiser.c
+    ../Routino/src/waysx.c
+)
+
+set(HDRS_${APPNAME}
+    ../Routino/src/errorlog.h
+    ../Routino/src/errorlogx.h
+    ../Routino/src/nodesx.h
+    ../Routino/src/osmparser.h
+    ../Routino/src/prunex.h
+    ../Routino/src/relationsx.h
+    ../Routino/src/segmentsx.h
+    ../Routino/src/sorting.h
+    ../Routino/src/superx.h
+    ../Routino/src/tagging.h
+    ../Routino/src/typesx.h
+    ../Routino/src/uncompress.h
+    ../Routino/src/visualiser.h
+    ../Routino/src/waysx.h
+)
+
+set(ALLINP_${APPNAME}
+    ${SRCS_${APPNAME}}
+    ${HDRS_${APPNAME}}
+)
+
+INCLUDE_DIRECTORIES(
+    ${ZLIB_DEV_PATH}
+)
+
+LINK_DIRECTORIES(
+    ${ZLIB_DEV_PATH}
+)
+
+add_executable(${APPNAME} ${ALLINP_${APPNAME}})
+
+if(MSVC)
+target_link_libraries(${APPNAME} routino zlibstat)
+endif(MSVC)
+
+if(UNIX)
+target_link_libraries(${APPNAME} routino z)
+endif(UNIX)
+
+
+install(
+    TARGETS
+      ${APPNAME}
+    DESTINATION
+      ${BIN_INSTALL_DIR}
+)
+
+
+########### router ###########
+
+set(APPNAME router)
+
+set(SRCS_${APPNAME}
+    ../Routino/src/router.c
+    ../Routino/src/output.c
+)
+
+set(HDRS_${APPNAME}
+)
+
+set(ALLINP_${APPNAME}
+    ${SRCS_${APPNAME}}
+    ${HDRS_${APPNAME}}
+)
+
+add_executable(${APPNAME} ${ALLINP_${APPNAME}})
+target_link_libraries(${APPNAME} routino)
+
diff --git a/3rdparty/RoutinoLib/binout.c b/3rdparty/RoutinoLib/binout.c
new file mode 100644
index 0000000..f734dce
--- /dev/null
+++ b/3rdparty/RoutinoLib/binout.c
@@ -0,0 +1,570 @@
+/**********************************************************************************************
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+**********************************************************************************************/
+
+#include "binout.h"
+#include "fakes.h"
+#include "nodes.h"
+#include "profiles.h"
+#include "results.h"
+#include "segments.h"
+#include "translations.h"
+#include "types.h"
+#include "ways.h"
+#include "xmlparse.h"
+
+#include <stdlib.h>
+
+
+/* Global variables */
+
+/*+ The option to calculate the quickest route insted of the shortest. +*/
+extern int option_quickest;
+
+/*+ The options to select the format of the output. +*/
+extern int option_html,option_gpx_track,option_gpx_route,option_text,option_text_all,option_stdout;
+
+
+/* Local variables */
+
+/*+ Heuristics for determining if a junction is important. +*/
+static const char junction_other_way[Highway_Count][Highway_Count]=
+{  /* M, T, P, S, T, U, R, S, T, C, P, S, F = Way type of route not taken */
+    {   1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },/* Motorway     */
+    {   1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },/* Trunk        */
+    {   1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },/* Primary      */
+    {   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },/* Secondary    */
+    {   1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 },/* Tertiary     */
+    {   1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1 },/* Unclassified */
+    {   1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1 },/* Residential  */
+    {   1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1 },/* Service      */
+    {   1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1 },/* Track        */
+    {   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1 },/* Cycleway     */
+    {   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },/* Path         */
+    {   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },/* Steps        */
+    {   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },/* Ferry        */
+};
+
+
+/*++++++++++++++++++++++++++++++++++++++
+   Print the optimum route between two nodes.
+
+   Results **results The set of results to print (consecutive in array even if not consecutive waypoints).
+
+   int nresults The number of results in the list.
+
+   Nodes *nodes The set of nodes to use.
+
+   Segments *segments The set of segments to use.
+
+   Ways *ways The set of ways to use.
+
+   Profile *profile The profile containing the transport type, speeds and allowed highways.
+++++++++++++++++++++++++++++++++++++++*/
+T_RoutinoRoute * SimplifyResult(Results ** results, int nresults, Nodes *nodes, Segments *segments, Ways *ways, Profile *profile)
+{
+    FILE *textfile = stdout;
+
+    index_t prev_node=NO_NODE;
+    distance_t cum_distance=0;
+    duration_t cum_duration=0;
+
+    int point=0;
+    int point_count=0;
+    int roundabout=0;
+
+    T_RoutinoRoute * route_first   = 0;
+    T_RoutinoRoute * route_next    = 0;
+
+
+    /* Loop through all the sections of the route and print them */
+
+    do
+    {
+        int first=1;
+        int next_point=point;
+        distance_t junc_distance=0;
+        duration_t junc_duration=0;
+        Result *result;
+
+#if DEBUG
+        printf("Route section %d - waypoint %d to waypoint %d\n",point,results[point]->start_waypoint,results[point]->finish_waypoint);
+        printf("  start_node=%"Pindex_t " prev_segment=%"Pindex_t "\n",results[point]->start_node,results[point]->prev_segment);
+        printf("  finish_node=%"Pindex_t " last_segment=%"Pindex_t "\n",results[point]->finish_node,results[point]->last_segment);
+
+        Result *r=FindResult(results[point],results[point]->start_node,results[point]->prev_segment);
+
+        while(r)
+        {
+            printf("    node=%"Pindex_t " segment=%"Pindex_t " score=%f\n",r->node,r->segment,r->score);
+
+            r=r->next;
+        }
+#endif
+
+        result=FindResult(results[point],results[point]->start_node,results[point]->prev_segment);
+
+        /* Loop through all the points within a section of the route and print them */
+
+        do
+        {
+            double latitude,longitude;
+            Node *resultnodep=NULL;
+            index_t realsegment=NO_SEGMENT,next_realsegment=NO_SEGMENT;
+            Segment *resultsegmentp=NULL,*next_resultsegmentp=NULL;
+            Way *resultwayp=NULL,*next_resultwayp=NULL;
+            Result *next_result;
+            int important=IMP_UNIMPORTANT;
+
+            distance_t seg_distance=0;
+            duration_t seg_duration=0;
+            char *waynameraw=NULL,*wayname=NULL,*next_waynameraw=NULL;
+            int turn_int=0, next_bearing_int=0;
+            char *turn=NULL,*next_bearing=NULL;
+
+            /* Calculate the information about this point */
+
+            if(IsFakeNode(result->node))
+            {
+                GetFakeLatLong(result->node,&latitude,&longitude);
+            }
+            else
+            {
+                resultnodep=LookupNode(nodes,result->node,6);
+
+                GetLatLong(nodes,result->node,resultnodep,&latitude,&longitude);
+            }
+
+            /* Calculate the next result */
+
+            next_result=result->next;
+
+            if(!next_result)
+            {
+                next_point++;
+
+                if(next_point<nresults)
+                {
+                    next_result=FindResult(results[next_point],results[next_point]->start_node,results[next_point]->prev_segment);
+                    next_result=next_result->next;
+                }
+            }
+
+            /* Calculate the information about this segment */
+
+            if(!first)          /* not first point of a section of the route */
+            {
+                if(IsFakeSegment(result->segment))
+                {
+                    resultsegmentp=LookupFakeSegment(result->segment);
+                    realsegment=IndexRealSegment(result->segment);
+                }
+                else
+                {
+                    resultsegmentp=LookupSegment(segments,result->segment,2);
+                    realsegment=result->segment;
+                }
+
+                resultwayp=LookupWay(ways,resultsegmentp->way,1);
+
+                seg_distance+=DISTANCE(resultsegmentp->distance);
+                seg_duration+=Duration(resultsegmentp,resultwayp,profile);
+
+                /* Calculate the cumulative distance/duration */
+
+                junc_distance+=seg_distance;
+                junc_duration+=seg_duration;
+                cum_distance+=seg_distance;
+                cum_duration+=seg_duration;
+            }
+
+            /* Calculate the information about the next segment */
+
+            if(next_result)
+            {
+                if(IsFakeSegment(next_result->segment))
+                {
+                    next_resultsegmentp=LookupFakeSegment(next_result->segment);
+                    next_realsegment=IndexRealSegment(next_result->segment);
+                }
+                else
+                {
+                    next_resultsegmentp=LookupSegment(segments,next_result->segment,1);
+                    next_realsegment=next_result->segment;
+                }
+            }
+
+            /* Decide if this is a roundabout */
+
+            if(next_result)
+            {
+                next_resultwayp=LookupWay(ways,next_resultsegmentp->way,2);
+
+                if(next_resultwayp->type&Highway_Roundabout)
+                {
+                    if(roundabout==0)
+                    {
+                        roundabout++;
+                        important=IMP_RB_ENTRY;
+                    }
+                    else
+                    {
+                        Segment *segmentp;
+
+                        if(resultnodep)
+                        {
+                            segmentp=FirstSegment(segments,resultnodep,3);
+                        }
+                        else
+                        {
+                            segmentp=FirstFakeSegment(result->node);
+                        }
+
+                        do
+                        {
+                            index_t othernode=OtherNode(segmentp,result->node);
+                            index_t thissegment;
+
+                            if(IsFakeNode(result->node))
+                            {
+                                thissegment=IndexFakeSegment(segmentp);
+                            }
+                            else
+                            {
+                                thissegment=IndexSegment(segments,segmentp);
+                            }
+
+                            if(othernode!=prev_node && othernode!=next_result->node &&
+                               thissegment!=realsegment && IsNormalSegment(segmentp))
+                            {
+                                int canexit=1;
+
+                                if(profile->oneway && IsOnewayTo(segmentp,result->node))
+                                {
+                                    if(profile->allow!=Transports_Bicycle)
+                                    {
+                                        canexit=0;
+                                    }
+                                    else
+                                    {
+                                        Way *wayp=LookupWay(ways,segmentp->way,3);
+
+                                        if(!(wayp->type&Highway_CycleBothWays))
+                                        {
+                                            canexit=0;
+                                        }
+                                    }
+                                }
+
+                                if(canexit)
+                                {
+                                    Way *wayp=LookupWay(ways,segmentp->way,3);
+
+                                    if(!(wayp->type&Highway_Roundabout))
+                                    {
+                                        roundabout++;
+                                        important=IMP_RB_NOT_EXIT;
+                                    }
+                                }
+                            }
+
+                            if(resultnodep)
+                            {
+                                segmentp=NextSegment(segments,segmentp,result->node);
+                            }
+                            else
+                            {
+                                segmentp=NextFakeSegment(segmentp,result->node);
+                            }
+                        }
+                        while(segmentp);
+                    }
+                }
+                else
+                if(roundabout)
+                {
+                    roundabout++;
+                    important=IMP_RB_EXIT;
+                }
+            }
+
+            /* Decide if this is an important junction */
+
+            if(point_count==0) /* first point overall = Waypoint */
+            {
+                important=IMP_WAYPOINT;
+            }
+            else if(result->next==NULL) /* Waypoint */
+            {
+                important=IMP_WAYPOINT;
+            }
+            else if(first)      /* first point of a section of the route */
+            {
+                important=IMP_IGNORE;
+            }
+            else if(roundabout) /* roundabout */
+            {
+                ;
+            }
+            else if(realsegment==next_realsegment) /* U-turn */
+            {
+                important=IMP_UTURN;
+            }
+            else if(resultnodep && (resultnodep->flags&NODE_MINIRNDBT))
+            {
+                important=IMP_MINI_RB; /* mini-roundabout */
+            }
+            else
+            {
+                Segment *segmentp=FirstSegment(segments,resultnodep,3);
+
+                do
+                {
+                    index_t seg=IndexSegment(segments,segmentp);
+
+                    if(seg!=realsegment && IsNormalSegment(segmentp))
+                    {
+                        int cango=1;
+
+                        if(profile->oneway && IsOnewayTo(segmentp,result->node))
+                        {
+                            if(profile->allow!=Transports_Bicycle)
+                            {
+                                cango=0;
+                            }
+                            else
+                            {
+                                Way *wayp=LookupWay(ways,segmentp->way,3);
+
+                                if(!(wayp->type&Highway_CycleBothWays))
+                                {
+                                    cango=0;
+                                }
+                            }
+                        }
+
+                        if(cango)
+                        {
+                            Way *wayp=LookupWay(ways,segmentp->way,3);
+
+                            if(seg==next_realsegment) /* the next segment that we follow */
+                            {
+                                if(HIGHWAY(wayp->type)!=HIGHWAY(resultwayp->type))
+                                {
+                                    if(important<IMP_CHANGE)
+                                    {
+                                        important=IMP_CHANGE;
+                                    }
+                                }
+                            }
+                            else /* a segment that we don't follow */
+                            {
+                                if(junction_other_way[HIGHWAY(resultwayp->type)-1][HIGHWAY(wayp->type)-1])
+                                {
+                                    if(important<IMP_JUNCT_IMPORT)
+                                    {
+                                        important=IMP_JUNCT_IMPORT;
+                                    }
+                                }
+
+                                if(important<IMP_JUNCT_CONT)
+                                {
+                                    important=IMP_JUNCT_CONT;
+                                }
+                            }
+                        }
+                    }
+
+                    segmentp=NextSegment(segments,segmentp,result->node);
+                }
+                while(segmentp);
+            }
+
+            /* Calculate the strings to be used */
+
+            if(next_result && important>IMP_JUNCT_CONT)
+            {
+
+                next_waynameraw=WayName(ways,next_resultwayp);
+                if(!*next_waynameraw)
+                {
+                   //next_waynameraw=translate_raw_highway[HIGHWAY(next_resultwayp->type)];
+                }
+
+                if(!first && textfile)
+                {
+                    if(DISTANCE(resultsegmentp->distance)==0 || DISTANCE(next_resultsegmentp->distance)==0)
+                    {
+                        turn_int=0;
+                    }
+                    else
+                    {
+                        turn_int=(int)TurnAngle(nodes,resultsegmentp,next_resultsegmentp,result->node);
+                    }
+
+                    //turn=translate_xml_turn[((202+turn_int)/45)%8];
+                }
+
+
+                if(textfile)
+                {
+                    if(!first && DISTANCE(next_resultsegmentp->distance)==0)
+                    {
+                        next_bearing_int=(int)BearingAngle(nodes,resultsegmentp,result->node);
+                    }
+                    else
+                    {
+                        next_bearing_int=(int)BearingAngle(nodes,next_resultsegmentp,next_result->node);
+                    }
+
+                    //next_bearing=translate_xml_heading[(4+(22+next_bearing_int)/45)%8];
+                }
+            }
+
+            /* Print out the important points (junctions / waypoints) */
+            if(important>IMP_IGNORE)
+            {
+                if(textfile)
+                {
+//                    char *type;
+
+//                    if(important==IMP_WAYPOINT)
+//                    {
+//                        type="Waypt";
+//                    }
+//                    else
+//                    {
+//                        type="Junct";
+//                    }
+
+                    if(point_count==0) /* first point */
+                    {
+//                        fprintf(textfile,"%10.6f\t%11.6f\t%6.3f km\t%4.1f min\t%5.1f km\t%4.0f min\t%s\t\t %+d\t%s\n",
+//                                radians_to_degrees(latitude),radians_to_degrees(longitude),
+//                                0.0,0.0,0.0,0.0,
+//                                type,
+//                                ((22+next_bearing_int)/45+4)%8-4,
+//                                next_waynameraw);
+
+                        route_first = malloc(sizeof(T_RoutinoRoute));
+                        route_first->lat = (float)latitude;
+                        route_first->lon = (float)longitude;
+                        route_first->dist = 0;
+                        route_first->time = 0;
+                        route_first->type = important;
+                        route_first->turn = -1;
+                        route_first->bearing = next_bearing_int;
+                        route_first->string = next_waynameraw;
+
+                        route_next = route_first;
+
+                    }
+                    else if(!next_result) /* end point */
+                    {
+//                        fprintf(textfile,"%10.6f\t%11.6f\t%6.3f km\t%4.1f min\t%5.1f km\t%4.0f min\t%s\t\t\t\n",
+//                                radians_to_degrees(latitude),radians_to_degrees(longitude),
+//                                distance_to_km(junc_distance),duration_to_minutes(junc_duration),
+//                                distance_to_km(cum_distance),duration_to_minutes(cum_duration),
+//                                type);
+
+                        T_RoutinoRoute * temp = malloc(sizeof(T_RoutinoRoute));
+
+                        temp->lat = (float)latitude;
+                        temp->lon = (float)longitude;
+                        temp->dist = (float)cum_distance;
+                        temp->time = (float)cum_duration;
+                        temp->type = important;
+                        temp->turn = turn_int;
+                        temp->bearing = next_bearing_int;
+                        temp->string = next_waynameraw;
+
+                        route_next->next = temp;
+                        route_next = temp;
+                        route_next->next = 0;
+                    }
+                    else        /* middle point */
+                    {
+//                        fprintf(textfile,"%10.6f\t%11.6f\t%6.3f km\t%4.1f min\t%5.1f km\t%4.0f min\t%s\t %+d\t %+d\t%s\n",
+//                                radians_to_degrees(latitude),radians_to_degrees(longitude),
+//                                distance_to_km(junc_distance),duration_to_minutes(junc_duration),
+//                                distance_to_km(cum_distance),duration_to_minutes(cum_duration),
+//                                type,
+//                                (22+turn_int)/45,
+//                                ((22+next_bearing_int)/45+4)%8-4,
+//                                next_waynameraw);
+
+                        T_RoutinoRoute * temp = malloc(sizeof(T_RoutinoRoute));
+
+                        temp->lat = (float)latitude;
+                        temp->lon = (float)longitude;
+                        temp->dist = (float)cum_distance;
+                        temp->time = (float)cum_duration;
+                        temp->type = important;
+                        temp->turn = turn_int;
+                        temp->bearing = next_bearing_int;
+                        temp->string = next_waynameraw;
+
+                        route_next->next = temp;
+                        route_next = temp;
+                    }
+                }
+
+                junc_distance=0;
+                junc_duration=0;
+
+                if(roundabout>1)
+                {
+                    roundabout=0;
+                }
+            }
+
+            /* Print out all of the results */
+
+            if(wayname && wayname!=waynameraw)
+            {
+                free(wayname);
+            }
+
+            result=next_result;
+
+            if(important>IMP_JUNCT_CONT)
+            {
+                point_count++;
+            }
+
+            first=0;
+        }
+        while(point==next_point);
+
+        /* Print the end of the segment */
+
+        point=next_point;
+
+        if(result)
+        {
+            prev_node=result->node;
+        }
+        else
+        {
+            prev_node=NO_NODE;
+        }
+    }
+    while(point<nresults);
+
+
+    return route_first;
+}
diff --git a/src/gis/IGisLine.h b/3rdparty/RoutinoLib/binout.h
similarity index 71%
copy from src/gis/IGisLine.h
copy to 3rdparty/RoutinoLib/binout.h
index ffd609c..309b9ad 100644
--- a/src/gis/IGisLine.h
+++ b/3rdparty/RoutinoLib/binout.h
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -16,20 +16,15 @@
 
 **********************************************************************************************/
 
-#ifndef IGISLINE_H
-#define IGISLINE_H
+#ifndef BINOUT_H
+#define BINOUT_H
 
-class QPolygonF;
+#include "profiles.h"
+#include "results.h"
+#include "types.h"
+#include "routino.h"
 
-class IGisLine
-{
-public:
-    IGisLine();
-    virtual ~IGisLine();
+extern T_RoutinoRoute *SimplifyResult(Results ** results, int nresults, Nodes *nodes, Segments *segments, Ways *ways, Profile *profile);
 
-    virtual void setDataFromPolyline(const QPolygonF& line) = 0;
-    virtual void getPolylineFromData(QPolygonF& line) = 0;
-};
-
-#endif //IGISLINE_H
+#endif //BINOUT_H
 
diff --git a/3rdparty/RoutinoLib/routino.c b/3rdparty/RoutinoLib/routino.c
new file mode 100644
index 0000000..2df5289
--- /dev/null
+++ b/3rdparty/RoutinoLib/routino.c
@@ -0,0 +1,426 @@
+/**********************************************************************************************
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+**********************************************************************************************/
+
+#include "binout.h"
+#include "fakes.h"
+#include "files.h"
+#include "functions.h"
+#include "nodes.h"
+#include "profiles.h"
+#include "relations.h"
+#include "results.h"
+#include "routino.h"
+#include "segments.h"
+#include "translations.h"
+#include "ways.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define MAXSEARCH 1
+
+static int isInitialized    = 0;
+int option_quickest         = 0;
+int option_quiet            = 0;
+
+
+struct T_DataSet
+{
+    Nodes     *OSMNodes;
+    Segments  *OSMSegments;
+    Ways      *OSMWays;
+    Relations *OSMRelations;
+};
+
+static Results *CalculateRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,
+                               index_t start_node,index_t prev_segment,index_t finish_node,
+                               int start_waypoint,int finish_waypoint);
+
+int RoutinoInit(const char *profiles, const char *translations)
+{
+    if(isInitialized)
+    {
+        return 0;
+    }
+
+    if(ParseXMLProfiles(profiles))
+    {
+        return -1;
+    }
+
+    if(ParseXMLTranslations(translations, NULL))
+    {
+        return -1;
+    }
+
+    isInitialized = 1;
+    return 0;
+}
+
+int RoutinoRelease()
+{
+    if(!isInitialized)
+    {
+        return 0;
+    }
+
+    ///@todo free memory from profiles and translations
+
+    isInitialized = 0;
+    return 0;
+}
+
+extern H_RoutinoDataSet RoutinoRegisterData(const char * dirname, const char * prefix)
+{
+    if(!isInitialized)
+    {
+        return 0;
+    }
+
+    char * filename;
+    Nodes     *OSMNodes;
+    Segments  *OSMSegments;
+    Ways      *OSMWays;
+    Relations *OSMRelations;
+
+    filename = FileName(dirname,prefix,"nodes.mem");
+    OSMNodes = LoadNodeList(filename);
+    free(filename);
+    if(OSMNodes == NULL)
+    {
+        goto RegisterDataErrorNodes;
+    }
+
+    filename = FileName(dirname,prefix,"segments.mem");
+    OSMSegments = LoadSegmentList(filename);
+    free(filename);
+    if(OSMSegments == NULL)
+    {
+        goto RegisterDataErrorSegments;
+    }
+
+    filename = FileName(dirname,prefix,"ways.mem");
+    OSMWays = LoadWayList(filename);
+    free(filename);
+    if(OSMWays == NULL)
+    {
+        goto RegisterDataErrorWays;
+    }
+
+    filename = FileName(dirname,prefix,"relations.mem");
+    OSMRelations = LoadRelationList(filename);
+    free(filename);
+    if(OSMNodes == NULL)
+    {
+        goto RegisterDataErrorRelations;
+    }
+
+    H_RoutinoDataSet dataset = malloc(sizeof(struct T_DataSet));
+    dataset->OSMNodes       = OSMNodes;
+    dataset->OSMSegments    = OSMSegments;
+    dataset->OSMWays        = OSMWays;
+    dataset->OSMRelations   = OSMRelations;
+    return dataset;
+
+RegisterDataErrorRelations:
+    DestroyWayList(OSMWays);
+RegisterDataErrorWays:
+    DestroySegmentList(OSMSegments);
+RegisterDataErrorSegments:
+    DestroyNodeList(OSMNodes);
+RegisterDataErrorNodes:
+    return 0;
+}
+
+extern void RoutinoFreeData(H_RoutinoDataSet data)
+{
+    if(data)
+    {
+        DestroyNodeList(data->OSMNodes);
+        DestroySegmentList(data->OSMSegments);
+        DestroyWayList(data->OSMWays);
+        DestroyRelationList(data->OSMRelations);
+        free(data);
+    }
+}
+
+extern T_RoutinoRoute * RoutinoCalculate(H_RoutinoDataSet data, const char * profilename, int quickest, const float * lon, const float * lat, int nCoord)
+{
+    Profile profile;
+
+    if(!isInitialized)
+    {
+        return 0;
+    }
+
+    if(nCoord < 2)
+    {
+        return 0;
+    }
+
+    Profile * pProfile = GetProfile(profilename);
+    if(pProfile == NULL)
+    {
+        return 0;
+    }
+
+    profile = *pProfile;
+
+    if(UpdateProfile(&profile,data->OSMWays))
+    {
+        return 0;
+    }
+
+    option_quickest = quickest;
+
+    int i;
+    T_RoutinoRoute * route         = 0;
+    int nResults                    = 0;    
+    Results * results[NWAYPOINTS+1] = {NULL};
+    index_t start_node              = NO_NODE;
+    index_t finish_node             = NO_NODE;
+    waypoint_t start_waypoint       = NO_WAYPOINT;
+    waypoint_t finish_waypoint      = NO_WAYPOINT;
+    for(i = 1; i <= nCoord; i++)
+    {
+        distance_t distmax          = 300;//km_to_distance(MAXSEARCH);
+        index_t segment             = NO_SEGMENT;
+        index_t join_segment        = NO_SEGMENT;
+        distance_t distmin;
+        distance_t dist1;
+        distance_t dist2;
+        index_t node1;
+        index_t node2;
+
+        start_node = finish_node;
+        start_waypoint=finish_waypoint;
+
+        segment = FindClosestSegment(data->OSMNodes, data->OSMSegments, data->OSMWays, lat[i-1], lon[i-1], distmax, &profile, &distmin, &node1, &node2, &dist1, &dist2);
+
+        if(segment!=NO_SEGMENT)
+        {
+            finish_node = CreateFakes(data->OSMNodes, data->OSMSegments, i, LookupSegment(data->OSMSegments, segment, 1), node1, node2, dist1, dist2);
+        }
+        else
+        {
+            finish_node=NO_NODE;
+        }
+
+
+        if(finish_node == NO_NODE)
+        {
+            goto RoutinoCalculate_end;
+        }
+
+
+        finish_waypoint = i;
+
+        if(start_node == NO_NODE)
+        {
+            continue;
+        }
+
+
+        results[nResults] = CalculateRoute(data->OSMNodes, data->OSMSegments, data->OSMWays, data->OSMRelations, &profile, start_node, join_segment, finish_node, start_waypoint, finish_waypoint);
+
+        join_segment = results[nResults]->last_segment;
+
+        nResults++;
+    }
+
+    route = SimplifyResult(results, nResults, data->OSMNodes, data->OSMSegments, data->OSMWays, &profile);
+
+RoutinoCalculate_end:
+
+    DeleteFakeNodes();
+    for(int n = 0; results[n] != NULL; n++)
+    {
+        FreeResultsList(results[n]);
+    }
+
+    return route;
+}
+
+extern void RoutinoFreeRoute(T_RoutinoRoute * route)
+{
+    while(route)
+    {
+        T_RoutinoRoute * next = route->next;
+        free(route);
+        route = next;
+    }
+}
+
+// ---------------------- stop API ------------------------------
+
+static Results *CalculateRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,
+                               index_t start_node,index_t prev_segment,index_t finish_node,
+                               int start_waypoint,int finish_waypoint)
+{
+    Results *complete=NULL;
+
+    /* A special case if the first and last nodes are the same */
+
+    if(start_node==finish_node)
+    {
+        index_t fake_segment;
+        Result *result1,*result2;
+
+        complete=NewResultsList(8);
+
+        if(prev_segment==NO_SEGMENT)
+        {
+            double lat,lon;
+            distance_t distmin,dist1,dist2;
+            index_t node1,node2;
+
+            GetLatLong(nodes,start_node,NULL,&lat,&lon);
+
+            prev_segment=FindClosestSegment(nodes,segments,ways,lat,lon,1,profile,&distmin,&node1,&node2,&dist1,&dist2);
+        }
+
+        fake_segment=CreateFakeNullSegment(segments,start_node,prev_segment,finish_waypoint);
+
+        result1=InsertResult(complete,start_node,prev_segment);
+        result2=InsertResult(complete,finish_node,fake_segment);
+
+        result1->next=result2;
+
+        complete->start_node=start_node;
+        complete->prev_segment=prev_segment;
+
+        complete->finish_node=finish_node;
+        complete->last_segment=fake_segment;
+    }
+    else
+    {
+        Results *begin;
+
+        /* Calculate the beginning of the route */
+
+        begin=FindStartRoutes(nodes,segments,ways,relations,profile,start_node,prev_segment,finish_node);
+
+        if(begin)
+        {
+            /* Check if the end of the route was reached */
+
+            if(begin->finish_node!=NO_NODE)
+            {
+                complete=begin;
+            }
+        }
+        else
+        {
+            if(prev_segment!=NO_SEGMENT)
+            {
+                /* Try again but allow a U-turn at the start waypoint -
+                   this solves the problem of facing a dead-end that contains no super-nodes. */
+
+                prev_segment=NO_SEGMENT;
+
+                begin=FindStartRoutes(nodes,segments,ways,relations,profile,start_node,prev_segment,finish_node);
+            }
+
+            if(begin)
+            {
+                /* Check if the end of the route was reached */
+
+                if(begin->finish_node!=NO_NODE)
+                {
+                    complete=begin;
+                }
+            }
+            else
+            {
+                fprintf(stderr,"Error: Cannot find initial section of route compatible with profile.\n");
+                exit(EXIT_FAILURE);
+            }
+        }
+
+        /* Calculate the rest of the route */
+
+        if(!complete)
+        {
+            Results *middle,*end;
+
+            /* Calculate the end of the route */
+
+            end=FindFinishRoutes(nodes,segments,ways,relations,profile,finish_node);
+
+            if(!end)
+            {
+                fprintf(stderr,"Error: Cannot find final section of route compatible with profile.\n");
+                exit(EXIT_FAILURE);
+            }
+
+            /* Calculate the middle of the route */
+
+            middle=FindMiddleRoute(nodes,segments,ways,relations,profile,begin,end);
+
+            if(!middle && prev_segment!=NO_SEGMENT)
+            {
+                /* Try again but allow a U-turn at the start waypoint -
+                   this solves the problem of facing a dead-end that contains some super-nodes. */
+
+                FreeResultsList(begin);
+
+                begin=FindStartRoutes(nodes,segments,ways,relations,profile,start_node,NO_SEGMENT,finish_node);
+
+                if(begin)
+                {
+                    middle=FindMiddleRoute(nodes,segments,ways,relations,profile,begin,end);
+                }
+            }
+
+            if(!middle)
+            {
+                fprintf(stderr,"Error: Cannot find super-route compatible with profile.\n");
+                exit(EXIT_FAILURE);
+            }
+
+            complete=CombineRoutes(nodes,segments,ways,relations,profile,begin,middle,end);
+
+            if(!complete)
+            {
+                fprintf(stderr,"Error: Cannot create combined route following super-route.\n");
+                exit(EXIT_FAILURE);
+            }
+
+            FreeResultsList(begin);
+            FreeResultsList(middle);
+            FreeResultsList(end);
+        }
+    }
+
+    complete->start_waypoint=start_waypoint;
+    complete->finish_waypoint=finish_waypoint;
+
+#if DEBUG
+    Result *r=FindResult(complete,complete->start_node,complete->prev_segment);
+
+    printf("The final route is:\n");
+
+    while(r)
+    {
+        printf("  node=%"Pindex_t " segment=%"Pindex_t " score=%f\n",r->node,r->segment,r->score);
+
+        r=r->next;
+    }
+#endif
+
+    return complete;
+}
diff --git a/3rdparty/RoutinoLib/routino.h b/3rdparty/RoutinoLib/routino.h
new file mode 100644
index 0000000..710e4ad
--- /dev/null
+++ b/3rdparty/RoutinoLib/routino.h
@@ -0,0 +1,130 @@
+/**********************************************************************************************
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+**********************************************************************************************/
+
+#ifndef ROUTINO_H
+#define ROUTINO_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define IMP_IGNORE      -1      /*+ Ignore this point. +*/
+#define IMP_UNIMPORTANT  0      /*+ An unimportant, intermediate, node. +*/
+#define IMP_RB_NOT_EXIT  1      /*+ A roundabout exit that is not taken. +*/
+#define IMP_JUNCT_CONT   2      /*+ An un-interesting junction where the route continues without comment. +*/
+#define IMP_CHANGE       3      /*+ The highway changes type but nothing else happens. +*/
+#define IMP_JUNCT_IMPORT 4      /*+ An interesting junction to be described. +*/
+#define IMP_RB_ENTRY     5      /*+ The entrance to a roundabout. +*/
+#define IMP_RB_EXIT      6      /*+ The exit from a roundabout. +*/
+#define IMP_MINI_RB      7      /*+ The location of a mini-roundabout. +*/
+#define IMP_UTURN        8      /*+ The location of a U-turn. +*/
+#define IMP_WAYPOINT     9      /*+ A waypoint. +*/
+
+typedef struct T_DataSet * H_RoutinoDataSet;
+
+typedef struct _T_RoutinoRoute
+{
+    /// pointer to next point. 0 if last point
+    struct _T_RoutinoRoute * next;
+    /// the longitude in [rad]
+    float lon;
+    /// the latitude in [rad]
+    float lat;
+    /// the total distance in [m]
+    float dist;
+    /// the total time in [s]
+    float time;
+    /// the type of the point. one of IMP_*
+    uint32_t type;
+    ///
+    int32_t turn;
+    ///
+    int32_t bearing;
+    /// string attached to point
+    const char * string;
+}T_RoutinoRoute;
+
+/**
+   @brief Initialize Routino library.
+
+   This has to be called once on program startup.
+
+   @param profiles      a string pointer to the XML file defining the profiles
+   @param translations  a string pointer to the XML file defining the translation tables
+
+   @return Returns 0 on success and -1 on failure
+ */
+extern int RoutinoInit(const char * profiles, const char *translations);
+
+/**
+   @brief Register a routing database and obtain a handle
+
+   @param dirname
+   @param prefix
+
+   @return A handle to the data. This has to be used with RoutinoCalculate.
+ */
+extern H_RoutinoDataSet RoutinoRegisterData(const char *dirname, const char * prefix);
+
+/**
+   @brief Calcualte a route.
+
+   The result will be a linked list of intermediate route points. The original route points will be included with type IMP_WAYPOINT.
+
+   @param data          a handle to a routing database
+   @param profilename   the profile name to use. Valid names are: "foot", "horse", "wheelchair", "bicycle", "moped", "motorcycle", "motorcar", "goods"
+   @param quickest      set to 0 for shortest and 1 for quickest
+   @param lon           pointer to an array of longitude coordinates
+   @param lat           pointer to an array of latitude coordinates
+   @param nCoord        number off coordinates
+
+   @return A linked list of routepoints.
+ */
+extern T_RoutinoRoute * RoutinoCalculate(H_RoutinoDataSet data, const char * profilename, int quickest, const float * lon, const float * lat, int nCoord);
+
+/**
+   @brief Free the memory of the route information allocated by RoutinoCalculate
+
+   @param route         ointer to linked list of routepoints.
+ */
+extern void RoutinoFreeRoute(T_RoutinoRoute * route);
+
+/**
+   @brief Free a routing database.
+
+   @param data  the handle to the database
+ */
+extern void RoutinoFreeData(H_RoutinoDataSet data);
+
+/**
+   @brief Release Routino library
+
+   This has to be called once when releasing the library.
+
+   @return Return 0.
+ */
+extern int RoutinoRelease();
+
+#ifdef __cplusplus
+}
+#endif
+#endif //ROUTINO_H
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c0c0c2c..649905b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,17 +2,12 @@ cmake_minimum_required(VERSION 3.0.0)
 
 project(QMapShack)
 
-# has to be removed later on
-
-if(UNIX)
-#set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} /opt/Qt/5.3/gcc_64)
-endif(UNIX)
-
 
 if(WIN32)
-set(QT_DEV_PATH   "" CACHE PATH "Path to directory containing Qt5 include and lib, e.g. C:\\Qt5\\5.3\\msvc2013_64")
-set(GDAL_DEV_PATH "" CACHE PATH "Path to directory containing GDAL include and lib, e.g. M:\\lib\\gdal")
-set(PROJ_DEV_PATH "" CACHE PATH "Path to directory containing PROJ.4 include and lib, e.g. M:\\lib\\PROJ")
+set(QT_DEV_PATH   "C:\\Qt\\5.4\\msvc2013_64" CACHE PATH "Path to directory containing Qt5 include and lib, e.g. C:\\Qt5\\5.3\\msvc2013_64")
+set(GDAL_DEV_PATH "C:\\GDAL" CACHE PATH "Path to directory containing GDAL include and lib, e.g. M:\\lib\\gdal")
+set(PROJ_DEV_PATH "C:\\PROJ" CACHE PATH "Path to directory containing PROJ.4 include and lib, e.g. M:\\lib\\PROJ")
+set(ZLIB_DEV_PATH "C:\\zlib" CACHE PATH "Path to directory containing zlib include and lib, e.g. M:\\lib\\zlib")
 set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${QT_DEV_PATH})
 endif(WIN32)
 
@@ -20,8 +15,8 @@ endif(WIN32)
 set(APPLICATION_NAME qmapshack)
 
 set(APPLICATION_VERSION_MAJOR "1")
-set(APPLICATION_VERSION_MINOR "2")
-set(APPLICATION_VERSION_PATCH "2")
+set(APPLICATION_VERSION_MINOR "3")
+set(APPLICATION_VERSION_PATCH "0")
 
 add_definitions(-DVER_MAJOR=${APPLICATION_VERSION_MAJOR} -DVER_MINOR=${APPLICATION_VERSION_MINOR} -DVER_STEP=${APPLICATION_VERSION_PATCH} -DAPPLICATION_NAME=${PROJECT_NAME})
 
@@ -65,7 +60,7 @@ configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
 
 set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
 add_subdirectory(3rdparty/CGetOpt)
-#add_subdirectory(3rdparty/DBConverter)
+add_subdirectory(3rdparty/RoutinoLib)
 add_subdirectory(src)
 
 
@@ -100,3 +95,4 @@ CONFIGURE_FILE(
 ADD_CUSTOM_TARGET(uninstall
   "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
 
+
diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user
index 68d683b..d8c51fb 100644
--- a/CMakeLists.txt.user
+++ b/CMakeLists.txt.user
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE QtCreatorProject>
-<!-- Written by QtCreator 3.3.1, 2015-04-29T20:35:21. -->
+<!-- Written by QtCreator 3.4.1, 2015-06-29T19:46:44. -->
 <qtcreator>
  <data>
   <variable>EnvironmentId</variable>
@@ -157,7 +157,7 @@
      <value type="int">14</value>
     </valuelist>
     <value type="QString" key="CMakeProjectManager.CMakeRunConfiguation.Title">qmapshack</value>
-    <value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.Arguments">-d </value>
+    <value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.Arguments"></value>
     <value type="bool" key="CMakeProjectManager.CMakeRunConfiguration.UseTerminal">false</value>
     <value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory"></value>
     <value type="int" key="PE.EnvironmentAspect.Base">2</value>
@@ -172,7 +172,109 @@
     <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
     <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
    </valuemap>
-   <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.1">
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
+    <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
+    <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
+    <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
+    <value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
+    <value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
+    <value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
+    <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
+    <value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
+    <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
+    <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
+     <value type="int">0</value>
+     <value type="int">1</value>
+     <value type="int">2</value>
+     <value type="int">3</value>
+     <value type="int">4</value>
+     <value type="int">5</value>
+     <value type="int">6</value>
+     <value type="int">7</value>
+     <value type="int">8</value>
+     <value type="int">9</value>
+     <value type="int">10</value>
+     <value type="int">11</value>
+     <value type="int">12</value>
+     <value type="int">13</value>
+     <value type="int">14</value>
+    </valuelist>
+    <value type="QString" key="CMakeProjectManager.CMakeRunConfiguation.Title">router</value>
+    <value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.Arguments"></value>
+    <value type="bool" key="CMakeProjectManager.CMakeRunConfiguration.UseTerminal">false</value>
+    <value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory"></value>
+    <value type="int" key="PE.EnvironmentAspect.Base">2</value>
+    <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">router</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.router</value>
+    <value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
+    <value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
+    <value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
+    <value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
+    <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
+    <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
+   </valuemap>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.2">
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
+    <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
+    <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
+    <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
+    <value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
+    <value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
+    <value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
+    <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
+    <value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
+    <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
+    <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
+     <value type="int">0</value>
+     <value type="int">1</value>
+     <value type="int">2</value>
+     <value type="int">3</value>
+     <value type="int">4</value>
+     <value type="int">5</value>
+     <value type="int">6</value>
+     <value type="int">7</value>
+     <value type="int">8</value>
+     <value type="int">9</value>
+     <value type="int">10</value>
+     <value type="int">11</value>
+     <value type="int">12</value>
+     <value type="int">13</value>
+     <value type="int">14</value>
+    </valuelist>
+    <value type="QString" key="CMakeProjectManager.CMakeRunConfiguation.Title">planetsplitter</value>
+    <value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.Arguments"></value>
+    <value type="bool" key="CMakeProjectManager.CMakeRunConfiguration.UseTerminal">false</value>
+    <value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory"></value>
+    <value type="int" key="PE.EnvironmentAspect.Base">2</value>
+    <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">planetsplitter</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.planetsplitter</value>
+    <value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
+    <value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
+    <value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
+    <value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
+    <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
+    <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
+   </valuemap>
+   <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">3</value>
   </valuemap>
  </data>
  <data>
diff --git a/CMakeLists.txt.user.3.3-pre1 b/CMakeLists.txt.user.3.3-pre1
deleted file mode 100644
index 2d183c2..0000000
--- a/CMakeLists.txt.user.3.3-pre1
+++ /dev/null
@@ -1,188 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE QtCreatorProject>
-<!-- Written by QtCreator 3.2.2, 2015-03-13T18:02:53. -->
-<qtcreator>
- <data>
-  <variable>EnvironmentId</variable>
-  <value type="QByteArray">{044d553a-749a-4a4b-b707-1344605bd255}</value>
- </data>
- <data>
-  <variable>ProjectExplorer.Project.ActiveTarget</variable>
-  <value type="int">0</value>
- </data>
- <data>
-  <variable>ProjectExplorer.Project.EditorSettings</variable>
-  <valuemap type="QVariantMap">
-   <value type="bool" key="EditorConfiguration.AutoIndent">true</value>
-   <value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
-   <value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
-   <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
-    <value type="QString" key="language">Cpp</value>
-    <valuemap type="QVariantMap" key="value">
-     <value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
-    </valuemap>
-   </valuemap>
-   <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
-    <value type="QString" key="language">QmlJS</value>
-    <valuemap type="QVariantMap" key="value">
-     <value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
-    </valuemap>
-   </valuemap>
-   <value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
-   <value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
-   <value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
-   <value type="int" key="EditorConfiguration.IndentSize">4</value>
-   <value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
-   <value type="int" key="EditorConfiguration.MarginColumn">80</value>
-   <value type="bool" key="EditorConfiguration.MouseHiding">true</value>
-   <value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
-   <value type="int" key="EditorConfiguration.PaddingMode">1</value>
-   <value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
-   <value type="bool" key="EditorConfiguration.ShowMargin">false</value>
-   <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
-   <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
-   <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
-   <value type="int" key="EditorConfiguration.TabSize">8</value>
-   <value type="bool" key="EditorConfiguration.UseGlobal">true</value>
-   <value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
-   <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
-   <value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
-   <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
-   <value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
-  </valuemap>
- </data>
- <data>
-  <variable>ProjectExplorer.Project.PluginSettings</variable>
-  <valuemap type="QVariantMap"/>
- </data>
- <data>
-  <variable>ProjectExplorer.Project.Target.0</variable>
-  <valuemap type="QVariantMap">
-   <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 4.8.4 in Pfad (System)</value>
-   <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Qt 4.8.4 in Pfad (System)</value>
-   <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{b3896d75-6773-49ab-b85b-a90805c4269a}</value>
-   <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
-   <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
-   <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
-   <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
-    <value type="bool" key="CMakeProjectManager.CMakeBuildConfiguration.UseNinja">false</value>
-    <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/oeichler/Code/cpp/build_QMapShack</value>
-    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
-     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
-      <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments">-j8</value>
-      <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets"/>
-      <value type="bool" key="CMakeProjectManager.MakeStep.Clean">false</value>
-      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
-      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
-      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
-      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
-     </valuemap>
-     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
-     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
-     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
-     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
-    </valuemap>
-    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
-     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
-      <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments">clean</value>
-      <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets"/>
-      <value type="bool" key="CMakeProjectManager.MakeStep.Clean">true</value>
-      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
-      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
-      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
-      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
-     </valuemap>
-     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
-     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Bereinigen</value>
-     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
-     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
-    </valuemap>
-    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
-    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
-    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
-    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">all</value>
-    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
-    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
-   </valuemap>
-   <value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
-   <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
-    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
-     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
-     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deployment</value>
-     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
-     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
-    </valuemap>
-    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
-    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Lokales Deployment</value>
-    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
-    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
-   </valuemap>
-   <value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
-   <valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
-   <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
-    <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
-    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
-    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
-    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
-    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
-    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
-    <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
-    <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
-    <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
-    <value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
-    <value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
-    <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
-    <value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
-    <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
-    <value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
-    <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
-    <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
-    <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
-     <value type="int">0</value>
-     <value type="int">1</value>
-     <value type="int">2</value>
-     <value type="int">3</value>
-     <value type="int">4</value>
-     <value type="int">5</value>
-     <value type="int">6</value>
-     <value type="int">7</value>
-     <value type="int">8</value>
-     <value type="int">9</value>
-     <value type="int">10</value>
-     <value type="int">11</value>
-     <value type="int">12</value>
-     <value type="int">13</value>
-     <value type="int">14</value>
-    </valuelist>
-    <value type="QString" key="CMakeProjectManager.CMakeRunConfiguation.Title">qmapshack</value>
-    <value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.Arguments"></value>
-    <value type="bool" key="CMakeProjectManager.CMakeRunConfiguration.UseTerminal">false</value>
-    <value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory"></value>
-    <value type="int" key="PE.EnvironmentAspect.Base">2</value>
-    <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
-    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmapshack</value>
-    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
-    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.qmapshack</value>
-    <value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
-    <value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
-    <value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
-    <value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
-    <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
-    <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
-   </valuemap>
-   <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
-  </valuemap>
- </data>
- <data>
-  <variable>ProjectExplorer.Project.TargetCount</variable>
-  <value type="int">1</value>
- </data>
- <data>
-  <variable>ProjectExplorer.Project.Updater.FileVersion</variable>
-  <value type="int">16</value>
- </data>
- <data>
-  <variable>Version</variable>
-  <value type="int">16</value>
- </data>
-</qtcreator>
diff --git a/changelog.txt b/changelog.txt
index 2eaf4c1..54021a2 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,23 @@
+V 1.3.0
+* Cluttered items select: make text sensitive, too
+* TwoNav: Fix problems with decoding records created with old firmware.
+* [Issue #20] Add command "Duplicate View"
+* Ask for saving chnages when closing db project via db folder check box
+* Rework user interface to edit line items (tracks, routes, areas)
+* Add Routino as offline auto-router
+* Add GUI tool to create Routino database files
+* Rte: Create route from selected waypoints
+* Complete lines via router in line edit mode
+* View: Fix bad scaling on startup when using square scale
+* [Issue #25] Saved tracks get wrong timestamps
+* [Issue #23] Update French translation and fix missleading translation
+* Trk/Wpt: Make track/waypoint correlation an option if it takes too long.
+* Workspace: Add warning when loading a project twice
+* Speed up project file loading
+* Trk: Allow combining tracks for tracks on devices. 
+* Trk: Allow pre-selection of several tracks for combining tracks
+* Many GUI fixes and code cleanup.
+
 V 1.2.2
 * TwoNav: Find wpt files created from device in the TwoNavData folder
 * Wpt: Display waypoint description/comment as bubble
diff --git a/mkfile b/mkfile
index 1e64165..e203824 100755
--- a/mkfile
+++ b/mkfile
@@ -22,6 +22,8 @@ if ext == ".h":
     template = os.path.join(pathTemplates, "header.h")
 elif ext == ".cpp":
     template = os.path.join(pathTemplates, "source.cpp")
+elif ext == ".c":
+    template = os.path.join(pathTemplates, "source.c")    
 else:
     print "unknown file type"
     sys.exit(-1)
diff --git a/src/CMainWindow.cpp b/src/CMainWindow.cpp
index af25faa..547b855 100644
--- a/src/CMainWindow.cpp
+++ b/src/CMainWindow.cpp
@@ -30,8 +30,9 @@
 #include "map/CMapDraw.h"
 #include "map/CMapItem.h"
 #include "map/CMapList.h"
-#include "map/CMapVrtBuilder.h"
-#include "qlgt/CImportDatabase.h"
+#include "tool/CImportDatabase.h"
+#include "tool/CMapVrtBuilder.h"
+#include "tool/CRoutinoDatabaseBuilder.h"
 #include "units/CTimeZoneSetup.h"
 #include "units/CUnitsSetup.h"
 #include "units/IUnit.h"
@@ -87,6 +88,7 @@ CMainWindow::CMainWindow()
     connect(actionAbout, SIGNAL(triggered()), this, SLOT(slotAbout()));
     connect(actionHelp, SIGNAL(triggered()), this, SLOT(slotHelp()));
     connect(actionAddMapView, SIGNAL(triggered()), this, SLOT(slotAddCanvas()));
+    connect(actionCloneMapView, SIGNAL(triggered()), this, SLOT(slotCloneCanvas()));
     connect(actionShowScale, SIGNAL(changed()), this, SLOT(slotUpdateCurrentWidget()));
     connect(actionShowGrid, SIGNAL(changed()), this, SLOT(update()));
     connect(actionPOIText, SIGNAL(changed()), this, SLOT(slotUpdateCurrentWidget()));
@@ -108,6 +110,7 @@ CMainWindow::CMainWindow()
     connect(actionStoreView, SIGNAL(triggered()), this, SLOT(slotStoreView()));
     connect(actionLoadView, SIGNAL(triggered()), this, SLOT(slotLoadView()));
     connect(actionClose, SIGNAL(triggered()), this, SLOT(close()));
+    connect(actionCreateRoutinoDatabase, SIGNAL(triggered()), this, SLOT(slotCreateRoutinoDatabase()));
     connect(tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(slotTabCloseRequest(int)));
 
 
@@ -175,6 +178,7 @@ CMainWindow::CMainWindow()
     menuWindow->addAction(dockMaps->toggleViewAction());
     menuWindow->addAction(dockDem->toggleViewAction());
     menuWindow->addAction(dockGis->toggleViewAction());
+    menuWindow->addAction(dockRte->toggleViewAction());
 
     loadGISData(qlOpts->arguments);
 }
@@ -336,6 +340,33 @@ qreal CMainWindow::getEelevationAt(const QPointF& pos)
     return NOFLOAT;
 }
 
+
+void CMainWindow::getEelevationAt(SGisLine &line)
+{
+    CCanvas * canvas = getVisibleCanvas();
+    if(canvas)
+    {
+        canvas->getElevationAt(line);
+    }
+    else
+    {
+        for(int i = 0; i < tabWidget->count(); i++)
+        {
+            canvas = dynamic_cast<CCanvas*>(tabWidget->widget(i));
+            if(canvas)
+            {
+                canvas->getElevationAt(line);
+                return;
+            }
+        }
+
+        for(int i = 0; i < line.size(); i++)
+        {
+            line[i].resetElevation();
+        }
+    }
+}
+
 void CMainWindow::getEelevationAt(const QPolygonF &pos, QPolygonF& ele)
 {
     CCanvas * canvas = getVisibleCanvas();
@@ -390,6 +421,43 @@ void CMainWindow::slotAddCanvas()
     tabWidget->setCurrentWidget(canvas);
 }
 
+void CMainWindow::slotCloneCanvas()
+{
+    CCanvas * source = getVisibleCanvas();
+    if(source == 0)
+    {
+        return;
+    }
+
+    QTemporaryFile temp;
+    temp.open();
+    temp.close();
+
+    QSettings view(temp.fileName(), QSettings::IniFormat);
+    view.clear();
+
+    source->saveConfig(view);
+
+    slotAddCanvas();
+
+    CCanvas * target = getVisibleCanvas();
+    if(target == 0)
+    {
+        return;
+    }
+
+    target->loadConfig(view);
+
+    SETTINGS;
+    cfg.beginGroup("Canvas");
+    cfg.beginGroup("Views");
+    cfg.beginGroup(target->objectName());
+    target->saveConfig(cfg);
+    cfg.endGroup();
+    cfg.endGroup();
+    cfg.endGroup();
+}
+
 void CMainWindow::slotTabCloseRequest(int i)
 {
     QMutexLocker lock(&CMapItem::mutexActiveMaps);
@@ -607,6 +675,11 @@ void CMainWindow::slotBuildVrt()
     addWidgetToTab(widget);
 }
 
+void CMainWindow::slotCreateRoutinoDatabase()
+{
+    CRoutinoDatabaseBuilder * widget = new CRoutinoDatabaseBuilder(this);
+    addWidgetToTab(widget);
+}
 
 void CMainWindow::slotLoadGISData()
 {
diff --git a/src/CMainWindow.h b/src/CMainWindow.h
index 0403bbb..e65b2a9 100644
--- a/src/CMainWindow.h
+++ b/src/CMainWindow.h
@@ -19,6 +19,7 @@
 #ifndef CMAINWINDOW_H
 #define CMAINWINDOW_H
 
+#include "gis/IGisLine.h"
 #include "ui_IMainWindow.h"
 #include <QMainWindow>
 
@@ -62,6 +63,7 @@ public:
      */
     qreal getEelevationAt(const QPointF &pos);
     void  getEelevationAt(const QPolygonF& pos, QPolygonF &ele);
+    void  getEelevationAt(SGisLine &line);
     /**
        @brief Get pointer to the currently visibale canvas object.
        @return If the currently visible tab does not contain a CCanvas object 0 is returned.
@@ -80,6 +82,7 @@ private slots:
     void slotAbout();
     void slotHelp();
     void slotAddCanvas();
+    void slotCloneCanvas();
     void slotTabCloseRequest(int i);
     void slotCurrentTabCanvas(int i);
     void slotCurrentTabMaps(int i);
@@ -100,6 +103,7 @@ private slots:
     void slotStoreView();
     void slotLoadView();
     void slotSetProfileMode(bool on);
+    void slotCreateRoutinoDatabase();
 
 private:
     friend int main(int argc, char ** argv);
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f181c66..8b4b1a9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -19,6 +19,9 @@ endif(UNIX)
 find_package(GDAL REQUIRED)
 find_package(PROJ REQUIRED)
 
+file(GLOB XML_FILES "${CMAKE_SOURCE_DIR}/3rdparty/Routino/xml/*.xml")
+file(COPY ${XML_FILES} DESTINATION ${CMAKE_SOURCE_DIR}/src/xml/routino)
+
 set( SRCS
 
     main.cpp
@@ -49,8 +52,7 @@ set( SRCS
     dem/CDemList.cpp
     dem/CDemItem.cpp
     dem/CDemPathSetup.cpp
-    dem/CDemPropSetup.cpp
-    map/CMapVrtBuilder.cpp
+    dem/CDemPropSetup.cpp    
     map/IMap.cpp
     map/CMapDraw.cpp
     map/CMapItem.cpp
@@ -84,20 +86,28 @@ set( SRCS
     grid/CGridSetup.cpp
     grid/CProjWizard.cpp
     grid/mitab.cpp
-    mouse/IMouse.cpp
-    mouse/IMouseEditLine.cpp
+    mouse/IMouse.cpp    
     mouse/IScrOpt.cpp
+    mouse/CMouseDummy.cpp
     mouse/CMouseNormal.cpp
     mouse/CMouseMoveWpt.cpp
     mouse/CMouseEditTrk.cpp
+    mouse/CMouseEditRte.cpp
     mouse/CMouseEditArea.cpp
     mouse/CMouseRangeTrk.cpp
     mouse/CMouseWptBubble.cpp
     mouse/CScrOptUnclutter.cpp    
-    mouse/CScrOptPoint.cpp
-    mouse/CScrOptEditLine.cpp
+    mouse/CScrOptPoint.cpp    
     mouse/CScrOptRange.cpp
     mouse/CScrOptRangeTrk.cpp    
+    mouse/line/IMouseEditLine.cpp
+    mouse/line/CScrOptEditLine.cpp
+    mouse/line/CScrOptRangeLine.cpp
+    mouse/line/ILineOp.cpp
+    mouse/line/CLineOpMovePoint.cpp
+    mouse/line/CLineOpAddPoint.cpp
+    mouse/line/CLineOpDeletePoint.cpp
+    mouse/line/CLineOpSelectRange.cpp
     gis/WptIcons.cpp
     gis/CGisDraw.cpp
     gis/IGisItem.cpp
@@ -152,6 +162,12 @@ set( SRCS
     gis/trk/filter/CFilterSpeed.cpp
     gis/rte/CGisItemRte.cpp
     gis/rte/CScrOptRte.cpp
+    gis/rte/CCreateRouteFromWpt.cpp
+    gis/rte/router/IRouter.cpp
+    gis/rte/router/CRouterSetup.cpp
+    gis/rte/router/CRouterRoutino.cpp
+    gis/rte/router/CRouterMapQuest.cpp
+    gis/rte/router/CRouterRoutinoPathSetup.cpp    
     gis/ovl/CGisItemOvlArea.cpp
     gis/ovl/CScrOptOvlArea.cpp
     gis/ovl/CDetailsOvlArea.cpp    
@@ -172,14 +188,17 @@ set( SRCS
     qlgt/CQlgtTrack.cpp
     qlgt/CQlgtRoute.cpp
     qlgt/CQlgtDiary.cpp
-    qlgt/IQlgtOverlay.cpp
-    qlgt/CImportDatabase.cpp
+    qlgt/IQlgtOverlay.cpp    
     qlgt/CQlgtDb.cpp
     qlgt/CQmsDb.cpp
     device/IDeviceWatcher.cpp
     device/IDevice.cpp
     device/CDeviceGarmin.cpp
     device/CDeviceTwoNav.cpp
+    tool/IToolShell.cpp
+    tool/CMapVrtBuilder.cpp
+    tool/CImportDatabase.cpp
+    tool/CRoutinoDatabaseBuilder.cpp
 )
 
 if(UNIX)
@@ -231,7 +250,6 @@ set( HDRS
     dem/CDemItem.h
     dem/CDemPathSetup.h
     dem/CDemPropSetup.h
-    map/CMapVrtBuilder.h
     map/IMap.h
     map/IMapProp.h
     map/CMapDraw.h
@@ -267,20 +285,28 @@ set( HDRS
     grid/CGridSetup.h
     grid/CProjWizard.h
     grid/mitab.h
-    mouse/IMouse.h
-    mouse/IMouseEditLine.h
+    mouse/IMouse.h    
     mouse/IScrOpt.h
+    mouse/CMouseDummy.h
     mouse/CMouseNormal.h
     mouse/CMouseMoveWpt.h
     mouse/CMouseEditTrk.h
+    mouse/CMouseEditRte.h
     mouse/CMouseEditArea.h
     mouse/CMouseRangeTrk.h
     mouse/CMouseWptBubble.h
     mouse/CScrOptUnclutter.h
-    mouse/CScrOptPoint.h
-    mouse/CScrOptEditLine.h
+    mouse/CScrOptPoint.h    
     mouse/CScrOptRange.h
     mouse/CScrOptRangeTrk.h
+    mouse/line/CScrOptEditLine.h
+    mouse/line/CScrOptRangeLine.h
+    mouse/line/IMouseEditLine.h
+    mouse/line/ILineOp.h
+    mouse/line/CLineOpMovePoint.h
+    mouse/line/CLineOpAddPoint.h
+    mouse/line/CLineOpDeletePoint.h
+    mouse/line/CLineOpSelectRange.h
     gis/WptIcons.h
     gis/CGisDraw.h
     gis/IGisItem.h
@@ -330,6 +356,12 @@ set( HDRS
     gis/trk/filter/CFilterSpeed.h
     gis/rte/CGisItemRte.h
     gis/rte/CScrOptRte.h
+    gis/rte/CCreateRouteFromWpt.h
+    gis/rte/router/IRouter.h
+    gis/rte/router/CRouterSetup.h
+    gis/rte/router/CRouterRoutino.h
+    gis/rte/router/CRouterMapQuest.h
+    gis/rte/router/CRouterRoutinoPathSetup.h
     gis/ovl/CGisItemOvlArea.h
     gis/ovl/CScrOptOvlArea.h
     gis/ovl/CDetailsOvlArea.h    
@@ -352,13 +384,16 @@ set( HDRS
     qlgt/CQlgtRoute.h
     qlgt/CQlgtDiary.h
     qlgt/IQlgtOverlay.h
-    qlgt/CImportDatabase.h
     qlgt/CQlgtDb.h
     qlgt/CQmsDb.h
     device/IDeviceWatcher.h    
     device/IDevice.h
     device/CDeviceGarmin.h
     device/CDeviceTwoNav.h
+    tool/IToolShell.h
+    tool/CMapVrtBuilder.h
+    tool/CImportDatabase.h
+    tool/CRoutinoDatabaseBuilder.h
 )
 
 if(UNIX)
@@ -393,14 +428,14 @@ set( UIS
     dem/IDemPropSetup.ui
     map/IMapList.ui
     map/IMapPathSetup.ui
-    map/IMapPropSetup.ui
-    map/IMapVrtBuilder.ui
+    map/IMapPropSetup.ui    
     grid/IGridSetup.ui
     grid/IProjWizard.ui
-    mouse/IScrOptPoint.ui
-    mouse/IScrOptEditLine.ui
+    mouse/IScrOptPoint.ui    
     mouse/IScrOptRange.ui
     mouse/IScrOptRangeTrk.ui
+    mouse/line/IScrOptEditLine.ui
+    mouse/line/IScrOptRangeLine.ui
     gis/IGisWidget.ui
     gis/ISelDevices.ui
     gis/prj/IDetailsPrj.ui
@@ -427,13 +462,21 @@ set( UIS
     gis/trk/filter/IFilterObscureDate.ui
     gis/trk/filter/IFilterSpeed.ui
     gis/rte/IScrOptRte.ui
+    gis/rte/ICreateRouteFromWpt.ui
+    gis/rte/router/IRouterSetup.ui
+    gis/rte/router/IRouterRoutino.ui
+    gis/rte/router/IRouterMapQuest.ui
+    gis/rte/router/IRouterRoutinoPathSetup.ui
     gis/ovl/IScrOptOvlArea.ui
     gis/ovl/IDetailsOvlArea.ui
     units/ITimeZoneSetup.ui
     units/IUnitsSetup.ui
-    qlgt/IImportDatabase.ui
+    tool/IImportDatabase.ui
+    tool/IMapVrtBuilder.ui
+    tool/IRoutinoDatabaseBuilder.ui
 )
 
+
 set( RCS
     resources.qrc
 )
@@ -446,6 +489,9 @@ if(UNIX)
     add_definitions(-Wall -Wno-switch -Wno-strict-aliasing)
 endif(UNIX)
 
+if(WIN32)
+    add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+endif(WIN32)
 
 file(GLOB TRANSLATIONS_FILES locale/*.ts)
 
@@ -467,28 +513,23 @@ set(ALLINP
 include_directories(
     ${CMAKE_BINARY_DIR}
     ${CMAKE_SOURCE_DIR}/3rdparty/CGetOpt
+    ${CMAKE_SOURCE_DIR}/3rdparty/RoutinoLib
     ${GDAL_INCLUDE_DIRS}
     ${PROJ_INCLUDE_DIRS}
 
 )
 
 
-
-# Tell CMake to create the helloworld executable
 add_executable(${APPLICATION_NAME} WIN32 ${ALLINP})
 
+
+
 if(UNIX)
-set(DBUS_LIB
-    Qt5::DBus
-)
+    set(DBUS_LIB Qt5::DBus)
 else(UNIX)
-set(DBUS_LIB
-)
+    set(DBUS_LIB)
 endif(UNIX)
 
-
-
-# Use the Widgets module from Qt 5.
 target_link_libraries(${APPLICATION_NAME}
     Qt5::Widgets
     Qt5::Xml
@@ -497,7 +538,8 @@ target_link_libraries(${APPLICATION_NAME}
     Qt5::WebKitWidgets
     Qt5::PrintSupport
     CGetOpt
-	${DBUS_LIB}
+    routino
+    ${DBUS_LIB}
     ${GDAL_LIBRARIES}
     ${PROJ_LIBRARIES}
 )
diff --git a/src/GeoMath.cpp b/src/GeoMath.cpp
index 1180720..ed97d8c 100644
--- a/src/GeoMath.cpp
+++ b/src/GeoMath.cpp
@@ -580,45 +580,45 @@ void segment_t::apply(const QPolygonF& coords, const QPolygonF& pixel, QPolygonF
     {
         if(idx11 == idx21)
         {
-            segPixel.push_back(px1);
-            segPixel.push_back(px2);
+//            segPixel.push_back(px1);
+//            segPixel.push_back(px2);
 
-            segCoord.push_back(pt1);
-            segCoord.push_back(pt2);
+//            segCoord.push_back(pt1);
+//            segCoord.push_back(pt2);
         }
         else if(idx12 == idx21)
         {
-            segPixel.push_back(px1);
+//            segPixel.push_back(px1);
             segPixel.push_back(pixel[idx12]);
-            segPixel.push_back(px2);
+//            segPixel.push_back(px2);
 
-            segCoord.push_back(pt1);
+//            segCoord.push_back(pt1);
             segCoord.push_back(coords[idx12]);
-            segCoord.push_back(pt2);
+//            segCoord.push_back(pt2);
         }
         else if(idx11 < idx21)
         {
-            segPixel.push_back(px1);
-            segCoord.push_back(pt1);
+//            segPixel.push_back(px1);
+//            segCoord.push_back(pt1);
             for(int i = idx12; i <= idx21; i++)
             {
                 segPixel.push_back(pixel[i]);
                 segCoord.push_back(coords[i]);
             }
-            segPixel.push_back(px2);
-            segCoord.push_back(pt2);
+//            segPixel.push_back(px2);
+//            segCoord.push_back(pt2);
         }
         else if(idx11 > idx21)
         {
-            segPixel.push_back(px1);
-            segCoord.push_back(pt1);
+//            segPixel.push_back(px1);
+//            segCoord.push_back(pt1);
             for(int i = idx11; i > idx21; i--)
             {
                 segPixel.push_back(pixel[i]);
                 segCoord.push_back(coords[i]);
             }
-            segPixel.push_back(px2);
-            segCoord.push_back(pt2);
+//            segPixel.push_back(px2);
+//            segCoord.push_back(pt2);
         }
     }
 }
diff --git a/src/IMainWindow.ui b/src/IMainWindow.ui
index d662a81..b9703f7 100644
--- a/src/IMainWindow.ui
+++ b/src/IMainWindow.ui
@@ -78,6 +78,7 @@
      <string>View</string>
     </property>
     <addaction name="actionAddMapView"/>
+    <addaction name="actionCloneMapView"/>
     <addaction name="separator"/>
     <addaction name="actionShowScale"/>
     <addaction name="actionShowGrid"/>
@@ -121,6 +122,7 @@
     </property>
     <addaction name="actionImportDatabase"/>
     <addaction name="actionVrtBuilder"/>
+    <addaction name="actionCreateRoutinoDatabase"/>
    </widget>
    <addaction name="menuFile"/>
    <addaction name="menuProject"/>
@@ -212,6 +214,39 @@
    </attribute>
    <widget class="QWidget" name="dockWidgetContents_2"/>
   </widget>
+  <widget class="QDockWidget" name="dockRte">
+   <property name="features">
+    <set>QDockWidget::DockWidgetFeatureMask</set>
+   </property>
+   <property name="windowTitle">
+    <string>Route</string>
+   </property>
+   <attribute name="dockWidgetArea">
+    <number>2</number>
+   </attribute>
+   <widget class="QWidget" name="dockWidgetContents_5">
+    <layout class="QVBoxLayout" name="verticalLayout_4">
+     <property name="spacing">
+      <number>0</number>
+     </property>
+     <property name="leftMargin">
+      <number>0</number>
+     </property>
+     <property name="topMargin">
+      <number>0</number>
+     </property>
+     <property name="rightMargin">
+      <number>0</number>
+     </property>
+     <property name="bottomMargin">
+      <number>0</number>
+     </property>
+     <item>
+      <widget class="CRouterSetup" name="widget" native="true"/>
+     </item>
+    </layout>
+   </widget>
+  </widget>
   <action name="actionAddMapView">
    <property name="icon">
     <iconset resource="resources.qrc">
@@ -539,7 +574,36 @@
     <string>Close</string>
    </property>
   </action>
+  <action name="actionCloneMapView">
+   <property name="icon">
+    <iconset resource="resources.qrc">
+     <normaloff>:/icons/32x32/CloneMapWorkspace.png</normaloff>:/icons/32x32/CloneMapWorkspace.png</iconset>
+   </property>
+   <property name="text">
+    <string>Clone Map View</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Shift+T</string>
+   </property>
+  </action>
+  <action name="actionCreateRoutinoDatabase">
+   <property name="icon">
+    <iconset resource="resources.qrc">
+     <normaloff>:/icons/32x32/RouteSetup.png</normaloff>:/icons/32x32/RouteSetup.png</iconset>
+   </property>
+   <property name="text">
+    <string>Create Routino Database</string>
+   </property>
+  </action>
  </widget>
+ <customwidgets>
+  <customwidget>
+   <class>CRouterSetup</class>
+   <extends>QWidget</extends>
+   <header>gis/rte/router/CRouterSetup.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
  <resources>
   <include location="resources.qrc"/>
  </resources>
diff --git a/src/canvas/CCanvas.cpp b/src/canvas/CCanvas.cpp
index cedb124..26738a2 100644
--- a/src/canvas/CCanvas.cpp
+++ b/src/canvas/CCanvas.cpp
@@ -30,6 +30,7 @@
 #include "helpers/CSettings.h"
 #include "map/CMapDraw.h"
 #include "mouse/CMouseEditArea.h"
+#include "mouse/CMouseEditRte.h"
 #include "mouse/CMouseEditTrk.h"
 #include "mouse/CMouseMoveWpt.h"
 #include "mouse/CMouseNormal.h"
@@ -105,6 +106,9 @@ CCanvas::CCanvas(QWidget *parent, const QString &name)
     demLoadIndicator->show();
 
     labelStatusMessages = new QLabel(this);
+    labelStatusMessages->setWordWrap(true);
+    labelStatusMessages->setMinimumWidth(300);
+    labelStatusMessages->setAlignment(Qt::AlignJustify);
     labelStatusMessages->hide();
 
     connect(map, SIGNAL(sigStartThread()), mapLoadIndicator, SLOT(show()));
@@ -188,6 +192,17 @@ void CCanvas::setMouseEditTrk(const QPointF &pt)
     }
 }
 
+void CCanvas::setMouseEditRte(const QPointF &pt)
+{
+    mouse->deleteLater();
+    mouse = new CMouseEditRte(pt, gis, this);
+    if(underMouse())
+    {
+        QApplication::restoreOverrideCursor();
+        QApplication::setOverrideCursor(*mouse);
+    }
+}
+
 void CCanvas::setMouseEditTrk(CGisItemTrk& trk)
 {
     mouse->deleteLater();
@@ -232,6 +247,17 @@ void CCanvas::setMouseEditArea(CGisItemOvlArea& area)
     }
 }
 
+void CCanvas::setMouseEditRte(CGisItemRte& rte)
+{
+    mouse->deleteLater();
+    mouse = new CMouseEditRte(rte, gis, this);
+    if(underMouse())
+    {
+        QApplication::restoreOverrideCursor();
+        QApplication::setOverrideCursor(*mouse);
+    }
+}
+
 void CCanvas::setMouseWptBubble(const IGisItem::key_t& key)
 {
     mouse->deleteLater();
@@ -729,6 +755,11 @@ void CCanvas::getElevationAt(const QPolygonF& pos, QPolygonF& ele)
     return dem->getElevationAt(pos, ele);
 }
 
+void CCanvas::getElevationAt(SGisLine& line)
+{
+    return dem->getElevationAt(line);
+}
+
 void CCanvas::setZoom(bool in, redraw_e& needsRedraw)
 {
     map->zoom(in, needsRedraw);
@@ -736,7 +767,7 @@ void CCanvas::setZoom(bool in, redraw_e& needsRedraw)
     gis->zoom(map->zoom());
 }
 
-bool CCanvas::findPolylineCloseBy(QPointF& pt1, QPointF& pt2, qint32 threshold, QPolygonF& polyline)
+bool CCanvas::findPolylineCloseBy(const QPointF& pt1, const QPointF& pt2, qint32 threshold, QPolygonF& polyline)
 {
     return map->findPolylineCloseBy(pt1, pt2, threshold, polyline);
 }
diff --git a/src/canvas/CCanvas.h b/src/canvas/CCanvas.h
index 729f93f..a91af83 100644
--- a/src/canvas/CCanvas.h
+++ b/src/canvas/CCanvas.h
@@ -25,6 +25,7 @@
 #include <QWidget>
 
 #include "gis/IGisItem.h"
+#include "gis/IGisLine.h"
 
 class CMapDraw;
 class CGrid;
@@ -32,6 +33,7 @@ class CDemDraw;
 class CGisDraw;
 class CGisItemWpt;
 class CGisItemTrk;
+class CGisItemRte;
 class CGisItemOvlArea;
 class QSettings;
 class QPointF;
@@ -46,12 +48,12 @@ inline void USE_ANTI_ALIASING(QPainter& p, bool useAntiAliasing)
     p.setRenderHints(QPainter::TextAntialiasing|QPainter::Antialiasing|QPainter::SmoothPixmapTransform|QPainter::HighQualityAntialiasing, useAntiAliasing);
 }
 
-#define PROGRESS_SETUP(lbl, max) \
-    QProgressDialog progress(lbl, "Abort", 0, max, 0); \
+#define PROGRESS_SETUP(lbl, parent) \
+    QProgressDialog progress(lbl, "Abort", 0, 100, parent); \
     progress.setWindowModality(Qt::WindowModal); \
 
-#define PROGRESS(x, cmd) \
-    progress.setValue(x); \
+#define PROGRESS(x, total, cmd) \
+    progress.setValue(qRound(x * 100.0 / total)); \
     if (progress.wasCanceled()) { cmd; } \
 
 #define PAINT_ROUNDED_RECT(p,r) p.drawRoundedRect(r,5,5)
@@ -85,6 +87,7 @@ public:
 
     qreal getElevationAt(const QPointF &pos);
     void  getElevationAt(const QPolygonF& pos, QPolygonF &ele);
+    void  getElevationAt(SGisLine &line);
 
     void moveMap(const QPointF &delta);
     void zoomTo(const QRectF& rect);
@@ -100,6 +103,7 @@ public:
         , eRedrawMap = 0x01
         , eRedrawDem = 0x02
         , eRedrawGis = 0x04
+        , eRedrawMouse = 0x08
         , eRedrawAll = 0xFFFFFFFF
     };
 
@@ -114,6 +118,8 @@ public:
     void setMouseEditTrk(CGisItemTrk& trk);
     void setMouseRangeTrk(CGisItemTrk& trk);
     void setMouseEditTrk(const QPointF& pt);
+    void setMouseEditRte(const QPointF& pt);
+    void setMouseEditRte(CGisItemRte& rte);
     void setMouseEditArea(CGisItemOvlArea& area);
     void setMouseEditArea(const QPointF& pt);
     void setMouseWptBubble(const IGisItem::key_t& key);
@@ -147,7 +153,7 @@ public:
        @param polyline      the resulting polyline, if any, in [rad]
        @return              Return true if a line has been found.
      */
-    bool findPolylineCloseBy(QPointF& pt1, QPointF& pt2, qint32 threshold, QPolygonF& polyline);
+    bool findPolylineCloseBy(const QPointF& pt1, const QPointF& pt2, qint32 threshold, QPolygonF& polyline);
 
 signals:
     void sigMousePosition(const QPointF& pos, qreal ele);
diff --git a/src/canvas/IDrawContext.cpp b/src/canvas/IDrawContext.cpp
index d6a8034..896cab8 100644
--- a/src/canvas/IDrawContext.cpp
+++ b/src/canvas/IDrawContext.cpp
@@ -163,7 +163,11 @@ QString IDrawContext::getProjection()
     {
         return QString::Null();
     }
-    return pj_get_def(pjsrc,0);
+    char * p = pj_get_def(pjsrc,0);
+    QString str(p);
+    free(p);
+
+    return str;
 }
 
 void IDrawContext::setProjection(const QString& proj)
@@ -244,7 +248,7 @@ void IDrawContext::zoom(const QRectF& rect)
         convertRad2Px(pt2);
 
         QPointF pt = pt2 - pt1;
-        if(qAbs(pt.x()) < (bufWidth - 2 * BUFFER_BORDER) && qAbs(pt.y() < (bufHeight - 2 * BUFFER_BORDER)))
+        if(qAbs(pt.x()) < (bufWidth - 2 * BUFFER_BORDER) && (qAbs(pt.y()) < (bufHeight - 2 * BUFFER_BORDER)))
         {
             break;
         }
@@ -274,7 +278,7 @@ void IDrawContext::zoom(int idx)
     }
 
     mutex.lock(); // --------- start serialize with thread
-    if(zoomIndex != idx)
+    if((zoomIndex != idx) || (zoomFactor.x() != scales[idx]))
     {
         zoomIndex       = idx;
         zoomFactor.rx() = scales[idx];
diff --git a/src/cursors/cursorDelete.png b/src/cursors/cursorDelete.png
new file mode 100644
index 0000000..2881f7f
Binary files /dev/null and b/src/cursors/cursorDelete.png differ
diff --git a/src/cursors/cursorMovePoint.png b/src/cursors/cursorMovePoint.png
new file mode 100644
index 0000000..5513d1c
Binary files /dev/null and b/src/cursors/cursorMovePoint.png differ
diff --git a/src/dem/CDemDraw.cpp b/src/dem/CDemDraw.cpp
index 84de920..44d26b0 100644
--- a/src/dem/CDemDraw.cpp
+++ b/src/dem/CDemDraw.cpp
@@ -285,6 +285,11 @@ void CDemDraw::getElevationAt(const QPolygonF& pos, QPolygonF& ele)
     }
 }
 
+void CDemDraw::getElevationAt(SGisLine& line)
+{
+    line.updateElevation(this);
+}
+
 void CDemDraw::drawt(buffer_t& currentBuffer)
 {
     // iterate over all active maps and call the draw method
diff --git a/src/dem/CDemDraw.h b/src/dem/CDemDraw.h
index 6e45f0c..b4c9d1d 100644
--- a/src/dem/CDemDraw.h
+++ b/src/dem/CDemDraw.h
@@ -49,6 +49,7 @@ public:
 
     qreal getElevationAt(const QPointF& pos);
     void  getElevationAt(const QPolygonF& pos, QPolygonF& ele);
+    void  getElevationAt(SGisLine& line);
 
     void setProjection(const QString& proj);
 
diff --git a/src/dem/CDemPathSetup.cpp b/src/dem/CDemPathSetup.cpp
index e613a70..5e9b8d1 100644
--- a/src/dem/CDemPathSetup.cpp
+++ b/src/dem/CDemPathSetup.cpp
@@ -56,8 +56,11 @@ void CDemPathSetup::slotAddPath()
     QString path = QFileDialog::getExistingDirectory(this, tr("Select DEM file path..."), QDir::homePath(), 0);
     if(!path.isEmpty())
     {
-        QListWidgetItem * item = new QListWidgetItem(listWidget);
-        item->setText(path);
+        if(!paths.contains(path))
+        {
+            QListWidgetItem * item = new QListWidgetItem(listWidget);
+            item->setText(path);
+        }
     }
 }
 
diff --git a/src/dem/CDemVRT.cpp b/src/dem/CDemVRT.cpp
index 724537b..4ded0a3 100644
--- a/src/dem/CDemVRT.cpp
+++ b/src/dem/CDemVRT.cpp
@@ -82,6 +82,7 @@ CDemVRT::CDemVRT(const QString &filename, CDemDraw *parent)
     qDebug() << ptr;
 
     pjsrc = pj_init_plus(ptr);
+    free(ptr);
     if(pjsrc == 0)
     {
         delete dataset; dataset = 0;
diff --git a/src/device/IDevice.cpp b/src/device/IDevice.cpp
index 85124c8..49b7c1f 100644
--- a/src/device/IDevice.cpp
+++ b/src/device/IDevice.cpp
@@ -192,7 +192,9 @@ void IDevice::updateProject(IGisProject * project)
         }
     }
 
+    project->blockUpdateItems(true);
     insertCopyOfProject(project);
+    project->blockUpdateItems(false);
 }
 
 bool IDevice::testForExternalProject(const QString& filename)
diff --git a/src/device/IDeviceWatcher.cpp b/src/device/IDeviceWatcher.cpp
index 2ed45fa..359f244 100644
--- a/src/device/IDeviceWatcher.cpp
+++ b/src/device/IDeviceWatcher.cpp
@@ -21,6 +21,7 @@
 #include "device/IDeviceWatcher.h"
 #include "gis/CGisListWks.h"
 
+#include <QApplication>
 #include <QtCore>
 
 IDeviceWatcher::IDeviceWatcher(CGisListWks *parent)
@@ -45,6 +46,7 @@ void IDeviceWatcher::probeForDevice(const QString& mountPoint, const QString& pa
     qDebug() << "Probe device at" << mountPoint << path << label;
     QStringList entries = dir.entryList();
 
+    QApplication::setOverrideCursor(Qt::WaitCursor);
     if(entries.contains("Garmin"))
     {
         if(dir.exists("Garmin/GarminDevice.xml"))
@@ -62,4 +64,5 @@ void IDeviceWatcher::probeForDevice(const QString& mountPoint, const QString& pa
     {
         qDebug() << "Don't know it :(";
     }
+    QApplication::restoreOverrideCursor();
 }
diff --git a/src/gis/CGisListWks.cpp b/src/gis/CGisListWks.cpp
index c95c690..7d15cde 100644
--- a/src/gis/CGisListWks.cpp
+++ b/src/gis/CGisListWks.cpp
@@ -39,6 +39,7 @@
 #include "gis/ovl/CGisItemOvlArea.h"
 #include "gis/prj/IGisProject.h"
 #include "gis/qms/CQmsProject.h"
+#include "gis/rte/CCreateRouteFromWpt.h"
 #include "gis/rte/CGisItemRte.h"
 #include "gis/search/CSearchGoogle.h"
 #include "gis/trk/CGisItemTrk.h"
@@ -139,6 +140,11 @@ CGisListWks::CGisListWks(QWidget *parent)
     menuItemRte     = new QMenu(this);
     menuItemRte->addAction(actionEditDetails);
     menuItemRte->addAction(actionCopyItem);
+    menuItemRte->addSeparator();
+    actionCalcRte   = menuItemRte->addAction(QIcon("://icons/32x32/Apply.png"), tr("Calculate Route"), this, SLOT(slotCalcRte()));
+    actionResetRte  = menuItemRte->addAction(QIcon("://icons/32x32/Reset.png"), tr("Reset Route"), this, SLOT(slotResetRte()));
+    actionEditRte   = menuItemRte->addAction(QIcon("://icons/32x32/LineMove.png"), tr("Edit Route"), this, SLOT(slotEditRte()));
+    menuItemRte->addSeparator();
     menuItemRte->addAction(actionDelete);
 
 
@@ -153,8 +159,11 @@ CGisListWks::CGisListWks(QWidget *parent)
 
     menuItem        = new QMenu(this);
     menuItem->addAction(actionCopyItem);
+    actionRteFromWpt = menuItem->addAction(QIcon("://icons/32x32/Route.png"), tr("Create Route"), this, SLOT(slotRteFromWpt()));
+    menuItem->addAction(actionCombineTrk);
     menuItem->addAction(actionDelete);
 
+
     connect(actionFocusTrk, SIGNAL(triggered(bool)), this, SLOT(slotFocusTrk(bool)));
     connect(qApp, SIGNAL(aboutToQuit ()), this, SLOT(slotSaveWorkspace()));
 
@@ -261,9 +270,9 @@ void CGisListWks::migrateDB(int version)
 
     for(version++; version <= DB_VERSION; version++)
     {
-        switch(version)
-        {
-        }
+//        switch(version)
+//        {
+//        }
     }
     query.prepare( "UPDATE versioninfo set version=:version");
     query.bindValue(":version", version - 1);
@@ -563,6 +572,8 @@ void CGisListWks::dropEvent ( QDropEvent  * e )
     IGisProject * project = dynamic_cast<IGisProject*>(itemAt(e->pos()));
     if(project)
     {
+        project->blockUpdateItems(true);
+
         int cnt = 1;
         int N   = items.size();
         QProgressDialog progress("Drop items...", "Abort drop", 0, 100, this);
@@ -570,7 +581,7 @@ void CGisListWks::dropEvent ( QDropEvent  * e )
 
         foreach(QTreeWidgetItem * item, items)
         {
-            progress.setValue((100 * cnt++) / N);
+            progress.setValue(qRound(100.0 * cnt++ / N));
             if (progress.wasCanceled())
             {
                 break;
@@ -582,6 +593,8 @@ void CGisListWks::dropEvent ( QDropEvent  * e )
                 project->insertCopyOfItem(gisItem, NOIDX, lastResult);
             }
         }
+
+        project->blockUpdateItems(false);
     }
 
     IDevice * device = dynamic_cast<IDevice*>(itemAt(e->pos()));
@@ -693,11 +706,11 @@ void CGisListWks::slotSaveWorkspace()
     qDebug() << "slotSaveWorkspace()";
 
     const int total = topLevelItemCount();
-    PROGRESS_SETUP(tr("Saving workspace. Please wait."), total);
+    PROGRESS_SETUP(tr("Saving workspace. Please wait."), this);
 
     for(int i = 0; i < total; i++)
     {
-        PROGRESS(i, return );
+        PROGRESS(i, total, return );
 
         IGisProject * project = dynamic_cast<IGisProject*>(topLevelItem(i));
         if(project == 0)
@@ -734,12 +747,15 @@ void CGisListWks::slotLoadWorkspace()
     query.prepare("SELECT type, key, name, changed, data FROM workspace");
     QUERY_EXEC(return );
 
-    PROGRESS_SETUP(tr("Loading workspace. Please wait."), query.size());
+    const int total = query.size();
+    PROGRESS_SETUP(tr("Loading workspace. Please wait."), this);
     quint32 progCnt = 0;
 
+    QApplication::setOverrideCursor(Qt::WaitCursor);
+
     while(query.next())
     {
-        PROGRESS(progCnt++, return );
+        PROGRESS(progCnt++, total, return );
 
         int type        = query.value(0).toInt();
         QString name    = query.value(2).toString();
@@ -771,8 +787,10 @@ void CGisListWks::slotLoadWorkspace()
         {
             CDBProject * dbProject;
             project = dbProject = new CDBProject(this);
+
             project->IGisProject::operator<<(stream);
             dbProject->restoreDBLink();
+
             if(!project->isValid())
             {
                 delete project;
@@ -799,6 +817,7 @@ void CGisListWks::slotLoadWorkspace()
     }
 
     emit sigChanged();
+    QApplication::restoreOverrideCursor();
 }
 
 void CGisListWks::slotContextMenu(const QPoint& point)
@@ -830,6 +849,29 @@ void CGisListWks::slotContextMenu(const QPoint& point)
         IGisItem * gisItem = dynamic_cast<IGisItem*>(currentItem());
         if(gisItem != 0)
         {
+            bool onlyWpts = true;
+            bool onlyTrks = true;
+            foreach(QTreeWidgetItem * item, selectedItems())
+            {
+                if(item->type() != IGisItem::eTypeWpt)
+                {
+                    onlyWpts = false;
+                }
+
+                if(item->type() != IGisItem::eTypeTrk)
+                {
+                    onlyTrks = false;
+                }
+
+                if(!onlyTrks && !onlyWpts)
+                {
+                    break;
+                }
+            }
+
+            actionRteFromWpt->setEnabled(onlyWpts);
+            actionCombineTrk->setEnabled(onlyTrks);
+
             menuItem->exec(p);
             return;
         }
@@ -868,7 +910,7 @@ void CGisListWks::slotContextMenu(const QPoint& point)
             switch(gisItem->type())
             {
             case IGisItem::eTypeTrk:
-                actionCombineTrk->setDisabled(isOnDevice);
+                actionCombineTrk->setEnabled(true); // might be disabled by menuItem
                 actionRangeTrk->setDisabled(isOnDevice);
                 actionReverseTrk->setDisabled(isOnDevice);
                 actionEditTrk->setDisabled(isOnDevice);
@@ -953,7 +995,9 @@ void CGisListWks::slotDeleteProject()
         IGisProject * project = dynamic_cast<IGisProject*>(item);
         if(project != 0)
         {
+            QApplication::setOverrideCursor(Qt::ArrowCursor);
             int res = QMessageBox::question(&CMainWindow::self(), QObject::tr("Delete project..."), QObject::tr("Do you really want to delete %1?").arg(project->getFilename()), QMessageBox::Ok|QMessageBox::No,QMessageBox::Ok);
+            QApplication::restoreOverrideCursor();
             if(res != QMessageBox::Ok)
             {
                 continue;
@@ -1047,7 +1091,8 @@ void CGisListWks::slotDeleteItem()
     QList<QTreeWidgetItem*> items       = selectedItems();
     QMessageBox::StandardButtons last   = QMessageBox::NoButton;
 
-    QSet<CDBProject*> projects;
+    QSet<CDBProject*>   projects;
+    QSet<IGisProject*>  projectsAll;
 
     foreach(QTreeWidgetItem * item, items)
     {
@@ -1058,16 +1103,23 @@ void CGisListWks::slotDeleteItem()
             IGisProject * project = dynamic_cast<IGisProject*>(gisItem->parent());
             if(project)
             {
+                project->blockUpdateItems(true);
                 yes = project->delItemByKey(gisItem->getKey(), last);
-            }
 
-            /*
-                collect database projects to update their counterpart in
-                the database view, after all operations are done.
-             */
-            if(yes && project->getType() == IGisProject::eTypeDb)
-            {
-                projects << dynamic_cast<CDBProject*>(project);
+
+                /*
+                    collect database projects to update their counterpart in
+                    the database view, after all operations are done.
+                 */
+                if(yes && project->getType() == IGisProject::eTypeDb)
+                {
+                    projects << dynamic_cast<CDBProject*>(project);
+                }
+
+                /*
+                    Collect all projects to unblock update later on.
+                 */
+                projectsAll << project;
             }
 
             if(last == QMessageBox::Cancel)
@@ -1081,16 +1133,18 @@ void CGisListWks::slotDeleteItem()
     // this will update the database view.
     foreach(CDBProject * project, projects)
     {
-        if(project)
-        {
-            project->postStatus();
-        }
+        project->postStatus();
+    }
+    // unblock update for all projects seen
+    foreach(IGisProject * project, projectsAll)
+    {
+        project->blockUpdateItems(false);
     }
 }
 
 void CGisListWks::slotCopyItem()
 {
-    CGisListWksEditLock lock(false, IGisItem::mutexItems);
+    CGisListWksEditLock lock(true, IGisItem::mutexItems);
 
     IGisProject * project = CGisWidget::self().selectProject();
     if(project == 0)
@@ -1100,6 +1154,7 @@ void CGisListWks::slotCopyItem()
 
     int lastResult = CSelectCopyAction::eResultNone;
 
+    project->blockUpdateItems(true);
     QList<QTreeWidgetItem*> items = selectedItems();
     foreach(QTreeWidgetItem * item, items)
     {
@@ -1111,6 +1166,7 @@ void CGisListWks::slotCopyItem()
 
         project->insertCopyOfItem(gisItem, NOIDX, lastResult);
     }
+    project->blockUpdateItems(false);
 }
 
 void CGisListWks::slotProjWpt()
@@ -1176,10 +1232,22 @@ void CGisListWks::slotReverseTrk()
 void CGisListWks::slotCombineTrk()
 {
     CGisListWksEditLock lock(false, IGisItem::mutexItems);
-    CGisItemTrk * gisItem = dynamic_cast<CGisItemTrk*>(currentItem());
-    if(gisItem != 0)
+
+    QList<IGisItem::key_t> keys;
+
+    QList<QTreeWidgetItem*> items = selectedItems();
+    foreach(QTreeWidgetItem * item, items)
+    {
+        CGisItemTrk * gisItem = dynamic_cast<CGisItemTrk*>(item);
+        if(gisItem)
+        {
+            keys << gisItem->getKey();
+        }
+    }
+
+    if(!keys.isEmpty())
     {
-        CGisWidget::self().combineTrkByKey(gisItem->getKey());
+        CGisWidget::self().combineTrkByKey(keys);
     }
 }
 
@@ -1193,6 +1261,37 @@ void CGisListWks::slotRangeTrk()
     }
 }
 
+void CGisListWks::slotCalcRte()
+{
+    CGisListWksEditLock lock(false, IGisItem::mutexItems);
+    CGisItemRte * gisItem = dynamic_cast<CGisItemRte*>(currentItem());
+    if(gisItem != 0)
+    {
+        CGisWidget::self().calcRteByKey(gisItem->getKey());
+    }
+}
+
+void CGisListWks::slotResetRte()
+{
+    CGisListWksEditLock lock(false, IGisItem::mutexItems);
+    CGisItemRte * gisItem = dynamic_cast<CGisItemRte*>(currentItem());
+    if(gisItem != 0)
+    {
+        CGisWidget::self().resetRteByKey(gisItem->getKey());
+    }
+}
+
+
+void CGisListWks::slotEditRte()
+{
+    CGisListWksEditLock lock(false, IGisItem::mutexItems);
+    CGisItemRte * gisItem = dynamic_cast<CGisItemRte*>(currentItem());
+    if(gisItem != 0)
+    {
+        CGisWidget::self().editRteByKey(gisItem->getKey());
+    }
+}
+
 void CGisListWks::slotEditArea()
 {
     CGisListWksEditLock lock(false, IGisItem::mutexItems);
@@ -1262,7 +1361,7 @@ void CGisListWks::slotSearchGoogle(bool on)
 
 void CGisListWks::slotSyncWksDev()
 {
-    CGisListWksEditLock lock(false, IGisItem::mutexItems);
+    CGisListWksEditLock lock(true, IGisItem::mutexItems);
 
     IGisProject * project = dynamic_cast<IGisProject*>(currentItem());
     if(project == 0)
@@ -1281,7 +1380,6 @@ void CGisListWks::slotSyncWksDev()
         dlg.getSlectedDevices(keys);
     }
 
-    QApplication::setOverrideCursor(Qt::WaitCursor);
     CCanvas * canvas = CMainWindow::self().getVisibleCanvas();
     const int N = topLevelItemCount();
     for(int n = 0; n < N; n++)
@@ -1305,7 +1403,6 @@ void CGisListWks::slotSyncWksDev()
         canvas->reportStatus("device", "");
     }
     emit sigChanged();
-    QApplication::restoreOverrideCursor();
 }
 
 void CGisListWks::slotSyncDevWks()
@@ -1350,98 +1447,124 @@ void CGisListWks::slotSyncDevWks()
 
 bool CGisListWks::event(QEvent * e)
 {
-    CGisListWksEditLock lock(true, IGisItem::mutexItems);
-
-    switch(e->type())
-    {
-    case eEvtD2WReqInfo:
+    if(e->type() > QEvent::User)
     {
-        CEvtD2WReqInfo * evt = (CEvtD2WReqInfo*)e;
-        CDBProject * project =  getProjectById(evt->id, evt->db);
-        if(project)
+        CGisListWksEditLock lock(true, IGisItem::mutexItems);
+
+
+        switch(e->type())
+        {
+        case eEvtD2WReqInfo:
         {
-            project->postStatus();
+            CEvtD2WReqInfo * evt = (CEvtD2WReqInfo*)e;
+            CDBProject * project =  getProjectById(evt->id, evt->db);
+            if(project)
+            {
+                project->postStatus();
+            }
+            e->accept();
+            emit sigChanged();
+            return true;
         }
-        e->accept();
-        emit sigChanged();
-        return true;
-    }
 
-    case eEvtD2WShowFolder:
-    {
-        CEvtD2WShowFolder * evt = (CEvtD2WShowFolder*)e;
-        CDBProject * project =  getProjectById(evt->id, evt->db);
-        if(project == 0)
+        case eEvtD2WShowFolder:
         {
-            if(evt->id == 0)
+            CEvtD2WShowFolder * evt = (CEvtD2WShowFolder*)e;
+            CDBProject * project =  getProjectById(evt->id, evt->db);
+            if(project == 0)
             {
-                project = new CLostFoundProject(evt->db, this);
+                if(evt->id == 0)
+                {
+                    project = new CLostFoundProject(evt->db, this);
+                }
+                else
+                {
+                    project = new CDBProject(evt->db, evt->id, this);
+                }
+                if(!project->isValid())
+                {
+                    delete project;
+                }
             }
-            else
+            e->accept();
+            emit sigChanged();
+            return true;
+        }
+
+        case eEvtD2WHideFolder:
+        {
+            CEvtD2WHideFolder * evt = (CEvtD2WHideFolder*)e;
+            CDBProject * project =  getProjectById(evt->id, evt->db);
+            if(project && project->askBeforClose())
             {
-                project = new CDBProject(evt->db, evt->id, this);
+                return false;
             }
-            if(!project->isValid())
+            delete project;
+
+            e->accept();
+            emit sigChanged();
+            return true;
+        }
+
+        case eEvtD2WShowItems:
+        {
+            CEvtD2WShowItems * evt = (CEvtD2WShowItems*)e;
+            CDBProject * project =  getProjectById(evt->id, evt->db);
+            if(project)
             {
-                delete project;
+                project->showItems(evt);
             }
+            e->accept();
+            emit sigChanged();
+            return true;
         }
-        e->accept();
-        emit sigChanged();
-        return true;
-    }
 
-    case eEvtD2WHideFolder:
-    {
-        CEvtD2WHideFolder * evt = (CEvtD2WHideFolder*)e;
-        CDBProject * project =  getProjectById(evt->id, evt->db);
-        delete project;
-
-        e->accept();
-        emit sigChanged();
-        return true;
-    }
-
-    case eEvtD2WShowItems:
-    {
-        CEvtD2WShowItems * evt = (CEvtD2WShowItems*)e;
-        CDBProject * project =  getProjectById(evt->id, evt->db);
-        if(project)
+        case eEvtD2WHideItems:
         {
-            project->showItems(evt);
+            CEvtD2WHideItems * evt = (CEvtD2WHideItems*)e;
+            CDBProject * project =  getProjectById(evt->id, evt->db);
+            if(project)
+            {
+                project->hideItems(evt);
+            }
+            e->accept();
+            emit sigChanged();
+            return true;
         }
-        e->accept();
-        emit sigChanged();
-        return true;
-    }
 
-    case eEvtD2WHideItems:
-    {
-        CEvtD2WHideItems * evt = (CEvtD2WHideItems*)e;
-        CDBProject * project =  getProjectById(evt->id, evt->db);
-        if(project)
+        case eEvtD2WUpdateLnF:
         {
-            project->hideItems(evt);
+            CEvtD2WUpdateLnF * evt = (CEvtD2WUpdateLnF*)e;
+            CLostFoundProject * project = dynamic_cast<CLostFoundProject*>(getProjectById(evt->id, evt->db));
+            if(project)
+            {
+                project->updateFromDb();
+            }
+            e->accept();
+            emit sigChanged();
+            return true;
+        }
         }
-        e->accept();
-        emit sigChanged();
-        return true;
     }
+    return QTreeWidget::event(e);
+}
+
+
 
-    case eEvtD2WUpdateLnF:
+void CGisListWks::slotRteFromWpt()
+{
+    QList<IGisItem::key_t> keys;
+    foreach(QTreeWidgetItem * item, selectedItems())
     {
-        CEvtD2WUpdateLnF * evt = (CEvtD2WUpdateLnF*)e;
-        CLostFoundProject * project = dynamic_cast<CLostFoundProject*>(getProjectById(evt->id, evt->db));
-        if(project)
+        CGisItemWpt * wpt = dynamic_cast<CGisItemWpt*>(item);
+        if(wpt == 0)
         {
-            project->updateFromDb();
+            continue;
         }
-        e->accept();
-        emit sigChanged();
-        return true;
-    }
+
+        keys << wpt->getKey();
     }
 
-    return QTreeWidget::event(e);
+    CCreateRouteFromWpt dlg(keys, this);
+    dlg.exec();
 }
-
diff --git a/src/gis/CGisListWks.h b/src/gis/CGisListWks.h
index ce09f65..211b8cb 100644
--- a/src/gis/CGisListWks.h
+++ b/src/gis/CGisListWks.h
@@ -83,6 +83,9 @@ private slots:
     void slotReverseTrk();
     void slotCombineTrk();
     void slotRangeTrk();
+    void slotCalcRte();
+    void slotResetRte();
+    void slotEditRte();
     void slotEditArea();
     void slotAddEmptyProject();
     void slotCloseAllProjects();
@@ -90,6 +93,7 @@ private slots:
     void slotCopyItem();
     void slotSyncWksDev();
     void slotSyncDevWks();
+    void slotRteFromWpt();
 
 
 private:
@@ -129,7 +133,11 @@ private:
     QAction * actionReverseTrk;
     QAction * actionCombineTrk;
     QAction * actionRangeTrk;
+    QAction * actionCalcRte;
+    QAction * actionResetRte;
+    QAction * actionEditRte;
     QAction * actionEditArea;
+    QAction * actionRteFromWpt;
 
     QMenu * menuNone;
 
diff --git a/src/gis/CGisWidget.cpp b/src/gis/CGisWidget.cpp
index 3a3180d..c616912 100644
--- a/src/gis/CGisWidget.cpp
+++ b/src/gis/CGisWidget.cpp
@@ -28,6 +28,7 @@
 #include "gis/ovl/CGisItemOvlArea.h"
 #include "gis/prj/IGisProject.h"
 #include "gis/qms/CQmsProject.h"
+#include "gis/rte/CGisItemRte.h"
 #include "gis/trk/CGisItemTrk.h"
 #include "gis/wpt/CGisItemWpt.h"
 #include "gis/wpt/CProjWpt.h"
@@ -87,6 +88,8 @@ void CGisWidget::loadGisProject(const QString& filename)
 {
     // add project to workspace
     QApplication::setOverrideCursor(Qt::WaitCursor);
+    treeWks->blockSignals(true);
+
     QMutexLocker lock(&IGisItem::mutexItems);
     IGisProject * item = 0;
     QString suffix = QFileInfo(filename).suffix().toLower();
@@ -108,11 +111,13 @@ void CGisWidget::loadGisProject(const QString& filename)
     // skip if project is already loaded
     if(item && treeWks->hasProject(item))
     {
+        QMessageBox::information(this, tr("Load project..."), tr("The project \"%1\" is already in the workspace.").arg(item->getName()), QMessageBox::Abort);
+
         delete item;
         item = 0;
     }
 
-
+    treeWks->blockSignals(false);
     QApplication::restoreOverrideCursor();
 
     emit sigChanged();
@@ -466,12 +471,24 @@ void CGisWidget::reverseTrkByKey(const IGisItem::key_t& key)
 
 void CGisWidget::combineTrkByKey(const IGisItem::key_t& key)
 {
+    QList<IGisItem::key_t> keys;
+    keys << key;
+    combineTrkByKey(keys);
+}
+
+void CGisWidget::combineTrkByKey(const QList<IGisItem::key_t>& keys)
+{
+    if(keys.isEmpty())
+    {
+        return;
+    }
+
     QMutexLocker lock(&IGisItem::mutexItems);
 
-    CGisItemTrk * trk = dynamic_cast<CGisItemTrk*>(getItemByKey(key));
+    CGisItemTrk * trk = dynamic_cast<CGisItemTrk*>(getItemByKey(keys.first()));
     if(trk)
     {
-        trk->combine();
+        trk->combine(keys);
     }
 
     emit sigChanged();
@@ -512,6 +529,53 @@ void CGisWidget::rangeTrkByKey(const IGisItem::key_t& key)
     }
 }
 
+void CGisWidget::editRteByKey(const IGisItem::key_t& key)
+{
+    QMutexLocker lock(&IGisItem::mutexItems);
+
+    CGisItemRte * rte = dynamic_cast<CGisItemRte*>(getItemByKey(key));
+    if(rte != 0)
+    {
+        if(!rte->setReadOnlyMode(false))
+        {
+            return;
+        }
+
+        CCanvas * canvas = CMainWindow::self().getVisibleCanvas();
+        if(canvas != 0)
+        {
+            canvas->setMouseEditRte(*rte);
+        }
+    }
+}
+
+void CGisWidget::calcRteByKey(const IGisItem::key_t& key)
+{
+    QMutexLocker lock(&IGisItem::mutexItems);
+
+    CGisItemRte * rte = dynamic_cast<CGisItemRte*>(getItemByKey(key));
+    if(rte != 0)
+    {
+        QApplication::setOverrideCursor(Qt::WaitCursor);
+        rte->calc();
+        QApplication::restoreOverrideCursor();
+    }
+}
+
+void CGisWidget::resetRteByKey(const IGisItem::key_t& key)
+{
+    QMutexLocker lock(&IGisItem::mutexItems);
+
+    CGisItemRte * rte = dynamic_cast<CGisItemRte*>(getItemByKey(key));
+    if(rte != 0)
+    {
+        QApplication::setOverrideCursor(Qt::WaitCursor);
+        rte->reset();
+        QApplication::restoreOverrideCursor();
+    }
+}
+
+
 void CGisWidget::editAreaByKey(const IGisItem::key_t& key)
 {
     QMutexLocker lock(&IGisItem::mutexItems);
diff --git a/src/gis/CGisWidget.h b/src/gis/CGisWidget.h
index 0afd5cd..07c409b 100644
--- a/src/gis/CGisWidget.h
+++ b/src/gis/CGisWidget.h
@@ -257,8 +257,16 @@ public:
 
     void combineTrkByKey(const IGisItem::key_t &key);
 
+    void combineTrkByKey(const QList<IGisItem::key_t>& keys);
+
     void rangeTrkByKey(const IGisItem::key_t &key);
 
+    void editRteByKey(const IGisItem::key_t& key);
+
+    void calcRteByKey(const IGisItem::key_t& key);
+
+    void resetRteByKey(const IGisItem::key_t& key);
+
     void editAreaByKey(const IGisItem::key_t &key);
 
     /**
diff --git a/src/gis/CSelDevices.cpp b/src/gis/CSelDevices.cpp
index aed62b2..d562904 100644
--- a/src/gis/CSelDevices.cpp
+++ b/src/gis/CSelDevices.cpp
@@ -53,10 +53,13 @@ CSelDevices::CSelDevices(IGisProject * project, QTreeWidget *wks)
             item->setCheckState(Qt::Unchecked);
         }
     }
+
+    QApplication::setOverrideCursor(Qt::ArrowCursor);
 }
 
 CSelDevices::~CSelDevices()
 {
+    QApplication::restoreOverrideCursor();
 }
 
 
diff --git a/src/gis/IGisItem.cpp b/src/gis/IGisItem.cpp
index 46b3d98..58dd0ed 100644
--- a/src/gis/IGisItem.cpp
+++ b/src/gis/IGisItem.cpp
@@ -419,12 +419,12 @@ bool IGisItem::setReadOnlyMode(bool readOnly)
         {
             QApplication::setOverrideCursor(Qt::ArrowCursor);
             QString str = QObject::tr("This element is probably read-only because it was not created within QMapShack. Usually you should not want to change imported data. But if you think that is ok press'Ok'.");
-            if(QMessageBox::warning(&CMainWindow::self(), QObject::tr("Read Only Mode..."), str, QMessageBox::Ok|QMessageBox::Abort, QMessageBox::Ok) != QMessageBox::Ok)
+            int res = QMessageBox::warning(&CMainWindow::self(), QObject::tr("Read Only Mode..."), str, QMessageBox::Ok|QMessageBox::Abort, QMessageBox::Ok);
+            QApplication::restoreOverrideCursor();
+            if(res != QMessageBox::Ok)
             {
-                QApplication::restoreOverrideCursor();
                 return false;
             }
-            QApplication::restoreOverrideCursor();
         }
     }
 
diff --git a/src/gis/IGisLine.cpp b/src/gis/IGisLine.cpp
index c56e721..cd2382c 100644
--- a/src/gis/IGisLine.cpp
+++ b/src/gis/IGisLine.cpp
@@ -16,7 +16,70 @@
 
 **********************************************************************************************/
 
-#include "IGisLine.h"
+#include "dem/CDemDraw.h"
+#include "gis/CGisDraw.h"
+#include "gis/IGisLine.h"
+
+IGisLine::subpt_t::subpt_t()
+    : ele(NOINT)
+{
+}
+
+IGisLine::subpt_t::subpt_t(const QPointF& pt)
+    : coord(pt)
+    , ele(NOINT)
+{
+}
+
+IGisLine::point_t::point_t(const QPointF& pt)
+{
+    coord = pt;
+    pixel = pt;
+}
+
+void IGisLine::point_t::resetElevation()
+{
+    ele = NOINT;
+    for(int i = 0; i < subpts.size(); i++)
+    {
+        subpts[i].ele = NOINT;
+    }
+}
+
+void SGisLine::updateElevation(CDemDraw * dem)
+{
+    for(int i = 0; i < size(); i++)
+    {
+        IGisLine::point_t& pt = (*this)[i];
+        pt.ele = dem->getElevationAt(pt.coord);
+
+        for(int n = 0; n < pt.subpts.size(); n++)
+        {
+            IGisLine::subpt_t& sub = pt.subpts[n];
+            sub.ele = dem->getElevationAt(sub.coord);
+        }
+    }
+}
+
+
+void SGisLine::updatePixel(CGisDraw * gis)
+{
+    for(int i = 0; i < size(); i++)
+    {
+        IGisLine::point_t& pt = (*this)[i];
+
+        pt.pixel = pt.coord;
+        gis->convertRad2Px(pt.pixel);
+
+        for(int n = 0; n < pt.subpts.size(); n++)
+        {
+            IGisLine::subpt_t& sub = pt.subpts[n];
+
+            sub.pixel = sub.coord;
+            gis->convertRad2Px(sub.pixel);
+        }
+    }
+}
 
 IGisLine::IGisLine()
 {
diff --git a/src/gis/IGisLine.h b/src/gis/IGisLine.h
index ffd609c..ebfdc80 100644
--- a/src/gis/IGisLine.h
+++ b/src/gis/IGisLine.h
@@ -19,7 +19,13 @@
 #ifndef IGISLINE_H
 #define IGISLINE_H
 
+#include <QPointF>
+#include <QVector>
+
 class QPolygonF;
+class CGisDraw;
+class CDemDraw;
+struct SGisLine;
 
 class IGisLine
 {
@@ -27,9 +33,35 @@ public:
     IGisLine();
     virtual ~IGisLine();
 
-    virtual void setDataFromPolyline(const QPolygonF& line) = 0;
-    virtual void getPolylineFromData(QPolygonF& line) = 0;
+    struct subpt_t
+    {
+        subpt_t();
+        subpt_t(const QPointF& pt);
+        QPointF coord;
+        QPointF pixel;
+        qint32 ele;
+    };
+
+    struct point_t : public subpt_t
+    {
+        point_t()
+        {
+        }
+        point_t(const QPointF &pt);
+        void resetElevation();
+        QVector<subpt_t> subpts;
+    };
+
+    virtual void setDataFromPolyline(const SGisLine& line) = 0;
+    virtual void getPolylineFromData(SGisLine& line) = 0;
 };
 
+struct SGisLine : public QVector<IGisLine::point_t>
+{
+    void updateElevation(CDemDraw * dem);
+    void updatePixel(CGisDraw * gis);
+};
+
+
 #endif //IGISLINE_H
 
diff --git a/src/gis/db/CDBItem.cpp b/src/gis/db/CDBItem.cpp
index 07e6707..f39c181 100644
--- a/src/gis/db/CDBItem.cpp
+++ b/src/gis/db/CDBItem.cpp
@@ -95,5 +95,5 @@ void CDBItem::remove()
     query.prepare("DELETE FROM folder2item WHERE parent=:parent AND child=:child");
     query.bindValue(":parent", folder->getId());
     query.bindValue(":child", id);
-    QUERY_EXEC();
+    QUERY_EXEC(; );
 }
diff --git a/src/gis/db/CDBProject.cpp b/src/gis/db/CDBProject.cpp
index 31dafda..cb673c5 100644
--- a/src/gis/db/CDBProject.cpp
+++ b/src/gis/db/CDBProject.cpp
@@ -112,7 +112,7 @@ void CDBProject::setupName(const QString &defaultName)
     query.bindValue(":id", id);
     query.bindValue(":type1", IDBFolder::eTypeGroup);
     query.bindValue(":type2", IDBFolder::eTypeProject);
-    QUERY_EXEC( );
+    QUERY_EXEC(; );
     if(query.next())
     {
         nameSuffix   = query.value(0).toString();
@@ -334,10 +334,9 @@ bool CDBProject::save()
                             throw -1;
                         }
 
-                        QApplication::setOverrideCursor(Qt::ArrowCursor);
+
                         CSelectSaveAction dlg(item, item1, &progress);
                         dlg.exec();
-                        QApplication::restoreOverrideCursor();
 
                         result = dlg.getResult();
                         if(dlg.allOthersToo())
@@ -453,8 +452,8 @@ void CDBProject::showItems(CEvtD2WShowItems * evt)
         }
     }
 
-    setToolTip(CGisListWks::eColumnName, getInfo());
     postStatus();
+    setToolTip(CGisListWks::eColumnName, getInfo());
 }
 
 void CDBProject::hideItems(CEvtD2WHideItems * evt)
@@ -469,7 +468,8 @@ void CDBProject::hideItems(CEvtD2WHideItems * evt)
         key.item = k;
         delItemByKey(key, last);
     }
-    setToolTip(CGisListWks::eColumnName, getInfo());
+
     postStatus();
+    setToolTip(CGisListWks::eColumnName, getInfo());
 }
 
diff --git a/src/gis/db/CSelectDBFolder.cpp b/src/gis/db/CSelectDBFolder.cpp
index 62213d6..f78792a 100644
--- a/src/gis/db/CSelectDBFolder.cpp
+++ b/src/gis/db/CSelectDBFolder.cpp
@@ -43,10 +43,13 @@ CSelectDBFolder::CSelectDBFolder(quint64 &id, QString &db, QWidget *parent)
 
     connect(treeWidget, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(slotItemExpanded(QTreeWidgetItem*)));
     connect(treeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(slotItemSelectionChanged()));
+
+    QApplication::setOverrideCursor(Qt::ArrowCursor);
 }
 
 CSelectDBFolder::~CSelectDBFolder()
 {
+    QApplication::restoreOverrideCursor();
 }
 
 void CSelectDBFolder::slotItemExpanded(QTreeWidgetItem * item)
diff --git a/src/gis/db/CSelectSaveAction.cpp b/src/gis/db/CSelectSaveAction.cpp
index a010ccb..21d4c81 100644
--- a/src/gis/db/CSelectSaveAction.cpp
+++ b/src/gis/db/CSelectSaveAction.cpp
@@ -34,10 +34,13 @@ CSelectSaveAction::CSelectSaveAction(const IGisItem *src, const IGisItem *tar, Q
 
     connect(pushSave, SIGNAL(clicked()), this, SLOT(slotSelectResult()));
     connect(pushSkip, SIGNAL(clicked()), this, SLOT(slotSelectResult()));
+
+    QApplication::setOverrideCursor(Qt::ArrowCursor);
 }
 
 CSelectSaveAction::~CSelectSaveAction()
 {
+    QApplication::restoreOverrideCursor();
 }
 
 bool CSelectSaveAction::allOthersToo()
diff --git a/src/gis/db/CSetupFolder.cpp b/src/gis/db/CSetupFolder.cpp
index 9918e18..7a495c5 100644
--- a/src/gis/db/CSetupFolder.cpp
+++ b/src/gis/db/CSetupFolder.cpp
@@ -50,10 +50,13 @@ CSetupFolder::CSetupFolder(IDBFolder::type_e& type, QString &name, bool groupAll
     radioGroup->setEnabled(groupAllowed);
 
     slotNameChanged(name);
+
+    QApplication::setOverrideCursor(Qt::ArrowCursor);
 }
 
 CSetupFolder::~CSetupFolder()
 {
+    QApplication::restoreOverrideCursor();
 }
 
 void CSetupFolder::accept()
diff --git a/src/gis/db/IDB.cpp b/src/gis/db/IDB.cpp
index 8ff7eb0..ae30e0e 100644
--- a/src/gis/db/IDB.cpp
+++ b/src/gis/db/IDB.cpp
@@ -173,9 +173,10 @@ bool IDB::migrateDB(int version)
 
     for(version++; version <= DB_VERSION; version++)
     {
-        switch(version)
-        {
-        }
+//        switch(version)
+//        {
+//        default:;
+//        }
     }
     query.prepare( "UPDATE versioninfo set version=:version");
     query.bindValue(":version", version - 1);
diff --git a/src/gis/db/macros.h b/src/gis/db/macros.h
index 3d7c630..5b07da6 100644
--- a/src/gis/db/macros.h
+++ b/src/gis/db/macros.h
@@ -29,12 +29,12 @@
         cmd; \
     } \
 
-#define PROGRESS_SETUP(lbl, max) \
-    QProgressDialog progress(lbl, "Abort", 0, max, 0); \
+#define PROGRESS_SETUP(lbl, parent) \
+    QProgressDialog progress(lbl, "Abort", 0, 100, parent); \
     progress.setWindowModality(Qt::WindowModal); \
 
-#define PROGRESS(x, cmd) \
-    progress.setValue(x); \
+#define PROGRESS(x, total, cmd) \
+    progress.setValue(qRound(x * 100.0 / total)); \
     if (progress.wasCanceled()) { cmd; } \
 
 
diff --git a/src/gis/gpx/CGpxProject.cpp b/src/gis/gpx/CGpxProject.cpp
index 20fb2bc..4cd1a5b 100644
--- a/src/gis/gpx/CGpxProject.cpp
+++ b/src/gis/gpx/CGpxProject.cpp
@@ -36,16 +36,18 @@ CGpxProject::CGpxProject(const QString &filename, CGisListWks *parent)
     : IGisProject(eTypeGpx, filename, parent)
 {
     setIcon(CGisListWks::eColumnIcon,QIcon("://icons/32x32/GpxProject.png"));
+    blockUpdateItems(true);
     loadGpx(filename);
-    updateItems();
+    blockUpdateItems(false);
 }
 
 CGpxProject::CGpxProject(const QString &filename, IDevice * parent)
     : IGisProject(eTypeGpx, filename, parent)
 {
     setIcon(CGisListWks::eColumnIcon,QIcon("://icons/32x32/GpxProject.png"));
+    blockUpdateItems(true);
     loadGpx(filename);
-    updateItems();
+    blockUpdateItems(false);
 }
 
 CGpxProject::CGpxProject(const QString &filename, const IGisProject * project, IDevice * parent)
@@ -53,6 +55,7 @@ CGpxProject::CGpxProject(const QString &filename, const IGisProject * project, I
 {
     setIcon(CGisListWks::eColumnIcon,QIcon("://icons/32x32/GpxProject.png"));
     *(IGisProject*)this = *project;
+    blockUpdateItems(project->blockUpdateItems());
 
     const int N = project->childCount();
     for(int n = 0; n < N; n++)
@@ -65,10 +68,9 @@ CGpxProject::CGpxProject(const QString &filename, const IGisProject * project, I
         }
     }
 
-
     setupName(QFileInfo(filename).baseName().replace("_", " "));
+    blockUpdateItems(false);
     setToolTip(CGisListWks::eColumnName, getInfo());
-    updateItems();
     valid = true;
 }
 
@@ -130,6 +132,10 @@ void CGpxProject::loadGpx(const QString& filename)
         sorting = sorting_e(xmlExtension.namedItem("ql:sorting").toElement().text().toInt());
     }
 
+    if(xmlExtension.namedItem("ql:correlation").isElement())
+    {
+        noCorrelation = bool(xmlExtension.namedItem("ql:correlation").toElement().text().toInt() == 0);
+    }
 
     const QDomNode& xmlMetadata = xmlGpx.namedItem("metadata");
     if(xmlMetadata.isElement())
@@ -211,6 +217,7 @@ bool CGpxProject::saveAs()
 {
     SETTINGS;
     QString path = cfg.value("Paths/lastGisPath", QDir::homePath()).toString();
+    path += "/" + getName() + ".gpx";
 
     QString filter = "*.gpx";
     QString fn = QFileDialog::getSaveFileName(&CMainWindow::self(), QObject::tr("Save GIS data to..."), path, "*.gpx;; *.qms", &filter);
@@ -383,6 +390,13 @@ bool CGpxProject::saveAs(const QString& fn, IGisProject& project)
         elem.appendChild(text);
     }
 
+    {
+        QDomElement elem = xmlExt.ownerDocument().createElement("ql:correlation");
+        xmlExt.appendChild(elem);
+        QDomText text = xmlExt.ownerDocument().createTextNode(QString::number(project.doCorrelation()));
+        elem.appendChild(text);
+    }
+
     //  ---- stop  content of gpx
 
     bool res = true;
diff --git a/src/gis/ovl/CGisItemOvlArea.cpp b/src/gis/ovl/CGisItemOvlArea.cpp
index a4a2e43..e919ddc 100644
--- a/src/gis/ovl/CGisItemOvlArea.cpp
+++ b/src/gis/ovl/CGisItemOvlArea.cpp
@@ -113,13 +113,13 @@ const Qt::BrushStyle CGisItemOvlArea::brushStyles[OVL_N_STYLES] =
 
 IGisItem::key_t CGisItemOvlArea::keyUserFocus;
 
-CGisItemOvlArea::CGisItemOvlArea(const QPolygonF& line, const QString &name, IGisProject * project, int idx)
+CGisItemOvlArea::CGisItemOvlArea(const SGisLine &line, const QString &name, IGisProject * project, int idx)
     : IGisItem(project, eTypeOvl, idx)
     , penForeground(Qt::blue, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)
     , penBackground(Qt::white, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)
 {
     area.name = name;
-    readLine(line);
+    readAreaDataFromGisLine(line);
 
     flags |=  eFlagCreatedInQms|eFlagWriteAllowed;
 
@@ -244,18 +244,29 @@ QPointF CGisItemOvlArea::getPointCloseBy(const QPoint& screenPos)
     return line[idx];
 }
 
-void CGisItemOvlArea::readLine(const QPolygonF &line)
+void CGisItemOvlArea::readAreaDataFromGisLine(const SGisLine &l)
 {
     area.pts.clear();
-    area.pts.resize(line.size());
 
-    for(int i = 0; i < line.size(); i++)
+    for(int i = 0; i < l.size(); i++)
     {
-        pt_t& areapt        = area.pts[i];
-        const QPointF& pt   = line[i];
+        area.pts << pt_t();
+
+        pt_t& areapt      = area.pts.last();
+        const point_t& pt = l[i];
 
-        areapt.lon = pt.x() * RAD_TO_DEG;
-        areapt.lat = pt.y() * RAD_TO_DEG;
+        areapt.lon = pt.coord.x() * RAD_TO_DEG;
+        areapt.lat = pt.coord.y() * RAD_TO_DEG;
+
+        for(int n = 0; n < pt.subpts.size(); n++)
+        {
+            area.pts << pt_t();
+            pt_t& areapt       = area.pts.last();
+            const subpt_t& sub = pt.subpts[n];
+
+            areapt.lon = sub.coord.x() * RAD_TO_DEG;
+            areapt.lat = sub.coord.y() * RAD_TO_DEG;
+        }
     }
 
     deriveSecondaryData();
@@ -473,18 +484,18 @@ QString CGisItemOvlArea::getInfo(bool allowEdit) const
     return str;
 }
 
-void CGisItemOvlArea::getPolylineFromData(QPolygonF& line)
+void CGisItemOvlArea::getPolylineFromData(SGisLine &l)
 {
-    line.clear();
+    l.clear();
     foreach(const pt_t &pt, area.pts)
     {
-        line << QPointF(pt.lon * DEG_TO_RAD, pt.lat * DEG_TO_RAD);
+        l << point_t(QPointF(pt.lon * DEG_TO_RAD, pt.lat * DEG_TO_RAD));
     }
 }
 
-void CGisItemOvlArea::setDataFromPolyline(const QPolygonF& line)
+void CGisItemOvlArea::setDataFromPolyline(const SGisLine& l)
 {
-    readLine(line);
+    readAreaDataFromGisLine(l);
 
     flags |= eFlagTainted;
 
diff --git a/src/gis/ovl/CGisItemOvlArea.h b/src/gis/ovl/CGisItemOvlArea.h
index b06d505..ea78e18 100644
--- a/src/gis/ovl/CGisItemOvlArea.h
+++ b/src/gis/ovl/CGisItemOvlArea.h
@@ -36,7 +36,7 @@ class IQlgtOverlay;
 class CGisItemOvlArea : public IGisItem, public IGisLine
 {
 public:
-    CGisItemOvlArea(const QPolygonF& line, const QString &name, IGisProject * project, int idx);
+    CGisItemOvlArea(const SGisLine& line, const QString &name, IGisProject * project, int idx);
     CGisItemOvlArea(const CGisItemOvlArea &parentArea, IGisProject * project, int idx, bool clone);
     CGisItemOvlArea(const QDomNode &xml, IGisProject *project);
     CGisItemOvlArea(const history_t& hist, IGisProject * project);
@@ -53,7 +53,7 @@ public:
         return colorIdx;
     }
     QString getInfo(bool allowEdit = false) const;
-    void getPolylineFromData(QPolygonF& line);
+    void getPolylineFromData(SGisLine& l);
     const QString& getComment() const
     {
         return area.cmt;
@@ -81,7 +81,7 @@ public:
 
     void setName(const QString& str);
     void setColor(int idx);
-    void setDataFromPolyline(const QPolygonF& line);
+    void setDataFromPolyline(const SGisLine& l);
     void setWidth(qint32 w);
     void setStyle(qint32 s);
     void setOpacity(bool yes);
@@ -157,7 +157,7 @@ private:
     void readArea(const QDomNode& xml, area_t& area);
     void setColor(const QColor& c);
     void setIcon(const QString& c);
-    void readLine(const QPolygonF &line);
+    void readAreaDataFromGisLine(const SGisLine &line);
     void deriveSecondaryData();
     QPointF getPolygonCentroid(const QPolygonF& polygon);
 
diff --git a/src/gis/ovl/CScrOptOvlArea.cpp b/src/gis/ovl/CScrOptOvlArea.cpp
index 0b49e39..689724d 100644
--- a/src/gis/ovl/CScrOptOvlArea.cpp
+++ b/src/gis/ovl/CScrOptOvlArea.cpp
@@ -24,7 +24,7 @@
 #include "mouse/IMouse.h"
 
 CScrOptOvlArea::CScrOptOvlArea(CGisItemOvlArea *area, const QPoint &point, IMouse *parent)
-    : IScrOpt(parent->getCanvas())
+    : IScrOpt(parent)
 {
     key = area->getKey();
 
diff --git a/src/gis/ovl/IScrOptOvlArea.ui b/src/gis/ovl/IScrOptOvlArea.ui
index 88e6522..9eb74c2 100644
--- a/src/gis/ovl/IScrOptOvlArea.ui
+++ b/src/gis/ovl/IScrOptOvlArea.ui
@@ -36,6 +36,9 @@
      </property>
      <item>
       <widget class="QToolButton" name="toolEditDetails">
+       <property name="toolTip">
+        <string>View details and edit.</string>
+       </property>
        <property name="text">
         <string>...</string>
        </property>
@@ -61,6 +64,9 @@
      </item>
      <item>
       <widget class="QToolButton" name="toolDelete">
+       <property name="toolTip">
+        <string>Delete area from project.</string>
+       </property>
        <property name="text">
         <string>...</string>
        </property>
@@ -79,6 +85,9 @@
      </item>
      <item>
       <widget class="QToolButton" name="toolEdit">
+       <property name="toolTip">
+        <string>Edit shape of the area.</string>
+       </property>
        <property name="text">
         <string>...</string>
        </property>
diff --git a/src/gis/prj/CDetailsPrj.cpp b/src/gis/prj/CDetailsPrj.cpp
index b047959..7f73a9f 100644
--- a/src/gis/prj/CDetailsPrj.cpp
+++ b/src/gis/prj/CDetailsPrj.cpp
@@ -77,6 +77,19 @@ void CDetailsPrj::slotSetupGui()
 
     comboSort->blockSignals(true);
     comboSort->setCurrentIndex(prj.getSorting());
+    if((prj.getSorting() > IGisProject::eSortTime) && !prj.doCorrelation())
+    {
+        QString msg = tr("You want to sort waypoints along a track, but you switched off track and waypoint correlation. Do you want to switch it on again?");
+        int res = QMessageBox::question(this, tr("Correlation..."), msg, QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes);
+        if(res == QMessageBox::Yes)
+        {
+            prj.switchOnCorrelation();
+        }
+        else
+        {
+            comboSort->setCurrentIndex(IGisProject::eSortNone);
+        }
+    }
     comboSort->blockSignals(false);
 
     toolLock->blockSignals(true);
diff --git a/src/gis/prj/IGisProject.cpp b/src/gis/prj/IGisProject.cpp
index 6b15cf7..f631afb 100644
--- a/src/gis/prj/IGisProject.cpp
+++ b/src/gis/prj/IGisProject.cpp
@@ -37,8 +37,13 @@ IGisProject::IGisProject(type_e type, const QString &filename, CGisListWks *pare
     , type(type)
     , filename(filename)
     , valid(false)
+    , noUpdate(false)
+    , noCorrelation(false)
     , sorting(eSortNone)
+    , cntTrkPts(0)
+    , cntWpts(0)
 {
+    memset(cntItemsByType, 0, sizeof(cntItemsByType));
     setCheckState(CGisListWks::eColumnDecoration, Qt::Checked);
 }
 
@@ -47,7 +52,11 @@ IGisProject::IGisProject(type_e type, const QString &filename, IDevice *parent)
     , type(type)
     , filename(filename)
     , valid(false)
+    , noUpdate(false)
+    , noCorrelation(false)
     , sorting(eSortNone)
+    , cntTrkPts(0)
+    , cntWpts(0)
 {
     setCheckState(CGisListWks::eColumnDecoration, Qt::Checked);
 
@@ -66,12 +75,13 @@ bool IGisProject::askBeforClose()
     if(isChanged())
     {
         QApplication::setOverrideCursor(Qt::ArrowCursor);
-        res = QMessageBox::question(&CMainWindow::self(), QObject::tr("Save project?"), QObject::tr("The project \"%1\" was changed. Save befor closing it?").arg(getName()), QMessageBox::Save|QMessageBox::No|QMessageBox::Abort, QMessageBox::Save);
+        res = QMessageBox::question(&CMainWindow::self(), QObject::tr("Save project?"), QObject::tr("The project \"%1\" was changed. Save befor closing it?").arg(getName()), QMessageBox::Save|QMessageBox::No|QMessageBox::Abort, QMessageBox::No);
+        QApplication::restoreOverrideCursor();
+
         if(res == QMessageBox::Save)
         {
             save();
         }
-        QApplication::restoreOverrideCursor();
     }
 
     return res == QMessageBox::Abort;
@@ -175,15 +185,46 @@ void IGisProject::setChanged()
     updateItems();
 }
 
+void IGisProject::switchOnCorrelation()
+{
+    noCorrelation = false;
+    updateItems();
+}
 
 void IGisProject::updateItems()
 {
+    if(noUpdate)
+    {
+        return;
+    }
+
+    updateItemCounters();
+
+    if(noCorrelation || getItemCountByType(IGisItem::eTypeTrk) == 0 || getItemCountByType(IGisItem::eTypeWpt) == 0)
+    {
+        return;
+    }
+
+    quint32 total = cntTrkPts * cntWpts;
+    quint32 current = 0;
+
+    QProgressDialog progress(QObject::tr("%1: Correlate tracks and waypoints.").arg(getName()), QObject::tr("Abort"), 0, 100, &CMainWindow::self());
+    progress.setWindowModality(Qt::WindowModal);
+    progress.setMinimumDuration(1000);
+
     for(int i = 0; i < childCount(); i++)
     {
         CGisItemTrk * trk = dynamic_cast<CGisItemTrk*>(child(i));
         if(trk)
         {
-            trk->findWaypointsCloseBy();
+            trk->findWaypointsCloseBy(progress, current, total);
+            if(progress.wasCanceled())
+            {
+                QString msg = QObject::tr("Did that take too long for you? Do you want to skip correlation of tracks and waypoints for this project (%1) in the future?").arg(getNameEx());
+                int res = QMessageBox::question(&CMainWindow::self(), QObject::tr("Cancelled correlation..."), msg, QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes);
+                noCorrelation = res == QMessageBox::Yes;
+                break;
+            }
         }
     }
 }
@@ -261,33 +302,21 @@ QString IGisProject::getInfo() const
         str += QObject::tr("<br/>\nFilename: %1").arg(filename);
     }
 
-    // count number of items by type
-    int counter[IGisItem::eTypeMax] = {0};
-    for(int i = 0; i < childCount(); i++)
+    if(cntItemsByType[IGisItem::eTypeWpt])
     {
-        IGisItem * item = dynamic_cast<IGisItem*>(child(i));
-        if(item == 0)
-        {
-            continue;
-        }
-
-        counter[item->type()]++;
+        str += "<br/>\n" + QObject::tr("Waypoints: %1").arg(cntItemsByType[IGisItem::eTypeWpt]);
     }
-    if(counter[IGisItem::eTypeWpt])
+    if(cntItemsByType[IGisItem::eTypeTrk])
     {
-        str += "<br/>\n" + QObject::tr("Waypoints: %1").arg(counter[IGisItem::eTypeWpt]);
+        str += "<br/>\n" + QObject::tr("Tracks: %1").arg(cntItemsByType[IGisItem::eTypeTrk]);
     }
-    if(counter[IGisItem::eTypeTrk])
+    if(cntItemsByType[IGisItem::eTypeRte])
     {
-        str += "<br/>\n" + QObject::tr("Tracks: %1").arg(counter[IGisItem::eTypeTrk]);
+        str += "<br/>\n" + QObject::tr("Routes: %1").arg(cntItemsByType[IGisItem::eTypeRte]);
     }
-    if(counter[IGisItem::eTypeRte])
+    if(cntItemsByType[IGisItem::eTypeOvl])
     {
-        str += "<br/>\n" + QObject::tr("Routes: %1").arg(counter[IGisItem::eTypeRte]);
-    }
-    if(counter[IGisItem::eTypeOvl])
-    {
-        str += "<br/>\n" + QObject::tr("Areas: %1").arg(counter[IGisItem::eTypeOvl]);
+        str += "<br/>\n" + QObject::tr("Areas: %1").arg(cntItemsByType[IGisItem::eTypeOvl]);
     }
 
     return str;
@@ -632,4 +661,42 @@ bool IGisProject::remove()
     return true;
 }
 
+void IGisProject::updateItemCounters()
+{
+    // count number of items by type
+    memset(cntItemsByType, 0, sizeof(cntItemsByType));
+    cntTrkPts = 0;
+    cntWpts = 0;
+
+    for(int i = 0; i < childCount(); i++)
+    {
+        IGisItem * item = dynamic_cast<IGisItem*>(child(i));
+        if(item == 0)
+        {
+            continue;
+        }
+
+        cntItemsByType[item->type()]++;
 
+        CGisItemTrk * trk = dynamic_cast<CGisItemTrk*>(item);
+        if(trk)
+        {
+            cntTrkPts += trk->getNumberOfVisiblePoints();
+        }
+
+        CGisItemWpt * wpt = dynamic_cast<CGisItemWpt*>(item);
+        if(wpt)
+        {
+            cntWpts++;
+        }
+    }
+}
+
+void IGisProject::blockUpdateItems(bool yes)
+{
+    noUpdate = yes;
+    if(noUpdate == false)
+    {
+        updateItems();
+    }
+}
diff --git a/src/gis/prj/IGisProject.h b/src/gis/prj/IGisProject.h
index 60b1700..534dbb0 100644
--- a/src/gis/prj/IGisProject.h
+++ b/src/gis/prj/IGisProject.h
@@ -236,6 +236,19 @@ public:
      */
     void getItemsByPos(const QPointF& pos, QList<IGisItem*>& items);
 
+
+    int getItemCountByType(IGisItem::type_e type)
+    {
+        return cntItemsByType[type];
+    }
+
+    bool doCorrelation()
+    {
+        return !noCorrelation;
+    }
+
+    void switchOnCorrelation();
+
     /**
        @brief Receive the current mouse position
 
@@ -356,14 +369,32 @@ public:
      */
     bool remove();
 
+    /**
+       @brief Block update of items.
+
+        Use this to speed up actions with many items, e.g. copy actions.
+        If the blocking is stopped (yes == false) updateItems() is called.
+
+       @param yes set true to block updateing items
+     */
+    void blockUpdateItems(bool yes);
+
+    /**
+       @brief  Return state of current update block
+       @return True if updates are blocked.
+     */
+    bool blockUpdateItems() const
+    {
+        return noUpdate;
+    }
+
 protected:
     void genKey();
     virtual void setupName(const QString& defaultName);
     void markAsSaved();
     void readMetadata(const QDomNode& xml, metadata_t& metadata);
     void updateItems();
-
-
+    void updateItemCounters();
 
     // Those are the URIs of the GPX extensions we support
     static const QString gpxx_ns;
@@ -380,6 +411,8 @@ protected:
     QString key;
     QString filename;
     bool valid;
+    bool noUpdate;
+    bool noCorrelation;
 
     metadata_t metadata;
     QString nameSuffix;
@@ -387,6 +420,11 @@ protected:
     QPointer<CDetailsPrj> dlgDetails;
 
     sorting_e sorting;
+
+    qint32 cntItemsByType[IGisItem::eTypeMax];
+
+    qint32 cntTrkPts;
+    qint32 cntWpts;
 };
 
 #endif //IGISPROJECT_H
diff --git a/src/gis/qms/CQmsProject.cpp b/src/gis/qms/CQmsProject.cpp
index 3f2abd2..513abc5 100644
--- a/src/gis/qms/CQmsProject.cpp
+++ b/src/gis/qms/CQmsProject.cpp
@@ -89,6 +89,7 @@ bool CQmsProject::saveAs()
 {
     SETTINGS;
     QString path = cfg.value("Paths/lastGisPath", QDir::homePath()).toString();
+    path += "/" + getName() + ".qms";
 
     QString filter = "*.qms";
     QString fn = QFileDialog::getSaveFileName(&CMainWindow::self(), QObject::tr("Save GIS data to..."), path, "*.gpx;; *.qms", &filter);
diff --git a/src/gis/qms/serialization.cpp b/src/gis/qms/serialization.cpp
index 14fb528..69e40e7 100644
--- a/src/gis/qms/serialization.cpp
+++ b/src/gis/qms/serialization.cpp
@@ -38,7 +38,7 @@
 #define VER_GC_T        quint8(1)
 #define VER_GCLOG_T     quint8(1)
 #define VER_IMAGE       quint8(1)
-#define VER_PROJECT     quint8(3)
+#define VER_PROJECT     quint8(4)
 #define VER_COPYRIGHT   quint8(1)
 #define VER_PERSON      quint8(1)
 #define VER_HIST        quint8(1)
@@ -667,6 +667,8 @@ QDataStream& IGisProject::operator<<(QDataStream& stream)
         return stream;
     }
 
+    blockUpdateItems(true);
+
     stream >> version;
     stream >> filename;
     stream >> metadata.name;
@@ -687,6 +689,12 @@ QDataStream& IGisProject::operator<<(QDataStream& stream)
         stream >> tmp;
         sorting = (sorting_e)tmp;
     }
+    if(version > 3)
+    {
+        qint8 tmp;
+        stream >> tmp;
+        noCorrelation = tmp != 0;
+    }
 
     while(!stream.atEnd())
     {
@@ -728,7 +736,7 @@ QDataStream& IGisProject::operator<<(QDataStream& stream)
         }
     }
 
-    updateItems();
+    blockUpdateItems(false);
     return stream;
 }
 
@@ -748,6 +756,7 @@ QDataStream& IGisProject::operator>>(QDataStream& stream)
     stream << metadata.bounds;
     stream << key;
     stream << qint32(sorting);
+    stream << qint8(noCorrelation);
 
     for(int i = 0; i < childCount(); i++)
     {
@@ -836,6 +845,12 @@ QDataStream& CDBProject::operator<<(QDataStream& stream)
         stream >> tmp;
         sorting = (sorting_e)tmp;
     }
+    if(version > 3)
+    {
+        qint8 tmp;
+        stream >> tmp;
+        noCorrelation = tmp != 0;
+    }
 
     return stream;
 }
@@ -856,6 +871,7 @@ QDataStream& CDBProject::operator>>(QDataStream& stream)
     stream << metadata.bounds;
     stream << key;
     stream << qint32(sorting);
+    stream << qint8(noCorrelation);
 
     return stream;
 }
diff --git a/src/gis/rte/CCreateRouteFromWpt.cpp b/src/gis/rte/CCreateRouteFromWpt.cpp
new file mode 100644
index 0000000..8abe314
--- /dev/null
+++ b/src/gis/rte/CCreateRouteFromWpt.cpp
@@ -0,0 +1,138 @@
+/**********************************************************************************************
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+**********************************************************************************************/
+
+#include "CMainWindow.h"
+#include "gis/CGisWidget.h"
+#include "gis/CGisWidget.h"
+#include "gis/IGisLine.h"
+#include "gis/prj/IGisProject.h"
+#include "gis/rte/CCreateRouteFromWpt.h"
+#include "gis/rte/CGisItemRte.h"
+#include "gis/wpt/CGisItemWpt.h"
+
+
+#include <QtWidgets>
+#include <proj_api.h>
+
+CCreateRouteFromWpt::CCreateRouteFromWpt(const QList<IGisItem::key_t> &keys, QWidget *parent)
+    : QDialog(parent)
+{
+    setupUi(this);
+
+    foreach(const IGisItem::key_t& key, keys)
+    {
+        CGisItemWpt * wpt = dynamic_cast<CGisItemWpt*>(CGisWidget::self().getItemByKey(key));
+        if(wpt == 0)
+        {
+            continue;
+        }
+
+        QListWidgetItem * item = new QListWidgetItem(listWidget);
+        item->setText(wpt->getName());
+        item->setIcon(wpt->getIcon());
+        item->setToolTip(wpt->getInfo());
+        item->setData(Qt::UserRole, QPointF(wpt->getPosition()*DEG_TO_RAD));
+    }
+
+    connect(listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(slotSelectionChanged()));
+    connect(toolUp, SIGNAL(clicked()), this, SLOT(slotUp()));
+    connect(toolDown, SIGNAL(clicked()), this, SLOT(slotDown()));
+}
+
+CCreateRouteFromWpt::~CCreateRouteFromWpt()
+{
+}
+
+void CCreateRouteFromWpt::accept()
+{
+    QDialog::accept();
+
+    QString name = QInputDialog::getText(&CMainWindow::self(), QObject::tr("Edit name..."), QObject::tr("Enter new route name."), QLineEdit::Normal, "");
+    if(name.isEmpty())
+    {
+        return;
+    }
+
+    IGisProject * project = CGisWidget::self().selectProject();
+    if(project == 0)
+    {
+        return;
+    }
+
+    SGisLine points;
+    for(int i = 0; i < listWidget->count(); i++)
+    {
+        QListWidgetItem * item = listWidget->item(i);
+        points << IGisLine::point_t(item->data(Qt::UserRole).toPointF());
+    }
+
+    CGisItemRte* rte = new CGisItemRte(points,name, project, NOIDX);
+    QApplication::setOverrideCursor(Qt::WaitCursor);
+    rte->calc();
+    QApplication::restoreOverrideCursor();
+}
+
+void CCreateRouteFromWpt::slotSelectionChanged()
+{
+    QListWidgetItem * item = listWidget->currentItem();
+    if(item != 0)
+    {
+        int row = listWidget->row(item);
+        toolUp->setEnabled(row != 0);
+        toolDown->setEnabled(row != (listWidget->count() - 1));
+    }
+    else
+    {
+        toolUp->setEnabled(false);
+        toolDown->setEnabled(false);
+    }
+}
+
+void CCreateRouteFromWpt::slotUp()
+{
+    QListWidgetItem * item = listWidget->currentItem();
+    if(item)
+    {
+        int row = listWidget->row(item);
+        if(row == 0)
+        {
+            return;
+        }
+        listWidget->takeItem(row);
+        row = row - 1;
+        listWidget->insertItem(row,item);
+        listWidget->setCurrentItem(item);
+    }
+}
+
+void CCreateRouteFromWpt::slotDown()
+{
+    QListWidgetItem * item = listWidget->currentItem();
+    if(item)
+    {
+        int row = listWidget->row(item);
+        if(row == (listWidget->count() - 1))
+        {
+            return;
+        }
+        listWidget->takeItem(row);
+        row = row + 1;
+        listWidget->insertItem(row,item);
+        listWidget->setCurrentItem(item);
+    }
+}
diff --git a/src/gis/rte/CScrOptRte.h b/src/gis/rte/CCreateRouteFromWpt.h
similarity index 62%
copy from src/gis/rte/CScrOptRte.h
copy to src/gis/rte/CCreateRouteFromWpt.h
index 21543df..ee98541 100644
--- a/src/gis/rte/CScrOptRte.h
+++ b/src/gis/rte/CCreateRouteFromWpt.h
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -16,35 +16,30 @@
 
 **********************************************************************************************/
 
-#ifndef CSCROPTRTE_H
-#define CSCROPTRTE_H
+#ifndef CCREATEROUTEFROMWPT_H
+#define CCREATEROUTEFROMWPT_H
 
-#include "gis/IGisItem.h"
-#include "mouse/IScrOpt.h"
+#include <gis/IGisItem.h>
 
-#include "ui_IScrOptRte.h"
-#include <QWidget>
+#include "ui_ICreateRouteFromWpt.h"
+#include <QDialog>
 
-class CGisItemRte;
-class IMouse;
 
-class CScrOptRte : public IScrOpt, private Ui::IScrOptRte
+class CCreateRouteFromWpt : public QDialog, private Ui::ICreateRouteFromWpt
 {
     Q_OBJECT
 public:
-    CScrOptRte(CGisItemRte * rte, const QPoint &point, IMouse *parent);
-    virtual ~CScrOptRte();
+    CCreateRouteFromWpt(const QList<IGisItem::key_t>& keys, QWidget * parent);
+    virtual ~CCreateRouteFromWpt();
 
-    void draw(QPainter& p);
+public slots:
+    void accept();
 
 private slots:
-    void slotDelete();
-    void slotCopy();
-
-private:
-    IGisItem::key_t key;
-    QPointF anchor;
+    void slotSelectionChanged();
+    void slotUp();
+    void slotDown();
 };
 
-#endif //CSCROPTRTE_H
+#endif //CCREATEROUTEFROMWPT_H
 
diff --git a/src/gis/rte/CGisItemRte.cpp b/src/gis/rte/CGisItemRte.cpp
index f266eda..d0e7797 100644
--- a/src/gis/rte/CGisItemRte.cpp
+++ b/src/gis/rte/CGisItemRte.cpp
@@ -16,6 +16,7 @@
 
 **********************************************************************************************/
 
+#include "CMainWindow.h"
 #include "canvas/CCanvas.h"
 #include "gis/CGisDraw.h"
 #include "gis/CGisListWks.h"
@@ -34,7 +35,10 @@ IGisItem::key_t CGisItemRte::keyUserFocus;
 /// used to create a copy of route with new parent
 CGisItemRte::CGisItemRte(const CGisItemRte& parentRte, IGisProject * project, int idx, bool clone)
     : IGisItem(project, eTypeRte, idx)
-    , penForeground(Qt::magenta, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)
+    , penForeground(Qt::darkBlue, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)
+    , lastRoutedCalcTime(0)
+    , totalDistance(NOFLOAT)
+    , totalDays(NOINT)
 {
     *this = parentRte;
     key.project = project->getKey();
@@ -63,13 +67,17 @@ CGisItemRte::CGisItemRte(const CGisItemRte& parentRte, IGisProject * project, in
 
 
     setupHistory();
+    deriveSecondaryData();
     updateDecoration(eMarkChanged, eMarkNone);
 }
 
 /// used to create route from GPX file
 CGisItemRte::CGisItemRte(const QDomNode& xml, IGisProject *parent)
     : IGisItem(parent, eTypeRte, parent->childCount())
-    , penForeground(Qt::magenta, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)
+    , penForeground(Qt::darkBlue, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)
+    , lastRoutedCalcTime(0)
+    , totalDistance(NOFLOAT)
+    , totalDays(NOINT)
 {
     // --- start read and process data ----
     readRte(xml, rte);
@@ -82,7 +90,10 @@ CGisItemRte::CGisItemRte(const QDomNode& xml, IGisProject *parent)
 
 CGisItemRte::CGisItemRte(const history_t& hist, IGisProject * project)
     : IGisItem(project, eTypeRte, project->childCount())
-    , penForeground(Qt::magenta, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)
+    , penForeground(Qt::darkBlue, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)
+    , lastRoutedCalcTime(0)
+    , totalDistance(NOFLOAT)
+    , totalDays(NOINT)
 {
     history = hist;
     loadHistory(hist.histIdxCurrent);
@@ -91,11 +102,30 @@ CGisItemRte::CGisItemRte(const history_t& hist, IGisProject * project)
 
 CGisItemRte::CGisItemRte(quint64 id, QSqlDatabase& db, IGisProject * project)
     : IGisItem(project, eTypeRte, NOIDX)
-    , penForeground(Qt::magenta, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)
+    , penForeground(Qt::darkBlue, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)
+    , lastRoutedCalcTime(0)
+    , totalDistance(NOFLOAT)
+    , totalDays(NOINT)
 {
     loadFromDb(id, db);
 }
 
+CGisItemRte::CGisItemRte(const SGisLine &l, const QString &name, IGisProject *project, int idx)
+    : IGisItem(project, eTypeRte, idx)
+    , penForeground(Qt::darkBlue, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)
+    , lastRoutedCalcTime(0)
+    , totalDistance(NOFLOAT)
+    , totalDays(NOINT)
+{
+    rte.name = name;
+    readRouteDataFromGisLine(l);
+
+    flags |=  eFlagCreatedInQms|eFlagWriteAllowed;
+
+    setupHistory();
+    updateDecoration(eMarkChanged, eMarkNone);
+}
+
 CGisItemRte::~CGisItemRte()
 {
 }
@@ -125,6 +155,26 @@ void CGisItemRte::deriveSecondaryData()
         {
             north   = rtept.lat;
         }
+
+        foreach(const subpt_t &subpt, rtept.subpts)
+        {
+            if(subpt.lon < west)
+            {
+                west    = subpt.lon;
+            }
+            if(subpt.lon > east)
+            {
+                east    = subpt.lon;
+            }
+            if(subpt.lat < south)
+            {
+                south   = subpt.lat;
+            }
+            if(subpt.lat > north)
+            {
+                north   = subpt.lat;
+            }
+        }
     }
 
     boundingRect = QRectF(QPointF(west * DEG_TO_RAD, north * DEG_TO_RAD), QPointF(east * DEG_TO_RAD,south * DEG_TO_RAD));
@@ -158,9 +208,55 @@ void CGisItemRte::setLinks(const QList<link_t>& links)
 
 QString CGisItemRte::getInfo(bool allowEdit) const
 {
-    QString str = getName();
+    QString val1, unit1, val2, unit2;
+    QString str = "<div>";
+
+    if(allowEdit)
+    {
+        str += "<b>" + toLink(isReadOnly(), "name", getName(), "") + "</b>";
+    }
+    else
+    {
+        str += "<div style='font-weight: bold;'>" + getName() + "</div>";
+    }
+
+    str += "<br/>\n";
+    if(totalDistance != NOFLOAT)
+    {
+        IUnit::self().meter2distance(totalDistance, val1, unit1);
+        str += QObject::tr("Length: %1 %2").arg(val1).arg(unit1);
+    }
+    else
+    {
+        str += QObject::tr("Length: -");
+    }
 
+    str += "<br/>\n";
+    if(totalTime.isValid())
+    {
+        if(totalDays != 0 && totalDays != NOINT)
+        {
+            str += QObject::tr("Time: %2 days %1").arg(totalTime.toString()).arg(totalDays);
+        }
+        else
+        {
+            str += QObject::tr("Time: %1").arg(totalTime.toString());
+        }
+    }
+    else
+    {
+        str += QObject::tr("Time: -");
+    }
 
+    if(!lastRoutedWith.isEmpty())
+    {
+        str += "<br/>\n";
+        str += QObject::tr("Last time routed:<br/>%1").arg(IUnit::datetime2string(lastRoutedTime, false, boundingRect.center()));
+        str += "<br/>\n";
+        str += QObject::tr("with %1").arg(lastRoutedWith);
+        str += "<br/>\n";
+        str += QObject::tr("Calculation took %1 sec.").arg(lastRoutedCalcTime/1000.0, 0, 'f', 2);
+    }
     return str;
 }
 
@@ -221,6 +317,8 @@ void CGisItemRte::drawItem(QPainter& p, const QPolygonF& viewport, QList<QRectF>
     gis->convertRad2Px(p2);
     QRectF extViewport(p1,p2);
 
+    QVector<qint32> points;
+
     foreach(const rtept_t &rtept, rte.pts)
     {
         QPointF pt(rtept.lon * DEG_TO_RAD, rtept.lat * DEG_TO_RAD);
@@ -228,24 +326,64 @@ void CGisItemRte::drawItem(QPainter& p, const QPolygonF& viewport, QList<QRectF>
         gis->convertRad2Px(pt);
 
         line << pt;
+        points << 1;
 
         blockedAreas << QRectF(pt - rtept.focus, rtept.icon.size());
+        foreach(const subpt_t &subpt, rtept.subpts)
+        {
+            QPointF pt(subpt.lon * DEG_TO_RAD, subpt.lat * DEG_TO_RAD);
+            gis->convertRad2Px(pt);
+            line << pt;
+            if(subpt.type != subpt_t::eTypeNone)
+            {
+                points << 2;
+            }
+            else
+            {
+                points << 0;
+            }
+        }
     }
 
-    QList<QPolygonF> lines;
-    splitLineToViewport(line, extViewport, lines);
-
     p.setPen(penBackground);
-    foreach(const QPolygonF &line, lines)
+    p.drawPolyline(line);
+
+    p.setPen(Qt::NoPen);
+    p.setBrush(Qt::white);
+    for(int i = 0; i < line.size(); i++)
     {
-        p.drawPolyline(line);
+        switch(points[i])
+        {
+        case 1:
+            p.drawEllipse(line[i],7,7);
+            break;
+
+        case 2:
+            p.drawEllipse(line[i],5,5);
+            break;
+        }
     }
+
     p.setPen(penForeground);
     p.setBrush(penForeground.color());
-    foreach(const QPolygonF &line, lines)
+    drawArrows(line, extViewport, p);
+    p.drawPolyline(line);
+
+    p.setPen(Qt::NoPen);
+    for(int i = 0; i < line.size(); i++)
     {
-        p.drawPolyline(line);
-        drawArrows(line, extViewport, p);
+        switch(points[i])
+        {
+        case 1:
+            p.setBrush(Qt::red);
+            p.drawEllipse(line[i],5,5);
+            break;
+
+        case 2:
+            p.setBrush(Qt::cyan);
+            p.drawEllipse(line[i],3,3);
+            break;
+        }
     }
 }
 
@@ -262,8 +400,8 @@ void CGisItemRte::drawLabel(QPainter& p, const QPolygonF& viewport, QList<QRectF
         QPointF pt(rtept.lon * DEG_TO_RAD, rtept.lat * DEG_TO_RAD);
 
         gis->convertRad2Px(pt);
-        pt = pt - rtept.focus;
-        p.drawPixmap(pt, rtept.icon);
+        //pt = pt - rtept.focus;
+        //p.drawPixmap(pt, rtept.icon);
 
         QRectF rect = fm.boundingRect(rtept.name);
         rect.adjust(-2,-2,2,2);
@@ -305,9 +443,141 @@ void CGisItemRte::drawHighlight(QPainter& p)
 
     p.setPen(QPen(QColor(255,0,0,100),11,Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
     p.drawPolyline(line);
+}
 
-    foreach(const QPointF &pt, line)
+void CGisItemRte::readRouteDataFromGisLine(const SGisLine &l)
+{
+    bool doAutoRouting = !l.first().subpts.isEmpty();
+    rte.pts.clear();
+
+    for(int i = 0; i < l.size(); i++)
+    {
+        rte.pts << rtept_t();
+
+        rtept_t& rtept      = rte.pts.last();
+        const point_t& pt   = l[i];
+
+        rtept.lon = pt.coord.x() * RAD_TO_DEG;
+        rtept.lat = pt.coord.y() * RAD_TO_DEG;
+        rtept.ele = pt.ele;
+    }
+
+    if(doAutoRouting)
+    {
+        calc();
+    }
+    deriveSecondaryData();
+}
+
+void CGisItemRte::setDataFromPolyline(const SGisLine &l)
+{
+//    delete dlgDetails;
+
+    readRouteDataFromGisLine(l);
+
+    flags |= eFlagTainted;
+    changed(QObject::tr("Changed route points."), "://icons/48x48/LineMove.png");
+}
+
+void CGisItemRte::getPolylineFromData(SGisLine& l)
+{
+    l.clear();
+    foreach(const rtept_t &rtept, rte.pts)
+    {
+        l << point_t(QPointF(rtept.lon * DEG_TO_RAD, rtept.lat * DEG_TO_RAD));
+
+        point_t& pt = l.last();
+
+        pt.subpts.clear();
+        foreach(const subpt_t &subpt, rtept.subpts)
+        {
+            pt.subpts << IGisLine::subpt_t(QPointF(subpt.lon * DEG_TO_RAD, subpt.lat * DEG_TO_RAD));
+        }
+    }
+}
+
+void CGisItemRte::calc()
+{
+    for(int i = 0; i < rte.pts.size(); i++)
+    {
+        rte.pts[i].subpts.clear();
+    }
+    QTime time;
+    time.start();
+    CRouterSetup::self().calcRoute(getKey());
+    lastRoutedCalcTime = time.elapsed();
+}
+
+void CGisItemRte::reset()
+{
+    for(int i = 0; i < rte.pts.size(); i++)
     {
-        p.drawImage(pt - QPointF(31,31), QImage("://cursors/wptHighlight.png"));
+        rte.pts[i].subpts.clear();
     }
+
+    totalDays       = NOINT;
+    totalDistance   = NOFLOAT;
+    totalTime       = QTime();
+    lastRoutedTime  = QDateTime();
+    lastRoutedWith  = "";
+    lastRoutedCalcTime = 0;
+
+    deriveSecondaryData();
+    updateHistory();
+}
+
+void CGisItemRte::setResult(T_RoutinoRoute * route, const QString& options)
+{
+    qint32 idxRtept = -1;
+    rtept_t * rtept = 0;
+
+    T_RoutinoRoute * next = route;
+    while(next)
+    {
+        if(next->type == IMP_WAYPOINT)
+        {
+            idxRtept++;
+            rtept = &rte.pts[idxRtept];
+            rtept->subpts.clear();
+        }
+
+        if(rtept != 0)
+        {
+            rtept->subpts << subpt_t();
+            subpt_t& subpt  = rtept->subpts.last();
+            subpt.lon       = next->lon * RAD_TO_DEG;
+            subpt.lat       = next->lat * RAD_TO_DEG;
+
+            subpt.turn      = next->turn;
+            subpt.bearing   = next->bearing;
+            subpt.distance  = next->dist;
+            subpt.time      = subpt.time.addSecs(next->time/10);
+
+            if(next->string != 0)
+            {
+                subpt.names << next->string;
+            }
+
+            if(next->type > IMP_CHANGE)
+            {
+                subpt.type = subpt_t::eTypeJunct;
+            }
+            else
+            {
+                subpt.type = subpt_t::eTypeNone;
+            }
+
+            totalDistance = subpt.distance;
+            totalTime     = subpt.time;
+            totalDays     = qFloor(next->time/864000);
+        }
+
+        next = next->next;
+    }
+
+    lastRoutedTime = QDateTime::currentDateTimeUtc();
+    lastRoutedWith = "Routino, " + options;
+
+    deriveSecondaryData();
+    updateHistory();
 }
diff --git a/src/gis/rte/CGisItemRte.h b/src/gis/rte/CGisItemRte.h
index cbeeb88..35f2161 100644
--- a/src/gis/rte/CGisItemRte.h
+++ b/src/gis/rte/CGisItemRte.h
@@ -21,6 +21,7 @@
 
 #include "gis/IGisItem.h"
 #include "gis/IGisLine.h"
+#include <routino.h>
 
 #include <QPen>
 
@@ -31,10 +32,35 @@ class CQlgtRoute;
 class CGisItemRte : public IGisItem, public IGisLine
 {
 public:
+    struct subpt_t
+    {
+        subpt_t() : lon(NOFLOAT), lat(NOFLOAT), time(0,0)
+        {
+        }
+
+        enum type_e
+        {
+            eTypeNone
+            , eTypeJunct
+        };
+
+        qreal lon;
+        qreal lat;
+        quint8 type;
+
+        qreal turn;
+        qreal bearing;
+        QStringList names;
+
+        qreal distance;
+        QTime time;
+    };
+
     struct rtept_t : public wpt_t
     {
         QPixmap icon;
         QPointF focus;
+        QVector<subpt_t> subpts;
     };
 
     struct rte_t
@@ -60,6 +86,7 @@ public:
     CGisItemRte(const history_t& hist, IGisProject * project);
     CGisItemRte(quint64 id, QSqlDatabase& db, IGisProject * project);
     CGisItemRte(const CQlgtRoute& rte1);
+    CGisItemRte(const SGisLine& l, const QString &name, IGisProject *project, int idx);
     virtual ~CGisItemRte();
 
     QDataStream& operator<<(QDataStream& stream);
@@ -79,12 +106,9 @@ public:
     bool isCloseTo(const QPointF& pos);
     void gainUserFocus(bool yes);
 
-    void setDataFromPolyline(const QPolygonF& line)
-    {
-    }
-    void getPolylineFromData(QPolygonF& line)
-    {
-    }
+    void setDataFromPolyline(const SGisLine& l);
+
+    void getPolylineFromData(SGisLine &l);
 
     const QString& getComment() const
     {
@@ -103,20 +127,33 @@ public:
     void setDescription(const QString& str);
     void setLinks(const QList<link_t>& links);
 
+    void calc();
+
+    void reset();
+
+    void setResult(T_RoutinoRoute * route, const QString &options);
+
 private:
     void deriveSecondaryData();
     void setSymbol();
     void readRte(const QDomNode& xml, rte_t& rte);
+    void readRouteDataFromGisLine(const SGisLine &l);
 
     static key_t keyUserFocus;
 
-
-
     static const QPen penBackground;
     QPen penForeground;
 
     rte_t rte;
     QPolygonF line;
+
+    QString lastRoutedWith;
+    QDateTime lastRoutedTime;
+    quint32 lastRoutedCalcTime;
+
+    qreal totalDistance;
+    QTime totalTime;
+    quint32 totalDays;
 };
 
 #endif //CGISITEMRTE_H
diff --git a/src/gis/rte/CScrOptRte.cpp b/src/gis/rte/CScrOptRte.cpp
index 402c2d5..6eef22d 100644
--- a/src/gis/rte/CScrOptRte.cpp
+++ b/src/gis/rte/CScrOptRte.cpp
@@ -24,7 +24,7 @@
 #include "mouse/IMouse.h"
 
 CScrOptRte::CScrOptRte(CGisItemRte *rte, const QPoint& point, IMouse *parent)
-    : IScrOpt(parent->getCanvas())
+    : IScrOpt(parent)
 
 {
     key = rte->getKey();
@@ -41,6 +41,9 @@ CScrOptRte::CScrOptRte(CGisItemRte *rte, const QPoint& point, IMouse *parent)
 
     connect(toolDelete, SIGNAL(clicked()), this, SLOT(slotDelete()));
     connect(toolCopy, SIGNAL(clicked()), this, SLOT(slotCopy()));
+    connect(toolCalc, SIGNAL(clicked()), this, SLOT(slotCalc()));
+    connect(toolReset, SIGNAL(clicked()), this, SLOT(slotReset()));
+    connect(toolEdit, SIGNAL(clicked()), this, SLOT(slotEdit()));
 }
 
 CScrOptRte::~CScrOptRte()
@@ -58,6 +61,25 @@ void CScrOptRte::slotCopy()
     deleteLater();
 }
 
+void CScrOptRte::slotCalc()
+{
+    CGisWidget::self().calcRteByKey(key);
+    deleteLater();
+}
+
+void CScrOptRte::slotReset()
+{
+    CGisWidget::self().resetRteByKey(key);
+    deleteLater();
+}
+
+void CScrOptRte::slotEdit()
+{
+    CGisWidget::self().editRteByKey(key);
+    deleteLater();
+}
+
+
 void CScrOptRte::draw(QPainter& p)
 {
     IGisItem * item = CGisWidget::self().getItemByKey(key);
@@ -70,3 +92,4 @@ void CScrOptRte::draw(QPainter& p)
 
     drawBubble2(anchor, p);
 }
+
diff --git a/src/gis/rte/CScrOptRte.h b/src/gis/rte/CScrOptRte.h
index 21543df..78edb2a 100644
--- a/src/gis/rte/CScrOptRte.h
+++ b/src/gis/rte/CScrOptRte.h
@@ -40,6 +40,9 @@ public:
 private slots:
     void slotDelete();
     void slotCopy();
+    void slotCalc();
+    void slotReset();
+    void slotEdit();
 
 private:
     IGisItem::key_t key;
diff --git a/src/gis/rte/ICreateRouteFromWpt.ui b/src/gis/rte/ICreateRouteFromWpt.ui
new file mode 100644
index 0000000..9a951dd
--- /dev/null
+++ b/src/gis/rte/ICreateRouteFromWpt.ui
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ICreateRouteFromWpt</class>
+ <widget class="QDialog" name="ICreateRouteFromWpt">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Create Route from Waypoints</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QListWidget" name="listWidget"/>
+     </item>
+     <item>
+      <layout class="QVBoxLayout" name="verticalLayout">
+       <item>
+        <widget class="QToolButton" name="toolUp">
+         <property name="enabled">
+          <bool>false</bool>
+         </property>
+         <property name="text">
+          <string>...</string>
+         </property>
+         <property name="icon">
+          <iconset resource="../../resources.qrc">
+           <normaloff>:/icons/32x32/Up.png</normaloff>:/icons/32x32/Up.png</iconset>
+         </property>
+         <property name="iconSize">
+          <size>
+           <width>22</width>
+           <height>22</height>
+          </size>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QToolButton" name="toolDown">
+         <property name="enabled">
+          <bool>false</bool>
+         </property>
+         <property name="text">
+          <string>...</string>
+         </property>
+         <property name="icon">
+          <iconset resource="../../resources.qrc">
+           <normaloff>:/icons/32x32/Down.png</normaloff>:/icons/32x32/Down.png</iconset>
+         </property>
+         <property name="iconSize">
+          <size>
+           <width>22</width>
+           <height>22</height>
+          </size>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../../resources.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>ICreateRouteFromWpt</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>ICreateRouteFromWpt</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/src/gis/rte/IScrOptRte.ui b/src/gis/rte/IScrOptRte.ui
index c084f11..da93e94 100644
--- a/src/gis/rte/IScrOptRte.ui
+++ b/src/gis/rte/IScrOptRte.ui
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>400</width>
-    <height>68</height>
+    <height>69</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -25,7 +25,7 @@
         <bool>false</bool>
        </property>
        <property name="toolTip">
-        <string><html><head/><body><p>View details &amp; Edit</p></body></html></string>
+        <string>View details and edit.</string>
        </property>
        <property name="text">
         <string>...</string>
@@ -53,7 +53,7 @@
      <item>
       <widget class="QToolButton" name="toolDelete">
        <property name="toolTip">
-        <string><html><head/><body><p>Delete</p></body></html></string>
+        <string>Delete route from project.</string>
        </property>
        <property name="text">
         <string>...</string>
@@ -65,6 +65,55 @@
       </widget>
      </item>
      <item>
+      <widget class="Line" name="line">
+       <property name="orientation">
+        <enum>Qt::Vertical</enum>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="toolCalc">
+       <property name="toolTip">
+        <string>Calculate route.</string>
+       </property>
+       <property name="text">
+        <string>...</string>
+       </property>
+       <property name="icon">
+        <iconset resource="../../resources.qrc">
+         <normaloff>:/icons/32x32/Apply.png</normaloff>:/icons/32x32/Apply.png</iconset>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="toolReset">
+       <property name="toolTip">
+        <string>Reset route calculation.</string>
+       </property>
+       <property name="text">
+        <string>...</string>
+       </property>
+       <property name="icon">
+        <iconset resource="../../resources.qrc">
+         <normaloff>:/icons/32x32/Reset.png</normaloff>:/icons/32x32/Reset.png</iconset>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="toolEdit">
+       <property name="toolTip">
+        <string>Move route points.</string>
+       </property>
+       <property name="text">
+        <string>...</string>
+       </property>
+       <property name="icon">
+        <iconset resource="../../resources.qrc">
+         <normaloff>:/icons/32x32/LineMove.png</normaloff>:/icons/32x32/LineMove.png</iconset>
+       </property>
+      </widget>
+     </item>
+     <item>
       <spacer name="horizontalSpacer">
        <property name="orientation">
         <enum>Qt::Horizontal</enum>
diff --git a/src/mouse/CScrOptEditLine.cpp b/src/gis/rte/router/CRouterMapQuest.cpp
similarity index 76%
copy from src/mouse/CScrOptEditLine.cpp
copy to src/gis/rte/router/CRouterMapQuest.cpp
index b795628..565d9e7 100644
--- a/src/mouse/CScrOptEditLine.cpp
+++ b/src/gis/rte/router/CRouterMapQuest.cpp
@@ -16,21 +16,24 @@
 
 **********************************************************************************************/
 
-#include "CScrOptEditLine.h"
+#include "gis/rte/router/CRouterMapQuest.h"
 
-#include <QtWidgets>
-
-CScrOptEditLine::CScrOptEditLine(QWidget *parent)
-    : IScrOpt(parent)
+CRouterMapQuest::CRouterMapQuest(QWidget *parent)
+    : IRouter(false, parent)
 {
     setupUi(this);
+}
+
+CRouterMapQuest::~CRouterMapQuest()
+{
+}
 
-    move(0,0);
-    adjustSize();
-    show();
+QString CRouterMapQuest::getOptions()
+{
+    return QString();
 }
 
-CScrOptEditLine::~CScrOptEditLine()
+void CRouterMapQuest::calcRoute(const IGisItem::key_t& key)
 {
 }
 
diff --git a/src/mouse/CScrOptEditLine.h b/src/gis/rte/router/CRouterMapQuest.h
similarity index 67%
copy from src/mouse/CScrOptEditLine.h
copy to src/gis/rte/router/CRouterMapQuest.h
index 4325729..c446bc7 100644
--- a/src/mouse/CScrOptEditLine.h
+++ b/src/gis/rte/router/CRouterMapQuest.h
@@ -16,23 +16,27 @@
 
 **********************************************************************************************/
 
-#ifndef CSCROPTEDITLINE_H
-#define CSCROPTEDITLINE_H
+#ifndef CROUTERMAPQUEST_H
+#define CROUTERMAPQUEST_H
 
-#include "mouse/IScrOpt.h"
-#include "ui_IScrOptEditLine.h"
+#include "gis/rte/router/IRouter.h"
+#include "ui_IRouterMapQuest.h"
 
-class CScrOptEditLine : public IScrOpt, public Ui::IScrOptEditLine
+class CRouterMapQuest : public IRouter, private Ui::IRouterMapQuest
 {
     Q_OBJECT
 public:
-    CScrOptEditLine(QWidget * parent);
-    virtual ~CScrOptEditLine();
+    CRouterMapQuest(QWidget * parent);
+    virtual ~CRouterMapQuest();
 
-    void draw(QPainter& p)
+    void calcRoute(const IGisItem::key_t& key);
+    bool calcRoute(const QPointF& p1, const QPointF& p2, QPolygonF& coords)
     {
+        return false;
     }
+
+    QString getOptions();
 };
 
-#endif //CSCROPTEDITLINE_H
+#endif //CROUTERMAPQUEST_H
 
diff --git a/src/gis/rte/router/CRouterRoutino.cpp b/src/gis/rte/router/CRouterRoutino.cpp
new file mode 100644
index 0000000..100243c
--- /dev/null
+++ b/src/gis/rte/router/CRouterRoutino.cpp
@@ -0,0 +1,238 @@
+/**********************************************************************************************
+    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+**********************************************************************************************/
+
+#include "gis/CGisWidget.h"
+#include "gis/rte/CGisItemRte.h"
+#include "gis/rte/router/CRouterRoutino.h"
+#include "gis/rte/router/CRouterRoutinoPathSetup.h"
+#include "helpers/CSettings.h"
+#include <QtWidgets>
+#include <proj_api.h>
+#include <routino.h>
+
+
+CRouterRoutino::CRouterRoutino(QWidget *parent)
+    : IRouter(true, parent)
+{
+    setupUi(this);
+
+    comboProfile->addItem(tr("Foot"), "foot");
+    comboProfile->addItem(tr("Horse"), "horse");
+    comboProfile->addItem(tr("Wheelchair"), "wheelchair");
+    comboProfile->addItem(tr("Bicycle"), "bicycle");
+    comboProfile->addItem(tr("Moped"), "moped");
+    comboProfile->addItem(tr("Motorcycle"), "motorcycle");
+    comboProfile->addItem(tr("Motorcar"), "motorcar");
+    comboProfile->addItem(tr("Goods"), "goods");
+
+    comboMode->addItem(tr("Shortest"));
+    comboMode->addItem(tr("Quickest"));
+
+    QFile _profiles("://xml/routino/routino-profiles.xml");
+    _profiles.open(QIODevice::ReadOnly);
+    QTemporaryFile profiles;
+    profiles.open();
+    profiles.write(_profiles.readAll());
+    profiles.close();
+
+    QFile _translations("://xml/routino/routino-translations.xml");
+    _translations.open(QIODevice::ReadOnly);
+    QTemporaryFile translations;
+    translations.open();
+    translations.write(_translations.readAll());
+    translations.close();
+
+    RoutinoInit(profiles.fileName().toUtf8(), translations.fileName().toUtf8());
+
+    connect(toolSetupPaths, SIGNAL(clicked()), this, SLOT(slotSetupPaths()));
+
+    SETTINGS;
+    dbPaths = cfg.value("Route/routino/paths", dbPaths).toStringList();
+    buildDatabaseList();
+
+    comboProfile->setCurrentIndex(cfg.value("Route/routino/profile",0).toInt());
+    comboMode->setCurrentIndex(cfg.value("Route/routino/mode",0).toInt());
+    comboDatabase->setCurrentIndex(cfg.value("Route/routino/database",0).toInt());
+
+    updateHelpText();
+}
+
+CRouterRoutino::~CRouterRoutino()
+{
+    SETTINGS;
+    cfg.setValue("Route/routino/paths", dbPaths);
+    cfg.setValue("Route/routino/profile", comboProfile->currentIndex());
+    cfg.setValue("Route/routino/mode", comboMode->currentIndex());
+    cfg.setValue("Route/routino/database", comboDatabase->currentIndex());
+
+    freeDatabaseList();
+    RoutinoRelease();
+}
+
+bool CRouterRoutino::hasFastRouting()
+{
+    return IRouter::hasFastRouting() && (comboDatabase->count() != 0);
+}
+
+QString CRouterRoutino::getOptions()
+{
+    QString str;
+
+    str  = tr("profile \"%1\"").arg(comboProfile->currentText());
+    str += tr(", mode \"%1\"").arg(comboMode->currentText());
+
+    return str;
+}
+
+void CRouterRoutino::slotSetupPaths()
+{
+    CRouterRoutinoPathSetup dlg(dbPaths);
+    dlg.exec();
+
+    buildDatabaseList();
+    updateHelpText();
+}
+
+void CRouterRoutino::buildDatabaseList()
+{
+    QRegExp re("(.*)-segments.mem");
+    freeDatabaseList();
+
+    foreach(const QString &path, dbPaths)
+    {
+        QDir dir(path);
+        foreach(const QString &filename, dir.entryList(QStringList("*segments.mem"), QDir::Files|QDir::Readable, QDir::Name))
+        {
+            QString prefix;
+            if(re.exactMatch(filename))
+            {
+                prefix = re.cap(1);
+            }
+            else
+            {
+                continue;
+            }
+
+#ifdef OS_WIN
+            QFileInfo fi(dir.absoluteFilePath(filename));
+            if(fi.size() > 0x0FFFFFFFFLL)
+            {
+                QMessageBox::warning(this, tr("Warning..."), tr("%1: Due to limitations in the Windows POSIX API Routino can't handle files larger than 4GB.").arg(prefix), QMessageBox::Ok);
+                continue;
+            }
+#endif
+            H_RoutinoDataSet data = RoutinoRegisterData(dir.absolutePath().toUtf8(), prefix.toUtf8());
+            if(data)
+            {
+                comboDatabase->addItem(prefix.replace("_", " "), quint64(data));
+            }
+        }
+    }
+}
+
+void CRouterRoutino::freeDatabaseList()
+{
+    for(int i = 0; i < comboDatabase->count(); i++)
+    {
+        H_RoutinoDataSet data = H_RoutinoDataSet(comboDatabase->itemData(i, Qt::UserRole).toULongLong());
+        RoutinoFreeData(data);
+    }
+    comboDatabase->clear();
+}
+
+void CRouterRoutino::updateHelpText()
+{
+    if(comboDatabase->count() != 0)
+    {
+        frameHelp->hide();
+        comboDatabase->setEnabled(true);
+    }
+    else
+    {
+        frameHelp->show();
+        comboDatabase->setEnabled(false);
+    }
+}
+
+void CRouterRoutino::calcRoute(const IGisItem::key_t& key)
+{
+    CGisItemRte * rte = dynamic_cast<CGisItemRte*>(CGisWidget::self().getItemByKey(key));
+    if(rte == 0)
+    {
+        return;
+    }
+
+    H_RoutinoDataSet data   = H_RoutinoDataSet(comboDatabase->currentData(Qt::UserRole).toULongLong());
+    if(data == 0)
+    {
+        return;
+    }
+
+    QString profile         = comboProfile->currentData(Qt::UserRole).toString();
+
+    SGisLine line;
+    QVector<float> lon,lat;
+    rte->getPolylineFromData(line);
+    foreach(const IGisLine::point_t &pt, line)
+    {
+        lon << pt.coord.x();
+        lat << pt.coord.y();
+    }
+
+    T_RoutinoRoute * route = RoutinoCalculate(data, profile.toUtf8(), comboMode->currentIndex(), lon.data(), lat.data(), line.size());
+
+    rte->setResult(route, getOptions());
+
+    RoutinoFreeRoute(route);
+}
+
+
+bool CRouterRoutino::calcRoute(const QPointF& p1, const QPointF& p2, QPolygonF& coords)
+{
+    H_RoutinoDataSet data   = H_RoutinoDataSet(comboDatabase->currentData(Qt::UserRole).toULongLong());
+    if(data == 0)
+    {
+        return 0;
+    }
+    QString profile         = comboProfile->currentData(Qt::UserRole).toString();
+
+
+    float lon[2];
+    float lat[2];
+
+    lon[0] = p1.x();
+    lon[1] = p2.x();
+
+    lat[0] = p1.y();
+    lat[1] = p2.y();
+
+    T_RoutinoRoute * route = RoutinoCalculate(data, profile.toUtf8(), comboMode->currentIndex(), lon, lat, 2);
+
+    T_RoutinoRoute * next = route;
+    while(next)
+    {
+        if(next->type != IMP_WAYPOINT)
+        {
+            coords << QPointF(next->lon, next->lat);
+        }
+        next = next->next;
+    }
+
+    RoutinoFreeRoute(route);
+    return !coords.isEmpty();
+}
diff --git a/src/gis/rte/CScrOptRte.h b/src/gis/rte/router/CRouterRoutino.h
similarity index 61%
copy from src/gis/rte/CScrOptRte.h
copy to src/gis/rte/router/CRouterRoutino.h
index 21543df..e69210b 100644
--- a/src/gis/rte/CScrOptRte.h
+++ b/src/gis/rte/router/CRouterRoutino.h
@@ -16,35 +16,37 @@
 
 **********************************************************************************************/
 
-#ifndef CSCROPTRTE_H
-#define CSCROPTRTE_H
+#ifndef CROUTERROUTINO_H
+#define CROUTERROUTINO_H
 
-#include "gis/IGisItem.h"
-#include "mouse/IScrOpt.h"
+#include "gis/rte/router/IRouter.h"
+#include "ui_IRouterRoutino.h"
+#include <routino.h>
 
-#include "ui_IScrOptRte.h"
-#include <QWidget>
-
-class CGisItemRte;
-class IMouse;
-
-class CScrOptRte : public IScrOpt, private Ui::IScrOptRte
+class CRouterRoutino : public IRouter, private Ui::IRouterRoutino
 {
     Q_OBJECT
 public:
-    CScrOptRte(CGisItemRte * rte, const QPoint &point, IMouse *parent);
-    virtual ~CScrOptRte();
+    CRouterRoutino(QWidget * parent);
+    virtual ~CRouterRoutino();
+
+    void calcRoute(const IGisItem::key_t& key);
+    bool calcRoute(const QPointF& p1, const QPointF& p2, QPolygonF& coords);
 
-    void draw(QPainter& p);
+    bool hasFastRouting();
+
+    QString getOptions();
 
 private slots:
-    void slotDelete();
-    void slotCopy();
+    void slotSetupPaths();
+
 
 private:
-    IGisItem::key_t key;
-    QPointF anchor;
+    void buildDatabaseList();
+    void freeDatabaseList();
+    void updateHelpText();
+    QStringList dbPaths;
 };
 
-#endif //CSCROPTRTE_H
+#endif //CROUTERROUTINO_H
 
diff --git a/src/dem/CDemPathSetup.cpp b/src/gis/rte/router/CRouterRoutinoPathSetup.cpp
similarity index 75%
copy from src/dem/CDemPathSetup.cpp
copy to src/gis/rte/router/CRouterRoutinoPathSetup.cpp
index e613a70..6abf3e3 100644
--- a/src/dem/CDemPathSetup.cpp
+++ b/src/gis/rte/router/CRouterRoutinoPathSetup.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -17,12 +17,11 @@
 **********************************************************************************************/
 
 #include "CMainWindow.h"
-#include "dem/CDemDraw.h"
-#include "dem/CDemPathSetup.h"
+#include "gis/rte/router/CRouterRoutinoPathSetup.h"
 
 #include <QtWidgets>
 
-CDemPathSetup::CDemPathSetup(QStringList &paths)
+CRouterRoutinoPathSetup::CRouterRoutinoPathSetup(QStringList &paths)
     : QDialog(&CMainWindow::self())
     , paths(paths)
 {
@@ -38,22 +37,22 @@ CDemPathSetup::CDemPathSetup(QStringList &paths)
         item->setText(path);
     }
 
-    labelHelp->setText(tr("Add or remove paths containing DEM data. There can be multiple files in a path but no sub-path is parsed. Supported formats are: %1").arg(CDemDraw::getSupportedFormats().join(", ")));
+    labelHelp->setText(tr("Add or remove paths containing Routino data. There can be multiple databases in a path but no sub-path is parsed."));
 }
 
-CDemPathSetup::~CDemPathSetup()
+CRouterRoutinoPathSetup::~CRouterRoutinoPathSetup()
 {
 }
 
-void CDemPathSetup::slotItemSelectionChanged()
+void CRouterRoutinoPathSetup::slotItemSelectionChanged()
 {
     QList<QListWidgetItem*> items = listWidget->selectedItems();
     toolDelete->setEnabled(!items.isEmpty());
 }
 
-void CDemPathSetup::slotAddPath()
+void CRouterRoutinoPathSetup::slotAddPath()
 {
-    QString path = QFileDialog::getExistingDirectory(this, tr("Select DEM file path..."), QDir::homePath(), 0);
+    QString path = QFileDialog::getExistingDirectory(this, tr("Select routing data file path..."), QDir::homePath(), 0);
     if(!path.isEmpty())
     {
         QListWidgetItem * item = new QListWidgetItem(listWidget);
@@ -61,13 +60,13 @@ void CDemPathSetup::slotAddPath()
     }
 }
 
-void CDemPathSetup::slotDelPath()
+void CRouterRoutinoPathSetup::slotDelPath()
 {
     QList<QListWidgetItem *> items = listWidget->selectedItems();
     qDeleteAll(items);
 }
 
-void CDemPathSetup::accept()
+void CRouterRoutinoPathSetup::accept()
 {
     paths.clear();
     for(int i = 0; i < listWidget->count(); i++)
diff --git a/src/gis/rte/CScrOptRte.h b/src/gis/rte/router/CRouterRoutinoPathSetup.h
similarity index 62%
copy from src/gis/rte/CScrOptRte.h
copy to src/gis/rte/router/CRouterRoutinoPathSetup.h
index 21543df..974fbcc 100644
--- a/src/gis/rte/CScrOptRte.h
+++ b/src/gis/rte/router/CRouterRoutinoPathSetup.h
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -16,35 +16,31 @@
 
 **********************************************************************************************/
 
-#ifndef CSCROPTRTE_H
-#define CSCROPTRTE_H
+#ifndef CROUTERROUTINOPATHSETUP_H
+#define CROUTERROUTINOPATHSETUP_H
 
-#include "gis/IGisItem.h"
-#include "mouse/IScrOpt.h"
+#include "ui_IRouterRoutinoPathSetup.h"
+#include <QDialog>
 
-#include "ui_IScrOptRte.h"
-#include <QWidget>
-
-class CGisItemRte;
-class IMouse;
-
-class CScrOptRte : public IScrOpt, private Ui::IScrOptRte
+class CRouterRoutinoPathSetup : public QDialog, private Ui::IRouterRoutinoPathSetup
 {
     Q_OBJECT
 public:
-    CScrOptRte(CGisItemRte * rte, const QPoint &point, IMouse *parent);
-    virtual ~CScrOptRte();
+    CRouterRoutinoPathSetup(QStringList& paths);
+    virtual ~CRouterRoutinoPathSetup();
 
-    void draw(QPainter& p);
+public slots:
+    void accept();
 
 private slots:
-    void slotDelete();
-    void slotCopy();
+    void slotAddPath();
+    void slotDelPath();
+    void slotItemSelectionChanged();
+
 
 private:
-    IGisItem::key_t key;
-    QPointF anchor;
+    QStringList& paths;
 };
 
-#endif //CSCROPTRTE_H
+#endif //CROUTERROUTINOPATHSETUP_H
 
diff --git a/src/gis/rte/router/CRouterSetup.cpp b/src/gis/rte/router/CRouterSetup.cpp
new file mode 100644
index 0000000..3228520
--- /dev/null
+++ b/src/gis/rte/router/CRouterSetup.cpp
@@ -0,0 +1,87 @@
+/**********************************************************************************************
+    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+**********************************************************************************************/
+
+#include "gis/CGisWidget.h"
+#include "gis/rte/CGisItemRte.h"
+#include "gis/rte/router/CRouterMapQuest.h"
+#include "gis/rte/router/CRouterRoutino.h"
+#include "gis/rte/router/CRouterSetup.h"
+#include "helpers/CSettings.h"
+
+#include <QtWidgets>
+
+CRouterSetup * CRouterSetup::pSelf = 0;
+
+CRouterSetup::CRouterSetup(QWidget * parent)
+    : QWidget(parent)
+{
+    setupUi(this);
+    pSelf = this;
+
+    comboRouter->addItem(tr("Routino (offline)"));
+    comboRouter->addItem(tr("MapQuest (online)"));
+
+    stackedWidget->addWidget(new CRouterRoutino(this));
+    stackedWidget->addWidget(new CRouterMapQuest(this));
+
+    connect(comboRouter, SIGNAL(currentIndexChanged(int)), this, SLOT(slotSelectRouter(int)));
+
+    SETTINGS;
+    comboRouter->setCurrentIndex(cfg.value("Route/current",0).toInt());
+}
+
+CRouterSetup::~CRouterSetup()
+{
+    SETTINGS;
+    cfg.setValue("Route/current", comboRouter->currentIndex());
+}
+
+bool CRouterSetup::hasFastRouting()
+{
+    IRouter * router = dynamic_cast<IRouter*>(stackedWidget->currentWidget());
+    if(router)
+    {
+        return router->hasFastRouting();
+    }
+    return false;
+}
+
+void CRouterSetup::slotSelectRouter(int i)
+{
+    stackedWidget->setCurrentIndex(i);
+}
+
+void CRouterSetup::calcRoute(const IGisItem::key_t& key)
+{
+    IRouter * router = dynamic_cast<IRouter*>(stackedWidget->currentWidget());
+    if(router)
+    {
+        router->calcRoute(key);
+    }
+}
+
+bool CRouterSetup::calcRoute(const QPointF& p1, const QPointF& p2, QPolygonF& coords)
+{
+    IRouter * router = dynamic_cast<IRouter*>(stackedWidget->currentWidget());
+    if(router)
+    {
+        return router->calcRoute(p1, p2, coords);
+    }
+
+    return false;
+}
diff --git a/src/gis/rte/CScrOptRte.h b/src/gis/rte/router/CRouterSetup.h
similarity index 64%
copy from src/gis/rte/CScrOptRte.h
copy to src/gis/rte/router/CRouterSetup.h
index 21543df..5241d55 100644
--- a/src/gis/rte/CScrOptRte.h
+++ b/src/gis/rte/router/CRouterSetup.h
@@ -16,35 +16,37 @@
 
 **********************************************************************************************/
 
-#ifndef CSCROPTRTE_H
-#define CSCROPTRTE_H
+#ifndef CROUTERSETUP_H
+#define CROUTERSETUP_H
 
 #include "gis/IGisItem.h"
-#include "mouse/IScrOpt.h"
-
-#include "ui_IScrOptRte.h"
+#include "ui_IRouterSetup.h"
 #include <QWidget>
 
-class CGisItemRte;
-class IMouse;
-
-class CScrOptRte : public IScrOpt, private Ui::IScrOptRte
+class CRouterSetup : public QWidget, private Ui::IRouterSetup
 {
     Q_OBJECT
 public:
-    CScrOptRte(CGisItemRte * rte, const QPoint &point, IMouse *parent);
-    virtual ~CScrOptRte();
+    static CRouterSetup& self()
+    {
+        return *pSelf;
+    }
+    virtual ~CRouterSetup();
 
-    void draw(QPainter& p);
+    void calcRoute(const IGisItem::key_t &key);
+    bool calcRoute(const QPointF& p1, const QPointF& p2, QPolygonF& coords);
+
+    bool hasFastRouting();
 
 private slots:
-    void slotDelete();
-    void slotCopy();
+    void slotSelectRouter(int i);
 
 private:
-    IGisItem::key_t key;
-    QPointF anchor;
+    friend class Ui_IMainWindow;
+    CRouterSetup(QWidget * parent);
+
+    static CRouterSetup * pSelf;
 };
 
-#endif //CSCROPTRTE_H
+#endif //CROUTERSETUP_H
 
diff --git a/src/gis/IGisLine.cpp b/src/gis/rte/router/IRouter.cpp
similarity index 85%
copy from src/gis/IGisLine.cpp
copy to src/gis/rte/router/IRouter.cpp
index c56e721..0ebca74 100644
--- a/src/gis/IGisLine.cpp
+++ b/src/gis/rte/router/IRouter.cpp
@@ -16,13 +16,15 @@
 
 **********************************************************************************************/
 
-#include "IGisLine.h"
+#include "gis/rte/router/IRouter.h"
 
-IGisLine::IGisLine()
+IRouter::IRouter(bool fastRouting, QWidget *parent)
+    : QWidget(parent)
+    , fastRouting(fastRouting)
 {
 }
 
-IGisLine::~IGisLine()
+IRouter::~IRouter()
 {
 }
 
diff --git a/src/gis/rte/CScrOptRte.h b/src/gis/rte/router/IRouter.h
similarity index 69%
copy from src/gis/rte/CScrOptRte.h
copy to src/gis/rte/router/IRouter.h
index 21543df..5485361 100644
--- a/src/gis/rte/CScrOptRte.h
+++ b/src/gis/rte/router/IRouter.h
@@ -16,35 +16,31 @@
 
 **********************************************************************************************/
 
-#ifndef CSCROPTRTE_H
-#define CSCROPTRTE_H
+#ifndef IROUTER_H
+#define IROUTER_H
 
 #include "gis/IGisItem.h"
-#include "mouse/IScrOpt.h"
-
-#include "ui_IScrOptRte.h"
 #include <QWidget>
 
-class CGisItemRte;
-class IMouse;
-
-class CScrOptRte : public IScrOpt, private Ui::IScrOptRte
+class IRouter : public QWidget
 {
     Q_OBJECT
 public:
-    CScrOptRte(CGisItemRte * rte, const QPoint &point, IMouse *parent);
-    virtual ~CScrOptRte();
+    IRouter(bool fastRouting, QWidget * parent);
+    virtual ~IRouter();
 
-    void draw(QPainter& p);
+    virtual void calcRoute(const IGisItem::key_t& key) = 0;
+    virtual bool calcRoute(const QPointF& p1, const QPointF& p2, QPolygonF& coords) = 0;
+    virtual bool hasFastRouting()
+    {
+        return fastRouting;
+    }
 
-private slots:
-    void slotDelete();
-    void slotCopy();
+    virtual QString getOptions() = 0;
 
 private:
-    IGisItem::key_t key;
-    QPointF anchor;
+    bool fastRouting;
 };
 
-#endif //CSCROPTRTE_H
+#endif //IROUTER_H
 
diff --git a/src/gis/rte/router/IRouterMapQuest.ui b/src/gis/rte/router/IRouterMapQuest.ui
new file mode 100644
index 0000000..9eeb32e
--- /dev/null
+++ b/src/gis/rte/router/IRouterMapQuest.ui
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>IRouterMapQuest</class>
+ <widget class="QWidget" name="IRouterMapQuest">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>t.b.d</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/gis/rte/router/IRouterRoutino.ui b/src/gis/rte/router/IRouterRoutino.ui
new file mode 100644
index 0000000..92ff7c6
--- /dev/null
+++ b/src/gis/rte/router/IRouterRoutino.ui
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>IRouterRoutino</class>
+ <widget class="QWidget" name="IRouterRoutino">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QGridLayout" name="gridLayout">
+     <item row="2" column="1">
+      <widget class="QComboBox" name="comboDatabase"/>
+     </item>
+     <item row="0" column="1">
+      <widget class="QComboBox" name="comboProfile"/>
+     </item>
+     <item row="1" column="1">
+      <widget class="QComboBox" name="comboMode"/>
+     </item>
+     <item row="0" column="0">
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Profile</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="label_2">
+       <property name="text">
+        <string>Mode</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="0">
+      <widget class="QLabel" name="label_5">
+       <property name="text">
+        <string>Database</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="2">
+      <widget class="QToolButton" name="toolSetupPaths">
+       <property name="toolTip">
+        <string>Add paths with Routino database.</string>
+       </property>
+       <property name="text">
+        <string>...</string>
+       </property>
+       <property name="icon">
+        <iconset resource="../../../resources.qrc">
+         <normaloff>:/icons/32x32/PathBlue.png</normaloff>:/icons/32x32/PathBlue.png</iconset>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QFrame" name="frameHelp">
+       <property name="frameShape">
+        <enum>QFrame::NoFrame</enum>
+       </property>
+       <property name="frameShadow">
+        <enum>QFrame::Plain</enum>
+       </property>
+       <layout class="QHBoxLayout" name="horizontalLayout">
+        <item>
+         <widget class="QLabel" name="label_3">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string/>
+          </property>
+          <property name="pixmap">
+           <pixmap resource="../../../resources.qrc">:/icons/48x48/Help.png</pixmap>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="label_4">
+          <property name="text">
+           <string>To use offline routing you need to define paths to local routing data. Use the setup tool button to register a path.</string>
+          </property>
+          <property name="alignment">
+           <set>Qt::AlignJustify|Qt::AlignTop</set>
+          </property>
+          <property name="wordWrap">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../../../resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/map/IMapPathSetup.ui b/src/gis/rte/router/IRouterRoutinoPathSetup.ui
similarity index 58%
copy from src/map/IMapPathSetup.ui
copy to src/gis/rte/router/IRouterRoutinoPathSetup.ui
index 5761e9a..fc068f1 100644
--- a/src/map/IMapPathSetup.ui
+++ b/src/gis/rte/router/IRouterRoutinoPathSetup.ui
@@ -1,69 +1,23 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <ui version="4.0">
- <class>IMapPathSetup</class>
- <widget class="QDialog" name="IMapPathSetup">
+ <class>IRouterRoutinoPathSetup</class>
+ <widget class="QDialog" name="IRouterRoutinoPathSetup">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>450</width>
-    <height>275</height>
+    <height>200</height>
    </rect>
   </property>
   <property name="windowTitle">
-   <string>Setup map paths</string>
+   <string>Setup Routino database...</string>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout_2">
    <item>
-    <widget class="QLabel" name="label">
-     <property name="text">
-      <string>Root path of tile cache for online maps:</string>
-     </property>
-    </widget>
-   </item>
-   <item>
     <layout class="QHBoxLayout" name="horizontalLayout_2">
      <item>
-      <widget class="QLabel" name="labelCacheRoot">
-       <property name="text">
-        <string>-</string>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QToolButton" name="toolCacheRoot">
-       <property name="text">
-        <string>...</string>
-       </property>
-       <property name="icon">
-        <iconset resource="../resources.qrc">
-         <normaloff>:/icons/32x32/PathBlue.png</normaloff>:/icons/32x32/PathBlue.png</iconset>
-       </property>
-       <property name="iconSize">
-        <size>
-         <width>22</width>
-         <height>22</height>
-        </size>
-       </property>
-      </widget>
-     </item>
-    </layout>
-   </item>
-   <item>
-    <widget class="Line" name="line">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-    </widget>
-   </item>
-   <item>
-    <layout class="QHBoxLayout" name="horizontalLayout_3">
-     <item>
-      <widget class="QListWidget" name="listWidget">
-       <property name="selectionMode">
-        <enum>QAbstractItemView::ExtendedSelection</enum>
-       </property>
-      </widget>
+      <widget class="QListWidget" name="listWidget"/>
      </item>
      <item>
       <layout class="QVBoxLayout" name="verticalLayout">
@@ -73,7 +27,7 @@
           <string>...</string>
          </property>
          <property name="icon">
-          <iconset resource="../resources.qrc">
+          <iconset resource="../../../resources.qrc">
            <normaloff>:/icons/32x32/Add.png</normaloff>:/icons/32x32/Add.png</iconset>
          </property>
          <property name="iconSize">
@@ -93,7 +47,7 @@
           <string>...</string>
          </property>
          <property name="icon">
-          <iconset resource="../resources.qrc">
+          <iconset resource="../../../resources.qrc">
            <normaloff>:/icons/32x32/DeleteMultiple.png</normaloff>:/icons/32x32/DeleteMultiple.png</iconset>
          </property>
          <property name="iconSize">
@@ -124,51 +78,36 @@
    <item>
     <layout class="QHBoxLayout" name="horizontalLayout">
      <item>
-      <widget class="QLabel" name="labelHelp">
+      <widget class="QLabel" name="label">
        <property name="sizePolicy">
-        <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+        <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
          <horstretch>0</horstretch>
          <verstretch>0</verstretch>
         </sizepolicy>
        </property>
        <property name="text">
-        <string>-</string>
-       </property>
-       <property name="alignment">
-        <set>Qt::AlignJustify|Qt::AlignVCenter</set>
+        <string/>
        </property>
-       <property name="wordWrap">
-        <bool>true</bool>
+       <property name="pixmap">
+        <pixmap resource="../../../resources.qrc">:/icons/48x48/Help.png</pixmap>
        </property>
       </widget>
      </item>
      <item>
-      <widget class="QLabel" name="label_3">
-       <property name="maximumSize">
-        <size>
-         <width>64</width>
-         <height>16777215</height>
-        </size>
-       </property>
+      <widget class="QLabel" name="labelHelp">
        <property name="text">
-        <string/>
-       </property>
-       <property name="pixmap">
-        <pixmap resource="../resources.qrc">:/icons/48x48/Help.png</pixmap>
+        <string>-</string>
        </property>
        <property name="alignment">
-        <set>Qt::AlignCenter</set>
+        <set>Qt::AlignJustify|Qt::AlignTop</set>
+       </property>
+       <property name="wordWrap">
+        <bool>true</bool>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QDialogButtonBox" name="buttonBox">
-       <property name="sizePolicy">
-        <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
-         <horstretch>0</horstretch>
-         <verstretch>0</verstretch>
-        </sizepolicy>
-       </property>
        <property name="orientation">
         <enum>Qt::Vertical</enum>
        </property>
@@ -179,24 +118,16 @@
      </item>
     </layout>
    </item>
-   <item>
-    <widget class="QPushButton" name="pushMapHonk">
-     <property name="text">
-      <string>Help! I want maps!
-I don't want to read the documentation!</string>
-     </property>
-    </widget>
-   </item>
   </layout>
  </widget>
  <resources>
-  <include location="../resources.qrc"/>
+  <include location="../../../resources.qrc"/>
  </resources>
  <connections>
   <connection>
    <sender>buttonBox</sender>
    <signal>accepted()</signal>
-   <receiver>IMapPathSetup</receiver>
+   <receiver>IRouterRoutinoPathSetup</receiver>
    <slot>accept()</slot>
    <hints>
     <hint type="sourcelabel">
@@ -212,7 +143,7 @@ I don't want to read the documentation!</string>
   <connection>
    <sender>buttonBox</sender>
    <signal>rejected()</signal>
-   <receiver>IMapPathSetup</receiver>
+   <receiver>IRouterRoutinoPathSetup</receiver>
    <slot>reject()</slot>
    <hints>
     <hint type="sourcelabel">
diff --git a/src/gis/rte/router/IRouterSetup.ui b/src/gis/rte/router/IRouterSetup.ui
new file mode 100644
index 0000000..1750221
--- /dev/null
+++ b/src/gis/rte/router/IRouterSetup.ui
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>IRouterSetup</class>
+ <widget class="QWidget" name="IRouterSetup">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>302</width>
+    <height>382</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>3</number>
+   </property>
+   <property name="rightMargin">
+    <number>3</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QComboBox" name="comboRouter"/>
+   </item>
+   <item>
+    <widget class="QStackedWidget" name="stackedWidget"/>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/gis/tnv/serialization.cpp b/src/gis/tnv/serialization.cpp
index f84fa4a..a1fc1b6 100644
--- a/src/gis/tnv/serialization.cpp
+++ b/src/gis/tnv/serialization.cpp
@@ -477,8 +477,20 @@ bool CGisItemTrk::readTwoNav(const QString& filename)
         case 'C':
         {
             QStringList values = line.split(' ', QString::SkipEmptyParts);
-            QColor c(values[1].toInt(),values[2].toInt(),values[3].toInt());
-            setColor(c);
+            if(values.size() > 2)
+            {
+                QColor c(values[1].toInt(),values[2].toInt(),values[3].toInt());
+                setColor(c);
+            }
+            else
+            {
+                values = values[1].split(',',QString::SkipEmptyParts);
+                if(values.size() >= 3)
+                {
+                    QColor c(values[0].toInt(),values[1].toInt(),values[2].toInt());
+                    setColor(c);
+                }
+            }
             break;
         }
 
@@ -493,8 +505,8 @@ bool CGisItemTrk::readTwoNav(const QString& filename)
                 return false;
             }
 
-            QString lat = values[2].replace(QChar(186),"");
-            QString lon = values[3].replace(QChar(186),"");
+            QString lat = values[2].replace(QChar(186),"").replace(QChar(-3),"");
+            QString lon = values[3].replace(QChar(186),"").replace(QChar(-3),"");
             GPS_Math_Str_To_Deg(lat + " " + lon, pt.lon, pt.lat);
 
             pt.time = readCompeTime(values[4] + " " + values[5], true);
@@ -692,8 +704,8 @@ bool CTwoNavProject::loadWpts(const QString& filename, const QDir& dir)
 
             wpt.name = values[1];
 
-            QString lat = values[3].replace(QChar(186),"");
-            QString lon = values[4].replace(QChar(186),"");
+            QString lat = values[3].replace(QChar(186),"").replace(QChar(-3),"");
+            QString lon = values[4].replace(QChar(186),"").replace(QChar(-3),"");
             GPS_Math_Str_To_Deg(lat + " " + lon, wpt.lon, wpt.lat);
 
             wpt.time = readCompeTime(values[5] + " " + values[6], false);
diff --git a/src/gis/trk/CCombineTrk.cpp b/src/gis/trk/CCombineTrk.cpp
index a146cb5..e6b6c26 100644
--- a/src/gis/trk/CCombineTrk.cpp
+++ b/src/gis/trk/CCombineTrk.cpp
@@ -23,7 +23,7 @@
 
 #include <QtWidgets>
 
-CCombineTrk::CCombineTrk(CGisItemTrk& trk, IGisProject& project, QWidget * parent)
+CCombineTrk::CCombineTrk(CGisItemTrk& trk, const QList<IGisItem::key_t> &keysPreSel, IGisProject& project, QWidget * parent)
     : QDialog(parent)
     , trk(trk)
     , project(project)
@@ -39,7 +39,7 @@ CCombineTrk::CCombineTrk(CGisItemTrk& trk, IGisProject& project, QWidget * paren
             continue;
         }
 
-        if(trk.getKey() == trk1->getKey())
+        if(keysPreSel.contains(trk1->getKey()))
         {
             continue;
         }
@@ -50,14 +50,24 @@ CCombineTrk::CCombineTrk(CGisItemTrk& trk, IGisProject& project, QWidget * paren
         item->setIcon(trk1->getIcon());
         item->setData(Qt::UserRole + 1, key.item);
         item->setData(Qt::UserRole + 2, key.project);
+        item->setData(Qt::UserRole + 3, key.device);
     }
 
-    const IGisItem::key_t& key = trk.getKey();
-    QListWidgetItem * item = new QListWidgetItem(listSelected);
-    item->setText(trk.getName());
-    item->setIcon(trk.getIcon());
-    item->setData(Qt::UserRole + 1, key.item);
-    item->setData(Qt::UserRole + 2, key.project);
+    foreach(const IGisItem::key_t& key, keysPreSel)
+    {
+        IGisItem * gisItem = dynamic_cast<IGisItem*>(project.getItemByKey(key));
+        if(gisItem == 0)
+        {
+            continue;
+        }
+
+        QListWidgetItem * item = new QListWidgetItem(listSelected);
+        item->setText(gisItem->getName());
+        item->setIcon(gisItem->getIcon());
+        item->setData(Qt::UserRole + 1, key.item);
+        item->setData(Qt::UserRole + 2, key.project);
+        item->setData(Qt::UserRole + 3, key.device);
+    }
 
     connect(listAvailable, SIGNAL(itemSelectionChanged()), this, SLOT(slotSelectionChanged()));
     connect(listSelected, SIGNAL(itemSelectionChanged()), this, SLOT(slotSelectionChanged()));
@@ -84,6 +94,7 @@ void CCombineTrk::accept()
         IGisItem::key_t key;
         key.item    = listSelected->item(i)->data(Qt::UserRole + 1).toString();
         key.project = listSelected->item(i)->data(Qt::UserRole + 2).toString();
+        key.device  = listSelected->item(i)->data(Qt::UserRole + 3).toString();
         CGisItemTrk * trk1 = dynamic_cast<CGisItemTrk*>(project.getItemByKey(key));
         if(trk1 == 0)
         {
@@ -151,6 +162,7 @@ void CCombineTrk::slotRemove()
     IGisItem::key_t key;
     key.item    = item->data(Qt::UserRole + 1).toString();
     key.project = item->data(Qt::UserRole + 2).toString();
+    key.device  = item->data(Qt::UserRole + 3).toString();
 
     if(key == trk.getKey())
     {
@@ -210,6 +222,7 @@ void CCombineTrk::updatePreview()
         IGisItem::key_t key;
         key.item    = listSelected->item(i)->data(Qt::UserRole + 1).toString();
         key.project = listSelected->item(i)->data(Qt::UserRole + 2).toString();
+        key.device  = listSelected->item(i)->data(Qt::UserRole + 3).toString();
 
 
         CGisItemTrk * trk1 = dynamic_cast<CGisItemTrk*>(project.getItemByKey(key));
diff --git a/src/gis/trk/CCombineTrk.h b/src/gis/trk/CCombineTrk.h
index 13e6a55..dd54267 100644
--- a/src/gis/trk/CCombineTrk.h
+++ b/src/gis/trk/CCombineTrk.h
@@ -30,7 +30,7 @@ class CCombineTrk : public QDialog, private Ui::ICombineTrk
 {
     Q_OBJECT
 public:
-    CCombineTrk(CGisItemTrk& trk, IGisProject &project, QWidget * parent);
+    CCombineTrk(CGisItemTrk& trk, const QList<IGisItem::key_t>& keysPreSel, IGisProject &project, QWidget * parent);
     virtual ~CCombineTrk();
 
     const QList<IGisItem::key_t>& getTrackKeys()
diff --git a/src/gis/trk/CDetailsTrk.cpp b/src/gis/trk/CDetailsTrk.cpp
index dac5df2..76333c7 100644
--- a/src/gis/trk/CDetailsTrk.cpp
+++ b/src/gis/trk/CDetailsTrk.cpp
@@ -373,10 +373,8 @@ void CDetailsTrk::slotColorChanged(int idx)
 
 void CDetailsTrk::slotChangeReadOnlyMode(bool on)
 {
-    QApplication::setOverrideCursor(Qt::WaitCursor);
     trk.setReadOnlyMode(on);
     setupGui();
-    QApplication::restoreOverrideCursor();
 }
 
 
diff --git a/src/gis/trk/CGisItemTrk.cpp b/src/gis/trk/CGisItemTrk.cpp
index 7328347..49d7025 100644
--- a/src/gis/trk/CGisItemTrk.cpp
+++ b/src/gis/trk/CGisItemTrk.cpp
@@ -206,7 +206,7 @@ CGisItemTrk::CGisItemTrk(const CGisItemTrk& parentTrk, IGisProject *project, int
 }
 
 
-CGisItemTrk::CGisItemTrk(const QPolygonF& l, const QString& name, IGisProject * project, int idx)
+CGisItemTrk::CGisItemTrk(const SGisLine& l, const QString& name, IGisProject * project, int idx)
     : IGisItem(project, eTypeTrk, idx)
     , penForeground(Qt::blue, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)
     , mode(eModeNormal)
@@ -217,7 +217,7 @@ CGisItemTrk::CGisItemTrk(const QPolygonF& l, const QString& name, IGisProject *
     , rangeState(eRangeStateIdle)
 {
     trk.name = name;
-    readTrackDataFromPolyLine(l);
+    readTrackDataFromGisLine(l);
 
     flags |=  eFlagCreatedInQms|eFlagWriteAllowed;
     setColor(str2color(""));
@@ -320,7 +320,7 @@ void CGisItemTrk::setSymbol()
     setColor(str2color(trk.color));
 }
 
-void CGisItemTrk::setDataFromPolyline(const QPolygonF &l)
+void CGisItemTrk::setDataFromPolyline(const SGisLine &l)
 {
     /*
         as this will change the line significantly we better stop
@@ -334,7 +334,7 @@ void CGisItemTrk::setDataFromPolyline(const QPolygonF &l)
 
     delete dlgDetails;
 
-    readTrackDataFromPolyLine(l);
+    readTrackDataFromGisLine(l);
 
     flags |= eFlagTainted;
     changed(QObject::tr("Changed trackpoints, sacrificed all previous data."), "://icons/48x48/LineMove.png");
@@ -356,25 +356,50 @@ void CGisItemTrk::getPolylineFromData(QPolygonF &l)
     }
 }
 
-void CGisItemTrk::readTrackDataFromPolyLine(const QPolygonF &l)
+void CGisItemTrk::getPolylineFromData(SGisLine &l)
+{
+    l.clear();
+    foreach (const trkseg_t &seg, trk.segs)
+    {
+        foreach(const trkpt_t &pt, seg.pts)
+        {
+            if(pt.flags & trkpt_t::eHidden)
+            {
+                continue;
+            }
+            l << point_t(QPointF(pt.lon*DEG_TO_RAD, pt.lat * DEG_TO_RAD));
+        }
+    }
+}
+
+void CGisItemTrk::readTrackDataFromGisLine(const SGisLine &l)
 {
     trk.segs.clear();
     trk.segs.resize(1);
     trkseg_t& seg = trk.segs.first();
 
-    seg.pts.resize(l.size());
-
-    QPolygonF ele(l.size());
-    CMainWindow::self().getEelevationAt(l, ele);
-
     for(int i = 0; i < l.size(); i++)
     {
-        trkpt_t& trkpt      = seg.pts[i];
-        const QPointF& pt   = l[i];
+        seg.pts << trkpt_t();
 
-        trkpt.lon = pt.x() * RAD_TO_DEG;
-        trkpt.lat = pt.y() * RAD_TO_DEG;
-        trkpt.ele = ele[i].y();
+        trkpt_t& trkpt      = seg.pts.last();
+        const point_t& pt   = l[i];
+
+        trkpt.lon = pt.coord.x() * RAD_TO_DEG;
+        trkpt.lat = pt.coord.y() * RAD_TO_DEG;
+        trkpt.ele = pt.ele;
+
+        for(int n = 0; n < pt.subpts.size(); n++)
+        {
+            seg.pts << trkpt_t();
+
+            trkpt_t& trkpt      = seg.pts.last();
+            const subpt_t& sub  = pt.subpts[n];
+
+            trkpt.lon = sub.coord.x() * RAD_TO_DEG;
+            trkpt.lat = sub.coord.y() * RAD_TO_DEG;
+            trkpt.ele = sub.ele;
+        }
     }
 
     deriveSecondaryData();
@@ -982,7 +1007,7 @@ void CGisItemTrk::deriveSecondaryData()
 }
 
 
-void CGisItemTrk::findWaypointsCloseBy()
+void CGisItemTrk::findWaypointsCloseBy(QProgressDialog& progress, quint32& current, quint32 total)
 {
     IGisProject * project = dynamic_cast<IGisProject*>(parent());
     if(project == 0)
@@ -990,9 +1015,9 @@ void CGisItemTrk::findWaypointsCloseBy()
         return;
     }
 
-    bool withDoubles = project->getSorting() != IGisProject::eSortTrackWithoutDouble;
+    quint32 lastCurrent = current;
 
-    QApplication::setOverrideCursor(Qt::WaitCursor);
+    bool withDoubles = project->getSorting() != IGisProject::eSortTrackWithoutDouble;
 
     QVector<pointDP> line;
     // combine all segments to a single line
@@ -1055,7 +1080,7 @@ void CGisItemTrk::findWaypointsCloseBy()
     // convert all coordinates into meter relative to the first track point.
     for(int i = 0; i < line.size(); i++)
     {
-        qreal d, a1, a2;
+        qreal d, a1 = 0, a2 = 0;
         pointDP& pt1 = line[i];
 
         d = GPS_Math_Distance(pt0.x, pt0.y, pt1.x, pt1.y, a1, a2);
@@ -1071,6 +1096,7 @@ void CGisItemTrk::findWaypointsCloseBy()
 
         foreach(const pointDP &pt, line)
         {
+            current++;
             qreal d = (trkwpt.x - pt.x)*(trkwpt.x - pt.x) + (trkwpt.y - pt.y)*(trkwpt.y - pt.y);
 
             if(d < WPT_FOCUS_DIST_IN)
@@ -1093,6 +1119,16 @@ void CGisItemTrk::findWaypointsCloseBy()
                 index = NOIDX;
                 minD  = WPT_FOCUS_DIST_IN;
             }
+
+            if(current  - lastCurrent > 100)
+            {
+                lastCurrent = current;
+                progress.setValue(qRound(current * 100.0/total));
+                if(progress.wasCanceled())
+                {
+                    return;
+                }
+            }
         }
 
         if(index != NOIDX)
@@ -1114,9 +1150,6 @@ void CGisItemTrk::findWaypointsCloseBy()
     {
         plot->updateData();
     }
-
-
-    QApplication::restoreOverrideCursor();
 }
 
 bool CGisItemTrk::isCloseTo(const QPointF& pos)
@@ -1241,7 +1274,7 @@ void CGisItemTrk::reverse()
     trk1->updateDecoration(eMarkChanged, eMarkNone);
 }
 
-void CGisItemTrk::combine()
+void CGisItemTrk::combine(const QList<IGisItem::key_t>& keysPreSel)
 {
     IGisProject * project = dynamic_cast<IGisProject*>(parent());
     if(project == 0)
@@ -1249,7 +1282,7 @@ void CGisItemTrk::combine()
         return;
     }
 
-    CCombineTrk dlg(*this, *project, &CMainWindow::self());
+    CCombineTrk dlg(*this, keysPreSel, *project, &CMainWindow::self());
     dlg.exec();
 
     QList<IGisItem::key_t> keys = dlg.getTrackKeys();
diff --git a/src/gis/trk/CGisItemTrk.h b/src/gis/trk/CGisItemTrk.h
index e8c324b..084b27f 100644
--- a/src/gis/trk/CGisItemTrk.h
+++ b/src/gis/trk/CGisItemTrk.h
@@ -34,6 +34,7 @@ class QSqlDatabase;
 class CQlgtTrack;
 class IQlgtOverlay;
 class QDir;
+class QProgressDialog;
 
 #define TRK_N_COLORS 17
 
@@ -81,7 +82,7 @@ public:
        @param project
        @param idx
      */
-    CGisItemTrk(const QPolygonF& l, const QString &name, IGisProject *project, int idx);
+    CGisItemTrk(const SGisLine &l, const QString &name, IGisProject *project, int idx);
     /**
        @brief Used to create track from GPX file
        @param xml
@@ -175,12 +176,18 @@ public:
     {
         return trk.links;
     }
-    void getPolylineFromData(QPolygonF& l);
+    void getPolylineFromData(QPolygonF &l);
+    void getPolylineFromData(SGisLine& l);
     const QDateTime& getTimeStart() const
     {
         return timeStart;
     }
 
+    qint32 getNumberOfVisiblePoints() const
+    {
+        return cntVisiblePoints;
+    }
+
     /**
        @brief Get the indeces of visible points for a selected range
 
@@ -197,7 +204,7 @@ public:
     void setComment(const QString& str);
     void setDescription(const QString& str);
     void setLinks(const QList<link_t>& links);
-    void setDataFromPolyline(const QPolygonF& l);
+    void setDataFromPolyline(const SGisLine &l);
 
     IScrOpt * getScreenOptions(const QPoint &origin, IMouse * mouse);
     QPointF getPointCloseBy(const QPoint& screenPos);
@@ -246,10 +253,12 @@ public:
     /**
        @brief Combine this track with several others.
 
+       @param keysPreSel list of pre-selected track item keys
+
        Handle the complete process of selecting tracks, choosing the order and
        the final name with dialogs.
      */
-    void combine();
+    void combine(const QList<key_t> &keysPreSel);
 
     /**
        @brief Set the trkpt_t::eHidden flag
@@ -410,7 +419,7 @@ public:
      */
     void filterSpeed(qreal speed);
 
-    void findWaypointsCloseBy();
+    void findWaypointsCloseBy(QProgressDialog &progress, quint32 &current, quint32 total);
 
     static const QColor lineColors[TRK_N_COLORS];
     static const QString bulletColors[TRK_N_COLORS];
@@ -487,7 +496,7 @@ private:
 
        @param l     A polyline with coordinates [rad]
      */
-    void readTrackDataFromPolyLine(const QPolygonF &l);
+    void readTrackDataFromGisLine(const SGisLine &l);
     /**
        @brief Overide IGisItem::changed() method
 
diff --git a/src/gis/trk/CScrOptTrk.cpp b/src/gis/trk/CScrOptTrk.cpp
index 73fa23b..cad447f 100644
--- a/src/gis/trk/CScrOptTrk.cpp
+++ b/src/gis/trk/CScrOptTrk.cpp
@@ -24,7 +24,7 @@
 #include "mouse/IMouse.h"
 
 CScrOptTrk::CScrOptTrk(CGisItemTrk * trk, const QPoint& point, IMouse *parent)
-    : IScrOpt(parent->getCanvas())
+    : IScrOpt(parent)
 {
     key         = trk->getKey();
 
@@ -44,7 +44,6 @@ CScrOptTrk::CScrOptTrk(CGisItemTrk * trk, const QPoint& point, IMouse *parent)
     toolCut->setDisabled(isOnDevice);
     toolEdit->setDisabled(isOnDevice);
     toolReverse->setDisabled(isOnDevice);
-    toolCombine->setDisabled(isOnDevice);
     toolRange->setDisabled(isOnDevice);
 
     connect(toolEditDetails, SIGNAL(clicked()), this, SLOT(slotEditDetails()));
diff --git a/src/gis/trk/IScrOptTrk.ui b/src/gis/trk/IScrOptTrk.ui
index 0f6dab3..6a11db6 100644
--- a/src/gis/trk/IScrOptTrk.ui
+++ b/src/gis/trk/IScrOptTrk.ui
@@ -37,7 +37,7 @@
      <item>
       <widget class="QToolButton" name="toolEditDetails">
        <property name="toolTip">
-        <string>View details &amp; Edit properties of track.</string>
+        <string>View details and edit properties of track.</string>
        </property>
        <property name="text">
         <string>...</string>
@@ -65,7 +65,7 @@
      <item>
       <widget class="QToolButton" name="toolDelete">
        <property name="toolTip">
-        <string>Delete</string>
+        <string>Delete track from project.</string>
        </property>
        <property name="text">
         <string>...</string>
diff --git a/src/gis/trk/filter/CFilterNewDate.cpp b/src/gis/trk/filter/CFilterNewDate.cpp
index 7120324..59c46e0 100644
--- a/src/gis/trk/filter/CFilterNewDate.cpp
+++ b/src/gis/trk/filter/CFilterNewDate.cpp
@@ -25,6 +25,7 @@ CFilterNewDate::CFilterNewDate(CGisItemTrk &trk, QWidget *parent)
 {
     setupUi(this);
 
+    labelTimeZone->setText(QDateTime::currentDateTime().timeZone().abbreviation(QDateTime::currentDateTime()));
     dateTimeEdit->setDateTime(QDateTime::currentDateTime());
 
     connect(toolApply, SIGNAL(clicked()), this, SLOT(slotApply()));
diff --git a/src/gis/trk/filter/IFilterNewDate.ui b/src/gis/trk/filter/IFilterNewDate.ui
index 0d42f2c..63a7608 100644
--- a/src/gis/trk/filter/IFilterNewDate.ui
+++ b/src/gis/trk/filter/IFilterNewDate.ui
@@ -47,12 +47,22 @@
      </item>
      <item>
       <widget class="QDateTimeEdit" name="dateTimeEdit">
+       <property name="displayFormat">
+        <string>dd.MM.yy HH:mm:ss</string>
+       </property>
        <property name="calendarPopup">
         <bool>true</bool>
        </property>
       </widget>
      </item>
      <item>
+      <widget class="QLabel" name="labelTimeZone">
+       <property name="text">
+        <string>-</string>
+       </property>
+      </widget>
+     </item>
+     <item>
       <spacer name="horizontalSpacer">
        <property name="orientation">
         <enum>Qt::Horizontal</enum>
diff --git a/src/gis/trk/filter/filter.cpp b/src/gis/trk/filter/filter.cpp
index 587aa4e..2d483ae 100644
--- a/src/gis/trk/filter/filter.cpp
+++ b/src/gis/trk/filter/filter.cpp
@@ -288,7 +288,7 @@ void CGisItemTrk::filterObscureDate(int delta)
         QDateTime timestamp = timeStart;
         if(!timestamp.isValid())
         {
-            timestamp = QDateTime::currentDateTime();
+            timestamp = QDateTime::currentDateTime().toUTC();
         }
 
         for(int i = 0; i < trk.segs.size(); i++)
@@ -313,7 +313,7 @@ void CGisItemTrk::filterSpeed(qreal speed)
     QDateTime timestamp = timeStart;
     if(!timestamp.isValid())
     {
-        timestamp = QDateTime::currentDateTime();
+        timestamp = QDateTime::currentDateTime().toUTC();
     }
 
     for(int i = 0; i < trk.segs.size(); i++)
diff --git a/src/gis/wpt/CScrOptWpt.cpp b/src/gis/wpt/CScrOptWpt.cpp
index 98d9faa..bc75ab4 100644
--- a/src/gis/wpt/CScrOptWpt.cpp
+++ b/src/gis/wpt/CScrOptWpt.cpp
@@ -28,7 +28,7 @@
 #include <QtWidgets>
 
 CScrOptWpt::CScrOptWpt(CGisItemWpt *wpt, const QPoint& point, IMouse *parent)
-    : IScrOpt(parent->getCanvas())
+    : IScrOpt(parent)
 {
     key         = wpt->getKey();
 
diff --git a/src/gis/wpt/IScrOptWpt.ui b/src/gis/wpt/IScrOptWpt.ui
index e091f37..faaa94d 100644
--- a/src/gis/wpt/IScrOptWpt.ui
+++ b/src/gis/wpt/IScrOptWpt.ui
@@ -46,7 +46,7 @@
         <bool>true</bool>
        </property>
        <property name="toolTip">
-        <string><html><head/><body><p>View details &amp; Edit</p></body></html></string>
+        <string>View details and edit.</string>
        </property>
        <property name="text">
         <string>...</string>
@@ -74,7 +74,7 @@
      <item>
       <widget class="QToolButton" name="toolDelete">
        <property name="toolTip">
-        <string><html><head/><body><p>Delete</p></body></html></string>
+        <string>Delete waypoint from project.</string>
        </property>
        <property name="text">
         <string>...</string>
@@ -94,6 +94,9 @@
      </item>
      <item>
       <widget class="QToolButton" name="toolBubble">
+       <property name="toolTip">
+        <string>Show content as static bubble.</string>
+       </property>
        <property name="text">
         <string>...</string>
        </property>
@@ -109,7 +112,7 @@
      <item>
       <widget class="QToolButton" name="toolMove">
        <property name="toolTip">
-        <string><html><head/><body><p>Move waypoint to a new location.</p></body></html></string>
+        <string>Move waypoint to a new location.</string>
        </property>
        <property name="text">
         <string>...</string>
@@ -123,7 +126,7 @@
      <item>
       <widget class="QToolButton" name="toolProj">
        <property name="toolTip">
-        <string><html><head/><body><p>Clone waypoint and move clone a given distance and angle.</p></body></html></string>
+        <string>Clone waypoint and move clone a given distance and angle.</string>
        </property>
        <property name="text">
         <string>...</string>
diff --git a/src/grid/CGrid.cpp b/src/grid/CGrid.cpp
index 2529e21..51a5f87 100644
--- a/src/grid/CGrid.cpp
+++ b/src/grid/CGrid.cpp
@@ -40,6 +40,8 @@ CGrid::CGrid(CMapDraw *map)
 
 CGrid::~CGrid()
 {
+    pj_free(pjWGS84);
+    pj_free(pjGrid);
 }
 
 void CGrid::convertPos2Str(const QPointF& pos, QString& info)
diff --git a/src/helpers/CSelectCopyAction.cpp b/src/helpers/CSelectCopyAction.cpp
index ca98f27..576bbda 100644
--- a/src/helpers/CSelectCopyAction.cpp
+++ b/src/helpers/CSelectCopyAction.cpp
@@ -38,6 +38,8 @@ CSelectCopyAction::CSelectCopyAction(const IGisItem *src, const IGisItem *tar, Q
     connect(pushCopy, SIGNAL(clicked()), this, SLOT(slotSelectResult()));
     connect(pushSkip, SIGNAL(clicked()), this, SLOT(slotSelectResult()));
     connect(pushClone, SIGNAL(clicked()), this, SLOT(slotSelectResult()));
+
+    QApplication::setOverrideCursor(Qt::ArrowCursor);
 }
 
 CSelectCopyAction::CSelectCopyAction(const IGisProject * src, const IGisProject * tar, QWidget * parent)
@@ -57,10 +59,13 @@ CSelectCopyAction::CSelectCopyAction(const IGisProject * src, const IGisProject
 
     connect(pushCopy, SIGNAL(clicked()), this, SLOT(slotSelectResult()));
     connect(pushSkip, SIGNAL(clicked()), this, SLOT(slotSelectResult()));
+
+    QApplication::setOverrideCursor(Qt::ArrowCursor);
 }
 
 CSelectCopyAction::~CSelectCopyAction()
 {
+    QApplication::restoreOverrideCursor();
 }
 
 bool CSelectCopyAction::allOthersToo()
diff --git a/src/helpers/CSelectProjectDialog.cpp b/src/helpers/CSelectProjectDialog.cpp
index 589b8c3..7e82959 100644
--- a/src/helpers/CSelectProjectDialog.cpp
+++ b/src/helpers/CSelectProjectDialog.cpp
@@ -83,10 +83,13 @@ CSelectProjectDialog::CSelectProjectDialog(QString &key, QString &name, type_e&
     connect(radioDatabase, SIGNAL(toggled(bool)), this, SLOT(slotDatabase()));
 
     adjustSize();
+
+    QApplication::setOverrideCursor(Qt::ArrowCursor);
 }
 
 CSelectProjectDialog::~CSelectProjectDialog()
 {
+    QApplication::restoreOverrideCursor();
 }
 
 void CSelectProjectDialog::reject()
diff --git a/src/icons/32x32/A.png b/src/icons/32x32/A.png
new file mode 100644
index 0000000..c1ce654
Binary files /dev/null and b/src/icons/32x32/A.png differ
diff --git a/src/icons/32x32/AddArea.png b/src/icons/32x32/AddArea.png
index 7c0b909..8f7e408 100644
Binary files a/src/icons/32x32/AddArea.png and b/src/icons/32x32/AddArea.png differ
diff --git a/src/icons/32x32/AddRte.png b/src/icons/32x32/AddRte.png
new file mode 100644
index 0000000..7b9bc17
Binary files /dev/null and b/src/icons/32x32/AddRte.png differ
diff --git a/src/icons/32x32/AddTrk.png b/src/icons/32x32/AddTrk.png
index b855e2e..54bda7b 100644
Binary files a/src/icons/32x32/AddTrk.png and b/src/icons/32x32/AddTrk.png differ
diff --git a/src/icons/32x32/AddWpt.png b/src/icons/32x32/AddWpt.png
index 8b7016f..c32f708 100644
Binary files a/src/icons/32x32/AddWpt.png and b/src/icons/32x32/AddWpt.png differ
diff --git a/src/icons/32x32/CloneMapWorkspace.png b/src/icons/32x32/CloneMapWorkspace.png
new file mode 100644
index 0000000..2d1ee9c
Binary files /dev/null and b/src/icons/32x32/CloneMapWorkspace.png differ
diff --git a/src/icons/32x32/O.png b/src/icons/32x32/O.png
new file mode 100644
index 0000000..fba6c26
Binary files /dev/null and b/src/icons/32x32/O.png differ
diff --git a/src/icons/32x32/Route.png b/src/icons/32x32/Route.png
index f525532..31a3771 100644
Binary files a/src/icons/32x32/Route.png and b/src/icons/32x32/Route.png differ
diff --git a/src/icons/32x32/RouteSetup.png b/src/icons/32x32/RouteSetup.png
new file mode 100644
index 0000000..a78ffd4
Binary files /dev/null and b/src/icons/32x32/RouteSetup.png differ
diff --git a/src/icons/32x32/V.png b/src/icons/32x32/V.png
new file mode 100644
index 0000000..a389787
Binary files /dev/null and b/src/icons/32x32/V.png differ
diff --git a/src/icons/48x48/A.png b/src/icons/48x48/A.png
new file mode 100644
index 0000000..8438ecd
Binary files /dev/null and b/src/icons/48x48/A.png differ
diff --git a/src/icons/48x48/AddArea.png b/src/icons/48x48/AddArea.png
index b8a39e5..587175f 100644
Binary files a/src/icons/48x48/AddArea.png and b/src/icons/48x48/AddArea.png differ
diff --git a/src/icons/48x48/AddRte.png b/src/icons/48x48/AddRte.png
new file mode 100644
index 0000000..f32394f
Binary files /dev/null and b/src/icons/48x48/AddRte.png differ
diff --git a/src/icons/48x48/AddTrk.png b/src/icons/48x48/AddTrk.png
index 8c25f27..047dd97 100644
Binary files a/src/icons/48x48/AddTrk.png and b/src/icons/48x48/AddTrk.png differ
diff --git a/src/icons/48x48/AddWpt.png b/src/icons/48x48/AddWpt.png
index 89ad965..34aed72 100644
Binary files a/src/icons/48x48/AddWpt.png and b/src/icons/48x48/AddWpt.png differ
diff --git a/src/icons/48x48/CloneMapWorkspace.png b/src/icons/48x48/CloneMapWorkspace.png
new file mode 100644
index 0000000..d1c4f7e
Binary files /dev/null and b/src/icons/48x48/CloneMapWorkspace.png differ
diff --git a/src/icons/48x48/O.png b/src/icons/48x48/O.png
new file mode 100644
index 0000000..f263a2c
Binary files /dev/null and b/src/icons/48x48/O.png differ
diff --git a/src/icons/48x48/Route.png b/src/icons/48x48/Route.png
index 5adb498..ff58892 100644
Binary files a/src/icons/48x48/Route.png and b/src/icons/48x48/Route.png differ
diff --git a/src/icons/48x48/RouteSetup.png b/src/icons/48x48/RouteSetup.png
new file mode 100644
index 0000000..ea63ee0
Binary files /dev/null and b/src/icons/48x48/RouteSetup.png differ
diff --git a/src/icons/48x48/V.png b/src/icons/48x48/V.png
new file mode 100644
index 0000000..6b11a82
Binary files /dev/null and b/src/icons/48x48/V.png differ
diff --git a/src/icons/A.svg b/src/icons/A.svg
new file mode 100644
index 0000000..e0017cb
--- /dev/null
+++ b/src/icons/A.svg
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64px"
+   height="64px"
+   id="svg3513"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="A.svg">
+  <defs
+     id="defs3515" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.5"
+     inkscape:cx="32"
+     inkscape:cy="32"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1920"
+     inkscape:window-height="996"
+     inkscape:window-x="-2"
+     inkscape:window-y="-3"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata3518">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <text
+       xml:space="preserve"
+       style="font-size:40px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
+       x="24"
+       y="38.909092"
+       id="text3002"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3004"
+         x="24"
+         y="38.909092">A</tspan></text>
+  </g>
+</svg>
diff --git a/src/icons/AddArea.svg b/src/icons/AddArea.svg
index e214f48..ba6a608 100644
--- a/src/icons/AddArea.svg
+++ b/src/icons/AddArea.svg
@@ -15,7 +15,7 @@
    height="64px"
    id="svg3377"
    version="1.1"
-   inkscape:version="0.48.4 r9939"
+   inkscape:version="0.48.5 r10040"
    sodipodi:docname="AddArea.svg">
   <defs
      id="defs3379">
@@ -124,14 +124,14 @@
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
      inkscape:zoom="11"
-     inkscape:cx="4.0115391"
+     inkscape:cx="-8.4430064"
      inkscape:cy="27.46309"
      inkscape:current-layer="layer1"
      showgrid="true"
      inkscape:document-units="px"
      inkscape:grid-bbox="true"
      inkscape:window-width="1920"
-     inkscape:window-height="1012"
+     inkscape:window-height="996"
      inkscape:window-x="-2"
      inkscape:window-y="-3"
      inkscape:window-maximized="1">
@@ -147,7 +147,7 @@
         <dc:format>image/svg+xml</dc:format>
         <dc:type
            rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <dc:title></dc:title>
+        <dc:title />
       </cc:Work>
     </rdf:RDF>
   </metadata>
@@ -158,7 +158,7 @@
     <g
        id="g3801"
        style="fill:#ff0000"
-       transform="translate(28.545455,7.2743753)">
+       transform="translate(31.628111,7.2743753)">
       <path
          inkscape:connector-curvature="0"
          id="path3015"
@@ -206,8 +206,8 @@
       </g>
     </g>
     <path
-       style="fill:#000080;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.82368106;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
-       d="m 23.245105,49.356033 10.214288,9e-6 0,10.197539 8.747753,0 0,-10.197548 10.214278,0 0,-8.781223 -10.214278,0 0,-10.197548 -8.747746,0 0,10.197556 -10.214279,-8e-6 0,8.781223 z"
+       style="fill:#000080;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.54912072;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 36.19048,52.892495 6.809525,5e-6 0,6.798361 5.831837,0 0,-6.798366 6.809518,0 0,-5.854148 -6.809518,0 -6e-6,-6.798366 -5.831831,0 -5e-6,6.798371 -6.80952,-5e-6 0,5.854148 z"
        id="rect3117-7"
        inkscape:connector-curvature="0"
        inkscape:export-filename="/home/oeichler/Code/cpp/MapRoom/src/icons/16x16/add.png"
diff --git a/src/icons/AddRte.svg b/src/icons/AddRte.svg
new file mode 100644
index 0000000..f461f52
--- /dev/null
+++ b/src/icons/AddRte.svg
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   width="64"
+   height="67"
+   sodipodi:docname="AddRte.svg">
+  <metadata
+     id="metadata8">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs6" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="996"
+     id="namedview4"
+     showgrid="true"
+     inkscape:zoom="3.5223881"
+     inkscape:cx="51.937619"
+     inkscape:cy="45.751544"
+     inkscape:window-x="-2"
+     inkscape:window-y="-3"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg2">
+    <inkscape:grid
+       type="xygrid"
+       id="grid2982" />
+  </sodipodi:namedview>
+  <g
+     id="g3063"
+     transform="matrix(0.72727272,0,0,0.66666667,8.6363638,13.593741)">
+    <path
+       inkscape:connector-curvature="0"
+       id="path3036"
+       d="M 15,12 50,32 20,52"
+       style="fill:none;stroke:#ff0000;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    <path
+       transform="matrix(1.3333333,0,0,1.3333333,-1.6666667,-7.3333333)"
+       sodipodi:open="true"
+       sodipodi:end="6.2789689"
+       sodipodi:start="0"
+       d="M 20,14.5 C 20,18.642136 16.642136,22 12.5,22 8.3578644,22 5,18.642136 5,14.5 5,10.357864 8.3578644,7 12.5,7 c 4.129791,0 7.482521,3.338622 7.499933,7.468377"
+       sodipodi:ry="7.5"
+       sodipodi:rx="7.5"
+       sodipodi:cy="14.5"
+       sodipodi:cx="12.5"
+       id="path2984"
+       style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+       sodipodi:type="arc" />
+    <path
+       transform="matrix(1.3333333,0,0,1.3333333,33.333334,12.666667)"
+       sodipodi:open="true"
+       sodipodi:end="6.2789689"
+       sodipodi:start="0"
+       d="M 20,14.5 C 20,18.642136 16.642136,22 12.5,22 8.3578644,22 5,18.642136 5,14.5 5,10.357864 8.3578644,7 12.5,7 c 4.129791,0 7.482521,3.338622 7.499933,7.468377"
+       sodipodi:ry="7.5"
+       sodipodi:rx="7.5"
+       sodipodi:cy="14.5"
+       sodipodi:cx="12.5"
+       id="path2984-8"
+       style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+       sodipodi:type="arc" />
+    <path
+       transform="matrix(1.3333333,0,0,1.3333333,3.3333338,32.666667)"
+       sodipodi:open="true"
+       sodipodi:end="6.2789689"
+       sodipodi:start="0"
+       d="M 20,14.5 C 20,18.642136 16.642136,22 12.5,22 8.3578644,22 5,18.642136 5,14.5 5,10.357864 8.3578644,7 12.5,7 c 4.129791,0 7.482521,3.338622 7.499933,7.468377"
+       sodipodi:ry="7.5"
+       sodipodi:rx="7.5"
+       sodipodi:cy="14.5"
+       sodipodi:cx="12.5"
+       id="path2984-0"
+       style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+       sodipodi:type="arc" />
+  </g>
+  <path
+     style="fill:#000080;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.54912072;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+     d="m 32.547287,47.854148 6.809525,5e-6 0,6.798361 5.831837,0 0,-6.798366 6.809518,0 0,-5.854148 -6.809518,0 -6e-6,-6.798366 -5.831831,0 -5e-6,6.798371 -6.80952,-5e-6 0,5.854148 z"
+     id="rect3117-7"
+     inkscape:connector-curvature="0"
+     inkscape:export-filename="/home/oeichler/Code/cpp/MapRoom/src/icons/16x16/add.png"
+     inkscape:export-xdpi="75.913841"
+     inkscape:export-ydpi="75.913841" />
+</svg>
diff --git a/src/icons/AddTrk.svg b/src/icons/AddTrk.svg
index 3977714..a9b95ee 100644
--- a/src/icons/AddTrk.svg
+++ b/src/icons/AddTrk.svg
@@ -13,7 +13,7 @@
    height="64px"
    id="svg3377"
    version="1.1"
-   inkscape:version="0.48.4 r9939"
+   inkscape:version="0.48.5 r10040"
    sodipodi:docname="AddTrk.svg">
   <defs
      id="defs3379" />
@@ -25,7 +25,7 @@
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
      inkscape:zoom="5.5"
-     inkscape:cx="-20.727273"
+     inkscape:cx="-45.636364"
      inkscape:cy="32"
      inkscape:current-layer="layer1"
      showgrid="true"
@@ -181,8 +181,8 @@
       </g>
     </g>
     <path
-       style="fill:#000080;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.94174314;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
-       d="m 17.412331,39.012396 11.673383,9e-6 0,11.664162 9.997357,0 0,-11.664171 11.673372,0 0,-10.044146 -11.673372,0 -10e-6,-11.66417 -9.997347,0 -1.1e-5,11.664179 -11.673372,-9e-6 0,10.044146 z"
+       style="fill:#000080;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.54912072;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 31.501877,44.074513 6.809525,5e-6 0,6.798361 5.831837,0 0,-6.798366 6.809518,0 0,-5.854148 -6.809518,0 -6e-6,-6.798366 -5.831831,0 -5e-6,6.798371 -6.80952,-5e-6 0,5.854148 z"
        id="rect3117-7"
        inkscape:connector-curvature="0"
        inkscape:export-filename="/home/oeichler/Code/cpp/MapRoom/src/icons/16x16/add.png"
diff --git a/src/icons/AddWpt.svg b/src/icons/AddWpt.svg
index 9d88b08..6f79ca4 100644
--- a/src/icons/AddWpt.svg
+++ b/src/icons/AddWpt.svg
@@ -13,8 +13,8 @@
    height="64px"
    id="svg3513"
    version="1.1"
-   inkscape:version="0.48.4 r9939"
-   sodipodi:docname="Add.svg">
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="AddWpt.svg">
   <defs
      id="defs3515" />
   <sodipodi:namedview
@@ -25,7 +25,7 @@
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
      inkscape:zoom="5.5"
-     inkscape:cx="32"
+     inkscape:cx="7.0909091"
      inkscape:cy="32"
      inkscape:current-layer="layer1"
      showgrid="true"
@@ -44,7 +44,7 @@
         <dc:format>image/svg+xml</dc:format>
         <dc:type
            rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <dc:title></dc:title>
+        <dc:title />
       </cc:Work>
     </rdf:RDF>
   </metadata>
@@ -52,31 +52,34 @@
      id="layer1"
      inkscape:label="Layer 1"
      inkscape:groupmode="layer">
-    <rect
-       style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:none"
-       id="rect2996"
-       width="40"
-       height="40"
-       x="10.181817"
-       y="12.909091" />
     <g
-       id="g2992"
-       transform="translate(7.6363638,-19.818182)">
-      <path
-         inkscape:connector-curvature="0"
-         id="path3763"
-         d="m 10.447631,33.891728 25.339695,10.78737 -28.5071566,10.7873 3.1674616,-21.57467"
-         style="fill:#ff0000;stroke:#ff0000;stroke-width:1.34993112;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
-      <path
-         sodipodi:nodetypes="cccc"
-         inkscape:connector-curvature="0"
-         id="path3761"
-         d="m 3.8972165,72.422998 3.6091739,-39.39145 3.6091736,0 z"
-         style="fill:#000000;stroke:#000000;stroke-width:0.71901649px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
+       id="g3057">
+      <rect
+         y="12.909091"
+         x="10.181817"
+         height="40"
+         width="40"
+         id="rect2996"
+         style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+      <g
+         transform="translate(7.6363638,-19.818182)"
+         id="g2992">
+        <path
+           style="fill:#ff0000;stroke:#ff0000;stroke-width:1.34993112;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+           d="m 10.447631,33.891728 25.339695,10.78737 -28.5071566,10.7873 3.1674616,-21.57467"
+           id="path3763"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#000000;stroke:#000000;stroke-width:0.71901649px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+           d="m 3.8972165,72.422998 3.6091739,-39.39145 3.6091736,0 z"
+           id="path3761"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccc" />
+      </g>
     </g>
     <path
-       style="fill:#000080;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.82368112;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
-       d="m 19.066505,42.356031 10.214286,8e-6 0,10.197541 8.747755,0 0,-10.197549 10.214278,0 0,-8.781221 -10.214278,0 -8e-6,-10.197549 -8.747747,0 -8e-6,10.197557 -10.214278,-8e-6 0,8.781221 z"
+       style="fill:#000080;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.54912072;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 30.456378,45.891398 6.809525,5e-6 0,6.798361 5.831836,0 0,-6.798366 6.809518,0 0,-5.854147 -6.809518,0 -6e-6,-6.798366 -5.83183,0 -5e-6,6.798371 -6.80952,-5e-6 0,5.854147 z"
        id="rect3117-7"
        inkscape:connector-curvature="0"
        inkscape:export-filename="/home/oeichler/Code/cpp/MapRoom/src/icons/16x16/add.png"
diff --git a/src/icons/CloneMapWorkspace.svg b/src/icons/CloneMapWorkspace.svg
new file mode 100644
index 0000000..45390d3
--- /dev/null
+++ b/src/icons/CloneMapWorkspace.svg
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64px"
+   height="64px"
+   id="svg3513"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="CloneMapWorkspace.svg">
+  <defs
+     id="defs3515" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.9445436"
+     inkscape:cx="149.76191"
+     inkscape:cy="147.00891"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1920"
+     inkscape:window-height="1012"
+     inkscape:window-x="-2"
+     inkscape:window-y="-3"
+     inkscape:window-maximized="1">
+    <inkscape:grid
+       type="xygrid"
+       id="grid2991" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata3518">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <g
+       id="g3020"
+       transform="matrix(0.7,0,0,0.7,2.5558498,-2.7264186)">
+      <path
+         inkscape:connector-curvature="0"
+         d="m 8.1859729,30.263745 c 5.9957181,9.867863 18.7209451,12.923577 28.4225791,6.82512 2.822568,-1.774263 5.18323,-4.214229 6.882092,-7.113257 M 8.4512572,29.433391 c 5.9957188,-9.867863 18.7209448,-12.923577 28.4225788,-6.82512 2.822568,1.774263 5.18323,4.214228 6.882092,7.113257"
+         style="fill:#ffffff;stroke:#ffffff;stroke-width:4.43720007;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         id="path4129-7-3-9" />
+      <path
+         inkscape:connector-curvature="0"
+         d="m 8.1859718,30.263745 c 5.9957182,9.867863 18.7209462,12.923577 28.4225802,6.82512 2.822568,-1.774263 5.18323,-4.214229 6.882092,-7.113257 M 8.4512562,29.433391 c 5.9957188,-9.867863 18.7209458,-12.923577 28.4225798,-6.82512 2.822568,1.774263 5.18323,4.214228 6.882092,7.113257"
+         style="fill:#ffffff;stroke:#000080;stroke-width:2.03560519;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
+         id="path4129-7-3" />
+      <path
+         transform="matrix(0.89711754,0,0,0.95224119,-310.44813,-0.96816237)"
+         sodipodi:type="arc"
+         style="fill:#000080;stroke:#000080;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         id="path4149-5"
+         sodipodi:cx="375"
+         sodipodi:cy="32.362183"
+         sodipodi:rx="5"
+         sodipodi:ry="5"
+         d="m 379.43534,30.05399 c 1.27478,2.449571 0.32242,5.468754 -2.12715,6.743533 -2.44957,1.27478 -5.46875,0.322423 -6.74353,-2.127148 -1.27478,-2.449571 -0.32242,-5.468754 2.12715,-6.743533 2.35027,-1.223101 5.24659,-0.40052 6.60312,1.875344"
+         sodipodi:start="5.8033439"
+         sodipodi:end="12.02886"
+         sodipodi:open="true" />
+    </g>
+    <g
+       id="g3020-0"
+       transform="matrix(0.7,0,0,0.7,9.1231971,4.812505)">
+      <path
+         inkscape:connector-curvature="0"
+         d="m 8.1859729,30.263745 c 5.9957181,9.867863 18.7209451,12.923577 28.4225791,6.82512 2.822568,-1.774263 5.18323,-4.214229 6.882092,-7.113257 M 8.4512572,29.433391 c 5.9957188,-9.867863 18.7209448,-12.923577 28.4225788,-6.82512 2.822568,1.774263 5.18323,4.214228 6.882092,7.113257"
+         style="fill:#ffffff;stroke:#ffffff;stroke-width:4.43720007;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         id="path4129-7-3-9-0" />
+      <path
+         inkscape:connector-curvature="0"
+         d="m 8.1859718,30.263745 c 5.9957182,9.867863 18.7209462,12.923577 28.4225802,6.82512 2.822568,-1.774263 5.18323,-4.214229 6.882092,-7.113257 M 8.4512562,29.433391 c 5.9957188,-9.867863 18.7209458,-12.923577 28.4225798,-6.82512 2.822568,1.774263 5.18323,4.214228 6.882092,7.113257"
+         style="fill:#ffffff;stroke:#000080;stroke-width:2.03560519;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
+         id="path4129-7-3-7" />
+      <path
+         transform="matrix(0.89711754,0,0,0.95224119,-310.44813,-0.96816237)"
+         sodipodi:type="arc"
+         style="fill:#000080;stroke:#000080;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         id="path4149-5-9"
+         sodipodi:cx="375"
+         sodipodi:cy="32.362183"
+         sodipodi:rx="5"
+         sodipodi:ry="5"
+         d="m 379.43534,30.05399 c 1.27478,2.449571 0.32242,5.468754 -2.12715,6.743533 -2.44957,1.27478 -5.46875,0.322423 -6.74353,-2.127148 -1.27478,-2.449571 -0.32242,-5.468754 2.12715,-6.743533 2.35027,-1.223101 5.24659,-0.40052 6.60312,1.875344"
+         sodipodi:start="5.8033439"
+         sodipodi:end="12.02886"
+         sodipodi:open="true" />
+    </g>
+    <g
+       id="g3949"
+       transform="matrix(1.1800758,0,0,1.1715736,-203.45769,-134.78777)">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3161-9"
+         d="m 195.375,147.36218 5,0 0,5 5,0 0,-5 5,0 0,-5 -5,0 0,-5 -5,0 0,5 -5,0 z"
+         style="fill:#ffffff;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3161"
+         d="m 195.375,150.86278 5,0 0,5 5,0 0,-5 5,0 0,-5 -5,0 0,-5 -5,0 0,5 -5,0 z"
+         style="fill:#88aa00;stroke:#445500;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
+    </g>
+    <rect
+       y="9.8485737"
+       x="8.5113773"
+       height="40"
+       width="37.47588"
+       id="rect4156-1"
+       style="fill:none;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+  </g>
+</svg>
diff --git a/src/icons/O.svg b/src/icons/O.svg
new file mode 100644
index 0000000..cdb3e0e
--- /dev/null
+++ b/src/icons/O.svg
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64px"
+   height="64px"
+   id="svg3513"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="O.svg">
+  <defs
+     id="defs3515" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.5"
+     inkscape:cx="32"
+     inkscape:cy="32"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1920"
+     inkscape:window-height="996"
+     inkscape:window-x="-2"
+     inkscape:window-y="-3"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata3518">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <text
+       xml:space="preserve"
+       style="font-size:40px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
+       x="24"
+       y="38.909092"
+       id="text3002"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3004"
+         x="24"
+         y="38.909092">O</tspan></text>
+  </g>
+</svg>
diff --git a/src/icons/Route.svg b/src/icons/Route.svg
index 1340542..5870a62 100644
--- a/src/icons/Route.svg
+++ b/src/icons/Route.svg
@@ -7,15 +7,14 @@
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
-   xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
    id="svg2"
    version="1.1"
-   inkscape:version="0.48.4 r9939"
+   inkscape:version="0.48.5 r10040"
    width="64"
    height="67"
-   sodipodi:docname="220px-ROUTE_66_sign.png">
+   sodipodi:docname="Route.svg">
   <metadata
      id="metadata8">
     <rdf:RDF>
@@ -24,7 +23,7 @@
         <dc:format>image/svg+xml</dc:format>
         <dc:type
            rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <dc:title></dc:title>
+        <dc:title />
       </cc:Work>
     </rdf:RDF>
   </metadata>
@@ -39,129 +38,63 @@
      guidetolerance="10"
      inkscape:pageopacity="0"
      inkscape:pageshadow="2"
-     inkscape:window-width="657"
-     inkscape:window-height="480"
+     inkscape:window-width="1920"
+     inkscape:window-height="996"
      id="namedview4"
-     showgrid="false"
+     showgrid="true"
      inkscape:zoom="3.5223881"
-     inkscape:cx="32"
+     inkscape:cx="-33.154661"
      inkscape:cy="33.5"
-     inkscape:window-x="0"
-     inkscape:window-y="0"
-     inkscape:window-maximized="0"
-     inkscape:current-layer="svg2" />
-  <image
-     width="64"
-     height="67"
-     xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABDCAYAAAAs/QNwAAAABHNCSVQICAgIfAhkiAAAF1hJREFU
-eJzdW3l4FFW2/92q6s7GHkAiQpBNkJFFBJRlRB1cWcQRQR1GwB1BGEUFF0BBARVQEVkUUVSQMKK4
-gqA8RJBNCDsxYSdkIwkhSy9VdX/vj6rqdHe6k6B8vjdzvq++7lruueece/a6BZwHkAw/185nfDge
-kq6ga+ofwCMAwOv1njeO85osaMI3GSQN5164gKIQG47za5JTSCrhz1ZFi/Ncbm5ug7y8PJKM+z28
-VQlhzC/0+w2SlCRNkk/b1xWSajAjQeMVkhrJWPu8A8k9um7SAcOQpSTfJ3mR/UysoxXhwrPncdn/
-XzYMSZKmlNJ84IEHmnz99deuqoR4vgIQACCl+arPZzA1NUv27fsJSZo+n0HTlCUkl5PsSrJxhPHJ
-JK8hOV3XzWybcf+mTSfYtetC3nnncmZnF5sk6fUa1HXzIMnZJLtEoacLyQ8MQx6WUtLnM8whQ1aQ
-pDRN7nGEfqGYBwDs3p2aStKbkZFPYAL/9rcPCYzi+vVHWVbmN0l6nNU0TRlyBEHZ0aOFxurV6axb
-dxrr1p3Ot9/eyrFjvyMwgW3azGF6ej7z8kp1kqXBA1es+De/+GJVML4yXTeNd9/9lcDT7Np1IZs2
-nUWSxbpuHgqm/XczTlLYR6bPZ+jp6fkEJjE1NYter8HiYh9drpfocr3IOnWmcerUDfzsswMMh2XL
-9nLy5PUEJlJRJjMhYSo9Hj1EOH6/wS1bThKYQGASgWc5a9Zmbt+eWQHfpEnr2aLFGwQmsX37d1hQ
-UEaS7N79PTZpMoskDZKnCwrKHB6i8imqWHkNwObSUn/n9PQCpVOnN7F791i0b38RAEBKQlEESkv9
-2LYtE//zP8ewceNxnDp1DocPF0LKbDRs2Bxt29bHDTc0x1//mowuXRojPt4FKQkhBIQon0/YJ3l5
-ZUhLO4Nt2zKxZk0Gdu7MwpkzhwG48de/XgmSmDHjRrRpk4i6deMgpcWgogj06bMEp08XY//+x0Dy
-hKIoybYvMR38Va580P+ZJMv27MkhMI6bN5+g329WWBHDkPR49ArXw8Hj0Wk7rErBMEz6fEalz5SW
-+mkYFWkhydtu+4QtW75JkmU+n3EIAPbv318197TV3v6/gKS01P55bt+eyZISf5XERwIprePPhN69
-F7NRo9dIsvTIkWPHSSqXXnpppeYQLIglpaV+7t2bQ2AiDxzIrfbEUobadTiEOcWIUNkzhiGp6yb9
-fiPkCA6pDg29ey9ms2azncvLI/HqrHbA/kjO8/mMR/buzWWXLm+IXbueQMeOjUIG+XwmVq48gClT
-NsARqJREkya1sWrV3XC7VbhcCsaM+Q4ff7wHBQVnAAj06NEGCxb0RevWiXC5VCQlvY5Bg9ph9uyb
-ICWxfPl+PPfcD5g16ybMn78DmZnnoOsSAGxfo2POnFuQmpqN06eLYRjWPZdLRatW9TBuXI+AT3H8
-U79+S5GRUYCDB0fBNOV8TVMfDeZZY6jNzwXwUEZGAbp0eUts3ToGrVsnRjSV4mI/jh07i8TE+ABx
-x46dRefO83Ho0Ghs2HAMb721FQDQpMnFME2JrVtPoXv3RSgqmgAAyM4uRG5uKUiABIqLfThxogh7
-9+ZAVQV++y0fpqnD7Y6BaRKmWYQtW07hyJFC/PDDURQWnrXXUMM11yRj3LgeARoVxZLEV1/dg1tu
-+RhDhqzAp58Oesg0pVRV5TGHj+DsaomumzxwIJeKMpn79uXQ643s2DwenfPnbycwkadPFwfUD5hI
-4En7/5MEJnHz5hOB+127LiTwAhcu3GE/M56DBi2nrpvUdZPbt2cSeIYTJqwNzPXEE6sJTGBa2pnA
-teuv/4DA01WakmNOum4SmMTXX9/sXF7iCEABoJB0A7hL0xRj+PAv0Lt3M7Rr1xAxMVXVOkT9+nHQ
-NAXFxX4oigLA66wBAC+uuaYJNE0BCWzd+iAAD+bN2xHA4HJZ9YsQQKQoZam5guPHz8LnMwMhD5BV
-0FauCaoqsH//Yxg3bjHOnfOZUvIum2dFE0JIAH6SNxiG/HnLlgchxHhs356JK69MgqpGzyhjYlxw
-u58EoAKQSEhogK1bJ9l3BYLTjGDmDMMMMLF+/TFomhKw53AQAlAUF3bvzkGvXskBX1WjRl0IMQqO
-CbRq1RxpaaMrCNE0JQxDol27GdiyZSJq1YpRAXQXQvgBK9FxYIemKXMAPJaSMlTp2nUhyBcrEy4M
-Q2LAgG5YteogWrdugLS00UGMWEKpCETduuVFm9tdXsFGjlAWR6oayllJSRk+//wxlJT4oaoKGjRI
-iKhBqqpg7NjVuPjiJHTrdokPwGIAe5z7wcvrE0I8TuL0oEHtcMUVjbBgwQ6YZnRVI4GGDRMwcmQ3
-HDt2Fv36LYWmWSiHDesKwI3Nm0/C49FBAmPHrgbgxn33dQgII9hrO0zKoCnLtSUcdNx+e1vcc097
-DBnyF9xwQ/MI9BFnz3rx9tvfIjPzSZCMEUI8CsBLu8JVwga4hMAAkly8+HaMGvUtVFWJuDJCCGia
-gpgYDXPn3oYmTWrhm29+w3ffpcMwJN5++1YAJvr3X4p//GMlBgxYhkWLduKyyy7GiBFXAgA6dWqB
-vLwyDB68AgsX/oprr10MQMW//nUNpCR03cSrr94YCGkOqKoCTUvA4MEr8Pe/L8fgwf/G5MnrK9Bp
-msScOVvRvXsnmCYhhOjH8iaOAJAUEIBtW7oQYqcQIr9z5yTZqlUiPvpodwXVEkKgZk03kpNro149
-S503b34AzZvXw+23f4r8/DIkJLixfftjaNAgAStXHsRPPx3Dddddig0bhkFKQkritdf6IDExDikp
-v2L06E8hJXD//d3QsGECFEVACAGfz0CzZnVQq1ZMwP4bNUpAq1b1cOBAHtLT85GRUYBTp85VWCRN
-U5CSsh/z5vWVtgB3AKBVgwghhOhdQWXs3ys8Hp0pKfvYsOGrdnYVPdREuxee9+u6GZIpRqoLLlTK
-7MwDPORcWhUmHwXAXRWkxvJaIJWkH3g2atHx/x0++WQPhw373DmNYWhprAAYVCHQCyFIq5uyAsDU
-Xr1aQtOehuXV/1PAYdKN99+/U3o8uh4f7/aRFEEpPwHkR8t0JICZAKb27dsKR48WolWrxD/WYfkT
-wSFzw4Yj6NOnOV0utSj8GSEEAfwYBYGFQddN5uWVEhhDsrys/U84SLJ27Wk8dqzQ4/MZXzFKjzDi
-xYqdE2Ffr/5hmhJCACUlPjjx/kIcum6G4I90kITHo6OkxO+kzoGqt1oCqPhgNVpJIeOBoiIfLr54
-Jm655eMIAj1/cGqANWsyIMS4QMIVCYQAYmM1uFwKQtPxinRU2Tq24mdMtQkliezsYtSv/wJyc0uw
-adNJjBr1LUzzj/kPRREYPfpb9O+/FAkJ9TBw4KdBhVEo2HEeMTGqk11GTWejCUCQvFnTFGzceALD
-hnWrNqEFBV5cfPFUCFHDzr6AuXM3QFVFVIKrAp/PwPLl+/D2278AsJqwX3yxE5mZFZOfYFAUBadO
-ndMAdBBCSNohPuSZKGMFgHsB6Js2HUezZnWqJFLXrZy9fv0X4XbXCEpLrTmnTv0pJJ09H0hPL8CQ
-IR9BiPJQ7HLVRM+e71c6buzYbvjmm99UTVOahhBTGdBujErpJEJjmJVVXGmX1sm6EhOnU1Em2339
-SRRiMoHnuXDhr78rkSlvtEyiy/VSCN527eYGIlM0yMsrpdv9knN6KwBMnjw5hF8tnHkAQghBXTc7
-HD9+FkLURa1aMZX2BYQQmDhxPQoLvSFqThLbtj2CDh0aRR1bGWiagtat3wJQrmEA0LJlXezbN9Ke
-O/r4+vXjUatWDE6fLjaSkmp8CUALF0AIV7bzIMkcTVPkM8+sxVNPdUd8vKtCPe6AlMTBg3mYMmVt
-mI0b2LnzYXTp0jik5q8u+P0mUlOzkZ5+JnDNWgQvDh0aHbWBEgymKfH4490wZsx3mpRUc3JyWpWU
-lIR49BCuSMYAaADgeHGxX6lVazzIWSFd40jQseN8pKWdgddr2Fck7rzzL1ixomKtcT6gKJMBiKCw
-bKC4eCJq1HCfFx4hXgA5BaYpt2maGuLRwzXAB2ClaVIZOPBTTJhwm514RGd+9eoM7N59PMC8pilI
-TEzAihV3RenwVA1SEu+8s73CnoNhw65CQsL5MW+N64wRI1ZBVZWuJC9h0GaM4AxJBdBBSv5q1eIP
-g1wQFamjFfXrz0BRkS9IJXX8/PPDuPrqSyr1G9HxWnbdtOksZGWVwDAkFEUgPt6F4uJnzxufYUjk
-5JSiSZOZKCgY709IcH/udqtDHPrDKRylKMLbsuVbWLTokRDHEw5CCKxbdwT5+SUh9jhyZHf06NG0
-AvNer1GtPEAIICOjACdPZgfwCgHMnHkTiop88HqNwFEdP6BpCho3rok+fVpg7drDbkURg0PmA8pX
-0+83mJNTyiZNXhMFBc+hdu2YSmN3584LsHPnaQDCzsGBn38ege3bT2P37mxkZBRAVQXi4ly44462
-GDLkCtSsWbUKDxiwDF9+eRDlFuqBz/cK5s/fgZgYS3t9PhO33toKLVvWs980R051AUsLNE2BEBNB
-vgQSixRFPECyqXCYJzkawFuvv74ZX32Vhg0bhkclUErC4zFQo8aLCIukAHTExMTBNGWQ/Vq9eb/f
-g2nTbsXTT/eIKFinVVaz5ivw+8vfAVj0+RATExfwK1a7zAfAg3XrRqJnz2S43WrEsOiYVePGM7Fi
-xV1G166NszRNSUZwFCW5C8DlQjzhzs9/GXXqxEZdfa/XwKef7sNDD30ZeHdXfZBo0aI+0tJGWTYY
-NIffb2L//lxceeV8VLcAszTPRL16NZCf/wxMU0b1PUuX7sXOnVly6tTrGRur1QTgV2htYHKRaAZA
-BWKq9LSxsRpSUvb9ztxeweHD+ejZ8/0KAna7VXz//eHzwub477NnvYiNnQpVVeDzGRGfvfnmlkhJ
-2afExmqqEMIDQFFgGVqClLLO3r05anx8DbhcSqUZFmA5qkhhzipT/QDKgg5P2KoI7NmTg+ef/6HC
-+KNHCyPOZ40Px1seop02uhAvRH2lV69eHE6ePAAAIPmeEEJXYDXQhGEQn312EB07Ngq0pCuD9PSj
-ETSAMAwdKSn3gnw1cOTmTqwg0LIyHS+/vAbZ2SUhglywYD0qqj9hmjpWrfpnCN6xY3uALI9UFj0q
-FizYEdU0k5LaOH/PAYAihDABTAEQeMlZFaxenQEgfE+ijrlz+4KcgkGD2gUcGknUr58AXZ+IG29s
-ETIiNrYWnnlmbdjbp3D7lRg/vhfIKejfv00Ar5TE7Nk3o7DwWZQ3QQGXS8GiRbvsZkhFsPsSXLRo
-0b+CZ/MCQG5uKWbOvLFKAfj9oTbmdqtITm6AkSO7hGxYcjTJWf01a4aGvHA1DImNG4+HdXfKhWGZ
-oopp0/4WEJKD1/EfLpeKhQv7B8bousT27fui0l6zphsHDhQwLs5awLBU2IqvVYEM0y6/X8fDD3cO
-EBgNfD4Dw4d3sjwPLAEcPXrCJtzEpk0nAMQHMePFe+/1A4Conj0+XsN993UEUBp0Nfpr/dJSHZdf
-Xk+55557XgLKBaAAlpN47bVNUQc7UNE9GGjbtkGV41RVwbXXJkPXg83MSctFYK9A0EwoKancJIUQ
-drVZ9cI5NNiQAFibIxQAswDC6zWq1bVp2rQ2glVVUWLw7be/VVn8+P0mfvrpONzu4IrUIlzTBLp2
-bYzyDRaAFTIjRwUHQl/0OBA9N8nMDITZ2s4oAeCcpim4++4rsGXLKZgmK43xnTolIVjlhAC++CIN
-QiBqfm6aRHy8C88992PgGU1T0Lx5soMFAFCjRr3AGFV1Ye7cbQAim6bjZCdMWAdNqwXAMsHExKSI
-NOzYcRqXXNLCplk8SNLlhMEyVVXOtm9/ken1ZkNKWWWSc/PN3QLOyzSJwkIPhJgAj0eP+HxpqR8N
-GrwaUhSpqoIePZrCMGTArGbNugmOVzdNCdOUaNx4ZqAGCAZFEdi48QSmT/8+IFS3W8X993eKmAwt
-WZKK+++/Unq9hklra70MToWXABjap88S9O9/GUaPjt4J1nUTe/fm4qqrFobU60IAMTEa7rijLW64
-oTlGjOiEHTtO4/nnf8SaNRk2Y8Emlg9yTuDMCW8xMVMC5zZ1qF07Du3bX4R//rMDpLQ2PkyfvhGF
-hSUQwhVERykyMyeiUaMaAXMmLbyJia/im2/uMbp1u8SpBRAsgIt8PjM7O7sYzZpNBzk9qgAc6Ndv
-Kb7++rcQxqzCRQIwYNmzBiDOKbgCggKAlJS70Ldva8TGhnrtN9/cgrFjvwRQnpI7zEjpOEUBTXOH
-mJzLpeDDDwfi7ruvCMFHEidPnkNy8gyQrwDAB0KI4YDtOeyKMCcmRj2VnFzHrF27Nr76Kq3SQoe0
-9uBdd92lAPTgjZa2MFwAasJJmBzmFUWA9OPhh6/CnXdeXoF5ABgz5mqMGHF1SLHkaIeF1wVAC+kX
-AAYuu6w+hgy5ogI+IQR69lyElSuHOrwOD9DjPJCSkuJ64403JgBQV68eiv7934yaTZVPCnz//VC8
-887Aar85ltKPDz8cjHnz+lb63Lx5t+HHH++rVsFFSjzwQFfs3Tuywj2/38SuXVnIzi7F7be38ZNY
-EcKHhaC87pZS/iqEuPK++z7Hli2nkJY2usqmKACUlPgxbNgX+OyzHbBepRFxcXHweErtaXx48cV+
-ePzxbqhTJ7ZKphzQdRMjR36D997bZuMJ1kofbrqpA55//lr07Nk0UPc7YJrWxishnsDRoxPRrFkd
-q+dv7RMIlazdgHRLyVj7RYI/Lm4Kx4+3dm1G2zXqQPA2+rVrD3PdusN89NGvmZqaxdTUrMC94E3N
-1YHgbTQ//HCEv/xykr/8cpIbNx4PbMaOtLla102apiTwLN96awt9PsMkOYJW+V+51Elear/tMWvX
-foV16047L6Kdra9er0HDkNX6RqC6eA2j/Ajeb+SAc+3kySICz/Kdd7Y5Ajpapbox9Ouwlg7SAQOW
-ERjPdesOBwiJNPn/FUjJkH1MAwcuIzCRH3yQSlrfHv1m81T19wIsF4BC8vLdu/eQpCcrq5h16kxj
-gwYz+PLLPzEvL+SbJnq9Oj0enX6/GdCAC81kuWbpFb5QWbp0D3v0WETgET799PfMyio27HHrHOYj
-8VupZ+vevbvYtGnTpQCX6Lrs4XKpxg8/HFGWLdunLF++DyUlx9Cr19Xo1SsZnTolwe1W0bZtfcTG
-atA0BUlJNUPwGYa0nVLV9UZwWe3AiRNFUFWrm6TrEqtXZ+DQoTysX78NrVq1wYMPdsZTT/UwTZMq
-gDJVFXOEEONt5hlp3iopsQdrANoASJWSUkpqThr87ru/wjAklizZjUOHzkDXJUpLnWTFBGAiKSkR
-Q4e2x5Qp10PTlGoVXB6PjtzcMsyZsxVvvLEFpqlDCBWapqBWrVh07NgIN97YHN26NcG11yYHhKYo
-QgcwWQjxCknVbvj8MQi2G5K1Sf5dSq4O8wNlJL0kfXl5JUZRkVcvKvJwz55sbt58koMHpxAYy8TE
-6ezde3FgULgH//nnE+zceQGBFxgXN4XDh3/O9PR8ZmaeMwsLPYaU9NvzBAZKKb1S8k2Sl9PeCkvb
-3lnN/KRaQrAPNdieSF5GshXJl0g+S3Lud9+t2aXr5pZDh9ICtmuDb8+eHHPSpPUEHmC3bu+yqMgb
-CLGdOy9gjRovc8aMn5mfX6aT1EnS5zPo95uFum6mmqb8iORTJO8l2TmMRjcv1Bej5yEY1T5iaX0b
-HOnb4XiS/yB51IrP1sINHbqSwDPctSuLwFMcOfJrkjS9Xp1+v3EkPT19Dck7I+CLtZnVLugqXwgg
-iXvvvRdSSvz4448RiZs9e/ZSwzDo9xtyw4ZjBF7gkiWppPXFJ0kmMOxz+iAN/NN4ueBAUuzcudP5
-IrwByXMky5xESUquse8p0cLWfw2w/NP4d21HONM+/+9mPBwcp/WnOy8b/hcVKJnACudeyAAAAABJ
-RU5ErkJggg==
-"
-     id="image10"
-     x="0"
-     y="0" />
+     inkscape:window-x="-2"
+     inkscape:window-y="-3"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg2">
+    <inkscape:grid
+       type="xygrid"
+       id="grid2982" />
+  </sodipodi:namedview>
+  <path
+     style="fill:none;stroke:#000080;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+     d="M 15,12 50,32 20,52"
+     id="path3036"
+     inkscape:connector-curvature="0" />
+  <path
+     sodipodi:type="arc"
+     style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+     id="path2984"
+     sodipodi:cx="12.5"
+     sodipodi:cy="14.5"
+     sodipodi:rx="7.5"
+     sodipodi:ry="7.5"
+     d="m 20,14.5 a 7.5,7.5 0 1 1 -6.7e-5,-0.03162"
+     sodipodi:start="0"
+     sodipodi:end="6.2789689"
+     sodipodi:open="true"
+     transform="matrix(1.3333333,0,0,1.3333333,-1.6666667,-7.3333333)" />
+  <path
+     sodipodi:type="arc"
+     style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+     id="path2984-8"
+     sodipodi:cx="12.5"
+     sodipodi:cy="14.5"
+     sodipodi:rx="7.5"
+     sodipodi:ry="7.5"
+     d="m 20,14.5 a 7.5,7.5 0 1 1 -6.7e-5,-0.03162"
+     sodipodi:start="0"
+     sodipodi:end="6.2789689"
+     sodipodi:open="true"
+     transform="matrix(1.3333333,0,0,1.3333333,33.333334,12.666667)" />
+  <path
+     sodipodi:type="arc"
+     style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+     id="path2984-0"
+     sodipodi:cx="12.5"
+     sodipodi:cy="14.5"
+     sodipodi:rx="7.5"
+     sodipodi:ry="7.5"
+     d="m 20,14.5 a 7.5,7.5 0 1 1 -6.7e-5,-0.03162"
+     sodipodi:start="0"
+     sodipodi:end="6.2789689"
+     sodipodi:open="true"
+     transform="matrix(1.3333333,0,0,1.3333333,3.3333338,32.666667)" />
 </svg>
diff --git a/src/icons/RouteSetup.svg b/src/icons/RouteSetup.svg
new file mode 100644
index 0000000..1e88422
--- /dev/null
+++ b/src/icons/RouteSetup.svg
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   width="64"
+   height="67"
+   sodipodi:docname="RouteSetup.svg">
+  <metadata
+     id="metadata8">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs6" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1012"
+     id="namedview4"
+     showgrid="true"
+     inkscape:zoom="3.5223881"
+     inkscape:cx="-40.897126"
+     inkscape:cy="45.751545"
+     inkscape:window-x="-2"
+     inkscape:window-y="-3"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg2">
+    <inkscape:grid
+       type="xygrid"
+       id="grid2982" />
+  </sodipodi:namedview>
+  <g
+     id="g3759"
+     transform="matrix(0.54545454,0,0,0.5,2.6140215,1.0000001)">
+    <path
+       inkscape:connector-curvature="0"
+       id="path3036"
+       d="M 15,12 50,32 20,52"
+       style="fill:none;stroke:#000080;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    <path
+       transform="matrix(1.3333333,0,0,1.3333333,-1.6666667,-7.3333333)"
+       sodipodi:open="true"
+       sodipodi:end="6.2789689"
+       sodipodi:start="0"
+       d="M 20,14.5 C 20,18.642136 16.642136,22 12.5,22 8.3578644,22 5,18.642136 5,14.5 5,10.357864 8.3578644,7 12.5,7 c 4.129791,0 7.482521,3.338622 7.499933,7.468377"
+       sodipodi:ry="7.5"
+       sodipodi:rx="7.5"
+       sodipodi:cy="14.5"
+       sodipodi:cx="12.5"
+       id="path2984"
+       style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+       sodipodi:type="arc" />
+    <path
+       transform="matrix(1.3333333,0,0,1.3333333,33.333334,12.666667)"
+       sodipodi:open="true"
+       sodipodi:end="6.2789689"
+       sodipodi:start="0"
+       d="M 20,14.5 C 20,18.642136 16.642136,22 12.5,22 8.3578644,22 5,18.642136 5,14.5 5,10.357864 8.3578644,7 12.5,7 c 4.129791,0 7.482521,3.338622 7.499933,7.468377"
+       sodipodi:ry="7.5"
+       sodipodi:rx="7.5"
+       sodipodi:cy="14.5"
+       sodipodi:cx="12.5"
+       id="path2984-8"
+       style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+       sodipodi:type="arc" />
+    <path
+       transform="matrix(1.3333333,0,0,1.3333333,3.3333338,32.666667)"
+       sodipodi:open="true"
+       sodipodi:end="6.2789689"
+       sodipodi:start="0"
+       d="M 20,14.5 C 20,18.642136 16.642136,22 12.5,22 8.3578644,22 5,18.642136 5,14.5 5,10.357864 8.3578644,7 12.5,7 c 4.129791,0 7.482521,3.338622 7.499933,7.468377"
+       sodipodi:ry="7.5"
+       sodipodi:rx="7.5"
+       sodipodi:cy="14.5"
+       sodipodi:cx="12.5"
+       id="path2984-0"
+       style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+       sodipodi:type="arc" />
+  </g>
+  <g
+     id="g3765"
+     transform="translate(-7,-5)">
+    <path
+       inkscape:connector-curvature="0"
+       id="path3014"
+       d="M 28.956521,32.819843 27.217391,37 l 0,25.08094 L 62,62.08094 62,37 l -20,0 -1.73913,-4.180157 -11.304349,0 z"
+       style="fill:#808000;fill-opacity:1;stroke:#808000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path3016"
+       d="m 27.217391,62 4.347826,-20.900784 34.782609,0 L 62,62 z"
+       style="fill:#445500;stroke:#445500;stroke-width:0.85263342px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
+  </g>
+</svg>
diff --git a/src/icons/V.svg b/src/icons/V.svg
new file mode 100644
index 0000000..1d37a40
--- /dev/null
+++ b/src/icons/V.svg
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64px"
+   height="64px"
+   id="svg3513"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="V.svg">
+  <defs
+     id="defs3515" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.5"
+     inkscape:cx="32"
+     inkscape:cy="32"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1920"
+     inkscape:window-height="996"
+     inkscape:window-x="-2"
+     inkscape:window-y="-3"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata3518">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <text
+       xml:space="preserve"
+       style="font-size:40px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
+       x="24"
+       y="38.909092"
+       id="text3002"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3004"
+         x="24"
+         y="38.909092">V</tspan></text>
+  </g>
+</svg>
diff --git a/src/locale/qmapshack_cs.ts b/src/locale/qmapshack_cs.ts
index be0eb51..9a3bcbd 100644
--- a/src/locale/qmapshack_cs.ts
+++ b/src/locale/qmapshack_cs.ts
@@ -8,7 +8,7 @@
         <translation type="obsolete">Pohled %1</translation>
     </message>
     <message>
-        <location filename="../canvas/CCanvas.cpp" line="63"/>
+        <location filename="../canvas/CCanvas.cpp" line="64"/>
         <source>View %1</source>
         <translation>Pohled %1</translation>
     </message>
@@ -53,7 +53,7 @@
         <location filename="../dem/CDemVRT.cpp" line="45"/>
         <location filename="../dem/CDemVRT.cpp" line="52"/>
         <location filename="../dem/CDemVRT.cpp" line="61"/>
-        <location filename="../dem/CDemVRT.cpp" line="88"/>
+        <location filename="../dem/CDemVRT.cpp" line="89"/>
         <source>Error...</source>
         <translation>Chyba...</translation>
     </message>
@@ -69,7 +69,7 @@
         <translation>DEM musí mít jedno pásmo s 16bitovými nebo 32bitovými daty.</translation>
     </message>
     <message>
-        <location filename="../dem/CDemVRT.cpp" line="88"/>
+        <location filename="../dem/CDemVRT.cpp" line="89"/>
         <source>No georeference information found.</source>
         <translation>Nenalezeny žádné údaje o vyjádření prostorových vztahů.</translation>
     </message>
@@ -112,7 +112,7 @@
     </message>
     <message>
         <source>Enter new waypoint name.</source>
-        <translation type="vanished">Zadat  nový název cestovního bodu.</translation>
+        <translation type="obsolete">Zadat  nový název cestovního bodu.</translation>
     </message>
     <message>
         <source><h4>Comment:</h4></source>
@@ -134,91 +134,101 @@
 <context>
     <name>CDetailsPrj</name>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="175"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="537"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="188"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="550"/>
         <source>none</source>
         <translation>žádné</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="234"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="247"/>
         <source>Build diary...</source>
         <translation>Sestavit deník...</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="234"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="247"/>
         <source>Abort</source>
         <translation>Zrušit</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="292"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="305"/>
         <source><h2>Waypoints</h2></source>
         <translation><h2>Cestovní body</h2></translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="255"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="299"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="330"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="438"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="268"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="312"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="343"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="451"/>
         <source>Info</source>
         <translation>Informace</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="256"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="300"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="331"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="439"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="269"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="313"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="344"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="452"/>
         <source>Comment</source>
         <translation>Poznámka</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="323"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="336"/>
         <source><h2>Tracks</h2></source>
         <translation><h2>Stopy</h2></translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="248"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="261"/>
         <source><h2>Areas</h2></source>
         <translation><h2>Oblasti</h2></translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="461"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="82"/>
+        <source>You want to sort waypoints along a track, but you switched off track and waypoint correlation. Do you want to switch it on again?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="83"/>
+        <source>Correlation...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="474"/>
         <source>distance: %1%2</source>
         <translation>Vzdálenost: %1%2</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="463"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="476"/>
         <source>ascent: %1%2</source>
         <translation>Stoupání: %1%2</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="465"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="478"/>
         <source>descend: %1%2</source>
         <translation>Klesání: %1%2</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="523"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="550"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="536"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="563"/>
         <source>Edit name...</source>
         <translation>Upravit název...</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="523"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="550"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="536"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="563"/>
         <source>Enter new project name.</source>
         <translation>Zadejte název projektu.</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="532"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="545"/>
         <source>Edit keywords...</source>
         <translation>Upravit klíčová slova...</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="532"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="545"/>
         <source>Enter keywords.</source>
         <translation>Zadejte klíčová slova.</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="666"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="679"/>
         <source>Print Diary</source>
         <translation>Tisk deníku</translation>
     </message>
@@ -256,12 +266,12 @@
         <translation>%1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CDetailsTrk.cpp" line="397"/>
+        <location filename="../gis/trk/CDetailsTrk.cpp" line="395"/>
         <source>Edit name...</source>
         <translation>Upravit název...</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CDetailsTrk.cpp" line="397"/>
+        <location filename="../gis/trk/CDetailsTrk.cpp" line="395"/>
         <source>Enter new track name.</source>
         <translation>Zadat název nové stopy.</translation>
     </message>
@@ -401,124 +411,144 @@
 <context>
     <name>CGisListWks</name>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="95"/>
+        <location filename="../gis/CGisListWks.cpp" line="96"/>
         <source>Save As...</source>
         <translation>Uložit jako...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="96"/>
+        <location filename="../gis/CGisListWks.cpp" line="97"/>
         <source>Save</source>
         <translation>Uložit</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="94"/>
+        <location filename="../gis/CGisListWks.cpp" line="95"/>
         <source>Edit..</source>
         <translation>Upravit...</translation>
     </message>
     <message>
         <source>Update Project on Devices</source>
-        <translation type="vanished">Aktualizovat projekt na zařízeních</translation>
+        <translation type="obsolete">Aktualizovat projekt na zařízeních</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="98"/>
+        <location filename="../gis/CGisListWks.cpp" line="99"/>
         <source>Close</source>
         <translation>Zavřít</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="104"/>
+        <location filename="../gis/CGisListWks.cpp" line="105"/>
         <source>Update Project on Device</source>
         <translation>Aktualizovat projekt na zařízení</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="116"/>
+        <location filename="../gis/CGisListWks.cpp" line="117"/>
         <source>Edit...</source>
         <translation>Upravit...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="117"/>
+        <location filename="../gis/CGisListWks.cpp" line="118"/>
         <source>Copy to...</source>
         <translation>Kopírovat do...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="132"/>
+        <location filename="../gis/CGisListWks.cpp" line="133"/>
         <source>Show Bubble</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="134"/>
+        <location filename="../gis/CGisListWks.cpp" line="135"/>
         <source>Move Waypoint</source>
         <translation>Přesunout cestovní bod</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="135"/>
+        <location filename="../gis/CGisListWks.cpp" line="136"/>
         <source>Proj. Waypoint...</source>
         <translation>Promítnutí cestovního bodu...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="596"/>
-        <location filename="../gis/CGisListWks.cpp" line="1296"/>
-        <location filename="../gis/CGisListWks.cpp" line="1335"/>
+        <location filename="../gis/CGisListWks.cpp" line="144"/>
+        <source>Calculate Route</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisListWks.cpp" line="145"/>
+        <source>Reset Route</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisListWks.cpp" line="146"/>
+        <source>Edit Route</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisListWks.cpp" line="162"/>
+        <source>Create Route</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisListWks.cpp" line="608"/>
+        <location filename="../gis/CGisListWks.cpp" line="1371"/>
+        <location filename="../gis/CGisListWks.cpp" line="1409"/>
         <source><b>Update devices</b><p>Update %1<br/>Please wait...</p></source>
         <translation><b>Aktualizovat zařízení</b><p>Aktualizovat %1<br/>Počkejte, prosím...</p></translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="119"/>
+        <location filename="../gis/CGisListWks.cpp" line="120"/>
         <source>Track Profile</source>
         <translation>Profil stopy</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="97"/>
+        <location filename="../gis/CGisListWks.cpp" line="98"/>
         <source>Send to Devices</source>
         <translation>Poslat do zařízení</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="121"/>
+        <location filename="../gis/CGisListWks.cpp" line="122"/>
         <source>Select Range</source>
         <translation>Vybrat rozsah</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="122"/>
+        <location filename="../gis/CGisListWks.cpp" line="123"/>
         <source>Edit Track Points</source>
         <translation>Upravit body stopy</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="123"/>
+        <location filename="../gis/CGisListWks.cpp" line="124"/>
         <source>Reverse Track</source>
         <translation>Obrátit stopu</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="124"/>
+        <location filename="../gis/CGisListWks.cpp" line="125"/>
         <source>Combine Tracks</source>
         <translation>Spojit stopy</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="149"/>
+        <location filename="../gis/CGisListWks.cpp" line="155"/>
         <source>Edit Area Points</source>
         <translation>Upravit body oblasti</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="105"/>
-        <location filename="../gis/CGisListWks.cpp" line="126"/>
+        <location filename="../gis/CGisListWks.cpp" line="106"/>
+        <location filename="../gis/CGisListWks.cpp" line="127"/>
         <source>Delete</source>
         <translation>Smazat</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="696"/>
+        <location filename="../gis/CGisListWks.cpp" line="708"/>
         <source>Saving workspace. Please wait.</source>
         <translation>Ukládá se pohled. Počkejte, prosím.</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="737"/>
+        <location filename="../gis/CGisListWks.cpp" line="750"/>
         <source>Loading workspace. Please wait.</source>
         <translation>Nahrává se pohled. Počkejte, prosím.</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="921"/>
+        <location filename="../gis/CGisListWks.cpp" line="952"/>
         <source>Close all projects...</source>
         <translation>Zavřít všechny projekty...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="921"/>
+        <location filename="../gis/CGisListWks.cpp" line="952"/>
         <source>This will remove all projects from the workspace.</source>
         <translation>Tímto budou všechny projekty odstraněny z pohledu.</translation>
     </message>
@@ -526,12 +556,22 @@
 <context>
     <name>CGisWidget</name>
     <message>
-        <location filename="../gis/CGisWidget.cpp" line="444"/>
+        <location filename="../gis/CGisWidget.cpp" line="114"/>
+        <source>Load project...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisWidget.cpp" line="114"/>
+        <source>The project "%1" is already in the workspace.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisWidget.cpp" line="449"/>
         <source>Cut Track...</source>
         <translation>Rozkrajet stopu...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisWidget.cpp" line="444"/>
+        <location filename="../gis/CGisWidget.cpp" line="449"/>
         <source>Do you want to delete the original track?</source>
         <translation>Opravdu chcete smazat původní stopu?</translation>
     </message>
@@ -543,12 +583,12 @@
         <translation type="obsolete">[Mřížka: %1]</translation>
     </message>
     <message>
-        <location filename="../grid/CGrid.cpp" line="61"/>
+        <location filename="../grid/CGrid.cpp" line="63"/>
         <source>[Grid: %1%2%5 %3%4%5] </source>
         <translation>[Mřížka: %1%2%5 %3%4%5] </translation>
     </message>
     <message>
-        <location filename="../grid/CGrid.cpp" line="65"/>
+        <location filename="../grid/CGrid.cpp" line="67"/>
         <source>[Grid: N %1m, E %2m] </source>
         <translation>[Mřížka: S %1m, V %2m] </translation>
     </message>
@@ -564,17 +604,17 @@
 <context>
     <name>CImportDatabase</name>
     <message>
-        <location filename="../qlgt/CImportDatabase.cpp" line="29"/>
+        <location filename="../tool/CImportDatabase.cpp" line="29"/>
         <source>Import QLandkarte Database</source>
         <translation>Zavést databázi QLandkarte</translation>
     </message>
     <message>
-        <location filename="../qlgt/CImportDatabase.cpp" line="73"/>
+        <location filename="../tool/CImportDatabase.cpp" line="73"/>
         <source>Select source database...</source>
         <translation>Vybrat zdrojovou databázi...</translation>
     </message>
     <message>
-        <location filename="../qlgt/CImportDatabase.cpp" line="93"/>
+        <location filename="../tool/CImportDatabase.cpp" line="93"/>
         <source>Select target database...</source>
         <translation>Vybrat cílovou databázi...</translation>
     </message>
@@ -582,22 +622,22 @@
 <context>
     <name>CMainWindow</name>
     <message>
-        <location filename="../CMainWindow.cpp" line="492"/>
+        <location filename="../CMainWindow.cpp" line="560"/>
         <source>Ele: %1%2</source>
         <translation>Výška: %1%2</translation>
     </message>
     <message>
-        <location filename="../CMainWindow.cpp" line="618"/>
+        <location filename="../CMainWindow.cpp" line="691"/>
         <source>Load GIS Data...</source>
         <translation>Nahrát data GIS...</translation>
     </message>
     <message>
-        <location filename="../CMainWindow.cpp" line="652"/>
+        <location filename="../CMainWindow.cpp" line="725"/>
         <source>Select output file</source>
         <translation>Vybrat výstupní soubor</translation>
     </message>
     <message>
-        <location filename="../CMainWindow.cpp" line="678"/>
+        <location filename="../CMainWindow.cpp" line="751"/>
         <source>Select file to load</source>
         <translation>Vybrat soubor k nahrání</translation>
     </message>
@@ -1189,46 +1229,46 @@
         <translation>Nepodařilo se přečíst stavbu souboru: </translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="640"/>
+        <location filename="../map/CMapIMG.cpp" line="642"/>
         <source>Loading %1</source>
         <translation>Nahrává se %1</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="645"/>
+        <location filename="../map/CMapIMG.cpp" line="649"/>
         <source>User abort: </source>
         <translation>Zrušeno uživatelem: </translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="648"/>
+        <location filename="../map/CMapIMG.cpp" line="652"/>
         <source>File is NT format. QMapShack is unable to read map files with NT format: </source>
         <translation>Soubor je ve formátu NT. QMapShack nedokáže číst mapové soubory ve formátu NT: </translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="740"/>
+        <location filename="../map/CMapIMG.cpp" line="744"/>
         <source>File contains locked / encypted data. Garmin does not want you to use this file with any other software than the one supplied by Garmin.</source>
         <translation>Soubor obsahuje zamknutá/zašifrovaná data. Garmin nechce, aby byl tento soubor použit s jiným programem než dodaným Garminem.</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="2496"/>
-        <location filename="../map/CMapIMG.cpp" line="2504"/>
+        <location filename="../map/CMapIMG.cpp" line="2500"/>
         <location filename="../map/CMapIMG.cpp" line="2508"/>
-        <location filename="../map/CMapIMG.cpp" line="2513"/>
-        <location filename="../map/CMapIMG.cpp" line="2559"/>
-        <location filename="../map/CMapIMG.cpp" line="2567"/>
+        <location filename="../map/CMapIMG.cpp" line="2512"/>
+        <location filename="../map/CMapIMG.cpp" line="2517"/>
+        <location filename="../map/CMapIMG.cpp" line="2563"/>
         <location filename="../map/CMapIMG.cpp" line="2571"/>
-        <location filename="../map/CMapIMG.cpp" line="2576"/>
+        <location filename="../map/CMapIMG.cpp" line="2575"/>
+        <location filename="../map/CMapIMG.cpp" line="2580"/>
         <source>Point of Interest</source>
         <translation>Podivuhodnost</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="2703"/>
+        <location filename="../map/CMapIMG.cpp" line="2707"/>
         <source>Unknown</source>
         <translation>Neznámý</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="2749"/>
-        <location filename="../map/CMapIMG.cpp" line="2757"/>
-        <location filename="../map/CMapIMG.cpp" line="2764"/>
+        <location filename="../map/CMapIMG.cpp" line="2753"/>
+        <location filename="../map/CMapIMG.cpp" line="2761"/>
+        <location filename="../map/CMapIMG.cpp" line="2768"/>
         <source>Area</source>
         <translation>Oblast</translation>
     </message>
@@ -1282,7 +1322,7 @@
         <translation>Vybrat cestu k mapě...</translation>
     </message>
     <message>
-        <location filename="../map/CMapPathSetup.cpp" line="78"/>
+        <location filename="../map/CMapPathSetup.cpp" line="81"/>
         <source>Select root path...</source>
         <translation>Vybrat cestu ke kořeni...</translation>
     </message>
@@ -1291,7 +1331,7 @@
     <name>CMapPropSetup</name>
     <message>
         <source>Cache path...</source>
-        <translation type="vanished">Cesta k vyrovnávací paměti...</translation>
+        <translation type="obsolete">Cesta k vyrovnávací paměti...</translation>
     </message>
 </context>
 <context>
@@ -1376,7 +1416,7 @@ line %2, column %3:
         <location filename="../map/CMapVRT.cpp" line="47"/>
         <location filename="../map/CMapVRT.cpp" line="61"/>
         <location filename="../map/CMapVRT.cpp" line="89"/>
-        <location filename="../map/CMapVRT.cpp" line="124"/>
+        <location filename="../map/CMapVRT.cpp" line="125"/>
         <source>Error...</source>
         <translation>Chyba...</translation>
     </message>
@@ -1393,7 +1433,7 @@ line %2, column %3:
         <translation>Soubor musí mít 8 bitovou barevnou paletu nebo být v odstínech šedi.</translation>
     </message>
     <message>
-        <location filename="../map/CMapVRT.cpp" line="124"/>
+        <location filename="../map/CMapVRT.cpp" line="125"/>
         <source>No georeference information found.</source>
         <translation>Nenalezeny žádné údaje o vyjádření prostorových vztahů.</translation>
     </message>
@@ -1401,22 +1441,22 @@ line %2, column %3:
 <context>
     <name>CMapVrtBuilder</name>
     <message>
-        <location filename="../map/CMapVrtBuilder.cpp" line="29"/>
+        <location filename="../tool/CMapVrtBuilder.cpp" line="29"/>
         <source>Build GDAL VRT</source>
         <translation>Sestavit GDAL VRT</translation>
     </message>
     <message>
-        <location filename="../map/CMapVrtBuilder.cpp" line="51"/>
+        <location filename="../tool/CMapVrtBuilder.cpp" line="51"/>
         <source>Select files...</source>
         <translation>Vybrat soubory...</translation>
     </message>
     <message>
-        <location filename="../map/CMapVrtBuilder.cpp" line="75"/>
+        <location filename="../tool/CMapVrtBuilder.cpp" line="75"/>
         <source>Select target file...</source>
         <translation>Vybrat cílový soubor...</translation>
     </message>
     <message>
-        <location filename="../map/CMapVrtBuilder.cpp" line="196"/>
+        <location filename="../tool/CMapVrtBuilder.cpp" line="196"/>
         <source>!!! failed !!!
 </source>
         <translation>Nepodařilo se!</translation>
@@ -1429,7 +1469,7 @@ line %2, column %3:
         <location filename="../map/CMapWMTS.cpp" line="55"/>
         <location filename="../map/CMapWMTS.cpp" line="65"/>
         <location filename="../map/CMapWMTS.cpp" line="74"/>
-        <location filename="../map/CMapWMTS.cpp" line="198"/>
+        <location filename="../map/CMapWMTS.cpp" line="206"/>
         <source>Error...</source>
         <translation>Chyba...</translation>
     </message>
@@ -1460,7 +1500,7 @@ Neznámá stavba.</translation>
         <translation>Neočekávaná služba. Očekáváno '* WMTS 1.0.0'. Přečteno '%1 %2'.</translation>
     </message>
     <message>
-        <location filename="../map/CMapWMTS.cpp" line="198"/>
+        <location filename="../map/CMapWMTS.cpp" line="206"/>
         <source>No georeference information found.</source>
         <translation>Nenalezeny žádné údaje o soustavě souřadnic.</translation>
     </message>
@@ -1469,7 +1509,7 @@ Neznámá stavba.</translation>
         <translation type="obsolete">--- Vše ---</translation>
     </message>
     <message>
-        <location filename="../map/CMapWMTS.cpp" line="384"/>
+        <location filename="../map/CMapWMTS.cpp" line="392"/>
         <source><b>%1</b>: %2 tiles pending<br/></source>
         <translation><b>%1</b>: %2 dlaždic čeká<br/></translation>
     </message>
@@ -1477,17 +1517,43 @@ Neznámá stavba.</translation>
 <context>
     <name>CMouseEditArea</name>
     <message>
-        <location filename="../mouse/CMouseEditArea.cpp" line="38"/>
         <source><b>Edit Area</b><br/>Select a corner point for more options.<br/></source>
-        <translation><b>Upravit oblast</b><br/>Vyberte rohový bod pro více voleb.<br/></translation>
+        <translation type="obsolete"><b>Upravit oblast</b><br/>Vyberte rohový bod pro více voleb.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditArea.cpp" line="37"/>
+        <source><b>Edit Area</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>CMouseEditRte</name>
+    <message>
+        <location filename="../mouse/CMouseEditRte.cpp" line="39"/>
+        <source><b>Edit Route Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/></source>
+        <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
     <name>CMouseEditTrk</name>
     <message>
-        <location filename="../mouse/CMouseEditTrk.cpp" line="44"/>
         <source><b>Edit Track Points</b><br/>Select a track point for more options.<br/></source>
-        <translation><b>Upravit body stopy</b><br/>Vyberte bod stopy pro více voleb.<br/></translation>
+        <translation type="obsolete"><b>Upravit body stopy</b><br/>Vyberte bod stopy pro více voleb.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="39"/>
+        <source><b>Edit Track Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="81"/>
+        <source>Warning!</source>
+        <translation type="unfinished">Varování!</translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="81"/>
+        <source>This will replace all data of the orignal by a simple line of coordinates. All other data will be lost permanently.</source>
+        <translation type="unfinished">Tímto budou všechny původní údaje nahrazeny jednoduchou čárou souřadnic. Všechna ostatní data budou trvale ztracena.</translation>
     </message>
 </context>
 <context>
@@ -1504,11 +1570,16 @@ Neznámá stavba.</translation>
     </message>
     <message>
         <location filename="../mouse/CMouseNormal.cpp" line="44"/>
+        <source>Add Route</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseNormal.cpp" line="45"/>
         <source>Add Area</source>
         <translation>Přidat oblast</translation>
     </message>
     <message>
-        <location filename="../mouse/CMouseNormal.cpp" line="46"/>
+        <location filename="../mouse/CMouseNormal.cpp" line="48"/>
         <source>Copy position</source>
         <translation>Kopírovat polohu</translation>
     </message>
@@ -1632,127 +1703,127 @@ není platným vymezením soustavy souřadnic
 <context>
     <name>CQlgtDb</name>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="304"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="307"/>
         <source>Migrating database from version 4 to 5.</source>
         <translation>Přestěhovat databázi z verze 4 na verzi 5.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="357"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="361"/>
         <source>Migrating database from version 5 to 6.</source>
         <translation>Přestěhovat databázi z verze 5 na verzi 6.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="414"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="419"/>
         <source>Migrating database from version 6 to 7.</source>
         <translation>Přestěhovat databázi z verze 6 na verzi 7.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="480"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="485"/>
         <source>Migrating database from version 7 to 8.</source>
         <translation>Přestěhovat databázi z verze 7 na verzi 8.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="509"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="514"/>
         <source>Migrating database from version 8 to 9.</source>
         <translation>Přestěhovat databázi z verze 8 na verzi 9.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="532"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="537"/>
         <source>Open database: %1</source>
         <translation>Otevřít databázi: %1</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="541"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="546"/>
         <source>Folders:          %1</source>
         <translation>Složky: %1</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="550"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="555"/>
         <source>Tracks:           %1</source>
         <translation>Stopy: %1</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="558"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="563"/>
         <source>Routes:           %1 (Only the basic route will be copied)</source>
         <translation>Cesty: %1 (Bude koírována pouze základní cesta)</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="566"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="571"/>
         <source>Waypoints:        %1</source>
         <translation>Cestovní body: %1</translation>
     </message>
     <message>
         <source>Overlays:         %1 (only area overlays will be converted to QMapShack)</source>
-        <translation type="vanished">Překrytí:         %1 (pouze překrytí oblasti budou převedena do QMapShack)</translation>
+        <translation type="obsolete">Překrytí:         %1 (pouze překrytí oblasti budou převedena do QMapShack)</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="574"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="579"/>
         <source>Overlays:         %1 (areas will be converted as areas, distance lines will be converted to tracks, all other overlay items will be lost)</source>
         <translation>Překrytí:         %1 (oblasti budou převáděny jako oblasti, vzdálenostní čáry budou převedeny do stop, všechny ostatní překrývající prvky budou ztraceny)</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="581"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="586"/>
         <source>Diaries:          %1</source>
         <translation>Deníky:          %1</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="588"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="593"/>
         <source>Map selections:   %1 (can't be converted to QMapShack)</source>
         <translation>Výběry map:       %1 (nelze převést do QMapShack)</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="594"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="599"/>
         <source>------ Start to convert database to %1------</source>
         <translation>------ Začít převádět databázi do %1------</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="598"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="603"/>
         <source>Failed to create target database.</source>
         <translation>Nepodařilo se vytvořit cílovou databázi.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="599"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="604"/>
         <source>------ Abort ------</source>
         <translation>------ Zrušit ------</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="627"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="632"/>
         <source>------ Done ------</source>
         <translation>------ Hotovo ------</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="635"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="640"/>
         <source>Restore folders...</source>
         <translation>Obnovit složky...</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="635"/>
-        <location filename="../qlgt/CQlgtDb.cpp" line="668"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="640"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="673"/>
         <source>Abort</source>
         <translation>Zrušit</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="662"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="667"/>
         <source>Imported %1 folders and %2 diaries</source>
         <translation>Zavedeno %1 složek a %2 deníků</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="668"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="673"/>
         <source>Copy items...</source>
         <translation>Kopírovat prvky...</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="692"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="697"/>
         <source>Imported %1 tracks, %2 waypoints, %3 routes, %4 areas</source>
         <translation>Zavedeno %1 stop, %2 cestovních bodů, %3 cest, %4 oblastí</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="693"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="698"/>
         <source>Import folders...</source>
         <translation>Zavést složky...</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="758"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="763"/>
         <source>Overlay of type '%1' cant be converted</source>
         <translation>Překrytí typu '%1' nelze převést</translation>
     </message>
@@ -1781,6 +1852,123 @@ není platným vymezením soustavy souřadnic
     </message>
 </context>
 <context>
+    <name>CRouterRoutino</name>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="34"/>
+        <source>Foot</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="35"/>
+        <source>Horse</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="36"/>
+        <source>Wheelchair</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="37"/>
+        <source>Bicycle</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="38"/>
+        <source>Moped</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="39"/>
+        <source>Motorcycle</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="40"/>
+        <source>Motorcar</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="41"/>
+        <source>Goods</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="43"/>
+        <source>Shortest</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="44"/>
+        <source>Quickest</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="96"/>
+        <source>profile "%1"</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="97"/>
+        <source>, mode "%1"</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>CRouterRoutinoPathSetup</name>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutinoPathSetup.cpp" line="40"/>
+        <source>Add or remove paths containing Routino data. There can be multiple databases in a path but no sub-path is parsed.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutinoPathSetup.cpp" line="55"/>
+        <source>Select routing data file path...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Select DEM file path...</source>
+        <translation type="obsolete">Vybrat cestu k souboru DEM...</translation>
+    </message>
+</context>
+<context>
+    <name>CRouterSetup</name>
+    <message>
+        <location filename="../gis/rte/router/CRouterSetup.cpp" line="36"/>
+        <source>Routino (offline)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterSetup.cpp" line="37"/>
+        <source>MapQuest (online)</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>CRoutinoDatabaseBuilder</name>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="30"/>
+        <source>Create Routino Database</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="61"/>
+        <source>Select files...</source>
+        <translation type="unfinished">Vybrat soubory...</translation>
+    </message>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="85"/>
+        <source>Select target path...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="206"/>
+        <source>!!! failed !!!
+</source>
+        <translation type="unfinished">Nepodařilo se!</translation>
+    </message>
+</context>
+<context>
     <name>CSearchGoogle</name>
     <message>
         <location filename="../gis/search/CSearchGoogle.cpp" line="119"/>
@@ -1997,6 +2185,20 @@ není platným vymezením soustavy souřadnic
     </message>
 </context>
 <context>
+    <name>ICreateRouteFromWpt</name>
+    <message>
+        <location filename="../gis/rte/ICreateRouteFromWpt.ui" line="14"/>
+        <source>Create Route from Waypoints</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/ICreateRouteFromWpt.ui" line="30"/>
+        <location filename="../gis/rte/ICreateRouteFromWpt.ui" line="50"/>
+        <source>...</source>
+        <translation type="unfinished">...</translation>
+    </message>
+</context>
+<context>
     <name>IDemPathSetup</name>
     <message>
         <location filename="../dem/IDemPathSetup.ui" line="14"/>
@@ -2240,11 +2442,11 @@ není platným vymezením soustavy souřadnic
     </message>
     <message>
         <source>Keep Order of Project</source>
-        <translation type="vanished">Zachovat pořadí projektu</translation>
+        <translation type="obsolete">Zachovat pořadí projektu</translation>
     </message>
     <message>
         <source>Sort Along Track</source>
-        <translation type="vanished">Třídit podle stopy</translation>
+        <translation type="obsolete">Třídit podle stopy</translation>
     </message>
     <message>
         <location filename="../gis/prj/IDetailsPrj.ui" line="115"/>
@@ -2463,7 +2665,7 @@ není platným vymezením soustavy souřadnic
     </message>
     <message>
         <source><html><head/><body><p>Read Only Mode</p></body></html></source>
-        <translation type="vanished"><html><head/><body><p>Režim pouze pro čtení</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Režim pouze pro čtení</p></body></html></translation>
     </message>
     <message>
         <location filename="../gis/wpt/IDetailsWpt.ui" line="270"/>
@@ -2611,7 +2813,17 @@ není platným vymezením soustavy souřadnic
         <translation>Změnit začáteční čas stopy na </translation>
     </message>
     <message>
-        <location filename="../gis/trk/filter/IFilterNewDate.ui" line="71"/>
+        <location filename="../gis/trk/filter/IFilterNewDate.ui" line="51"/>
+        <source>dd.MM.yy HH:mm:ss</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/trk/filter/IFilterNewDate.ui" line="61"/>
+        <source>-</source>
+        <translation type="unfinished">-</translation>
+    </message>
+    <message>
+        <location filename="../gis/trk/filter/IFilterNewDate.ui" line="81"/>
         <source>...</source>
         <translation>...</translation>
     </message>
@@ -2823,34 +3035,34 @@ není platným vymezením soustavy souřadnic
 <context>
     <name>IImportDatabase</name>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="14"/>
+        <location filename="../tool/IImportDatabase.ui" line="14"/>
         <source>Form</source>
         <translation>Formulář</translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="45"/>
+        <location filename="../tool/IImportDatabase.ui" line="45"/>
         <source>Source Database:</source>
         <translation>Zdrojová databáze:</translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="52"/>
-        <location filename="../qlgt/IImportDatabase.ui" line="93"/>
+        <location filename="../tool/IImportDatabase.ui" line="52"/>
+        <location filename="../tool/IImportDatabase.ui" line="93"/>
         <source>-</source>
         <translation>-</translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="22"/>
-        <location filename="../qlgt/IImportDatabase.ui" line="63"/>
+        <location filename="../tool/IImportDatabase.ui" line="22"/>
+        <location filename="../tool/IImportDatabase.ui" line="63"/>
         <source>...</source>
         <translation>...</translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="86"/>
+        <location filename="../tool/IImportDatabase.ui" line="86"/>
         <source>Target Database:</source>
         <translation>Cílová databáze:</translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="102"/>
+        <location filename="../tool/IImportDatabase.ui" line="102"/>
         <source>Start</source>
         <translation>Spustit</translation>
     </message>
@@ -2915,37 +3127,37 @@ není platným vymezením soustavy souřadnic
         <translation>Pohled</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="98"/>
+        <location filename="../IMainWindow.ui" line="99"/>
         <source>Window</source>
         <translation>Okno</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="103"/>
+        <location filename="../IMainWindow.ui" line="104"/>
         <source>?</source>
         <translation>Nápověda</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="110"/>
+        <location filename="../IMainWindow.ui" line="111"/>
         <source>Project</source>
         <translation>Projekt</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="120"/>
+        <location filename="../IMainWindow.ui" line="121"/>
         <source>Tool</source>
         <translation>Nástroj</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="138"/>
+        <location filename="../IMainWindow.ui" line="140"/>
         <source>Maps</source>
         <translation>Mapy</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="175"/>
+        <location filename="../IMainWindow.ui" line="177"/>
         <source>Dig. Elev. Model (DEM)</source>
         <translation>Digitální výškový model (DEM)</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="208"/>
+        <location filename="../IMainWindow.ui" line="210"/>
         <source>Data</source>
         <translation>Data</translation>
     </message>
@@ -2954,78 +3166,78 @@ není platným vymezením soustavy souřadnic
         <translation type="obsolete">Přidat pohled na mapu</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="227"/>
+        <location filename="../IMainWindow.ui" line="262"/>
         <source>Ctrl+T</source>
         <translation>Ctrl+T</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="239"/>
+        <location filename="../IMainWindow.ui" line="274"/>
         <source>Show Scale</source>
         <translation>Ukázat měřítko</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="248"/>
+        <location filename="../IMainWindow.ui" line="283"/>
         <source>Setup Map Font</source>
         <translation>Nastavit písmo mapy</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="260"/>
+        <location filename="../IMainWindow.ui" line="295"/>
         <source>Show Grid</source>
         <translation>Ukázat mřížku</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="263"/>
+        <location filename="../IMainWindow.ui" line="298"/>
         <source>Ctrl+G</source>
         <translation>Ctrl+G</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="272"/>
+        <location filename="../IMainWindow.ui" line="307"/>
         <source>Setup Grid</source>
         <translation>Nastavit mřížku</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="275"/>
+        <location filename="../IMainWindow.ui" line="310"/>
         <source>Ctrl+Alt+G</source>
         <translation>Ctrl+Alt+G</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="287"/>
+        <location filename="../IMainWindow.ui" line="322"/>
         <source>Flip Mouse Wheel</source>
         <translation>Obrátit kolečko myši</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="296"/>
-        <location filename="../IMainWindow.ui" line="299"/>
+        <location filename="../IMainWindow.ui" line="331"/>
+        <location filename="../IMainWindow.ui" line="334"/>
         <source>Setup Map Paths</source>
         <translation>Nastavit cesty k mapám</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="311"/>
+        <location filename="../IMainWindow.ui" line="346"/>
         <source>POI Text</source>
         <translation>Text POI</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="323"/>
+        <location filename="../IMainWindow.ui" line="358"/>
         <source>Night / Day</source>
         <translation>Noc/Den</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="335"/>
+        <location filename="../IMainWindow.ui" line="370"/>
         <source>Map Tool Tip</source>
         <translation>Rada k nástroji pro mapu</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="344"/>
+        <location filename="../IMainWindow.ui" line="379"/>
         <source>Setup DEM Paths</source>
         <translation>Nastavit cesty k DEM</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="353"/>
+        <location filename="../IMainWindow.ui" line="388"/>
         <source>About</source>
         <translation>O programu</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="362"/>
+        <location filename="../IMainWindow.ui" line="397"/>
         <source>Help</source>
         <translation>Nápověda</translation>
     </message>
@@ -3034,143 +3246,163 @@ není platným vymezením soustavy souřadnic
         <translation type="obsolete">Nastavit pohled na mapu</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="221"/>
-        <location filename="../IMainWindow.ui" line="224"/>
+        <location filename="../IMainWindow.ui" line="222"/>
+        <source>Route</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../IMainWindow.ui" line="256"/>
+        <location filename="../IMainWindow.ui" line="259"/>
         <source>Add Map View</source>
         <translation>Přidat pohled na mapu</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="371"/>
-        <location filename="../IMainWindow.ui" line="374"/>
+        <location filename="../IMainWindow.ui" line="406"/>
+        <location filename="../IMainWindow.ui" line="409"/>
         <source>Setup Map View</source>
         <translation>Nastavit pohled na mapu</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="383"/>
+        <location filename="../IMainWindow.ui" line="418"/>
         <source>Load GIS Data</source>
         <translation>Nahrát data GIS</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="386"/>
+        <location filename="../IMainWindow.ui" line="421"/>
         <source>Load projects from file</source>
         <translation>Nahrát projekty ze souboru</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="389"/>
+        <location filename="../IMainWindow.ui" line="424"/>
         <source>Ctrl+L</source>
         <translation>Ctrl+L</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="398"/>
+        <location filename="../IMainWindow.ui" line="433"/>
         <source>Save All GIS Data</source>
         <translation>Uložit všechna data GIS</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="401"/>
+        <location filename="../IMainWindow.ui" line="436"/>
         <source>Save all projects in the workspace</source>
         <translation>Uložit všechny projekty na pracovním místě</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="404"/>
+        <location filename="../IMainWindow.ui" line="439"/>
         <source>Ctrl+S</source>
         <translation>Ctrl+S</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="413"/>
+        <location filename="../IMainWindow.ui" line="448"/>
         <source>Setup Time Zone</source>
         <translation>Nastavit časové pásmo</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="422"/>
+        <location filename="../IMainWindow.ui" line="457"/>
         <source>Add empty project</source>
         <translation>Přidat prázdný projekt</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="434"/>
+        <location filename="../IMainWindow.ui" line="469"/>
         <source>Search Google</source>
         <translation>Hledat pomocí Google</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="443"/>
+        <location filename="../IMainWindow.ui" line="478"/>
         <source>Close all projects</source>
         <translation>Zavřít všechny projekty</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="446"/>
+        <location filename="../IMainWindow.ui" line="481"/>
         <source>F8</source>
         <translation>F8</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="455"/>
+        <location filename="../IMainWindow.ui" line="490"/>
         <source>Setup Units</source>
         <translation>Nastavit jednotky</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="464"/>
+        <location filename="../IMainWindow.ui" line="499"/>
         <source>Setup Workspace</source>
         <translation>Nastavit pohled</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="467"/>
+        <location filename="../IMainWindow.ui" line="502"/>
         <source>Setup save on exit.</source>
         <translation>Nastavit uložení při ukončení.</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="476"/>
+        <location filename="../IMainWindow.ui" line="511"/>
         <source>Import Database from QLandkarte</source>
         <translation>Zavést databázi z QLandkarte</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="479"/>
+        <location filename="../IMainWindow.ui" line="514"/>
         <source>Import QLandkarte GT database</source>
         <translation>Zavést databázi GT QLandkarte</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="488"/>
+        <location filename="../IMainWindow.ui" line="523"/>
         <source>VRT Builder</source>
         <translation>Sestavovač VRT</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="491"/>
+        <location filename="../IMainWindow.ui" line="526"/>
         <source>GUI front end to gdalbuildvrt</source>
         <translation>Rozhraní pro gdalbuildvrt</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="500"/>
+        <location filename="../IMainWindow.ui" line="535"/>
         <source>Store Map View</source>
         <translation>Uložit pohled na mapu</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="503"/>
+        <location filename="../IMainWindow.ui" line="538"/>
         <source>Write current active map and DEM list including the properties to a file</source>
         <translation>Zapsat nynější činnou mapu a seznam DEM včetně vlastností do souboru</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="512"/>
+        <location filename="../IMainWindow.ui" line="547"/>
         <source>Load Map View</source>
         <translation>Nahrát pohled na mapu</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="515"/>
+        <location filename="../IMainWindow.ui" line="550"/>
         <source>Restore view with active map and DEM list including the properties from a file</source>
         <translation>Obnovit pohled s činnou mapou a seznam DEM včetně vlastností ze souboru</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="527"/>
+        <location filename="../IMainWindow.ui" line="562"/>
         <source>Ext. Profile</source>
         <translation>Ext. Profil</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="530"/>
+        <location filename="../IMainWindow.ui" line="565"/>
         <source>Ctrl+E</source>
         <translation>Ctrl+E</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="539"/>
+        <location filename="../IMainWindow.ui" line="574"/>
         <source>Close</source>
         <translation>Zavřít</translation>
     </message>
     <message>
+        <location filename="../IMainWindow.ui" line="583"/>
+        <source>Clone Map View</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../IMainWindow.ui" line="586"/>
+        <source>Ctrl+Shift+T</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../IMainWindow.ui" line="595"/>
+        <source>Create Routino Database</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
         <source>Setup Database</source>
         <translation type="obsolete">Nastavit databázi</translation>
     </message>
@@ -3237,7 +3469,7 @@ Nechce se mi číst dokumentaci!</translation>
     </message>
     <message>
         <location filename="../map/IMapPathSetup.ui" line="29"/>
-        <location filename="../map/IMapPathSetup.ui" line="135"/>
+        <location filename="../map/IMapPathSetup.ui" line="154"/>
         <source>-</source>
         <translation>-</translation>
     </message>
@@ -3314,33 +3546,33 @@ Nechce se mi číst dokumentaci!</translation>
 <context>
     <name>IMapVrtBuilder</name>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="14"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="14"/>
         <source>Form</source>
         <translation>Formulář</translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="22"/>
-        <location filename="../map/IMapVrtBuilder.ui" line="56"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="22"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="56"/>
         <source>...</source>
         <translation>...</translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="39"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="39"/>
         <source>Select source files:</source>
         <translation>Vybrat zdrojové soubory:</translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="79"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="79"/>
         <source>Target Filename:</source>
         <translation>Název cílového souboru:</translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="86"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="86"/>
         <source>-</source>
         <translation>-</translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="95"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="95"/>
         <source>Start</source>
         <translation>Spustit</translation>
     </message>
@@ -3348,24 +3580,60 @@ Nechce se mi číst dokumentaci!</translation>
 <context>
     <name>IMouseEditLine</name>
     <message>
-        <location filename="../mouse/IMouseEditLine.cpp" line="344"/>
         <source>Add points?</source>
-        <translation>Přidat body?</translation>
+        <translation type="obsolete">Přidat body?</translation>
     </message>
     <message>
-        <location filename="../mouse/IMouseEditLine.cpp" line="344"/>
         <source>Add points to temporary line?</source>
-        <translation>Přidat body do dočasné čáry?</translation>
+        <translation type="obsolete">Přidat body do dočasné čáry?</translation>
     </message>
     <message>
-        <location filename="../mouse/IMouseEditLine.cpp" line="887"/>
         <source>Warning!</source>
-        <translation>Varování!</translation>
+        <translation type="obsolete">Varování!</translation>
     </message>
     <message>
-        <location filename="../mouse/IMouseEditLine.cpp" line="887"/>
         <source>This will replace all data of the orignal by a simple line of coordinates. All other data will be lost permanently.</source>
-        <translation>Tímto budou všechny původní údaje nahrazeny jednoduchou čárou souřadnic. Všechna ostatní data budou trvale ztracena.</translation>
+        <translation type="obsolete">Tímto budou všechny původní údaje nahrazeny jednoduchou čárou souřadnic. Všechna ostatní data budou trvale ztracena.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="238"/>
+        <source><b>New Line</b><br/>Move the mouse and use the left mouse button to drop points. When done use the right mouse button to stop.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="279"/>
+        <source><b>Delete Point</b><br/>Move the mouse close to a point and press the left button to delete it.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="287"/>
+        <source><b>Select Range of Points</b><br/>Left click on first point to start selection. Left click second point to complete selection and choose from options. Use the right mouse button to cancel.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="295"/>
+        <source><b>Move Point</b><br/>Move the mouse close to a point and press the left button to make it stick to the cursor. Move the mouse to move the point. Drop the point by a left click. Use the right mouse button to cancel.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="303"/>
+        <source><b>Add Point</b><br/>Move the mouse close to a line segment and press the left button to add a point. The point will stick to the cursor and you can move it.  Drop the point by a left click. Use the right mouse button to cancel.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="311"/>
+        <source><b>No Routing</b><br/>All points will be connected with a straight line.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="316"/>
+        <source><b>Auto Routing</b><br/>The current router setup is used to derive a route between points. <b>Note:</b> The selected router must be able to route on-the-fly. Offline routers usually can do, online routers can't.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="321"/>
+        <source><b>Vector Routing</b><br/>Connect points with a line from a loaded vector map if possible.<br/></source>
+        <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
@@ -3521,27 +3789,214 @@ nebo
     </message>
 </context>
 <context>
+    <name>IRouterMapQuest</name>
+    <message>
+        <location filename="../gis/rte/router/IRouterMapQuest.ui" line="14"/>
+        <source>Form</source>
+        <translation type="unfinished">Formulář</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterMapQuest.ui" line="20"/>
+        <source>t.b.d</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>IRouterRoutino</name>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="14"/>
+        <source>Form</source>
+        <translation type="unfinished">Formulář</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="31"/>
+        <source>Profile</source>
+        <translation type="unfinished">Profil</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="38"/>
+        <source>Mode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="45"/>
+        <source>Database</source>
+        <translation type="unfinished">Databáze</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="52"/>
+        <source>Add paths with Routino database.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="55"/>
+        <source>...</source>
+        <translation type="unfinished">...</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="121"/>
+        <source>To use offline routing you need to define paths to local routing data. Use the setup tool button to register a path.</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>IRouterRoutinoPathSetup</name>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutinoPathSetup.ui" line="14"/>
+        <source>Setup Routino database...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutinoPathSetup.ui" line="27"/>
+        <location filename="../gis/rte/router/IRouterRoutinoPathSetup.ui" line="47"/>
+        <source>...</source>
+        <translation type="unfinished">...</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutinoPathSetup.ui" line="99"/>
+        <source>-</source>
+        <translation type="unfinished">-</translation>
+    </message>
+</context>
+<context>
+    <name>IRouterSetup</name>
+    <message>
+        <location filename="../gis/rte/router/IRouterSetup.ui" line="14"/>
+        <source>Form</source>
+        <translation type="unfinished">Formulář</translation>
+    </message>
+</context>
+<context>
+    <name>IRoutinoDatabaseBuilder</name>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="14"/>
+        <source>Form</source>
+        <translation type="unfinished">Formulář</translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="22"/>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="63"/>
+        <source>...</source>
+        <translation type="unfinished">...</translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="39"/>
+        <source>Select source files:</source>
+        <translation type="unfinished">Vybrat zdrojové soubory:</translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="54"/>
+        <source>Start</source>
+        <translation type="unfinished">Spustit</translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="86"/>
+        <source>Target Path:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="93"/>
+        <source>-</source>
+        <translation type="unfinished">-</translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="100"/>
+        <source>File Prefix</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>IScrOptEditLine</name>
     <message>
-        <location filename="../mouse/IScrOptEditLine.ui" line="26"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="32"/>
         <source>Form</source>
         <translation>Formulář</translation>
     </message>
     <message>
-        <location filename="../mouse/IScrOptEditLine.ui" line="47"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="53"/>
         <source>Save to orignal</source>
         <translation>Uložit do předlohy</translation>
     </message>
     <message>
-        <location filename="../mouse/IScrOptEditLine.ui" line="54"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="60"/>
         <source>Save as new</source>
         <translation>Uložit jako nový</translation>
     </message>
     <message>
-        <location filename="../mouse/IScrOptEditLine.ui" line="61"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="67"/>
         <source>Abort</source>
         <translation>Přerušit</translation>
     </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="102"/>
+        <source>Move points.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="105"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="128"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="148"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="168"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="280"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="297"/>
+        <source>...</source>
+        <translation type="unfinished">...</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="125"/>
+        <source>Add new points.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="145"/>
+        <source>Select a range of points.</source>
+        <translation type="unfinished">Vybrat rozsah bodů.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="165"/>
+        <source>Delete a point.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="216"/>
+        <source>No auto-routing or line snapping</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="219"/>
+        <source>0</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="232"/>
+        <source>Use auto-routing to between points.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="235"/>
+        <source>A</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="248"/>
+        <source>Snap line along lines of a vector map.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="251"/>
+        <source>V</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="277"/>
+        <source>Undo last change</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="294"/>
+        <source>Redo last change</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>IScrOptOvlArea</name>
@@ -3552,19 +4007,34 @@ nebo
     </message>
     <message>
         <location filename="../gis/ovl/IScrOptOvlArea.ui" line="40"/>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="54"/>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="65"/>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="83"/>
+        <source>View details and edit.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="43"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="57"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="71"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="92"/>
         <source>...</source>
         <translation>...</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="51"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="54"/>
         <source>Copy area into another project.</source>
         <translation>Kopírovat oblast do dalšího projektu.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="112"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="68"/>
+        <source>Delete area from project.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="89"/>
+        <source>Edit shape of the area.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="121"/>
         <source>TextLabel</source>
         <translation>Textový štítek</translation>
     </message>
@@ -3630,6 +4100,30 @@ nebo
     </message>
 </context>
 <context>
+    <name>IScrOptRangeLine</name>
+    <message>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="14"/>
+        <source>Form</source>
+        <translation type="unfinished">Formulář</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="20"/>
+        <source>Delete all points between the first and last one.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="23"/>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="37"/>
+        <source>...</source>
+        <translation type="unfinished">...</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="34"/>
+        <source>Caclculate a route between the first and last selected point.</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>IScrOptRangeTrk</name>
     <message>
         <location filename="../mouse/IScrOptRangeTrk.ui" line="14"/>
@@ -3672,14 +4166,16 @@ nebo
         <translation>Formulář</translation>
     </message>
     <message>
-        <location filename="../gis/rte/IScrOptRte.ui" line="28"/>
         <source><html><head/><body><p>View details &amp; Edit</p></body></html></source>
-        <translation><html><head/><body><p>Zobrazit podrobnosti a upravit</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Zobrazit podrobnosti a upravit</p></body></html></translation>
     </message>
     <message>
         <location filename="../gis/rte/IScrOptRte.ui" line="31"/>
         <location filename="../gis/rte/IScrOptRte.ui" line="45"/>
         <location filename="../gis/rte/IScrOptRte.ui" line="59"/>
+        <location filename="../gis/rte/IScrOptRte.ui" line="80"/>
+        <location filename="../gis/rte/IScrOptRte.ui" line="94"/>
+        <location filename="../gis/rte/IScrOptRte.ui" line="108"/>
         <source>...</source>
         <translation>...</translation>
     </message>
@@ -3689,12 +4185,36 @@ nebo
         <translation>Kopírovat cestu do dalšího projektu.</translation>
     </message>
     <message>
-        <location filename="../gis/rte/IScrOptRte.ui" line="56"/>
         <source><html><head/><body><p>Delete</p></body></html></source>
-        <translation><html><head/><body><p>Smazat</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Smazat</p></body></html></translation>
     </message>
     <message>
-        <location filename="../gis/rte/IScrOptRte.ui" line="85"/>
+        <location filename="../gis/rte/IScrOptRte.ui" line="28"/>
+        <source>View details and edit.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="56"/>
+        <source>Delete route from project.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="77"/>
+        <source>Calculate route.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="91"/>
+        <source>Reset route calculation.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="105"/>
+        <source>Move route points.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="134"/>
         <source>TextLabel</source>
         <translation>Textový štítek</translation>
     </message>
@@ -3707,9 +4227,8 @@ nebo
         <translation>Formulář</translation>
     </message>
     <message>
-        <location filename="../gis/trk/IScrOptTrk.ui" line="40"/>
         <source>View details &amp; Edit properties of track.</source>
-        <translation>Zobrazit podrobnosti a upravit vlastnosti stopy.</translation>
+        <translation type="obsolete">Zobrazit podrobnosti a upravit vlastnosti stopy.</translation>
     </message>
     <message>
         <location filename="../gis/trk/IScrOptTrk.ui" line="54"/>
@@ -3717,9 +4236,8 @@ nebo
         <translation>Kopírovat stopu do dalšího projektu.</translation>
     </message>
     <message>
-        <location filename="../gis/trk/IScrOptTrk.ui" line="68"/>
         <source>Delete</source>
-        <translation>Smazat</translation>
+        <translation type="obsolete">Smazat</translation>
     </message>
     <message>
         <location filename="../gis/trk/IScrOptTrk.ui" line="89"/>
@@ -3737,6 +4255,16 @@ nebo
         <translation>Upravit polohu bodů stopy.</translation>
     </message>
     <message>
+        <location filename="../gis/trk/IScrOptTrk.ui" line="40"/>
+        <source>View details and edit properties of track.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/trk/IScrOptTrk.ui" line="68"/>
+        <source>Delete track from project.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
         <location filename="../gis/trk/IScrOptTrk.ui" line="106"/>
         <source>Select a range of points.</source>
         <translation>Vybrat rozsah bodů.</translation>
@@ -3786,17 +4314,21 @@ nebo
         <translation>Formulář</translation>
     </message>
     <message>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="49"/>
         <source><html><head/><body><p>View details &amp; Edit</p></body></html></source>
-        <translation><html><head/><body><p>Zobrazit podrobnosti a upravit</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Zobrazit podrobnosti a upravit</p></body></html></translation>
+    </message>
+    <message>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="49"/>
+        <source>View details and edit.</source>
+        <translation type="unfinished"></translation>
     </message>
     <message>
         <location filename="../gis/wpt/IScrOptWpt.ui" line="52"/>
         <location filename="../gis/wpt/IScrOptWpt.ui" line="66"/>
         <location filename="../gis/wpt/IScrOptWpt.ui" line="80"/>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="98"/>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="115"/>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="129"/>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="101"/>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="118"/>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="132"/>
         <source>...</source>
         <translation>...</translation>
     </message>
@@ -3807,21 +4339,38 @@ nebo
     </message>
     <message>
         <location filename="../gis/wpt/IScrOptWpt.ui" line="77"/>
+        <source>Delete waypoint from project.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="98"/>
+        <source>Show content as static bubble.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="115"/>
+        <source>Move waypoint to a new location.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="129"/>
+        <source>Clone waypoint and move clone a given distance and angle.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
         <source><html><head/><body><p>Delete</p></body></html></source>
-        <translation><html><head/><body><p>Smazat</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Smazat</p></body></html></translation>
     </message>
     <message>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="112"/>
         <source><html><head/><body><p>Move waypoint to a new location.</p></body></html></source>
-        <translation><html><head/><body><p>Přesunout cestovní bod do nového umístění.</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Přesunout cestovní bod do nového umístění.</p></body></html></translation>
     </message>
     <message>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="126"/>
         <source><html><head/><body><p>Clone waypoint and move clone a given distance and angle.</p></body></html></source>
-        <translation><html><head/><body><p>Klonovat cestovní bod a přesunout kopii o danou vzdálenost a ve stanoveném úhlu.</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Klonovat cestovní bod a přesunout kopii o danou vzdálenost a ve stanoveném úhlu.</p></body></html></translation>
     </message>
     <message>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="173"/>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="176"/>
         <source>TextLabel</source>
         <translation>Textový štítek</translation>
     </message>
@@ -4051,11 +4600,11 @@ nebo
     <name>ISetupFolder</name>
     <message>
         <source>Folder...</source>
-        <translation type="vanished">Složka...</translation>
+        <translation type="obsolete">Složka...</translation>
     </message>
     <message>
         <source>Name</source>
-        <translation type="vanished">Název</translation>
+        <translation type="obsolete">Název</translation>
     </message>
     <message>
         <location filename="../gis/db/ISetupFolder.ui" line="14"/>
@@ -4382,16 +4931,16 @@ nebo
     </message>
     <message>
         <source>Bad position format. Must be: [N|S] ddd mm.sss [W|E] ddd mm.sss</source>
-        <translation type="vanished">Špatný polohový formát. Musí být: "[N|S] ddd mm.sss [W|E] ddd mm.sss"</translation>
+        <translation type="obsolete">Špatný polohový formát. Musí být: "[N|S] ddd mm.sss [W|E] ddd mm.sss"</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="109"/>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="118"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="111"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="120"/>
         <source>Failed to read...</source>
         <translation>Nepodařilo se přečíst...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="109"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="111"/>
         <source>Failed to read: %1
 line %2, column %3:
  %4</source>
@@ -4400,7 +4949,7 @@ line %2, column %3:
 %4</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="118"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="120"/>
         <source>Not a GPX file: </source>
         <translation>Není souborem GPX: </translation>
     </message>
@@ -4435,44 +4984,64 @@ Areas: %1</source>
 Oblasti: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="69"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="78"/>
         <source>Save project?</source>
         <translation>Uložit projekt?</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="69"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="78"/>
         <source>The project "%1" was changed. Save befor closing it?</source>
         <translation>Projekt "%1" byl změněn. Uložit jej před zavřením?</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="261"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="211"/>
+        <source>%1: Correlate tracks and waypoints.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/IGisProject.cpp" line="211"/>
+        <source>Abort</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/IGisProject.cpp" line="223"/>
+        <source>Did that take too long for you? Do you want to skip correlation of tracks and waypoints for this project (%1) in the future?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/IGisProject.cpp" line="224"/>
+        <source>Cancelled correlation...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/IGisProject.cpp" line="302"/>
         <source><br/>
 Filename: %1</source>
         <translation><br/>
 Název souboru: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="278"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="307"/>
         <source>Waypoints: %1</source>
         <translation>Cestovní body: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="282"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="311"/>
         <source>Tracks: %1</source>
         <translation>Stopy: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="286"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="315"/>
         <source>Routes: %1</source>
         <translation>Cesty: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="290"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="319"/>
         <source>Areas: %1</source>
         <translation>Oblasti: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="370"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="399"/>
         <source>Are you sure you want to delete '%1' from project '%2'?</source>
         <translation>Jste si jistý, že chcete smazat '%1' z projektu '%2'?</translation>
     </message>
@@ -4483,28 +5052,28 @@ Název souboru: %1</translation>
     </message>
     <message>
         <location filename="../gis/CGisListDB.cpp" line="436"/>
-        <location filename="../gis/prj/IGisProject.cpp" line="371"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="400"/>
         <source>Delete...</source>
         <translation>Smazat...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="96"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="98"/>
         <location filename="../gis/qms/CQmsProject.cpp" line="48"/>
-        <location filename="../gis/qms/CQmsProject.cpp" line="144"/>
+        <location filename="../gis/qms/CQmsProject.cpp" line="145"/>
         <source>Failed to open...</source>
         <translation>Nepodařilo se otevřít...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="96"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="98"/>
         <location filename="../gis/qms/CQmsProject.cpp" line="48"/>
-        <location filename="../gis/qms/CQmsProject.cpp" line="144"/>
+        <location filename="../gis/qms/CQmsProject.cpp" line="145"/>
         <source>Failed to open %1</source>
         <translation>Nepodařilo se otevřít %1</translation>
     </message>
     <message>
         <location filename="../gis/db/CDBProject.cpp" line="149"/>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="216"/>
-        <location filename="../gis/qms/CQmsProject.cpp" line="94"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="223"/>
+        <location filename="../gis/qms/CQmsProject.cpp" line="95"/>
         <location filename="../gis/tnv/CTwoNavProject.cpp" line="159"/>
         <source>Save GIS data to...</source>
         <translation>Uložit data GIS do...</translation>
@@ -4520,27 +5089,27 @@ Název souboru: %1</translation>
         <translation>Zrušit ukládání</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="291"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="298"/>
         <source>File exists ...</source>
         <translation>Soubor existuje...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="292"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="299"/>
         <source>The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains GPX data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file.  Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b></source>
         <translation>Soubor existuje a nebyl vytvořen programem QMapShack. Pokud stisknete Ano, budou všechna data v tomto souboru ztracena. I když by tento soubor obsahoval data GPX a byl nahrán programem QMapShack, QMapShack nemusí být schopen nahrát a uložit všechny prvky tohoto souboru.  Tyto prvky budou ztraceny. Doporučuje se použít jiný soubor. <b>Opravdu chcete soubor přepsat?</b></translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="407"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="421"/>
         <source>Saveing GIS data failed...</source>
         <translation>Nepodařilo se uložit data GIS...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="393"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="407"/>
         <source>Failed to create file '%1'</source>
         <translation>Nepodařilo se vytvořit soubor '%1'</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="402"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="416"/>
         <source>Failed to write file '%1'</source>
         <translation>Nepodařilo se zapsat soubor '%1'</translation>
     </message>
@@ -4594,99 +5163,101 @@ Název souboru: %1</translation>
         <translation><p>--- žádné odkazy ---</p></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="416"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="227"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="441"/>
         <source>Length: %1 %2</source>
         <translation>Délka: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="423"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="448"/>
         <source>, %1%2 %3, %4%5 %6</source>
         <translation>, %1%2 %3, %4%5 %6</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="431"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="243"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="456"/>
         <source>Time: %1</source>
         <translation>Čas: %1</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="434"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="444"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="459"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="469"/>
         <source>, Speed: %1 %2</source>
         <translation>, Rychlost: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="441"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="466"/>
         <source>Moving: %1</source>
         <translation>Pohyb: %1</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="450"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="475"/>
         <source>Start: %1</source>
         <translation>Začátek: %1</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="455"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="480"/>
         <source>End: %1</source>
         <translation>Konec: %1</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="459"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="484"/>
         <source>Points: %1 (%2)</source>
         <translation>Body: %1 (%2)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="577"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="602"/>
         <source>Ele.: %1 %2</source>
         <translation>Výška: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="580"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="605"/>
         <source> slope: %1%3 (%2%)</source>
         <translation> sklon: %1%3 (%2%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="651"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="676"/>
         <source>Ascend: %1%2</source>
         <translation>Stoupání: %1%2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="656"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="673"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="681"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="698"/>
         <source>, %1%2</source>
         <translation>, %1%2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="661"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="686"/>
         <source>Ascend: -</source>
         <translation>Stoupání: -</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="668"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="693"/>
         <source> Descend: %1%2</source>
         <translation> Klesání: %1%2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="678"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="703"/>
         <source>Descend: -</source>
         <translation>Klesání: -</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="684"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="709"/>
         <source>Dist.: %1%2</source>
         <translation>Vzdál.: %1%2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="689"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="714"/>
         <source> Time: %1%2</source>
         <translation> Čas: %1%2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1370"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1403"/>
         <source>Hide points.</source>
         <translation>Skrýt body.</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1416"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1449"/>
         <source>Show points.</source>
         <translation>Ukázat body.</translation>
     </message>
@@ -4695,32 +5266,32 @@ Název souboru: %1</translation>
         <translation type="obsolete"> sklon: %1°(%2%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="585"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="610"/>
         <source> speed: %1%2</source>
         <translation> rychlost: %1%2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="597"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="622"/>
         <source>Ascend: %1%2 (%3%)</source>
         <translation>Stoupání: %1%2 (%3%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="601"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="626"/>
         <source>Ascend: - (-)</source>
         <translation>Stoupání: - (-)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="611"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="636"/>
         <source> Descend: - (-) </source>
         <translation> Klesání: - (-) </translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="632"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="657"/>
         <source> Moving: - (-) </source>
         <translation> Pohyb: - (-) </translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="607"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="632"/>
         <source> Descend: %1%2 (%3%)</source>
         <translation> Klesání: %1%2 (%3%) </translation>
     </message>
@@ -4734,17 +5305,17 @@ Název souboru: %1</translation>
         <translation type="obsolete"> sklon: %1° (%2%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="618"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="643"/>
         <source>Dist.: %1%2 (%3%)</source>
         <translation>Vzdálenost: %1%2 (%3%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="622"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="647"/>
         <source>Dist.: - (-)</source>
         <translation>Vzdálenost: - (-)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="628"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="653"/>
         <source> Moving: %1%2 (%3%)</source>
         <translation> Pohyb: %1%2 (%3%) </translation>
     </message>
@@ -4770,63 +5341,63 @@ Název souboru: %1</translation>
     </message>
     <message>
         <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="142"/>
-        <location filename="../gis/rte/CGisItemRte.cpp" line="45"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="49"/>
         <location filename="../gis/trk/CGisItemTrk.cpp" line="184"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="131"/>
         <source>_Clone</source>
         <translation>_Klon</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="433"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="444"/>
         <source>Area: %1%2</source>
         <translation>Oblast: %1%2</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="491"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="502"/>
         <source>Changed area shape.</source>
         <translation>Změněn tvar oblasti.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="499"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="510"/>
         <source>Changed name.</source>
         <translation>Změněn název.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="505"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="516"/>
         <source>Changed border width.</source>
         <translation>Změněna šířka okraje.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="511"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="522"/>
         <source>Changed fill pattern.</source>
         <translation>Změněn vzor výplně.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="517"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="528"/>
         <source>Changed opacity.</source>
         <translation>Změněna neprůhlednost.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="523"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="534"/>
         <source>Changed comment.</source>
         <translation>Změněna poznámka.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="529"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="540"/>
         <source>Changed description.</source>
         <translation>Změněn popis.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="535"/>
-        <location filename="../gis/rte/CGisItemRte.cpp" line="154"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1775"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="546"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="204"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1808"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="448"/>
         <source>Changed links</source>
         <translation>Změněné odkazy</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="547"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1787"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="558"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1820"/>
         <source>Changed color</source>
         <translation>Změněná barva</translation>
     </message>
@@ -4841,25 +5412,27 @@ Název souboru: %1</translation>
         <translation>Blízkost: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1757"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1790"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="396"/>
         <source>Changed name</source>
         <translation>Změněný název</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1168"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1183"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1202"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1261"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1441"/>
-        <location filename="../mouse/CMouseEditArea.cpp" line="100"/>
-        <location filename="../mouse/CMouseEditTrk.cpp" line="104"/>
+        <location filename="../gis/rte/CCreateRouteFromWpt.cpp" line="65"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1201"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1216"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1235"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1294"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1474"/>
+        <location filename="../mouse/CMouseEditArea.cpp" line="99"/>
+        <location filename="../mouse/CMouseEditRte.cpp" line="109"/>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="115"/>
         <source>Edit name...</source>
         <translation>Upravit název...</translation>
     </message>
     <message>
         <source>Enter new waypoint name.</source>
-        <translation type="vanished">Zadat nový název pro cestovní bod.</translation>
+        <translation type="obsolete">Zadat nový název pro cestovní bod.</translation>
     </message>
     <message>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="406"/>
@@ -4892,20 +5465,55 @@ Název souboru: %1</translation>
         <translation>Přidat obrázek</translation>
     </message>
     <message>
-        <location filename="../gis/rte/CGisItemRte.cpp" line="142"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1763"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="192"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1796"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="436"/>
         <source>Changed comment</source>
         <translation>Změněná poznámka</translation>
     </message>
     <message>
-        <location filename="../gis/rte/CGisItemRte.cpp" line="148"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1769"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="198"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1802"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="442"/>
         <source>Changed description</source>
         <translation>Změněný popis</translation>
     </message>
     <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="231"/>
+        <source>Length: -</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="239"/>
+        <source>Time: %2 days %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="248"/>
+        <source>Time: -</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="254"/>
+        <source>Last time routed:<br/>%1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="256"/>
+        <source>with %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="258"/>
+        <source>Calculation took %1 sec.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="479"/>
+        <source>Changed route points.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
         <location filename="../gis/gpx/serialization.cpp" line="599"/>
         <source>Archived</source>
         <translation>Archivováno</translation>
@@ -4937,17 +5545,17 @@ Název souboru: %1</translation>
         <translation>Toto je souborový typ s neznámým druhem čáry. Nahlašte to, prosím!</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1168"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1183"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1202"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1261"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1441"/>
-        <location filename="../mouse/CMouseEditTrk.cpp" line="104"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1201"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1216"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1235"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1294"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1474"/>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="115"/>
         <source>Enter new track name.</source>
         <translation>Zadat název nové stopy.</translation>
     </message>
     <message>
-        <location filename="../mouse/CMouseEditArea.cpp" line="100"/>
+        <location filename="../mouse/CMouseEditArea.cpp" line="99"/>
         <source>Enter new area name.</source>
         <translation>Zadat název nové oblasti.</translation>
     </message>
@@ -5048,12 +5656,12 @@ Název souboru: %1</translation>
         <translation>Rychlost změněna na %1%2.</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="956"/>
+        <location filename="../gis/CGisListWks.cpp" line="988"/>
         <source>Delete project...</source>
         <translation>Smazat projekt...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="956"/>
+        <location filename="../gis/CGisListWks.cpp" line="988"/>
         <source>Do you really want to delete %1?</source>
         <translation>Opravdu chcete smazat %1?</translation>
     </message>
@@ -5064,13 +5672,13 @@ Název souboru: %1</translation>
         <location filename="../gis/tnv/serialization.cpp" line="431"/>
         <location filename="../gis/tnv/serialization.cpp" line="460"/>
         <location filename="../gis/tnv/serialization.cpp" line="471"/>
-        <location filename="../gis/tnv/serialization.cpp" line="492"/>
-        <location filename="../gis/tnv/serialization.cpp" line="632"/>
-        <location filename="../gis/tnv/serialization.cpp" line="660"/>
-        <location filename="../gis/tnv/serialization.cpp" line="671"/>
-        <location filename="../gis/tnv/serialization.cpp" line="689"/>
-        <location filename="../gis/tnv/serialization.cpp" line="717"/>
-        <location filename="../gis/tnv/serialization.cpp" line="791"/>
+        <location filename="../gis/tnv/serialization.cpp" line="504"/>
+        <location filename="../gis/tnv/serialization.cpp" line="644"/>
+        <location filename="../gis/tnv/serialization.cpp" line="672"/>
+        <location filename="../gis/tnv/serialization.cpp" line="683"/>
+        <location filename="../gis/tnv/serialization.cpp" line="701"/>
+        <location filename="../gis/tnv/serialization.cpp" line="729"/>
+        <location filename="../gis/tnv/serialization.cpp" line="803"/>
         <source>Error...</source>
         <translation>Chyba...</translation>
     </message>
@@ -5079,23 +5687,23 @@ Název souboru: %1</translation>
         <location filename="../gis/tnv/CTwoNavProject.cpp" line="191"/>
         <location filename="../gis/tnv/serialization.cpp" line="295"/>
         <location filename="../gis/tnv/serialization.cpp" line="431"/>
-        <location filename="../gis/tnv/serialization.cpp" line="632"/>
+        <location filename="../gis/tnv/serialization.cpp" line="644"/>
         <source>Failed to open %1.</source>
         <translation>Nepodařilo se otevřít %1.</translation>
     </message>
     <message>
         <location filename="../gis/tnv/serialization.cpp" line="460"/>
         <location filename="../gis/tnv/serialization.cpp" line="471"/>
-        <location filename="../gis/tnv/serialization.cpp" line="660"/>
-        <location filename="../gis/tnv/serialization.cpp" line="671"/>
+        <location filename="../gis/tnv/serialization.cpp" line="672"/>
+        <location filename="../gis/tnv/serialization.cpp" line="683"/>
         <source>Only support lon/lat WGS 84 format.</source>
         <translation>Jako formát je podporován jen lon/lat WGS 84.</translation>
     </message>
     <message>
-        <location filename="../gis/tnv/serialization.cpp" line="492"/>
-        <location filename="../gis/tnv/serialization.cpp" line="689"/>
-        <location filename="../gis/tnv/serialization.cpp" line="717"/>
-        <location filename="../gis/tnv/serialization.cpp" line="791"/>
+        <location filename="../gis/tnv/serialization.cpp" line="504"/>
+        <location filename="../gis/tnv/serialization.cpp" line="701"/>
+        <location filename="../gis/tnv/serialization.cpp" line="729"/>
+        <location filename="../gis/tnv/serialization.cpp" line="803"/>
         <source>Failed to read data.</source>
         <translation>Nepodařilo se přečíst data.</translation>
     </message>
@@ -5105,9 +5713,15 @@ Název souboru: %1</translation>
         <translation>Obrázek %1</translation>
     </message>
     <message>
-        <location filename="../device/IDevice.cpp" line="202"/>
+        <location filename="../device/IDevice.cpp" line="204"/>
         <source>There is another project with the same name. If you press 'ok' it will be removed and replaced.</source>
         <translation>Je jiný projekt se stejným názvem. Pokud stisknete OK, bude odstraněn a nahrazen.</translation>
     </message>
+    <message>
+        <location filename="../gis/rte/CCreateRouteFromWpt.cpp" line="65"/>
+        <location filename="../mouse/CMouseEditRte.cpp" line="109"/>
+        <source>Enter new route name.</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 </TS>
diff --git a/src/locale/qmapshack_de.ts b/src/locale/qmapshack_de.ts
index a1f9602..0a3430d 100644
--- a/src/locale/qmapshack_de.ts
+++ b/src/locale/qmapshack_de.ts
@@ -8,7 +8,7 @@
         <translation type="obsolete">Ansicht %1</translation>
     </message>
     <message>
-        <location filename="../canvas/CCanvas.cpp" line="63"/>
+        <location filename="../canvas/CCanvas.cpp" line="64"/>
         <source>View %1</source>
         <translation>Ansicht %1</translation>
     </message>
@@ -53,7 +53,7 @@
         <location filename="../dem/CDemVRT.cpp" line="45"/>
         <location filename="../dem/CDemVRT.cpp" line="52"/>
         <location filename="../dem/CDemVRT.cpp" line="61"/>
-        <location filename="../dem/CDemVRT.cpp" line="88"/>
+        <location filename="../dem/CDemVRT.cpp" line="89"/>
         <source>Error...</source>
         <translation>Fehler...</translation>
     </message>
@@ -73,7 +73,7 @@
         <translation type="obsolete">Das DEM muss aus einem Satz mit 16 bit oder 32 bit Daten bestehen.</translation>
     </message>
     <message>
-        <location filename="../dem/CDemVRT.cpp" line="88"/>
+        <location filename="../dem/CDemVRT.cpp" line="89"/>
         <source>No georeference information found.</source>
         <translation>Keine Georeferenzierung gefunden.</translation>
     </message>
@@ -116,7 +116,7 @@
     </message>
     <message>
         <source>Enter new waypoint name.</source>
-        <translation type="vanished">Geben Sie einen neuen Namen für den Wegpunkt ein.</translation>
+        <translation type="obsolete">Geben Sie einen neuen Namen für den Wegpunkt ein.</translation>
     </message>
     <message>
         <source><h4>Comment:</h4></source>
@@ -138,81 +138,91 @@
 <context>
     <name>CDetailsPrj</name>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="175"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="537"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="188"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="550"/>
         <source>none</source>
         <translation>keine</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="234"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="247"/>
         <source>Build diary...</source>
         <translation>Tagebuch erstellen...</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="234"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="247"/>
         <source>Abort</source>
         <translation>Abbrechen</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="292"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="305"/>
         <source><h2>Waypoints</h2></source>
         <translation><h2>Wegpunkte</h2></translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="255"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="299"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="330"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="438"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="268"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="312"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="343"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="451"/>
         <source>Info</source>
         <translation>Information</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="256"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="300"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="331"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="439"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="269"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="313"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="344"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="452"/>
         <source>Comment</source>
         <translation>Kommentar</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="323"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="336"/>
         <source><h2>Tracks</h2></source>
         <translation><h2>Tracks</h2></translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="248"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="261"/>
         <source><h2>Areas</h2></source>
         <translation><h2>Gebiete</h2></translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="461"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="82"/>
+        <source>You want to sort waypoints along a track, but you switched off track and waypoint correlation. Do you want to switch it on again?</source>
+        <translation>Sie wollen Wegpunkte entlang eines Tracks sortieren, aber Sie haben die Verknüpfung von Wegpunkten und Tracks ausgeschaltet. Wollen Sie sie wieder anschalten?</translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="83"/>
+        <source>Correlation...</source>
+        <translation>Verknüpfungen...</translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="474"/>
         <source>distance: %1%2</source>
         <translation>Entfernung: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="463"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="476"/>
         <source>ascent: %1%2</source>
         <translation>Anstieg: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="465"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="478"/>
         <source>descend: %1%2</source>
         <translation>Abstieg: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="523"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="550"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="536"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="563"/>
         <source>Edit name...</source>
         <translation>Name bearbeiten...</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="523"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="550"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="536"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="563"/>
         <source>Enter new project name.</source>
         <translation>Geben Sie einen neuen Namen für das Projekt ein.</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="666"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="679"/>
         <source>Print Diary</source>
         <translation>Tagebuch drucken</translation>
     </message>
@@ -221,12 +231,12 @@
         <translation type="obsolete">Name eingeben.</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="532"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="545"/>
         <source>Edit keywords...</source>
         <translation>Stichwörter bearbeiten...</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="532"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="545"/>
         <source>Enter keywords.</source>
         <translation>Stichwörter eingeben.</translation>
     </message>
@@ -264,12 +274,12 @@
         <translation></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CDetailsTrk.cpp" line="397"/>
+        <location filename="../gis/trk/CDetailsTrk.cpp" line="395"/>
         <source>Edit name...</source>
         <translation>Name bearbeiten...</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CDetailsTrk.cpp" line="397"/>
+        <location filename="../gis/trk/CDetailsTrk.cpp" line="395"/>
         <source>Enter new track name.</source>
         <translation>Geben Sie einen neuen Namen für den Track ein.</translation>
     </message>
@@ -418,7 +428,7 @@
     <message>
         <location filename="../gis/CGisListDB.cpp" line="347"/>
         <source>Are you sure you want to delete all items from Lost&Found? This will remove them permanently.</source>
-        <translation>Sind Sie sicher, dass Sie alle Elemente in Verloren & Gefunden löschen wollen? Sie werden dauerhaftentfernt.</translation>
+        <translation>Sind Sie sicher, dass Sie alle Elemente in Verloren & Gefunden löschen wollen? Sie werden dauerhaft entfernt.</translation>
     </message>
     <message>
         <location filename="../gis/CGisListDB.cpp" line="362"/>
@@ -429,58 +439,78 @@
 <context>
     <name>CGisListWks</name>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="96"/>
+        <location filename="../gis/CGisListWks.cpp" line="97"/>
         <source>Save</source>
         <translation>Speichern</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="95"/>
+        <location filename="../gis/CGisListWks.cpp" line="96"/>
         <source>Save As...</source>
         <translation>Speichern unter...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="94"/>
+        <location filename="../gis/CGisListWks.cpp" line="95"/>
         <source>Edit..</source>
         <translation>Bearbeiten..</translation>
     </message>
     <message>
         <source>Update Project on Devices</source>
-        <translation type="vanished">Aktualisiere das Projekt auf allen Geräten </translation>
+        <translation type="obsolete">Aktualisiere das Projekt auf allen Geräten </translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="98"/>
+        <location filename="../gis/CGisListWks.cpp" line="99"/>
         <source>Close</source>
         <translation>Schließen</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="104"/>
+        <location filename="../gis/CGisListWks.cpp" line="105"/>
         <source>Update Project on Device</source>
         <translation>Aktualisiere das Projekt auf dem Gerät</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="116"/>
+        <location filename="../gis/CGisListWks.cpp" line="117"/>
         <source>Edit...</source>
         <translation>Bearbeiten...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="117"/>
+        <location filename="../gis/CGisListWks.cpp" line="118"/>
         <source>Copy to...</source>
         <translation>Kopieren nach...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="132"/>
+        <location filename="../gis/CGisListWks.cpp" line="133"/>
         <source>Show Bubble</source>
         <translation>Infoblase anzeigen</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="134"/>
+        <location filename="../gis/CGisListWks.cpp" line="135"/>
         <source>Move Waypoint</source>
         <translation>Wegpunkt verschieben</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="596"/>
-        <location filename="../gis/CGisListWks.cpp" line="1296"/>
-        <location filename="../gis/CGisListWks.cpp" line="1335"/>
+        <location filename="../gis/CGisListWks.cpp" line="144"/>
+        <source>Calculate Route</source>
+        <translation>Route berechnen</translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisListWks.cpp" line="145"/>
+        <source>Reset Route</source>
+        <translation>Route zurücksetzen</translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisListWks.cpp" line="146"/>
+        <source>Edit Route</source>
+        <translation>Route bearbeiten</translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisListWks.cpp" line="162"/>
+        <source>Create Route</source>
+        <translation>Route erstellen</translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisListWks.cpp" line="608"/>
+        <location filename="../gis/CGisListWks.cpp" line="1371"/>
+        <location filename="../gis/CGisListWks.cpp" line="1409"/>
         <source><b>Update devices</b><p>Update %1<br/>Please wait...</p></source>
         <translation><b>Aktualisieren der Geräte</b><p>Aktualisiere %1<br/>Bitte warten...</p></translation>
     </message>
@@ -489,74 +519,74 @@
         <translation type="obsolete">Wegpunkt verschieben...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="135"/>
+        <location filename="../gis/CGisListWks.cpp" line="136"/>
         <source>Proj. Waypoint...</source>
         <translation>Wegpunkt Projektion...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="119"/>
+        <location filename="../gis/CGisListWks.cpp" line="120"/>
         <source>Track Profile</source>
         <translation>Trackprofil</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="97"/>
+        <location filename="../gis/CGisListWks.cpp" line="98"/>
         <source>Send to Devices</source>
         <translation>Ans Gerät senden</translation>
     </message>
     <message>
         <source>Lock/Unlock</source>
-        <translation type="vanished">Sperren/Entsperren</translation>
+        <translation type="obsolete">Sperren/Entsperren</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="121"/>
+        <location filename="../gis/CGisListWks.cpp" line="122"/>
         <source>Select Range</source>
         <translation>Bereich wählen</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="122"/>
+        <location filename="../gis/CGisListWks.cpp" line="123"/>
         <source>Edit Track Points</source>
         <translation>Trackpunkte bearbeiten</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="123"/>
+        <location filename="../gis/CGisListWks.cpp" line="124"/>
         <source>Reverse Track</source>
         <translation>Track umkehren</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="124"/>
+        <location filename="../gis/CGisListWks.cpp" line="125"/>
         <source>Combine Tracks</source>
         <translation>Tracks verbinden</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="149"/>
+        <location filename="../gis/CGisListWks.cpp" line="155"/>
         <source>Edit Area Points</source>
         <translation>Gebietspunkte bearbeiten</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="105"/>
-        <location filename="../gis/CGisListWks.cpp" line="126"/>
+        <location filename="../gis/CGisListWks.cpp" line="106"/>
+        <location filename="../gis/CGisListWks.cpp" line="127"/>
         <source>Delete</source>
         <translation>Löschen</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="696"/>
+        <location filename="../gis/CGisListWks.cpp" line="708"/>
         <source>Saving workspace. Please wait.</source>
-        <translation>Ansicht speichern. Bitte warten.</translation>
+        <translation>Arbeitsplatz speichern. Bitte warten.</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="737"/>
+        <location filename="../gis/CGisListWks.cpp" line="750"/>
         <source>Loading workspace. Please wait.</source>
-        <translation>Ansicht laden. Bitte warten.</translation>
+        <translation>Arbeitsplatz laden. Bitte warten.</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="921"/>
+        <location filename="../gis/CGisListWks.cpp" line="952"/>
         <source>Close all projects...</source>
         <translation>Alle Projekte schließen...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="921"/>
+        <location filename="../gis/CGisListWks.cpp" line="952"/>
         <source>This will remove all projects from the workspace.</source>
-        <translation>Dies wird alle Projekte aus der Ansicht entfernen.</translation>
+        <translation>Dies wird alle Projekte aus dem Arbeitsplatz entfernen.</translation>
     </message>
     <message>
         <source>Add Empty Project</source>
@@ -570,12 +600,22 @@
 <context>
     <name>CGisWidget</name>
     <message>
-        <location filename="../gis/CGisWidget.cpp" line="444"/>
+        <location filename="../gis/CGisWidget.cpp" line="114"/>
+        <source>Load project...</source>
+        <translation>Lade Projekt...</translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisWidget.cpp" line="114"/>
+        <source>The project "%1" is already in the workspace.</source>
+        <translation>Das Projekt "%1" ist schon im Arbeitsplatz geladen.</translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisWidget.cpp" line="449"/>
         <source>Cut Track...</source>
         <translation>Track teilen...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisWidget.cpp" line="444"/>
+        <location filename="../gis/CGisWidget.cpp" line="449"/>
         <source>Do you want to delete the original track?</source>
         <translation>Wollen Sie den ursprünglichen Track löschen?</translation>
     </message>
@@ -587,12 +627,12 @@
         <translation type="obsolete">[Gitter: %1]</translation>
     </message>
     <message>
-        <location filename="../grid/CGrid.cpp" line="61"/>
+        <location filename="../grid/CGrid.cpp" line="63"/>
         <source>[Grid: %1%2%5 %3%4%5] </source>
         <translation>[Gitter: %1%2%5 %3%4%5] </translation>
     </message>
     <message>
-        <location filename="../grid/CGrid.cpp" line="65"/>
+        <location filename="../grid/CGrid.cpp" line="67"/>
         <source>[Grid: N %1m, E %2m] </source>
         <translation>[Gitter: N %1m, E %2m]</translation>
     </message>
@@ -608,17 +648,17 @@
 <context>
     <name>CImportDatabase</name>
     <message>
-        <location filename="../qlgt/CImportDatabase.cpp" line="29"/>
+        <location filename="../tool/CImportDatabase.cpp" line="29"/>
         <source>Import QLandkarte Database</source>
         <translation>QLandkarte Datenbank importieren</translation>
     </message>
     <message>
-        <location filename="../qlgt/CImportDatabase.cpp" line="73"/>
+        <location filename="../tool/CImportDatabase.cpp" line="73"/>
         <source>Select source database...</source>
         <translation>Quelldatenbank wählen...</translation>
     </message>
     <message>
-        <location filename="../qlgt/CImportDatabase.cpp" line="93"/>
+        <location filename="../tool/CImportDatabase.cpp" line="93"/>
         <source>Select target database...</source>
         <translation>Zieldatenbank wählen...</translation>
     </message>
@@ -634,22 +674,22 @@
 <context>
     <name>CMainWindow</name>
     <message>
-        <location filename="../CMainWindow.cpp" line="492"/>
+        <location filename="../CMainWindow.cpp" line="560"/>
         <source>Ele: %1%2</source>
         <translation>Höhe: %1%2</translation>
     </message>
     <message>
-        <location filename="../CMainWindow.cpp" line="618"/>
+        <location filename="../CMainWindow.cpp" line="691"/>
         <source>Load GIS Data...</source>
         <translation>GIS Daten laden...</translation>
     </message>
     <message>
-        <location filename="../CMainWindow.cpp" line="652"/>
+        <location filename="../CMainWindow.cpp" line="725"/>
         <source>Select output file</source>
         <translation>Ausgabedatei auswählen</translation>
     </message>
     <message>
-        <location filename="../CMainWindow.cpp" line="678"/>
+        <location filename="../CMainWindow.cpp" line="751"/>
         <source>Select file to load</source>
         <translation>Zu ladende Datei auswählen</translation>
     </message>
@@ -1242,46 +1282,46 @@
         <translation>Lesen der Dateistruktur fehlgeschlagen:</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="640"/>
+        <location filename="../map/CMapIMG.cpp" line="642"/>
         <source>Loading %1</source>
         <translation>Lädt %1</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="645"/>
+        <location filename="../map/CMapIMG.cpp" line="649"/>
         <source>User abort: </source>
         <translation>Benutzerabbruch:</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="648"/>
+        <location filename="../map/CMapIMG.cpp" line="652"/>
         <source>File is NT format. QMapShack is unable to read map files with NT format: </source>
         <translation>Die Datei hat das NT Format. QMapShack kann dieses Format nicht lesen:</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="740"/>
+        <location filename="../map/CMapIMG.cpp" line="744"/>
         <source>File contains locked / encypted data. Garmin does not want you to use this file with any other software than the one supplied by Garmin.</source>
         <translation>Die Datei enthält verschlüsselte Daten. Garmin möchte nicht dass diese Datei mit einer anderen Software, als der von Garmin bereitgestellten, benutzt wird.</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="2496"/>
-        <location filename="../map/CMapIMG.cpp" line="2504"/>
+        <location filename="../map/CMapIMG.cpp" line="2500"/>
         <location filename="../map/CMapIMG.cpp" line="2508"/>
-        <location filename="../map/CMapIMG.cpp" line="2513"/>
-        <location filename="../map/CMapIMG.cpp" line="2559"/>
-        <location filename="../map/CMapIMG.cpp" line="2567"/>
+        <location filename="../map/CMapIMG.cpp" line="2512"/>
+        <location filename="../map/CMapIMG.cpp" line="2517"/>
+        <location filename="../map/CMapIMG.cpp" line="2563"/>
         <location filename="../map/CMapIMG.cpp" line="2571"/>
-        <location filename="../map/CMapIMG.cpp" line="2576"/>
+        <location filename="../map/CMapIMG.cpp" line="2575"/>
+        <location filename="../map/CMapIMG.cpp" line="2580"/>
         <source>Point of Interest</source>
         <translation>Ort von Interesse</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="2703"/>
+        <location filename="../map/CMapIMG.cpp" line="2707"/>
         <source>Unknown</source>
         <translation>Unbekannt</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="2749"/>
-        <location filename="../map/CMapIMG.cpp" line="2757"/>
-        <location filename="../map/CMapIMG.cpp" line="2764"/>
+        <location filename="../map/CMapIMG.cpp" line="2753"/>
+        <location filename="../map/CMapIMG.cpp" line="2761"/>
+        <location filename="../map/CMapIMG.cpp" line="2768"/>
         <source>Area</source>
         <translation>Gebiet</translation>
     </message>
@@ -1335,7 +1375,7 @@
         <translation>Kartenpfad wählen...</translation>
     </message>
     <message>
-        <location filename="../map/CMapPathSetup.cpp" line="78"/>
+        <location filename="../map/CMapPathSetup.cpp" line="81"/>
         <source>Select root path...</source>
         <translation>Hauptverzeichnis auswählen...</translation>
     </message>
@@ -1344,7 +1384,7 @@
     <name>CMapPropSetup</name>
     <message>
         <source>Cache path...</source>
-        <translation type="vanished">Cache Pfad...</translation>
+        <translation type="obsolete">Cache Pfad...</translation>
     </message>
 </context>
 <context>
@@ -1433,7 +1473,7 @@ Zeile %2, Spalte %3:
         <location filename="../map/CMapVRT.cpp" line="47"/>
         <location filename="../map/CMapVRT.cpp" line="61"/>
         <location filename="../map/CMapVRT.cpp" line="89"/>
-        <location filename="../map/CMapVRT.cpp" line="124"/>
+        <location filename="../map/CMapVRT.cpp" line="125"/>
         <source>Error...</source>
         <translation>Fehler...</translation>
     </message>
@@ -1449,7 +1489,7 @@ Zeile %2, Spalte %3:
         <translation>Die Datei muss eine 8 bit Palette haben, oder Graustufen.</translation>
     </message>
     <message>
-        <location filename="../map/CMapVRT.cpp" line="124"/>
+        <location filename="../map/CMapVRT.cpp" line="125"/>
         <source>No georeference information found.</source>
         <translation>Keine Georeferenzierung gefunden.</translation>
     </message>
@@ -1457,22 +1497,22 @@ Zeile %2, Spalte %3:
 <context>
     <name>CMapVrtBuilder</name>
     <message>
-        <location filename="../map/CMapVrtBuilder.cpp" line="29"/>
+        <location filename="../tool/CMapVrtBuilder.cpp" line="29"/>
         <source>Build GDAL VRT</source>
         <translation>GDAL VRT erstellen</translation>
     </message>
     <message>
-        <location filename="../map/CMapVrtBuilder.cpp" line="51"/>
+        <location filename="../tool/CMapVrtBuilder.cpp" line="51"/>
         <source>Select files...</source>
         <translation>Dateien auswählen...</translation>
     </message>
     <message>
-        <location filename="../map/CMapVrtBuilder.cpp" line="75"/>
+        <location filename="../tool/CMapVrtBuilder.cpp" line="75"/>
         <source>Select target file...</source>
         <translation>Zieldatei auswählen...</translation>
     </message>
     <message>
-        <location filename="../map/CMapVrtBuilder.cpp" line="196"/>
+        <location filename="../tool/CMapVrtBuilder.cpp" line="196"/>
         <source>!!! failed !!!
 </source>
         <translation>!!! fehlgeschlagen !!!</translation>
@@ -1485,7 +1525,7 @@ Zeile %2, Spalte %3:
         <location filename="../map/CMapWMTS.cpp" line="55"/>
         <location filename="../map/CMapWMTS.cpp" line="65"/>
         <location filename="../map/CMapWMTS.cpp" line="74"/>
-        <location filename="../map/CMapWMTS.cpp" line="198"/>
+        <location filename="../map/CMapWMTS.cpp" line="206"/>
         <source>Error...</source>
         <translation>Fehler...</translation>
     </message>
@@ -1520,7 +1560,7 @@ Unbekannte Struktur.</translation>
         <translation type="obsolete">--- Alle ---</translation>
     </message>
     <message>
-        <location filename="../map/CMapWMTS.cpp" line="384"/>
+        <location filename="../map/CMapWMTS.cpp" line="392"/>
         <source><b>%1</b>: %2 tiles pending<br/></source>
         <translation><b>%1</b>: %2 unerledigte Kacheln</translation>
     </message>
@@ -1533,7 +1573,7 @@ Unbekannte Struktur.</translation>
         <translation type="obsolete">Unerwarterter Dienst. 'OGC WMTS 1.0.0' Wird erwartet. '%1 %2' wird gelesen.</translation>
     </message>
     <message>
-        <location filename="../map/CMapWMTS.cpp" line="198"/>
+        <location filename="../map/CMapWMTS.cpp" line="206"/>
         <source>No georeference information found.</source>
         <translation>Keine Georeferenzierung gefunden.</translation>
     </message>
@@ -1541,9 +1581,13 @@ Unbekannte Struktur.</translation>
 <context>
     <name>CMouseEditArea</name>
     <message>
-        <location filename="../mouse/CMouseEditArea.cpp" line="38"/>
         <source><b>Edit Area</b><br/>Select a corner point for more options.<br/></source>
-        <translation><b>Gebiet bearbeiten</b><br/>Wähle einen Eckpunkt für mehr Optionen.<br/></translation>
+        <translation type="obsolete"><b>Gebiet bearbeiten</b><br/>Wähle einen Eckpunkt für mehr Optionen.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditArea.cpp" line="37"/>
+        <source><b>Edit Area</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/></source>
+        <translation><b>Gebiet bearbeiten</b><br/>Wählen Sie mittels der Werkzeug-Buttons eine Funkion und einen Routing-Modus. Als nächstes wählen Sie einen Punkt auf der Linie. Es können nur Punkte geändert werden, die mit einem großen Quadrat markiert sind. Schwarze Punkte sind durchs Routing erzeugte Unterpunkte.<br/></translation>
     </message>
 </context>
 <context>
@@ -1566,11 +1610,37 @@ Unbekannte Struktur.</translation>
     </message>
 </context>
 <context>
+    <name>CMouseEditRte</name>
+    <message>
+        <source><b>Edit Route Points</b><br/>Select a route point for more options.<br/></source>
+        <translation type="obsolete"><b>Routenpunkte bearbeiten</b><br/>Wählen Sie einen Routenpunkt für mehr Optionen.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditRte.cpp" line="39"/>
+        <source><b>Edit Route Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/></source>
+        <translation><b>Routenpunkte bearbeiten</b><br/>Wählen Sie mittels der Werkzeug-Buttons eine Funkion und einen Routing-Modus. Als nächstes wählen Sie einen Punkt auf der Linie. Es können nur Punkte geändert werden, die mit einem großen Quadrat markiert sind. Schwarze Punkte sind durchs Routing erzeugte Unterpunkte.<br/></translation>
+    </message>
+</context>
+<context>
     <name>CMouseEditTrk</name>
     <message>
-        <location filename="../mouse/CMouseEditTrk.cpp" line="44"/>
         <source><b>Edit Track Points</b><br/>Select a track point for more options.<br/></source>
-        <translation><b>Trackpunkte bearbeiten</b><br/>Wähle einen Trackpunkt für mehr Optionen.<br/></translation>
+        <translation type="obsolete"><b>Trackpunkte bearbeiten</b><br/>Wähle einen Trackpunkt für mehr Optionen.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="39"/>
+        <source><b>Edit Track Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/></source>
+        <translation><b>Trackpunkte bearbeiten</b><br/>Wählen Sie mittels der Werkzeug-Buttons eine Funkion und einen Routing-Modus. Als nächstes wählen Sie einen Punkt auf der Linie. Es können nur Punkte geändert werden, die mit einem großen Quadrat markiert sind. Schwarze Punkte sind durchs Routing erzeugte Unterpunkte.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="81"/>
+        <source>Warning!</source>
+        <translation>Warnung!</translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="81"/>
+        <source>This will replace all data of the orignal by a simple line of coordinates. All other data will be lost permanently.</source>
+        <translation>Alle ursprünglichen Daten werden durch eine einfache Koordinatenlinie ersetzt. Alle anderen Daten sind dauerhaft verloren.</translation>
     </message>
 </context>
 <context>
@@ -1587,11 +1657,16 @@ Unbekannte Struktur.</translation>
     </message>
     <message>
         <location filename="../mouse/CMouseNormal.cpp" line="44"/>
+        <source>Add Route</source>
+        <translation>Route hinzufügen</translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseNormal.cpp" line="45"/>
         <source>Add Area</source>
         <translation>Gebiet hinzufügen</translation>
     </message>
     <message>
-        <location filename="../mouse/CMouseNormal.cpp" line="46"/>
+        <location filename="../mouse/CMouseNormal.cpp" line="48"/>
         <source>Copy position</source>
         <translation>Position kopieren</translation>
     </message>
@@ -1715,42 +1790,42 @@ ist keine gültige Koordinatensystemdefinition:
 <context>
     <name>CQlgtDb</name>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="304"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="307"/>
         <source>Migrating database from version 4 to 5.</source>
         <translation>Datenbank von Version 4 nach 5 migrieren.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="357"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="361"/>
         <source>Migrating database from version 5 to 6.</source>
         <translation>Datenbank von Version 5 nach 6 migrieren.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="414"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="419"/>
         <source>Migrating database from version 6 to 7.</source>
         <translation>Datenbank von Version 6 nach 7 migrieren.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="480"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="485"/>
         <source>Migrating database from version 7 to 8.</source>
         <translation>Datenbank von Version 7 nach 8 migrieren.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="509"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="514"/>
         <source>Migrating database from version 8 to 9.</source>
         <translation>Datenbank von Version 8 nach 9 migrieren.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="532"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="537"/>
         <source>Open database: %1</source>
         <translation>Öffne Datenbank: %1</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="541"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="546"/>
         <source>Folders:          %1</source>
         <translation>Ordner: %1</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="550"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="555"/>
         <source>Tracks:           %1</source>
         <translation>Tracks: %1</translation>
     </message>
@@ -1759,87 +1834,87 @@ ist keine gültige Koordinatensystemdefinition:
         <translation type="obsolete">Routen: %1 (noch nicht unterstützt)</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="558"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="563"/>
         <source>Routes:           %1 (Only the basic route will be copied)</source>
         <translation>Routen:           %1 (Es wird nur die Basisroute kopiert)</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="566"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="571"/>
         <source>Waypoints:        %1</source>
         <translation>Wegpunkte: %1</translation>
     </message>
     <message>
         <source>Overlays:         %1 (only area overlays will be converted to QMapShack)</source>
-        <translation type="vanished">Overlays:         %1 (Es werden nur Gebietsoverlays nach QMapShack konvertiert)</translation>
+        <translation type="obsolete">Overlays:         %1 (Es werden nur Gebietsoverlays nach QMapShack konvertiert)</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="574"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="579"/>
         <source>Overlays:         %1 (areas will be converted as areas, distance lines will be converted to tracks, all other overlay items will be lost)</source>
         <translation>Overlays:         %1 (Flächen werden als Flächen übernommen, Distanzlinien werden als Tracks übernommen, alle anderen Overlays gehen verloren)</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="581"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="586"/>
         <source>Diaries:          %1</source>
         <translation>Tagebücher:          %1</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="588"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="593"/>
         <source>Map selections:   %1 (can't be converted to QMapShack)</source>
         <translation>Kartenselektionen:   %1 (können nicht nach QMapShack konvertiert werden)</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="594"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="599"/>
         <source>------ Start to convert database to %1------</source>
         <translation>------ Konvertierung der Datenbank %1 beginnt ------</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="598"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="603"/>
         <source>Failed to create target database.</source>
         <translation>Erstellen der Zieldatenbank fehlgeschlagen.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="599"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="604"/>
         <source>------ Abort ------</source>
         <translation>------ Abbrechen ------</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="627"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="632"/>
         <source>------ Done ------</source>
         <translation>------ Fertig ------</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="635"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="640"/>
         <source>Restore folders...</source>
         <translation>Ordner wiederherstellen...</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="635"/>
-        <location filename="../qlgt/CQlgtDb.cpp" line="668"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="640"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="673"/>
         <source>Abort</source>
         <translation>Abbrechen</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="662"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="667"/>
         <source>Imported %1 folders and %2 diaries</source>
         <translation>Importiert wurden %1 Ordner und %2 Tagebücher</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="668"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="673"/>
         <source>Copy items...</source>
         <translation>Elemente kopieren...</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="692"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="697"/>
         <source>Imported %1 tracks, %2 waypoints, %3 routes, %4 areas</source>
         <translation>Importiert wurden %1 Tracks, %2 Wegpunkte, %3 Routen, %4 Gebiete</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="693"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="698"/>
         <source>Import folders...</source>
         <translation>Importiere Ordner...</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="758"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="763"/>
         <source>Overlay of type '%1' cant be converted</source>
         <translation>Das Overlay vom Typ '%1' kann nicht konvertiert werden</translation>
     </message>
@@ -1868,6 +1943,129 @@ ist keine gültige Koordinatensystemdefinition:
     </message>
 </context>
 <context>
+    <name>CRouterRoutino</name>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="34"/>
+        <source>Foot</source>
+        <translation>Fußgänger</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="35"/>
+        <source>Horse</source>
+        <translation>Reiter</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="36"/>
+        <source>Wheelchair</source>
+        <translation>Rollstuhl</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="37"/>
+        <source>Bicycle</source>
+        <translation>Fahrrad</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="38"/>
+        <source>Moped</source>
+        <translation>Moped</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="39"/>
+        <source>Motorcycle</source>
+        <translation>Motorrad</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="40"/>
+        <source>Motorcar</source>
+        <translation>Auto</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="41"/>
+        <source>Goods</source>
+        <translation>LKW</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="43"/>
+        <source>Shortest</source>
+        <translation>Kürzeste</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="44"/>
+        <source>Quickest</source>
+        <translation>Schnellste</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="96"/>
+        <source>profile "%1"</source>
+        <translation>Profil "%1"</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="97"/>
+        <source>, mode "%1"</source>
+        <translation>, Modus "%1"</translation>
+    </message>
+</context>
+<context>
+    <name>CRouterRoutinoPathSetup</name>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutinoPathSetup.cpp" line="40"/>
+        <source>Add or remove paths containing Routino data. There can be multiple databases in a path but no sub-path is parsed.</source>
+        <translation>Pfade mit Routino Daten hinzufügen oder entfernen. In einem Pfad können mehrere Datenbanken sein. Teilpfade werden nicht geparst.</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutinoPathSetup.cpp" line="55"/>
+        <source>Select routing data file path...</source>
+        <translation>Pfad für Routingdatendatei wählen...</translation>
+    </message>
+    <message>
+        <source>Select DEM file path...</source>
+        <translation type="obsolete">Pfad für DEM Dateien wählen...</translation>
+    </message>
+</context>
+<context>
+    <name>CRouterSetup</name>
+    <message>
+        <location filename="../gis/rte/router/CRouterSetup.cpp" line="36"/>
+        <source>Routino (offline)</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterSetup.cpp" line="37"/>
+        <source>MapQuest (online)</source>
+        <translation></translation>
+    </message>
+</context>
+<context>
+    <name>CRoutinoDatabaseBuilder</name>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="32"/>
+        <source>Create Routino Database</source>
+        <translation>Routino Datenbank erstellen</translation>
+    </message>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="63"/>
+        <source>Select files...</source>
+        <translation>Dateien auswählen...</translation>
+    </message>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="87"/>
+        <source>Select target path...</source>
+        <translation>Zielpfad auswählen...</translation>
+    </message>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="211"/>
+        <source>!!! failed !!!
+</source>
+        <translation>!!! fehlgeschlagen !!!</translation>
+    </message>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="218"/>
+        <source>!!! done !!!
+</source>
+        <translation>!!! erledigt !!!</translation>
+    </message>
+</context>
+<context>
     <name>CSearchGoogle</name>
     <message>
         <location filename="../gis/search/CSearchGoogle.cpp" line="119"/>
@@ -2084,6 +2282,20 @@ ist keine gültige Koordinatensystemdefinition:
     </message>
 </context>
 <context>
+    <name>ICreateRouteFromWpt</name>
+    <message>
+        <location filename="../gis/rte/ICreateRouteFromWpt.ui" line="14"/>
+        <source>Create Route from Waypoints</source>
+        <translation>Route aus Wegpunkten erstellen</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/ICreateRouteFromWpt.ui" line="30"/>
+        <location filename="../gis/rte/ICreateRouteFromWpt.ui" line="50"/>
+        <source>...</source>
+        <translation></translation>
+    </message>
+</context>
+<context>
     <name>IDemPathSetup</name>
     <message>
         <location filename="../dem/IDemPathSetup.ui" line="14"/>
@@ -2327,15 +2539,15 @@ ist keine gültige Koordinatensystemdefinition:
     </message>
     <message>
         <source>Sort By Time</source>
-        <translation type="vanished">Sortieren nach Zeit</translation>
+        <translation type="obsolete">Sortieren nach Zeit</translation>
     </message>
     <message>
         <source>Keep Order of Project</source>
-        <translation type="vanished">Reihenfolge beibehalten</translation>
+        <translation type="obsolete">Reihenfolge beibehalten</translation>
     </message>
     <message>
         <source>Sort Along Track</source>
-        <translation type="vanished">Sort. entl. d. Tracks</translation>
+        <translation type="obsolete">Sort. entl. d. Tracks</translation>
     </message>
     <message>
         <location filename="../gis/prj/IDetailsPrj.ui" line="115"/>
@@ -2371,11 +2583,11 @@ ist keine gültige Koordinatensystemdefinition:
     </message>
     <message>
         <source>Sort along track (with doubles)</source>
-        <translation type="vanished">Sort. entl. d. Tracks (mehrfach)</translation>
+        <translation type="obsolete">Sort. entl. d. Tracks (mehrfach)</translation>
     </message>
     <message>
         <source>Sort along track (without doubles)</source>
-        <translation type="vanished">Sort. entl. d. Tracks (einmalig)</translation>
+        <translation type="obsolete">Sort. entl. d. Tracks (einmalig)</translation>
     </message>
     <message>
         <location filename="../gis/prj/IDetailsPrj.ui" line="135"/>
@@ -2472,7 +2684,7 @@ ist keine gültige Koordinatensystemdefinition:
     <message>
         <location filename="../gis/trk/IDetailsTrk.ui" line="478"/>
         <source>Slope</source>
-        <translation>Steigung</translation>
+        <translation>Neigung</translation>
     </message>
     <message>
         <location filename="../gis/trk/IDetailsTrk.ui" line="483"/>
@@ -2573,7 +2785,7 @@ ist keine gültige Koordinatensystemdefinition:
     </message>
     <message>
         <source><html><head/><body><p>Read Only Mode</p></body></html></source>
-        <translation type="vanished"><html><head/><body><p>Schreibschutz</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Schreibschutz</p></body></html></translation>
     </message>
     <message>
         <location filename="../gis/wpt/IDetailsWpt.ui" line="270"/>
@@ -2721,7 +2933,17 @@ ist keine gültige Koordinatensystemdefinition:
         <translation>Ändert den Trackbeginn auf </translation>
     </message>
     <message>
-        <location filename="../gis/trk/filter/IFilterNewDate.ui" line="71"/>
+        <location filename="../gis/trk/filter/IFilterNewDate.ui" line="51"/>
+        <source>dd.MM.yy HH:mm:ss</source>
+        <translation>dd.MM.yy HH:mm:ss</translation>
+    </message>
+    <message>
+        <location filename="../gis/trk/filter/IFilterNewDate.ui" line="61"/>
+        <source>-</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../gis/trk/filter/IFilterNewDate.ui" line="81"/>
         <source>...</source>
         <translation></translation>
     </message>
@@ -2933,37 +3155,37 @@ ist keine gültige Koordinatensystemdefinition:
 <context>
     <name>IImportDatabase</name>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="14"/>
+        <location filename="../tool/IImportDatabase.ui" line="14"/>
         <source>Form</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="45"/>
+        <location filename="../tool/IImportDatabase.ui" line="45"/>
         <source>Source Database:</source>
         <translation>Quelldatenbank:</translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="52"/>
-        <location filename="../qlgt/IImportDatabase.ui" line="93"/>
+        <location filename="../tool/IImportDatabase.ui" line="52"/>
+        <location filename="../tool/IImportDatabase.ui" line="93"/>
         <source>-</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="22"/>
-        <location filename="../qlgt/IImportDatabase.ui" line="63"/>
+        <location filename="../tool/IImportDatabase.ui" line="102"/>
+        <source>Start</source>
+        <translation>Starten</translation>
+    </message>
+    <message>
+        <location filename="../tool/IImportDatabase.ui" line="22"/>
+        <location filename="../tool/IImportDatabase.ui" line="63"/>
         <source>...</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="86"/>
+        <location filename="../tool/IImportDatabase.ui" line="86"/>
         <source>Target Database:</source>
         <translation>Zieldatenbank:</translation>
     </message>
-    <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="102"/>
-        <source>Start</source>
-        <translation></translation>
-    </message>
 </context>
 <context>
     <name>IInputDialog</name>
@@ -3025,37 +3247,37 @@ ist keine gültige Koordinatensystemdefinition:
         <translation>Ansicht</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="98"/>
+        <location filename="../IMainWindow.ui" line="99"/>
         <source>Window</source>
         <translation>Fenster</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="103"/>
+        <location filename="../IMainWindow.ui" line="104"/>
         <source>?</source>
         <translation>?</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="110"/>
+        <location filename="../IMainWindow.ui" line="111"/>
         <source>Project</source>
         <translation>Projekt</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="120"/>
+        <location filename="../IMainWindow.ui" line="121"/>
         <source>Tool</source>
         <translation>Werkzeug</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="138"/>
+        <location filename="../IMainWindow.ui" line="140"/>
         <source>Maps</source>
         <translation>Karten</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="175"/>
+        <location filename="../IMainWindow.ui" line="177"/>
         <source>Dig. Elev. Model (DEM)</source>
         <translation>Dig. Höhenmodell (DEM)</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="208"/>
+        <location filename="../IMainWindow.ui" line="210"/>
         <source>Data</source>
         <translation>Daten</translation>
     </message>
@@ -3064,214 +3286,234 @@ ist keine gültige Koordinatensystemdefinition:
         <translation type="obsolete">Ansicht hinzufügen</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="221"/>
-        <location filename="../IMainWindow.ui" line="224"/>
+        <location filename="../IMainWindow.ui" line="222"/>
+        <source>Route</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../IMainWindow.ui" line="256"/>
+        <location filename="../IMainWindow.ui" line="259"/>
         <source>Add Map View</source>
         <translation>Kartenansicht hinzufügen</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="227"/>
+        <location filename="../IMainWindow.ui" line="262"/>
         <source>Ctrl+T</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="239"/>
+        <location filename="../IMainWindow.ui" line="274"/>
         <source>Show Scale</source>
         <translation>Maßstab</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="248"/>
+        <location filename="../IMainWindow.ui" line="283"/>
         <source>Setup Map Font</source>
         <translation>Kartenfont einstellen</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="260"/>
+        <location filename="../IMainWindow.ui" line="295"/>
         <source>Show Grid</source>
         <translation>Gitter</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="263"/>
+        <location filename="../IMainWindow.ui" line="298"/>
         <source>Ctrl+G</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="272"/>
+        <location filename="../IMainWindow.ui" line="307"/>
         <source>Setup Grid</source>
         <translation>Gitter einstellen</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="275"/>
+        <location filename="../IMainWindow.ui" line="310"/>
         <source>Ctrl+Alt+G</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="287"/>
+        <location filename="../IMainWindow.ui" line="322"/>
         <source>Flip Mouse Wheel</source>
         <translation>Mausrad umdrehen</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="296"/>
-        <location filename="../IMainWindow.ui" line="299"/>
+        <location filename="../IMainWindow.ui" line="331"/>
+        <location filename="../IMainWindow.ui" line="334"/>
         <source>Setup Map Paths</source>
         <translation>Kartenverzeichnisse angeben</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="311"/>
+        <location filename="../IMainWindow.ui" line="346"/>
         <source>POI Text</source>
         <translation>POI Text</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="323"/>
+        <location filename="../IMainWindow.ui" line="358"/>
         <source>Night / Day</source>
         <translation>Nacht / Tag</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="335"/>
+        <location filename="../IMainWindow.ui" line="370"/>
         <source>Map Tool Tip</source>
         <translation>Kartentooltip</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="344"/>
+        <location filename="../IMainWindow.ui" line="379"/>
         <source>Setup DEM Paths</source>
         <translation>DEM Verzeichnisse angeben</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="353"/>
+        <location filename="../IMainWindow.ui" line="388"/>
         <source>About</source>
         <translation>Über</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="362"/>
+        <location filename="../IMainWindow.ui" line="397"/>
         <source>Help</source>
         <translation>Hilfe</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="371"/>
-        <location filename="../IMainWindow.ui" line="374"/>
+        <location filename="../IMainWindow.ui" line="406"/>
+        <location filename="../IMainWindow.ui" line="409"/>
         <source>Setup Map View</source>
         <translation>Kartenansicht einstellen</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="488"/>
+        <location filename="../IMainWindow.ui" line="523"/>
         <source>VRT Builder</source>
         <translation>VRT Builder</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="491"/>
+        <location filename="../IMainWindow.ui" line="526"/>
         <source>GUI front end to gdalbuildvrt</source>
         <translation>Eine graphische Benutzerschnittstelle zu gdalbuildvrt </translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="500"/>
+        <location filename="../IMainWindow.ui" line="535"/>
         <source>Store Map View</source>
         <translation>Kartenansicht speichern</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="503"/>
+        <location filename="../IMainWindow.ui" line="538"/>
         <source>Write current active map and DEM list including the properties to a file</source>
         <translation>Speichert die aktive Karten und DEM Dateien inklusive der Eigenschaften in einer Datei</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="512"/>
+        <location filename="../IMainWindow.ui" line="547"/>
         <source>Load Map View</source>
         <translation>Kartenansicht laden</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="515"/>
+        <location filename="../IMainWindow.ui" line="550"/>
         <source>Restore view with active map and DEM list including the properties from a file</source>
         <translation>Stellt die aktive Karten und DEM Dateien inklusive der Eigenschaften aus einer Datei wieder her</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="527"/>
+        <location filename="../IMainWindow.ui" line="562"/>
         <source>Ext. Profile</source>
         <translation>Erw. Profil</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="530"/>
+        <location filename="../IMainWindow.ui" line="565"/>
         <source>Ctrl+E</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="539"/>
+        <location filename="../IMainWindow.ui" line="574"/>
         <source>Close</source>
         <translation>Schließen</translation>
     </message>
     <message>
+        <location filename="../IMainWindow.ui" line="583"/>
+        <source>Clone Map View</source>
+        <translation>Kartenansicht klonen</translation>
+    </message>
+    <message>
+        <location filename="../IMainWindow.ui" line="586"/>
+        <source>Ctrl+Shift+T</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../IMainWindow.ui" line="595"/>
+        <source>Create Routino Database</source>
+        <translation>Routino Datenbank erstellen</translation>
+    </message>
+    <message>
         <source>Setup Map Workspace</source>
         <translation type="obsolete">Arbeitsplatz einstellen</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="383"/>
+        <location filename="../IMainWindow.ui" line="418"/>
         <source>Load GIS Data</source>
         <translation>GIS Daten laden</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="386"/>
+        <location filename="../IMainWindow.ui" line="421"/>
         <source>Load projects from file</source>
         <translation>Lade Datei als Projekt</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="389"/>
+        <location filename="../IMainWindow.ui" line="424"/>
         <source>Ctrl+L</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="398"/>
+        <location filename="../IMainWindow.ui" line="433"/>
         <source>Save All GIS Data</source>
         <translation>Alle GIS Daten speichern</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="401"/>
+        <location filename="../IMainWindow.ui" line="436"/>
         <source>Save all projects in the workspace</source>
-        <translation>Alle Projekte im Arbeitsplatz speichern</translation>
+        <translation>Alle Projekte die sich auf dem Arbeitsplatz befinden, speichern</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="404"/>
+        <location filename="../IMainWindow.ui" line="439"/>
         <source>Ctrl+S</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="413"/>
+        <location filename="../IMainWindow.ui" line="448"/>
         <source>Setup Time Zone</source>
         <translation>Zeitzone einstellen</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="422"/>
+        <location filename="../IMainWindow.ui" line="457"/>
         <source>Add empty project</source>
         <translation>Leeres Projekt hinzufügen</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="434"/>
+        <location filename="../IMainWindow.ui" line="469"/>
         <source>Search Google</source>
         <translation>Mit Google suchen</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="443"/>
+        <location filename="../IMainWindow.ui" line="478"/>
         <source>Close all projects</source>
         <translation>Alle Projekte schließen</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="446"/>
+        <location filename="../IMainWindow.ui" line="481"/>
         <source>F8</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="455"/>
+        <location filename="../IMainWindow.ui" line="490"/>
         <source>Setup Units</source>
         <translation>Einheiten einstellen</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="464"/>
+        <location filename="../IMainWindow.ui" line="499"/>
         <source>Setup Workspace</source>
-        <translation>Arbeitsplatz einstellen</translation>
+        <translation>Arbeitsplatz konfigurieren</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="467"/>
+        <location filename="../IMainWindow.ui" line="502"/>
         <source>Setup save on exit.</source>
         <translation>Speichert Einstellungen beim Beenden.</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="476"/>
+        <location filename="../IMainWindow.ui" line="511"/>
         <source>Import Database from QLandkarte</source>
         <translation>Datenbankimport aus QLandkarte</translation>
     </message>
@@ -3284,7 +3526,7 @@ ist keine gültige Koordinatensystemdefinition:
         <translation type="obsolete">Datenbank importieren</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="479"/>
+        <location filename="../IMainWindow.ui" line="514"/>
         <source>Import QLandkarte GT database</source>
         <translation>QLandkarte GT Datenbank importieren</translation>
     </message>
@@ -3351,7 +3593,7 @@ Keine Lust die Anleitung zu lesen!</translation>
     </message>
     <message>
         <location filename="../map/IMapPathSetup.ui" line="29"/>
-        <location filename="../map/IMapPathSetup.ui" line="135"/>
+        <location filename="../map/IMapPathSetup.ui" line="154"/>
         <source>-</source>
         <translation></translation>
     </message>
@@ -3428,33 +3670,33 @@ Keine Lust die Anleitung zu lesen!</translation>
 <context>
     <name>IMapVrtBuilder</name>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="14"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="14"/>
         <source>Form</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="22"/>
-        <location filename="../map/IMapVrtBuilder.ui" line="56"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="22"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="56"/>
         <source>...</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="39"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="39"/>
         <source>Select source files:</source>
         <translation>Quelldateien auswählen:</translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="79"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="79"/>
         <source>Target Filename:</source>
         <translation>Zieldatei auswählen:</translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="86"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="86"/>
         <source>-</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="95"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="95"/>
         <source>Start</source>
         <translation></translation>
     </message>
@@ -3462,24 +3704,64 @@ Keine Lust die Anleitung zu lesen!</translation>
 <context>
     <name>IMouseEditLine</name>
     <message>
-        <location filename="../mouse/IMouseEditLine.cpp" line="344"/>
         <source>Add points?</source>
-        <translation>Punkte hinzufügen?</translation>
+        <translation type="obsolete">Punkte hinzufügen?</translation>
     </message>
     <message>
-        <location filename="../mouse/IMouseEditLine.cpp" line="344"/>
         <source>Add points to temporary line?</source>
-        <translation>Punkte zur temporären Linie hinzufügen?</translation>
+        <translation type="obsolete">Punkte zur temporären Linie hinzufügen?</translation>
     </message>
     <message>
-        <location filename="../mouse/IMouseEditLine.cpp" line="887"/>
         <source>Warning!</source>
-        <translation>Warnung!</translation>
+        <translation type="obsolete">Warnung!</translation>
     </message>
     <message>
-        <location filename="../mouse/IMouseEditLine.cpp" line="887"/>
         <source>This will replace all data of the orignal by a simple line of coordinates. All other data will be lost permanently.</source>
-        <translation>Alle ursprünglichen Daten werden durch eine einfache Koordinatenlinie ersetzt. Alle anderen Daten sind dauerhaft verloren.</translation>
+        <translation type="obsolete">Alle ursprünglichen Daten werden durch eine einfache Koordinatenlinie ersetzt. Alle anderen Daten sind dauerhaft verloren.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="238"/>
+        <source><b>New Line</b><br/>Move the mouse and use the left mouse button to drop points. When done use the right mouse button to stop.<br/></source>
+        <translation><b>Neue Linie</b><br/>Erstellen Sie Punkte durch Verschieben des Mauscursors und Drücken der linken Maustaste. Mit der rechten Maustaste beenden Sie den Vorgang.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="279"/>
+        <source><b>Delete Point</b><br/>Move the mouse close to a point and press the left button to delete it.<br/></source>
+        <translation><b>Punkt löschen</b><br/>Bewegen Sie den Mauscursor nahe an einen Punkt und drücken Sie die linke Maustaste um ihn zu löschen. <br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="287"/>
+        <source><b>Select Range of Points</b><br/>Left click on first point to start selection. Left click second point to complete selection and choose from options. Use the right mouse button to cancel.<br/></source>
+        <translation><b>Punktebereich auswählen</b><br/>Mit der linken Maustaste wählen Sie den ersten Punkt aus. Mit einem erneuten Drücken der linken Maustaste wählen Sie den zweiten Punkt aus und dann wählen Sie eine der Optionen. Zum Abbrechen nutzen Sie die rechte Maustaste.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="295"/>
+        <source><b>Move Point</b><br/>Move the mouse close to a point and press the left button to make it stick to the cursor. Move the mouse to move the point. Drop the point by a left click. Use the right mouse button to cancel.<br/></source>
+        <translation><b>Punkt verschieben</b><br/>Bewegen Sie den Mauscursor nahe an einen Punkt und drücken die linke Maustaste, um ihn mit dem Cursor zu fangen. Verschieben Sie den Punkt mit der Maus. Setzen Sie den Punkt mit einem Linksklick. Zum Abbrechen nutzen Sie die rechte Maustaste.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="303"/>
+        <source><b>Add Point</b><br/>Move the mouse close to a line segment and press the left button to add a point. The point will stick to the cursor and you can move it.  Drop the point by a left click. Use the right mouse button to cancel.<br/></source>
+        <translation><b>Punkt hinzufügen</b><br/>Bewegen Sie den Mauscursor nahe an ein Liniensegment und drücken die linke Maustaste, um einen Punkt hinzuzufügen. Der Punkt wird durch den Cursor gefangen und kann verschoben werden. Setzen Sie den Punkt mit einem Linksklick. Zum Abbrechen nutzen Sie die rechte Maustaste.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="311"/>
+        <source><b>No Routing</b><br/>All points will be connected with a straight line.<br/></source>
+        <translation><b>Kein Routing</b><br/>Alle Punkte werden mittles einer geraden Linie verbunden.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="316"/>
+        <source><b>Auto Routing</b><br/>The current router setup is used to derive a route between points. <b>Note:</b> The selected router must be able to route on-the-fly. Offline routers usually can do, online routers can't.<br/></source>
+        <translation><b>Auto Routing</b><br/>Die aktuellen Router Einstellungen erstellen eine Route zwischen Punkten. <b>Hinweis:</b> Der gewählte Router muss schnell routen können. Offline Router können dies gewöhnlich, Online Router nicht.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="321"/>
+        <source><b>Vector Routing</b><br/>Connect points with a line from a loaded vector map if possible.<br/></source>
+        <translation><b>Vektor Routing</b><br/>Verbindet Punkte mit einer Linie einer geladenen Vektorkarte, soweit möglich.<br/></translation>
+    </message>
+    <message>
+        <source><b>No Routing</b><br/>Connect points with a line from a loaded vector map if possible.<br/></source>
+        <translation type="obsolete"><b>Keun Routing</b><br/>Verbindet Punkte mit einer Linie einer geladenen Vektorkarte, soweit möglich.<br/></translation>
     </message>
 </context>
 <context>
@@ -3636,27 +3918,218 @@ sein</translation>
     </message>
 </context>
 <context>
+    <name>IRouterMapQuest</name>
+    <message>
+        <location filename="../gis/rte/router/IRouterMapQuest.ui" line="14"/>
+        <source>Form</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterMapQuest.ui" line="20"/>
+        <source>t.b.d</source>
+        <translation></translation>
+    </message>
+</context>
+<context>
+    <name>IRouterRoutino</name>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="14"/>
+        <source>Form</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="31"/>
+        <source>Profile</source>
+        <translation>Profil</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="38"/>
+        <source>Mode</source>
+        <translation>Modus</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="45"/>
+        <source>Database</source>
+        <translation>Datenbank</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="52"/>
+        <source>Add paths with Routino database.</source>
+        <translation>Fügt Pfade mit Routino Datenbanken hinzu.</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="55"/>
+        <source>...</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="121"/>
+        <source>To use offline routing you need to define paths to local routing data. Use the setup tool button to register a path.</source>
+        <translation>Um Offline-Routing zu nutzen, müssen Pfade zu lokalen Routendaten definiert sein. Benutzen Sie den Werkzeugbutton, um einen Pfad zu registrieren.</translation>
+    </message>
+</context>
+<context>
+    <name>IRouterRoutinoPathSetup</name>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutinoPathSetup.ui" line="14"/>
+        <source>Setup Routino database...</source>
+        <translation>Routino Datenbank einrichten...</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutinoPathSetup.ui" line="27"/>
+        <location filename="../gis/rte/router/IRouterRoutinoPathSetup.ui" line="47"/>
+        <source>...</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutinoPathSetup.ui" line="99"/>
+        <source>-</source>
+        <translation></translation>
+    </message>
+</context>
+<context>
+    <name>IRouterSetup</name>
+    <message>
+        <location filename="../gis/rte/router/IRouterSetup.ui" line="14"/>
+        <source>Form</source>
+        <translation></translation>
+    </message>
+</context>
+<context>
+    <name>IRoutinoDatabaseBuilder</name>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="14"/>
+        <source>Form</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="22"/>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="63"/>
+        <source>...</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="39"/>
+        <source>Select source files:</source>
+        <translation>Quelldateien auswählen:</translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="54"/>
+        <source>Start</source>
+        <translation>Starten</translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="86"/>
+        <source>Target Path:</source>
+        <translation>Zielpfad:</translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="93"/>
+        <source>-</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="100"/>
+        <source>File Prefix</source>
+        <translation>Dateipräfix</translation>
+    </message>
+</context>
+<context>
     <name>IScrOptEditLine</name>
     <message>
-        <location filename="../mouse/IScrOptEditLine.ui" line="26"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="32"/>
         <source>Form</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../mouse/IScrOptEditLine.ui" line="47"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="53"/>
         <source>Save to orignal</source>
         <translation>Ins Original speichern</translation>
     </message>
     <message>
-        <location filename="../mouse/IScrOptEditLine.ui" line="54"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="60"/>
         <source>Save as new</source>
         <translation>Als neu speichern</translation>
     </message>
     <message>
-        <location filename="../mouse/IScrOptEditLine.ui" line="61"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="67"/>
         <source>Abort</source>
         <translation>Abbrechen</translation>
     </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="102"/>
+        <source>Move points.</source>
+        <translation>Punkte verschieben.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="105"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="128"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="148"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="168"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="280"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="297"/>
+        <source>...</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="125"/>
+        <source>Add new points.</source>
+        <translation>Punkte hinzufügen.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="145"/>
+        <source>Select a range of points.</source>
+        <translation>Einen Punktebereich wählen.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="165"/>
+        <source>Delete a point.</source>
+        <translation>Einen Punkt löschen.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="216"/>
+        <source>No auto-routing or line snapping</source>
+        <translation>Kein Auto-Routing oder Fangen an Linie</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="219"/>
+        <source>0</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="232"/>
+        <source>Use auto-routing to between points.</source>
+        <translation>Auto-Routing zwischen Punkten benutzen.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="235"/>
+        <source>A</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="248"/>
+        <source>Snap line along lines of a vector map.</source>
+        <translation>Fängt die Linie längs Linien einer Vektorkarte.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="251"/>
+        <source>V</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="277"/>
+        <source>Undo last change</source>
+        <translation>Letzte Änderung rückgängig machen</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="294"/>
+        <source>Redo last change</source>
+        <translation>Letzte Änderung wiederherstellen</translation>
+    </message>
+    <message>
+        <source>Redo next change</source>
+        <translation type="obsolete">Letzte Änderung wiederherstellen</translation>
+    </message>
 </context>
 <context>
     <name>IScrOptOvlArea</name>
@@ -3667,23 +4140,38 @@ sein</translation>
     </message>
     <message>
         <location filename="../gis/ovl/IScrOptOvlArea.ui" line="40"/>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="54"/>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="65"/>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="83"/>
+        <source>View details and edit.</source>
+        <translation>Details anzeigen und bearbeiten.</translation>
+    </message>
+    <message>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="43"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="57"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="71"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="92"/>
         <source>...</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="51"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="54"/>
         <source>Copy area into another project.</source>
         <translation>Gebiet in ein anderes Projekt kopieren.</translation>
     </message>
     <message>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="68"/>
+        <source>Delete area from project.</source>
+        <translation>Gebiet aus einem Projekt entfernen.</translation>
+    </message>
+    <message>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="89"/>
+        <source>Edit shape of the area.</source>
+        <translation>Form eines Gebietes ändern.</translation>
+    </message>
+    <message>
         <source>Toggle read only mode. You have to open the lock to edit the item.</source>
-        <translation type="vanished">Den Schreibschutz ändern. Das Schloss muss offen sein um das Element zu bearbeiten.</translation>
+        <translation type="obsolete">Den Schreibschutz ändern. Das Schloss muss offen sein um das Element zu bearbeiten.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="112"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="121"/>
         <source>TextLabel</source>
         <translation>Bezeichnung</translation>
     </message>
@@ -3749,6 +4237,30 @@ sein</translation>
     </message>
 </context>
 <context>
+    <name>IScrOptRangeLine</name>
+    <message>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="14"/>
+        <source>Form</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="20"/>
+        <source>Delete all points between the first and last one.</source>
+        <translation>Alle Punkte zwischen dem ersten und dem letzten Punkt löschen.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="23"/>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="37"/>
+        <source>...</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="34"/>
+        <source>Caclculate a route between the first and last selected point.</source>
+        <translation>Eine Route zwischen dem ersten und dem letzten Punkt berechnen.</translation>
+    </message>
+</context>
+<context>
     <name>IScrOptRangeTrk</name>
     <message>
         <location filename="../mouse/IScrOptRangeTrk.ui" line="14"/>
@@ -3803,14 +4315,21 @@ sein</translation>
         <translation></translation>
     </message>
     <message>
-        <location filename="../gis/rte/IScrOptRte.ui" line="28"/>
         <source><html><head/><body><p>View details &amp; Edit</p></body></html></source>
-        <translation><html><head/><body><p>Details anzeigen & Bearbeiten</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Details anzeigen & Bearbeiten</p></body></html></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="28"/>
+        <source>View details and edit.</source>
+        <translation>Details anzeigen und bearbeiten.</translation>
     </message>
     <message>
         <location filename="../gis/rte/IScrOptRte.ui" line="31"/>
         <location filename="../gis/rte/IScrOptRte.ui" line="45"/>
         <location filename="../gis/rte/IScrOptRte.ui" line="59"/>
+        <location filename="../gis/rte/IScrOptRte.ui" line="80"/>
+        <location filename="../gis/rte/IScrOptRte.ui" line="94"/>
+        <location filename="../gis/rte/IScrOptRte.ui" line="108"/>
         <source>...</source>
         <translation></translation>
     </message>
@@ -3821,15 +4340,39 @@ sein</translation>
     </message>
     <message>
         <location filename="../gis/rte/IScrOptRte.ui" line="56"/>
+        <source>Delete route from project.</source>
+        <translation>Route aus einem Projekt entfernen.</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="91"/>
+        <source>Reset route calculation.</source>
+        <translation>Routenberechnung zurücksetzen.</translation>
+    </message>
+    <message>
         <source><html><head/><body><p>Delete</p></body></html></source>
-        <translation><html><head/><body><p>Löschen</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Löschen</p></body></html></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="77"/>
+        <source>Calculate route.</source>
+        <translation>Route berechnen.</translation>
+    </message>
+    <message>
+        <source>Reset route caclulation.</source>
+        <translatorcomment>??? calculation statt caclulation - ja :)</translatorcomment>
+        <translation type="obsolete">Routenberechnung zurücksetzen.</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="105"/>
+        <source>Move route points.</source>
+        <translation>Routenpunkte verschieben.</translation>
     </message>
     <message>
         <source>Toggle read only mode. You have to open the lock to edit the item.</source>
-        <translation type="vanished">Den Schreibschutz ändern. Das Schloss muss offen sein um das Element zu bearbeiten.</translation>
+        <translation type="obsolete">Den Schreibschutz ändern. Das Schloss muss offen sein um das Element zu bearbeiten.</translation>
     </message>
     <message>
-        <location filename="../gis/rte/IScrOptRte.ui" line="85"/>
+        <location filename="../gis/rte/IScrOptRte.ui" line="134"/>
         <source>TextLabel</source>
         <translation>Bezeichnung</translation>
     </message>
@@ -3842,9 +4385,8 @@ sein</translation>
         <translation></translation>
     </message>
     <message>
-        <location filename="../gis/trk/IScrOptTrk.ui" line="40"/>
         <source>View details &amp; Edit properties of track.</source>
-        <translation>Detailansicht & Trackeigenschaften bearbeiten.</translation>
+        <translation type="obsolete">Detailansicht & Trackeigenschaften bearbeiten.</translation>
     </message>
     <message>
         <location filename="../gis/trk/IScrOptTrk.ui" line="54"/>
@@ -3852,9 +4394,8 @@ sein</translation>
         <translation>Track in ein anderes Projekt kopieren.</translation>
     </message>
     <message>
-        <location filename="../gis/trk/IScrOptTrk.ui" line="68"/>
         <source>Delete</source>
-        <translation>Löschen</translation>
+        <translation type="obsolete">Löschen</translation>
     </message>
     <message>
         <location filename="../gis/trk/IScrOptTrk.ui" line="89"/>
@@ -3873,7 +4414,17 @@ sein</translation>
     </message>
     <message>
         <source>Toggle read only mode. You have to open the lock to edit the item.</source>
-        <translation type="vanished">Den Schreibschutz ändern. Das Schloss muss offen sein um das Element zu bearbeiten.</translation>
+        <translation type="obsolete">Den Schreibschutz ändern. Das Schloss muss offen sein um das Element zu bearbeiten.</translation>
+    </message>
+    <message>
+        <location filename="../gis/trk/IScrOptTrk.ui" line="40"/>
+        <source>View details and edit properties of track.</source>
+        <translation>Details anzeigen und Trackeigenschaften bearbeiten.</translation>
+    </message>
+    <message>
+        <location filename="../gis/trk/IScrOptTrk.ui" line="68"/>
+        <source>Delete track from project.</source>
+        <translation>Track aus einem Projekt entfernen.</translation>
     </message>
     <message>
         <location filename="../gis/trk/IScrOptTrk.ui" line="106"/>
@@ -3941,17 +4492,21 @@ sein</translation>
         <translation></translation>
     </message>
     <message>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="49"/>
         <source><html><head/><body><p>View details &amp; Edit</p></body></html></source>
-        <translation><html><head/><body><p>Details anzeigen &amp; Bearbeiten</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Details anzeigen &amp; Bearbeiten</p></body></html></translation>
+    </message>
+    <message>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="49"/>
+        <source>View details and edit.</source>
+        <translation>Details anzeigen und editieren.</translation>
     </message>
     <message>
         <location filename="../gis/wpt/IScrOptWpt.ui" line="52"/>
         <location filename="../gis/wpt/IScrOptWpt.ui" line="66"/>
         <location filename="../gis/wpt/IScrOptWpt.ui" line="80"/>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="98"/>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="115"/>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="129"/>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="101"/>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="118"/>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="132"/>
         <source>...</source>
         <translation></translation>
     </message>
@@ -3962,25 +4517,42 @@ sein</translation>
     </message>
     <message>
         <location filename="../gis/wpt/IScrOptWpt.ui" line="77"/>
+        <source>Delete waypoint from project.</source>
+        <translation>Wegpunkt aus einem Projekt entfernen.</translation>
+    </message>
+    <message>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="98"/>
+        <source>Show content as static bubble.</source>
+        <translation>Inhalt als statische Legende zeigen.</translation>
+    </message>
+    <message>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="115"/>
+        <source>Move waypoint to a new location.</source>
+        <translation>Wegpunkt an einen neuen Ort verschieben.</translation>
+    </message>
+    <message>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="129"/>
+        <source>Clone waypoint and move clone a given distance and angle.</source>
+        <translation>Wegpunkt klonen und um eine bestimmte Entfernung und einen bestimmten Winkel verschieben.</translation>
+    </message>
+    <message>
         <source><html><head/><body><p>Delete</p></body></html></source>
-        <translation><html><head/><body><p>Löschen</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Löschen</p></body></html></translation>
     </message>
     <message>
         <source>Toggle read only mode. You have to open the lock to edit the item.</source>
-        <translation type="vanished">Den Schreibschutz ändern. Das Schloss muss offen sein um das Element zu bearbeiten.</translation>
+        <translation type="obsolete">Den Schreibschutz ändern. Das Schloss muss offen sein um das Element zu bearbeiten.</translation>
     </message>
     <message>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="112"/>
         <source><html><head/><body><p>Move waypoint to a new location.</p></body></html></source>
-        <translation><html><head/><body><p>Wegpunkt verschieben.</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Wegpunkt verschieben.</p></body></html></translation>
     </message>
     <message>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="126"/>
         <source><html><head/><body><p>Clone waypoint and move clone a given distance and angle.</p></body></html></source>
-        <translation><html><head/><body><p>Wegpunkt kopieren und unter Angabe von Entfernung und Winkel verschieben.</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Wegpunkt kopieren und unter Angabe von Entfernung und Winkel verschieben.</p></body></html></translation>
     </message>
     <message>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="173"/>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="176"/>
         <source>TextLabel</source>
         <translation>Bezeichnung</translation>
     </message>
@@ -4202,11 +4774,11 @@ sein</translation>
     <name>ISetupFolder</name>
     <message>
         <source>Folder...</source>
-        <translation type="vanished">Ordner...</translation>
+        <translation type="obsolete">Ordner...</translation>
     </message>
     <message>
         <source>Name</source>
-        <translation type="vanished">Name</translation>
+        <translation type="obsolete">Name</translation>
     </message>
     <message>
         <location filename="../gis/db/ISetupFolder.ui" line="14"/>
@@ -4283,7 +4855,7 @@ sein</translation>
     <message>
         <location filename="../gis/db/ISetupWorkspace.ui" line="14"/>
         <source>Setup workspace...</source>
-        <translation>Arbeitsplatz einstellen...</translation>
+        <translation>Arbeitsplatz konfigurieren...</translation>
     </message>
     <message>
         <location filename="../gis/db/ISetupWorkspace.ui" line="35"/>
@@ -4530,16 +5102,16 @@ sein</translation>
     </message>
     <message>
         <source>Bad position format. Must be: [N|S] ddd mm.sss [W|E] ddd mm.sss</source>
-        <translation type="vanished">Falsches Positionsformat. Richtig: [N|S] ddd mm.sss [W|E] ddd mm.sss </translation>
+        <translation type="obsolete">Falsches Positionsformat. Richtig: [N|S] ddd mm.sss [W|E] ddd mm.sss </translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="109"/>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="118"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="111"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="120"/>
         <source>Failed to read...</source>
         <translation>Lesen fehlgeschlagen...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="109"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="111"/>
         <source>Failed to read: %1
 line %2, column %3:
  %4</source>
@@ -4548,7 +5120,7 @@ Zeile %2, Spalte %3:
 %4</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="118"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="120"/>
         <source>Not a GPX file: </source>
         <translation>Keine GPX Datei:</translation>
     </message>
@@ -4578,44 +5150,64 @@ Areas: %1</source>
         <translation type="obsolete">Fläche: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="69"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="78"/>
         <source>Save project?</source>
         <translation>Projekt speichern?</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="69"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="78"/>
         <source>The project "%1" was changed. Save befor closing it?</source>
         <translation>Das Projekt "%1" wurde geändert. Speichern bevor es geschlossen wird?</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="261"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="211"/>
+        <source>%1: Correlate tracks and waypoints.</source>
+        <translation>%1: Tracks und Wegpunkte verknüpfen.</translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/IGisProject.cpp" line="211"/>
+        <source>Abort</source>
+        <translation>Abbrechen</translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/IGisProject.cpp" line="223"/>
+        <source>Did that take too long for you? Do you want to skip correlation of tracks and waypoints for this project (%1) in the future?</source>
+        <translation>Hat das zu lange gedauert? Wollen Sie die Verknüpfung von Tracks und Wegpunkten auch in Zukunft für das Projekt (%1) überspringen?</translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/IGisProject.cpp" line="224"/>
+        <source>Cancelled correlation...</source>
+        <translation>Verknüpfung abgebrochen...</translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/IGisProject.cpp" line="302"/>
         <source><br/>
 Filename: %1</source>
         <translation><br/>
 Dateiname: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="278"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="307"/>
         <source>Waypoints: %1</source>
         <translation>Wegpunkte: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="282"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="311"/>
         <source>Tracks: %1</source>
         <translation>Tracks: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="286"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="315"/>
         <source>Routes: %1</source>
         <translation>Routen: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="290"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="319"/>
         <source>Areas: %1</source>
         <translation>Gebiete: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="370"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="399"/>
         <source>Are you sure you want to delete '%1' from project '%2'?</source>
         <translation>Sind Sie sicher, dass Sie '%1' aus dem Projekt '%2' löschen wollen? </translation>
     </message>
@@ -4626,28 +5218,28 @@ Dateiname: %1</translation>
     </message>
     <message>
         <location filename="../gis/CGisListDB.cpp" line="436"/>
-        <location filename="../gis/prj/IGisProject.cpp" line="371"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="400"/>
         <source>Delete...</source>
         <translation>Löschen...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="96"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="98"/>
         <location filename="../gis/qms/CQmsProject.cpp" line="48"/>
-        <location filename="../gis/qms/CQmsProject.cpp" line="144"/>
+        <location filename="../gis/qms/CQmsProject.cpp" line="145"/>
         <source>Failed to open...</source>
         <translation>Öffnen fehlgeschlagen...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="96"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="98"/>
         <location filename="../gis/qms/CQmsProject.cpp" line="48"/>
-        <location filename="../gis/qms/CQmsProject.cpp" line="144"/>
+        <location filename="../gis/qms/CQmsProject.cpp" line="145"/>
         <source>Failed to open %1</source>
         <translation>Öffnen fehlgeschlagen: %1</translation>
     </message>
     <message>
         <location filename="../gis/db/CDBProject.cpp" line="149"/>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="216"/>
-        <location filename="../gis/qms/CQmsProject.cpp" line="94"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="223"/>
+        <location filename="../gis/qms/CQmsProject.cpp" line="95"/>
         <location filename="../gis/tnv/CTwoNavProject.cpp" line="159"/>
         <source>Save GIS data to...</source>
         <translation>GIS Daten speichern in...</translation>
@@ -4663,27 +5255,27 @@ Dateiname: %1</translation>
         <translation>Speichern abbrechen</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="291"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="298"/>
         <source>File exists ...</source>
         <translation>Datei existiert...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="292"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="299"/>
         <source>The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains GPX data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file.  Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b></source>
         <translation>Diese Datei wurde nicht mit QMapShack erstellt. Wenn Sie 'Ja' drücken werden alle Daten dieser Datei gelöscht. Selbst wenn diese Datei GPX Daten enthält und mit QMapShack geladen wurde, können nicht alle Elemente dieser Datei durch QMapShack geladen und gespeichert werden. Diese Elemente sind verloren. Ich empfehle die Nutzung einer anderen Datei. <b>Wollen Sie die Datei wirklich überschreiben?</b></translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="393"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="407"/>
         <source>Failed to create file '%1'</source>
         <translation>Datei %1' konnte nicht erstellt werden</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="407"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="421"/>
         <source>Saveing GIS data failed...</source>
         <translation>Speichern der GIS Daten fehlgeschlagen...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="402"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="416"/>
         <source>Failed to write file '%1'</source>
         <translation>Datei %1' konnte nicht gespeichert werden</translation>
     </message>
@@ -4693,89 +5285,91 @@ Dateiname: %1</translation>
         <translation>Wegpunkte geändert, alle vorherigen Daten sind verloren.</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="416"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="227"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="441"/>
         <source>Length: %1 %2</source>
         <translation>Länge: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="423"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="448"/>
         <source>, %1%2 %3, %4%5 %6</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="431"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="243"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="456"/>
         <source>Time: %1</source>
         <translation>Gesamtzeit: %1</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="434"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="444"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="459"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="469"/>
         <source>, Speed: %1 %2</source>
         <translation>, Geschw.: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="441"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="466"/>
         <source>Moving: %1</source>
         <translation>Zeit in Bew.: %1</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="450"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="475"/>
         <source>Start: %1</source>
         <translation>Beginn: %1</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="455"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="480"/>
         <source>End: %1</source>
         <translation>Ende: %1</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="459"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="484"/>
         <source>Points: %1 (%2)</source>
         <translation>Punkte: %1 von %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="577"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="602"/>
         <source>Ele.: %1 %2</source>
         <translation>Höhe: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="580"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="605"/>
         <source> slope: %1%3 (%2%)</source>
         <translation>, Steigung: %1%3 (%2%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="651"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="676"/>
         <source>Ascend: %1%2</source>
         <translation>Anstieg: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="656"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="673"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="681"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="698"/>
         <source>, %1%2</source>
         <translation>, %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="661"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="686"/>
         <source>Ascend: -</source>
         <translation>Anstieg: -</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="668"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="693"/>
         <source> Descend: %1%2</source>
         <translation> Abstieg: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="678"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="703"/>
         <source>Descend: -</source>
         <translation>Abstieg: -</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="684"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="709"/>
         <source>Dist.: %1%2</source>
         <translation>Entf.: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="689"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="714"/>
         <source> Time: %1%2</source>
         <translation> Zeit: %1 %2</translation>
     </message>
@@ -4784,12 +5378,12 @@ Dateiname: %1</translation>
         <translation type="obsolete"> Neigung: %1° (%2%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1370"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1403"/>
         <source>Hide points.</source>
         <translation>Punkte ausblenden.</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1416"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1449"/>
         <source>Show points.</source>
         <translation>Punkte einblenden.</translation>
     </message>
@@ -4798,47 +5392,47 @@ Dateiname: %1</translation>
         <translation type="obsolete">Neigung: %1°(%2%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="585"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="610"/>
         <source> speed: %1%2</source>
         <translation>, Geschw.: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="597"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="622"/>
         <source>Ascend: %1%2 (%3%)</source>
         <translation>Anstieg: %1 %2 (%3%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="601"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="626"/>
         <source>Ascend: - (-)</source>
         <translation>Anstieg: - (-)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="607"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="632"/>
         <source> Descend: %1%2 (%3%)</source>
         <translation>, Abstieg: %1 %2 (%3%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="611"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="636"/>
         <source> Descend: - (-) </source>
         <translation>, Abstieg: - (-) </translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="618"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="643"/>
         <source>Dist.: %1%2 (%3%)</source>
         <translation>Entf.: %1 %2 (%3%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="622"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="647"/>
         <source>Dist.: - (-)</source>
         <translation>Entf.: - (-)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="628"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="653"/>
         <source> Moving: %1%2 (%3%)</source>
         <translation>, Zeit in Bew.: %1 %2 (%3%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="632"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="657"/>
         <source> Moving: - (-) </source>
         <translation>, Zeit in Bew.: - (-) </translation>
     </message>
@@ -4864,80 +5458,82 @@ Dateiname: %1</translation>
     </message>
     <message>
         <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="142"/>
-        <location filename="../gis/rte/CGisItemRte.cpp" line="45"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="49"/>
         <location filename="../gis/trk/CGisItemTrk.cpp" line="184"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="131"/>
         <source>_Clone</source>
         <translation>_Klon</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="433"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="444"/>
         <source>Area: %1%2</source>
         <translation>Gebiet: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="491"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="502"/>
         <source>Changed area shape.</source>
         <translation>Gebietsform geändert.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="499"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="510"/>
         <source>Changed name.</source>
         <translation>Name geändert.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="505"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="516"/>
         <source>Changed border width.</source>
         <translation>Umrandungsbreite geändert.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="511"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="522"/>
         <source>Changed fill pattern.</source>
         <translation>Füllung geändert.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="517"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="528"/>
         <source>Changed opacity.</source>
         <translation>Durchsichtigkeit geändert.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="523"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="534"/>
         <source>Changed comment.</source>
         <translation>Kommentar geändert.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="529"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="540"/>
         <source>Changed description.</source>
         <translation>Beschreibung geändert.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="535"/>
-        <location filename="../gis/rte/CGisItemRte.cpp" line="154"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1775"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="546"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="204"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1808"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="448"/>
         <source>Changed links</source>
         <translation>Geänderte Verknüpfungen</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="547"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1787"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="558"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1820"/>
         <source>Changed color</source>
         <translation>Farbe geändert</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1168"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1183"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1202"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1261"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1441"/>
-        <location filename="../mouse/CMouseEditArea.cpp" line="100"/>
-        <location filename="../mouse/CMouseEditTrk.cpp" line="104"/>
+        <location filename="../gis/rte/CCreateRouteFromWpt.cpp" line="65"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1201"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1216"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1235"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1294"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1474"/>
+        <location filename="../mouse/CMouseEditArea.cpp" line="99"/>
+        <location filename="../mouse/CMouseEditRte.cpp" line="109"/>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="115"/>
         <source>Edit name...</source>
         <translation>Name bearbeiten...</translation>
     </message>
     <message>
         <source>Enter new waypoint name.</source>
-        <translation type="vanished">Geben Sie einen neuen Namen für den Wegpunkt ein.</translation>
+        <translation type="obsolete">Geben Sie einen neuen Namen für den Wegpunkt ein.</translation>
     </message>
     <message>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="314"/>
@@ -4950,7 +5546,7 @@ Dateiname: %1</translation>
         <translation>Abstand: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1757"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1790"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="396"/>
         <source>Changed name</source>
         <translation>Name geändert</translation>
@@ -4986,20 +5582,55 @@ Dateiname: %1</translation>
         <translation>Bild hinzufügen</translation>
     </message>
     <message>
-        <location filename="../gis/rte/CGisItemRte.cpp" line="142"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1763"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="192"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1796"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="436"/>
         <source>Changed comment</source>
         <translation>Kommentar geändert</translation>
     </message>
     <message>
-        <location filename="../gis/rte/CGisItemRte.cpp" line="148"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1769"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="198"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1802"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="442"/>
         <source>Changed description</source>
         <translation>Beschreibung geändert</translation>
     </message>
     <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="231"/>
+        <source>Length: -</source>
+        <translation>Länge: -</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="239"/>
+        <source>Time: %2 days %1</source>
+        <translation>Gesamtzeit: %2 days %1</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="248"/>
+        <source>Time: -</source>
+        <translation>Gesamtzeit: -</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="254"/>
+        <source>Last time routed:<br/>%1</source>
+        <translation>Letzte Routenberechnung: <br/>%1</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="256"/>
+        <source>with %1</source>
+        <translation>mit %1</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="258"/>
+        <source>Calculation took %1 sec.</source>
+        <translation>Die Berechnung dauerte %1 Sek.</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="479"/>
+        <source>Changed route points.</source>
+        <translation>Geänderte Routenpukte.</translation>
+    </message>
+    <message>
         <location filename="../gis/gpx/serialization.cpp" line="599"/>
         <source>Archived</source>
         <translation>Archiviert</translation>
@@ -5080,17 +5711,17 @@ Dateiname: %1</translation>
         <translation><p>--- keine ---</p></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1168"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1183"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1202"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1261"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1441"/>
-        <location filename="../mouse/CMouseEditTrk.cpp" line="104"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1201"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1216"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1235"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1294"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1474"/>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="115"/>
         <source>Enter new track name.</source>
         <translation>Geben Sie einen neuen Namen für den Track ein.</translation>
     </message>
     <message>
-        <location filename="../mouse/CMouseEditArea.cpp" line="100"/>
+        <location filename="../mouse/CMouseEditArea.cpp" line="99"/>
         <source>Enter new area name.</source>
         <translation>Geben Sie einen neuen Namen für das Gebiet ein.</translation>
     </message>
@@ -5195,18 +5826,18 @@ Dateiname: %1</translation>
         <translation>Geschwindigkeit auf %1 %2 geändert.</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="956"/>
+        <location filename="../gis/CGisListWks.cpp" line="988"/>
         <source>Delete project...</source>
         <translation>Projekt löschen...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="956"/>
+        <location filename="../gis/CGisListWks.cpp" line="988"/>
         <source>Do you really want to delete %1?</source>
         <translation>Sind Sie sicher, dass sie %1? löschen wollen?</translation>
     </message>
     <message>
         <source>Do you really want to delete %1</source>
-        <translation type="vanished">Sind Sie sicher, dass sie %1 löschen wollen?</translation>
+        <translation type="obsolete">Sind Sie sicher, dass sie %1 löschen wollen?</translation>
     </message>
     <message>
         <location filename="../gis/tnv/CTwoNavProject.cpp" line="87"/>
@@ -5215,13 +5846,13 @@ Dateiname: %1</translation>
         <location filename="../gis/tnv/serialization.cpp" line="431"/>
         <location filename="../gis/tnv/serialization.cpp" line="460"/>
         <location filename="../gis/tnv/serialization.cpp" line="471"/>
-        <location filename="../gis/tnv/serialization.cpp" line="492"/>
-        <location filename="../gis/tnv/serialization.cpp" line="632"/>
-        <location filename="../gis/tnv/serialization.cpp" line="660"/>
-        <location filename="../gis/tnv/serialization.cpp" line="671"/>
-        <location filename="../gis/tnv/serialization.cpp" line="689"/>
-        <location filename="../gis/tnv/serialization.cpp" line="717"/>
-        <location filename="../gis/tnv/serialization.cpp" line="791"/>
+        <location filename="../gis/tnv/serialization.cpp" line="504"/>
+        <location filename="../gis/tnv/serialization.cpp" line="644"/>
+        <location filename="../gis/tnv/serialization.cpp" line="672"/>
+        <location filename="../gis/tnv/serialization.cpp" line="683"/>
+        <location filename="../gis/tnv/serialization.cpp" line="701"/>
+        <location filename="../gis/tnv/serialization.cpp" line="729"/>
+        <location filename="../gis/tnv/serialization.cpp" line="803"/>
         <source>Error...</source>
         <translation>Fehler...</translation>
     </message>
@@ -5230,23 +5861,23 @@ Dateiname: %1</translation>
         <location filename="../gis/tnv/CTwoNavProject.cpp" line="191"/>
         <location filename="../gis/tnv/serialization.cpp" line="295"/>
         <location filename="../gis/tnv/serialization.cpp" line="431"/>
-        <location filename="../gis/tnv/serialization.cpp" line="632"/>
+        <location filename="../gis/tnv/serialization.cpp" line="644"/>
         <source>Failed to open %1.</source>
         <translation>Die Datei %1 konnte nicht geöffnet werden.</translation>
     </message>
     <message>
         <location filename="../gis/tnv/serialization.cpp" line="460"/>
         <location filename="../gis/tnv/serialization.cpp" line="471"/>
-        <location filename="../gis/tnv/serialization.cpp" line="660"/>
-        <location filename="../gis/tnv/serialization.cpp" line="671"/>
+        <location filename="../gis/tnv/serialization.cpp" line="672"/>
+        <location filename="../gis/tnv/serialization.cpp" line="683"/>
         <source>Only support lon/lat WGS 84 format.</source>
         <translation>Es wird nur lon/lat WGS 84 als Format unterstützt.</translation>
     </message>
     <message>
-        <location filename="../gis/tnv/serialization.cpp" line="492"/>
-        <location filename="../gis/tnv/serialization.cpp" line="689"/>
-        <location filename="../gis/tnv/serialization.cpp" line="717"/>
-        <location filename="../gis/tnv/serialization.cpp" line="791"/>
+        <location filename="../gis/tnv/serialization.cpp" line="504"/>
+        <location filename="../gis/tnv/serialization.cpp" line="701"/>
+        <location filename="../gis/tnv/serialization.cpp" line="729"/>
+        <location filename="../gis/tnv/serialization.cpp" line="803"/>
         <source>Failed to read data.</source>
         <translation>Datenlesen fehlgeschlagen.</translation>
     </message>
@@ -5256,9 +5887,15 @@ Dateiname: %1</translation>
         <translation>Bild %1</translation>
     </message>
     <message>
-        <location filename="../device/IDevice.cpp" line="202"/>
+        <location filename="../device/IDevice.cpp" line="204"/>
         <source>There is another project with the same name. If you press 'ok' it will be removed and replaced.</source>
         <translation>Es gibt schon ein Projekt mit dem selben Namen. Wenn Sie 'ok' drücken wird dieses entfernt und ersetzt.</translation>
     </message>
+    <message>
+        <location filename="../gis/rte/CCreateRouteFromWpt.cpp" line="65"/>
+        <location filename="../mouse/CMouseEditRte.cpp" line="109"/>
+        <source>Enter new route name.</source>
+        <translation>Geben Sie einen Namen für die Route ein.</translation>
+    </message>
 </context>
 </TS>
diff --git a/src/locale/qmapshack_es.ts b/src/locale/qmapshack_es.ts
index 3afce05..9bd6d20 100644
--- a/src/locale/qmapshack_es.ts
+++ b/src/locale/qmapshack_es.ts
@@ -8,7 +8,7 @@
         <translation type="obsolete">Espacio de Trabajo %1</translation>
     </message>
     <message>
-        <location filename="../canvas/CCanvas.cpp" line="63"/>
+        <location filename="../canvas/CCanvas.cpp" line="64"/>
         <source>View %1</source>
         <translation>Vista %1</translation>
     </message>
@@ -53,7 +53,7 @@
         <location filename="../dem/CDemVRT.cpp" line="45"/>
         <location filename="../dem/CDemVRT.cpp" line="52"/>
         <location filename="../dem/CDemVRT.cpp" line="61"/>
-        <location filename="../dem/CDemVRT.cpp" line="88"/>
+        <location filename="../dem/CDemVRT.cpp" line="89"/>
         <source>Error...</source>
         <translation>Error...</translation>
     </message>
@@ -69,7 +69,7 @@
         <translation>El DEM debe tener una sola banda con datos de 16 o 32 bits.</translation>
     </message>
     <message>
-        <location filename="../dem/CDemVRT.cpp" line="88"/>
+        <location filename="../dem/CDemVRT.cpp" line="89"/>
         <source>No georeference information found.</source>
         <translation>No se encontró información de georreferenciación.</translation>
     </message>
@@ -112,7 +112,7 @@
     </message>
     <message>
         <source>Enter new waypoint name.</source>
-        <translation type="vanished">Editar el nombre del nuevo waypoint.</translation>
+        <translation type="obsolete">Editar el nombre del nuevo waypoint.</translation>
     </message>
     <message>
         <source><h4>Comment:</h4></source>
@@ -134,91 +134,101 @@
 <context>
     <name>CDetailsPrj</name>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="175"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="537"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="188"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="550"/>
         <source>none</source>
         <translation>ninguna</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="234"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="247"/>
         <source>Build diary...</source>
         <translation>Creando diario...</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="234"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="247"/>
         <source>Abort</source>
         <translation>Cancelar</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="292"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="305"/>
         <source><h2>Waypoints</h2></source>
         <translation>Waypoints</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="255"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="299"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="330"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="438"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="268"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="312"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="343"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="451"/>
         <source>Info</source>
         <translation>Información</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="256"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="300"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="331"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="439"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="269"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="313"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="344"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="452"/>
         <source>Comment</source>
         <translation>Comentario</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="323"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="336"/>
         <source><h2>Tracks</h2></source>
         <translation>Tracks</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="248"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="261"/>
         <source><h2>Areas</h2></source>
         <translation>Áreas</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="461"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="82"/>
+        <source>You want to sort waypoints along a track, but you switched off track and waypoint correlation. Do you want to switch it on again?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="83"/>
+        <source>Correlation...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="474"/>
         <source>distance: %1%2</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="463"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="476"/>
         <source>ascent: %1%2</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="465"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="478"/>
         <source>descend: %1%2</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="523"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="550"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="536"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="563"/>
         <source>Edit name...</source>
         <translation>Editar nombre...</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="523"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="550"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="536"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="563"/>
         <source>Enter new project name.</source>
         <translation>Introducir nuevo nombre de proyecto.</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="532"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="545"/>
         <source>Edit keywords...</source>
         <translation>Editar etiquetas...</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="532"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="545"/>
         <source>Enter keywords.</source>
         <translation>Introducir etiquetas.</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="666"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="679"/>
         <source>Print Diary</source>
         <translation>Imprimir Diario</translation>
     </message>
@@ -256,12 +266,12 @@
         <translation></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CDetailsTrk.cpp" line="397"/>
+        <location filename="../gis/trk/CDetailsTrk.cpp" line="395"/>
         <source>Edit name...</source>
         <translation type="unfinished">Editar nombre...</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CDetailsTrk.cpp" line="397"/>
+        <location filename="../gis/trk/CDetailsTrk.cpp" line="395"/>
         <source>Enter new track name.</source>
         <translation type="unfinished">Introduzca el nombre del nuevo track.</translation>
     </message>
@@ -397,124 +407,144 @@
 <context>
     <name>CGisListWks</name>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="96"/>
+        <location filename="../gis/CGisListWks.cpp" line="97"/>
         <source>Save</source>
         <translation>Guardar</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="95"/>
+        <location filename="../gis/CGisListWks.cpp" line="96"/>
         <source>Save As...</source>
         <translation>Guardar Como...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="94"/>
+        <location filename="../gis/CGisListWks.cpp" line="95"/>
         <source>Edit..</source>
         <translation>Editar..</translation>
     </message>
     <message>
         <source>Update Project on Devices</source>
-        <translation type="vanished">Actualizar Proyecto en Dispositivos</translation>
+        <translation type="obsolete">Actualizar Proyecto en Dispositivos</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="98"/>
+        <location filename="../gis/CGisListWks.cpp" line="99"/>
         <source>Close</source>
         <translation>Cerrar</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="104"/>
+        <location filename="../gis/CGisListWks.cpp" line="105"/>
         <source>Update Project on Device</source>
         <translation>Actualizar Proyecto en Dsipositivo</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="116"/>
+        <location filename="../gis/CGisListWks.cpp" line="117"/>
         <source>Edit...</source>
         <translation>Editar...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="117"/>
+        <location filename="../gis/CGisListWks.cpp" line="118"/>
         <source>Copy to...</source>
         <translation>Copiar a...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="132"/>
+        <location filename="../gis/CGisListWks.cpp" line="133"/>
         <source>Show Bubble</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="134"/>
+        <location filename="../gis/CGisListWks.cpp" line="135"/>
         <source>Move Waypoint</source>
         <translation>Mover Waypoint</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="135"/>
+        <location filename="../gis/CGisListWks.cpp" line="136"/>
         <source>Proj. Waypoint...</source>
         <translation>Proyectar Waypoint...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="596"/>
-        <location filename="../gis/CGisListWks.cpp" line="1296"/>
-        <location filename="../gis/CGisListWks.cpp" line="1335"/>
+        <location filename="../gis/CGisListWks.cpp" line="144"/>
+        <source>Calculate Route</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisListWks.cpp" line="145"/>
+        <source>Reset Route</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisListWks.cpp" line="146"/>
+        <source>Edit Route</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisListWks.cpp" line="162"/>
+        <source>Create Route</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisListWks.cpp" line="608"/>
+        <location filename="../gis/CGisListWks.cpp" line="1371"/>
+        <location filename="../gis/CGisListWks.cpp" line="1409"/>
         <source><b>Update devices</b><p>Update %1<br/>Please wait...</p></source>
         <translation type="unfinished"><b>Actualizar dispositivos</b><p>Actualizar %1<br/>Por favor espere...</p></translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="119"/>
+        <location filename="../gis/CGisListWks.cpp" line="120"/>
         <source>Track Profile</source>
         <translation>Perfil del Track</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="97"/>
+        <location filename="../gis/CGisListWks.cpp" line="98"/>
         <source>Send to Devices</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="121"/>
+        <location filename="../gis/CGisListWks.cpp" line="122"/>
         <source>Select Range</source>
         <translation>Seleccionar Rango</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="122"/>
+        <location filename="../gis/CGisListWks.cpp" line="123"/>
         <source>Edit Track Points</source>
         <translation>Editar Puntos del Track</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="123"/>
+        <location filename="../gis/CGisListWks.cpp" line="124"/>
         <source>Reverse Track</source>
         <translation>Invertir Track</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="124"/>
+        <location filename="../gis/CGisListWks.cpp" line="125"/>
         <source>Combine Tracks</source>
         <translation>Combinar Tracks</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="149"/>
+        <location filename="../gis/CGisListWks.cpp" line="155"/>
         <source>Edit Area Points</source>
         <translation>Editar Puntos del Área</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="105"/>
-        <location filename="../gis/CGisListWks.cpp" line="126"/>
+        <location filename="../gis/CGisListWks.cpp" line="106"/>
+        <location filename="../gis/CGisListWks.cpp" line="127"/>
         <source>Delete</source>
         <translation>Borrar</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="696"/>
+        <location filename="../gis/CGisListWks.cpp" line="708"/>
         <source>Saving workspace. Please wait.</source>
         <translation>Guardando espacio de trabajo. Por favor espere.</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="737"/>
+        <location filename="../gis/CGisListWks.cpp" line="750"/>
         <source>Loading workspace. Please wait.</source>
         <translation>Cargando espacio de trabajo. Por favor espere.</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="921"/>
+        <location filename="../gis/CGisListWks.cpp" line="952"/>
         <source>Close all projects...</source>
         <translation>Cerrar todos los proyectos...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="921"/>
+        <location filename="../gis/CGisListWks.cpp" line="952"/>
         <source>This will remove all projects from the workspace.</source>
         <translation>Esto quitará.todos los proyectos.del espacio de trabajo.</translation>
     </message>
@@ -522,12 +552,22 @@
 <context>
     <name>CGisWidget</name>
     <message>
-        <location filename="../gis/CGisWidget.cpp" line="444"/>
+        <location filename="../gis/CGisWidget.cpp" line="114"/>
+        <source>Load project...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisWidget.cpp" line="114"/>
+        <source>The project "%1" is already in the workspace.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisWidget.cpp" line="449"/>
         <source>Cut Track...</source>
         <translation>Partir Track...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisWidget.cpp" line="444"/>
+        <location filename="../gis/CGisWidget.cpp" line="449"/>
         <source>Do you want to delete the original track?</source>
         <translation>¿Desea borrar el track original?</translation>
     </message>
@@ -539,12 +579,12 @@
         <translation type="obsolete">[Malla: %1] </translation>
     </message>
     <message>
-        <location filename="../grid/CGrid.cpp" line="61"/>
+        <location filename="../grid/CGrid.cpp" line="63"/>
         <source>[Grid: %1%2%5 %3%4%5] </source>
         <translation>[Malla: %1%2%5 %3%4%5] </translation>
     </message>
     <message>
-        <location filename="../grid/CGrid.cpp" line="65"/>
+        <location filename="../grid/CGrid.cpp" line="67"/>
         <source>[Grid: N %1m, E %2m] </source>
         <translation>[Malla: N %1m, E %2m] </translation>
     </message>
@@ -560,17 +600,17 @@
 <context>
     <name>CImportDatabase</name>
     <message>
-        <location filename="../qlgt/CImportDatabase.cpp" line="29"/>
+        <location filename="../tool/CImportDatabase.cpp" line="29"/>
         <source>Import QLandkarte Database</source>
         <translation>Importar Base de Datos de Qlandkarte</translation>
     </message>
     <message>
-        <location filename="../qlgt/CImportDatabase.cpp" line="73"/>
+        <location filename="../tool/CImportDatabase.cpp" line="73"/>
         <source>Select source database...</source>
         <translation>Seleccionar origen de base de datos...</translation>
     </message>
     <message>
-        <location filename="../qlgt/CImportDatabase.cpp" line="93"/>
+        <location filename="../tool/CImportDatabase.cpp" line="93"/>
         <source>Select target database...</source>
         <translation>Seleecionar destino de base de datos...</translation>
     </message>
@@ -578,22 +618,22 @@
 <context>
     <name>CMainWindow</name>
     <message>
-        <location filename="../CMainWindow.cpp" line="492"/>
+        <location filename="../CMainWindow.cpp" line="560"/>
         <source>Ele: %1%2</source>
         <translation>Alt: %1%2</translation>
     </message>
     <message>
-        <location filename="../CMainWindow.cpp" line="618"/>
+        <location filename="../CMainWindow.cpp" line="691"/>
         <source>Load GIS Data...</source>
         <translation>Cargar Datos GIS...</translation>
     </message>
     <message>
-        <location filename="../CMainWindow.cpp" line="652"/>
+        <location filename="../CMainWindow.cpp" line="725"/>
         <source>Select output file</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../CMainWindow.cpp" line="678"/>
+        <location filename="../CMainWindow.cpp" line="751"/>
         <source>Select file to load</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1185,46 +1225,46 @@
         <translation>Fallo al leer la estructura del archivo: </translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="640"/>
+        <location filename="../map/CMapIMG.cpp" line="642"/>
         <source>Loading %1</source>
         <translation>Cargando %1</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="645"/>
+        <location filename="../map/CMapIMG.cpp" line="649"/>
         <source>User abort: </source>
         <translation>Abortado por el usuario: </translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="648"/>
+        <location filename="../map/CMapIMG.cpp" line="652"/>
         <source>File is NT format. QMapShack is unable to read map files with NT format: </source>
         <translation>El archivo está en formato NT. QMapShack no puede leer archivos en formato NT: </translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="740"/>
+        <location filename="../map/CMapIMG.cpp" line="744"/>
         <source>File contains locked / encypted data. Garmin does not want you to use this file with any other software than the one supplied by Garmin.</source>
         <translation>El archivo contiene datos bloqueados/cifrados. Garmin no quiere que use este archivo con otros programas distintos a los que ellos proporcionan.</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="2496"/>
-        <location filename="../map/CMapIMG.cpp" line="2504"/>
+        <location filename="../map/CMapIMG.cpp" line="2500"/>
         <location filename="../map/CMapIMG.cpp" line="2508"/>
-        <location filename="../map/CMapIMG.cpp" line="2513"/>
-        <location filename="../map/CMapIMG.cpp" line="2559"/>
-        <location filename="../map/CMapIMG.cpp" line="2567"/>
+        <location filename="../map/CMapIMG.cpp" line="2512"/>
+        <location filename="../map/CMapIMG.cpp" line="2517"/>
+        <location filename="../map/CMapIMG.cpp" line="2563"/>
         <location filename="../map/CMapIMG.cpp" line="2571"/>
-        <location filename="../map/CMapIMG.cpp" line="2576"/>
+        <location filename="../map/CMapIMG.cpp" line="2575"/>
+        <location filename="../map/CMapIMG.cpp" line="2580"/>
         <source>Point of Interest</source>
         <translation>Punto de Interés</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="2703"/>
+        <location filename="../map/CMapIMG.cpp" line="2707"/>
         <source>Unknown</source>
         <translation>Desconocido</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="2749"/>
-        <location filename="../map/CMapIMG.cpp" line="2757"/>
-        <location filename="../map/CMapIMG.cpp" line="2764"/>
+        <location filename="../map/CMapIMG.cpp" line="2753"/>
+        <location filename="../map/CMapIMG.cpp" line="2761"/>
+        <location filename="../map/CMapIMG.cpp" line="2768"/>
         <source>Area</source>
         <translation>Área</translation>
     </message>
@@ -1278,7 +1318,7 @@
         <translation>Selecciona la ruta del mapa...</translation>
     </message>
     <message>
-        <location filename="../map/CMapPathSetup.cpp" line="78"/>
+        <location filename="../map/CMapPathSetup.cpp" line="81"/>
         <source>Select root path...</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1287,7 +1327,7 @@
     <name>CMapPropSetup</name>
     <message>
         <source>Cache path...</source>
-        <translation type="vanished">Ruta de la caché...</translation>
+        <translation type="obsolete">Ruta de la caché...</translation>
     </message>
 </context>
 <context>
@@ -1372,7 +1412,7 @@ línea %2, columna %3.
         <location filename="../map/CMapVRT.cpp" line="47"/>
         <location filename="../map/CMapVRT.cpp" line="61"/>
         <location filename="../map/CMapVRT.cpp" line="89"/>
-        <location filename="../map/CMapVRT.cpp" line="124"/>
+        <location filename="../map/CMapVRT.cpp" line="125"/>
         <source>Error...</source>
         <translation>Error...</translation>
     </message>
@@ -1388,7 +1428,7 @@ línea %2, columna %3.
         <translation>El archivo debe ser con paleta de 8 bits o escala de grises indexada.</translation>
     </message>
     <message>
-        <location filename="../map/CMapVRT.cpp" line="124"/>
+        <location filename="../map/CMapVRT.cpp" line="125"/>
         <source>No georeference information found.</source>
         <translation>No se encontró información de georreferenciación.</translation>
     </message>
@@ -1396,22 +1436,22 @@ línea %2, columna %3.
 <context>
     <name>CMapVrtBuilder</name>
     <message>
-        <location filename="../map/CMapVrtBuilder.cpp" line="29"/>
+        <location filename="../tool/CMapVrtBuilder.cpp" line="29"/>
         <source>Build GDAL VRT</source>
         <translation>Crear GDAL VRT</translation>
     </message>
     <message>
-        <location filename="../map/CMapVrtBuilder.cpp" line="51"/>
+        <location filename="../tool/CMapVrtBuilder.cpp" line="51"/>
         <source>Select files...</source>
         <translation>Seleccionar ficheros de origen...</translation>
     </message>
     <message>
-        <location filename="../map/CMapVrtBuilder.cpp" line="75"/>
+        <location filename="../tool/CMapVrtBuilder.cpp" line="75"/>
         <source>Select target file...</source>
         <translation>Seleccionar fichero de destino...</translation>
     </message>
     <message>
-        <location filename="../map/CMapVrtBuilder.cpp" line="196"/>
+        <location filename="../tool/CMapVrtBuilder.cpp" line="196"/>
         <source>!!! failed !!!
 </source>
         <translation>!!! fallo !!!</translation>
@@ -1424,7 +1464,7 @@ línea %2, columna %3.
         <location filename="../map/CMapWMTS.cpp" line="55"/>
         <location filename="../map/CMapWMTS.cpp" line="65"/>
         <location filename="../map/CMapWMTS.cpp" line="74"/>
-        <location filename="../map/CMapWMTS.cpp" line="198"/>
+        <location filename="../map/CMapWMTS.cpp" line="206"/>
         <source>Error...</source>
         <translation>Error...</translation>
     </message>
@@ -1455,12 +1495,12 @@ Estructura desconocida.</translation>
         <translation>Servicio no esperado. se esperaba'* WMTS 1.0.0'. Se leyó '%1 %2'.</translation>
     </message>
     <message>
-        <location filename="../map/CMapWMTS.cpp" line="198"/>
+        <location filename="../map/CMapWMTS.cpp" line="206"/>
         <source>No georeference information found.</source>
         <translation>No se encontró información de georreferenciación.</translation>
     </message>
     <message>
-        <location filename="../map/CMapWMTS.cpp" line="384"/>
+        <location filename="../map/CMapWMTS.cpp" line="392"/>
         <source><b>%1</b>: %2 tiles pending<br/></source>
         <translation><b>%1</b>: %2 teselas pendientes<br/></translation>
     </message>
@@ -1468,17 +1508,43 @@ Estructura desconocida.</translation>
 <context>
     <name>CMouseEditArea</name>
     <message>
-        <location filename="../mouse/CMouseEditArea.cpp" line="38"/>
         <source><b>Edit Area</b><br/>Select a corner point for more options.<br/></source>
-        <translation><b>Editar Área</b><br/>Seleccione un punto de las esquinas para más información.<br/></translation>
+        <translation type="obsolete"><b>Editar Área</b><br/>Seleccione un punto de las esquinas para más información.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditArea.cpp" line="37"/>
+        <source><b>Edit Area</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>CMouseEditRte</name>
+    <message>
+        <location filename="../mouse/CMouseEditRte.cpp" line="39"/>
+        <source><b>Edit Route Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/></source>
+        <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
     <name>CMouseEditTrk</name>
     <message>
-        <location filename="../mouse/CMouseEditTrk.cpp" line="44"/>
         <source><b>Edit Track Points</b><br/>Select a track point for more options.<br/></source>
-        <translation><b>Editar Puntos del Track</b><br/>Selecciones un punto del track para más opciones.<br/></translation>
+        <translation type="obsolete"><b>Editar Puntos del Track</b><br/>Selecciones un punto del track para más opciones.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="39"/>
+        <source><b>Edit Track Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="81"/>
+        <source>Warning!</source>
+        <translation type="unfinished">¡Cuidado!</translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="81"/>
+        <source>This will replace all data of the orignal by a simple line of coordinates. All other data will be lost permanently.</source>
+        <translation type="unfinished">Esto sustituirá todos los datos del original con una simple línea de coordenadas. Todos los demás datos se perderán definitivamente.</translation>
     </message>
 </context>
 <context>
@@ -1495,11 +1561,16 @@ Estructura desconocida.</translation>
     </message>
     <message>
         <location filename="../mouse/CMouseNormal.cpp" line="44"/>
+        <source>Add Route</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseNormal.cpp" line="45"/>
         <source>Add Area</source>
         <translation>Añadir Área</translation>
     </message>
     <message>
-        <location filename="../mouse/CMouseNormal.cpp" line="46"/>
+        <location filename="../mouse/CMouseNormal.cpp" line="48"/>
         <source>Copy position</source>
         <translation>Copiar posición</translation>
     </message>
@@ -1623,127 +1694,127 @@ no es una definición de sistema de coordenadas válido:
 <context>
     <name>CQlgtDb</name>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="304"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="307"/>
         <source>Migrating database from version 4 to 5.</source>
         <translation>Convirtiendo base de datos de version 4 a 5.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="357"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="361"/>
         <source>Migrating database from version 5 to 6.</source>
         <translation>Convirtiendo base de datos de version 5 a 6.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="414"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="419"/>
         <source>Migrating database from version 6 to 7.</source>
         <translation>Convirtiendo base de datos de version 6 a 7.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="480"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="485"/>
         <source>Migrating database from version 7 to 8.</source>
         <translation>Convirtiendo base de datos de version 7 a 8.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="509"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="514"/>
         <source>Migrating database from version 8 to 9.</source>
         <translation>Convirtiendo base de datos de version 8 a 9.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="532"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="537"/>
         <source>Open database: %1</source>
         <translation>Abrir base de datos:%1</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="541"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="546"/>
         <source>Folders:          %1</source>
         <translation>Carpetas:          %1</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="550"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="555"/>
         <source>Tracks:           %1</source>
         <translation>Tracks:           %1</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="558"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="563"/>
         <source>Routes:           %1 (Only the basic route will be copied)</source>
         <translation>Routes:           %1 (Only the basic route will be copied)</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="566"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="571"/>
         <source>Waypoints:        %1</source>
         <translation>Waypoints:        %1</translation>
     </message>
     <message>
         <source>Overlays:         %1 (only area overlays will be converted to QMapShack)</source>
-        <translation type="vanished">Superposiciones:         %1 (solo las superposiciones de área se copiaran a QMapShack)</translation>
+        <translation type="obsolete">Superposiciones:         %1 (solo las superposiciones de área se copiaran a QMapShack)</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="574"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="579"/>
         <source>Overlays:         %1 (areas will be converted as areas, distance lines will be converted to tracks, all other overlay items will be lost)</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="581"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="586"/>
         <source>Diaries:          %1</source>
         <translation>Diarios:          %1</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="588"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="593"/>
         <source>Map selections:   %1 (can't be converted to QMapShack)</source>
         <translation>Selecciones de mapa:   %1 (NO pueden convertirse a QMapShack)</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="594"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="599"/>
         <source>------ Start to convert database to %1------</source>
         <translation>------ Comenzar a convertir base de datos a %1------</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="598"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="603"/>
         <source>Failed to create target database.</source>
         <translation>Fallo al crear la base de datos de destino.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="599"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="604"/>
         <source>------ Abort ------</source>
         <translation>------ Abortar ------</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="627"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="632"/>
         <source>------ Done ------</source>
         <translation>------ Hecho ------</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="635"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="640"/>
         <source>Restore folders...</source>
         <translation>Restaurar carpetas...</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="635"/>
-        <location filename="../qlgt/CQlgtDb.cpp" line="668"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="640"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="673"/>
         <source>Abort</source>
         <translation>Abortar</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="662"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="667"/>
         <source>Imported %1 folders and %2 diaries</source>
         <translation>Importadas %1 carpetas y %2 diarios</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="668"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="673"/>
         <source>Copy items...</source>
         <translation>Copia elementos....</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="692"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="697"/>
         <source>Imported %1 tracks, %2 waypoints, %3 routes, %4 areas</source>
         <translation>Importado: %1 tracks, %2 waypoints, %3 routes, %4 areas</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="693"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="698"/>
         <source>Import folders...</source>
         <translation>Importar carpetas...</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="758"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="763"/>
         <source>Overlay of type '%1' cant be converted</source>
         <translation>No puede convertirse superposición del tipo '%1' </translation>
     </message>
@@ -1772,6 +1843,123 @@ no es una definición de sistema de coordenadas válido:
     </message>
 </context>
 <context>
+    <name>CRouterRoutino</name>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="34"/>
+        <source>Foot</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="35"/>
+        <source>Horse</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="36"/>
+        <source>Wheelchair</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="37"/>
+        <source>Bicycle</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="38"/>
+        <source>Moped</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="39"/>
+        <source>Motorcycle</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="40"/>
+        <source>Motorcar</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="41"/>
+        <source>Goods</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="43"/>
+        <source>Shortest</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="44"/>
+        <source>Quickest</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="96"/>
+        <source>profile "%1"</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="97"/>
+        <source>, mode "%1"</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>CRouterRoutinoPathSetup</name>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutinoPathSetup.cpp" line="40"/>
+        <source>Add or remove paths containing Routino data. There can be multiple databases in a path but no sub-path is parsed.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutinoPathSetup.cpp" line="55"/>
+        <source>Select routing data file path...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Select DEM file path...</source>
+        <translation type="obsolete">Seleccione la ruta al archivo DEM...</translation>
+    </message>
+</context>
+<context>
+    <name>CRouterSetup</name>
+    <message>
+        <location filename="../gis/rte/router/CRouterSetup.cpp" line="36"/>
+        <source>Routino (offline)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterSetup.cpp" line="37"/>
+        <source>MapQuest (online)</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>CRoutinoDatabaseBuilder</name>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="30"/>
+        <source>Create Routino Database</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="61"/>
+        <source>Select files...</source>
+        <translation type="unfinished">Seleccionar ficheros de origen...</translation>
+    </message>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="85"/>
+        <source>Select target path...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="206"/>
+        <source>!!! failed !!!
+</source>
+        <translation type="unfinished">!!! fallo !!!</translation>
+    </message>
+</context>
+<context>
     <name>CSearchGoogle</name>
     <message>
         <location filename="../gis/search/CSearchGoogle.cpp" line="119"/>
@@ -1988,6 +2176,20 @@ no es una definición de sistema de coordenadas válido:
     </message>
 </context>
 <context>
+    <name>ICreateRouteFromWpt</name>
+    <message>
+        <location filename="../gis/rte/ICreateRouteFromWpt.ui" line="14"/>
+        <source>Create Route from Waypoints</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/ICreateRouteFromWpt.ui" line="30"/>
+        <location filename="../gis/rte/ICreateRouteFromWpt.ui" line="50"/>
+        <source>...</source>
+        <translation type="unfinished">...</translation>
+    </message>
+</context>
+<context>
     <name>IDemPathSetup</name>
     <message>
         <location filename="../dem/IDemPathSetup.ui" line="14"/>
@@ -2231,11 +2433,11 @@ no es una definición de sistema de coordenadas válido:
     </message>
     <message>
         <source>Sort By Time</source>
-        <translation type="vanished">Ordenar por Fecha/Hora</translation>
+        <translation type="obsolete">Ordenar por Fecha/Hora</translation>
     </message>
     <message>
         <source>Keep Order of Project</source>
-        <translation type="vanished">Mantener orden del proyecto</translation>
+        <translation type="obsolete">Mantener orden del proyecto</translation>
     </message>
     <message>
         <location filename="../gis/prj/IDetailsPrj.ui" line="115"/>
@@ -2454,7 +2656,7 @@ no es una definición de sistema de coordenadas válido:
     </message>
     <message>
         <source><html><head/><body><p>Read Only Mode</p></body></html></source>
-        <translation type="vanished"><html><head/><body><p>Modo Sólo Lectura</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Modo Sólo Lectura</p></body></html></translation>
     </message>
     <message>
         <location filename="../gis/wpt/IDetailsWpt.ui" line="270"/>
@@ -2602,7 +2804,17 @@ no es una definición de sistema de coordenadas válido:
         <translation>Modificar el inicio del track a </translation>
     </message>
     <message>
-        <location filename="../gis/trk/filter/IFilterNewDate.ui" line="71"/>
+        <location filename="../gis/trk/filter/IFilterNewDate.ui" line="51"/>
+        <source>dd.MM.yy HH:mm:ss</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/trk/filter/IFilterNewDate.ui" line="61"/>
+        <source>-</source>
+        <translation type="unfinished">-</translation>
+    </message>
+    <message>
+        <location filename="../gis/trk/filter/IFilterNewDate.ui" line="81"/>
         <source>...</source>
         <translation>...</translation>
     </message>
@@ -2810,34 +3022,34 @@ no es una definición de sistema de coordenadas válido:
 <context>
     <name>IImportDatabase</name>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="14"/>
+        <location filename="../tool/IImportDatabase.ui" line="14"/>
         <source>Form</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="45"/>
+        <location filename="../tool/IImportDatabase.ui" line="45"/>
         <source>Source Database:</source>
         <translation>Origen de Base de datos:</translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="52"/>
-        <location filename="../qlgt/IImportDatabase.ui" line="93"/>
+        <location filename="../tool/IImportDatabase.ui" line="52"/>
+        <location filename="../tool/IImportDatabase.ui" line="93"/>
         <source>-</source>
         <translation>-</translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="22"/>
-        <location filename="../qlgt/IImportDatabase.ui" line="63"/>
+        <location filename="../tool/IImportDatabase.ui" line="22"/>
+        <location filename="../tool/IImportDatabase.ui" line="63"/>
         <source>...</source>
         <translation>...</translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="86"/>
+        <location filename="../tool/IImportDatabase.ui" line="86"/>
         <source>Target Database:</source>
         <translation>Destino de Base de Datos:</translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="102"/>
+        <location filename="../tool/IImportDatabase.ui" line="102"/>
         <source>Start</source>
         <translation>Comenzar</translation>
     </message>
@@ -2902,37 +3114,37 @@ no es una definición de sistema de coordenadas válido:
         <translation>Ver</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="98"/>
+        <location filename="../IMainWindow.ui" line="99"/>
         <source>Window</source>
         <translation>Ventana</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="103"/>
+        <location filename="../IMainWindow.ui" line="104"/>
         <source>?</source>
         <translation>?</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="110"/>
+        <location filename="../IMainWindow.ui" line="111"/>
         <source>Project</source>
         <translation>Proyecto</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="120"/>
+        <location filename="../IMainWindow.ui" line="121"/>
         <source>Tool</source>
         <translation>Herramientas</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="138"/>
+        <location filename="../IMainWindow.ui" line="140"/>
         <source>Maps</source>
         <translation>Mapas</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="175"/>
+        <location filename="../IMainWindow.ui" line="177"/>
         <source>Dig. Elev. Model (DEM)</source>
         <translation>Modelo Digital del Terreno (DEM)</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="208"/>
+        <location filename="../IMainWindow.ui" line="210"/>
         <source>Data</source>
         <translation>Datos</translation>
     </message>
@@ -2941,219 +3153,239 @@ no es una definición de sistema de coordenadas válido:
         <translation type="obsolete">Añadir Espacio de Trabajo de Mapa</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="221"/>
-        <location filename="../IMainWindow.ui" line="224"/>
+        <location filename="../IMainWindow.ui" line="222"/>
+        <source>Route</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../IMainWindow.ui" line="256"/>
+        <location filename="../IMainWindow.ui" line="259"/>
         <source>Add Map View</source>
         <translation>Añadir Vista de Mapa</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="227"/>
+        <location filename="../IMainWindow.ui" line="262"/>
         <source>Ctrl+T</source>
         <translation>Ctrl+T</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="239"/>
+        <location filename="../IMainWindow.ui" line="274"/>
         <source>Show Scale</source>
         <translation>Mostrar Escala</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="248"/>
+        <location filename="../IMainWindow.ui" line="283"/>
         <source>Setup Map Font</source>
         <translation>Configurar Fuente del Mapa</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="260"/>
+        <location filename="../IMainWindow.ui" line="295"/>
         <source>Show Grid</source>
         <translation>Mostrar Malla</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="263"/>
+        <location filename="../IMainWindow.ui" line="298"/>
         <source>Ctrl+G</source>
         <translation>Ctrl+G</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="272"/>
+        <location filename="../IMainWindow.ui" line="307"/>
         <source>Setup Grid</source>
         <translation>Configurar Malla</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="275"/>
+        <location filename="../IMainWindow.ui" line="310"/>
         <source>Ctrl+Alt+G</source>
         <translation>Ctrl+Alt+G</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="287"/>
+        <location filename="../IMainWindow.ui" line="322"/>
         <source>Flip Mouse Wheel</source>
         <translation>Invertir la Rueda del Ratón</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="296"/>
-        <location filename="../IMainWindow.ui" line="299"/>
+        <location filename="../IMainWindow.ui" line="331"/>
+        <location filename="../IMainWindow.ui" line="334"/>
         <source>Setup Map Paths</source>
         <translation>Configurar Rutas de Mapas</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="311"/>
+        <location filename="../IMainWindow.ui" line="346"/>
         <source>POI Text</source>
         <translation>Texto del POI</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="323"/>
+        <location filename="../IMainWindow.ui" line="358"/>
         <source>Night / Day</source>
         <translation>Noche / Día</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="335"/>
+        <location filename="../IMainWindow.ui" line="370"/>
         <source>Map Tool Tip</source>
         <translation>Mostrar Tooltips en los Mapas</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="344"/>
+        <location filename="../IMainWindow.ui" line="379"/>
         <source>Setup DEM Paths</source>
         <translation>Configurar Rutas a los DEM</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="353"/>
+        <location filename="../IMainWindow.ui" line="388"/>
         <source>About</source>
         <translation>Acerca de</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="362"/>
+        <location filename="../IMainWindow.ui" line="397"/>
         <source>Help</source>
         <translation>Ayuda</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="371"/>
-        <location filename="../IMainWindow.ui" line="374"/>
+        <location filename="../IMainWindow.ui" line="406"/>
+        <location filename="../IMainWindow.ui" line="409"/>
         <source>Setup Map View</source>
         <translation>Configurar Vista de Mapa</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="488"/>
+        <location filename="../IMainWindow.ui" line="523"/>
         <source>VRT Builder</source>
         <translation>Asistente VRT</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="491"/>
+        <location filename="../IMainWindow.ui" line="526"/>
         <source>GUI front end to gdalbuildvrt</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="500"/>
+        <location filename="../IMainWindow.ui" line="535"/>
         <source>Store Map View</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="503"/>
+        <location filename="../IMainWindow.ui" line="538"/>
         <source>Write current active map and DEM list including the properties to a file</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="512"/>
+        <location filename="../IMainWindow.ui" line="547"/>
         <source>Load Map View</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="515"/>
+        <location filename="../IMainWindow.ui" line="550"/>
         <source>Restore view with active map and DEM list including the properties from a file</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="527"/>
+        <location filename="../IMainWindow.ui" line="562"/>
         <source>Ext. Profile</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="530"/>
+        <location filename="../IMainWindow.ui" line="565"/>
         <source>Ctrl+E</source>
         <translation type="unfinished">Ctrl+E</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="539"/>
+        <location filename="../IMainWindow.ui" line="574"/>
         <source>Close</source>
         <translation type="unfinished">Cerrar</translation>
     </message>
     <message>
+        <location filename="../IMainWindow.ui" line="583"/>
+        <source>Clone Map View</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../IMainWindow.ui" line="586"/>
+        <source>Ctrl+Shift+T</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../IMainWindow.ui" line="595"/>
+        <source>Create Routino Database</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
         <source>Setup Map Workspace</source>
         <translation type="obsolete">Configurar Espacio de Trabajo de Mapas</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="383"/>
+        <location filename="../IMainWindow.ui" line="418"/>
         <source>Load GIS Data</source>
         <translation>Cargar Datos GIS</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="386"/>
+        <location filename="../IMainWindow.ui" line="421"/>
         <source>Load projects from file</source>
         <translation>Cargar proyectos desde archivo</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="389"/>
+        <location filename="../IMainWindow.ui" line="424"/>
         <source>Ctrl+L</source>
         <translation>Ctrl+L</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="398"/>
+        <location filename="../IMainWindow.ui" line="433"/>
         <source>Save All GIS Data</source>
         <translation>Guardar Todos los Datos GIS</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="401"/>
+        <location filename="../IMainWindow.ui" line="436"/>
         <source>Save all projects in the workspace</source>
         <translation>Guardar todos los proyectos del espacio de trabajo</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="404"/>
+        <location filename="../IMainWindow.ui" line="439"/>
         <source>Ctrl+S</source>
         <translation>Ctrl+S</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="413"/>
+        <location filename="../IMainWindow.ui" line="448"/>
         <source>Setup Time Zone</source>
         <translation>Configurar Zona Horaria</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="422"/>
+        <location filename="../IMainWindow.ui" line="457"/>
         <source>Add empty project</source>
         <translation>Añadir proyecto vacío</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="434"/>
+        <location filename="../IMainWindow.ui" line="469"/>
         <source>Search Google</source>
         <translation>Buscar en Google</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="443"/>
+        <location filename="../IMainWindow.ui" line="478"/>
         <source>Close all projects</source>
         <translation>Cerrar todos los proyectos</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="446"/>
+        <location filename="../IMainWindow.ui" line="481"/>
         <source>F8</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="455"/>
+        <location filename="../IMainWindow.ui" line="490"/>
         <source>Setup Units</source>
         <translation>Configurar Unidades</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="464"/>
+        <location filename="../IMainWindow.ui" line="499"/>
         <source>Setup Workspace</source>
         <translation>Configurar Espacio de trabajo</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="467"/>
+        <location filename="../IMainWindow.ui" line="502"/>
         <source>Setup save on exit.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="476"/>
+        <location filename="../IMainWindow.ui" line="511"/>
         <source>Import Database from QLandkarte</source>
         <translation>Importar base de datos de Qlandkarte</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="479"/>
+        <location filename="../IMainWindow.ui" line="514"/>
         <source>Import QLandkarte GT database</source>
         <translation type="unfinished"></translation>
     </message>
@@ -3218,7 +3450,7 @@ I don't want to read the documentation!</source>
     </message>
     <message>
         <location filename="../map/IMapPathSetup.ui" line="29"/>
-        <location filename="../map/IMapPathSetup.ui" line="135"/>
+        <location filename="../map/IMapPathSetup.ui" line="154"/>
         <source>-</source>
         <translation>-</translation>
     </message>
@@ -3295,33 +3527,33 @@ I don't want to read the documentation!</source>
 <context>
     <name>IMapVrtBuilder</name>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="14"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="14"/>
         <source>Form</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="22"/>
-        <location filename="../map/IMapVrtBuilder.ui" line="56"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="22"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="56"/>
         <source>...</source>
         <translation>...</translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="39"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="39"/>
         <source>Select source files:</source>
         <translation>Seleccionar ficheros de origen:</translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="79"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="79"/>
         <source>Target Filename:</source>
         <translation>Fichero de destino:</translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="86"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="86"/>
         <source>-</source>
         <translation>-</translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="95"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="95"/>
         <source>Start</source>
         <translation>Comenzar</translation>
     </message>
@@ -3329,24 +3561,60 @@ I don't want to read the documentation!</source>
 <context>
     <name>IMouseEditLine</name>
     <message>
-        <location filename="../mouse/IMouseEditLine.cpp" line="344"/>
         <source>Add points?</source>
-        <translation>¿Añadir puntos?</translation>
+        <translation type="obsolete">¿Añadir puntos?</translation>
     </message>
     <message>
-        <location filename="../mouse/IMouseEditLine.cpp" line="344"/>
         <source>Add points to temporary line?</source>
-        <translation>¿Añadir puntos a la línea temporal?</translation>
+        <translation type="obsolete">¿Añadir puntos a la línea temporal?</translation>
     </message>
     <message>
-        <location filename="../mouse/IMouseEditLine.cpp" line="887"/>
         <source>Warning!</source>
-        <translation>¡Cuidado!</translation>
+        <translation type="obsolete">¡Cuidado!</translation>
     </message>
     <message>
-        <location filename="../mouse/IMouseEditLine.cpp" line="887"/>
         <source>This will replace all data of the orignal by a simple line of coordinates. All other data will be lost permanently.</source>
-        <translation>Esto sustituirá todos los datos del original con una simple línea de coordenadas. Todos los demás datos se perderán definitivamente.</translation>
+        <translation type="obsolete">Esto sustituirá todos los datos del original con una simple línea de coordenadas. Todos los demás datos se perderán definitivamente.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="238"/>
+        <source><b>New Line</b><br/>Move the mouse and use the left mouse button to drop points. When done use the right mouse button to stop.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="279"/>
+        <source><b>Delete Point</b><br/>Move the mouse close to a point and press the left button to delete it.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="287"/>
+        <source><b>Select Range of Points</b><br/>Left click on first point to start selection. Left click second point to complete selection and choose from options. Use the right mouse button to cancel.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="295"/>
+        <source><b>Move Point</b><br/>Move the mouse close to a point and press the left button to make it stick to the cursor. Move the mouse to move the point. Drop the point by a left click. Use the right mouse button to cancel.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="303"/>
+        <source><b>Add Point</b><br/>Move the mouse close to a line segment and press the left button to add a point. The point will stick to the cursor and you can move it.  Drop the point by a left click. Use the right mouse button to cancel.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="311"/>
+        <source><b>No Routing</b><br/>All points will be connected with a straight line.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="316"/>
+        <source><b>Auto Routing</b><br/>The current router setup is used to derive a route between points. <b>Note:</b> The selected router must be able to route on-the-fly. Offline routers usually can do, online routers can't.<br/></source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="321"/>
+        <source><b>Vector Routing</b><br/>Connect points with a line from a loaded vector map if possible.<br/></source>
+        <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
@@ -3502,27 +3770,214 @@ o
     </message>
 </context>
 <context>
+    <name>IRouterMapQuest</name>
+    <message>
+        <location filename="../gis/rte/router/IRouterMapQuest.ui" line="14"/>
+        <source>Form</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterMapQuest.ui" line="20"/>
+        <source>t.b.d</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>IRouterRoutino</name>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="14"/>
+        <source>Form</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="31"/>
+        <source>Profile</source>
+        <translation type="unfinished">Perfil</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="38"/>
+        <source>Mode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="45"/>
+        <source>Database</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="52"/>
+        <source>Add paths with Routino database.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="55"/>
+        <source>...</source>
+        <translation type="unfinished">...</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="121"/>
+        <source>To use offline routing you need to define paths to local routing data. Use the setup tool button to register a path.</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>IRouterRoutinoPathSetup</name>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutinoPathSetup.ui" line="14"/>
+        <source>Setup Routino database...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutinoPathSetup.ui" line="27"/>
+        <location filename="../gis/rte/router/IRouterRoutinoPathSetup.ui" line="47"/>
+        <source>...</source>
+        <translation type="unfinished">...</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutinoPathSetup.ui" line="99"/>
+        <source>-</source>
+        <translation type="unfinished">-</translation>
+    </message>
+</context>
+<context>
+    <name>IRouterSetup</name>
+    <message>
+        <location filename="../gis/rte/router/IRouterSetup.ui" line="14"/>
+        <source>Form</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>IRoutinoDatabaseBuilder</name>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="14"/>
+        <source>Form</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="22"/>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="63"/>
+        <source>...</source>
+        <translation type="unfinished">...</translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="39"/>
+        <source>Select source files:</source>
+        <translation type="unfinished">Seleccionar ficheros de origen:</translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="54"/>
+        <source>Start</source>
+        <translation type="unfinished">Comenzar</translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="86"/>
+        <source>Target Path:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="93"/>
+        <source>-</source>
+        <translation type="unfinished">-</translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="100"/>
+        <source>File Prefix</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>IScrOptEditLine</name>
     <message>
-        <location filename="../mouse/IScrOptEditLine.ui" line="26"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="32"/>
         <source>Form</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../mouse/IScrOptEditLine.ui" line="47"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="53"/>
         <source>Save to orignal</source>
         <translation>Guardar al original</translation>
     </message>
     <message>
-        <location filename="../mouse/IScrOptEditLine.ui" line="54"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="60"/>
         <source>Save as new</source>
         <translation>Guardar como nuevo</translation>
     </message>
     <message>
-        <location filename="../mouse/IScrOptEditLine.ui" line="61"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="67"/>
         <source>Abort</source>
         <translation>Abortar</translation>
     </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="102"/>
+        <source>Move points.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="105"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="128"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="148"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="168"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="280"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="297"/>
+        <source>...</source>
+        <translation type="unfinished">...</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="125"/>
+        <source>Add new points.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="145"/>
+        <source>Select a range of points.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="165"/>
+        <source>Delete a point.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="216"/>
+        <source>No auto-routing or line snapping</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="219"/>
+        <source>0</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="232"/>
+        <source>Use auto-routing to between points.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="235"/>
+        <source>A</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="248"/>
+        <source>Snap line along lines of a vector map.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="251"/>
+        <source>V</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="277"/>
+        <source>Undo last change</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="294"/>
+        <source>Redo last change</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>IScrOptOvlArea</name>
@@ -3533,19 +3988,34 @@ o
     </message>
     <message>
         <location filename="../gis/ovl/IScrOptOvlArea.ui" line="40"/>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="54"/>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="65"/>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="83"/>
+        <source>View details and edit.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="43"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="57"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="71"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="92"/>
         <source>...</source>
         <translation>...</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="51"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="54"/>
         <source>Copy area into another project.</source>
         <translation>Copiar área en otro proyecto.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="112"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="68"/>
+        <source>Delete area from project.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="89"/>
+        <source>Edit shape of the area.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="121"/>
         <source>TextLabel</source>
         <translation type="unfinished"></translation>
     </message>
@@ -3611,6 +4081,30 @@ o
     </message>
 </context>
 <context>
+    <name>IScrOptRangeLine</name>
+    <message>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="14"/>
+        <source>Form</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="20"/>
+        <source>Delete all points between the first and last one.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="23"/>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="37"/>
+        <source>...</source>
+        <translation type="unfinished">...</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="34"/>
+        <source>Caclculate a route between the first and last selected point.</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>IScrOptRangeTrk</name>
     <message>
         <location filename="../mouse/IScrOptRangeTrk.ui" line="14"/>
@@ -3653,14 +4147,16 @@ o
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/rte/IScrOptRte.ui" line="28"/>
         <source><html><head/><body><p>View details &amp; Edit</p></body></html></source>
-        <translation><html><head/><body><p>Ver detalles &amp; Editar</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Ver detalles &amp; Editar</p></body></html></translation>
     </message>
     <message>
         <location filename="../gis/rte/IScrOptRte.ui" line="31"/>
         <location filename="../gis/rte/IScrOptRte.ui" line="45"/>
         <location filename="../gis/rte/IScrOptRte.ui" line="59"/>
+        <location filename="../gis/rte/IScrOptRte.ui" line="80"/>
+        <location filename="../gis/rte/IScrOptRte.ui" line="94"/>
+        <location filename="../gis/rte/IScrOptRte.ui" line="108"/>
         <source>...</source>
         <translation>...</translation>
     </message>
@@ -3670,12 +4166,36 @@ o
         <translation>Copiar ruta en otro proyecto.</translation>
     </message>
     <message>
-        <location filename="../gis/rte/IScrOptRte.ui" line="56"/>
         <source><html><head/><body><p>Delete</p></body></html></source>
-        <translation><html><head/><body><p>Borrar</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Borrar</p></body></html></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="28"/>
+        <source>View details and edit.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="56"/>
+        <source>Delete route from project.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="77"/>
+        <source>Calculate route.</source>
+        <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/rte/IScrOptRte.ui" line="85"/>
+        <location filename="../gis/rte/IScrOptRte.ui" line="91"/>
+        <source>Reset route calculation.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="105"/>
+        <source>Move route points.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="134"/>
         <source>TextLabel</source>
         <translation type="unfinished"></translation>
     </message>
@@ -3688,14 +4208,12 @@ o
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/trk/IScrOptTrk.ui" line="40"/>
         <source>View details &amp; Edit properties of track.</source>
-        <translation>Ver detalles / Editar las propiedades del track.</translation>
+        <translation type="obsolete">Ver detalles / Editar las propiedades del track.</translation>
     </message>
     <message>
-        <location filename="../gis/trk/IScrOptTrk.ui" line="68"/>
         <source>Delete</source>
-        <translation>Eliminar</translation>
+        <translation type="obsolete">Eliminar</translation>
     </message>
     <message>
         <location filename="../gis/trk/IScrOptTrk.ui" line="89"/>
@@ -3713,6 +4231,11 @@ o
         <translation>Editar la posición de los puntos del track.</translation>
     </message>
     <message>
+        <location filename="../gis/trk/IScrOptTrk.ui" line="40"/>
+        <source>View details and edit properties of track.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
         <location filename="../gis/trk/IScrOptTrk.ui" line="43"/>
         <location filename="../gis/trk/IScrOptTrk.ui" line="57"/>
         <location filename="../gis/trk/IScrOptTrk.ui" line="71"/>
@@ -3731,6 +4254,11 @@ o
         <translation>Copiar track en otro proyecto.</translation>
     </message>
     <message>
+        <location filename="../gis/trk/IScrOptTrk.ui" line="68"/>
+        <source>Delete track from project.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
         <location filename="../gis/trk/IScrOptTrk.ui" line="106"/>
         <source>Select a range of points.</source>
         <translation>Seleccionar un rango de puntos.</translation>
@@ -3759,17 +4287,21 @@ o
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="49"/>
         <source><html><head/><body><p>View details &amp; Edit</p></body></html></source>
-        <translation>Ver detalles / Editar</translation>
+        <translation type="obsolete">Ver detalles / Editar</translation>
+    </message>
+    <message>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="49"/>
+        <source>View details and edit.</source>
+        <translation type="unfinished"></translation>
     </message>
     <message>
         <location filename="../gis/wpt/IScrOptWpt.ui" line="52"/>
         <location filename="../gis/wpt/IScrOptWpt.ui" line="66"/>
         <location filename="../gis/wpt/IScrOptWpt.ui" line="80"/>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="98"/>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="115"/>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="129"/>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="101"/>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="118"/>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="132"/>
         <source>...</source>
         <translation>...</translation>
     </message>
@@ -3780,21 +4312,38 @@ o
     </message>
     <message>
         <location filename="../gis/wpt/IScrOptWpt.ui" line="77"/>
+        <source>Delete waypoint from project.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="98"/>
+        <source>Show content as static bubble.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="115"/>
+        <source>Move waypoint to a new location.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="129"/>
+        <source>Clone waypoint and move clone a given distance and angle.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
         <source><html><head/><body><p>Delete</p></body></html></source>
-        <translation>Eliminar</translation>
+        <translation type="obsolete">Eliminar</translation>
     </message>
     <message>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="112"/>
         <source><html><head/><body><p>Move waypoint to a new location.</p></body></html></source>
-        <translation><html><head/><body><p>Mover el waypoint a una nueva ubicación.</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Mover el waypoint a una nueva ubicación.</p></body></html></translation>
     </message>
     <message>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="126"/>
         <source><html><head/><body><p>Clone waypoint and move clone a given distance and angle.</p></body></html></source>
-        <translation><html><head/><body><p>Clonar el waypoibt y moverlo una cierta distancia y ángulo.</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Clonar el waypoibt y moverlo una cierta distancia y ángulo.</p></body></html></translation>
     </message>
     <message>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="173"/>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="176"/>
         <source>TextLabel</source>
         <translation type="unfinished"></translation>
     </message>
@@ -4020,11 +4569,11 @@ o
     <name>ISetupFolder</name>
     <message>
         <source>Folder...</source>
-        <translation type="vanished">Carpeta...</translation>
+        <translation type="obsolete">Carpeta...</translation>
     </message>
     <message>
         <source>Name</source>
-        <translation type="vanished">Nombre</translation>
+        <translation type="obsolete">Nombre</translation>
     </message>
     <message>
         <location filename="../gis/db/ISetupFolder.ui" line="14"/>
@@ -4347,16 +4896,16 @@ o
     </message>
     <message>
         <source>Bad position format. Must be: [N|S] ddd mm.sss [W|E] ddd mm.sss</source>
-        <translation type="vanished">Formato de posición incorrecto. Debe ser: "[N|S] ggg mm.sss [W|E] ggg mm.sss"</translation>
+        <translation type="obsolete">Formato de posición incorrecto. Debe ser: "[N|S] ggg mm.sss [W|E] ggg mm.sss"</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="109"/>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="118"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="111"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="120"/>
         <source>Failed to read...</source>
         <translation>Fallo al leer...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="109"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="111"/>
         <source>Failed to read: %1
 line %2, column %3:
  %4</source>
@@ -4365,7 +4914,7 @@ línea %2, columna %3.
  %4</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="118"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="120"/>
         <source>Not a GPX file: </source>
         <translation>No es un archivo GPX: </translation>
     </message>
@@ -4400,43 +4949,63 @@ Areas: %1</source>
 Áreas: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="69"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="78"/>
         <source>Save project?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="69"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="78"/>
         <source>The project "%1" was changed. Save befor closing it?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="261"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="211"/>
+        <source>%1: Correlate tracks and waypoints.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/IGisProject.cpp" line="211"/>
+        <source>Abort</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/IGisProject.cpp" line="223"/>
+        <source>Did that take too long for you? Do you want to skip correlation of tracks and waypoints for this project (%1) in the future?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/IGisProject.cpp" line="224"/>
+        <source>Cancelled correlation...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/IGisProject.cpp" line="302"/>
         <source><br/>
 Filename: %1</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="278"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="307"/>
         <source>Waypoints: %1</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="282"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="311"/>
         <source>Tracks: %1</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="286"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="315"/>
         <source>Routes: %1</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="290"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="319"/>
         <source>Areas: %1</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="370"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="399"/>
         <source>Are you sure you want to delete '%1' from project '%2'?</source>
         <translation>¿Desea realmente eleiminar '%1' del proyecto '%2'?</translation>
     </message>
@@ -4447,28 +5016,28 @@ Filename: %1</source>
     </message>
     <message>
         <location filename="../gis/CGisListDB.cpp" line="436"/>
-        <location filename="../gis/prj/IGisProject.cpp" line="371"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="400"/>
         <source>Delete...</source>
         <translation>Borrar...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="96"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="98"/>
         <location filename="../gis/qms/CQmsProject.cpp" line="48"/>
-        <location filename="../gis/qms/CQmsProject.cpp" line="144"/>
+        <location filename="../gis/qms/CQmsProject.cpp" line="145"/>
         <source>Failed to open...</source>
         <translation>Fallo al abrir...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="96"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="98"/>
         <location filename="../gis/qms/CQmsProject.cpp" line="48"/>
-        <location filename="../gis/qms/CQmsProject.cpp" line="144"/>
+        <location filename="../gis/qms/CQmsProject.cpp" line="145"/>
         <source>Failed to open %1</source>
         <translation>Fallo al abrir %1</translation>
     </message>
     <message>
         <location filename="../gis/db/CDBProject.cpp" line="149"/>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="216"/>
-        <location filename="../gis/qms/CQmsProject.cpp" line="94"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="223"/>
+        <location filename="../gis/qms/CQmsProject.cpp" line="95"/>
         <location filename="../gis/tnv/CTwoNavProject.cpp" line="159"/>
         <source>Save GIS data to...</source>
         <translation>Guardar los datos GIS en...</translation>
@@ -4484,154 +5053,156 @@ Filename: %1</source>
         <translation>Cancelar guardar</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="291"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="298"/>
         <source>File exists ...</source>
         <translation>El archivo ya existe ...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="292"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="299"/>
         <source>The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains GPX data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file.  Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b></source>
         <translation>El archivo ya existe y no lo ha creado QMapShack. Si pulsa 'sí' todos los datos de este archivo se perderán. Incluso si el archivo contiene datos GPX y QMapShack lo ha leído, QMapShack podría no ser capaz de leer y almacenar todos los elementos en el archivo, y aquellos que no haya leído se perderán. Se le recomienda usar otro archivo distinto. <b>¿Quiere realmente sobrescribir el archivo</b></translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="393"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="407"/>
         <source>Failed to create file '%1'</source>
         <translation>Fallo al crear el archivo '%1'</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="407"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="421"/>
         <source>Saveing GIS data failed...</source>
         <translation>Fallo al guardar los datos GIS...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="402"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="416"/>
         <source>Failed to write file '%1'</source>
         <translation>Fallo al escribir en el archivo '%1'</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="416"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="227"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="441"/>
         <source>Length: %1 %2</source>
         <translation>Longitud: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="423"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="448"/>
         <source>, %1%2 %3, %4%5 %6</source>
         <translation>, %1%2 %3, %4%5 %6</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="431"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="243"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="456"/>
         <source>Time: %1</source>
         <translation>Tiempo: %1</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="434"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="444"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="459"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="469"/>
         <source>, Speed: %1 %2</source>
         <translation>, Velocidad: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="441"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="466"/>
         <source>Moving: %1</source>
         <translation>En movimiento: %1</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="450"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="475"/>
         <source>Start: %1</source>
         <translation>Comienzo: %1</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="455"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="480"/>
         <source>End: %1</source>
         <translation>Final: %1</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="459"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="484"/>
         <source>Points: %1 (%2)</source>
         <translation>Puntos: %1 (%2)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="577"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="602"/>
         <source>Ele.: %1 %2</source>
         <translation>Altitud: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="580"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="605"/>
         <source> slope: %1%3 (%2%)</source>
         <translation> pendiente: %1%3 (%2%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="585"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="610"/>
         <source> speed: %1%2</source>
         <translation> velocidad: %1%2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="597"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="622"/>
         <source>Ascend: %1%2 (%3%)</source>
         <translation>Ascenso: %1%2 (%3%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="601"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="626"/>
         <source>Ascend: - (-)</source>
         <translation>Ascenso: - (-)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="611"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="636"/>
         <source> Descend: - (-) </source>
         <translation> Descenso: - (-) </translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="632"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="657"/>
         <source> Moving: - (-) </source>
         <translation> En movimiento: - (-) </translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="651"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="676"/>
         <source>Ascend: %1%2</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="656"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="673"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="681"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="698"/>
         <source>, %1%2</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="661"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="686"/>
         <source>Ascend: -</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="668"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="693"/>
         <source> Descend: %1%2</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="678"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="703"/>
         <source>Descend: -</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="684"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="709"/>
         <source>Dist.: %1%2</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="689"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="714"/>
         <source> Time: %1%2</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1370"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1403"/>
         <source>Hide points.</source>
         <translation>Ocultar puntos.</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1416"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1449"/>
         <source>Show points.</source>
         <translation>Mostrar puntos.</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="607"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="632"/>
         <source> Descend: %1%2 (%3%)</source>
         <translation> Descenso: %1%2 (%3%)</translation>
     </message>
@@ -4641,17 +5212,17 @@ Filename: %1</source>
         <translation>Se cambiaron los puntos del track, y descartados todos los datos previos.</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="618"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="643"/>
         <source>Dist.: %1%2 (%3%)</source>
         <translation>Distancia: %1%2 (%3%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="622"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="647"/>
         <source>Dist.: - (-)</source>
         <translation>Dist.: - (-)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="628"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="653"/>
         <source> Moving: %1%2 (%3%)</source>
         <translation> En movimiento: %1%2 (%3%)</translation>
     </message>
@@ -4677,63 +5248,63 @@ Filename: %1</source>
     </message>
     <message>
         <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="142"/>
-        <location filename="../gis/rte/CGisItemRte.cpp" line="45"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="49"/>
         <location filename="../gis/trk/CGisItemTrk.cpp" line="184"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="131"/>
         <source>_Clone</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="433"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="444"/>
         <source>Area: %1%2</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="491"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="502"/>
         <source>Changed area shape.</source>
         <translation>Se cambió la forma del área.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="499"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="510"/>
         <source>Changed name.</source>
         <translation>Se cambió el nombre.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="505"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="516"/>
         <source>Changed border width.</source>
         <translation>Se cambió la anchura del borde.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="511"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="522"/>
         <source>Changed fill pattern.</source>
         <translation>Se cambió el patró de relleno.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="517"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="528"/>
         <source>Changed opacity.</source>
         <translation>Se cambió la opacidad.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="523"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="534"/>
         <source>Changed comment.</source>
         <translation>Se cambió el comentario.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="529"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="540"/>
         <source>Changed description.</source>
         <translation>Se cambió la descripción.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="535"/>
-        <location filename="../gis/rte/CGisItemRte.cpp" line="154"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1775"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="546"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="204"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1808"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="448"/>
         <source>Changed links</source>
         <translation>Se cambió el enlace</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="547"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1787"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="558"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1820"/>
         <source>Changed color</source>
         <translation>Se cambió el color</translation>
     </message>
@@ -4748,25 +5319,27 @@ Filename: %1</source>
         <translation>Proximidad: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1757"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1790"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="396"/>
         <source>Changed name</source>
         <translation>Se cambió el nombre</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1168"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1183"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1202"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1261"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1441"/>
-        <location filename="../mouse/CMouseEditArea.cpp" line="100"/>
-        <location filename="../mouse/CMouseEditTrk.cpp" line="104"/>
+        <location filename="../gis/rte/CCreateRouteFromWpt.cpp" line="65"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1201"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1216"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1235"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1294"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1474"/>
+        <location filename="../mouse/CMouseEditArea.cpp" line="99"/>
+        <location filename="../mouse/CMouseEditRte.cpp" line="109"/>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="115"/>
         <source>Edit name...</source>
         <translation>Editar nombre...</translation>
     </message>
     <message>
         <source>Enter new waypoint name.</source>
-        <translation type="vanished">Introduzca el nuevo nombre del waypoint.</translation>
+        <translation type="obsolete">Introduzca el nuevo nombre del waypoint.</translation>
     </message>
     <message>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="406"/>
@@ -4799,20 +5372,55 @@ Filename: %1</source>
         <translation>Añadir Imagen</translation>
     </message>
     <message>
-        <location filename="../gis/rte/CGisItemRte.cpp" line="142"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1763"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="192"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1796"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="436"/>
         <source>Changed comment</source>
         <translation>Se cambió el comentario</translation>
     </message>
     <message>
-        <location filename="../gis/rte/CGisItemRte.cpp" line="148"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1769"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="198"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1802"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="442"/>
         <source>Changed description</source>
         <translation>Se cambió la descripción</translation>
     </message>
     <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="231"/>
+        <source>Length: -</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="239"/>
+        <source>Time: %2 days %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="248"/>
+        <source>Time: -</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="254"/>
+        <source>Last time routed:<br/>%1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="256"/>
+        <source>with %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="258"/>
+        <source>Calculation took %1 sec.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="479"/>
+        <source>Changed route points.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
         <location filename="../gis/gpx/serialization.cpp" line="599"/>
         <source>Archived</source>
         <translation>Archivado</translation>
@@ -4893,17 +5501,17 @@ Filename: %1</source>
         <translation><p>--- sin links ---</p></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1168"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1183"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1202"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1261"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1441"/>
-        <location filename="../mouse/CMouseEditTrk.cpp" line="104"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1201"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1216"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1235"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1294"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1474"/>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="115"/>
         <source>Enter new track name.</source>
         <translation>Introduzca el nombre del nuevo track.</translation>
     </message>
     <message>
-        <location filename="../mouse/CMouseEditArea.cpp" line="100"/>
+        <location filename="../mouse/CMouseEditArea.cpp" line="99"/>
         <source>Enter new area name.</source>
         <translation>Introduzca el nombre del nuevo área.</translation>
     </message>
@@ -5004,12 +5612,12 @@ Filename: %1</source>
         <translation>Velocidad modificada a %1%2.</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="956"/>
+        <location filename="../gis/CGisListWks.cpp" line="988"/>
         <source>Delete project...</source>
         <translation>Eliminar Proyecto...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="956"/>
+        <location filename="../gis/CGisListWks.cpp" line="988"/>
         <source>Do you really want to delete %1?</source>
         <translation>¿Desea realmente eliminar %1?</translation>
     </message>
@@ -5020,13 +5628,13 @@ Filename: %1</source>
         <location filename="../gis/tnv/serialization.cpp" line="431"/>
         <location filename="../gis/tnv/serialization.cpp" line="460"/>
         <location filename="../gis/tnv/serialization.cpp" line="471"/>
-        <location filename="../gis/tnv/serialization.cpp" line="492"/>
-        <location filename="../gis/tnv/serialization.cpp" line="632"/>
-        <location filename="../gis/tnv/serialization.cpp" line="660"/>
-        <location filename="../gis/tnv/serialization.cpp" line="671"/>
-        <location filename="../gis/tnv/serialization.cpp" line="689"/>
-        <location filename="../gis/tnv/serialization.cpp" line="717"/>
-        <location filename="../gis/tnv/serialization.cpp" line="791"/>
+        <location filename="../gis/tnv/serialization.cpp" line="504"/>
+        <location filename="../gis/tnv/serialization.cpp" line="644"/>
+        <location filename="../gis/tnv/serialization.cpp" line="672"/>
+        <location filename="../gis/tnv/serialization.cpp" line="683"/>
+        <location filename="../gis/tnv/serialization.cpp" line="701"/>
+        <location filename="../gis/tnv/serialization.cpp" line="729"/>
+        <location filename="../gis/tnv/serialization.cpp" line="803"/>
         <source>Error...</source>
         <translation>Error...</translation>
     </message>
@@ -5035,23 +5643,23 @@ Filename: %1</source>
         <location filename="../gis/tnv/CTwoNavProject.cpp" line="191"/>
         <location filename="../gis/tnv/serialization.cpp" line="295"/>
         <location filename="../gis/tnv/serialization.cpp" line="431"/>
-        <location filename="../gis/tnv/serialization.cpp" line="632"/>
+        <location filename="../gis/tnv/serialization.cpp" line="644"/>
         <source>Failed to open %1.</source>
         <translation>Fallo al abrir %1.</translation>
     </message>
     <message>
         <location filename="../gis/tnv/serialization.cpp" line="460"/>
         <location filename="../gis/tnv/serialization.cpp" line="471"/>
-        <location filename="../gis/tnv/serialization.cpp" line="660"/>
-        <location filename="../gis/tnv/serialization.cpp" line="671"/>
+        <location filename="../gis/tnv/serialization.cpp" line="672"/>
+        <location filename="../gis/tnv/serialization.cpp" line="683"/>
         <source>Only support lon/lat WGS 84 format.</source>
         <translation type="unfinished">Solamente soporta formato lon/lat WGS84.</translation>
     </message>
     <message>
-        <location filename="../gis/tnv/serialization.cpp" line="492"/>
-        <location filename="../gis/tnv/serialization.cpp" line="689"/>
-        <location filename="../gis/tnv/serialization.cpp" line="717"/>
-        <location filename="../gis/tnv/serialization.cpp" line="791"/>
+        <location filename="../gis/tnv/serialization.cpp" line="504"/>
+        <location filename="../gis/tnv/serialization.cpp" line="701"/>
+        <location filename="../gis/tnv/serialization.cpp" line="729"/>
+        <location filename="../gis/tnv/serialization.cpp" line="803"/>
         <source>Failed to read data.</source>
         <translation>Fallo al leer los datos.</translation>
     </message>
@@ -5061,9 +5669,15 @@ Filename: %1</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../device/IDevice.cpp" line="202"/>
+        <location filename="../device/IDevice.cpp" line="204"/>
         <source>There is another project with the same name. If you press 'ok' it will be removed and replaced.</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <location filename="../gis/rte/CCreateRouteFromWpt.cpp" line="65"/>
+        <location filename="../mouse/CMouseEditRte.cpp" line="109"/>
+        <source>Enter new route name.</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 </TS>
diff --git a/src/locale/qmapshack_fr.ts b/src/locale/qmapshack_fr.ts
index 1a28452..27ac261 100644
--- a/src/locale/qmapshack_fr.ts
+++ b/src/locale/qmapshack_fr.ts
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE TS>
-<TS version="2.1" language="fr">
+<TS version="2.0" language="fr">
 <context>
     <name>CCanvas</name>
     <message>
-        <location filename="../canvas/CCanvas.cpp" line="63"/>
+        <location filename="../canvas/CCanvas.cpp" line="64"/>
         <source>View %1</source>
         <translation>Vue %1</translation>
     </message>
@@ -40,7 +40,7 @@
     <message>
         <location filename="../dem/CDemPropSetup.cpp" line="183"/>
         <source><b>Grade %1</b></source>
-        <translation type="unfinished"><b>Niveau %1</b></translation>
+        <translation><b>Niveau %1</b></translation>
     </message>
 </context>
 <context>
@@ -49,7 +49,7 @@
         <location filename="../dem/CDemVRT.cpp" line="45"/>
         <location filename="../dem/CDemVRT.cpp" line="52"/>
         <location filename="../dem/CDemVRT.cpp" line="61"/>
-        <location filename="../dem/CDemVRT.cpp" line="88"/>
+        <location filename="../dem/CDemVRT.cpp" line="89"/>
         <source>Error...</source>
         <translation>Erreur...</translation>
     </message>
@@ -65,7 +65,7 @@
         <translation>Le DEM doit contenir un seule bande avec des données en 16 ou 32 bits.</translation>
     </message>
     <message>
-        <location filename="../dem/CDemVRT.cpp" line="88"/>
+        <location filename="../dem/CDemVRT.cpp" line="89"/>
         <source>No georeference information found.</source>
         <translation>Aucune information de géoréférencement trouvé</translation>
     </message>
@@ -105,101 +105,111 @@
     <message>
         <location filename="../gis/ovl/CDetailsOvlArea.cpp" line="136"/>
         <source>Enter new area name.</source>
-        <translation type="unfinished">Saisir le nouveau nom de la surface.</translation>
+        <translation type="unfinished">Entrez le nom de la nouvelle surface.</translation>
     </message>
     <message>
         <source>Enter new waypoint name.</source>
-        <translation type="vanished">Saisir le nouveau nom du waypoint.</translation>
+        <translation type="obsolete">Saisir le nouveau nom du waypoint.</translation>
     </message>
 </context>
 <context>
     <name>CDetailsPrj</name>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="175"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="537"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="188"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="550"/>
         <source>none</source>
         <translation>aucun</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="234"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="247"/>
         <source>Build diary...</source>
         <translation>Créer le journal...</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="234"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="247"/>
         <source>Abort</source>
         <translation>Annuler</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="292"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="305"/>
         <source><h2>Waypoints</h2></source>
         <translation><h2>Waypoints</h2></translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="255"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="299"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="330"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="438"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="268"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="312"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="343"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="451"/>
         <source>Info</source>
         <translation>Information</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="256"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="300"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="331"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="439"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="269"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="313"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="344"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="452"/>
         <source>Comment</source>
         <translation>Commentaire</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="323"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="336"/>
         <source><h2>Tracks</h2></source>
         <translation><h2>Traces</h2></translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="248"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="261"/>
         <source><h2>Areas</h2></source>
         <translation><h2>Surfaces</h2></translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="461"/>
-        <source>distance: %1%2</source>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="82"/>
+        <source>You want to sort waypoints along a track, but you switched off track and waypoint correlation. Do you want to switch it on again?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="463"/>
-        <source>ascent: %1%2</source>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="83"/>
+        <source>Correlation...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="465"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="474"/>
+        <source>distance: %1%2</source>
+        <translation>distance : %1%2</translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="476"/>
+        <source>ascent: %1%2</source>
+        <translation>montée : %1%2</translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="478"/>
         <source>descend: %1%2</source>
-        <translation type="unfinished"></translation>
+        <translation>descente : %1%2</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="523"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="550"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="536"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="563"/>
         <source>Edit name...</source>
         <translation>Éditer le nom...</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="523"/>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="550"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="536"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="563"/>
         <source>Enter new project name.</source>
-        <translation>Saisir le nom du projet.</translation>
+        <translation type="unfinished">Entrez le nom du nouveau projet.</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="532"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="545"/>
         <source>Edit keywords...</source>
         <translation>Éditer les mots-clés...</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="532"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="545"/>
         <source>Enter keywords.</source>
         <translation>Saisir les mots-clés.</translation>
     </message>
     <message>
-        <location filename="../gis/prj/CDetailsPrj.cpp" line="666"/>
+        <location filename="../gis/prj/CDetailsPrj.cpp" line="679"/>
         <source>Print Diary</source>
         <translation>Imprimer le journal</translation>
     </message>
@@ -237,14 +247,14 @@
         <translation></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CDetailsTrk.cpp" line="397"/>
+        <location filename="../gis/trk/CDetailsTrk.cpp" line="395"/>
         <source>Edit name...</source>
-        <translation type="unfinished">Éditer le nom...</translation>
+        <translation>Éditer le nom...</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CDetailsTrk.cpp" line="397"/>
+        <location filename="../gis/trk/CDetailsTrk.cpp" line="395"/>
         <source>Enter new track name.</source>
-        <translation type="unfinished">Saisir le nouveau nom de la trace.</translation>
+        <translation type="unfinished">Entrez le nom de la nouvelle trace.</translation>
     </message>
 </context>
 <context>
@@ -257,12 +267,12 @@
     <message>
         <location filename="../gis/wpt/CDetailsWpt.cpp" line="157"/>
         <source>Enter new waypoint name.</source>
-        <translation>Saisir le nouveau nom du waypoint.</translation>
+        <translation type="unfinished">Entrez le nom du nouveau waypoint.</translation>
     </message>
     <message>
         <location filename="../gis/wpt/CDetailsWpt.cpp" line="176"/>
         <source>Enter new proximity range.</source>
-        <translation>Saisir le rayon de l'alarme de proximité</translation>
+        <translation type="unfinished">Entrez le rayon de l'alarme de proximité.</translation>
     </message>
 </context>
 <context>
@@ -270,7 +280,7 @@
     <message>
         <location filename="../helpers/CElevationDialog.cpp" line="83"/>
         <source>No DEM data found for that point.</source>
-        <translation>Pas de données DEM disponibles pour ce point</translation>
+        <translation>Pas de données DEM disponibles pour ce point.</translation>
     </message>
 </context>
 <context>
@@ -346,124 +356,144 @@
 <context>
     <name>CGisListWks</name>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="94"/>
+        <location filename="../gis/CGisListWks.cpp" line="95"/>
         <source>Edit..</source>
         <translation>Éditer..</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="95"/>
+        <location filename="../gis/CGisListWks.cpp" line="96"/>
         <source>Save As...</source>
         <translation>Enregistrer sous...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="96"/>
+        <location filename="../gis/CGisListWks.cpp" line="97"/>
         <source>Save</source>
         <translation>Enregistrer</translation>
     </message>
     <message>
         <source>Update Project on Devices</source>
-        <translation type="vanished">Mettre à jour le projet sur tous les appareils</translation>
+        <translation type="obsolete">Mettre à jour le projet sur tous les appareils</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="97"/>
+        <location filename="../gis/CGisListWks.cpp" line="98"/>
         <source>Send to Devices</source>
-        <translation type="unfinished"></translation>
+        <translation>Envoyer vers les appareils</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="98"/>
+        <location filename="../gis/CGisListWks.cpp" line="99"/>
         <source>Close</source>
         <translation>Fermer</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="104"/>
+        <location filename="../gis/CGisListWks.cpp" line="105"/>
         <source>Update Project on Device</source>
         <translation>Mettre à jour le projet sur l'appareil</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="105"/>
-        <location filename="../gis/CGisListWks.cpp" line="126"/>
+        <location filename="../gis/CGisListWks.cpp" line="106"/>
+        <location filename="../gis/CGisListWks.cpp" line="127"/>
         <source>Delete</source>
         <translation>Supprimer</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="116"/>
+        <location filename="../gis/CGisListWks.cpp" line="117"/>
         <source>Edit...</source>
-        <translation>Éditer..</translation>
+        <translation>Éditer...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="117"/>
+        <location filename="../gis/CGisListWks.cpp" line="118"/>
         <source>Copy to...</source>
         <translation>Copier vers...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="119"/>
+        <location filename="../gis/CGisListWks.cpp" line="120"/>
         <source>Track Profile</source>
         <translation>Profile de la trace</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="121"/>
+        <location filename="../gis/CGisListWks.cpp" line="122"/>
         <source>Select Range</source>
         <translation>Sélectionner des points</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="122"/>
+        <location filename="../gis/CGisListWks.cpp" line="123"/>
         <source>Edit Track Points</source>
         <translation>Éditer les points de la trace</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="123"/>
+        <location filename="../gis/CGisListWks.cpp" line="124"/>
         <source>Reverse Track</source>
         <translation>Inverser la trace</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="124"/>
+        <location filename="../gis/CGisListWks.cpp" line="125"/>
         <source>Combine Tracks</source>
         <translation>Joindre des traces</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="132"/>
+        <location filename="../gis/CGisListWks.cpp" line="133"/>
         <source>Show Bubble</source>
-        <translation type="unfinished"></translation>
+        <translation>Afficher la bulle</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="134"/>
+        <location filename="../gis/CGisListWks.cpp" line="135"/>
         <source>Move Waypoint</source>
         <translation>Déplacer le waypoint</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="135"/>
+        <location filename="../gis/CGisListWks.cpp" line="136"/>
         <source>Proj. Waypoint...</source>
         <translation>Projection du waypoint...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="149"/>
+        <location filename="../gis/CGisListWks.cpp" line="144"/>
+        <source>Calculate Route</source>
+        <translation>Calculer l'itinéraire</translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisListWks.cpp" line="145"/>
+        <source>Reset Route</source>
+        <translation>Réinitialiser la route</translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisListWks.cpp" line="146"/>
+        <source>Edit Route</source>
+        <translation>Éditer la route</translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisListWks.cpp" line="155"/>
         <source>Edit Area Points</source>
         <translation>Éditer les points de la surface</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="696"/>
+        <location filename="../gis/CGisListWks.cpp" line="162"/>
+        <source>Create Route</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisListWks.cpp" line="708"/>
         <source>Saving workspace. Please wait.</source>
         <translation>Sauvegarde de l'espace de travail. Patientez.</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="737"/>
+        <location filename="../gis/CGisListWks.cpp" line="750"/>
         <source>Loading workspace. Please wait.</source>
         <translation>Chargement de l'espace de travail. Patientez.</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="921"/>
+        <location filename="../gis/CGisListWks.cpp" line="952"/>
         <source>Close all projects...</source>
         <translation>Fermer tous les projets...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="921"/>
+        <location filename="../gis/CGisListWks.cpp" line="952"/>
         <source>This will remove all projects from the workspace.</source>
         <translation>Ceci enlevera tous les projets de l'espace de travail.</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="596"/>
-        <location filename="../gis/CGisListWks.cpp" line="1296"/>
-        <location filename="../gis/CGisListWks.cpp" line="1335"/>
+        <location filename="../gis/CGisListWks.cpp" line="608"/>
+        <location filename="../gis/CGisListWks.cpp" line="1371"/>
+        <location filename="../gis/CGisListWks.cpp" line="1409"/>
         <source><b>Update devices</b><p>Update %1<br/>Please wait...</p></source>
         <translation><b>Mise à jour des appareils</b><p>Mise à jour de %1<br/>Patientez...</p></translation>
     </message>
@@ -471,25 +501,35 @@
 <context>
     <name>CGisWidget</name>
     <message>
-        <location filename="../gis/CGisWidget.cpp" line="444"/>
+        <location filename="../gis/CGisWidget.cpp" line="114"/>
+        <source>Load project...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisWidget.cpp" line="114"/>
+        <source>The project "%1" is already in the workspace.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/CGisWidget.cpp" line="449"/>
         <source>Cut Track...</source>
         <translation>Couper la trace...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisWidget.cpp" line="444"/>
+        <location filename="../gis/CGisWidget.cpp" line="449"/>
         <source>Do you want to delete the original track?</source>
-        <translation>Voulez-vous garder la trace originale ?</translation>
+        <translation>Voulez-vous supprimer la trace originale?</translation>
     </message>
 </context>
 <context>
     <name>CGrid</name>
     <message>
-        <location filename="../grid/CGrid.cpp" line="61"/>
+        <location filename="../grid/CGrid.cpp" line="63"/>
         <source>[Grid: %1%2%5 %3%4%5] </source>
         <translation>[Grille : %1%2%5 %3%4%5]</translation>
     </message>
     <message>
-        <location filename="../grid/CGrid.cpp" line="65"/>
+        <location filename="../grid/CGrid.cpp" line="67"/>
         <source>[Grid: N %1m, E %2m] </source>
         <translation>[Grille : N %1m, E %2m]</translation>
     </message>
@@ -505,17 +545,17 @@
 <context>
     <name>CImportDatabase</name>
     <message>
-        <location filename="../qlgt/CImportDatabase.cpp" line="29"/>
+        <location filename="../tool/CImportDatabase.cpp" line="29"/>
         <source>Import QLandkarte Database</source>
         <translation>Importer une base de données QLandkarte</translation>
     </message>
     <message>
-        <location filename="../qlgt/CImportDatabase.cpp" line="73"/>
+        <location filename="../tool/CImportDatabase.cpp" line="73"/>
         <source>Select source database...</source>
         <translation>Choisissez la base de données à importer...</translation>
     </message>
     <message>
-        <location filename="../qlgt/CImportDatabase.cpp" line="93"/>
+        <location filename="../tool/CImportDatabase.cpp" line="93"/>
         <source>Select target database...</source>
         <translation>Choisissez la base de données cible...</translation>
     </message>
@@ -523,24 +563,24 @@
 <context>
     <name>CMainWindow</name>
     <message>
-        <location filename="../CMainWindow.cpp" line="492"/>
+        <location filename="../CMainWindow.cpp" line="560"/>
         <source>Ele: %1%2</source>
         <translation>Altitude: %1%2</translation>
     </message>
     <message>
-        <location filename="../CMainWindow.cpp" line="618"/>
+        <location filename="../CMainWindow.cpp" line="691"/>
         <source>Load GIS Data...</source>
         <translation>Charger des données SIG...</translation>
     </message>
     <message>
-        <location filename="../CMainWindow.cpp" line="652"/>
+        <location filename="../CMainWindow.cpp" line="725"/>
         <source>Select output file</source>
-        <translation type="unfinished"></translation>
+        <translation>Sélectionner le fichier de sortie</translation>
     </message>
     <message>
-        <location filename="../CMainWindow.cpp" line="678"/>
+        <location filename="../CMainWindow.cpp" line="751"/>
         <source>Select file to load</source>
-        <translation type="unfinished"></translation>
+        <translation>Sélectionner le fichier à charger</translation>
     </message>
 </context>
 <context>
@@ -1130,46 +1170,46 @@
         <translation>Erreur de lecture de la structure du fichier : </translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="640"/>
+        <location filename="../map/CMapIMG.cpp" line="642"/>
         <source>Loading %1</source>
         <translation>Chargement de %1</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="645"/>
+        <location filename="../map/CMapIMG.cpp" line="649"/>
         <source>User abort: </source>
         <translation>Interruption par l'utilisateur : </translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="648"/>
+        <location filename="../map/CMapIMG.cpp" line="652"/>
         <source>File is NT format. QMapShack is unable to read map files with NT format: </source>
         <translation>Le fichier est au format NT. QMapShack ne peut pas lire des fichiers au format NT : </translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="740"/>
+        <location filename="../map/CMapIMG.cpp" line="744"/>
         <source>File contains locked / encypted data. Garmin does not want you to use this file with any other software than the one supplied by Garmin.</source>
         <translation>Le fichier contient des données verrouillées / cryptées. Garmin ne vous autorise pas d'utiliser ce fichier avec un logiciel non fourni par Garmin.</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="2496"/>
-        <location filename="../map/CMapIMG.cpp" line="2504"/>
+        <location filename="../map/CMapIMG.cpp" line="2500"/>
         <location filename="../map/CMapIMG.cpp" line="2508"/>
-        <location filename="../map/CMapIMG.cpp" line="2513"/>
-        <location filename="../map/CMapIMG.cpp" line="2559"/>
-        <location filename="../map/CMapIMG.cpp" line="2567"/>
+        <location filename="../map/CMapIMG.cpp" line="2512"/>
+        <location filename="../map/CMapIMG.cpp" line="2517"/>
+        <location filename="../map/CMapIMG.cpp" line="2563"/>
         <location filename="../map/CMapIMG.cpp" line="2571"/>
-        <location filename="../map/CMapIMG.cpp" line="2576"/>
+        <location filename="../map/CMapIMG.cpp" line="2575"/>
+        <location filename="../map/CMapIMG.cpp" line="2580"/>
         <source>Point of Interest</source>
         <translation>Point d'intérêt</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="2703"/>
+        <location filename="../map/CMapIMG.cpp" line="2707"/>
         <source>Unknown</source>
         <translation>Inconnu</translation>
     </message>
     <message>
-        <location filename="../map/CMapIMG.cpp" line="2749"/>
-        <location filename="../map/CMapIMG.cpp" line="2757"/>
-        <location filename="../map/CMapIMG.cpp" line="2764"/>
+        <location filename="../map/CMapIMG.cpp" line="2753"/>
+        <location filename="../map/CMapIMG.cpp" line="2761"/>
+        <location filename="../map/CMapIMG.cpp" line="2768"/>
         <source>Area</source>
         <translation>Surface</translation>
     </message>
@@ -1189,7 +1229,7 @@
     <message>
         <location filename="../map/CMapList.cpp" line="174"/>
         <source>Where do you want to store maps?</source>
-        <translation type="unfinished"></translation>
+        <translation>Où voulez vous enregistrer les cartes ?</translation>
     </message>
 </context>
 <context>
@@ -1223,16 +1263,16 @@
         <translation>Choisissez un répertoire...</translation>
     </message>
     <message>
-        <location filename="../map/CMapPathSetup.cpp" line="78"/>
+        <location filename="../map/CMapPathSetup.cpp" line="81"/>
         <source>Select root path...</source>
-        <translation type="unfinished"></translation>
+        <translation>Sélectionner le répertoire racine...</translation>
     </message>
 </context>
 <context>
     <name>CMapPropSetup</name>
     <message>
         <source>Cache path...</source>
-        <translation type="vanished">Répertoire de cache...</translation>
+        <translation type="obsolete">Répertoire de cache...</translation>
     </message>
 </context>
 <context>
@@ -1317,7 +1357,7 @@ ligne %2, colonne %3:
         <location filename="../map/CMapVRT.cpp" line="47"/>
         <location filename="../map/CMapVRT.cpp" line="61"/>
         <location filename="../map/CMapVRT.cpp" line="89"/>
-        <location filename="../map/CMapVRT.cpp" line="124"/>
+        <location filename="../map/CMapVRT.cpp" line="125"/>
         <source>Error...</source>
         <translation>Erreur...</translation>
     </message>
@@ -1333,7 +1373,7 @@ ligne %2, colonne %3:
         <translation>Le fichier doit avoir une palette à 8 bits ou être en niveaux de gris.</translation>
     </message>
     <message>
-        <location filename="../map/CMapVRT.cpp" line="124"/>
+        <location filename="../map/CMapVRT.cpp" line="125"/>
         <source>No georeference information found.</source>
         <translation>Aucune information de géoréférencement trouvé</translation>
     </message>
@@ -1341,22 +1381,22 @@ ligne %2, colonne %3:
 <context>
     <name>CMapVrtBuilder</name>
     <message>
-        <location filename="../map/CMapVrtBuilder.cpp" line="29"/>
+        <location filename="../tool/CMapVrtBuilder.cpp" line="29"/>
         <source>Build GDAL VRT</source>
         <translation>Générer le VRT GDAL</translation>
     </message>
     <message>
-        <location filename="../map/CMapVrtBuilder.cpp" line="51"/>
+        <location filename="../tool/CMapVrtBuilder.cpp" line="51"/>
         <source>Select files...</source>
         <translation>Sélectionnez les fichiers...</translation>
     </message>
     <message>
-        <location filename="../map/CMapVrtBuilder.cpp" line="75"/>
+        <location filename="../tool/CMapVrtBuilder.cpp" line="75"/>
         <source>Select target file...</source>
         <translation>Sélectionnez le fichier à créer...</translation>
     </message>
     <message>
-        <location filename="../map/CMapVrtBuilder.cpp" line="196"/>
+        <location filename="../tool/CMapVrtBuilder.cpp" line="196"/>
         <source>!!! failed !!!
 </source>
         <translation>!!! échec !!!</translation>
@@ -1369,7 +1409,7 @@ ligne %2, colonne %3:
         <location filename="../map/CMapWMTS.cpp" line="55"/>
         <location filename="../map/CMapWMTS.cpp" line="65"/>
         <location filename="../map/CMapWMTS.cpp" line="74"/>
-        <location filename="../map/CMapWMTS.cpp" line="198"/>
+        <location filename="../map/CMapWMTS.cpp" line="206"/>
         <source>Error...</source>
         <translation>Erreur...</translation>
     </message>
@@ -1400,12 +1440,12 @@ Structure inconnue.</translation>
         <translation>Service inconnu. 'Attendu : * WMTS 1.0.0', lu :  '%1 %2.</translation>
     </message>
     <message>
-        <location filename="../map/CMapWMTS.cpp" line="198"/>
+        <location filename="../map/CMapWMTS.cpp" line="206"/>
         <source>No georeference information found.</source>
         <translation>Aucune information de géoréférencement trouvé</translation>
     </message>
     <message>
-        <location filename="../map/CMapWMTS.cpp" line="384"/>
+        <location filename="../map/CMapWMTS.cpp" line="392"/>
         <source><b>%1</b>: %2 tiles pending<br/></source>
         <translation><b>%1</b>: %2 tuiles à charger<br/></translation>
     </message>
@@ -1413,17 +1453,43 @@ Structure inconnue.</translation>
 <context>
     <name>CMouseEditArea</name>
     <message>
-        <location filename="../mouse/CMouseEditArea.cpp" line="38"/>
         <source><b>Edit Area</b><br/>Select a corner point for more options.<br/></source>
-        <translation><b>Éditez la surface</b><br/>Sélectionnez un point d'angle pour voir plus d'options.</translation>
+        <translation type="obsolete"><b>Éditez la surface</b><br/>Sélectionnez un point d'angle pour voir plus d'options.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditArea.cpp" line="37"/>
+        <source><b>Edit Area</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/></source>
+        <translation><b>Éditer la surface</b><br/>Choisissez und fonction et un mode de calcul d'itinéraire à l'aide des boutons d'outils. Ensuite, sélectionnez un point de la ligne. Seulement les points marqués d'un carré large peuvet être modifiés. Les points noirs sont des sous-points introduits par le calcul d'itinéraire.<br/></translation>
+    </message>
+</context>
+<context>
+    <name>CMouseEditRte</name>
+    <message>
+        <location filename="../mouse/CMouseEditRte.cpp" line="39"/>
+        <source><b>Edit Route Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/></source>
+        <translation><b>Éditer les points de la route</b><br/>Choisissez une fonction et un mode de calcul d'itinéraire à l'aide des boutons d'outils. Ensuite, sélectionnez un point de la ligne. Seul les points marqués d'un carré large peuvent être modifiés. Les points noirs sont des sous-points introduits par le calcul d'itinéraire.<br/></translation>
     </message>
 </context>
 <context>
     <name>CMouseEditTrk</name>
     <message>
-        <location filename="../mouse/CMouseEditTrk.cpp" line="44"/>
         <source><b>Edit Track Points</b><br/>Select a track point for more options.<br/></source>
-        <translation><b>Éditer les points de la trace</b><br/>Sélectionner un point de la trace pour voir plus d'options.<br/></translation>
+        <translation type="obsolete"><b>Éditer les points de la trace</b><br/>Sélectionner un point de la trace pour voir plus d'options.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="39"/>
+        <source><b>Edit Track Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/></source>
+        <translation><b>Éditer les points de la trace</b><br/>Choisissez une fonction et un mode de calcul d'itinéraire à l'aide des boutons d'outils. Ensuite, sélectionnez un point de la ligne. Seul les points marqués d'un carré large peuvent être modifiés. Les points noirs sont des sous-points introduits par le calcul d'itinéraire.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="81"/>
+        <source>Warning!</source>
+        <translation>Avertissement !</translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="81"/>
+        <source>This will replace all data of the orignal by a simple line of coordinates. All other data will be lost permanently.</source>
+        <translation>Ceci remplacera les données de l'original par une ligne simple de coordonnées. Toutes les autres données seront définitivement perdues.</translation>
     </message>
 </context>
 <context>
@@ -1440,11 +1506,16 @@ Structure inconnue.</translation>
     </message>
     <message>
         <location filename="../mouse/CMouseNormal.cpp" line="44"/>
+        <source>Add Route</source>
+        <translation>Ajouter une route</translation>
+    </message>
+    <message>
+        <location filename="../mouse/CMouseNormal.cpp" line="45"/>
         <source>Add Area</source>
         <translation>Ajouter une surface</translation>
     </message>
     <message>
-        <location filename="../mouse/CMouseNormal.cpp" line="46"/>
+        <location filename="../mouse/CMouseNormal.cpp" line="48"/>
         <source>Copy position</source>
         <translation>Copier la position</translation>
     </message>
@@ -1558,133 +1629,133 @@ n'est pas une définition de système de coordonnées:
     <message>
         <location filename="../gis/wpt/CProjWpt.cpp" line="62"/>
         <source>Enter new waypoint name.</source>
-        <translation>Saisir le nouveau nom du waypoint.</translation>
+        <translation type="unfinished">Entrez le nom du nouveau waypoint.</translation>
     </message>
 </context>
 <context>
     <name>CQlgtDb</name>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="304"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="307"/>
         <source>Migrating database from version 4 to 5.</source>
         <translation>Migration de la base de données de version 4 en version 5.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="357"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="361"/>
         <source>Migrating database from version 5 to 6.</source>
         <translation>Migration de la base de données de version 5 en version 6.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="414"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="419"/>
         <source>Migrating database from version 6 to 7.</source>
         <translation>Migration de la base de données de version 6 en version 7.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="480"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="485"/>
         <source>Migrating database from version 7 to 8.</source>
         <translation>Migration de la base de données de version 7 en version 8.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="509"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="514"/>
         <source>Migrating database from version 8 to 9.</source>
         <translation>Migration de la base de données de version 8 en version 9.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="532"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="537"/>
         <source>Open database: %1</source>
         <translation>Ouvrir la base de données: %1</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="541"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="546"/>
         <source>Folders:          %1</source>
         <translation>Répertoires: %1</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="550"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="555"/>
         <source>Tracks:           %1</source>
         <translation>Traces: %1</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="558"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="563"/>
         <source>Routes:           %1 (Only the basic route will be copied)</source>
         <translation>Routes:           %1 (seulement la route de base sera copiée)</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="566"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="571"/>
         <source>Waypoints:        %1</source>
         <translation>Waypoints:        %1</translation>
     </message>
     <message>
         <source>Overlays:         %1 (only area overlays will be converted to QMapShack)</source>
-        <translation type="vanished">Overlays:         %1 (Seulements les overlays de type surface seront convertis vers QMapShack)</translation>
+        <translation type="obsolete">Overlays:         %1 (Seulements les overlays de type surface seront convertis vers QMapShack)</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="574"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="579"/>
         <source>Overlays:         %1 (areas will be converted as areas, distance lines will be converted to tracks, all other overlay items will be lost)</source>
-        <translation type="unfinished"></translation>
+        <translation>Overlays :        %1 (les surfaces seront convertis en surfaces, les lignes de distance en traces, tous les autres overlays seront perdus)</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="581"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="586"/>
         <source>Diaries:          %1</source>
         <translation>Journaux:          %1</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="588"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="593"/>
         <source>Map selections:   %1 (can't be converted to QMapShack)</source>
         <translation>Sélections de carte:   %1 (ne peuvent pas être convertis)</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="594"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="599"/>
         <source>------ Start to convert database to %1------</source>
         <translation>------ La conversion de base de donnée vers %1 commence ------</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="598"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="603"/>
         <source>Failed to create target database.</source>
         <translation>Erreur lors de la création de la base de données cible.</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="599"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="604"/>
         <source>------ Abort ------</source>
         <translation>------ Annuler ------</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="627"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="632"/>
         <source>------ Done ------</source>
         <translation>------ Terminé ------</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="635"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="640"/>
         <source>Restore folders...</source>
         <translation>Restaurer ls dossiers...</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="635"/>
-        <location filename="../qlgt/CQlgtDb.cpp" line="668"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="640"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="673"/>
         <source>Abort</source>
         <translation>Annuler</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="662"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="667"/>
         <source>Imported %1 folders and %2 diaries</source>
         <translation>%1 dossiers et %2 journaux ont été importés</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="668"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="673"/>
         <source>Copy items...</source>
         <translation>Copier les éléments...</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="692"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="697"/>
         <source>Imported %1 tracks, %2 waypoints, %3 routes, %4 areas</source>
         <translation>%1 traces, %2 waypoints, %3 routes et %4 surfaces ont été importés</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="693"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="698"/>
         <source>Import folders...</source>
         <translation>Importer les dossiers...</translation>
     </message>
     <message>
-        <location filename="../qlgt/CQlgtDb.cpp" line="758"/>
+        <location filename="../qlgt/CQlgtDb.cpp" line="763"/>
         <source>Overlay of type '%1' cant be converted</source>
         <translation>Overlay de type '%1' ne peut pas être converti</translation>
     </message>
@@ -1713,6 +1784,123 @@ n'est pas une définition de système de coordonnées:
     </message>
 </context>
 <context>
+    <name>CRouterRoutino</name>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="34"/>
+        <source>Foot</source>
+        <translation>à pied</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="35"/>
+        <source>Horse</source>
+        <translation>à cheval</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="36"/>
+        <source>Wheelchair</source>
+        <translation>en fauteuil roulant</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="37"/>
+        <source>Bicycle</source>
+        <translation>Vélo</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="38"/>
+        <source>Moped</source>
+        <translation>Cyclomoteur</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="39"/>
+        <source>Motorcycle</source>
+        <translation>Moto</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="40"/>
+        <source>Motorcar</source>
+        <translation>Voiture</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="41"/>
+        <source>Goods</source>
+        <translation>Camion</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="43"/>
+        <source>Shortest</source>
+        <translation>le plus court</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="44"/>
+        <source>Quickest</source>
+        <translation>le plus rapide</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="96"/>
+        <source>profile "%1"</source>
+        <translation>profile "%1"</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutino.cpp" line="97"/>
+        <source>, mode "%1"</source>
+        <translation>, mode "%1"</translation>
+    </message>
+</context>
+<context>
+    <name>CRouterRoutinoPathSetup</name>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutinoPathSetup.cpp" line="40"/>
+        <source>Add or remove paths containing Routino data. There can be multiple databases in a path but no sub-path is parsed.</source>
+        <translation>Ajouter ou enlever des répertoires contenant des données Routino. Il peut y avoir plusieurs bases de données dans un répertoire mais les sous-répertoires ne sont pas pris en compte.</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterRoutinoPathSetup.cpp" line="55"/>
+        <source>Select routing data file path...</source>
+        <translation>Sélectionner un répertoire de données de calcul d'itinéraire...</translation>
+    </message>
+    <message>
+        <source>Select DEM file path...</source>
+        <translation type="obsolete">Sélectionnez le répertoire qui contient les fichiers DEM</translation>
+    </message>
+</context>
+<context>
+    <name>CRouterSetup</name>
+    <message>
+        <location filename="../gis/rte/router/CRouterSetup.cpp" line="36"/>
+        <source>Routino (offline)</source>
+        <translation>Routino (hors ligne)</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/CRouterSetup.cpp" line="37"/>
+        <source>MapQuest (online)</source>
+        <translation>MapQuest (en ligne)</translation>
+    </message>
+</context>
+<context>
+    <name>CRoutinoDatabaseBuilder</name>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="30"/>
+        <source>Create Routino Database</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="61"/>
+        <source>Select files...</source>
+        <translation type="unfinished">Sélectionnez les fichiers...</translation>
+    </message>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="85"/>
+        <source>Select target path...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../tool/CRoutinoDatabaseBuilder.cpp" line="206"/>
+        <source>!!! failed !!!
+</source>
+        <translation type="unfinished">!!! échec !!!</translation>
+    </message>
+</context>
+<context>
     <name>CSearchGoogle</name>
     <message>
         <location filename="../gis/search/CSearchGoogle.cpp" line="119"/>
@@ -1807,47 +1995,47 @@ n'est pas une définition de système de coordonnées:
     <message>
         <location filename="../IAbout.ui" line="140"/>
         <source>Rainer Unseld </source>
-        <translation type="unfinished"></translation>
+        <translation></translation>
     </message>
     <message>
         <location filename="../IAbout.ui" line="147"/>
         <source>French</source>
-        <translation type="unfinished">Français</translation>
+        <translation>Français</translation>
     </message>
     <message>
         <location filename="../IAbout.ui" line="154"/>
         <source>Czech</source>
-        <translation type="unfinished">Tchèque</translation>
+        <translation>Tchèque</translation>
     </message>
     <message>
         <location filename="../IAbout.ui" line="161"/>
         <source>Pavel Fric</source>
-        <translation type="unfinished"></translation>
+        <translation></translation>
     </message>
     <message>
         <location filename="../IAbout.ui" line="168"/>
         <source>German</source>
-        <translation type="unfinished">Deutsch</translation>
+        <translation>Deutsch</translation>
     </message>
     <message>
         <location filename="../IAbout.ui" line="175"/>
         <source>Translation:</source>
-        <translation type="unfinished"></translation>
+        <translation></translation>
     </message>
     <message>
         <location filename="../IAbout.ui" line="182"/>
         <source>Josef Latt</source>
-        <translation type="unfinished"></translation>
+        <translation></translation>
     </message>
     <message>
         <location filename="../IAbout.ui" line="189"/>
         <source>Spanish</source>
-        <translation type="unfinished">Espagnol</translation>
+        <translation>Espagnol</translation>
     </message>
     <message>
         <location filename="../IAbout.ui" line="196"/>
         <source>Jose Luis Domingo Lopez</source>
-        <translation type="unfinished"></translation>
+        <translation></translation>
     </message>
     <message>
         <location filename="../IAbout.ui" line="212"/>
@@ -1880,17 +2068,17 @@ n'est pas une définition de système de coordonnées:
     <message>
         <location filename="../canvas/ICanvasSetup.ui" line="53"/>
         <source>Scales</source>
-        <translation type="unfinished"></translation>
+        <translation>Échelles</translation>
     </message>
     <message>
         <location filename="../canvas/ICanvasSetup.ui" line="59"/>
         <source>Logarithmic</source>
-        <translation type="unfinished"></translation>
+        <translation>Logarithmique</translation>
     </message>
     <message>
         <location filename="../canvas/ICanvasSetup.ui" line="66"/>
         <source>Square (optimized for TMS and WTMS tiles)</source>
-        <translation type="unfinished"></translation>
+        <translation>Carrée (optimisée pour tuiles TMS et WTMS)</translation>
     </message>
 </context>
 <context>
@@ -1910,6 +2098,20 @@ n'est pas une définition de système de coordonnées:
     </message>
 </context>
 <context>
+    <name>ICreateRouteFromWpt</name>
+    <message>
+        <location filename="../gis/rte/ICreateRouteFromWpt.ui" line="14"/>
+        <source>Create Route from Waypoints</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/ICreateRouteFromWpt.ui" line="30"/>
+        <location filename="../gis/rte/ICreateRouteFromWpt.ui" line="50"/>
+        <source>...</source>
+        <translation type="unfinished">...</translation>
+    </message>
+</context>
+<context>
     <name>IDemPathSetup</name>
     <message>
         <location filename="../dem/IDemPathSetup.ui" line="14"/>
@@ -2090,12 +2292,12 @@ n'est pas une définition de système de coordonnées:
     <message>
         <location filename="../gis/ovl/IDetailsOvlArea.ui" line="69"/>
         <source><html><head/><body><p>The waypoint was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. </p></body></html></source>
-        <translation type="unfinished"><html><head/><body><p>Le waypoint a été importé dans QMapShack et a été modifié. Il ne représente plus les données originales. Veuillez consulter l'historique pour voir les modifications. </p></body></html></translation>
+        <translation><html><head/><body><p>Le waypoint a été importé dans QMapShack et a été modifié. Il ne représente plus les données originales. Veuillez consulter l'historique pour voir les modifications. </p></body></html></translation>
     </message>
     <message>
         <location filename="../gis/ovl/IDetailsOvlArea.ui" line="85"/>
         <source>Toggle read only mode. You have to open the lock to edit the item.</source>
-        <translation type="unfinished"></translation>
+        <translation>Inverser le mode lecture seule. Ouvrez le cadenas pour pouvoir éditer l'objet.</translation>
     </message>
     <message>
         <location filename="../gis/ovl/IDetailsOvlArea.ui" line="88"/>
@@ -2159,20 +2361,20 @@ n'est pas une définition de système de coordonnées:
     <message>
         <location filename="../gis/prj/IDetailsPrj.ui" line="81"/>
         <source>Sort along track (multiple)</source>
-        <translation type="unfinished"></translation>
+        <translation>Trier le long de la trace (multiple)</translation>
     </message>
     <message>
         <location filename="../gis/prj/IDetailsPrj.ui" line="86"/>
         <source>Sort along track (single)</source>
-        <translation type="unfinished"></translation>
+        <translation>Trier le long de la trace (individuel)</translation>
     </message>
     <message>
         <source>Sort By Time</source>
-        <translation type="vanished">Trier par date</translation>
+        <translation type="obsolete">Trier par date</translation>
     </message>
     <message>
         <source>Keep Order of Project</source>
-        <translation type="vanished">Conserver l'ordre du projet</translation>
+        <translation type="obsolete">Conserver l'ordre du projet</translation>
     </message>
     <message>
         <location filename="../gis/prj/IDetailsPrj.ui" line="115"/>
@@ -2189,12 +2391,12 @@ n'est pas une définition de système de coordonnées:
     <message>
         <location filename="../gis/prj/IDetailsPrj.ui" line="71"/>
         <source>Keep order of project</source>
-        <translation type="unfinished"></translation>
+        <translation>Garder l'ordre du projet</translation>
     </message>
     <message>
         <location filename="../gis/prj/IDetailsPrj.ui" line="76"/>
         <source>Sort by time</source>
-        <translation type="unfinished"></translation>
+        <translation>Trier par ordre chronolgique</translation>
     </message>
     <message>
         <location filename="../gis/prj/IDetailsPrj.ui" line="135"/>
@@ -2230,7 +2432,7 @@ n'est pas une définition de système de coordonnées:
     <message>
         <location filename="../gis/trk/IDetailsTrk.ui" line="203"/>
         <source>Graph Control</source>
-        <translation type="unfinished"></translation>
+        <translation>Contrôle du graphe</translation>
     </message>
     <message>
         <location filename="../gis/trk/IDetailsTrk.ui" line="224"/>
@@ -2251,17 +2453,17 @@ n'est pas une définition de système de coordonnées:
     <message>
         <location filename="../gis/trk/IDetailsTrk.ui" line="248"/>
         <source>Track</source>
-        <translation type="unfinished"></translation>
+        <translation>Trace</translation>
     </message>
     <message>
         <location filename="../gis/trk/IDetailsTrk.ui" line="274"/>
         <source>Toggle read only mode. You have to open the lock to edit the item.</source>
-        <translation type="unfinished"></translation>
+        <translation>Inverser le mode lecture seule. Ouvrez le cadenas pour pouvoir éditer l'objet.</translation>
     </message>
     <message>
         <location filename="../gis/trk/IDetailsTrk.ui" line="307"/>
         <source><html><head/><body><p>The waypoint was imported to QMapShack and was changed. It does not show the original data anymore. Please see history for changes. </p></body></html></source>
-        <translation type="unfinished"><html><head/><body><p>Le waypoint a été importé dans QMapShack et a été modifié. Il ne représente plus les données originales. Veuillez consulter l'historique pour voir les modifications. </p></body></html></translation>
+        <translation><html><head/><body><p>Le waypoint a été importé dans QMapShack et a été modifié. Il ne représente plus les données originales. Veuillez consulter l'historique pour voir les modifications. </p></body></html></translation>
     </message>
     <message>
         <location filename="../gis/trk/IDetailsTrk.ui" line="335"/>
@@ -2368,11 +2570,11 @@ n'est pas une définition de système de coordonnées:
     <message>
         <location filename="../gis/wpt/IDetailsWpt.ui" line="204"/>
         <source>Toggle read only mode. You have to open the lock to edit the item.</source>
-        <translation type="unfinished"></translation>
+        <translation>Inverser le mode lecture seule. Ouvrez le cadenas pour pouvoir éditer l'objet.</translation>
     </message>
     <message>
         <source><html><head/><body><p>Read Only Mode</p></body></html></source>
-        <translation type="vanished"><html><head/><body><p>Mode lecture seule</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Mode lecture seule</p></body></html></translation>
     </message>
     <message>
         <location filename="../gis/wpt/IDetailsWpt.ui" line="207"/>
@@ -2523,7 +2725,17 @@ n'est pas une définition de système de coordonnées:
         <translation>Date et heure du début de la trace</translation>
     </message>
     <message>
-        <location filename="../gis/trk/filter/IFilterNewDate.ui" line="71"/>
+        <location filename="../gis/trk/filter/IFilterNewDate.ui" line="51"/>
+        <source>dd.MM.yy HH:mm:ss</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/trk/filter/IFilterNewDate.ui" line="61"/>
+        <source>-</source>
+        <translation type="unfinished">-</translation>
+    </message>
+    <message>
+        <location filename="../gis/trk/filter/IFilterNewDate.ui" line="81"/>
         <source>...</source>
         <translation></translation>
     </message>
@@ -2731,34 +2943,34 @@ n'est pas une définition de système de coordonnées:
 <context>
     <name>IImportDatabase</name>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="14"/>
+        <location filename="../tool/IImportDatabase.ui" line="14"/>
         <source>Form</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="22"/>
-        <location filename="../qlgt/IImportDatabase.ui" line="63"/>
+        <location filename="../tool/IImportDatabase.ui" line="22"/>
+        <location filename="../tool/IImportDatabase.ui" line="63"/>
         <source>...</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="45"/>
+        <location filename="../tool/IImportDatabase.ui" line="45"/>
         <source>Source Database:</source>
         <translation>Base de donnée source</translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="52"/>
-        <location filename="../qlgt/IImportDatabase.ui" line="93"/>
+        <location filename="../tool/IImportDatabase.ui" line="52"/>
+        <location filename="../tool/IImportDatabase.ui" line="93"/>
         <source>-</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="86"/>
+        <location filename="../tool/IImportDatabase.ui" line="86"/>
         <source>Target Database:</source>
         <translation>Base de donnée cible</translation>
     </message>
     <message>
-        <location filename="../qlgt/IImportDatabase.ui" line="102"/>
+        <location filename="../tool/IImportDatabase.ui" line="102"/>
         <source>Start</source>
         <translation>Démarrer</translation>
     </message>
@@ -2823,252 +3035,272 @@ n'est pas une définition de système de coordonnées:
         <translation>Vue</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="98"/>
+        <location filename="../IMainWindow.ui" line="99"/>
         <source>Window</source>
         <translation>Fenêtre</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="103"/>
+        <location filename="../IMainWindow.ui" line="104"/>
         <source>?</source>
         <translation>?</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="110"/>
+        <location filename="../IMainWindow.ui" line="111"/>
         <source>Project</source>
         <translation>Projet</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="120"/>
+        <location filename="../IMainWindow.ui" line="121"/>
         <source>Tool</source>
         <translation>Outils</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="138"/>
+        <location filename="../IMainWindow.ui" line="140"/>
         <source>Maps</source>
         <translation>Cartes</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="175"/>
+        <location filename="../IMainWindow.ui" line="177"/>
         <source>Dig. Elev. Model (DEM)</source>
-        <translation type="unfinished">Modèle numérique de terrain (DEM)</translation>
+        <translation>Modèle numérique de terrain (DEM)</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="208"/>
+        <location filename="../IMainWindow.ui" line="210"/>
         <source>Data</source>
         <translation>Données</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="221"/>
-        <location filename="../IMainWindow.ui" line="224"/>
+        <location filename="../IMainWindow.ui" line="222"/>
+        <source>Route</source>
+        <translation>Calcul d'itinéraire</translation>
+    </message>
+    <message>
+        <location filename="../IMainWindow.ui" line="256"/>
+        <location filename="../IMainWindow.ui" line="259"/>
         <source>Add Map View</source>
         <translation>Ajouter une vue cartographique</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="227"/>
+        <location filename="../IMainWindow.ui" line="262"/>
         <source>Ctrl+T</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="239"/>
+        <location filename="../IMainWindow.ui" line="274"/>
         <source>Show Scale</source>
         <translation>Afficher l'échelle</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="248"/>
+        <location filename="../IMainWindow.ui" line="283"/>
         <source>Setup Map Font</source>
         <translation>Configurer la police de la carte</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="260"/>
+        <location filename="../IMainWindow.ui" line="295"/>
         <source>Show Grid</source>
         <translation>Afficher la grille</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="263"/>
+        <location filename="../IMainWindow.ui" line="298"/>
         <source>Ctrl+G</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="272"/>
+        <location filename="../IMainWindow.ui" line="307"/>
         <source>Setup Grid</source>
         <translation>Configurer la grille</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="275"/>
+        <location filename="../IMainWindow.ui" line="310"/>
         <source>Ctrl+Alt+G</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="287"/>
+        <location filename="../IMainWindow.ui" line="322"/>
         <source>Flip Mouse Wheel</source>
         <translation>Inverser le sens de la molette de souris</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="296"/>
-        <location filename="../IMainWindow.ui" line="299"/>
+        <location filename="../IMainWindow.ui" line="331"/>
+        <location filename="../IMainWindow.ui" line="334"/>
         <source>Setup Map Paths</source>
         <translation>Configurer les répertoires des cartes</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="311"/>
+        <location filename="../IMainWindow.ui" line="346"/>
         <source>POI Text</source>
         <translation>Libellés des points d'interêt</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="323"/>
+        <location filename="../IMainWindow.ui" line="358"/>
         <source>Night / Day</source>
         <translation>Jour / Nuit</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="335"/>
+        <location filename="../IMainWindow.ui" line="370"/>
         <source>Map Tool Tip</source>
         <translation>Infobulles sur la carte</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="344"/>
+        <location filename="../IMainWindow.ui" line="379"/>
         <source>Setup DEM Paths</source>
         <translation>Configurer les répertoires DEM</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="353"/>
+        <location filename="../IMainWindow.ui" line="388"/>
         <source>About</source>
         <translation>À propos</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="362"/>
+        <location filename="../IMainWindow.ui" line="397"/>
         <source>Help</source>
         <translation>Aide</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="371"/>
-        <location filename="../IMainWindow.ui" line="374"/>
+        <location filename="../IMainWindow.ui" line="406"/>
+        <location filename="../IMainWindow.ui" line="409"/>
         <source>Setup Map View</source>
         <translation>Configurer la vue cartographique</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="383"/>
+        <location filename="../IMainWindow.ui" line="418"/>
         <source>Load GIS Data</source>
         <translation>Charger des données SIG...</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="386"/>
+        <location filename="../IMainWindow.ui" line="421"/>
         <source>Load projects from file</source>
         <translation>Charger un fichier projet</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="389"/>
+        <location filename="../IMainWindow.ui" line="424"/>
         <source>Ctrl+L</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="398"/>
+        <location filename="../IMainWindow.ui" line="433"/>
         <source>Save All GIS Data</source>
         <translation>Enregistrer toutes les données SIG</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="401"/>
+        <location filename="../IMainWindow.ui" line="436"/>
         <source>Save all projects in the workspace</source>
         <translation>Enregistrer tous les projets de l'espace de travail</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="404"/>
+        <location filename="../IMainWindow.ui" line="439"/>
         <source>Ctrl+S</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="413"/>
+        <location filename="../IMainWindow.ui" line="448"/>
         <source>Setup Time Zone</source>
         <translation>Configurer le fuseau horaire</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="422"/>
+        <location filename="../IMainWindow.ui" line="457"/>
         <source>Add empty project</source>
         <translation>Ajouter un projet vide</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="434"/>
+        <location filename="../IMainWindow.ui" line="469"/>
         <source>Search Google</source>
         <translation>Recherche Google</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="443"/>
+        <location filename="../IMainWindow.ui" line="478"/>
         <source>Close all projects</source>
         <translation>Fermer tous les projets</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="446"/>
+        <location filename="../IMainWindow.ui" line="481"/>
         <source>F8</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="455"/>
+        <location filename="../IMainWindow.ui" line="490"/>
         <source>Setup Units</source>
         <translation>Configurer les unités</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="464"/>
+        <location filename="../IMainWindow.ui" line="499"/>
         <source>Setup Workspace</source>
         <translation>Configurer l'espace de travail</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="467"/>
+        <location filename="../IMainWindow.ui" line="502"/>
         <source>Setup save on exit.</source>
         <translation>Sauvegarde de la configuration en quittant</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="476"/>
+        <location filename="../IMainWindow.ui" line="511"/>
         <source>Import Database from QLandkarte</source>
         <translation>Importer une base de données QLandkarte</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="479"/>
+        <location filename="../IMainWindow.ui" line="514"/>
         <source>Import QLandkarte GT database</source>
         <translation>Importer une base de données QLandkarte GT</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="488"/>
+        <location filename="../IMainWindow.ui" line="523"/>
         <source>VRT Builder</source>
         <translation>Générateur de VRT</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="491"/>
+        <location filename="../IMainWindow.ui" line="526"/>
         <source>GUI front end to gdalbuildvrt</source>
         <translation>Interface utilisateur pour gdalbuildvrt</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="500"/>
+        <location filename="../IMainWindow.ui" line="535"/>
         <source>Store Map View</source>
-        <translation type="unfinished"></translation>
+        <translation>Enregistrer une vue cartographique</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="503"/>
+        <location filename="../IMainWindow.ui" line="538"/>
         <source>Write current active map and DEM list including the properties to a file</source>
-        <translation type="unfinished"></translation>
+        <translation>Sauvegarder les cartes et calques DEM actives et leurs paramètres dans un fichier</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="512"/>
+        <location filename="../IMainWindow.ui" line="547"/>
         <source>Load Map View</source>
-        <translation type="unfinished"></translation>
+        <translation>Charger une vue cartographique</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="515"/>
+        <location filename="../IMainWindow.ui" line="550"/>
         <source>Restore view with active map and DEM list including the properties from a file</source>
-        <translation type="unfinished"></translation>
+        <translation>Rétablir une vue avec les cartes et calques DEM et leurs paramètres à partir d'un fichier</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="527"/>
+        <location filename="../IMainWindow.ui" line="562"/>
         <source>Ext. Profile</source>
-        <translation type="unfinished"></translation>
+        <translation>Profile externe</translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="530"/>
+        <location filename="../IMainWindow.ui" line="565"/>
         <source>Ctrl+E</source>
-        <translation type="unfinished"></translation>
+        <translation></translation>
     </message>
     <message>
-        <location filename="../IMainWindow.ui" line="539"/>
+        <location filename="../IMainWindow.ui" line="574"/>
         <source>Close</source>
-        <translation type="unfinished">Fermer</translation>
+        <translation>Fermer</translation>
+    </message>
+    <message>
+        <location filename="../IMainWindow.ui" line="583"/>
+        <source>Clone Map View</source>
+        <translation>Dupliquer une vue cartographique</translation>
+    </message>
+    <message>
+        <location filename="../IMainWindow.ui" line="586"/>
+        <source>Ctrl+Shift+T</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../IMainWindow.ui" line="595"/>
+        <source>Create Routino Database</source>
+        <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
@@ -3092,7 +3324,8 @@ n'est pas une définition de système de coordonnées:
         <location filename="../map/IMapList.ui" line="129"/>
         <source>Help! I want maps!
 I don't want to read the documentation!</source>
-        <translation type="unfinished"></translation>
+        <translation>Au secours ! Je veux des cartes !
+Je n'ai pas envie de lire la documentation !</translation>
     </message>
     <message>
         <location filename="../map/IMapList.ui" line="149"/>
@@ -3110,7 +3343,7 @@ I don't want to read the documentation!</source>
     <message>
         <location filename="../map/IMapPathSetup.ui" line="20"/>
         <source>Root path of tile cache for online maps:</source>
-        <translation type="unfinished"></translation>
+        <translation>Répertoire racine du cache de tuiles pour les cartes en ligne :</translation>
     </message>
     <message>
         <location filename="../map/IMapPathSetup.ui" line="36"/>
@@ -3123,11 +3356,12 @@ I don't want to read the documentation!</source>
         <location filename="../map/IMapPathSetup.ui" line="185"/>
         <source>Help! I want maps!
 I don't want to read the documentation!</source>
-        <translation type="unfinished"></translation>
+        <translation>Au secours ! Je veux des cartes !
+Je n'ai pas envie de lire la documentation !</translation>
     </message>
     <message>
         <location filename="../map/IMapPathSetup.ui" line="29"/>
-        <location filename="../map/IMapPathSetup.ui" line="135"/>
+        <location filename="../map/IMapPathSetup.ui" line="154"/>
         <source>-</source>
         <translation>-</translation>
     </message>
@@ -3188,7 +3422,7 @@ I don't want to read the documentation!</source>
     <message>
         <location filename="../map/IMapPropSetup.ui" line="240"/>
         <source>Cache Path</source>
-        <translation type="unfinished"></translation>
+        <translation>Répertoire du cache</translation>
     </message>
     <message>
         <location filename="../map/IMapPropSetup.ui" line="196"/>
@@ -3204,33 +3438,33 @@ I don't want to read the documentation!</source>
 <context>
     <name>IMapVrtBuilder</name>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="14"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="14"/>
         <source>Form</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="22"/>
-        <location filename="../map/IMapVrtBuilder.ui" line="56"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="22"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="56"/>
         <source>...</source>
         <translation>...</translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="39"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="39"/>
         <source>Select source files:</source>
         <translation>Sélectionnez les fichiers source:</translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="79"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="79"/>
         <source>Target Filename:</source>
         <translation>Fichier cible:</translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="86"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="86"/>
         <source>-</source>
         <translation>-</translation>
     </message>
     <message>
-        <location filename="../map/IMapVrtBuilder.ui" line="95"/>
+        <location filename="../tool/IMapVrtBuilder.ui" line="95"/>
         <source>Start</source>
         <translation>Démarrer</translation>
     </message>
@@ -3238,24 +3472,60 @@ I don't want to read the documentation!</source>
 <context>
     <name>IMouseEditLine</name>
     <message>
-        <location filename="../mouse/IMouseEditLine.cpp" line="344"/>
         <source>Add points?</source>
-        <translation>Ajouter les points ?</translation>
+        <translation type="obsolete">Ajouter les points ?</translation>
     </message>
     <message>
-        <location filename="../mouse/IMouseEditLine.cpp" line="344"/>
         <source>Add points to temporary line?</source>
-        <translation>Ajouter les points à la ligne temporaire ?</translation>
+        <translation type="obsolete">Ajouter les points à la ligne temporaire ?</translation>
     </message>
     <message>
-        <location filename="../mouse/IMouseEditLine.cpp" line="887"/>
         <source>Warning!</source>
-        <translation>Avertissement !</translation>
+        <translation type="obsolete">Avertissement !</translation>
     </message>
     <message>
-        <location filename="../mouse/IMouseEditLine.cpp" line="887"/>
         <source>This will replace all data of the orignal by a simple line of coordinates. All other data will be lost permanently.</source>
-        <translation>Ceci remplacera les données de l'original par une ligne simple de coordonnées. Toutes les autres données seront définitivement perdues.</translation>
+        <translation type="obsolete">Ceci remplacera les données de l'original par une ligne simple de coordonnées. Toutes les autres données seront définitivement perdues.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="238"/>
+        <source><b>New Line</b><br/>Move the mouse and use the left mouse button to drop points. When done use the right mouse button to stop.<br/></source>
+        <translation><b>Nouvelle ligne</b><br/>Déplacez la souris et utilisez le bouton gauche pour ajouter des points. Cliquez droit pour terminer.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="279"/>
+        <source><b>Delete Point</b><br/>Move the mouse close to a point and press the left button to delete it.<br/></source>
+        <translation><b>Supprimer un point</b><br/>Approchez le pointeur du point et cliquez gauche pour le supprimer.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="287"/>
+        <source><b>Select Range of Points</b><br/>Left click on first point to start selection. Left click second point to complete selection and choose from options. Use the right mouse button to cancel.<br/></source>
+        <translation><b>Sélectionner une série de points</b><br/> Pour commencer la sélection, cliquez gauche sur le premier point. Cliquez gauche sur le sur le deuxième point pour terminer la sélection et choisissez une option. Utilisez le bouton droit pour annuler.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="295"/>
+        <source><b>Move Point</b><br/>Move the mouse close to a point and press the left button to make it stick to the cursor. Move the mouse to move the point. Drop the point by a left click. Use the right mouse button to cancel.<br/></source>
+        <translation><b>Déplacer un point</b><br/>Approchez le pointeur près d'un point et cliquez gauche pour le coller au pointeur. Déplacez le point avec la souris. Déposez le point avec un clic gauche. Utilisez le bouton droit pour annuler.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="303"/>
+        <source><b>Add Point</b><br/>Move the mouse close to a line segment and press the left button to add a point. The point will stick to the cursor and you can move it.  Drop the point by a left click. Use the right mouse button to cancel.<br/></source>
+        <translation><b>Ajouter un point</b><br/>Placez le pointeur de la souris près d'un segment de ligne et cliquez gauche pour ajouter un point. Le nouveau point va coller au pointeur et vous pouvez le déplacer. Déposez le point par un clic gauche. Utilisez le clic droit pour annuler.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="311"/>
+        <source><b>No Routing</b><br/>All points will be connected with a straight line.<br/></source>
+        <translation><b>Aucun calcul d'itinéraire</b><br/>Les points seront connectés par une ligne droite.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="316"/>
+        <source><b>Auto Routing</b><br/>The current router setup is used to derive a route between points. <b>Note:</b> The selected router must be able to route on-the-fly. Offline routers usually can do, online routers can't.<br/></source>
+        <translation><b>Calcul d'itinéraire automatique</b><br/>Les paramètres de calcul d'itinéraire actuels serviront pour calculer un tracé entre les points. <b>Remarque :</b>Le routeur sélectionné doit être capable de faire le calcul à la volée. Généralement, les routeurs hors ligne en sont capables, les routeurs en ligne ne le sont pas.<br/></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IMouseEditLine.cpp" line="321"/>
+        <source><b>Vector Routing</b><br/>Connect points with a line from a loaded vector map if possible.<br/></source>
+        <translation><b>Calcul d'itinéraire vecteur</b><br/>Connecter les points avec une ligne basée sur une carte vecteur active, si possible.<br/></translation>
     </message>
 </context>
 <context>
@@ -3277,12 +3547,13 @@ I don't want to read the documentation!</source>
     <message>
         <location filename="../plot/IPlot.cpp" line="108"/>
         <source>Stop Range</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>tbc: range</translatorcomment>
+        <translation>Terminer la série</translation>
     </message>
     <message>
         <location filename="../plot/IPlot.cpp" line="109"/>
         <source>Save...</source>
-        <translation type="unfinished"></translation>
+        <translation>Enregistrer...</translation>
     </message>
     <message>
         <location filename="../plot/IPlot.cpp" line="602"/>
@@ -3292,7 +3563,7 @@ I don't want to read the documentation!</source>
     <message>
         <location filename="../plot/IPlot.cpp" line="1128"/>
         <source>Select output file</source>
-        <translation type="unfinished"></translation>
+        <translation>Sélectionner le fichier de sortie</translation>
     </message>
 </context>
 <context>
@@ -3408,27 +3679,216 @@ or
     </message>
 </context>
 <context>
+    <name>IRouterMapQuest</name>
+    <message>
+        <location filename="../gis/rte/router/IRouterMapQuest.ui" line="14"/>
+        <source>Form</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterMapQuest.ui" line="20"/>
+        <source>t.b.d</source>
+        <translation></translation>
+    </message>
+</context>
+<context>
+    <name>IRouterRoutino</name>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="14"/>
+        <source>Form</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="31"/>
+        <source>Profile</source>
+        <translation>Profile</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="38"/>
+        <source>Mode</source>
+        <translation>Mode</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="45"/>
+        <source>Database</source>
+        <translation>Base de données</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="52"/>
+        <source>Add paths with Routino database.</source>
+        <translation>Ajouter des répertoires qui contiennent des bases de données Routino.</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="55"/>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutino.ui" line="121"/>
+        <source>To use offline routing you need to define paths to local routing data. Use the setup tool button to register a path.</source>
+        <translatorcomment>tbc: setup tool button</translatorcomment>
+        <translation>Pour pouvoir utiliser le calcul d'itinéraire hors ligne, vous devez spécifier les répertoires qui contiennent les données de calcul d'itinéraire locales. Utilisez le bouton de configuration pour ajouter des répertoires.</translation>
+    </message>
+</context>
+<context>
+    <name>IRouterRoutinoPathSetup</name>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutinoPathSetup.ui" line="14"/>
+        <source>Setup Routino database...</source>
+        <translation>Configurez la base de données Routino...</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutinoPathSetup.ui" line="27"/>
+        <location filename="../gis/rte/router/IRouterRoutinoPathSetup.ui" line="47"/>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/router/IRouterRoutinoPathSetup.ui" line="99"/>
+        <source>-</source>
+        <translation>-</translation>
+    </message>
+</context>
+<context>
+    <name>IRouterSetup</name>
+    <message>
+        <location filename="../gis/rte/router/IRouterSetup.ui" line="14"/>
+        <source>Form</source>
+        <translation></translation>
+    </message>
+</context>
+<context>
+    <name>IRoutinoDatabaseBuilder</name>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="14"/>
+        <source>Form</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="22"/>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="63"/>
+        <source>...</source>
+        <translation type="unfinished">...</translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="39"/>
+        <source>Select source files:</source>
+        <translation type="unfinished">Sélectionnez les fichiers source:</translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="54"/>
+        <source>Start</source>
+        <translation type="unfinished">Démarrer</translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="86"/>
+        <source>Target Path:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="93"/>
+        <source>-</source>
+        <translation type="unfinished">-</translation>
+    </message>
+    <message>
+        <location filename="../tool/IRoutinoDatabaseBuilder.ui" line="100"/>
+        <source>File Prefix</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>IScrOptEditLine</name>
     <message>
-        <location filename="../mouse/IScrOptEditLine.ui" line="26"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="32"/>
         <source>Form</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../mouse/IScrOptEditLine.ui" line="47"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="53"/>
         <source>Save to orignal</source>
         <translation>Enregistrer</translation>
     </message>
     <message>
-        <location filename="../mouse/IScrOptEditLine.ui" line="54"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="60"/>
         <source>Save as new</source>
         <translation>Enregistrer sous...</translation>
     </message>
     <message>
-        <location filename="../mouse/IScrOptEditLine.ui" line="61"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="67"/>
         <source>Abort</source>
         <translation>Annuler</translation>
     </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="102"/>
+        <source>Move points.</source>
+        <translation>Déplacer des points.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="105"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="128"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="148"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="168"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="280"/>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="297"/>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="125"/>
+        <source>Add new points.</source>
+        <translation>Ajouter des points.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="145"/>
+        <source>Select a range of points.</source>
+        <translation>Sélectionner une série de points.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="165"/>
+        <source>Delete a point.</source>
+        <translation>Supprimer un point.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="216"/>
+        <source>No auto-routing or line snapping</source>
+        <translatorcomment>tbc: snapping -> verrouillage (used in Garmin device UI) </translatorcomment>
+        <translation>Aucun calcul d'itinéraire automatique ou verrouillage </translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="219"/>
+        <source>0</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="232"/>
+        <source>Use auto-routing to between points.</source>
+        <translation>Utiliser le calcul d'itinéraire automatique entre deux points.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="235"/>
+        <source>A</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="248"/>
+        <source>Snap line along lines of a vector map.</source>
+        <translation>Verrouiller la ligne aux lignes d'une carte vecteur.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="251"/>
+        <source>V</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="277"/>
+        <source>Undo last change</source>
+        <translation>Annuler la dernière modification</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptEditLine.ui" line="294"/>
+        <source>Redo last change</source>
+        <translation>Rétablir la dernière modification</translation>
+    </message>
 </context>
 <context>
     <name>IScrOptOvlArea</name>
@@ -3439,19 +3899,34 @@ or
     </message>
     <message>
         <location filename="../gis/ovl/IScrOptOvlArea.ui" line="40"/>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="54"/>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="65"/>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="83"/>
+        <source>View details and edit.</source>
+        <translation>Voir les détails et éditer.</translation>
+    </message>
+    <message>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="43"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="57"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="71"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="92"/>
         <source>...</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="51"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="54"/>
         <source>Copy area into another project.</source>
-        <translation>Copier la surface dans un autre projet</translation>
+        <translation>Copier la surface dans un autre projet.</translation>
+    </message>
+    <message>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="68"/>
+        <source>Delete area from project.</source>
+        <translation>Supprimer la surface du projet.</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="112"/>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="89"/>
+        <source>Edit shape of the area.</source>
+        <translation>Modifier la forme de la surface.</translation>
+    </message>
+    <message>
+        <location filename="../gis/ovl/IScrOptOvlArea.ui" line="121"/>
         <source>TextLabel</source>
         <translation>Libellé</translation>
     </message>
@@ -3517,6 +3992,30 @@ or
     </message>
 </context>
 <context>
+    <name>IScrOptRangeLine</name>
+    <message>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="14"/>
+        <source>Form</source>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="20"/>
+        <source>Delete all points between the first and last one.</source>
+        <translation>Supprimer tous les points entre le premier et le dernier point.</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="23"/>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="37"/>
+        <source>...</source>
+        <translation>...</translation>
+    </message>
+    <message>
+        <location filename="../mouse/line/IScrOptRangeLine.ui" line="34"/>
+        <source>Caclculate a route between the first and last selected point.</source>
+        <translation>Calcluler un itinéraire entre le premier et le dernier point sélectionné.</translation>
+    </message>
+</context>
+<context>
     <name>IScrOptRangeTrk</name>
     <message>
         <location filename="../mouse/IScrOptRangeTrk.ui" line="14"/>
@@ -3559,29 +4058,59 @@ or
         <translation></translation>
     </message>
     <message>
-        <location filename="../gis/rte/IScrOptRte.ui" line="28"/>
         <source><html><head/><body><p>View details &amp; Edit</p></body></html></source>
-        <translation><html><head/><body><p>Afficher et éditer les détails</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Afficher et éditer les détails</p></body></html></translation>
     </message>
     <message>
         <location filename="../gis/rte/IScrOptRte.ui" line="31"/>
         <location filename="../gis/rte/IScrOptRte.ui" line="45"/>
         <location filename="../gis/rte/IScrOptRte.ui" line="59"/>
+        <location filename="../gis/rte/IScrOptRte.ui" line="80"/>
+        <location filename="../gis/rte/IScrOptRte.ui" line="94"/>
+        <location filename="../gis/rte/IScrOptRte.ui" line="108"/>
         <source>...</source>
         <translation></translation>
     </message>
     <message>
         <location filename="../gis/rte/IScrOptRte.ui" line="42"/>
         <source>Copy route into another project.</source>
-        <translation>Copier la route dans un autre projet</translation>
+        <translation>Copier la route dans un autre projet.</translation>
     </message>
     <message>
-        <location filename="../gis/rte/IScrOptRte.ui" line="56"/>
         <source><html><head/><body><p>Delete</p></body></html></source>
-        <translation><html><head/><body><p>Supprimer</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Supprimer</p></body></html></translation>
     </message>
     <message>
-        <location filename="../gis/rte/IScrOptRte.ui" line="85"/>
+        <location filename="../gis/rte/IScrOptRte.ui" line="28"/>
+        <source>View details and edit.</source>
+        <translation>Voir les détails et éditer.</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="56"/>
+        <source>Delete route from project.</source>
+        <translation>Supprimer la route du projet.</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="77"/>
+        <source>Calculate route.</source>
+        <translation>Calculer la route.</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="91"/>
+        <source>Reset route calculation.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Reset route caclulation.</source>
+        <translation type="obsolete">Réinitialiser la route.</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="105"/>
+        <source>Move route points.</source>
+        <translation>Déplacer les points de la route.</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/IScrOptRte.ui" line="134"/>
         <source>TextLabel</source>
         <translation>Libellé</translation>
     </message>
@@ -3594,9 +4123,8 @@ or
         <translation></translation>
     </message>
     <message>
-        <location filename="../gis/trk/IScrOptTrk.ui" line="40"/>
         <source>View details &amp; Edit properties of track.</source>
-        <translation>Afficher et éditer les caractéristiques de la trace.</translation>
+        <translation type="obsolete">Afficher et éditer les caractéristiques de la trace.</translation>
     </message>
     <message>
         <location filename="../gis/trk/IScrOptTrk.ui" line="43"/>
@@ -3617,9 +4145,18 @@ or
         <translation>Copier la trace dans un autre projet</translation>
     </message>
     <message>
-        <location filename="../gis/trk/IScrOptTrk.ui" line="68"/>
         <source>Delete</source>
-        <translation>Supprimer</translation>
+        <translation type="obsolete">Supprimer</translation>
+    </message>
+    <message>
+        <location filename="../gis/trk/IScrOptTrk.ui" line="40"/>
+        <source>View details and edit properties of track.</source>
+        <translation>Voir les détails et éditer les paramètres de la trace.</translation>
+    </message>
+    <message>
+        <location filename="../gis/trk/IScrOptTrk.ui" line="68"/>
+        <source>Delete track from project.</source>
+        <translation>Supprimer la trace du projet.</translation>
     </message>
     <message>
         <location filename="../gis/trk/IScrOptTrk.ui" line="89"/>
@@ -3665,17 +4202,21 @@ or
         <translation></translation>
     </message>
     <message>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="49"/>
         <source><html><head/><body><p>View details &amp; Edit</p></body></html></source>
-        <translation><html><head/><body><p>Afficher et éditer les détails</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Afficher et éditer les détails</p></body></html></translation>
+    </message>
+    <message>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="49"/>
+        <source>View details and edit.</source>
+        <translation>Voir les détails et éditer.</translation>
     </message>
     <message>
         <location filename="../gis/wpt/IScrOptWpt.ui" line="52"/>
         <location filename="../gis/wpt/IScrOptWpt.ui" line="66"/>
         <location filename="../gis/wpt/IScrOptWpt.ui" line="80"/>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="98"/>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="115"/>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="129"/>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="101"/>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="118"/>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="132"/>
         <source>...</source>
         <translation></translation>
     </message>
@@ -3686,21 +4227,39 @@ or
     </message>
     <message>
         <location filename="../gis/wpt/IScrOptWpt.ui" line="77"/>
+        <source>Delete waypoint from project.</source>
+        <translatorcomment>tbc: waypoint</translatorcomment>
+        <translation>Supprimer le waypoint du projet.</translation>
+    </message>
+    <message>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="98"/>
+        <source>Show content as static bubble.</source>
+        <translation>Afficher le contenu comme bulle statique.</translation>
+    </message>
+    <message>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="115"/>
+        <source>Move waypoint to a new location.</source>
+        <translation>Déplacer le waypoint.</translation>
+    </message>
+    <message>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="129"/>
+        <source>Clone waypoint and move clone a given distance and angle.</source>
+        <translation>Dupliquer le waypoint et déplacer la copie d'une distance et d'un angle défini.</translation>
+    </message>
+    <message>
         <source><html><head/><body><p>Delete</p></body></html></source>
-        <translation><html><head/><body><p>Supprimer</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Supprimer</p></body></html></translation>
     </message>
     <message>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="112"/>
         <source><html><head/><body><p>Move waypoint to a new location.</p></body></html></source>
-        <translation><html><head/><body><p>Déplacer le waypoint à une nouvelle position.</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Déplacer le waypoint à une nouvelle position.</p></body></html></translation>
     </message>
     <message>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="126"/>
         <source><html><head/><body><p>Clone waypoint and move clone a given distance and angle.</p></body></html></source>
-        <translation><html><head/><body><p>Dupliquer le waypoint et déplacer la copie par une distance et un angle donnés .</p></body></html></translation>
+        <translation type="obsolete"><html><head/><body><p>Dupliquer le waypoint et déplacer la copie par une distance et un angle donnés .</p></body></html></translation>
     </message>
     <message>
-        <location filename="../gis/wpt/IScrOptWpt.ui" line="173"/>
+        <location filename="../gis/wpt/IScrOptWpt.ui" line="176"/>
         <source>TextLabel</source>
         <translation>Libellé</translation>
     </message>
@@ -3710,7 +4269,7 @@ or
     <message>
         <location filename="../gis/ISelDevices.ui" line="14"/>
         <source>Select devices...</source>
-        <translation type="unfinished"></translation>
+        <translation>Sélectionner les appareils...</translation>
     </message>
 </context>
 <context>
@@ -3769,12 +4328,12 @@ or
     <message>
         <location filename="../gis/db/ISelectDBFolder.ui" line="14"/>
         <source>Select Parent Folder...</source>
-        <translation type="unfinished"></translation>
+        <translation>Sélectionner le répertoire parent...</translation>
     </message>
     <message>
         <location filename="../gis/db/ISelectDBFolder.ui" line="26"/>
         <source>Name</source>
-        <translation type="unfinished">Nom</translation>
+        <translation>Nom</translation>
     </message>
 </context>
 <context>
@@ -3787,12 +4346,12 @@ or
     <message>
         <location filename="../helpers/ISelectProjectDialog.ui" line="20"/>
         <source>Select project from list or enter new project name.</source>
-        <translation>Choisissez le projet dans la liste ou entrez un nouveau nom de projet.</translation>
+        <translation type="unfinished">Choisissez un projet dans la liste ou entrez le nom d'un nouveau projet.</translation>
     </message>
     <message>
         <location filename="../helpers/ISelectProjectDialog.ui" line="33"/>
         <source>New project's name</source>
-        <translation type="unfinished"></translation>
+        <translation>Nom du nouveau projet</translation>
     </message>
     <message>
         <location filename="../helpers/ISelectProjectDialog.ui" line="43"/>
@@ -3812,7 +4371,7 @@ or
     <message>
         <location filename="../helpers/ISelectProjectDialog.ui" line="115"/>
         <source>Database</source>
-        <translation type="unfinished"></translation>
+        <translation>Base de données</translation>
     </message>
 </context>
 <context>
@@ -3820,17 +4379,17 @@ or
     <message>
         <location filename="../gis/db/ISelectSaveAction.ui" line="14"/>
         <source>Copy item...</source>
-        <translation type="unfinished">Copier un élément...</translation>
+        <translation>Copier un élément...</translation>
     </message>
     <message>
         <location filename="../gis/db/ISelectSaveAction.ui" line="23"/>
         <source>Replace existing item</source>
-        <translation type="unfinished">Remplacer l'élément existant</translation>
+        <translation>Remplacer l'élément existant</translation>
     </message>
     <message>
         <location filename="../gis/db/ISelectSaveAction.ui" line="30"/>
         <source>Replace with:</source>
-        <translation type="unfinished">Remplacer par:</translation>
+        <translation>Remplacer par:</translation>
     </message>
     <message>
         <location filename="../gis/db/ISelectSaveAction.ui" line="37"/>
@@ -3838,22 +4397,22 @@ or
         <location filename="../gis/db/ISelectSaveAction.ui" line="81"/>
         <location filename="../gis/db/ISelectSaveAction.ui" line="91"/>
         <source>TextLabel</source>
-        <translation type="unfinished">Libellé</translation>
+        <translation></translation>
     </message>
     <message>
         <location filename="../gis/db/ISelectSaveAction.ui" line="67"/>
         <source>Do not replace item</source>
-        <translation type="unfinished"></translation>
+        <translation>Ne pas remplacer l'élément</translation>
     </message>
     <message>
         <location filename="../gis/db/ISelectSaveAction.ui" line="74"/>
         <source>Use item:</source>
-        <translation type="unfinished"></translation>
+        <translation>Utiliser l'élément:</translation>
     </message>
     <message>
         <location filename="../gis/db/ISelectSaveAction.ui" line="111"/>
         <source>And for all other items, too.</source>
-        <translation type="unfinished">et pour tous les autres éléments</translation>
+        <translation>et pour tous les autres éléments</translation>
     </message>
 </context>
 <context>
@@ -3899,21 +4458,21 @@ or
     <name>ISetupFolder</name>
     <message>
         <source>Folder...</source>
-        <translation type="vanished">Dossier...</translation>
+        <translation type="obsolete">Dossier...</translation>
     </message>
     <message>
         <source>Name</source>
-        <translation type="vanished">Nom</translation>
+        <translation type="obsolete">Nom</translation>
     </message>
     <message>
         <location filename="../gis/db/ISetupFolder.ui" line="14"/>
         <source>Database Folder...</source>
-        <translation type="unfinished"></translation>
+        <translation>Dossier de base donnée...</translation>
     </message>
     <message>
         <location filename="../gis/db/ISetupFolder.ui" line="20"/>
         <source>Folder name</source>
-        <translation type="unfinished"></translation>
+        <translation>Nom du dossier</translation>
     </message>
     <message>
         <location filename="../gis/db/ISetupFolder.ui" line="30"/>
@@ -3936,27 +4495,27 @@ or
     <message>
         <location filename="../gis/wpt/ISetupNewWpt.ui" line="14"/>
         <source>New Waypoint...</source>
-        <translation type="unfinished"></translation>
+        <translation>Nouveau waypoint...</translation>
     </message>
     <message>
         <location filename="../gis/wpt/ISetupNewWpt.ui" line="22"/>
         <source>Symbol</source>
-        <translation type="unfinished"></translation>
+        <translation>Symbole</translation>
     </message>
     <message>
         <location filename="../gis/wpt/ISetupNewWpt.ui" line="29"/>
         <source>...</source>
-        <translation type="unfinished">...</translation>
+        <translation>...</translation>
     </message>
     <message>
         <location filename="../gis/wpt/ISetupNewWpt.ui" line="39"/>
         <source>Position</source>
-        <translation type="unfinished"></translation>
+        <translation>Position</translation>
     </message>
     <message>
         <location filename="../gis/wpt/ISetupNewWpt.ui" line="49"/>
         <source>Name</source>
-        <translation type="unfinished">Nom</translation>
+        <translation>Nom</translation>
     </message>
     <message>
         <location filename="../gis/wpt/ISetupNewWpt.ui" line="59"/>
@@ -3964,7 +4523,7 @@ or
 "[N|S] ddd mm.sss [W|E] ddd mm.sss"
 or
 "[N|S] ddd.ddd [W|E] ddd.ddd"</source>
-        <translation type="unfinished">Mauvais format de position. Formats valides: "[N|S] ddd mm.sss [W|E] ddd mm.sss" ou "[N|S] ddd.ddd [W|E] ddd.ddd" </translation>
+        <translation>Mauvais format de position. Formats valides: "[N|S] ddd mm.sss [W|E] ddd mm.sss" ou "[N|S] ddd.ddd [W|E] ddd.ddd" </translation>
     </message>
 </context>
 <context>
@@ -4155,17 +4714,17 @@ or
     <message>
         <location filename="../units/ITimeZoneSetup.ui" line="75"/>
         <source>Print date/time in </source>
-        <translation type="unfinished"></translation>
+        <translation>Afficher la date au format</translation>
     </message>
     <message>
         <location filename="../units/ITimeZoneSetup.ui" line="82"/>
         <source>long format, or</source>
-        <translation type="unfinished"></translation>
+        <translation>long</translation>
     </message>
     <message>
         <location filename="../units/ITimeZoneSetup.ui" line="92"/>
         <source>short format</source>
-        <translation type="unfinished"></translation>
+        <translation>court</translation>
     </message>
 </context>
 <context>
@@ -4229,17 +4788,17 @@ or
     </message>
     <message>
         <location filename="../gis/CGisListDB.cpp" line="436"/>
-        <location filename="../gis/prj/IGisProject.cpp" line="371"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="400"/>
         <source>Delete...</source>
         <translation>Supprimer...</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="956"/>
+        <location filename="../gis/CGisListWks.cpp" line="988"/>
         <source>Delete project...</source>
         <translation>Supprimer le projet</translation>
     </message>
     <message>
-        <location filename="../gis/CGisListWks.cpp" line="956"/>
+        <location filename="../gis/CGisListWks.cpp" line="988"/>
         <source>Do you really want to delete %1?</source>
         <translation>Êtes-vous sûr de vouloir supprimer %1?</translation>
     </message>
@@ -4262,8 +4821,8 @@ or
     </message>
     <message>
         <location filename="../gis/db/CDBProject.cpp" line="149"/>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="216"/>
-        <location filename="../gis/qms/CQmsProject.cpp" line="94"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="223"/>
+        <location filename="../gis/qms/CQmsProject.cpp" line="95"/>
         <location filename="../gis/tnv/CTwoNavProject.cpp" line="159"/>
         <source>Save GIS data to...</source>
         <translation>Enregistrer les données SIG dans...</translation>
@@ -4279,27 +4838,27 @@ or
         <translation>Annuler l'enregistrement</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="96"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="98"/>
         <location filename="../gis/qms/CQmsProject.cpp" line="48"/>
-        <location filename="../gis/qms/CQmsProject.cpp" line="144"/>
+        <location filename="../gis/qms/CQmsProject.cpp" line="145"/>
         <source>Failed to open...</source>
         <translation>Impossible d'ouvrir...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="96"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="98"/>
         <location filename="../gis/qms/CQmsProject.cpp" line="48"/>
-        <location filename="../gis/qms/CQmsProject.cpp" line="144"/>
+        <location filename="../gis/qms/CQmsProject.cpp" line="145"/>
         <source>Failed to open %1</source>
         <translation>Impossible d'ouvrir %1</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="109"/>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="118"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="111"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="120"/>
         <source>Failed to read...</source>
         <translation>Impossible de lire...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="109"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="111"/>
         <source>Failed to read: %1
 line %2, column %3:
  %4</source>
@@ -4308,32 +4867,32 @@ ligne %2, colonne %3:
 %4</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="118"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="120"/>
         <source>Not a GPX file: </source>
         <translation>N'est pas un fichier GPX:</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="291"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="298"/>
         <source>File exists ...</source>
         <translation>Le fichier existe...</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="292"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="299"/>
         <source>The file exists and it has not been created by QMapShack. If you press 'yes' all data in this file will be lost. Even if this file contains GPX data and has been loaded by QMapShack, QMapShack might not be able to load and store all elements of this file.  Those elements will be lost. I recommend to use another file. <b>Do you really want to overwrite the file?</b></source>
         <translation>Le fichier existe et n'a pas été créé par QMapShack. Si vous cliquez sur 'oui' tous les données de ce fichier seront perdues. Même si ce fichier contient des données GPX et sera ouvert par QMapShack certains éléments de ce fichier ne pourront pas être lus ou enregistrés. Ces élements seront perdus. Il est conseillé d'utiliser un autre fichier.<b>Voulez-vous vraiment écraser ce fichier ?</b> </translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="393"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="407"/>
         <source>Failed to create file '%1'</source>
         <translation>Impossible de créer le fichier: '%1'</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="402"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="416"/>
         <source>Failed to write file '%1'</source>
         <translation>Impossible d'écrire le fichier: '%1'</translation>
     </message>
     <message>
-        <location filename="../gis/gpx/CGpxProject.cpp" line="407"/>
+        <location filename="../gis/gpx/CGpxProject.cpp" line="421"/>
         <source>Saveing GIS data failed...</source>
         <translation>Impossible d'enregistrer les données SIG...</translation>
     </message>
@@ -4423,136 +4982,193 @@ ligne %2, colonne %3:
     </message>
     <message>
         <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="142"/>
-        <location filename="../gis/rte/CGisItemRte.cpp" line="45"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="49"/>
         <location filename="../gis/trk/CGisItemTrk.cpp" line="184"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="131"/>
         <source>_Clone</source>
         <translation>_Clone</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="433"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="444"/>
         <source>Area: %1%2</source>
         <translation>Surface: %1%2</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="491"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="502"/>
         <source>Changed area shape.</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="499"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="510"/>
         <source>Changed name.</source>
         <translation>Nom modifié...</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="505"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="516"/>
         <source>Changed border width.</source>
         <translation>Largeur de la bordure modifiée...</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="511"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="522"/>
         <source>Changed fill pattern.</source>
         <translation>Remplissage modifié...</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="517"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="528"/>
         <source>Changed opacity.</source>
         <translation>Opacité modifiée...</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="523"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="534"/>
         <source>Changed comment.</source>
         <translation>Commentaire modifié...</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="529"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="540"/>
         <source>Changed description.</source>
         <translation>Description modifiée...</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="535"/>
-        <location filename="../gis/rte/CGisItemRte.cpp" line="154"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1775"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="546"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="204"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1808"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="448"/>
         <source>Changed links</source>
         <translation>Liens modifiés...</translation>
     </message>
     <message>
-        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="547"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1787"/>
+        <location filename="../gis/ovl/CGisItemOvlArea.cpp" line="558"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1820"/>
         <source>Changed color</source>
         <translation>Couleur modifiée...</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="69"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="78"/>
         <source>Save project?</source>
-        <translation type="unfinished"></translation>
+        <translation>Enregistrer le projet ?</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="69"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="78"/>
         <source>The project "%1" was changed. Save befor closing it?</source>
+        <translation>Le projet "%1" a été modifié. Enregistrer avant de le fermer ?</translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/IGisProject.cpp" line="211"/>
+        <source>%1: Correlate tracks and waypoints.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="261"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="211"/>
+        <source>Abort</source>
+        <translation type="unfinished">Annuler</translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/IGisProject.cpp" line="223"/>
+        <source>Did that take too long for you? Do you want to skip correlation of tracks and waypoints for this project (%1) in the future?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/IGisProject.cpp" line="224"/>
+        <source>Cancelled correlation...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/prj/IGisProject.cpp" line="302"/>
         <source><br/>
 Filename: %1</source>
         <translation><br/>
 Nom de fichier: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="278"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="307"/>
         <source>Waypoints: %1</source>
         <translation>Waypoints: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="282"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="311"/>
         <source>Tracks: %1</source>
         <translation>Traces: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="286"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="315"/>
         <source>Routes: %1</source>
         <translation>Routes: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="290"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="319"/>
         <source>Areas: %1</source>
         <translation>Surfaces: %1</translation>
     </message>
     <message>
-        <location filename="../gis/prj/IGisProject.cpp" line="370"/>
+        <location filename="../gis/prj/IGisProject.cpp" line="399"/>
         <source>Are you sure you want to delete '%1' from project '%2'?</source>
         <translation>Êtes-vous sûr de vouloir supprimer %1 du projet '%2'?</translation>
     </message>
     <message>
-        <location filename="../gis/rte/CGisItemRte.cpp" line="142"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1763"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="192"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1796"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="436"/>
         <source>Changed comment</source>
         <translation>Commentaire modifié</translation>
     </message>
     <message>
-        <location filename="../gis/rte/CGisItemRte.cpp" line="148"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1769"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="198"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1802"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="442"/>
         <source>Changed description</source>
         <translation>Description modifiée</translation>
     </message>
     <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="231"/>
+        <source>Length: -</source>
+        <translation>Longueur: -</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="239"/>
+        <source>Time: %2 days %1</source>
+        <translation>Durée : %2 jours %1</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="248"/>
+        <source>Time: -</source>
+        <translatorcomment>tbc: heure/temps/durée</translatorcomment>
+        <translation>Heure : -</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="254"/>
+        <source>Last time routed:<br/>%1</source>
+        <translatorcomment>tbc</translatorcomment>
+        <translation>Date du dernier calcul d'itinéraire : <br/>%1</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="256"/>
+        <source>with %1</source>
+        <translation>avec %1</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="258"/>
+        <source>Calculation took %1 sec.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="479"/>
+        <source>Changed route points.</source>
+        <translation>Points de route modifiés.</translation>
+    </message>
+    <message>
         <location filename="../gis/tnv/CTwoNavProject.cpp" line="87"/>
         <location filename="../gis/tnv/CTwoNavProject.cpp" line="191"/>
         <location filename="../gis/tnv/serialization.cpp" line="295"/>
         <location filename="../gis/tnv/serialization.cpp" line="431"/>
         <location filename="../gis/tnv/serialization.cpp" line="460"/>
         <location filename="../gis/tnv/serialization.cpp" line="471"/>
-        <location filename="../gis/tnv/serialization.cpp" line="492"/>
-        <location filename="../gis/tnv/serialization.cpp" line="632"/>
-        <location filename="../gis/tnv/serialization.cpp" line="660"/>
-        <location filename="../gis/tnv/serialization.cpp" line="671"/>
-        <location filename="../gis/tnv/serialization.cpp" line="689"/>
-        <location filename="../gis/tnv/serialization.cpp" line="717"/>
-        <location filename="../gis/tnv/serialization.cpp" line="791"/>
+        <location filename="../gis/tnv/serialization.cpp" line="504"/>
+        <location filename="../gis/tnv/serialization.cpp" line="644"/>
+        <location filename="../gis/tnv/serialization.cpp" line="672"/>
+        <location filename="../gis/tnv/serialization.cpp" line="683"/>
+        <location filename="../gis/tnv/serialization.cpp" line="701"/>
+        <location filename="../gis/tnv/serialization.cpp" line="729"/>
+        <location filename="../gis/tnv/serialization.cpp" line="803"/>
         <source>Error...</source>
         <translation>Erreur...</translation>
     </message>
@@ -4561,23 +5177,23 @@ Nom de fichier: %1</translation>
         <location filename="../gis/tnv/CTwoNavProject.cpp" line="191"/>
         <location filename="../gis/tnv/serialization.cpp" line="295"/>
         <location filename="../gis/tnv/serialization.cpp" line="431"/>
-        <location filename="../gis/tnv/serialization.cpp" line="632"/>
+        <location filename="../gis/tnv/serialization.cpp" line="644"/>
         <source>Failed to open %1.</source>
         <translation>Impossible d'ouvrir %1</translation>
     </message>
     <message>
         <location filename="../gis/tnv/serialization.cpp" line="460"/>
         <location filename="../gis/tnv/serialization.cpp" line="471"/>
-        <location filename="../gis/tnv/serialization.cpp" line="660"/>
-        <location filename="../gis/tnv/serialization.cpp" line="671"/>
+        <location filename="../gis/tnv/serialization.cpp" line="672"/>
+        <location filename="../gis/tnv/serialization.cpp" line="683"/>
         <source>Only support lon/lat WGS 84 format.</source>
         <translation>Le seul format lon/lat autorisé est WGS 84</translation>
     </message>
     <message>
-        <location filename="../gis/tnv/serialization.cpp" line="492"/>
-        <location filename="../gis/tnv/serialization.cpp" line="689"/>
-        <location filename="../gis/tnv/serialization.cpp" line="717"/>
-        <location filename="../gis/tnv/serialization.cpp" line="791"/>
+        <location filename="../gis/tnv/serialization.cpp" line="504"/>
+        <location filename="../gis/tnv/serialization.cpp" line="701"/>
+        <location filename="../gis/tnv/serialization.cpp" line="729"/>
+        <location filename="../gis/tnv/serialization.cpp" line="803"/>
         <source>Failed to read data.</source>
         <translation>Impossible de lire les données.</translation>
     </message>
@@ -4587,170 +5203,174 @@ Nom de fichier: %1</translation>
         <translation>Points de la trace modifiés, Les données antérieures sont perdues.</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="416"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="227"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="441"/>
         <source>Length: %1 %2</source>
         <translation>Longueur: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="423"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="448"/>
         <source>, %1%2 %3, %4%5 %6</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="431"/>
+        <location filename="../gis/rte/CGisItemRte.cpp" line="243"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="456"/>
         <source>Time: %1</source>
         <translation>Durée: %1</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="434"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="444"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="459"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="469"/>
         <source>, Speed: %1 %2</source>
         <translation>, vitesse %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="441"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="466"/>
         <source>Moving: %1</source>
         <translation>Déplacement: %1</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="450"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="475"/>
         <source>Start: %1</source>
         <translation>Début: %1</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="455"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="480"/>
         <source>End: %1</source>
         <translation>Fin: %1</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="459"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="484"/>
         <source>Points: %1 (%2)</source>
         <translation></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="577"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="602"/>
         <source>Ele.: %1 %2</source>
         <translation>Altitude: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="580"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="605"/>
         <source> slope: %1%3 (%2%)</source>
         <translation> Pente: %1%3(%2%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="585"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="610"/>
         <source> speed: %1%2</source>
         <translation> Vitesse: %1 %2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="597"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="622"/>
         <source>Ascend: %1%2 (%3%)</source>
         <translation>Montée: %1%2 (%3%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="601"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="626"/>
         <source>Ascend: - (-)</source>
         <translation>Montées: - (-)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="607"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="632"/>
         <source> Descend: %1%2 (%3%)</source>
         <translation>  Descente: %1%2 (%3%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="611"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="636"/>
         <source> Descend: - (-) </source>
         <translation>Descente: - (-)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="618"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="643"/>
         <source>Dist.: %1%2 (%3%)</source>
         <translation>Dist.: %1%2 (%3%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="622"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="647"/>
         <source>Dist.: - (-)</source>
         <translation>Dist.: - (-)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="628"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="653"/>
         <source> Moving: %1%2 (%3%)</source>
         <translation>  En mouvement: %1%2 (%3%)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="632"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="657"/>
         <source> Moving: - (-) </source>
         <translation>En mouvement: - (-)</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="651"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="676"/>
         <source>Ascend: %1%2</source>
-        <translation type="unfinished"></translation>
+        <translation>Montée : %1%2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="656"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="673"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="681"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="698"/>
         <source>, %1%2</source>
-        <translation type="unfinished"></translation>
+        <translation></translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="661"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="686"/>
         <source>Ascend: -</source>
-        <translation type="unfinished"></translation>
+        <translation>Montée : -</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="668"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="693"/>
         <source> Descend: %1%2</source>
-        <translation type="unfinished"></translation>
+        <translation>Descente : %1%2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="678"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="703"/>
         <source>Descend: -</source>
-        <translation type="unfinished"></translation>
+        <translation>Descente : -</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="684"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="709"/>
         <source>Dist.: %1%2</source>
-        <translation type="unfinished"></translation>
+        <translation>Dist.: %1%2</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="689"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="714"/>
         <source> Time: %1%2</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1168"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1183"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1202"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1261"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1441"/>
-        <location filename="../mouse/CMouseEditArea.cpp" line="100"/>
-        <location filename="../mouse/CMouseEditTrk.cpp" line="104"/>
+        <translation> Temps : %1%2</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CCreateRouteFromWpt.cpp" line="65"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1201"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1216"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1235"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1294"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1474"/>
+        <location filename="../mouse/CMouseEditArea.cpp" line="99"/>
+        <location filename="../mouse/CMouseEditRte.cpp" line="109"/>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="115"/>
         <source>Edit name...</source>
         <translation>Éditer le nom...</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1168"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1183"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1202"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1261"/>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1441"/>
-        <location filename="../mouse/CMouseEditTrk.cpp" line="104"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1201"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1216"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1235"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1294"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1474"/>
+        <location filename="../mouse/CMouseEditTrk.cpp" line="115"/>
         <source>Enter new track name.</source>
-        <translation>Saisir le nouveau nom de la trace.</translation>
+        <translation type="unfinished">Entrez le nom de la nouvelle trace.</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1370"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1403"/>
         <source>Hide points.</source>
         <translation>Cacher des points.</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1416"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1449"/>
         <source>Show points.</source>
         <translation>Afficher les points.</translation>
     </message>
     <message>
-        <location filename="../gis/trk/CGisItemTrk.cpp" line="1757"/>
+        <location filename="../gis/trk/CGisItemTrk.cpp" line="1790"/>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="396"/>
         <source>Changed name</source>
         <translation>Nom modifié</translation>
@@ -4807,7 +5427,7 @@ Nom de fichier: %1</translation>
     </message>
     <message>
         <source>Enter new waypoint name.</source>
-        <translation type="vanished">Saisir le nouveau nom du waypoint.</translation>
+        <translation type="obsolete">Saisir le nouveau nom du waypoint.</translation>
     </message>
     <message>
         <location filename="../gis/wpt/CGisItemWpt.cpp" line="314"/>
@@ -4866,9 +5486,9 @@ Nom de fichier: %1</translation>
         <translation>Ceci est un fichier type avec un encodage de polyligne inconnu. Veuillez signaler ce problème.</translation>
     </message>
     <message>
-        <location filename="../mouse/CMouseEditArea.cpp" line="100"/>
+        <location filename="../mouse/CMouseEditArea.cpp" line="99"/>
         <source>Enter new area name.</source>
-        <translation>Saisir le nouveau nom de la surface.</translation>
+        <translation type="unfinished">Entrez le nom de la nouvelle surface.</translation>
     </message>
     <message>
         <location filename="../qlgt/converter.cpp" line="194"/>
@@ -4900,9 +5520,15 @@ Nom de fichier: %1</translation>
         <translation>Le nombre de points de trace ne correspond pas au nombre des points cachés</translation>
     </message>
     <message>
-        <location filename="../device/IDevice.cpp" line="202"/>
+        <location filename="../device/IDevice.cpp" line="204"/>
         <source>There is another project with the same name. If you press 'ok' it will be removed and replaced.</source>
-        <translation type="unfinished"></translation>
+        <translation>Un autre projet du même nom existe déjà. Si vous confirmez, il sera supprimé et remplacé.</translation>
+    </message>
+    <message>
+        <location filename="../gis/rte/CCreateRouteFromWpt.cpp" line="65"/>
+        <location filename="../mouse/CMouseEditRte.cpp" line="109"/>
+        <source>Enter new route name.</source>
+        <translation type="unfinished">Entrez le nom de la nouvelle route.</translation>
     </message>
 </context>
 </TS>
diff --git a/src/map/CMapDraw.cpp b/src/map/CMapDraw.cpp
index 208ffbd..9cc2280 100644
--- a/src/map/CMapDraw.cpp
+++ b/src/map/CMapDraw.cpp
@@ -78,6 +78,18 @@ void CMapDraw::setupMapPath()
     setupMapPath(paths);
 }
 
+void CMapDraw::setupMapPath(const QString &path)
+{
+    if(mapPaths.contains(path))
+    {
+        return;
+    }
+
+    QStringList paths(mapPaths);
+    paths << path;
+    setupMapPath(paths);
+}
+
 void CMapDraw::setupMapPath(const QStringList& paths)
 {
     mapPaths = paths;
@@ -159,7 +171,7 @@ void CMapDraw::getToolTip(const QPoint& px, QString& str)
     CMapItem::mutexActiveMaps.unlock();
 }
 
-bool CMapDraw::findPolylineCloseBy(QPointF& pt1, QPointF& pt2, qint32 threshold, QPolygonF& polyline)
+bool CMapDraw::findPolylineCloseBy(const QPointF& pt1, const QPointF& pt2, qint32 threshold, QPolygonF& polyline)
 {
     if(isRunning())
     {
diff --git a/src/map/CMapDraw.h b/src/map/CMapDraw.h
index 1418f2a..6985737 100644
--- a/src/map/CMapDraw.h
+++ b/src/map/CMapDraw.h
@@ -75,7 +75,8 @@ public:
     void setProjection(const QString& proj);
 
     static void setupMapPath();
-    static void setupMapPath(const QStringList& paths);
+    static void setupMapPath(const QString &path);
+    static void setupMapPath(const QStringList &paths);
     static void saveMapPath(QSettings &cfg);
     static void loadMapPath(QSettings &cfg);
     static const QStringList& getSupportedFormats()
@@ -112,7 +113,7 @@ public:
        @param polyline      the resulting polyline, if any, in [rad]
        @return              Return true if a line has been found.
      */
-    bool findPolylineCloseBy(QPointF& pt1, QPointF& pt2, qint32 threshold, QPolygonF& polyline);
+    bool findPolylineCloseBy(const QPointF& pt1, const QPointF& pt2, qint32 threshold, QPolygonF& polyline);
 
 protected:
     void drawt(buffer_t& currentBuffer);
diff --git a/src/map/CMapIMG.cpp b/src/map/CMapIMG.cpp
index 61efc62..6dd3aab 100644
--- a/src/map/CMapIMG.cpp
+++ b/src/map/CMapIMG.cpp
@@ -539,7 +539,7 @@ void CMapIMG::readBasics()
             break;
         }
         dataoffset += sizeof(FATblock_t);
-        readFile(file, dataoffset, sizeof(FATblock_t), FATblock);
+        readFile(file, quint32(dataoffset), quint32(sizeof(FATblock_t)), FATblock);
         pFATBlock = (const FATblock_t * )FATblock.data();
     }
 
@@ -593,12 +593,12 @@ void CMapIMG::readBasics()
 
                 subfile_part_t& part = subfile.parts[tmpstr];
                 part.size   = gar_load(uint32_t, pFATBlock->size);
-                part.offset = gar_load(uint16_t, pFATBlock->blocks[0]) * blocksize;
+                part.offset = quint32(gar_load(uint16_t, pFATBlock->blocks[0]) * blocksize);
             }
         }
 
         dataoffset += sizeof(FATblock_t);
-        readFile(file, dataoffset, sizeof(FATblock_t), FATblock);
+        readFile(file, quint32(dataoffset), quint32(sizeof(FATblock_t)), FATblock);
         pFATBlock = (const FATblock_t * )FATblock.data();
     }
 
@@ -637,12 +637,16 @@ void CMapIMG::readBasics()
 #endif                       //DEBUG_SHOW_SECT_DESC
 
     int cnt = 1;
-    PROGRESS_SETUP(tr("Loading %1").arg(QFileInfo(filename).fileName()), subfiles.count());
+    int tot = subfiles.count();
+
+    PROGRESS_SETUP(tr("Loading %1").arg(QFileInfo(filename).fileName()), &CMainWindow::self());
+    progress.setMinimumDuration(1000);
+
     maparea = QRectF();
     QMap<QString,subfile_desc_t>::iterator subfile = subfiles.begin();
     while(subfile != subfiles.end())
     {
-        PROGRESS(cnt++, throw exce_t(errAbort,tr("User abort: ") + filename))
+        PROGRESS(cnt++, tot, throw exce_t(errAbort,tr("User abort: ") + filename));
         if((*subfile).parts.contains("GMP"))
         {
             throw exce_t(errFormat,tr("File is NT format. QMapShack is unable to read map files with NT format: ") + filename);
@@ -2820,7 +2824,7 @@ static qreal getDistance(const QPolygonF& line, const QPointF& pt, qreal thresho
 
 
 
-bool CMapIMG::findPolylineCloseBy(QPointF& pt1, QPointF& pt2, qint32 threshold, QPolygonF& polyline)
+bool CMapIMG::findPolylineCloseBy(const QPointF& pt1, const QPointF& pt2, qint32 threshold, QPolygonF& polyline)
 {
     foreach(const CGarminPolygon &line, polylines)
     {
diff --git a/src/map/CMapIMG.h b/src/map/CMapIMG.h
index 299786e..cd5062e 100644
--- a/src/map/CMapIMG.h
+++ b/src/map/CMapIMG.h
@@ -164,7 +164,7 @@ public:
        @param polyline      the resulting polyline, if any, in [rad]
        @return              Return true if a line has been found.
      */
-    bool findPolylineCloseBy(QPointF& pt1, QPointF& pt2, qint32 threshold, QPolygonF& polyline);
+    bool findPolylineCloseBy(const QPointF &pt1, const QPointF &pt2, qint32 threshold, QPolygonF& polyline);
 
 
 private:
diff --git a/src/map/CMapList.cpp b/src/map/CMapList.cpp
index dfa5ff9..29fe8ee 100644
--- a/src/map/CMapList.cpp
+++ b/src/map/CMapList.cpp
@@ -185,7 +185,7 @@ void CMapList::slotMapHonk()
     saveResource("OSM_Topo.tms", dir);
     saveResource("OpenCycleMap.tms", dir);
 
-    CMapDraw::setupMapPath(QStringList(QStringList(path)));
+    CMapDraw::setupMapPath(path);
 
     CCanvas * canvas = CMainWindow::self().getVisibleCanvas();
     if(canvas)
diff --git a/src/map/CMapPathSetup.cpp b/src/map/CMapPathSetup.cpp
index 5d3db32..058cf18 100644
--- a/src/map/CMapPathSetup.cpp
+++ b/src/map/CMapPathSetup.cpp
@@ -62,8 +62,11 @@ void CMapPathSetup::slotAddPath()
     QString path = QFileDialog::getExistingDirectory(this, tr("Select map path..."), QDir::homePath(), 0);
     if(!path.isEmpty())
     {
-        QListWidgetItem * item = new QListWidgetItem(listWidget);
-        item->setText(path);
+        if(!paths.contains(path))
+        {
+            QListWidgetItem * item = new QListWidgetItem(listWidget);
+            item->setText(path);
+        }
     }
 }
 
diff --git a/src/map/CMapRMAP.h b/src/map/CMapRMAP.h
index 72b3b20..599f8bf 100644
--- a/src/map/CMapRMAP.h
+++ b/src/map/CMapRMAP.h
@@ -60,9 +60,9 @@ private:
     QString filename;
 
     /// total width in number of px
-    quint32 xsize_px;
+    qint32 xsize_px;
     /// total height in number of px
-    quint32 ysize_px;
+    qint32 ysize_px;
     /// width of a tile in number of px
     quint32 tileSizeX;
     /// height of a tile in number of px
diff --git a/src/map/CMapVRT.cpp b/src/map/CMapVRT.cpp
index 5e5bab4..ccafe4d 100644
--- a/src/map/CMapVRT.cpp
+++ b/src/map/CMapVRT.cpp
@@ -118,6 +118,7 @@ CMapVRT::CMapVRT(const QString &filename, CMapDraw *parent)
     qDebug() << ptr;
 
     pjsrc = pj_init_plus(ptr);
+    free(ptr);
     if(pjsrc == 0)
     {
         delete dataset; dataset = 0;
diff --git a/src/map/CMapWMTS.cpp b/src/map/CMapWMTS.cpp
index cb6a7ef..e0e898d 100644
--- a/src/map/CMapWMTS.cpp
+++ b/src/map/CMapWMTS.cpp
@@ -177,7 +177,11 @@ CMapWMTS::CMapWMTS(const QString &filename, CMapDraw *parent)
 
         // read projection string
         QString str = xmlTileMatrixSet.namedItem("SupportedCRS").toElement().text();
-        char * ptr = str.toLatin1().data();
+
+        char * ptr1 = (char*)malloc(str.toLatin1().size() + 1);
+        char * ptr2 = 0;
+
+        strncpy(ptr1,str.toLatin1().data(), str.toLatin1().size() + 1);
         OGRSpatialReference oSRS;
 
         if(str.startsWith("EPSG"))
@@ -187,12 +191,16 @@ CMapWMTS::CMapWMTS(const QString &filename, CMapDraw *parent)
         }
         else
         {
-            oSRS.importFromURN(ptr);
+            oSRS.importFromURN(ptr1);
         }
-        oSRS.exportToProj4(&ptr);
+        oSRS.exportToProj4(&ptr2);
+
+        qDebug() << ptr1 << ptr2;
+        tileset.pjsrc = pj_init_plus(ptr2);
+
+        free(ptr1);
+        free(ptr2);
 
-        qDebug() << ptr;
-        tileset.pjsrc = pj_init_plus(ptr);
         if(tileset.pjsrc == 0)
         {
             QMessageBox::warning(&CMainWindow::self(), tr("Error..."), tr("No georeference information found."));
diff --git a/src/map/IMap.cpp b/src/map/IMap.cpp
index 98e288f..3f5c670 100644
--- a/src/map/IMap.cpp
+++ b/src/map/IMap.cpp
@@ -129,7 +129,7 @@ void IMap::drawTile(QImage& img, QPolygonF& l, QPainter& p)
     p.restore();
 }
 
-bool IMap::findPolylineCloseBy(QPointF& pt1, QPointF& pt2, qint32 threshold, QPolygonF& polyline)
+bool IMap::findPolylineCloseBy(const QPointF& pt1, const QPointF& pt2, qint32 threshold, QPolygonF& polyline)
 {
     Q_UNUSED(pt1);
     Q_UNUSED(pt2);
diff --git a/src/map/IMap.h b/src/map/IMap.h
index 61fe525..8a55a07 100644
--- a/src/map/IMap.h
+++ b/src/map/IMap.h
@@ -157,7 +157,7 @@ public:
        @param polyline      the resulting polyline, if any, in [rad]
        @return              Return true if a line has been found.
      */
-    virtual bool findPolylineCloseBy(QPointF& pt1, QPointF& pt2, qint32 threshold, QPolygonF& polyline);
+    virtual bool findPolylineCloseBy(const QPointF& pt1, const QPointF& pt2, qint32 threshold, QPolygonF& polyline);
 
 public slots:
     void slotSetShowPolygons(bool yes)
diff --git a/src/map/IMapPathSetup.ui b/src/map/IMapPathSetup.ui
index 5761e9a..0bb753a 100644
--- a/src/map/IMapPathSetup.ui
+++ b/src/map/IMapPathSetup.ui
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>450</width>
-    <height>275</height>
+    <height>277</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -124,25 +124,6 @@
    <item>
     <layout class="QHBoxLayout" name="horizontalLayout">
      <item>
-      <widget class="QLabel" name="labelHelp">
-       <property name="sizePolicy">
-        <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
-         <horstretch>0</horstretch>
-         <verstretch>0</verstretch>
-        </sizepolicy>
-       </property>
-       <property name="text">
-        <string>-</string>
-       </property>
-       <property name="alignment">
-        <set>Qt::AlignJustify|Qt::AlignVCenter</set>
-       </property>
-       <property name="wordWrap">
-        <bool>true</bool>
-       </property>
-      </widget>
-     </item>
-     <item>
       <widget class="QLabel" name="label_3">
        <property name="maximumSize">
         <size>
@@ -162,6 +143,25 @@
       </widget>
      </item>
      <item>
+      <widget class="QLabel" name="labelHelp">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="text">
+        <string>-</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignJustify|Qt::AlignVCenter</set>
+       </property>
+       <property name="wordWrap">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
       <widget class="QDialogButtonBox" name="buttonBox">
        <property name="sizePolicy">
         <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
diff --git a/templates/source.cpp b/src/mouse/CMouseDummy.cpp
similarity index 79%
copy from templates/source.cpp
copy to src/mouse/CMouseDummy.cpp
index 5306387..22f49af 100644
--- a/templates/source.cpp
+++ b/src/mouse/CMouseDummy.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -16,15 +16,15 @@
 
 **********************************************************************************************/
 
-#include "CLASSNAME.h"
+#include "CMouseDummy.h"
 
-CLASSNAME::CLASSNAME()
+CMouseDummy::CMouseDummy()
+    : IMouse(0,0)
 {
-
+    cursor = QCursor(QPixmap(":/cursors/cursorArrow.png"),0,0);
 }
 
-CLASSNAME::~CLASSNAME()
+CMouseDummy::~CMouseDummy()
 {
-
 }
 
diff --git a/src/mouse/CScrOptEditLine.h b/src/mouse/CMouseDummy.h
similarity index 62%
copy from src/mouse/CScrOptEditLine.h
copy to src/mouse/CMouseDummy.h
index 4325729..f52c805 100644
--- a/src/mouse/CScrOptEditLine.h
+++ b/src/mouse/CMouseDummy.h
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -16,23 +16,34 @@
 
 **********************************************************************************************/
 
-#ifndef CSCROPTEDITLINE_H
-#define CSCROPTEDITLINE_H
+#ifndef CMOUSEDUMMY_H
+#define CMOUSEDUMMY_H
 
-#include "mouse/IScrOpt.h"
-#include "ui_IScrOptEditLine.h"
+#include <mouse/IMouse.h>
 
-class CScrOptEditLine : public IScrOpt, public Ui::IScrOptEditLine
+
+class CMouseDummy : public IMouse
 {
-    Q_OBJECT
 public:
-    CScrOptEditLine(QWidget * parent);
-    virtual ~CScrOptEditLine();
+    CMouseDummy();
+    virtual ~CMouseDummy();
 
-    void draw(QPainter& p)
+    void draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect)
+    {
+    }
+    void mousePressEvent(QMouseEvent * e)
+    {
+    }
+    void mouseMoveEvent(QMouseEvent * e)
+    {
+    }
+    void mouseReleaseEvent(QMouseEvent *e)
+    {
+    }
+    virtual void wheelEvent(QWheelEvent * e)
     {
     }
 };
 
-#endif //CSCROPTEDITLINE_H
+#endif //CMOUSEDUMMY_H
 
diff --git a/src/mouse/CMouseEditArea.cpp b/src/mouse/CMouseEditArea.cpp
index 777a711..4e8df27 100644
--- a/src/mouse/CMouseEditArea.cpp
+++ b/src/mouse/CMouseEditArea.cpp
@@ -25,17 +25,18 @@
 #include <QtWidgets>
 
 CMouseEditArea::CMouseEditArea(const QPointF& point, CGisDraw * gis, CCanvas * parent)
-    : IMouseEditLine(point, gis, parent)
+    : IMouseEditLine(IGisItem::key_t(), point, gis, parent)
 {
-    cursor = cursor1 = QCursor(QPixmap(":/cursors/cursorMoveArea.png"),0,0);
+    startNewLine(point);
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
 }
 
 CMouseEditArea::CMouseEditArea(CGisItemOvlArea &area, CGisDraw * gis, CCanvas * parent)
-    : IMouseEditLine(area, gis, parent)
+    : IMouseEditLine(area.getKey(), area, gis, parent)
 {
-    cursor = cursor1 = QCursor(QPixmap(":/cursors/cursorMoveArea.png"),0,0);
-    key         = area.getKey();
-    canvas->reportStatus(key.item, tr("<b>Edit Area</b><br/>Select a corner point for more options.<br/>"));
+    canvas->reportStatus(key.item, tr("<b>Edit Area</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/>"));
+
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
 }
 
 CMouseEditArea::~CMouseEditArea()
@@ -49,15 +50,13 @@ void CMouseEditArea::mousePressEvent(QMouseEvent * e)
     IMouseEditLine::mousePressEvent(e);
 }
 
-
-void CMouseEditArea::drawLine(const QPolygonF &l, QPainter& p)
+void CMouseEditArea::drawLine(const QPolygonF &l, const QColor color, int width, QPainter& p)
 {
-    p.setPen(QPen(Qt::magenta, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
+    p.setPen(QPen(color, width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
     p.setBrush(QBrush(Qt::magenta, Qt::BDiagPattern));
     p.drawPolygon(l);
 }
 
-
 IGisLine * CMouseEditArea::getGisLine()
 {
     return dynamic_cast<CGisItemOvlArea*>(CGisWidget::self().getItemByKey(key));
@@ -79,7 +78,7 @@ void CMouseEditArea::slotCopyToNew()
 {
     canvas->reportStatus(key.item,"");
 
-    if(coords1.size() < 3)
+    if(points.size() < 3)
     {
         return;
     }
@@ -104,7 +103,7 @@ void CMouseEditArea::slotCopyToNew()
         return;
     }
 
-    new CGisItemOvlArea(coords1,name, project, NOIDX);
+    new CGisItemOvlArea(points, name, project, NOIDX);
 
     canvas->resetMouse();
     canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis);
diff --git a/src/mouse/CMouseEditArea.h b/src/mouse/CMouseEditArea.h
index b492660..fb34880 100644
--- a/src/mouse/CMouseEditArea.h
+++ b/src/mouse/CMouseEditArea.h
@@ -20,7 +20,7 @@
 #define CMOUSEEDITAREA_H
 
 #include "gis/IGisItem.h"
-#include "mouse/IMouseEditLine.h"
+#include "mouse/line/IMouseEditLine.h"
 
 class CGisItemOvlArea;
 
@@ -40,11 +40,9 @@ protected slots:
     void slotCopyToOrig();
 
 protected:
-    virtual void drawLine(const QPolygonF& l, QPainter& p);
-    IGisLine * getGisLine();
+    void drawLine(const QPolygonF &l, const QColor color, int width, QPainter& p);
 
-private:
-    IGisItem::key_t key;
+    IGisLine * getGisLine();
 };
 
 #endif //CMOUSEEDITAREA_H
diff --git a/src/mouse/CMouseEditTrk.cpp b/src/mouse/CMouseEditRte.cpp
similarity index 54%
copy from src/mouse/CMouseEditTrk.cpp
copy to src/mouse/CMouseEditRte.cpp
index 61c1f25..2e735cc 100644
--- a/src/mouse/CMouseEditTrk.cpp
+++ b/src/mouse/CMouseEditRte.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -19,70 +19,75 @@
 #include "CMainWindow.h"
 #include "canvas/CCanvas.h"
 #include "gis/CGisWidget.h"
-#include "gis/trk/CGisItemTrk.h"
-#include "mouse/CMouseEditTrk.h"
+#include "gis/rte/CGisItemRte.h"
+#include "mouse/CMouseEditRte.h"
+#include "mouse/line/CScrOptEditLine.h"
 
 #include <QtWidgets>
 
-CMouseEditTrk::CMouseEditTrk(const QPointF& point, CGisDraw * gis, CCanvas * parent)
-    : IMouseEditLine(point, gis, parent)
+
+CMouseEditRte::CMouseEditRte(const QPointF &point, CGisDraw *gis, CCanvas *parent)
+    : IMouseEditLine(IGisItem::key_t(), point, gis, parent)
 {
-    cursor = cursor1 = QCursor(QPixmap(":/cursors/cursorMoveLine.png"),0,0);
+    startNewLine(point);
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
 }
 
-CMouseEditTrk::CMouseEditTrk(CGisItemTrk &trk, CGisDraw * gis, CCanvas * parent)
-    : IMouseEditLine(trk, gis, parent)
+CMouseEditRte::CMouseEditRte(CGisItemRte &rte, CGisDraw * gis, CCanvas * parent)
+    : IMouseEditLine(rte.getKey(), rte, gis, parent)
 {
-    cursor = cursor1 = QCursor(QPixmap(":/cursors/cursorMoveLine.png"),0,0);
-    key         = trk.getKey();
+    canvas->reportStatus(key.item, tr("<b>Edit Route Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/>"));
 
-    // reset any focus the track might have.
-    trk.setMouseFocusByPoint(NOPOINT, CGisItemTrk::eFocusMouseMove, "CMouseEditTrk");
-    trk.setMouseFocusByPoint(NOPOINT, CGisItemTrk::eFocusMouseClick, "CMouseEditTrk");
-    trk.looseUserFocus();
+    if(!points.first().subpts.isEmpty())
+    {
+        scrOptEditLine->toolAutoRoute->setChecked(true);
+    }
+    else
+    {
+        scrOptEditLine->toolNoRoute->setChecked(true);
+    }
 
-    canvas->reportStatus(key.item, tr("<b>Edit Track Points</b><br/>Select a track point for more options.<br/>"));
     /*
         trigger complete update of GIS components to make sure all changes to
         the originating object are reflected on the canvas
      */
-    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis);
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
 }
 
-CMouseEditTrk::~CMouseEditTrk()
+
+CMouseEditRte::~CMouseEditRte()
 {
-//    canvas->reportStatus(key,"");
 }
 
-void CMouseEditTrk::mousePressEvent(QMouseEvent * e)
+void CMouseEditRte::mousePressEvent(QMouseEvent * e)
 {
     canvas->reportStatus(key.item, "");
     IMouseEditLine::mousePressEvent(e);
 }
 
-IGisLine * CMouseEditTrk::getGisLine()
+IGisLine * CMouseEditRte::getGisLine()
 {
-    return dynamic_cast<CGisItemTrk*>(CGisWidget::self().getItemByKey(key));
+    return dynamic_cast<CGisItemRte*>(CGisWidget::self().getItemByKey(key));
 }
 
-void CMouseEditTrk::slotAbort()
+void CMouseEditRte::slotAbort()
 {
     canvas->reportStatus(key.item,"");
     IMouseEditLine::slotAbort();
 }
 
-void CMouseEditTrk::slotCopyToOrig()
+void CMouseEditRte::slotCopyToOrig()
 {
     canvas->reportStatus(key.item,"");
     IMouseEditLine::slotCopyToOrig();
 }
 
 
-void CMouseEditTrk::slotCopyToNew()
+void CMouseEditRte::slotCopyToNew()
 {
     canvas->reportStatus(key.item,"");
 
-    if(coords1.size() < 2)
+    if(points.size() < 2)
     {
         return;
     }
@@ -95,20 +100,20 @@ void CMouseEditTrk::slotCopyToNew()
 
     /// @todo make this independent from track
     QString name;
-    CGisItemTrk * trk = dynamic_cast<CGisItemTrk*>(CGisWidget::self().getItemByKey(key));
-    if(trk != 0)
+    CGisItemRte * rte = dynamic_cast<CGisItemRte*>(CGisWidget::self().getItemByKey(key));
+    if(rte != 0)
     {
-        name = trk->getName();
+        name = rte->getName();
     }
 
-    name = QInputDialog::getText(&CMainWindow::self(), QObject::tr("Edit name..."), QObject::tr("Enter new track name."), QLineEdit::Normal, name);
+    name = QInputDialog::getText(&CMainWindow::self(), QObject::tr("Edit name..."), QObject::tr("Enter new route name."), QLineEdit::Normal, name);
 
     if(name.isEmpty())
     {
         return;
     }
 
-    new CGisItemTrk(coords1,name, project, NOIDX);
+    new CGisItemRte(points,name, project, NOIDX);
 
     canvas->resetMouse();
     canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis);
diff --git a/src/mouse/CMouseEditTrk.h b/src/mouse/CMouseEditRte.h
similarity index 72%
copy from src/mouse/CMouseEditTrk.h
copy to src/mouse/CMouseEditRte.h
index bbb5840..5008e12 100644
--- a/src/mouse/CMouseEditTrk.h
+++ b/src/mouse/CMouseEditRte.h
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -16,21 +16,21 @@
 
 **********************************************************************************************/
 
-#ifndef CMOUSEEDITTRK_H
-#define CMOUSEEDITTRK_H
+#ifndef CMOUSEEDITRTE_H
+#define CMOUSEEDITRTE_H
 
 #include "gis/IGisItem.h"
-#include "mouse/IMouseEditLine.h"
+#include "mouse/line/IMouseEditLine.h"
 
-class CGisItemTrk;
+class CGisItemRte;
 
-class CMouseEditTrk : public IMouseEditLine
+class CMouseEditRte : public IMouseEditLine
 {
     Q_OBJECT
 public:
-    CMouseEditTrk(const QPointF& point, CGisDraw * gis, CCanvas * parent);
-    CMouseEditTrk(CGisItemTrk &trk, CGisDraw * gis, CCanvas * parent);
-    virtual ~CMouseEditTrk();
+    CMouseEditRte(const QPointF& point, CGisDraw * gis, CCanvas * parent);
+    CMouseEditRte(CGisItemRte &rte, CGisDraw * gis, CCanvas * parent);
+    virtual ~CMouseEditRte();
 
     void mousePressEvent(QMouseEvent * e);
 
@@ -42,10 +42,7 @@ protected slots:
 
 protected:
     IGisLine * getGisLine();
-
-private:
-    IGisItem::key_t key;
 };
 
-#endif //CMOUSEEDITTRK_H
+#endif //CMOUSEEDITRTE_H
 
diff --git a/src/mouse/CMouseEditTrk.cpp b/src/mouse/CMouseEditTrk.cpp
index 61c1f25..fdab280 100644
--- a/src/mouse/CMouseEditTrk.cpp
+++ b/src/mouse/CMouseEditTrk.cpp
@@ -25,28 +25,29 @@
 #include <QtWidgets>
 
 CMouseEditTrk::CMouseEditTrk(const QPointF& point, CGisDraw * gis, CCanvas * parent)
-    : IMouseEditLine(point, gis, parent)
+    : IMouseEditLine(IGisItem::key_t(), point, gis, parent)
+    , isNewLine(true)
 {
-    cursor = cursor1 = QCursor(QPixmap(":/cursors/cursorMoveLine.png"),0,0);
+    startNewLine(point);
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
 }
 
 CMouseEditTrk::CMouseEditTrk(CGisItemTrk &trk, CGisDraw * gis, CCanvas * parent)
-    : IMouseEditLine(trk, gis, parent)
+    : IMouseEditLine(trk.getKey(), trk, gis, parent)
+    , isNewLine(false)
 {
-    cursor = cursor1 = QCursor(QPixmap(":/cursors/cursorMoveLine.png"),0,0);
-    key         = trk.getKey();
+    canvas->reportStatus(key.item, tr("<b>Edit Track Points</b><br/>Select a function and a routing mode via the tool buttons. Next select a point of the line. Only points marked with a large square can be changed. The ones with a black dot are subpoints introduced by routing.<br/>"));
 
     // reset any focus the track might have.
     trk.setMouseFocusByPoint(NOPOINT, CGisItemTrk::eFocusMouseMove, "CMouseEditTrk");
     trk.setMouseFocusByPoint(NOPOINT, CGisItemTrk::eFocusMouseClick, "CMouseEditTrk");
     trk.looseUserFocus();
 
-    canvas->reportStatus(key.item, tr("<b>Edit Track Points</b><br/>Select a track point for more options.<br/>"));
     /*
         trigger complete update of GIS components to make sure all changes to
         the originating object are reflected on the canvas
      */
-    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis);
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
 }
 
 CMouseEditTrk::~CMouseEditTrk()
@@ -74,6 +75,16 @@ void CMouseEditTrk::slotAbort()
 void CMouseEditTrk::slotCopyToOrig()
 {
     canvas->reportStatus(key.item,"");
+
+    if(!isNewLine)
+    {
+        int res = QMessageBox::warning(canvas, tr("Warning!"), tr("This will replace all data of the orignal by a simple line of coordinates. All other data will be lost permanently."), QMessageBox::Ok|QMessageBox::Abort, QMessageBox::Ok);
+
+        if(res != QMessageBox::Ok)
+        {
+            return;
+        }
+    }
     IMouseEditLine::slotCopyToOrig();
 }
 
@@ -82,7 +93,7 @@ void CMouseEditTrk::slotCopyToNew()
 {
     canvas->reportStatus(key.item,"");
 
-    if(coords1.size() < 2)
+    if(points.size() < 2)
     {
         return;
     }
@@ -108,7 +119,9 @@ void CMouseEditTrk::slotCopyToNew()
         return;
     }
 
-    new CGisItemTrk(coords1,name, project, NOIDX);
+    CMainWindow::self().getEelevationAt(points);
+
+    new CGisItemTrk(points,name, project, NOIDX);
 
     canvas->resetMouse();
     canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis);
diff --git a/src/mouse/CMouseEditTrk.h b/src/mouse/CMouseEditTrk.h
index bbb5840..f55c838 100644
--- a/src/mouse/CMouseEditTrk.h
+++ b/src/mouse/CMouseEditTrk.h
@@ -19,8 +19,7 @@
 #ifndef CMOUSEEDITTRK_H
 #define CMOUSEEDITTRK_H
 
-#include "gis/IGisItem.h"
-#include "mouse/IMouseEditLine.h"
+#include "mouse/line/IMouseEditLine.h"
 
 class CGisItemTrk;
 
@@ -42,9 +41,7 @@ protected slots:
 
 protected:
     IGisLine * getGisLine();
-
-private:
-    IGisItem::key_t key;
+    bool isNewLine;
 };
 
 #endif //CMOUSEEDITTRK_H
diff --git a/src/mouse/CMouseMoveWpt.cpp b/src/mouse/CMouseMoveWpt.cpp
index 8ffcffe..09e4fee 100644
--- a/src/mouse/CMouseMoveWpt.cpp
+++ b/src/mouse/CMouseMoveWpt.cpp
@@ -41,7 +41,7 @@ CMouseMoveWpt::~CMouseMoveWpt()
 {
 }
 
-void CMouseMoveWpt::draw(QPainter& p,  bool needsRedraw, const QRect &rect)
+void CMouseMoveWpt::draw(QPainter& p,  CCanvas::redraw_e needsRedraw, const QRect &rect)
 {
     QString val, unit, str;
     qreal d, a1 = 0, a2 = 0;
diff --git a/src/mouse/CMouseMoveWpt.h b/src/mouse/CMouseMoveWpt.h
index b3783be..d5e46b2 100644
--- a/src/mouse/CMouseMoveWpt.h
+++ b/src/mouse/CMouseMoveWpt.h
@@ -34,7 +34,7 @@ public:
     CMouseMoveWpt(CGisItemWpt& wpt, CGisDraw * gis, CCanvas * parent);
     virtual ~CMouseMoveWpt();
 
-    void draw(QPainter& p,  bool needsRedraw, const QRect &rect);
+    void draw(QPainter& p,  CCanvas::redraw_e needsRedraw, const QRect &rect);
     void mousePressEvent(QMouseEvent * e);
     void mouseMoveEvent(QMouseEvent * e);
     void mouseReleaseEvent(QMouseEvent *e);
diff --git a/src/mouse/CMouseNormal.cpp b/src/mouse/CMouseNormal.cpp
index 8476c0e..1bfd262 100644
--- a/src/mouse/CMouseNormal.cpp
+++ b/src/mouse/CMouseNormal.cpp
@@ -36,12 +36,14 @@ CMouseNormal::CMouseNormal(CGisDraw *gis, CCanvas *canvas)
     , stateItemSel(eStateIdle)
 {
     cursor = QCursor(QPixmap(":/cursors/cursorMoveMap.png"),0,0);
-    screenUnclutter = new CScrOptUnclutter(canvas);
+    screenUnclutter = new CScrOptUnclutter(this);
 
     menu = new QMenu(canvas);
     menu->addAction(QIcon("://icons/32x32/AddWpt.png"), tr("Add Waypoint"), this, SLOT(slotAddWpt()));
     menu->addAction(QIcon("://icons/32x32/AddTrk.png"), tr("Add Track"), this, SLOT(slotAddTrk()));
+    menu->addAction(QIcon("://icons/32x32/AddRte.png"), tr("Add Route"), this, SLOT(slotAddRte()));
     menu->addAction(QIcon("://icons/32x32/AddArea.png"), tr("Add Area"), this, SLOT(slotAddArea()));
+
     menu->addSeparator();
     menu->addAction(QIcon("://icons/32x32/Copy.png"), tr("Copy position"), this, SLOT(slotCopyPosition()));
 }
@@ -173,9 +175,9 @@ void CMouseNormal::mouseReleaseEvent(QMouseEvent *e)
                 const CScrOptUnclutter::item_t * scrOpt = screenUnclutter->selectItem(point);
                 if(scrOpt != 0)
                 {
-                    screenUnclutter->clear();
-
                     IGisItem * item = CGisWidget::self().getItemByKey(scrOpt->key);
+                    screenUnclutter->clear(); // CAUTION!! this will delete the object scrOpt is pointing to.
+                    scrOpt = 0;
                     if(item)
                     {
                         item->treeWidget()->collapseAll();
@@ -241,7 +243,7 @@ bool CMouseNormal::setScreenOption(const QPoint& pt, IGisItem * item)
     return !screenItemOption.isNull();
 }
 
-void CMouseNormal::draw(QPainter& p, bool needsRedraw, const QRect &rect)
+void CMouseNormal::draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect)
 {
     // no mouse interaction while gis thread is running
     if(gis->isRunning())
@@ -348,6 +350,15 @@ void CMouseNormal::slotAddTrk()
     canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis);
 }
 
+void CMouseNormal::slotAddRte()
+{
+    QPointF pt = point;
+    gis->convertPx2Rad(pt);
+
+    canvas->setMouseEditRte(pt);
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis);
+}
+
 void CMouseNormal::slotAddArea()
 {
     QPointF pt = point;
diff --git a/src/mouse/CMouseNormal.h b/src/mouse/CMouseNormal.h
index cff0a6f..1cdfbaa 100644
--- a/src/mouse/CMouseNormal.h
+++ b/src/mouse/CMouseNormal.h
@@ -38,7 +38,7 @@ public:
     CMouseNormal(CGisDraw * gis, CCanvas *canvas);
     virtual ~CMouseNormal();
 
-    void draw(QPainter& p,  bool needsRedraw,  const QRect &rect);
+    void draw(QPainter& p,  CCanvas::redraw_e needsRedraw,  const QRect &rect);
     void mousePressEvent(QMouseEvent * e);
     void mouseMoveEvent(QMouseEvent * e);
     void mouseReleaseEvent(QMouseEvent *e);
@@ -48,6 +48,7 @@ public:
 private slots:
     void slotAddWpt();
     void slotAddTrk();
+    void slotAddRte();
     void slotAddArea();
     void slotCopyPosition();
 
diff --git a/src/mouse/CMouseRangeTrk.cpp b/src/mouse/CMouseRangeTrk.cpp
index eb100a7..f999e50 100644
--- a/src/mouse/CMouseRangeTrk.cpp
+++ b/src/mouse/CMouseRangeTrk.cpp
@@ -63,7 +63,7 @@ CMouseRangeTrk::~CMouseRangeTrk()
     delete scrOptRange;
 }
 
-void CMouseRangeTrk::draw(QPainter& p,  bool, const QRect &)
+void CMouseRangeTrk::draw(QPainter& p,  CCanvas::redraw_e, const QRect &)
 {
     CGisItemTrk * trk = dynamic_cast<CGisItemTrk*>(CGisWidget::self().getItemByKey(key));
     if(trk)
@@ -121,7 +121,7 @@ void CMouseRangeTrk::mousePressEvent(QMouseEvent * e)
             if(trk != 0 && anchor != NOPOINTF)
             {
                 QPointF pt = trk->setMouseFocusByPoint(point, CGisItemTrk::eFocusMouseClick, "CMouseRangeTrk");
-                scrOptRange = new CScrOptRangeTrk(pt, trk, canvas);
+                scrOptRange = new CScrOptRangeTrk(pt, trk, this);
                 connect(scrOptRange->toolHidePoints, SIGNAL(clicked()), this, SLOT(slotHidePoints()));
                 connect(scrOptRange->toolShowPoints, SIGNAL(clicked()), this, SLOT(slotShowPoints()));
                 connect(scrOptRange->toolCopy, SIGNAL(clicked()), this, SLOT(slotCopy()));
diff --git a/src/mouse/CMouseRangeTrk.h b/src/mouse/CMouseRangeTrk.h
index 5afeb01..3693e58 100644
--- a/src/mouse/CMouseRangeTrk.h
+++ b/src/mouse/CMouseRangeTrk.h
@@ -35,7 +35,7 @@ public:
     CMouseRangeTrk(CGisItemTrk& trk, CGisDraw * gis, CCanvas * parent);
     virtual ~CMouseRangeTrk();
 
-    void draw(QPainter& p, bool, const QRect &);
+    void draw(QPainter& p, CCanvas::redraw_e, const QRect &);
     void mousePressEvent(QMouseEvent * e);
     void mouseMoveEvent(QMouseEvent * e);
     void mouseReleaseEvent(QMouseEvent *e);
diff --git a/src/mouse/CMouseWptBubble.cpp b/src/mouse/CMouseWptBubble.cpp
index 0eaf03d..8150e8b 100644
--- a/src/mouse/CMouseWptBubble.cpp
+++ b/src/mouse/CMouseWptBubble.cpp
@@ -34,7 +34,7 @@ CMouseWptBubble::~CMouseWptBubble()
 {
 }
 
-void CMouseWptBubble::draw(QPainter& p, bool needsRedraw, const QRect &rect)
+void CMouseWptBubble::draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect)
 {
 }
 
diff --git a/src/mouse/CMouseWptBubble.h b/src/mouse/CMouseWptBubble.h
index 8bbad05..26ade10 100644
--- a/src/mouse/CMouseWptBubble.h
+++ b/src/mouse/CMouseWptBubble.h
@@ -34,7 +34,7 @@ public:
     CMouseWptBubble(const IGisItem::key_t& key, CGisDraw * gis, CCanvas * parent);
     virtual ~CMouseWptBubble();
 
-    virtual void draw(QPainter& p, bool needsRedraw, const QRect &rect);
+    virtual void draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect);
     virtual void mousePressEvent(QMouseEvent * e);
     virtual void mouseMoveEvent(QMouseEvent * e);
     virtual void mouseReleaseEvent(QMouseEvent *e);
diff --git a/src/mouse/CScrOptPoint.cpp b/src/mouse/CScrOptPoint.cpp
index 9ce3849..59f6529 100644
--- a/src/mouse/CScrOptPoint.cpp
+++ b/src/mouse/CScrOptPoint.cpp
@@ -21,8 +21,8 @@
 
 #include <QtWidgets>
 
-CScrOptPoint::CScrOptPoint(const QPointF &point, QWidget *parent)
-    : IScrOpt(parent)
+CScrOptPoint::CScrOptPoint(const QPointF &point, IMouse * mouse)
+    : IScrOpt(mouse)
 {
     setupUi(this);
     adjustSize();
diff --git a/src/mouse/CScrOptPoint.h b/src/mouse/CScrOptPoint.h
index a77947f..0008d03 100644
--- a/src/mouse/CScrOptPoint.h
+++ b/src/mouse/CScrOptPoint.h
@@ -25,7 +25,7 @@
 class CScrOptPoint : public IScrOpt, public Ui::IScrOptPoint
 {
 public:
-    CScrOptPoint(const QPointF& point, QWidget * parent);
+    CScrOptPoint(const QPointF& point, IMouse *mouse);
     virtual ~CScrOptPoint();
 
     void draw(QPainter& p);
diff --git a/src/mouse/CScrOptRange.cpp b/src/mouse/CScrOptRange.cpp
index da38781..8f893a2 100644
--- a/src/mouse/CScrOptRange.cpp
+++ b/src/mouse/CScrOptRange.cpp
@@ -20,8 +20,8 @@
 
 #include <QtWidgets>
 
-CScrOptRange::CScrOptRange(const QPointF &point, QWidget *parent)
-    : IScrOpt(parent)
+CScrOptRange::CScrOptRange(const QPointF &point, IMouse *mouse)
+    : IScrOpt(mouse)
 {
     setupUi(this);
     adjustSize();
diff --git a/src/mouse/CScrOptRange.h b/src/mouse/CScrOptRange.h
index 245b20f..318fe4a 100644
--- a/src/mouse/CScrOptRange.h
+++ b/src/mouse/CScrOptRange.h
@@ -25,7 +25,7 @@
 class CScrOptRange : public IScrOpt, public Ui::IScrOptRange
 {
 public:
-    CScrOptRange(const QPointF& point, QWidget * parent);
+    CScrOptRange(const QPointF& point, IMouse *mouse);
     virtual ~CScrOptRange();
 
     void draw(QPainter& p);
diff --git a/src/mouse/CScrOptRangeTrk.cpp b/src/mouse/CScrOptRangeTrk.cpp
index 27574df..fc6e16d 100644
--- a/src/mouse/CScrOptRangeTrk.cpp
+++ b/src/mouse/CScrOptRangeTrk.cpp
@@ -22,9 +22,13 @@
 
 #include <QtWidgets>
 
-CScrOptRangeTrk::CScrOptRangeTrk(const QPointF &point, CGisItemTrk * trk, QWidget *parent)
-    : IScrOpt(parent)
+CScrOptRangeTrk::CScrOptRangeTrk(const QPointF &point, CGisItemTrk * trk, IMouse *mouse, QWidget *parent)
+    : IScrOpt(mouse)
 {
+    if(parent != 0)
+    {
+        setParent(parent);
+    }
     setupUi(this);
     label->setFont(CMainWindow::self().getMapFont());
     label->setText(trk->getInfoRange());
diff --git a/src/mouse/CScrOptRangeTrk.h b/src/mouse/CScrOptRangeTrk.h
index 337cb34..7ff1b94 100644
--- a/src/mouse/CScrOptRangeTrk.h
+++ b/src/mouse/CScrOptRangeTrk.h
@@ -27,7 +27,7 @@ class CGisItemTrk;
 class CScrOptRangeTrk : public IScrOpt, public Ui::IScrOptRangeTrk
 {
 public:
-    CScrOptRangeTrk(const QPointF& point, CGisItemTrk *trk, QWidget * parent);
+    CScrOptRangeTrk(const QPointF& point, CGisItemTrk *trk, IMouse *mouse, QWidget * parent = 0);
     virtual ~CScrOptRangeTrk();
 
     void draw(QPainter& p);
diff --git a/src/mouse/CScrOptUnclutter.cpp b/src/mouse/CScrOptUnclutter.cpp
index 55b4c92..a092cb8 100644
--- a/src/mouse/CScrOptUnclutter.cpp
+++ b/src/mouse/CScrOptUnclutter.cpp
@@ -91,8 +91,8 @@ const QPoint CScrOptUnclutter::positions[9][8] =
 };
 
 
-CScrOptUnclutter::CScrOptUnclutter(QWidget *parent)
-    : IScrOpt(parent)
+CScrOptUnclutter::CScrOptUnclutter(IMouse *mouse)
+    : IScrOpt(mouse)
     , doSpecialCursor(false)
 {
 }
@@ -117,7 +117,7 @@ void CScrOptUnclutter::mouseMoveEvent(QMouseEvent * e)
 
     foreach(const item_t &item, items)
     {
-        if(item.active.contains(mousePos))
+        if(item.active.contains(mousePos) || item.text.contains(mousePos))
         {
             if(!doSpecialCursor)
             {
@@ -162,7 +162,7 @@ const CScrOptUnclutter::item_t * CScrOptUnclutter::selectItem(const QPoint& poin
 {
     foreach(const item_t &item, items)
     {
-        if(item.active.contains(point))
+        if(item.active.contains(point) || item.text.contains(point))
         {
             return &item;
         }
diff --git a/src/mouse/CScrOptUnclutter.h b/src/mouse/CScrOptUnclutter.h
index fd8e17a..177519d 100644
--- a/src/mouse/CScrOptUnclutter.h
+++ b/src/mouse/CScrOptUnclutter.h
@@ -26,7 +26,7 @@
 class CScrOptUnclutter : public IScrOpt
 {
 public:
-    CScrOptUnclutter(QWidget *parent);
+    CScrOptUnclutter(IMouse *mouse);
     virtual ~CScrOptUnclutter();
 
     struct item_t
diff --git a/src/mouse/IMouse.h b/src/mouse/IMouse.h
index b217abd..5b08636 100644
--- a/src/mouse/IMouse.h
+++ b/src/mouse/IMouse.h
@@ -19,6 +19,8 @@
 #ifndef IMOUSE_H
 #define IMOUSE_H
 
+#include <canvas/CCanvas.h>
+
 #include <QCursor>
 #include <QObject>
 #include <QPointer>
@@ -42,7 +44,7 @@ public:
         eNormal
     };
 
-    virtual void draw(QPainter& p, bool needsRedraw, const QRect &rect) = 0;
+    virtual void draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect) = 0;
     virtual void mousePressEvent(QMouseEvent * e) = 0;
     virtual void mouseMoveEvent(QMouseEvent * e) = 0;
     virtual void mouseReleaseEvent(QMouseEvent *e) = 0;
@@ -59,18 +61,20 @@ public:
     {
         return cursor;
     }
+
     CCanvas * getCanvas()
     {
         return canvas;
     }
 
+    void panCanvas(const QPoint& pos);
+
     virtual void setMouseTracking(bool enabled);
 
 protected slots:
     virtual void slotPanCanvas();
 
 protected:
-    void panCanvas(const QPoint& pos);
     /// the functions mouse icon
     QCursor cursor;
 
diff --git a/src/mouse/IMouseEditLine.cpp b/src/mouse/IMouseEditLine.cpp
deleted file mode 100644
index 04dd51d..0000000
--- a/src/mouse/IMouseEditLine.cpp
+++ /dev/null
@@ -1,903 +0,0 @@
-/**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
-
-    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 3 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, see <http://www.gnu.org/licenses/>.
-
-**********************************************************************************************/
-
-#include "GeoMath.h"
-#include "canvas/CCanvas.h"
-#include "gis/CGisDraw.h"
-#include "gis/CGisWidget.h"
-#include "gis/IGisLine.h"
-#include "mouse/CScrOptEditLine.h"
-#include "mouse/CScrOptPoint.h"
-#include "mouse/CScrOptRange.h"
-#include "mouse/IMouseEditLine.h"
-#include "units/IUnit.h"
-
-
-#include <QtWidgets>
-
-IMouseEditLine::IMouseEditLine(const QPointF& point, CGisDraw * gis, CCanvas * parent)
-    : IMouse(gis, parent)
-    , state(eStateAddPointFwd)
-    , idxFocus(0)
-    , idxStart(NOIDX)
-    , idxStop(NOIDX)
-{
-    // create a single point line
-    coords1 << point;
-    line << point;
-    gis->convertRad2Px(line);
-
-    // start with adding trackpints imediately
-    slotAddPoint2();
-
-    // create permanent line edit on screen options
-    scrOptEditLine = new CScrOptEditLine(canvas);
-    scrOptEditLine->pushSaveOrig->hide(); // hide as there is no original
-    connect(scrOptEditLine->pushSaveNew, SIGNAL(clicked()), this, SLOT(slotCopyToNew()));
-    connect(scrOptEditLine->pushAbort, SIGNAL(clicked()), this, SLOT(slotAbort()));
-}
-
-IMouseEditLine::IMouseEditLine(IGisLine &src, CGisDraw *gis, CCanvas *parent)
-    : IMouse(gis, parent)
-    , state(eStateIdle)
-    , idxFocus(NOIDX)
-    , idxStart(NOIDX)
-    , idxStop(NOIDX)
-{
-    src.getPolylineFromData(coords1);
-    // calculate a pixel polyline from track coordinates
-    line = coords1;
-    gis->convertRad2Px(line);
-
-    // create permanent line edit on screen options
-    scrOptEditLine = new CScrOptEditLine(canvas);
-    connect(scrOptEditLine->pushSaveOrig, SIGNAL(clicked()), this, SLOT(slotCopyToOrig()));
-    connect(scrOptEditLine->pushSaveNew, SIGNAL(clicked()), this, SLOT(slotCopyToNew()));
-    connect(scrOptEditLine->pushAbort, SIGNAL(clicked()), this, SLOT(slotAbort()));
-}
-
-IMouseEditLine::~IMouseEditLine()
-{
-    delete scrOptPoint;
-    delete scrOptEditLine;
-    delete scrOptRange;
-}
-
-void IMouseEditLine::drawLine(const QPolygonF &l, QPainter& p)
-{
-    p.setPen(QPen(Qt::magenta, 11, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
-    p.drawPolyline(l);
-    p.setPen(QPen(Qt::white, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
-    p.drawPolyline(l);
-}
-
-void IMouseEditLine::drawPointOfFocus(QPainter& p)
-{
-    if(idxFocus < 0)
-    {
-        return;
-    }
-
-    const QPointF& pt = line[idxFocus];
-
-    p.setPen(Qt::darkBlue);
-    p.setBrush(QColor(255,255,255,200));
-    p.drawEllipse(pt, 6, 6);
-
-    QPixmap bullet("://icons/8x8/bullet_magenta.png");
-    p.drawPixmap(pt.x() - 3, pt.y() - 3, bullet);
-}
-
-void IMouseEditLine::drawBullets(const QPolygonF &l, QPainter& p)
-{
-    QPixmap bullet("://icons/8x8/bullet_magenta.png");
-    foreach(const QPointF &pt, l)
-    {
-        p.drawPixmap(pt.x() - 3, pt.y() - 3, bullet);
-    }
-}
-
-void IMouseEditLine::drawHighlight1(QPainter& p)
-{
-    if(idxStart < 0 || idxFocus < 0)
-    {
-        return;
-    }
-
-    int pos = idxFocus < idxStart ? idxFocus : idxStart;
-    int len = qAbs(idxFocus - idxStart) + 1;
-
-    QPolygonF highlight = line.mid(pos,len);
-
-    p.setPen(QPen(Qt::darkGreen, 11, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
-    p.drawPolyline(highlight);
-    p.setPen(QPen(Qt::green, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
-    p.drawPolyline(highlight);
-}
-
-void IMouseEditLine::drawHighlight2(QPainter& p)
-{
-    if(idxStart < 0 || idxStop < 0)
-    {
-        return;
-    }
-
-    int pos = idxStop < idxStart ? idxStop : idxStart;
-    int len = qAbs(idxStop - idxStart) + 1;
-
-    QPolygonF highlight = line.mid(pos,len);
-
-    p.setPen(QPen(Qt::darkGreen, 11, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
-    p.drawPolyline(highlight);
-    p.setPen(QPen(Qt::green, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
-    p.drawPolyline(highlight);
-}
-
-void IMouseEditLine::drawArrows(const QPolygonF &l, QPainter& p)
-{
-    QPointF arrow[4] =
-    {
-        QPointF( 24.0, 9.0),     //front
-        QPointF( 0.0, 0.0),      //upper tail
-        QPointF( 5.0, 9.0),      //mid tail
-        QPointF( 0.0, 19.0)      //lower tail
-    };
-
-    QPointF pt, pt1, ptt;
-
-    // draw direction arrows
-    bool start = true;
-    qreal heading;
-
-    //generate arrow pic on-the-fly
-    QImage arrow_pic(25,20, QImage::Format_ARGB32);
-    arrow_pic.fill( qRgba(0,0,0,0));
-    QPainter t_paint(&arrow_pic);
-    USE_ANTI_ALIASING(t_paint, true);
-    t_paint.setPen(QPen(Qt::white, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
-    t_paint.setBrush(Qt::magenta);
-    t_paint.drawPolygon(arrow, 4);
-    t_paint.end();
-
-    foreach(pt,l)
-    {
-        if(start)                // no arrow on  the first loop
-        {
-            start = false;
-        }
-        else
-        {
-            if((qAbs(pt.x() - pt1.x()) + qAbs(pt.y() - pt1.y())) < 7)
-            {
-                pt1 = pt;
-                continue;
-            }
-            // keep distance
-            if((qAbs(pt.x() - ptt.x()) + qAbs(pt.y() - ptt.y())) > 100)
-            {
-                if(0 != pt.x() - pt1.x() && (pt.y() - pt1.y()))
-                {
-                    heading = ( qAtan2((qreal)(pt.y() - pt1.y()), (qreal)(pt.x() - pt1.x())) * 180.) / M_PI;
-
-                    p.save();
-                    // draw arrow between bullets
-                    p.translate((pt.x() + pt1.x())/2,(pt.y() + pt1.y())/2);
-                    p.rotate(heading);
-                    p.drawImage(-13, -9, arrow_pic);
-                    p.restore();
-                    //remember last point
-                    ptt = pt;
-                }
-            }
-        }
-        pt1 = pt;
-    }
-}
-
-void IMouseEditLine::drawLeadLine(const QPolygonF &l, QPainter& p)
-{
-    p.setPen(QPen(QColor(255,255,0,100), 9, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
-    p.drawPolyline(l);
-}
-
-void IMouseEditLine::draw(QPainter& p, bool needsRedraw, const QRect &rect)
-{
-    if(needsRedraw)
-    {
-        line = coords1;
-        gis->convertRad2Px(line);
-        newLine = newCoords;
-        gis->convertRad2Px(newLine);
-    }
-
-    switch(state)
-    {
-    case eStateMoveMap:
-    case eStateIdle:
-    case eStatePointSelected:
-        drawLine(line, p);
-        drawArrows(line, p);
-        drawBullets(line, p);
-        drawPointOfFocus(p);
-        break;
-
-    case eStateSelectRange:
-        drawLine(line, p);
-        drawArrows(line, p);
-        drawHighlight1(p);
-        drawBullets(line, p);
-        drawPointOfFocus(p);
-        break;
-
-    case eStateRangeSelected:
-        drawLine(line, p);
-        drawArrows(line, p);
-        drawHighlight2(p);
-        drawBullets(line, p);
-        drawPointOfFocus(p);
-        break;
-
-    case eStateMovePoint:
-        drawLine(line, p);
-        drawArrows(line, p);
-        drawBullets(line, p);
-        drawPointOfFocus(p);
-        break;
-
-    case eStateAddPointFwd:
-    {
-        QPolygonF l;
-        if(subLinePixel.isEmpty())
-        {
-            l = line.mid(0, idxStart) + newLine + line.mid(idxStop, -1);
-        }
-        else
-        {
-            l = line.mid(0, idxStart) + newLine.mid(0, newLine.size() - 2) + subLinePixel + line.mid(idxStop, -1);
-        }
-        drawLeadLine(leadLinePixel, p);
-        drawLine(l, p);
-        drawArrows(l, p);
-        drawBullets(l, p);
-        break;
-    }
-
-    case eStateAddPointBwd:
-    {
-        QPolygonF l;
-        if(subLinePixel.isEmpty())
-        {
-            l = line.mid(0, idxStart + 1) + newLine + line.mid(idxStop + 1, -1);
-        }
-        else
-        {
-            l = line.mid(0, idxStart + 1) + subLinePixel + newLine.mid(2, -1) + line.mid(idxStop + 1, -1);
-        }
-        drawLeadLine(leadLinePixel, p);
-        drawLine(l, p);
-        drawArrows(l, p);
-        drawBullets(l, p);
-        break;
-    }
-
-    default:;
-    }
-
-
-    if(!scrOptPoint.isNull())
-    {
-        scrOptPoint->draw(p);
-    }
-    if(!scrOptRange.isNull())
-    {
-        scrOptRange->draw(p);
-    }
-}
-
-void IMouseEditLine::mousePressEvent(QMouseEvent * e)
-{
-    point  = e->pos();
-    if(e->button() == Qt::RightButton)
-    {
-        switch(state)
-        {
-        case eStateSelectRange:
-            cursor  = cursor1;
-            QApplication::restoreOverrideCursor();
-            QApplication::setOverrideCursor(cursor);
-        //break; no break fall thru
-
-        case eStateRangeSelected:
-            delete scrOptRange;
-
-            state       = eStateIdle;
-            idxFocus    = NOIDX;
-            idxStart    = NOIDX;
-            idxStop     = NOIDX;
-            break;
-
-        case eStateMovePoint:
-            state       = eStateIdle;
-            idxFocus    = NOIDX;
-            coords1     = save;
-            line        = coords1;
-            gis->convertRad2Px(line);
-            break;
-
-        case eStateAddPointBwd:
-        case eStateAddPointFwd:
-            if(QMessageBox::question(canvas, tr("Add points?"), tr("Add points to temporary line?"), QMessageBox::Yes|QMessageBox::No) == QMessageBox::Yes)
-            {
-                if(state == eStateAddPointBwd)
-                {
-                    // remove first point, which is the current moving point
-                    newCoords.pop_front();
-                    save = coords1.mid(0, idxStart + 1) + newCoords + coords1.mid(idxStop + 1, -1);
-                }
-
-                if(state == eStateAddPointFwd)
-                {
-                    // remove last point, which is the current moving point
-                    newCoords.pop_back();
-                    save = coords1.mid(0, idxStart) + newCoords + coords1.mid(idxStop, -1);
-                }
-
-
-                coords1 = save;
-                line    = coords1;
-                gis->convertRad2Px(line);
-            }
-
-            state       = eStateIdle;
-            idxFocus    = NOIDX;
-            idxStart    = NOIDX;
-            idxStop     = NOIDX;
-
-            cursor  = cursor1;
-            QApplication::restoreOverrideCursor();
-            QApplication::setOverrideCursor(cursor);
-            break;
-
-        default:
-            delete scrOptPoint;
-            delete scrOptRange;
-
-            state       = eStateIdle;
-            idxFocus    = NOIDX;
-            idxStart    = NOIDX;
-            idxStop     = NOIDX;
-        }
-    }
-    else if(e->button() == Qt::LeftButton)
-    {
-        switch(state)
-        {
-        case eStateIdle:
-        {
-            if(idxFocus >= 0)
-            {
-                scrOptPoint = new CScrOptPoint(line[idxFocus], canvas);
-
-                // set icon for add points towards start (backward/eStateAddPointBwd)
-                if(idxFocus == 0)
-                {
-                    // point is first of line
-                    qreal a1, a2;
-                    if(coords1.size() > 1)
-                    {
-                        const QPointF& pt1 = coords1[idxFocus];
-                        const QPointF& pt2 = coords1[idxFocus + 1];
-                        GPS_Math_Distance(pt1.x(), pt1.y(), pt2.x(), pt2.y(), a1, a2);
-                    }
-                    else
-                    {
-                        // only one point in the line
-                        a1 = 90;
-                    }
-
-                    QPixmap pix("://icons/32x32/ToTop.png");
-                    QTransform trans;
-                    trans.rotate(a1 + 180);
-
-                    pix = pix.transformed(trans, Qt::SmoothTransformation);
-
-                    scrOptPoint->toolAdd1->setIcon(pix);
-                }
-                else
-                {
-                    // point in the middle of the line
-                    qreal a1, a2;
-                    const QPointF& pt1 = coords1[idxFocus];
-                    const QPointF& pt2 = coords1[idxFocus - 1];
-                    GPS_Math_Distance(pt1.x(), pt1.y(), pt2.x(), pt2.y(), a1, a2);
-
-                    QPixmap pix("://icons/32x32/Up.png");
-                    QTransform trans;
-                    trans.rotate(a1);
-
-                    pix = pix.transformed(trans, Qt::SmoothTransformation);
-
-                    scrOptPoint->toolAdd1->setIcon(pix);
-                }
-
-                // set icon for add points towards end (forward/eStateAddPointFwd)
-                if(idxFocus == (line.size() - 1))
-                {
-                    // point is last of line
-                    qreal a1, a2;
-                    if(coords1.size() > 1)
-                    {
-                        const QPointF& pt1 = coords1[idxFocus];
-                        const QPointF& pt2 = coords1[idxFocus - 1];
-                        GPS_Math_Distance(pt1.x(), pt1.y(), pt2.x(), pt2.y(), a1, a2);
-                    }
-                    else
-                    {
-                        // only one point in the line
-                        a1 = -90;
-                    }
-
-                    QPixmap pix("://icons/32x32/ToTop.png");
-                    QTransform trans;
-                    trans.rotate(a1 + 180);
-
-                    pix = pix.transformed(trans, Qt::SmoothTransformation);
-
-                    scrOptPoint->toolAdd2->setIcon(pix);
-                }
-                else
-                {
-                    // point in the middle of the line
-                    qreal a1, a2;
-                    const QPointF& pt1 = coords1[idxFocus];
-                    const QPointF& pt2 = coords1[idxFocus + 1];
-                    GPS_Math_Distance(pt1.x(), pt1.y(), pt2.x(), pt2.y(), a1, a2);
-
-                    QPixmap pix("://icons/32x32/Up.png");
-                    QTransform trans;
-                    trans.rotate(a1);
-
-                    pix = pix.transformed(trans, Qt::SmoothTransformation);
-
-                    scrOptPoint->toolAdd2->setIcon(pix);
-                }
-
-                connect(scrOptPoint->toolDelete, SIGNAL(clicked()), this, SLOT(slotDeletePoint()));
-                connect(scrOptPoint->toolSelectRange, SIGNAL(clicked()), this, SLOT(slotSelectRange()));
-                connect(scrOptPoint->toolMove, SIGNAL(clicked()), this, SLOT(slotMovePoint()));
-                connect(scrOptPoint->toolAdd1, SIGNAL(clicked()), this, SLOT(slotAddPoint1()));
-                connect(scrOptPoint->toolAdd2, SIGNAL(clicked()), this, SLOT(slotAddPoint2()));
-
-                state = eStatePointSelected;
-            }
-            else
-            {
-                state = eStateMoveMap;
-            }
-            break;
-        }
-
-        case eStateSelectRange:
-        {
-            state   = eStateRangeSelected;
-            idxStop = idxFocus;
-
-            scrOptRange = new CScrOptRange(line[idxStop], canvas);
-            connect(scrOptRange->toolDelete, SIGNAL(clicked()), this, SLOT(slotDeleteRange()));
-
-            cursor  = cursor1;
-            QApplication::restoreOverrideCursor();
-            QApplication::setOverrideCursor(cursor);
-            break;
-        }
-
-        case eStateAddPointFwd:
-        {
-            if(!subLineCoord.isEmpty())
-            {
-                newLine.pop_back();
-                newLine.pop_back();
-                newLine     = newLine + subLinePixel;
-                newCoords.pop_back();
-                newCoords.pop_back();
-                newCoords   = newCoords + subLineCoord;
-
-                subLineCoord.clear();
-                subLinePixel.clear();
-            }
-            newLine.append(newLine.last());
-            newCoords.append(newCoords.last());
-            idxFocus = newLine.size() - 1;
-            break;
-        }
-
-        case eStateAddPointBwd:
-        {
-            if(!subLineCoord.isEmpty())
-            {
-                newLine.pop_front();
-                newLine.pop_front();
-                newLine = subLinePixel + newLine;
-                newCoords.pop_front();
-                newCoords.pop_front();
-                newCoords = subLineCoord + newCoords;
-
-                subLineCoord.clear();
-                subLinePixel.clear();
-            }
-
-            newLine.prepend(newLine.first());
-            newCoords.prepend(newCoords.first());
-            idxFocus = 0;
-            break;
-        }
-
-        default:
-        {
-            delete scrOptPoint;
-            delete scrOptRange;
-
-            state       = eStateIdle;
-            idxFocus    = NOIDX;
-            idxStart    = NOIDX;
-            idxStop     = NOIDX;
-        }
-        }
-    }
-    canvas->update();
-}
-
-void IMouseEditLine::mouseMoveEvent(QMouseEvent * e)
-{
-    point  = e->pos();
-
-    switch(state)
-    {
-    case eStateIdle:
-    {
-        int old = idxFocus;
-        idxFocus = getPointCloseBy(point);
-        if(old != idxFocus)
-        {
-            canvas->update();
-        }
-        break;
-    }
-
-    case eStateSelectRange:
-    {
-        if(!scrOptEditLine->rect().contains(point))
-        {
-            panCanvas(point);
-        }
-
-        int old = idxFocus;
-        idxFocus = getPointCloseBy(point);
-
-        if(idxFocus < 0)
-        {
-            idxFocus = old;
-        }
-
-        if(old != idxFocus)
-        {
-            canvas->update();
-        }
-        break;
-    }
-
-    case eStateMovePoint:
-    {
-        panCanvas(point);
-
-        QPointF pt      = point;
-        line[idxFocus]  = pt;
-        gis->convertPx2Rad(pt);
-        coords1[idxFocus]  = pt;
-
-        canvas->update();
-        break;
-    }
-
-    case eStateAddPointBwd:
-    case eStateAddPointFwd:
-    {
-        panCanvas(point);
-
-        QPointF pt          = point;
-        newLine[idxFocus]   = pt;
-        gis->convertPx2Rad(pt);
-        newCoords[idxFocus] = pt;
-
-
-        leadLineCoord.clear();
-        leadLinePixel.clear();
-        subLinePixel.clear();
-        subLineCoord.clear();
-
-
-        // find polyline to snap
-        QPointF px1;
-        QPointF px2;
-        if(newLine.size() > 1)
-        {
-            px1 = state == eStateAddPointFwd ? newLine[idxFocus - 1] : newLine[1];
-            px2 = newLine[idxFocus];
-        }
-
-        if(canvas->findPolylineCloseBy(px2, px2, 10, leadLineCoord))
-        {
-            leadLinePixel = leadLineCoord;
-            gis->convertRad2Px(leadLinePixel);
-
-            segment_t result;
-            GPS_Math_SubPolyline(px1, px2, 10, leadLinePixel, result);
-            result.apply(leadLineCoord, leadLinePixel, subLineCoord, subLinePixel, gis);
-
-            if(state == eStateAddPointBwd)
-            {
-                QPolygonF tmp1;
-                QPolygonF tmp2;
-                for(int i = 0; i < subLineCoord.size(); i++)
-                {
-                    tmp1.push_front(subLineCoord[i]);
-                    tmp2.push_front(subLinePixel[i]);
-                }
-                subLineCoord = tmp1;
-                subLinePixel = tmp2;
-            }
-        }
-
-
-        canvas->update();
-        break;
-    }
-
-    case eStateMoveMap:
-    {
-        if(point != lastPoint)
-        {
-            QPoint delta = point - lastPoint;
-            canvas->moveMap(delta);
-        }
-        break;
-    }
-
-    default:;
-    }
-
-    lastPoint = point;
-}
-
-void IMouseEditLine::mouseReleaseEvent(QMouseEvent *e)
-{
-    if(e->button() == Qt::LeftButton)
-    {
-        if(state == eStateMoveMap)
-        {
-            state = eStateIdle;
-        }
-    }
-}
-
-void IMouseEditLine::wheelEvent(QWheelEvent * e)
-{
-    canvas->update();
-}
-
-
-int IMouseEditLine::getPointCloseBy(const QPoint& screenPos)
-{
-    qint32 i    = 0;
-    qint32 idx  = NOIDX;
-    qint32 d    = NOINT;
-    foreach(const QPointF &point, line)
-    {
-        int tmp = (screenPos - point).manhattanLength();
-        if(tmp < d)
-        {
-            idx = i;
-            d   = tmp;
-        }
-        i++;
-    }
-
-    if(d > 40)
-    {
-        idx = NOIDX;
-    }
-
-    return idx;
-}
-
-void IMouseEditLine::slotDeletePoint()
-{
-    if(idxFocus < 0)
-    {
-        return;
-    }
-    scrOptPoint->deleteLater();
-
-    coords1.remove(idxFocus);
-    line.remove(idxFocus);
-
-    idxFocus    = NOIDX;
-    state       = eStateIdle;
-
-    canvas->update();
-}
-
-void IMouseEditLine::slotSelectRange()
-{
-    if(idxFocus < 0)
-    {
-        return;
-    }
-    scrOptPoint->deleteLater();
-
-    idxStart    = idxFocus;
-    state       = eStateSelectRange;
-
-    cursor  = QCursor(QPixmap(":/cursors/cursorSelectRange.png"),0,0);
-    QApplication::restoreOverrideCursor();
-    QApplication::setOverrideCursor(cursor);
-}
-
-void IMouseEditLine::slotDeleteRange()
-{
-    if(idxStart < 0 || idxStop < 0)
-    {
-        return;
-    }
-    scrOptRange->deleteLater();
-
-    int len = qAbs(idxStop - idxStart);
-    int idx = idxStart < idxStop ? idxStart : idxStop;
-
-    coords1.remove(idx+1,len-1);
-    line = coords1;
-    gis->convertRad2Px(line);
-
-    state = eStateIdle;
-    idxFocus    = NOIDX;
-    idxStart    = NOIDX;
-    idxStop     = NOIDX;
-
-    canvas->update();
-}
-
-void IMouseEditLine::slotMovePoint()
-{
-    if(idxFocus < 0)
-    {
-        return;
-    }
-    scrOptPoint->deleteLater();
-
-    save    = coords1;
-    state   = eStateMovePoint;
-
-    canvas->update();
-}
-
-void IMouseEditLine::slotAddPoint1()
-{
-    if(idxFocus < 0)
-    {
-        return;
-    }
-    scrOptPoint->deleteLater();
-
-    newCoords.clear();
-    newLine.clear();
-    /*
-        Adding points will work completely on newLine and newCoords until the
-        line segment is taken over or dumped. The current point of focus is
-        added twice. The first time as fixed starting point of the tmeporary
-        newLine. And the second time as initial point to be moved by the mouse.
-
-     */
-    newCoords << coords1[idxFocus]  << coords1[idxFocus];
-    newLine << line[idxFocus]     << line[idxFocus];
-
-    // mark gap to insert points
-    idxStart = idxFocus - 1;
-    idxStop  = idxFocus;
-
-    // set focus to first point in newLine
-    idxFocus = 0;
-
-    state   = eStateAddPointBwd;
-    cursor  = QCursor(QPixmap(":/cursors/cursorAdd.png"),0,0);
-    QApplication::restoreOverrideCursor();
-    QApplication::setOverrideCursor(cursor);
-
-    canvas->update();
-}
-
-void IMouseEditLine::slotAddPoint2()
-{
-    if(idxFocus < 0)
-    {
-        return;
-    }
-
-    if(!scrOptPoint.isNull())
-    {
-        scrOptPoint->deleteLater();
-    }
-
-
-    newCoords.clear();
-    newLine.clear();
-    /*
-        Adding points will work completely on newLine and newCoords until the
-        line segment is taken over or dumped. The current point of focus is
-        added twice. The first time as fixed starting point of the tmeporary
-        newLine. And the second time as initial point to be moved by the mouse.
-
-     */
-    newCoords << coords1[idxFocus]  << coords1[idxFocus];
-    newLine << line[idxFocus]     << line[idxFocus];
-
-    // mark gap to insert points
-    idxStart = idxFocus;
-    idxStop  = idxFocus + 1;
-
-    // set focus to first point in newLine
-    idxFocus = 1;
-
-    state   = eStateAddPointFwd;
-    cursor  = QCursor(QPixmap(":/cursors/cursorAdd.png"),0,0);
-    QApplication::restoreOverrideCursor();
-    QApplication::setOverrideCursor(cursor);
-
-    canvas->update();
-}
-
-
-void IMouseEditLine::slotAbort()
-{
-    canvas->resetMouse();
-    canvas->update();
-}
-
-void IMouseEditLine::slotCopyToOrig()
-{
-    if(coords1.size() < 2)
-    {
-        return;
-    }
-
-    int res = QMessageBox::warning(canvas, tr("Warning!"), tr("This will replace all data of the orignal by a simple line of coordinates. All other data will be lost permanently."), QMessageBox::Ok|QMessageBox::Abort, QMessageBox::Ok);
-
-    if(res != QMessageBox::Ok)
-    {
-        return;
-    }
-
-    IGisLine * l = getGisLine();
-    if(l != 0)
-    {
-        l->setDataFromPolyline(coords1);
-    }
-    canvas->resetMouse();
-    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis);
-}
-
-
diff --git a/src/mouse/IScrOpt.cpp b/src/mouse/IScrOpt.cpp
index d0bc7ab..0704522 100644
--- a/src/mouse/IScrOpt.cpp
+++ b/src/mouse/IScrOpt.cpp
@@ -17,18 +17,25 @@
 **********************************************************************************************/
 
 #include "canvas/CCanvas.h"
+#include "mouse/IMouse.h"
 #include "mouse/IScrOpt.h"
 #include "units/IUnit.h"
 #include <QtWidgets>
 
 
-IScrOpt::IScrOpt(QWidget *parent)
-    : QWidget(parent)
+IScrOpt::IScrOpt(IMouse *mouse)
+    : QWidget(mouse->getCanvas())
+    , mouse(mouse)
 {
+    setFocusPolicy(Qt::WheelFocus);
 }
 
 IScrOpt::~IScrOpt()
 {
+    if(!mouse.isNull() && hasFocus())
+    {
+        QApplication::changeOverrideCursor(*mouse);
+    }
 }
 
 
@@ -37,6 +44,23 @@ void IScrOpt::mouseMoveEvent(QMouseEvent * e)
     mousePos = e->pos();
 }
 
+void IScrOpt::enterEvent(QEvent * e)
+{
+    QWidget::enterEvent(e);
+    QApplication::changeOverrideCursor(Qt::ArrowCursor);
+}
+
+
+void IScrOpt::leaveEvent(QEvent * e)
+{
+    QWidget::leaveEvent(e);
+    if(!mouse.isNull())
+    {
+        QApplication::changeOverrideCursor(*mouse);
+    }
+}
+
+
 void IScrOpt::drawBubble1(const QPointF& pt, QPainter& p)
 {
     QRectF r = rect();
diff --git a/src/mouse/IScrOpt.h b/src/mouse/IScrOpt.h
index 664a76d..edbbf01 100644
--- a/src/mouse/IScrOpt.h
+++ b/src/mouse/IScrOpt.h
@@ -20,17 +20,19 @@
 #define ISCROPT_H
 
 #include <QPixmap>
+#include <QPointer>
 #include <QRect>
 #include <QWidget>
 
 class QMouseEvent;
+class IMouse;
 
 #define SCR_OPT_OFFSET 15
 
 class IScrOpt : public QWidget
 {
 public:
-    IScrOpt(QWidget * parent);
+    IScrOpt(IMouse *mouse);
     virtual ~IScrOpt();
 
 
@@ -44,15 +46,19 @@ public:
     }
 
     virtual void draw(QPainter& p) = 0;
-    virtual void mouseMoveEvent(QMouseEvent *);
+    void mouseMoveEvent(QMouseEvent *);
 
 protected:
+    void enterEvent(QEvent * e);
+    void leaveEvent(QEvent * e);
+
     void drawBubble1(const QPointF &pt, QPainter& p);
     void drawBubble2(const QPointF &pt, QPainter& p);
 
     QPoint origin;
-
     QPoint mousePos;
+
+    QPointer<IMouse> mouse;
 };
 
 #endif //ISCROPT_H
diff --git a/src/mouse/IScrOptEditLine.ui b/src/mouse/IScrOptEditLine.ui
deleted file mode 100644
index cd0b1ac..0000000
--- a/src/mouse/IScrOptEditLine.ui
+++ /dev/null
@@ -1,97 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>IScrOptEditLine</class>
- <widget class="QWidget" name="IScrOptEditLine">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>368</width>
-    <height>100</height>
-   </rect>
-  </property>
-  <property name="minimumSize">
-   <size>
-    <width>0</width>
-    <height>100</height>
-   </size>
-  </property>
-  <property name="maximumSize">
-   <size>
-    <width>16777215</width>
-    <height>100</height>
-   </size>
-  </property>
-  <property name="windowTitle">
-   <string>Form</string>
-  </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <item>
-    <layout class="QHBoxLayout" name="horizontalLayout">
-     <item>
-      <spacer name="horizontalSpacer_2">
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-       <property name="sizeHint" stdset="0">
-        <size>
-         <width>40</width>
-         <height>20</height>
-        </size>
-       </property>
-      </spacer>
-     </item>
-     <item>
-      <widget class="QPushButton" name="pushSaveOrig">
-       <property name="text">
-        <string>Save to orignal</string>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QPushButton" name="pushSaveNew">
-       <property name="text">
-        <string>Save as new</string>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QPushButton" name="pushAbort">
-       <property name="text">
-        <string>Abort</string>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <spacer name="horizontalSpacer">
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-       <property name="sizeHint" stdset="0">
-        <size>
-         <width>40</width>
-         <height>20</height>
-        </size>
-       </property>
-      </spacer>
-     </item>
-    </layout>
-   </item>
-   <item>
-    <spacer name="verticalSpacer">
-     <property name="orientation">
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>20</width>
-       <height>45</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-  </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/mouse/line/CLineOpAddPoint.cpp b/src/mouse/line/CLineOpAddPoint.cpp
new file mode 100644
index 0000000..e9c16e2
--- /dev/null
+++ b/src/mouse/line/CLineOpAddPoint.cpp
@@ -0,0 +1,243 @@
+/**********************************************************************************************
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+**********************************************************************************************/
+
+#include "canvas/CCanvas.h"
+#include "gis/CGisDraw.h"
+#include "mouse/line/CLineOpAddPoint.h"
+#include "mouse/line/IMouseEditLine.h"
+
+#include <QtWidgets>
+
+CLineOpAddPoint::CLineOpAddPoint(SGisLine& points, CGisDraw *gis, CCanvas * canvas, IMouseEditLine * parent)
+    : ILineOp(points, gis, canvas, parent)
+    , addPoint(false)
+    , isPoint(false)
+{
+    cursor = QCursor(QPixmap(":/cursors/cursorAdd.png"),0,0);
+}
+
+CLineOpAddPoint::~CLineOpAddPoint()
+{
+}
+
+void CLineOpAddPoint::append()
+{
+    // this is called on construction when creating a complete new line
+    // A new point is appended to what ever line already exists,
+    // and add point mode is enetred imediately.
+    idxFocus = points.size();
+    points.insert(idxFocus, IGisLine::point_t(points.last()));
+    addPoint = true;
+    isPoint  = true;
+    parentHandler->setCanvasPanning(addPoint);
+}
+
+void CLineOpAddPoint::mousePressEventEx(QMouseEvent * e)
+{
+    if(e->button() == Qt::LeftButton)
+    {
+        if(addPoint)
+        {
+            // drop the new point at current position
+            // update subpoints of previous and this point
+            slotTimeoutRouting();
+
+            // if isPoint is true the line has been appended/prepended
+            // in this case go on with adding another point
+            if(isPoint)
+            {
+                if(idxFocus == (points.size() - 1))
+                {
+                    idxFocus++;
+                }
+
+                // store current state of line to undo/redo history
+                parentHandler->storeToHistory(points);
+
+                QPointF coord = e->pos();
+                gis->convertPx2Rad(coord);
+                points.insert(idxFocus, IGisLine::point_t(coord));
+            }
+            else
+            {
+                // store current state of line to undo/redo history
+                parentHandler->storeToHistory(points);
+                // terminate operation if the new point was inbetween a line segment.
+                addPoint = false;
+                idxFocus = NOIDX;
+            }
+        }
+        else if(isPoint)
+        {
+            // as isPoint is set, add a new point either at the start or end of the line
+            if(idxFocus == (points.size() - 1))
+            {
+                idxFocus++;
+            }
+
+            QPointF coord = e->pos();
+            gis->convertPx2Rad(coord);
+            points.insert(idxFocus, IGisLine::point_t(coord));
+
+            addPoint = true;
+        }
+        else
+        {
+            // clear current line segment
+            points[idxFocus].subpts.clear();
+
+            // add a new point to line segment
+            QPointF coord = e->pos();
+            gis->convertPx2Rad(coord);
+
+            idxFocus++;
+            points.insert(idxFocus, IGisLine::point_t(coord));
+
+            addPoint = true;
+        }
+    }
+    else if(e->button() == Qt::RightButton)
+    {
+        if(addPoint)
+        {
+            // cancel action and restore last state of line
+            cancelDelayedRouting();
+            parentHandler->restoreFromHistory(points);
+
+            addPoint = false;
+            idxFocus = NOIDX;
+        }
+        idxFocus = NOIDX;
+    }
+
+    parentHandler->setCanvasPanning(addPoint);
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
+}
+
+void CLineOpAddPoint::mouseMoveEventEx(QMouseEvent * e)
+{
+    if(addPoint)
+    {
+        QPointF coord = e->pos();
+        gis->convertPx2Rad(coord);
+
+        IGisLine::point_t& pt = points[idxFocus];
+        // update position of point
+        pt.coord = coord;
+
+        // clear subpoints, as they have to be recalulated
+        // by the routing, if any
+        pt.subpts.clear();
+        if(idxFocus > 0)
+        {
+            points[idxFocus - 1].subpts.clear();
+        }
+
+        // retrigger delayed routing
+        startDelayedRouting();
+    }
+    else
+    {
+        isPoint  = false;
+        // find line segment close to cursor
+        idxFocus = isCloseToLine(e->pos());
+        // if none is found try to find point
+        if(idxFocus == NOIDX)
+        {
+            // if no line segment is found but a point
+            // it is either first or the last point in the line
+            idxFocus = isCloseTo(e->pos());
+            isPoint  = true;
+        }
+    }
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
+}
+
+void CLineOpAddPoint::canvasPanned(QPointF pos)
+{
+    if(addPoint)
+    {
+        gis->convertPx2Rad(pos);
+        points[idxFocus].coord = pos;
+    }
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
+}
+
+
+void CLineOpAddPoint::drawFg(QPainter& p)
+{
+    if(idxFocus == NOIDX)
+    {
+        return;
+    }
+
+    if(addPoint)
+    {
+        const IGisLine::point_t& pt = points[idxFocus];
+        drawSinglePointSmall(pt.pixel, p);
+    }
+    else if(isPoint)
+    {
+        const IGisLine::point_t& pt = points[idxFocus];
+        drawSinglePointLarge(pt.pixel, p);
+    }
+    else if(idxFocus < (points.size() - 1))
+    {
+        QPolygonF line;
+        const IGisLine::point_t& pt1 = points[idxFocus];
+        const IGisLine::point_t& pt2 = points[idxFocus + 1];
+
+        if(pt1.subpts.isEmpty())
+        {
+            line << pt1.pixel << pt2.pixel;
+        }
+        else
+        {
+            line << pt1.pixel;
+            foreach(const IGisLine::subpt_t& pt, pt1.subpts)
+            {
+                line << pt.pixel;
+            }
+            line << pt2.pixel;
+        }
+
+        p.setPen(penBgPoint);
+        p.setBrush(brushBgPoint);
+
+        rectPoint.moveCenter(pt1.pixel.toPoint());
+        p.drawRect(rectPoint);
+        rectPoint.moveCenter(pt2.pixel.toPoint());
+        p.drawRect(rectPoint);
+
+        p.setPen(QPen(Qt::white, 7, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
+        p.drawPolyline(line);
+
+
+        p.setPen(penFgPoint);
+        p.setBrush(brushFgPoint);
+
+        rectPoint.moveCenter(pt1.pixel.toPoint());
+        p.drawRect(rectPoint);
+        rectPoint.moveCenter(pt2.pixel.toPoint());
+        p.drawRect(rectPoint);
+
+        p.setPen(QPen(Qt::red, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
+        p.drawPolyline(line);
+    }
+}
+
diff --git a/src/qlgt/CImportDatabase.h b/src/mouse/line/CLineOpAddPoint.h
similarity index 59%
copy from src/qlgt/CImportDatabase.h
copy to src/mouse/line/CLineOpAddPoint.h
index 72b034f..df96928 100644
--- a/src/qlgt/CImportDatabase.h
+++ b/src/mouse/line/CLineOpAddPoint.h
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -16,34 +16,33 @@
 
 **********************************************************************************************/
 
-#ifndef CIMPORTDATABASE_H
-#define CIMPORTDATABASE_H
+#ifndef CLINEOPADDPOINT_H
+#define CLINEOPADDPOINT_H
 
-#include "ui_IImportDatabase.h"
-#include <QPointer>
-#include <QWidget>
+#include "mouse/line/ILineOp.h"
 
-class CQlgtDb;
-
-class CImportDatabase : public QWidget, private Ui::IImportDatabase
+class CLineOpAddPoint : public ILineOp
 {
-    Q_OBJECT
 public:
-    CImportDatabase(QWidget * parent);
-    virtual ~CImportDatabase();
+    CLineOpAddPoint(SGisLine& points, CGisDraw *gis, CCanvas *canvas, IMouseEditLine *parent);
+    virtual ~CLineOpAddPoint();
+
+    void mousePressEventEx(QMouseEvent * e);
+    void mouseMoveEventEx(QMouseEvent * e);
+    void mouseReleaseEventEx(QMouseEvent *e)
+    {
+    }
 
-    void stdOut(const QString& str);
-    void stdErr(const QString& str);
+    void drawFg(QPainter& p);
 
-private slots:
-    void slotSelectSource();
-    void slotSelectTarget();
-    void slotStart();
+    void canvasPanned(QPointF pos);
 
+    void append();
 
 private:
-    QPointer<CQlgtDb> dbQlgt;
+    bool addPoint;
+    bool isPoint;
 };
 
-#endif //CIMPORTDATABASE_H
+#endif //CLINEOPADDPOINT_H
 
diff --git a/src/mouse/line/CLineOpDeletePoint.cpp b/src/mouse/line/CLineOpDeletePoint.cpp
new file mode 100644
index 0000000..4cb5b76
--- /dev/null
+++ b/src/mouse/line/CLineOpDeletePoint.cpp
@@ -0,0 +1,73 @@
+/**********************************************************************************************
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+**********************************************************************************************/
+
+#include "canvas/CCanvas.h"
+#include "mouse/line/CLineOpDeletePoint.h"
+#include "mouse/line/IMouseEditLine.h"
+#include "units/IUnit.h"
+
+#include <QtWidgets>
+
+CLineOpDeletePoint::CLineOpDeletePoint(SGisLine& points, CGisDraw *gis, CCanvas * canvas, IMouseEditLine * parent)
+    : ILineOp(points, gis, canvas, parent)
+{
+    cursor  = QCursor(QPixmap(":/cursors/cursorDelete.png"),0,0);
+}
+
+CLineOpDeletePoint::~CLineOpDeletePoint()
+{
+}
+
+void CLineOpDeletePoint::mouseMoveEventEx(QMouseEvent * e)
+{
+    idxFocus = isCloseTo(e->pos());
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
+}
+
+void CLineOpDeletePoint::mouseReleaseEventEx(QMouseEvent *e)
+{
+    if(!mapDidMove && idxFocus != NOIDX)
+    {
+        if(idxFocus > 0)
+        {
+            points[idxFocus - 1].subpts.clear();
+        }
+
+        points.remove(idxFocus--);
+        updateLeadLines(idxFocus);
+
+        slotTimeoutRouting();
+
+        // store to undo/redo history
+        parentHandler->storeToHistory(points);
+    }
+    idxFocus    = NOIDX;
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
+}
+
+
+void CLineOpDeletePoint::drawFg(QPainter& p)
+{
+    if(idxFocus == NOIDX)
+    {
+        return;
+    }
+
+    const IGisLine::point_t& pt = points[idxFocus];
+    drawSinglePointLarge(pt.pixel, p);
+}
diff --git a/src/mouse/CScrOptEditLine.h b/src/mouse/line/CLineOpDeletePoint.h
similarity index 62%
copy from src/mouse/CScrOptEditLine.h
copy to src/mouse/line/CLineOpDeletePoint.h
index 4325729..0083f26 100644
--- a/src/mouse/CScrOptEditLine.h
+++ b/src/mouse/line/CLineOpDeletePoint.h
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -16,23 +16,27 @@
 
 **********************************************************************************************/
 
-#ifndef CSCROPTEDITLINE_H
-#define CSCROPTEDITLINE_H
+#ifndef CLINEOPDELETEPOINT_H
+#define CLINEOPDELETEPOINT_H
 
-#include "mouse/IScrOpt.h"
-#include "ui_IScrOptEditLine.h"
+#include "mouse/line/ILineOp.h"
 
-class CScrOptEditLine : public IScrOpt, public Ui::IScrOptEditLine
+class CLineOpDeletePoint : public ILineOp
 {
-    Q_OBJECT
 public:
-    CScrOptEditLine(QWidget * parent);
-    virtual ~CScrOptEditLine();
+    CLineOpDeletePoint(SGisLine& points, CGisDraw *gis, CCanvas *canvas, IMouseEditLine *parent);
+    virtual ~CLineOpDeletePoint();
 
-    void draw(QPainter& p)
+    void mousePressEventEx(QMouseEvent * e)
     {
     }
+    void mouseMoveEventEx(QMouseEvent * e);
+    void mouseReleaseEventEx(QMouseEvent *e);
+
+    void drawFg(QPainter& p);
+
+private:
 };
 
-#endif //CSCROPTEDITLINE_H
+#endif //CLINEOPDELETEPOINT_H
 
diff --git a/src/mouse/line/CLineOpMovePoint.cpp b/src/mouse/line/CLineOpMovePoint.cpp
new file mode 100644
index 0000000..3f3f108
--- /dev/null
+++ b/src/mouse/line/CLineOpMovePoint.cpp
@@ -0,0 +1,150 @@
+/**********************************************************************************************
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+**********************************************************************************************/
+
+#include "canvas/CCanvas.h"
+#include "gis/CGisDraw.h"
+#include "mouse/line/CLineOpMovePoint.h"
+#include "mouse/line/IMouseEditLine.h"
+#include "units/IUnit.h"
+
+#include <QtWidgets>
+
+CLineOpMovePoint::CLineOpMovePoint(SGisLine &points, CGisDraw *gis, CCanvas * canvas, IMouseEditLine *parent)
+    : ILineOp(points, gis, canvas, parent)
+    , movePoint(false)
+{
+    cursor = QCursor(QPixmap(":/cursors/cursorMovePoint.png"),0,0);
+}
+
+CLineOpMovePoint::~CLineOpMovePoint()
+{
+}
+
+void CLineOpMovePoint::mousePressEventEx(QMouseEvent * e)
+{
+    if(e->button() == Qt::LeftButton)
+    {
+        if(movePoint)
+        {
+            // update subpoints by triggering the routing, if any.
+            slotTimeoutRouting();
+            // terminate moving the point
+            movePoint = false;
+            // store new state of line to undo/redo history
+            parentHandler->storeToHistory(points);
+        }
+        else
+        {
+            QPointF coord = e->pos();
+            gis->convertPx2Rad(coord);
+
+            // start moving the point
+            IGisLine::point_t& pt = points[idxFocus];
+            pt.coord = coord;
+            // clear the subpoints from this point to the next
+            pt.subpts.clear();
+
+
+            // clear the subpoints from the previous point to this point
+            if(idxFocus != 0)
+            {
+                points[idxFocus - 1].subpts.clear();
+            }
+
+            movePoint = true;
+        }
+    }
+    else if(e->button() == Qt::RightButton)
+    {
+        if(movePoint)
+        {
+            // cancel action and restore last state of line
+            cancelDelayedRouting();
+            parentHandler->restoreFromHistory(points);
+
+            movePoint = false;
+            idxFocus  = NOIDX;
+        }
+    }
+
+    // switch on map panning if move operation is in progress
+    parentHandler->setCanvasPanning(movePoint);
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
+}
+
+void CLineOpMovePoint::mouseMoveEventEx(QMouseEvent * e)
+{
+    if(movePoint)
+    {
+        QPointF coord = e->pos();
+        gis->convertPx2Rad(coord);
+
+        IGisLine::point_t& pt = points[idxFocus];
+
+        // update position of point
+        pt.coord = coord;
+
+        // clear subpoints, as they have to be recalulated
+        // by the routing, if any
+        pt.subpts.clear();
+        if(idxFocus > 0)
+        {
+            points[idxFocus - 1].subpts.clear();
+        }
+
+        // retrigger delayed routing
+        startDelayedRouting();
+    }
+    else
+    {
+        // no point selected yet, find point to highlight
+        idxFocus = isCloseTo(e->pos());
+    }
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
+}
+
+void CLineOpMovePoint::canvasPanned(QPointF pos)
+{
+    // update point position after canvas/map panning
+    if(movePoint)
+    {
+        gis->convertPx2Rad(pos);
+        points[idxFocus].coord = pos;
+    }
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
+}
+
+void CLineOpMovePoint::drawFg(QPainter& p)
+{
+    if(idxFocus == NOIDX)
+    {
+        return;
+    }
+
+    const IGisLine::point_t& pt = points[idxFocus];
+    if(movePoint)
+    {
+        drawSinglePointSmall(pt.pixel, p);
+    }
+    else
+    {
+        drawSinglePointLarge(pt.pixel, p);
+    }
+}
+
+
diff --git a/src/qlgt/CImportDatabase.h b/src/mouse/line/CLineOpMovePoint.h
similarity index 60%
copy from src/qlgt/CImportDatabase.h
copy to src/mouse/line/CLineOpMovePoint.h
index 72b034f..6edab86 100644
--- a/src/qlgt/CImportDatabase.h
+++ b/src/mouse/line/CLineOpMovePoint.h
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -16,34 +16,30 @@
 
 **********************************************************************************************/
 
-#ifndef CIMPORTDATABASE_H
-#define CIMPORTDATABASE_H
+#ifndef CLINEOPMOVEPOINT_H
+#define CLINEOPMOVEPOINT_H
 
-#include "ui_IImportDatabase.h"
-#include <QPointer>
-#include <QWidget>
+#include "mouse/line/ILineOp.h"
 
-class CQlgtDb;
-
-class CImportDatabase : public QWidget, private Ui::IImportDatabase
+class CLineOpMovePoint : public ILineOp
 {
-    Q_OBJECT
 public:
-    CImportDatabase(QWidget * parent);
-    virtual ~CImportDatabase();
+    CLineOpMovePoint(SGisLine& points, CGisDraw *gis, CCanvas *canvas, IMouseEditLine *parent);
+    virtual ~CLineOpMovePoint();
 
-    void stdOut(const QString& str);
-    void stdErr(const QString& str);
+    void mousePressEventEx(QMouseEvent * e);
+    void mouseMoveEventEx(QMouseEvent * e);
+    void mouseReleaseEventEx(QMouseEvent * e)
+    {
+    }
 
-private slots:
-    void slotSelectSource();
-    void slotSelectTarget();
-    void slotStart();
+    void drawFg(QPainter& p);
 
+    void canvasPanned(QPointF pos);
 
 private:
-    QPointer<CQlgtDb> dbQlgt;
+    bool movePoint;
 };
 
-#endif //CIMPORTDATABASE_H
+#endif //CLINEOPMOVEPOINT_H
 
diff --git a/src/mouse/line/CLineOpSelectRange.cpp b/src/mouse/line/CLineOpSelectRange.cpp
new file mode 100644
index 0000000..2f22444
--- /dev/null
+++ b/src/mouse/line/CLineOpSelectRange.cpp
@@ -0,0 +1,211 @@
+/**********************************************************************************************
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+**********************************************************************************************/
+
+#include "canvas/CCanvas.h"
+#include "mouse/line/CLineOpSelectRange.h"
+#include "mouse/line/CScrOptRangeLine.h"
+#include "mouse/line/IMouseEditLine.h"
+
+#include <QtWidgets>
+
+CLineOpSelectRange::CLineOpSelectRange(SGisLine& points, CGisDraw *gis, CCanvas * canvas, IMouseEditLine * parent)
+    : ILineOp(points, gis, canvas, parent)
+    , state(eStateIdle)
+    , idx2nd(NOIDX)
+{
+    cursor = QCursor(QPixmap(":/cursors/cursorSelectRange.png"),0,0);
+}
+
+CLineOpSelectRange::~CLineOpSelectRange()
+{
+}
+
+void CLineOpSelectRange::mousePressEventEx(QMouseEvent * e)
+{
+    if(e->button() == Qt::LeftButton)
+    {
+        switch(state)
+        {
+        case eStateIdle:
+        {
+            if(idxFocus != NOIDX)
+            {
+                state = eState1st;
+            }
+            break;
+        }
+
+        case eState1st:
+        {
+            qint32 d = qAbs(idxFocus - idx2nd);
+            if(d < 1)
+            {
+                resetState();
+                return;
+            }
+
+            scrOptRangeLine = new CScrOptRangeLine(points[idx2nd].pixel, parentHandler, canvas);
+            connect(scrOptRangeLine->toolDelete, SIGNAL(clicked()), this, SLOT(slotDelete()));
+            connect(scrOptRangeLine->toolCalcRoute, SIGNAL(clicked()), this, SLOT(slotCalc()));
+
+            if(d < 2)
+            {
+                scrOptRangeLine->toolDelete->setEnabled(false);
+            }
+
+            state = eState2nd;
+            break;
+        }
+        }
+    }
+    else if(e->button() == Qt::RightButton)
+    {
+        resetState();
+    }
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
+}
+void CLineOpSelectRange::mouseMoveEventEx(QMouseEvent * e)
+{
+    switch(state)
+    {
+    case eStateIdle:
+    {
+        // no point selected yet, find point to highlight
+        idxFocus = isCloseTo(e->pos());
+        break;
+    }
+
+    case eState1st:
+    {
+        idx2nd = isCloseTo(e->pos());
+        if(idx2nd == NOIDX)
+        {
+            idx2nd = isCloseToLine(e->pos());
+            if((idx2nd != NOIDX) && ((idx2nd + 1) < points.size()))
+            {
+                idx2nd++;
+            }
+        }
+        break;
+    }
+    }
+
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
+}
+
+void CLineOpSelectRange::drawFg(QPainter& p)
+{
+    if(idxFocus == NOIDX)
+    {
+        return;
+    }
+
+    switch(state)
+    {
+    case eStateIdle:
+    {
+        const IGisLine::point_t& pt = points[idxFocus];
+        drawSinglePointLarge(pt.pixel, p);
+        break;
+    }
+
+    case eState2nd:
+    {
+        if(!scrOptRangeLine.isNull())
+        {
+            scrOptRangeLine->draw(p);
+        }
+    }
+
+    case eState1st:
+    {
+        if(idx2nd != NOIDX)
+        {
+            qint32 idx1 = qMin(idxFocus, idx2nd);
+            qint32 idx2 = qMax(idxFocus, idx2nd);
+
+            QPolygonF seg;
+            for(int i = idx1; i <= idx2; i++)
+            {
+                const IGisLine::point_t& point = points[i];
+                seg << point.pixel;
+                foreach(const IGisLine::subpt_t& subpt, point.subpts)
+                {
+                    seg << subpt.pixel;
+                }
+            }
+
+            p.setPen(QPen(Qt::darkGreen, 11, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
+            p.drawPolyline(seg);
+
+            p.setPen(QPen(Qt::green, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
+            p.drawPolyline(seg);
+
+            QRectF r(0,0,7,7);
+            p.setPen(QPen(Qt::darkGreen,2));
+            p.setBrush(Qt::darkGreen);
+            foreach(const QPointF &pt, seg)
+            {
+                r.moveCenter(pt);
+                p.drawRect(r);
+            }
+            p.setPen(Qt::NoPen);
+            p.setBrush(Qt::black);
+            foreach(const QPointF &pt, seg)
+            {
+                r.moveCenter(pt);
+                p.drawRect(r);
+            }
+        }
+        break;
+    }
+    }
+}
+
+void CLineOpSelectRange::resetState()
+{
+    scrOptRangeLine->deleteLater();
+    idxFocus    = NOIDX;
+    idx2nd      = NOIDX;
+    state       = eStateIdle;
+}
+
+void CLineOpSelectRange::slotDelete()
+{
+    qint32 idx = qMin(idxFocus, idx2nd);
+    qint32 N   = qAbs(idxFocus - idx2nd) - 1;
+
+    points.remove(idx + 1, N);
+    parentHandler->storeToHistory(points);
+
+    resetState();
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
+}
+
+void CLineOpSelectRange::slotCalc()
+{
+    qint32 idx = qMin(idxFocus, idx2nd);
+    qint32 N   = qAbs(idxFocus - idx2nd) - 1;
+
+    points.remove(idx + 1, N);
+
+    finalizeOperation(idx);
+    parentHandler->storeToHistory(points);
+
+    resetState();
+}
diff --git a/src/gis/rte/CScrOptRte.h b/src/mouse/line/CLineOpSelectRange.h
similarity index 53%
copy from src/gis/rte/CScrOptRte.h
copy to src/mouse/line/CLineOpSelectRange.h
index 21543df..9e6e337 100644
--- a/src/gis/rte/CScrOptRte.h
+++ b/src/mouse/line/CLineOpSelectRange.h
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -16,35 +16,49 @@
 
 **********************************************************************************************/
 
-#ifndef CSCROPTRTE_H
-#define CSCROPTRTE_H
+#ifndef CLINEOPSELECTRANGE_H
+#define CLINEOPSELECTRANGE_H
 
-#include "gis/IGisItem.h"
-#include "mouse/IScrOpt.h"
+#include "mouse/line/ILineOp.h"
 
-#include "ui_IScrOptRte.h"
-#include <QWidget>
+#include <QPointer>
 
-class CGisItemRte;
-class IMouse;
+class CScrOptRangeLine;
 
-class CScrOptRte : public IScrOpt, private Ui::IScrOptRte
+class CLineOpSelectRange : public ILineOp
 {
     Q_OBJECT
 public:
-    CScrOptRte(CGisItemRte * rte, const QPoint &point, IMouse *parent);
-    virtual ~CScrOptRte();
+    CLineOpSelectRange(SGisLine& points, CGisDraw *gis, CCanvas *canvas, IMouseEditLine *parent);
+    virtual ~CLineOpSelectRange();
 
-    void draw(QPainter& p);
+    void mousePressEventEx(QMouseEvent * e);
+    void mouseMoveEventEx(QMouseEvent * e);
+    void mouseReleaseEventEx(QMouseEvent *e)
+    {
+    }
+
+    void drawFg(QPainter& p);
 
 private slots:
     void slotDelete();
-    void slotCopy();
+    void slotCalc();
 
 private:
-    IGisItem::key_t key;
-    QPointF anchor;
+    void resetState();
+    enum state_e
+    {
+        eStateIdle
+        , eState1st
+        , eState2nd
+    };
+
+    state_e state;
+
+    qint32 idx2nd;
+
+    QPointer<CScrOptRangeLine>  scrOptRangeLine;
 };
 
-#endif //CSCROPTRTE_H
+#endif //CLINEOPSELECTRANGE_H
 
diff --git a/src/mouse/CScrOptEditLine.cpp b/src/mouse/line/CScrOptEditLine.cpp
similarity index 90%
rename from src/mouse/CScrOptEditLine.cpp
rename to src/mouse/line/CScrOptEditLine.cpp
index b795628..f05d2f7 100644
--- a/src/mouse/CScrOptEditLine.cpp
+++ b/src/mouse/line/CScrOptEditLine.cpp
@@ -16,12 +16,12 @@
 
 **********************************************************************************************/
 
-#include "CScrOptEditLine.h"
+#include "mouse/line/CScrOptEditLine.h"
 
 #include <QtWidgets>
 
-CScrOptEditLine::CScrOptEditLine(QWidget *parent)
-    : IScrOpt(parent)
+CScrOptEditLine::CScrOptEditLine(IMouse *mouse)
+    : IScrOpt(mouse)
 {
     setupUi(this);
 
diff --git a/src/mouse/CScrOptEditLine.h b/src/mouse/line/CScrOptEditLine.h
similarity index 96%
rename from src/mouse/CScrOptEditLine.h
rename to src/mouse/line/CScrOptEditLine.h
index 4325729..fe7d353 100644
--- a/src/mouse/CScrOptEditLine.h
+++ b/src/mouse/line/CScrOptEditLine.h
@@ -26,7 +26,7 @@ class CScrOptEditLine : public IScrOpt, public Ui::IScrOptEditLine
 {
     Q_OBJECT
 public:
-    CScrOptEditLine(QWidget * parent);
+    CScrOptEditLine(IMouse *mouse);
     virtual ~CScrOptEditLine();
 
     void draw(QPainter& p)
diff --git a/src/mouse/CScrOptPoint.cpp b/src/mouse/line/CScrOptRangeLine.cpp
similarity index 70%
copy from src/mouse/CScrOptPoint.cpp
copy to src/mouse/line/CScrOptRangeLine.cpp
index 9ce3849..343487d 100644
--- a/src/mouse/CScrOptPoint.cpp
+++ b/src/mouse/line/CScrOptRangeLine.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -16,15 +16,19 @@
 
 **********************************************************************************************/
 
-#include "canvas/CCanvas.h"
-#include "mouse/CScrOptPoint.h"
+#include "CScrOptRangeLine.h"
 
-#include <QtWidgets>
-
-CScrOptPoint::CScrOptPoint(const QPointF &point, QWidget *parent)
-    : IScrOpt(parent)
+CScrOptRangeLine::CScrOptRangeLine(const QPointF &point, IMouse *mouse, QWidget * parent)
+    : IScrOpt(mouse)
 {
+    if(parent != 0)
+    {
+        setParent(parent);
+    }
+
     setupUi(this);
+//    label->setFont(CMainWindow::self().getMapFont());
+//    label->setText(trk->getInfoRange());
     adjustSize();
 
     setOrigin(point.toPoint());
@@ -33,11 +37,11 @@ CScrOptPoint::CScrOptPoint(const QPointF &point, QWidget *parent)
     show();
 }
 
-CScrOptPoint::~CScrOptPoint()
+CScrOptRangeLine::~CScrOptRangeLine()
 {
 }
 
-void CScrOptPoint::draw(QPainter& p)
+void CScrOptRangeLine::draw(QPainter& p)
 {
     drawBubble2(origin, p);
 }
diff --git a/src/mouse/CScrOptRangeTrk.h b/src/mouse/line/CScrOptRangeLine.h
similarity index 71%
copy from src/mouse/CScrOptRangeTrk.h
copy to src/mouse/line/CScrOptRangeLine.h
index 337cb34..2754053 100644
--- a/src/mouse/CScrOptRangeTrk.h
+++ b/src/mouse/line/CScrOptRangeLine.h
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -16,22 +16,21 @@
 
 **********************************************************************************************/
 
-#ifndef CSCROPTRANGETRK_H
-#define CSCROPTRANGETRK_H
+#ifndef CSCROPTRANGELINE_H
+#define CSCROPTRANGELINE_H
 
 #include "mouse/IScrOpt.h"
-#include "ui_IScrOptRangeTrk.h"
+#include "ui_IScrOptRangeLine.h"
 
-class CGisItemTrk;
-
-class CScrOptRangeTrk : public IScrOpt, public Ui::IScrOptRangeTrk
+class CScrOptRangeLine : public IScrOpt, public Ui::IScrOptRangeLine
 {
+    Q_OBJECT
 public:
-    CScrOptRangeTrk(const QPointF& point, CGisItemTrk *trk, QWidget * parent);
-    virtual ~CScrOptRangeTrk();
+    CScrOptRangeLine(const QPointF &point, IMouse *mouse, QWidget *parent);
+    virtual ~CScrOptRangeLine();
 
     void draw(QPainter& p);
 };
 
-#endif //CSCROPTRANGETRK_H
+#endif //CSCROPTRANGELINE_H
 
diff --git a/src/mouse/line/ILineOp.cpp b/src/mouse/line/ILineOp.cpp
new file mode 100644
index 0000000..090e518
--- /dev/null
+++ b/src/mouse/line/ILineOp.cpp
@@ -0,0 +1,377 @@
+/**********************************************************************************************
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+**********************************************************************************************/
+
+#include "GeoMath.h"
+#include "canvas/CCanvas.h"
+#include "gis/CGisDraw.h"
+#include "gis/rte/router/CRouterSetup.h"
+#include "mouse/line/ILineOp.h"
+#include "mouse/line/IMouseEditLine.h"
+
+#include <QtWidgets>
+
+ILineOp::ILineOp(SGisLine& points, CGisDraw *gis, CCanvas *canvas, IMouseEditLine *parent)
+    : QObject(parent)
+    , parentHandler(parent)
+    , points(points)
+    , canvas(canvas)
+    , gis(gis)
+    , idxFocus(NOIDX)
+    , mapMove(false)
+    , mapDidMove(false)
+    , rectPoint(0,0,9,9)
+    , penBgPoint(Qt::white, 4)
+    , penFgPoint(Qt::red, 2)
+    , brushBgPoint(Qt::white)
+    , brushFgPoint(Qt::red)
+{
+    timerRouting = new QTimer(this);
+    timerRouting->setSingleShot(true);
+    timerRouting->setInterval(400);
+    connect(timerRouting, SIGNAL(timeout()), this, SLOT(slotTimeoutRouting()));
+}
+
+ILineOp::~ILineOp()
+{
+}
+
+void ILineOp::cancelDelayedRouting()
+{
+    timerRouting->stop();
+}
+
+void ILineOp::startDelayedRouting()
+{
+    if(parentHandler->useAutoRouting())
+    {
+        timerRouting->start();
+    }
+    else if(parentHandler->useVectorRouting())
+    {
+        slotTimeoutRouting();
+    }
+}
+
+void ILineOp::slotTimeoutRouting()
+{
+    timerRouting->stop();
+    finalizeOperation(idxFocus);
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
+}
+
+
+void ILineOp::drawBg(QPainter& p)
+{
+    drawLeadLine(leadLinePixel1,p);
+    drawLeadLine(leadLinePixel2,p);
+}
+
+void ILineOp::drawSinglePointSmall(const QPointF& pt, QPainter& p)
+{
+    QRect r(0,0,3,3);
+    r.moveCenter(pt.toPoint());
+
+    p.setPen(QPen(Qt::white, 2));
+    p.setBrush(Qt::white);
+    p.drawRect(r);
+
+    p.setPen(Qt::black);
+    p.setBrush(Qt::black);
+    p.drawRect(r);
+}
+
+void ILineOp::drawSinglePointLarge(const QPointF &pt, QPainter& p)
+{
+    rectPoint.moveCenter(pt.toPoint());
+
+    p.setPen(penBgPoint);
+    p.setBrush(brushBgPoint);
+    p.drawRect(rectPoint);
+
+    p.setPen(penFgPoint);
+    p.setBrush(brushFgPoint);
+    p.drawRect(rectPoint);
+}
+
+void ILineOp::drawLeadLine(const QPolygonF& line, QPainter& p)
+{
+    p.setPen(QPen(Qt::yellow, 7, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
+    p.drawPolyline(line);
+}
+
+void ILineOp::mousePressEvent(QMouseEvent * e)
+{
+    if(idxFocus != NOIDX)
+    {
+        mousePressEventEx(e);
+    }
+    else
+    {
+        const QPoint& pos = e->pos();
+
+        if(e->button() == Qt::LeftButton)
+        {
+            lastPos     = pos;
+            mapMove     = true;
+            mapDidMove  = false;
+        }
+    }
+}
+
+void ILineOp::mouseMoveEvent(QMouseEvent * e)
+{
+    const QPoint& pos = e->pos();
+
+    if(mapMove)
+    {
+        if(pos != lastPos)
+        {
+            QPoint delta = pos - lastPos;
+            canvas->moveMap(delta);
+            mapDidMove  = true;
+        }
+    }
+    else
+    {
+        updateLeadLines(idxFocus);
+        mouseMoveEventEx(e);
+    }
+
+    lastPos = pos;
+}
+
+void ILineOp::mouseReleaseEvent(QMouseEvent *e)
+{
+    mouseReleaseEventEx(e);
+    mapMove     = false;
+    mapDidMove  = false;
+}
+
+void ILineOp::updateLeadLines(qint32 idx)
+{
+    leadLinePixel1.clear();
+    leadLinePixel2.clear();
+    subLinePixel1.clear();
+    subLinePixel2.clear();
+
+    if(parentHandler->useVectorRouting() && (idx != NOIDX))
+    {
+        leadLineCoord1.clear();
+        leadLineCoord2.clear();
+        subLineCoord1.clear();
+        subLineCoord2.clear();
+
+        if(idx > 0)
+        {
+            const IGisLine::point_t& pt1 = points[idx - 1];
+            const IGisLine::point_t& pt2 = points[idx];
+            if(canvas->findPolylineCloseBy(pt2.pixel, pt2.pixel, 10, leadLineCoord1))
+            {
+                leadLinePixel1 = leadLineCoord1;
+                gis->convertRad2Px(leadLinePixel1);
+
+                segment_t result;
+                GPS_Math_SubPolyline(pt1.pixel, pt2.pixel, 10, leadLinePixel1, result);
+                result.apply(leadLineCoord1, leadLinePixel1, subLineCoord1, subLinePixel1, gis);
+            }
+        }
+
+        if(idx < points.size() - 1)
+        {
+            const IGisLine::point_t& pt1 = points[idx];
+            const IGisLine::point_t& pt2 = points[idx + 1];
+            if(canvas->findPolylineCloseBy(pt1.pixel, pt1.pixel, 10, leadLineCoord2))
+            {
+                leadLinePixel2 = leadLineCoord2;
+                gis->convertRad2Px(leadLinePixel2);
+
+                segment_t result;
+                GPS_Math_SubPolyline(pt1.pixel, pt2.pixel, 10, leadLinePixel2, result);
+                result.apply(leadLineCoord2, leadLinePixel2, subLineCoord2, subLinePixel2, gis);
+            }
+        }
+    }
+}
+
+void ILineOp::finalizeOperation(qint32 idx)
+{
+    if(idx == NOIDX)
+    {
+        return;
+    }
+
+    if(parentHandler->useAutoRouting())
+    {
+        QApplication::setOverrideCursor(Qt::WaitCursor);
+        if(idx > 0)
+        {
+            QPolygonF subs;
+            IGisLine::point_t& pt1 = points[idx - 1];
+            IGisLine::point_t& pt2 = points[idx];
+            CRouterSetup::self().calcRoute(pt1.coord, pt2.coord, subs);
+
+            pt1.subpts.clear();
+            foreach(const QPointF &sub, subs)
+            {
+                pt1.subpts << IGisLine::subpt_t(sub);
+            }
+        }
+
+        if(idx < (points.size() - 1))
+        {
+            QPolygonF subs;
+            IGisLine::point_t& pt1 = points[idx];
+            IGisLine::point_t& pt2 = points[idx + 1];
+            CRouterSetup::self().calcRoute(pt1.coord, pt2.coord, subs);
+
+            pt1.subpts.clear();
+            foreach(const QPointF &sub, subs)
+            {
+                pt1.subpts << IGisLine::subpt_t(sub);
+            }
+        }
+        QApplication::restoreOverrideCursor();
+    }
+    else if(parentHandler->useVectorRouting())
+    {
+        if(idx > 0)
+        {
+            IGisLine::point_t& pt1 = points[idx - 1];
+            pt1.subpts.clear();
+            foreach(const QPointF &pt, subLineCoord1)
+            {
+                pt1.subpts << IGisLine::subpt_t(pt);
+            }
+        }
+
+        if(idx < (points.size() - 1))
+        {
+            IGisLine::point_t& pt1 = points[idx];
+            pt1.subpts.clear();
+            foreach(const QPointF &pt, subLineCoord2)
+            {
+                pt1.subpts << IGisLine::subpt_t(pt);
+            }
+        }
+    }
+}
+
+qint32 ILineOp::isCloseTo(const QPoint& pos)
+{
+    qint32 min = 30;
+    qint32 idx = NOIDX;
+    const int N = points.size();
+    for(int i = 0; i < N; i++)
+    {
+        const IGisLine::point_t& pt = points[i];
+
+        qint32 d = (pos - pt.pixel).manhattanLength();
+        if(d < min)
+        {
+            min = d;
+            idx = i;
+        }
+    }
+
+    return idx;
+}
+
+
+inline qreal sqr(qreal a)
+{
+    return a*a;
+}
+inline qreal sqrlen(const QPointF &a)
+{
+    return sqr(a.x()) + sqr(a.y());
+}
+
+qreal sqr_distance(const QPolygonF &points, const QPointF &q)
+{
+    const qint32 count = points.size();
+
+    QPointF b = points[0];
+    QPointF dbq = b - q;
+    qreal dist = sqrlen(dbq);
+
+    for (qint32 i = 1; i<count; ++i)
+    {
+        const QPointF a = b;
+        const QPointF daq = dbq;
+        b = points[i];
+        dbq = b - q;
+
+        const QPointF dab = a - b;
+
+        const qreal inv_sqrlen = 1./sqrlen(dab);
+        const qreal t = (dab.x()*daq.x() + dab.y()*daq.y())*inv_sqrlen;
+        if (t < 0.)
+        {
+            continue;
+        }
+        qreal current_dist;
+        if (t<=1.)
+        {
+            current_dist = sqr(dab.x()*dbq.y() - dab.y()*dbq.x())*inv_sqrlen;
+        }
+        else//t>1.
+        {
+            current_dist = sqrlen(dbq);
+        }
+        if (current_dist<dist)
+        {
+            dist = current_dist;
+        }
+    }
+    return dist;
+}
+qint32 ILineOp::isCloseToLine(const QPoint& pos)
+{
+    qint32 idx = NOIDX;
+    qreal dist = 60;
+
+    for(int i = 0; i < points.size() - 1; i++)
+    {
+        QPolygonF line;
+        const IGisLine::point_t& pt1 = points[i];
+        const IGisLine::point_t& pt2 = points[i + 1];
+
+        if(pt1.subpts.isEmpty())
+        {
+            line << pt1.pixel << pt2.pixel;
+        }
+        else
+        {
+            foreach(const IGisLine::subpt_t& pt, pt1.subpts)
+            {
+                line << pt.pixel;
+            }
+            line << pt2.pixel;
+        }
+
+        qreal d = sqr_distance(line, pos);
+        if(d < dist)
+        {
+            dist = d;
+            idx  = i;
+        }
+    }
+
+    return idx;
+}
+
diff --git a/src/mouse/line/ILineOp.h b/src/mouse/line/ILineOp.h
new file mode 100644
index 0000000..f158d0e
--- /dev/null
+++ b/src/mouse/line/ILineOp.h
@@ -0,0 +1,111 @@
+/**********************************************************************************************
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+**********************************************************************************************/
+
+#ifndef ILINEOP_H
+#define ILINEOP_H
+
+#include "gis/IGisLine.h"
+#include <QBrush>
+#include <QCursor>
+#include <QObject>
+#include <QPen>
+#include <QRect>
+
+class QMouseEvent;
+class CCanvas;
+class QPainter;
+class IMouseEditLine;
+
+class ILineOp : public QObject
+{
+    Q_OBJECT
+public:
+    ILineOp(SGisLine &points, CGisDraw * gis, CCanvas * canvas, IMouseEditLine * parent);
+    virtual ~ILineOp();
+
+    virtual void mousePressEvent(QMouseEvent * e);
+    virtual void mouseMoveEvent(QMouseEvent * e);
+    virtual void mouseReleaseEvent(QMouseEvent *e);
+
+    virtual void mousePressEventEx(QMouseEvent * e) = 0;
+    virtual void mouseMoveEventEx(QMouseEvent * e) = 0;
+    virtual void mouseReleaseEventEx(QMouseEvent *e) = 0;
+
+    virtual void drawFg(QPainter& p) = 0;
+    virtual void drawBg(QPainter& p);
+
+    const QCursor& getCursor()
+    {
+        return cursor;
+    }
+
+    virtual void canvasPanned(QPointF pos)
+    {
+    }
+
+protected slots:
+    void slotTimeoutRouting();
+
+protected:
+    virtual void cancelDelayedRouting();
+    virtual void startDelayedRouting();
+    virtual void finalizeOperation(qint32 idx);
+    qint32 isCloseTo(const QPoint& pos);
+    qint32 isCloseToLine(const QPoint& pos);
+
+    void drawSinglePointSmall(const QPointF& pt, QPainter& p);
+    void drawSinglePointLarge(const QPointF &pt, QPainter& p);
+    void drawLeadLine(const QPolygonF& line, QPainter& p);
+
+    void updateLeadLines(qint32 idx);
+
+    IMouseEditLine * parentHandler;
+    SGisLine& points;
+    CCanvas * canvas;
+    CGisDraw * gis;
+
+    QCursor cursor;
+
+    qint32 idxFocus;
+    bool mapMove;
+    bool mapDidMove;
+
+    QPoint lastPos;
+
+    QRect rectPoint;
+    const QPen penBgPoint;
+    const QPen penFgPoint;
+    const QBrush brushBgPoint;
+    const QBrush brushFgPoint;
+
+    QPolygonF leadLineCoord1;
+    QPolygonF leadLineCoord2;
+    QPolygonF leadLinePixel1;
+    QPolygonF leadLinePixel2;
+
+    QPolygonF subLineCoord1;
+    QPolygonF subLineCoord2;
+    QPolygonF subLinePixel1;
+    QPolygonF subLinePixel2;
+
+private:
+    QTimer * timerRouting;
+};
+
+#endif //ILINEOP_H
+
diff --git a/src/mouse/line/IMouseEditLine.cpp b/src/mouse/line/IMouseEditLine.cpp
new file mode 100644
index 0000000..e4f10ca
--- /dev/null
+++ b/src/mouse/line/IMouseEditLine.cpp
@@ -0,0 +1,402 @@
+/**********************************************************************************************
+    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+**********************************************************************************************/
+
+#include "CMainWindow.h"
+#include "GeoMath.h"
+#include "canvas/CCanvas.h"
+#include "gis/CGisDraw.h"
+#include "gis/CGisWidget.h"
+#include "gis/IGisLine.h"
+#include "gis/rte/router/CRouterSetup.h"
+#include "helpers/CSettings.h"
+#include "mouse/CScrOptPoint.h"
+#include "mouse/CScrOptRange.h"
+#include "mouse/line/CLineOpAddPoint.h"
+#include "mouse/line/CLineOpDeletePoint.h"
+#include "mouse/line/CLineOpMovePoint.h"
+#include "mouse/line/CLineOpSelectRange.h"
+#include "mouse/line/CScrOptEditLine.h"
+#include "mouse/line/IMouseEditLine.h"
+#include "units/IUnit.h"
+
+
+#include <QtWidgets>
+
+IMouseEditLine::IMouseEditLine(const IGisItem::key_t &key, const QPointF& point, CGisDraw * gis, CCanvas * parent)
+    : IMouse(gis, parent)
+    , idxHistory(NOIDX)
+    , key(key)
+    , doCanvasPanning(false)
+    , lineOp(0)
+{
+    commonSetup();
+    scrOptEditLine->pushSaveOrig->hide(); // hide as there is no original
+
+    points << IGisLine::point_t(point);
+    points.updatePixel(gis);
+
+    storeToHistory(points);
+}
+
+IMouseEditLine::IMouseEditLine(const IGisItem::key_t &key, IGisLine &src, CGisDraw *gis, CCanvas *parent)
+    : IMouse(gis, parent)
+    , idxHistory(NOIDX)
+    , key(key)
+    , doCanvasPanning(false)
+    , lineOp(0)
+{
+    commonSetup();
+
+    src.getPolylineFromData(points);
+    points.updatePixel(gis);
+
+    storeToHistory(points);
+}
+
+
+IMouseEditLine::~IMouseEditLine()
+{
+    int mode = 0;
+    if(scrOptEditLine->toolNoRoute->isChecked())
+    {
+        mode = 0;
+    }
+    else if(scrOptEditLine->toolAutoRoute->isChecked())
+    {
+        mode = 1;
+    }
+    else if(scrOptEditLine->toolVectorRoute->isChecked())
+    {
+        mode = 2;
+    }
+
+    SETTINGS;
+    cfg.setValue("Route/drawMode", mode);
+
+    delete scrOptEditLine;
+}
+
+void IMouseEditLine::commonSetup()
+{
+    // create permanent line edit on screen options
+    scrOptEditLine = new CScrOptEditLine(this);
+    connect(scrOptEditLine->pushSaveOrig, SIGNAL(clicked()), this, SLOT(slotCopyToOrig()));
+    connect(scrOptEditLine->pushSaveNew, SIGNAL(clicked()), this, SLOT(slotCopyToNew()));
+    connect(scrOptEditLine->pushAbort, SIGNAL(clicked()), this, SLOT(slotAbort()));
+
+    connect(scrOptEditLine->toolMovePoint, SIGNAL(clicked()), this, SLOT(slotMovePoint()));
+    connect(scrOptEditLine->toolSelectRange, SIGNAL(clicked()), this, SLOT(slotSelectRange()));
+    connect(scrOptEditLine->toolAddPoint, SIGNAL(clicked()), this, SLOT(slotAddPoint()));
+    connect(scrOptEditLine->toolDeletePoint, SIGNAL(clicked()), this, SLOT(slotDeletePoint()));
+
+    connect(scrOptEditLine->toolNoRoute, SIGNAL(clicked()), this, SLOT(slotNoRouting()));
+    connect(scrOptEditLine->toolAutoRoute, SIGNAL(clicked()), this, SLOT(slotAutoRouting()));
+    connect(scrOptEditLine->toolVectorRoute, SIGNAL(clicked()), this, SLOT(slotVectorRouting()));
+
+    connect(scrOptEditLine->toolUndo, SIGNAL(clicked()), this, SLOT(slotUndo()));
+    connect(scrOptEditLine->toolRedo, SIGNAL(clicked()), this, SLOT(slotRedo()));
+
+    SETTINGS;
+    int mode = cfg.value("Route/drawMode",0).toInt();
+    switch(mode)
+    {
+    case 0:
+        scrOptEditLine->toolNoRoute->setChecked(true);
+        break;
+
+    case 1:
+        scrOptEditLine->toolAutoRoute->setChecked(true);
+        break;
+
+    case 2:
+        scrOptEditLine->toolVectorRoute->setChecked(true);
+        break;
+    }
+
+    slotMovePoint();
+}
+
+bool IMouseEditLine::useAutoRouting()
+{
+    return scrOptEditLine->toolAutoRoute->isChecked();
+}
+
+bool IMouseEditLine::useVectorRouting()
+{
+    return scrOptEditLine->toolVectorRoute->isChecked();
+}
+
+void IMouseEditLine::drawLine(const QPolygonF &l, const QColor color, int width, QPainter& p)
+{
+    p.setPen(QPen(color, width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
+    p.drawPolyline(l);
+}
+
+
+void IMouseEditLine::draw(QPainter& p, CCanvas::redraw_e needsRedraw, const QRect &rect)
+{
+    if(needsRedraw & (CCanvas::eRedrawMouse|CCanvas::eRedrawGis))
+    {
+        points.updatePixel(gis);
+
+        pixelLine.clear();
+        pixelPts.clear();
+        pixelSubs.clear();
+
+        for(int i = 0; i < points.size(); i++)
+        {
+            IGisLine::point_t& pt = points[i];
+            pixelLine << pt.pixel;
+            pixelPts << pt.pixel;
+
+            for(int n = 0; n < pt.subpts.size(); n++)
+            {
+                IGisLine::subpt_t& sub = pt.subpts[n];
+                pixelLine << sub.pixel;
+                pixelSubs << sub.pixel;
+            }
+        }
+    }
+
+    if(pixelPts.isEmpty())
+    {
+        return;
+    }
+
+    lineOp->drawBg(p);
+
+    drawLine(pixelLine, Qt::white, 7, p);
+
+    p.setPen(Qt::NoPen);
+    p.setBrush(Qt::white);
+    QRect r1(0,0,9,9);
+    foreach(const QPointF &pt, pixelPts)
+    {
+        r1.moveCenter(pt.toPoint());
+        p.drawRect(r1);
+    }
+
+    drawLine(pixelLine, Qt::magenta, 5, p);
+
+    p.setPen(Qt::NoPen);
+    p.setBrush(Qt::black);
+    QRect r2(0,0,7,7);
+    foreach(const QPointF &pt, pixelPts)
+    {
+        r2.moveCenter(pt.toPoint());
+        p.drawRect(r2);
+    }
+
+    foreach(const QPointF &pt, pixelSubs)
+    {
+        p.drawEllipse(pt, 2, 2);
+    }
+
+    QRect r3(0,0,9,9);
+    p.setBrush(Qt::NoBrush);
+
+    p.setPen(QPen(Qt::yellow,2));
+    r3.moveCenter(pixelPts.first().toPoint());
+    p.drawRect(r3);
+
+    p.setPen(QPen(Qt::green,2));
+    r3.moveCenter(pixelPts.last().toPoint());
+    p.drawRect(r3);
+
+    lineOp->drawFg(p);
+}
+
+
+void IMouseEditLine::startNewLine(const QPointF& point)
+{
+    points << IGisLine::point_t(point);
+
+    scrOptEditLine->toolAddPoint->setChecked(true);
+    slotAddPoint();
+
+    CLineOpAddPoint * lineOpAddPoint = dynamic_cast<CLineOpAddPoint*>(lineOp);
+    if(lineOpAddPoint)
+    {
+        lineOpAddPoint->append();
+    }
+
+    canvas->reportStatus(key.item, tr("<b>New Line</b><br/>Move the mouse and use the left mouse button to drop points. When done use the right mouse button to stop.<br/>"));
+}
+
+void IMouseEditLine::mousePressEvent(QMouseEvent * e)
+{
+    point  = e->pos();
+    lineOp->mousePressEvent(e);
+}
+
+void IMouseEditLine::mouseMoveEvent(QMouseEvent * e)
+{
+    point  = e->pos();
+
+    if(doCanvasPanning)
+    {
+        panCanvas(e->pos());
+    }
+
+    lineOp->mouseMoveEvent(e);
+}
+
+void IMouseEditLine::mouseReleaseEvent(QMouseEvent *e)
+{
+    point  = e->pos();
+    lineOp->mouseReleaseEvent(e);
+}
+
+void IMouseEditLine::wheelEvent(QWheelEvent * e)
+{
+    canvas->update();
+}
+
+
+void IMouseEditLine::slotPanCanvas()
+{
+    IMouse::slotPanCanvas();
+    lineOp->canvasPanned(point);
+}
+
+void IMouseEditLine::slotDeletePoint()
+{
+    canvas->reportStatus(key.item, tr("<b>Delete Point</b><br/>Move the mouse close to a point and press the left button to delete it.<br/>"));
+    delete lineOp;
+    lineOp = new CLineOpDeletePoint(points, gis, canvas, this);
+    changeCursor();
+}
+
+void IMouseEditLine::slotSelectRange()
+{
+    canvas->reportStatus(key.item, tr("<b>Select Range of Points</b><br/>Left click on first point to start selection. Left click second point to complete selection and choose from options. Use the right mouse button to cancel.<br/>"));
+    delete lineOp;
+    lineOp = new CLineOpSelectRange(points, gis, canvas, this);
+    changeCursor();
+}
+
+void IMouseEditLine::slotMovePoint()
+{
+    canvas->reportStatus(key.item, tr("<b>Move Point</b><br/>Move the mouse close to a point and press the left button to make it stick to the cursor. Move the mouse to move the point. Drop the point by a left click. Use the right mouse button to cancel.<br/>"));
+    delete lineOp;
+    lineOp = new CLineOpMovePoint(points, gis, canvas, this);
+    changeCursor();
+}
+
+void IMouseEditLine::slotAddPoint()
+{
+    canvas->reportStatus(key.item, tr("<b>Add Point</b><br/>Move the mouse close to a line segment and press the left button to add a point. The point will stick to the cursor and you can move it.  Drop the point by a left click. Use the right mouse button to cancel.<br/>"));
+    delete lineOp;
+    lineOp = new CLineOpAddPoint(points, gis, canvas, this);
+    changeCursor();
+}
+
+void IMouseEditLine::slotNoRouting()
+{
+    canvas->reportStatus(key.item, tr("<b>No Routing</b><br/>All points will be connected with a straight line.<br/>"));
+}
+
+void IMouseEditLine::slotAutoRouting()
+{
+    canvas->reportStatus(key.item, tr("<b>Auto Routing</b><br/>The current router setup is used to derive a route between points. <b>Note:</b> The selected router must be able to route on-the-fly. Offline routers usually can do, online routers can't.<br/>"));
+}
+
+void IMouseEditLine::slotVectorRouting()
+{
+    canvas->reportStatus(key.item, tr("<b>Vector Routing</b><br/>Connect points with a line from a loaded vector map if possible.<br/>"));
+}
+
+
+void IMouseEditLine::changeCursor()
+{
+    cursor = lineOp->getCursor();
+    QApplication::changeOverrideCursor(cursor);
+}
+
+void IMouseEditLine::slotAbort()
+{
+    canvas->resetMouse();
+    canvas->update();
+}
+
+void IMouseEditLine::slotCopyToOrig()
+{
+    IGisLine * l = getGisLine();
+    if(l != 0)
+    {
+        CMainWindow::self().getEelevationAt(points);
+        l->setDataFromPolyline(points);
+    }
+
+
+    canvas->resetMouse();
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawGis);
+}
+
+void IMouseEditLine::restoreFromHistory(SGisLine& line)
+{
+    line = history[idxHistory];
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
+}
+
+void IMouseEditLine::storeToHistory(const SGisLine& line)
+{
+    // crop history if necessary
+    if(idxHistory != NOIDX)
+    {
+        while(history.size() > (idxHistory + 1))
+        {
+            history.pop_back();
+        }
+    }
+
+    history << line;
+    idxHistory = history.size() - 1;
+
+    scrOptEditLine->toolRedo->setEnabled(false);
+    scrOptEditLine->toolUndo->setEnabled(idxHistory > 0);
+}
+
+void IMouseEditLine::slotUndo()
+{
+    if(idxHistory > 0)
+    {
+        idxHistory--;
+    }
+
+    points = history[idxHistory];
+
+    scrOptEditLine->toolRedo->setEnabled(true);
+    scrOptEditLine->toolUndo->setEnabled(idxHistory > 0);
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
+}
+
+void IMouseEditLine::slotRedo()
+{
+    if(idxHistory < (history.size() - 1))
+    {
+        idxHistory++;
+    }
+
+
+    points = history[idxHistory];
+
+    scrOptEditLine->toolRedo->setEnabled(idxHistory < (history.size() - 1));
+    scrOptEditLine->toolUndo->setEnabled(true);
+    canvas->slotTriggerCompleteUpdate(CCanvas::eRedrawMouse);
+}
diff --git a/src/mouse/IMouseEditLine.h b/src/mouse/line/IMouseEditLine.h
similarity index 61%
rename from src/mouse/IMouseEditLine.h
rename to src/mouse/line/IMouseEditLine.h
index 17793af..7addf5f 100644
--- a/src/mouse/IMouseEditLine.h
+++ b/src/mouse/line/IMouseEditLine.h
@@ -19,7 +19,10 @@
 #ifndef IMOUSEEDITLINE_H
 #define IMOUSEEDITLINE_H
 
+#include "gis/IGisItem.h"
+#include "gis/IGisLine.h"
 #include "mouse/IMouse.h"
+#include <QDebug>
 #include <QPointer>
 #include <QPolygonF>
 
@@ -29,33 +32,51 @@ class IGisLine;
 class CScrOptPoint;
 class CScrOptEditLine;
 class CScrOptRange;
+class ILineOp;
 
 class IMouseEditLine : public IMouse
 {
     Q_OBJECT
 public:
+    enum features_e
+    {
+        eFeatureSnapToLines    = 0x01
+        ,eFeatureRouting        = 0x02
+    };
+
     /**
        @brief Start to create a new track with given point as first track point
        @param point     the starting point
        @param gis       the draw context to use
        @param parent    the canvas to use
      */
-    IMouseEditLine(const QPointF& point, CGisDraw * gis, CCanvas * parent);
+    IMouseEditLine(const IGisItem::key_t& key, const QPointF& point, CGisDraw * gis, CCanvas * parent);
     /**
        @brief Edit an existing track
        @param trk       the track to edit
        @param gis       the draw context to use
        @param parent    the canvas to use
      */
-    IMouseEditLine(IGisLine &src, CGisDraw * gis, CCanvas * parent);
+    IMouseEditLine(const IGisItem::key_t &key, IGisLine &src, CGisDraw * gis, CCanvas * parent);
     virtual ~IMouseEditLine();
 
-    void draw(QPainter& p,  bool needsRedraw, const QRect &rect);
+    void draw(QPainter& p,  CCanvas::redraw_e needsRedraw, const QRect &rect);
     void mousePressEvent(QMouseEvent * e);
     void mouseMoveEvent(QMouseEvent * e);
     void mouseReleaseEvent(QMouseEvent *e);
     void wheelEvent(QWheelEvent * e);
 
+    bool useAutoRouting();
+    bool useVectorRouting();
+
+    void setCanvasPanning(bool enable)
+    {
+        doCanvasPanning = enable;
+    }
+
+    void storeToHistory(const SGisLine& line);
+    void restoreFromHistory(SGisLine& line);
+
 protected slots:
     /**
        @brief Delete the selected point
@@ -66,85 +87,67 @@ protected slots:
      */
     void slotSelectRange();
     /**
-       @brief Delete selected range of points
-     */
-    void slotDeleteRange();
-    /**
        @brief Move selected point
      */
     void slotMovePoint();
     /**
        @brief Add points in direction start of track (eStateAddPointBwd)
      */
-    void slotAddPoint1();
-    /**
-       @brief Add points in direction end of track (eStateAddPointFwd)
-     */
-    void slotAddPoint2();
+    void slotAddPoint();
+
+    void slotNoRouting();
+    void slotAutoRouting();
+    void slotVectorRouting();
 
 
     virtual void slotAbort();
     virtual void slotCopyToOrig();
     virtual void slotCopyToNew() = 0;
 
+    void slotUndo();
+    void slotRedo();
+
+    void slotPanCanvas();
+
 protected:
-    virtual void drawLine(const QPolygonF& l, QPainter& p);
+    virtual void drawLine(const QPolygonF& l, const QColor color, int width, QPainter& p);
     /**
        @brief Get access to the IGisLine object a subclass of IMouseEditLine is handling.
        @return A valid pointer or 0.
      */
     virtual IGisLine * getGisLine() = 0;
+
+    virtual void startNewLine(const QPointF &point);
+
     /// shadow cursor needed to restore cursor after some actions providing their own cursor.
     QCursor cursor1;
-    /// the line's coordinates in [rad]
-    QPolygonF coords1;
 
-private:
-    void drawPointOfFocus(QPainter& p);
-    void drawBullets(const QPolygonF& l, QPainter& p);
-    void drawHighlight1(QPainter& p);
-    void drawHighlight2(QPainter& p);
-    void drawArrows(const QPolygonF &l, QPainter& p);
-    void drawLeadLine(const QPolygonF &l, QPainter& p);
-    int getPointCloseBy(const QPoint& screenPos);
-
-    /// backup for coord1
-    QPolygonF save;
-    /// the line's coordinates in [pixel]
-    QPolygonF line;
-
-    /// the temporary line of new point to add [rad]
-    QPolygonF newCoords;
-    /// the temporary line of new point to add [pixel]
-    QPolygonF newLine;
-
-    enum state_e
-    {
-        eStateIdle
-        ,eStatePointSelected
-        ,eStateSelectRange
-        ,eStateRangeSelected
-        ,eStateMovePoint
-        ,eStateAddPointBwd
-        ,eStateAddPointFwd
-        ,eStateMoveMap
-    };
+    /// the abstract line object to edit
+    SGisLine points;
+
+    /// undo/redo history
+    QList<SGisLine> history;
+    qint32 idxHistory;
 
-    state_e state;
-    qint32 idxFocus;
-    qint32 idxStart;
-    qint32 idxStop;
 
-    QPointer<CScrOptPoint> scrOptPoint;
-    QPointer<CScrOptRange> scrOptRange;
+    /// the on screen buttons
     CScrOptEditLine * scrOptEditLine;
 
-    QPoint lastPoint;
+    /// the key of the GIS item to edit
+    IGisItem::key_t key;
+private:
+    void commonSetup();
+    void changeCursor();
+
+    /// flag to enable/disable canvas/map panning
+    bool doCanvasPanning;
+
+    QPolygonF pixelLine;
+    QPolygonF pixelPts;
+    QPolygonF pixelSubs;
 
-    QPolygonF leadLineCoord;
-    QPolygonF leadLinePixel;
-    QPolygonF subLineCoord;
-    QPolygonF subLinePixel;
+    /// the current active line operation (move, add, delete...)
+    ILineOp  * lineOp;
 };
 
 #endif //IMOUSEEDITLINE_H
diff --git a/src/mouse/line/IScrOptEditLine.ui b/src/mouse/line/IScrOptEditLine.ui
new file mode 100644
index 0000000..b606895
--- /dev/null
+++ b/src/mouse/line/IScrOptEditLine.ui
@@ -0,0 +1,338 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>IScrOptEditLine</class>
+ <widget class="QWidget" name="IScrOptEditLine">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>653</width>
+    <height>46</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>0</width>
+    <height>0</height>
+   </size>
+  </property>
+  <property name="maximumSize">
+   <size>
+    <width>16777215</width>
+    <height>100</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <spacer name="horizontalSpacer_2">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pushSaveOrig">
+       <property name="text">
+        <string>Save to orignal</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pushSaveNew">
+       <property name="text">
+        <string>Save as new</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pushAbort">
+       <property name="text">
+        <string>Abort</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="Line" name="line">
+       <property name="orientation">
+        <enum>Qt::Vertical</enum>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QFrame" name="frame">
+       <property name="frameShape">
+        <enum>QFrame::NoFrame</enum>
+       </property>
+       <property name="frameShadow">
+        <enum>QFrame::Raised</enum>
+       </property>
+       <layout class="QHBoxLayout" name="horizontalLayout_2">
+        <property name="leftMargin">
+         <number>0</number>
+        </property>
+        <property name="topMargin">
+         <number>0</number>
+        </property>
+        <property name="rightMargin">
+         <number>0</number>
+        </property>
+        <property name="bottomMargin">
+         <number>0</number>
+        </property>
+        <item>
+         <widget class="QToolButton" name="toolMovePoint">
+          <property name="toolTip">
+           <string>Move points.</string>
+          </property>
+          <property name="text">
+           <string>...</string>
+          </property>
+          <property name="icon">
+           <iconset resource="../../resources.qrc">
+            <normaloff>:/icons/32x32/PointMove.png</normaloff>:/icons/32x32/PointMove.png</iconset>
+          </property>
+          <property name="checkable">
+           <bool>true</bool>
+          </property>
+          <property name="checked">
+           <bool>true</bool>
+          </property>
+          <property name="autoExclusive">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QToolButton" name="toolAddPoint">
+          <property name="toolTip">
+           <string>Add new points.</string>
+          </property>
+          <property name="text">
+           <string>...</string>
+          </property>
+          <property name="icon">
+           <iconset resource="../../resources.qrc">
+            <normaloff>:/icons/32x32/Add.png</normaloff>:/icons/32x32/Add.png</iconset>
+          </property>
+          <property name="checkable">
+           <bool>true</bool>
+          </property>
+          <property name="autoExclusive">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QToolButton" name="toolSelectRange">
+          <property name="toolTip">
+           <string>Select a range of points.</string>
+          </property>
+          <property name="text">
+           <string>...</string>
+          </property>
+          <property name="icon">
+           <iconset resource="../../resources.qrc">
+            <normaloff>:/icons/32x32/SelectRange.png</normaloff>:/icons/32x32/SelectRange.png</iconset>
+          </property>
+          <property name="checkable">
+           <bool>true</bool>
+          </property>
+          <property name="autoExclusive">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QToolButton" name="toolDeletePoint">
+          <property name="toolTip">
+           <string>Delete a point.</string>
+          </property>
+          <property name="text">
+           <string>...</string>
+          </property>
+          <property name="icon">
+           <iconset resource="../../resources.qrc">
+            <normaloff>:/icons/32x32/DeleteOne.png</normaloff>:/icons/32x32/DeleteOne.png</iconset>
+          </property>
+          <property name="checkable">
+           <bool>true</bool>
+          </property>
+          <property name="autoExclusive">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item>
+      <widget class="Line" name="line_2">
+       <property name="orientation">
+        <enum>Qt::Vertical</enum>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QFrame" name="frame_2">
+       <property name="frameShape">
+        <enum>QFrame::NoFrame</enum>
+       </property>
+       <property name="frameShadow">
+        <enum>QFrame::Raised</enum>
+       </property>
+       <layout class="QHBoxLayout" name="horizontalLayout_3">
+        <property name="leftMargin">
+         <number>0</number>
+        </property>
+        <property name="topMargin">
+         <number>0</number>
+        </property>
+        <property name="rightMargin">
+         <number>0</number>
+        </property>
+        <property name="bottomMargin">
+         <number>0</number>
+        </property>
+        <item>
+         <widget class="QToolButton" name="toolNoRoute">
+          <property name="toolTip">
+           <string>No auto-routing or line snapping</string>
+          </property>
+          <property name="text">
+           <string>0</string>
+          </property>
+          <property name="icon">
+           <iconset resource="../../resources.qrc">
+            <normaloff>:/icons/32x32/O.png</normaloff>:/icons/32x32/O.png</iconset>
+          </property>
+          <property name="checkable">
+           <bool>true</bool>
+          </property>
+          <property name="autoExclusive">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QToolButton" name="toolAutoRoute">
+          <property name="toolTip">
+           <string>Use auto-routing to between points.</string>
+          </property>
+          <property name="text">
+           <string>A</string>
+          </property>
+          <property name="icon">
+           <iconset resource="../../resources.qrc">
+            <normaloff>:/icons/32x32/A.png</normaloff>:/icons/32x32/A.png</iconset>
+          </property>
+          <property name="checkable">
+           <bool>true</bool>
+          </property>
+          <property name="autoExclusive">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QToolButton" name="toolVectorRoute">
+          <property name="toolTip">
+           <string>Snap line along lines of a vector map.</string>
+          </property>
+          <property name="text">
+           <string>V</string>
+          </property>
+          <property name="icon">
+           <iconset resource="../../resources.qrc">
+            <normaloff>:/icons/32x32/V.png</normaloff>:/icons/32x32/V.png</iconset>
+          </property>
+          <property name="checkable">
+           <bool>true</bool>
+          </property>
+          <property name="autoExclusive">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item>
+      <widget class="Line" name="line_3">
+       <property name="orientation">
+        <enum>Qt::Vertical</enum>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="toolUndo">
+       <property name="enabled">
+        <bool>false</bool>
+       </property>
+       <property name="toolTip">
+        <string>Undo last change</string>
+       </property>
+       <property name="text">
+        <string>...</string>
+       </property>
+       <property name="icon">
+        <iconset resource="../../resources.qrc">
+         <normaloff>:/icons/32x32/Undo.png</normaloff>:/icons/32x32/Undo.png</iconset>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="toolRedo">
+       <property name="enabled">
+        <bool>false</bool>
+       </property>
+       <property name="toolTip">
+        <string>Redo last change</string>
+       </property>
+       <property name="text">
+        <string>...</string>
+       </property>
+       <property name="icon">
+        <iconset resource="../../resources.qrc">
+         <normaloff>:/icons/32x32/Redo.png</normaloff>:/icons/32x32/Redo.png</iconset>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../../resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/mouse/line/IScrOptRangeLine.ui b/src/mouse/line/IScrOptRangeLine.ui
new file mode 100644
index 0000000..6eb929f
--- /dev/null
+++ b/src/mouse/line/IScrOptRangeLine.ui
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>IScrOptRangeLine</class>
+ <widget class="QWidget" name="IScrOptRangeLine">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>92</width>
+    <height>43</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout">
+   <item>
+    <widget class="QToolButton" name="toolDelete">
+     <property name="toolTip">
+      <string>Delete all points between the first and last one.</string>
+     </property>
+     <property name="text">
+      <string>...</string>
+     </property>
+     <property name="icon">
+      <iconset resource="../../resources.qrc">
+       <normaloff>:/icons/32x32/DeleteMultiple.png</normaloff>:/icons/32x32/DeleteMultiple.png</iconset>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QToolButton" name="toolCalcRoute">
+     <property name="toolTip">
+      <string>Caclculate a route between the first and last selected point.</string>
+     </property>
+     <property name="text">
+      <string>...</string>
+     </property>
+     <property name="icon">
+      <iconset resource="../../resources.qrc">
+       <normaloff>:/icons/32x32/Apply.png</normaloff>:/icons/32x32/Apply.png</iconset>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../../resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/plot/IPlot.cpp b/src/plot/IPlot.cpp
index 931140a..f1e377c 100644
--- a/src/plot/IPlot.cpp
+++ b/src/plot/IPlot.cpp
@@ -170,7 +170,7 @@ void IPlot::newLine(const QPolygonF& line, const QString& label)
     data->lines.clear();
 
     QRectF r = line.boundingRect();
-    if((r.height() < 0) || (r.width() < 0))
+    if((r.height() < 0) || (r.width() < 0) || line.isEmpty())
     {
         data->badData = true;
         return;
@@ -193,7 +193,7 @@ void IPlot::newLine(const QPolygonF& line, const QString& label)
 void IPlot::addLine(const QPolygonF& line, const QString& label)
 {
     QRectF r = line.boundingRect();
-    if(!r.isValid())
+    if(!r.isValid() || line.isEmpty())
     {
         return;
     }
@@ -384,7 +384,7 @@ void IPlot::mousePressEvent(QMouseEvent * e)
                     Later, when destroyed the slots will be disconnected automatically.
                  */
                 delete scrOptRange;
-                scrOptRange = new CScrOptRangeTrk(e->pos(), trk, this);
+                scrOptRange = new CScrOptRangeTrk(e->pos(), trk, &dummyMouse, this);
                 connect(scrOptRange->toolHidePoints, SIGNAL(clicked()), this, SLOT(slotHidePoints()));
                 connect(scrOptRange->toolShowPoints, SIGNAL(clicked()), this, SLOT(slotShowPoints()));
                 connect(scrOptRange->toolCopy, SIGNAL(clicked()), this, SLOT(slotCopy()));
diff --git a/src/plot/IPlot.h b/src/plot/IPlot.h
index ad5cc70..f9d1e47 100644
--- a/src/plot/IPlot.h
+++ b/src/plot/IPlot.h
@@ -20,6 +20,7 @@
 #define IPLOT_H
 
 #include "gis/trk/CGisItemTrk.h"
+#include "mouse/CMouseDummy.h"
 #include "plot/CPlotData.h"
 #include <QWidget>
 
@@ -164,6 +165,8 @@ protected:
     mouse_click_state_e mouseClickState;
 
     QPointer<CScrOptRangeTrk> scrOptRange;
+
+    CMouseDummy dummyMouse;
 };
 
 #endif //IPLOT_H
diff --git a/src/qlgt/CQlgtDb.cpp b/src/qlgt/CQlgtDb.cpp
index 3cbbee7..2bbd359 100644
--- a/src/qlgt/CQlgtDb.cpp
+++ b/src/qlgt/CQlgtDb.cpp
@@ -16,7 +16,6 @@
 
 **********************************************************************************************/
 
-#include "qlgt/CImportDatabase.h"
 #include "qlgt/CQlb.h"
 #include "qlgt/CQlgtDb.h"
 #include "qlgt/CQlgtFolder.h"
@@ -25,6 +24,7 @@
 #include "qlgt/CQlgtWpt.h"
 #include "qlgt/CQmsDb.h"
 #include "qlgt/IQlgtOverlay.h"
+#include "tool/CImportDatabase.h"
 
 #include "gis/WptIcons.h"
 #include "gis/db/macros.h"
@@ -33,6 +33,8 @@
 #include "gis/trk/CGisItemTrk.h"
 #include "gis/wpt/CGisItemWpt.h"
 
+#include "CMainWindow.h"
+
 #include <QtSql>
 #include <QtWidgets>
 
@@ -300,8 +302,9 @@ void CQlgtDb::migrateDB(int version)
                 return;
             }
 
+            const int total = query.size();
             quint32 progCnt = 0;
-            PROGRESS_SETUP(tr("Migrating database from version 4 to 5."), query.size());
+            PROGRESS_SETUP(tr("Migrating database from version 4 to 5."), &CMainWindow::self());
 
             while(query.next())
             {
@@ -337,7 +340,7 @@ void CQlgtDb::migrateDB(int version)
                     return;
                 }
 
-                PROGRESS(progCnt++, continue);
+                PROGRESS(progCnt++, total, continue);
             }
             break;
         }
@@ -353,8 +356,9 @@ void CQlgtDb::migrateDB(int version)
                 return;
             }
 
+            const int total = query.size();
             quint32 progCnt = 0;
-            PROGRESS_SETUP(tr("Migrating database from version 5 to 6."), query.size());
+            PROGRESS_SETUP(tr("Migrating database from version 5 to 6."), &CMainWindow::self());
 
             while(query.next())
             {
@@ -393,7 +397,7 @@ void CQlgtDb::migrateDB(int version)
                     return;
                 }
 
-                PROGRESS(progCnt++, continue);
+                PROGRESS(progCnt++, total, continue);
             }
 
             break;
@@ -410,8 +414,9 @@ void CQlgtDb::migrateDB(int version)
                 return;
             }
 
+            const int total = query.size();
             quint32 progCnt = 0;
-            PROGRESS_SETUP(tr("Migrating database from version 6 to 7."), query.size());
+            PROGRESS_SETUP(tr("Migrating database from version 6 to 7."), &CMainWindow::self());
 
             while(query.next())
             {
@@ -469,7 +474,7 @@ void CQlgtDb::migrateDB(int version)
                     return;
                 }
 
-                PROGRESS(progCnt++, continue);
+                PROGRESS(progCnt++, total, continue);
             }
 
             break;
@@ -477,7 +482,7 @@ void CQlgtDb::migrateDB(int version)
 
         case 8:
         {
-            PROGRESS_SETUP(tr("Migrating database from version 7 to 8."), 1);
+            PROGRESS_SETUP(tr("Migrating database from version 7 to 8."), &CMainWindow::self());
 
             if(!query.exec( "CREATE TABLE diarys ("
                             "id             INTEGER PRIMARY KEY AUTOINCREMENT,"
@@ -493,7 +498,7 @@ void CQlgtDb::migrateDB(int version)
                 return;
             }
 
-            PROGRESS(1, return );
+            PROGRESS(1, 1, return );
             break;
         }
 
@@ -506,7 +511,7 @@ void CQlgtDb::migrateDB(int version)
             QFile f(path.absoluteFilePath(name));
             f.copy(path.absoluteFilePath("qlgt_save_v4.db"));
 
-            PROGRESS_SETUP(tr("Migrating database from version 8 to 9."), 1);
+            PROGRESS_SETUP(tr("Migrating database from version 8 to 9."), &CMainWindow::self());
 
             if(!query.exec("ALTER TABLE folders ADD COLUMN locked BOOLEAN DEFAULT FALSE"))
             {
@@ -515,7 +520,7 @@ void CQlgtDb::migrateDB(int version)
                 return;
             }
 
-            PROGRESS(1, return );
+            PROGRESS(1, 1, return );
             break;
         }
         }
diff --git a/src/qlgt/CQmsDb.cpp b/src/qlgt/CQmsDb.cpp
index 6ac3f3f..4b3de93 100644
--- a/src/qlgt/CQmsDb.cpp
+++ b/src/qlgt/CQmsDb.cpp
@@ -24,7 +24,6 @@
 #include "gis/rte/CGisItemRte.h"
 #include "gis/trk/CGisItemTrk.h"
 #include "gis/wpt/CGisItemWpt.h"
-#include "qlgt/CImportDatabase.h"
 #include "qlgt/CQlgtDb.h"
 #include "qlgt/CQlgtFolder.h"
 #include "qlgt/CQlgtRoute.h"
@@ -32,6 +31,7 @@
 #include "qlgt/CQlgtWpt.h"
 #include "qlgt/CQmsDb.h"
 #include "qlgt/IQlgtOverlay.h"
+#include "tool/CImportDatabase.h"
 
 #include <QtSql>
 #include <QtWidgets>
diff --git a/src/resources.qrc b/src/resources.qrc
index 789ee00..f1c6629 100644
--- a/src/resources.qrc
+++ b/src/resources.qrc
@@ -23,6 +23,7 @@
         <file>icons/32x32/3DFix.png</file>
         <file>icons/32x32/Add.png</file>
         <file>icons/32x32/AddMapWorkspace.png</file>
+        <file>icons/32x32/CloneMapWorkspace.png</file>
         <file>icons/32x32/Cancel.png</file>
         <file>icons/32x32/Check.png</file>
         <file>icons/32x32/DeleteMultiple.png</file>
@@ -71,6 +72,7 @@
         <file>icons/32x32/QmsProject.png</file>
         <file>icons/32x32/DBProject.png</file>
         <file>icons/32x32/Route.png</file>
+        <file>icons/32x32/RouteSetup.png</file>        
         <file>icons/32x32/Close.png</file>
         <file>icons/32x32/Track.png</file>
         <file>icons/32x32/EditDetails.png</file>
@@ -101,6 +103,7 @@
         <file>icons/32x32/Tainted.png</file>
         <file>icons/32x32/AddWpt.png</file>
         <file>icons/32x32/AddTrk.png</file>
+        <file>icons/32x32/AddRte.png</file>
         <file>icons/32x32/AddArea.png</file>
         <file>icons/32x32/AddProject.png</file>
         <file>icons/32x32/LineMove.png</file>
@@ -143,11 +146,15 @@
         <file>icons/32x32/Bubble.png</file>
         <file>icons/32x32/MoveArrow.png</file>
         <file>icons/32x32/SizeArrow.png</file>
+        <file>icons/32x32/A.png</file>
+        <file>icons/32x32/V.png</file>
+        <file>icons/32x32/O.png</file>
 
         <file>icons/48x48/2DFix.png</file>
         <file>icons/48x48/3DFix.png</file>
         <file>icons/48x48/Add.png</file>
         <file>icons/48x48/AddMapWorkspace.png</file>
+        <file>icons/48x48/CloneMapWorkspace.png</file>
         <file>icons/48x48/Cancel.png</file>
         <file>icons/48x48/Check.png</file>
         <file>icons/48x48/DeleteMultiple.png</file>
@@ -196,6 +203,7 @@
         <file>icons/48x48/QmsProject.png</file>
         <file>icons/48x48/DBProject.png</file>
         <file>icons/48x48/Route.png</file>
+        <file>icons/48x48/RouteSetup.png</file>        
         <file>icons/48x48/Close.png</file>
         <file>icons/48x48/Track.png</file>
         <file>icons/48x48/EditDetails.png</file>
@@ -226,6 +234,7 @@
         <file>icons/48x48/Tainted.png</file>
         <file>icons/48x48/AddWpt.png</file>
         <file>icons/48x48/AddTrk.png</file>
+        <file>icons/48x48/AddRte.png</file>
         <file>icons/48x48/AddArea.png</file>
         <file>icons/48x48/AddProject.png</file>
         <file>icons/48x48/LineMove.png</file>
@@ -268,6 +277,10 @@
         <file>icons/48x48/Bubble.png</file>
         <file>icons/48x48/MoveArrow.png</file>
         <file>icons/48x48/SizeArrow.png</file>
+        <file>icons/48x48/A.png</file>
+        <file>icons/48x48/V.png</file>
+        <file>icons/48x48/O.png</file>
+
 
 
         <file>icons/cache/32x32/bluepin.png</file>
@@ -325,10 +338,12 @@
         <file>icons/waypoints/32x32/Waypoint.png</file>
         <file>cursors/cursorArrow.png</file>
         <file>cursors/cursorMove.png</file>
+        <file>cursors/cursorMovePoint.png</file>
         <file>cursors/cursorMoveMap.png</file>
         <file>cursors/cursorMoveWpt.png</file>
         <file>cursors/cursorMoveLine.png</file>
         <file>cursors/cursorMoveArea.png</file>
+        <file>cursors/cursorDelete.png</file>
         <file>cursors/cursorSelectRange.png</file>
         <file>cursors/cursorAdd.png</file>
         <file>cursors/wptHighlight.png</file>
@@ -346,5 +361,9 @@
         <file>map/OSM_Topo.tms</file>
         <file>map/OpenCycleMap.tms</file>
 
+        <file>xml/routino/routino-profiles.xml</file>
+        <file>xml/routino/routino-translations.xml</file>
+        <file>xml/routino/routino-tagging.xml</file>
+
     </qresource>
 </RCC>
diff --git a/src/qlgt/CImportDatabase.cpp b/src/tool/CImportDatabase.cpp
similarity index 98%
rename from src/qlgt/CImportDatabase.cpp
rename to src/tool/CImportDatabase.cpp
index 5e80591..3a733e1 100644
--- a/src/qlgt/CImportDatabase.cpp
+++ b/src/tool/CImportDatabase.cpp
@@ -17,8 +17,8 @@
 **********************************************************************************************/
 
 #include "helpers/CSettings.h"
-#include "qlgt/CImportDatabase.h"
 #include "qlgt/CQlgtDb.h"
+#include "tool/CImportDatabase.h"
 
 #include <QtWidgets>
 
diff --git a/src/qlgt/CImportDatabase.h b/src/tool/CImportDatabase.h
similarity index 100%
rename from src/qlgt/CImportDatabase.h
rename to src/tool/CImportDatabase.h
diff --git a/src/map/CMapVrtBuilder.cpp b/src/tool/CMapVrtBuilder.cpp
similarity index 59%
rename from src/map/CMapVrtBuilder.cpp
rename to src/tool/CMapVrtBuilder.cpp
index aa578d4..25ae03c 100644
--- a/src/map/CMapVrtBuilder.cpp
+++ b/src/tool/CMapVrtBuilder.cpp
@@ -22,8 +22,7 @@
 #include <QtWidgets>
 
 CMapVrtBuilder::CMapVrtBuilder(QWidget *parent)
-    : QWidget(parent)
-    , tainted(false)
+    : IToolShell(textBrowser, parent)
 {
     setupUi(this);
     setObjectName(tr("Build GDAL VRT"));
@@ -32,10 +31,6 @@ CMapVrtBuilder::CMapVrtBuilder(QWidget *parent)
     connect(toolTargetFile, SIGNAL(clicked()), this, SLOT(slotSelectTargetFile()));
     connect(pushStart, SIGNAL(clicked()), this, SLOT(slotStart()));
 
-    connect(&cmd, SIGNAL(readyReadStandardError()), this, SLOT(slotStderr()));
-    connect(&cmd, SIGNAL(readyReadStandardOutput()), this, SLOT(slotStdout()));
-    connect(&cmd, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(slotFinished(int,QProcess::ExitStatus)));
-
     pushStart->setDisabled(true);
 }
 
@@ -124,75 +119,10 @@ void CMapVrtBuilder::slotStart()
     cmd.start("gdalbuildvrt", args);
 }
 
-
-void CMapVrtBuilder::slotStderr()
-{
-    QString str;
-    textBrowser->setTextColor(Qt::red);
-
-    str = cmd.readAllStandardError();
-
-#ifndef WIN32
-    if(str[0] == '\r')
-    {
-        textBrowser->moveCursor( QTextCursor::End, QTextCursor::MoveAnchor );
-        textBrowser->moveCursor( QTextCursor::StartOfLine, QTextCursor::MoveAnchor );
-        textBrowser->moveCursor( QTextCursor::End, QTextCursor::KeepAnchor );
-        textBrowser->textCursor().removeSelectedText();
-
-        str = str.split("\r").last();
-    }
-#endif
-
-    textBrowser->insertPlainText(str);
-    textBrowser->verticalScrollBar()->setValue(textBrowser->verticalScrollBar()->maximum());
-
-    tainted = true;
-}
-
-void CMapVrtBuilder::slotStdout()
-{
-    QString str;
-    textBrowser->setTextColor(Qt::blue);
-    str = cmd.readAllStandardOutput();
-
-#ifndef WIN32
-    if(str[0] == '\r')
-    {
-        textBrowser->moveCursor( QTextCursor::End, QTextCursor::MoveAnchor );
-        textBrowser->moveCursor( QTextCursor::StartOfLine, QTextCursor::MoveAnchor );
-        textBrowser->moveCursor( QTextCursor::End, QTextCursor::KeepAnchor );
-        textBrowser->textCursor().removeSelectedText();
-
-        str = str.split("\r").last();
-    }
-#endif
-
-    textBrowser->insertPlainText(str);
-    textBrowser->verticalScrollBar()->setValue(textBrowser->verticalScrollBar()->maximum());
-}
-
-void CMapVrtBuilder::stdOut(const QString& str, bool gui)
-{
-    textBrowser->setTextColor(Qt::black);
-    textBrowser->append(str);
-}
-
-
-void CMapVrtBuilder::stdErr(const QString& str, bool gui)
-{
-    textBrowser->setTextColor(Qt::red);
-    textBrowser->append(str);
-}
-
-
-void CMapVrtBuilder::slotFinished(int exitCode, QProcess::ExitStatus status)
+void CMapVrtBuilder::finished(int exitCode, QProcess::ExitStatus status)
 {
-    output.clear();
-
-    if(exitCode || status)
-    {
-        textBrowser->setTextColor(Qt::red);
-        textBrowser->append(tr("!!! failed !!!\n"));
-    }
+    textBrowser->setTextColor(Qt::darkGreen);
+    textBrowser->append(tr("!!! done !!!\n"));
+    pushStart->setEnabled(true);
+    return;
 }
diff --git a/src/map/CMapVrtBuilder.h b/src/tool/CMapVrtBuilder.h
similarity index 76%
copy from src/map/CMapVrtBuilder.h
copy to src/tool/CMapVrtBuilder.h
index d7df331..ccf9f5f 100644
--- a/src/map/CMapVrtBuilder.h
+++ b/src/tool/CMapVrtBuilder.h
@@ -19,13 +19,13 @@
 #ifndef CMAPVRTBUILDER_H
 #define CMAPVRTBUILDER_H
 
+#include "tool/IToolShell.h"
 #include "ui_IMapVrtBuilder.h"
-#include <QProcess>
 #include <QWidget>
 
-class CMapVrtBuilder : public QWidget, private Ui::IMapVrtBuilder
+class CMapVrtBuilder : public IToolShell, private Ui::IMapVrtBuilder
 {
-    Q_OBJECT;
+    Q_OBJECT
 public:
     CMapVrtBuilder(QWidget * parent);
     virtual ~CMapVrtBuilder();
@@ -35,21 +35,9 @@ private slots:
     void slotSelectTargetFile();
     void slotStart();
 
-    void slotStderr();
-    void slotStdout();
-    void slotFinished(int exitCode, QProcess::ExitStatus status);
-
-
 private:
+    void finished(int exitCode, QProcess::ExitStatus status);
     void enabelStartButton();
-    void stdOut(const QString& str, bool gui = false);
-    void stdErr(const QString& str, bool gui = false);
-
-
-    bool tainted;
-    QString output;
-
-    QProcess cmd;
 };
 
 #endif //CMAPVRTBUILDER_H
diff --git a/src/tool/CRoutinoDatabaseBuilder.cpp b/src/tool/CRoutinoDatabaseBuilder.cpp
new file mode 100644
index 0000000..76271b4
--- /dev/null
+++ b/src/tool/CRoutinoDatabaseBuilder.cpp
@@ -0,0 +1,193 @@
+/**********************************************************************************************
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+**********************************************************************************************/
+
+#include "helpers/CSettings.h"
+#include "tool/CRoutinoDatabaseBuilder.h"
+
+#include <QtWidgets>
+
+CRoutinoDatabaseBuilder::CRoutinoDatabaseBuilder(QWidget * parent)
+    : IToolShell(textBrowser, parent)
+    , first(true)
+    , tainted(false)
+    , last(false)
+{
+    setupUi(this);
+
+    setObjectName(tr("Create Routino Database"));
+
+    connect(toolSourceFiles, SIGNAL(clicked()), this, SLOT(slotSelectSourceFiles()));
+    connect(toolTargetPath, SIGNAL(clicked()), this, SLOT(slotSelectTargetPath()));
+    connect(pushStart, SIGNAL(clicked()), this, SLOT(slotStart()));
+    connect(lineTargetPrefix, SIGNAL(textChanged(QString)), this, SLOT(enabelStartButton()));
+
+    pushStart->setDisabled(true);
+
+    QFile _translations("://xml/routino/routino-tagging.xml");
+    _translations.open(QIODevice::ReadOnly);
+
+    xmlTagging.open();
+    xmlTagging.write(_translations.readAll());
+    xmlTagging.close();
+
+    SETTINGS;
+    QString path = cfg.value("RoutinoDatabaseBuilder/targetPath",QDir::homePath()).toString();
+
+    labelTargetPath->setText(path);
+}
+
+CRoutinoDatabaseBuilder::~CRoutinoDatabaseBuilder()
+{
+}
+
+void CRoutinoDatabaseBuilder::slotSelectSourceFiles()
+{
+    SETTINGS;
+    QString path = cfg.value("RoutinoDatabaseBuilder/sourcePath",QDir::homePath()).toString();
+
+    QStringList files = QFileDialog::getOpenFileNames(this, tr("Select files..."), path, "OSM Database (*.pbf)");
+    if(files.isEmpty())
+    {
+        return;
+    }
+
+    QFileInfo fi(files.first());
+    path = fi.absolutePath();
+    cfg.setValue("RoutinoDatabaseBuilder/sourcePath", path);
+
+    listWidget->clear();
+    foreach(const QString &file, files)
+    {
+        new QListWidgetItem(QIcon("://icons/32x32/Map.png"), file, listWidget);
+    }
+
+    enabelStartButton();
+}
+
+void CRoutinoDatabaseBuilder::slotSelectTargetPath()
+{
+    SETTINGS;
+    QString path = cfg.value("RoutinoDatabaseBuilder/targetPath",QDir::homePath()).toString();
+
+    path = QFileDialog::getExistingDirectory(this, tr("Select target path..."), path);
+    if(path.isEmpty())
+    {
+        return;
+    }
+
+    cfg.setValue("RoutinoDatabaseBuilder/targetPath", path);
+
+
+    labelTargetPath->setText(path);
+
+    enabelStartButton();
+}
+
+
+void CRoutinoDatabaseBuilder::enabelStartButton()
+{
+    pushStart->setDisabled(true);
+    if(listWidget->count() == 0)
+    {
+        return;
+    }
+    if(labelTargetPath->text() == "-")
+    {
+        return;
+    }
+
+    if(lineTargetPrefix->text().isEmpty())
+    {
+        return;
+    }
+
+    pushStart->setEnabled(true);
+}
+
+
+void CRoutinoDatabaseBuilder::slotStart()
+{
+
+    pushStart->setDisabled(true);
+
+    sourceFiles.clear();
+    foreach(const QListWidgetItem * item, listWidget->findItems("*", Qt::MatchWildcard))
+    {
+        sourceFiles << item->text();
+    }
+
+    targetPrefix    = lineTargetPrefix->text();
+    targetPath      = labelTargetPath->text();
+    first           = true;
+    last            = false;
+
+    textBrowser->clear();
+
+    slotFinished(0,QProcess::NormalExit);
+}
+
+void CRoutinoDatabaseBuilder::finished(int exitCode, QProcess::ExitStatus status)
+{
+    if(last)
+    {
+        textBrowser->setTextColor(Qt::darkGreen);
+        textBrowser->append(tr("!!! done !!!\n"));
+        pushStart->setEnabled(true);
+        return;
+    }
+
+    if(sourceFiles.isEmpty())
+    {
+        QStringList args;
+
+        args << QString("--dir=%1").arg(targetPath);
+        args << QString("--prefix=%1").arg(targetPrefix);
+        args << QString("--tagging=%1").arg(xmlTagging.fileName());
+        args << "--process-only";
+
+        stdOut("planetsplitter " +  args.join(" ") + "\n");
+        cmd.start("planetsplitter", args);
+
+        last = true;
+    }
+    else
+    {
+        QStringList args;
+
+        args << QString("--dir=%1").arg(targetPath);
+        args << QString("--prefix=%1").arg(targetPrefix);
+        args << QString("--tagging=%1").arg(xmlTagging.fileName());
+
+        if(first)
+        {
+            first = false;
+            args << "--parse-only";
+        }
+        else
+        {
+            args << "--parse-only" << "--append";
+        }
+
+        args << sourceFiles.first();
+        sourceFiles.pop_front();
+
+
+        stdOut("planetsplitter " +  args.join(" ") + "\n");
+        cmd.start("planetsplitter", args);
+    }
+}
diff --git a/src/map/CMapVrtBuilder.h b/src/tool/CRoutinoDatabaseBuilder.h
similarity index 59%
copy from src/map/CMapVrtBuilder.h
copy to src/tool/CRoutinoDatabaseBuilder.h
index d7df331..f3642e4 100644
--- a/src/map/CMapVrtBuilder.h
+++ b/src/tool/CRoutinoDatabaseBuilder.h
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -16,41 +16,41 @@
 
 **********************************************************************************************/
 
-#ifndef CMAPVRTBUILDER_H
-#define CMAPVRTBUILDER_H
+#ifndef CROUTINODATABASEBUILDER_H
+#define CROUTINODATABASEBUILDER_H
 
-#include "ui_IMapVrtBuilder.h"
-#include <QProcess>
-#include <QWidget>
+#include "tool/IToolShell.h"
+#include "ui_IRoutinoDatabaseBuilder.h"
+#include <QTemporaryFile>
 
-class CMapVrtBuilder : public QWidget, private Ui::IMapVrtBuilder
+
+class CRoutinoDatabaseBuilder : public IToolShell, private Ui::IRoutinoDatabaseBuilder
 {
-    Q_OBJECT;
+    Q_OBJECT
 public:
-    CMapVrtBuilder(QWidget * parent);
-    virtual ~CMapVrtBuilder();
+    CRoutinoDatabaseBuilder(QWidget * parent);
+    virtual ~CRoutinoDatabaseBuilder();
 
 private slots:
     void slotSelectSourceFiles();
-    void slotSelectTargetFile();
+    void slotSelectTargetPath();
     void slotStart();
 
-    void slotStderr();
-    void slotStdout();
-    void slotFinished(int exitCode, QProcess::ExitStatus status);
-
-
-private:
     void enabelStartButton();
-    void stdOut(const QString& str, bool gui = false);
-    void stdErr(const QString& str, bool gui = false);
 
+private:
+    void finished(int exitCode, QProcess::ExitStatus status);
 
+    bool first;
     bool tainted;
-    QString output;
+    bool last;
+
+    QStringList sourceFiles;
+    QString targetPrefix;
+    QString targetPath;
 
-    QProcess cmd;
+    QTemporaryFile xmlTagging;
 };
 
-#endif //CMAPVRTBUILDER_H
+#endif //CROUTINODATABASEBUILDER_H
 
diff --git a/src/qlgt/IImportDatabase.ui b/src/tool/IImportDatabase.ui
similarity index 100%
rename from src/qlgt/IImportDatabase.ui
rename to src/tool/IImportDatabase.ui
diff --git a/src/map/IMapVrtBuilder.ui b/src/tool/IMapVrtBuilder.ui
similarity index 100%
copy from src/map/IMapVrtBuilder.ui
copy to src/tool/IMapVrtBuilder.ui
diff --git a/src/map/IMapVrtBuilder.ui b/src/tool/IRoutinoDatabaseBuilder.ui
similarity index 73%
rename from src/map/IMapVrtBuilder.ui
rename to src/tool/IRoutinoDatabaseBuilder.ui
index 5d6405a..fd3e552 100644
--- a/src/map/IMapVrtBuilder.ui
+++ b/src/tool/IRoutinoDatabaseBuilder.ui
@@ -1,13 +1,13 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <ui version="4.0">
- <class>IMapVrtBuilder</class>
- <widget class="QWidget" name="IMapVrtBuilder">
+ <class>IRoutinoDatabaseBuilder</class>
+ <widget class="QWidget" name="IRoutinoDatabaseBuilder">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>980</width>
-    <height>616</height>
+    <width>988</width>
+    <height>712</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -15,7 +15,7 @@
   </property>
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
-    <layout class="QHBoxLayout" name="horizontalLayout_2">
+    <layout class="QHBoxLayout" name="horizontalLayout_3">
      <item>
       <widget class="QToolButton" name="toolSourceFiles">
        <property name="text">
@@ -34,7 +34,7 @@
       </widget>
      </item>
      <item>
-      <widget class="QLabel" name="label_4">
+      <widget class="QLabel" name="label_5">
        <property name="text">
         <string>Select source files:</string>
        </property>
@@ -48,10 +48,17 @@
    <item row="1" column="1">
     <widget class="QTextBrowser" name="textBrowser"/>
    </item>
+   <item row="2" column="1">
+    <widget class="QPushButton" name="pushStart">
+     <property name="text">
+      <string>Start</string>
+     </property>
+    </widget>
+   </item>
    <item row="2" column="0">
-    <layout class="QHBoxLayout" name="horizontalLayout">
+    <layout class="QHBoxLayout" name="horizontalLayout_4">
      <item>
-      <widget class="QToolButton" name="toolTargetFile">
+      <widget class="QToolButton" name="toolTargetPath">
        <property name="text">
         <string>...</string>
        </property>
@@ -68,7 +75,7 @@
       </widget>
      </item>
      <item>
-      <widget class="QLabel" name="label">
+      <widget class="QLabel" name="label_2">
        <property name="sizePolicy">
         <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
          <horstretch>0</horstretch>
@@ -76,27 +83,33 @@
         </sizepolicy>
        </property>
        <property name="text">
-        <string>Target Filename:</string>
+        <string>Target Path:</string>
        </property>
       </widget>
      </item>
      <item>
-      <widget class="QLabel" name="labelTargetFilename">
+      <widget class="QLabel" name="labelTargetPath">
        <property name="text">
         <string>-</string>
        </property>
       </widget>
      </item>
+     <item>
+      <widget class="QLabel" name="label_3">
+       <property name="text">
+        <string>File Prefix</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLineEdit" name="lineTargetPrefix"/>
+     </item>
     </layout>
    </item>
-   <item row="2" column="1">
-    <widget class="QPushButton" name="pushStart">
-     <property name="text">
-      <string>Start</string>
-     </property>
-    </widget>
-   </item>
   </layout>
+  <zorder>textBrowser</zorder>
+  <zorder>pushStart</zorder>
+  <zorder>listWidget</zorder>
  </widget>
  <resources>
   <include location="../resources.qrc"/>
diff --git a/src/tool/IToolShell.cpp b/src/tool/IToolShell.cpp
new file mode 100644
index 0000000..62ad41e
--- /dev/null
+++ b/src/tool/IToolShell.cpp
@@ -0,0 +1,134 @@
+/**********************************************************************************************
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+
+**********************************************************************************************/
+
+#include "IToolShell.h"
+
+#include <QtWidgets>
+
+IToolShell::IToolShell(QTextBrowser *&textBrowser, QWidget * parent)
+    : QWidget(parent)
+    , text(textBrowser)
+{
+    connect(&cmd, SIGNAL(readyReadStandardError()), this, SLOT(slotStderr()));
+    connect(&cmd, SIGNAL(readyReadStandardOutput()), this, SLOT(slotStdout()));
+    connect(&cmd, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(slotFinished(int,QProcess::ExitStatus)));
+}
+
+IToolShell::~IToolShell()
+{
+}
+
+void IToolShell::setOutputBrowser(QTextBrowser * text)
+{
+
+}
+
+
+void IToolShell::slotStderr()
+{
+    QString str;
+    text->setTextColor(Qt::red);
+    str = cmd.readAllStandardError();
+
+    if(str[0] == '\r')
+    {
+#ifdef WIN32
+        if(str.contains("\n"))
+        {
+            text->insertPlainText("\n");
+        }
+        else
+#endif // WIN32
+        {
+            text->moveCursor( QTextCursor::End, QTextCursor::MoveAnchor );
+            text->moveCursor( QTextCursor::StartOfLine, QTextCursor::MoveAnchor );
+            text->moveCursor( QTextCursor::End, QTextCursor::KeepAnchor );
+            text->textCursor().removeSelectedText();
+        }
+
+
+#ifdef WIN32
+        str = str.split("\r").last().remove("\r").remove("\n");
+#else
+        str = str.split("\r").last();
+#endif
+
+    }
+
+    text->insertPlainText(str);
+    text->verticalScrollBar()->setValue(text->verticalScrollBar()->maximum());
+}
+
+void IToolShell::slotStdout()
+{
+    QString str;
+    text->setTextColor(Qt::blue);
+    str = cmd.readAllStandardOutput();
+
+    if(str[0] == '\r')
+    {
+#ifdef WIN32
+        if(str.contains("\n"))
+        {
+            text->insertPlainText("\n");
+        }
+        else
+#endif // WIN32
+        {
+            text->moveCursor( QTextCursor::End, QTextCursor::MoveAnchor );
+            text->moveCursor( QTextCursor::StartOfLine, QTextCursor::MoveAnchor );
+            text->moveCursor( QTextCursor::End, QTextCursor::KeepAnchor );
+            text->textCursor().removeSelectedText();
+        }
+
+#ifdef WIN32
+        str = str.split("\r").last().remove("\r").remove("\n");
+#else
+        str = str.split("\r").last();
+#endif
+    }
+
+    text->insertPlainText(str);
+    text->verticalScrollBar()->setValue(text->verticalScrollBar()->maximum());
+}
+
+void IToolShell::stdOut(const QString& str, bool gui)
+{
+    text->setTextColor(Qt::black);
+    text->append(str);
+}
+
+
+void IToolShell::stdErr(const QString& str, bool gui)
+{
+    text->setTextColor(Qt::red);
+    text->append(str);
+}
+
+
+void IToolShell::slotFinished(int exitCode, QProcess::ExitStatus status)
+{
+    if(exitCode || status)
+    {
+        text->setTextColor(Qt::red);
+        text->append(tr("!!! failed !!!\n"));
+        return;
+    }
+
+    finished(exitCode, status);
+}
diff --git a/src/map/CMapVrtBuilder.h b/src/tool/IToolShell.h
similarity index 65%
rename from src/map/CMapVrtBuilder.h
rename to src/tool/IToolShell.h
index d7df331..a51bcc2 100644
--- a/src/map/CMapVrtBuilder.h
+++ b/src/tool/IToolShell.h
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -16,41 +16,37 @@
 
 **********************************************************************************************/
 
-#ifndef CMAPVRTBUILDER_H
-#define CMAPVRTBUILDER_H
+#ifndef ITOOLSHELL_H
+#define ITOOLSHELL_H
 
-#include "ui_IMapVrtBuilder.h"
 #include <QProcess>
 #include <QWidget>
 
-class CMapVrtBuilder : public QWidget, private Ui::IMapVrtBuilder
+class QTextBrowser;
+
+class IToolShell : public QWidget
 {
-    Q_OBJECT;
+    Q_OBJECT
 public:
-    CMapVrtBuilder(QWidget * parent);
-    virtual ~CMapVrtBuilder();
-
-private slots:
-    void slotSelectSourceFiles();
-    void slotSelectTargetFile();
-    void slotStart();
+    IToolShell(QTextBrowser *&textBrowser, QWidget *parent);
+    virtual ~IToolShell();
 
+protected slots:
     void slotStderr();
     void slotStdout();
-    void slotFinished(int exitCode, QProcess::ExitStatus status);
+    virtual void slotFinished(int exitCode, QProcess::ExitStatus status);
 
+protected:
+    virtual void finished(int exitCode, QProcess::ExitStatus status) = 0;
 
-private:
-    void enabelStartButton();
+    void setOutputBrowser(QTextBrowser * textBrowser);
     void stdOut(const QString& str, bool gui = false);
     void stdErr(const QString& str, bool gui = false);
 
-
-    bool tainted;
-    QString output;
-
     QProcess cmd;
+
+    QTextBrowser *& text;
 };
 
-#endif //CMAPVRTBUILDER_H
+#endif //ITOOLSHELL_H
 
diff --git a/src/xml/routino/routino-profiles.xml b/src/xml/routino/routino-profiles.xml
new file mode 100644
index 0000000..40c0aad
--- /dev/null
+++ b/src/xml/routino/routino-profiles.xml
@@ -0,0 +1,509 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!-- ============================================================
+     An XML format file containing Routino routing profiles
+
+     Part of the Routino routing software.
+     ============================================================
+     This file Copyright 2010-2014 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<routino-profiles xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                  xsi:noNamespaceSchemaLocation="http://www.routino.org/xml/routino-profiles.xsd">
+
+  <profile name="foot" transport="foot">
+    <speeds>
+      <speed highway="motorway"      kph="0" />
+      <speed highway="trunk"         kph="4" />
+      <speed highway="primary"       kph="4" />
+      <speed highway="secondary"     kph="4" />
+      <speed highway="tertiary"      kph="4" />
+      <speed highway="unclassified"  kph="4" />
+      <speed highway="residential"   kph="4" />
+      <speed highway="service"       kph="4" />
+      <speed highway="track"         kph="4" />
+      <speed highway="cycleway"      kph="4" />
+      <speed highway="path"          kph="4" />
+      <speed highway="steps"         kph="4" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="0" />
+      <preference highway="trunk"         percent="40" />
+      <preference highway="primary"       percent="50" />
+      <preference highway="secondary"     percent="60" />
+      <preference highway="tertiary"      percent="70" />
+      <preference highway="unclassified"  percent="80" />
+      <preference highway="residential"   percent="90" />
+      <preference highway="service"       percent="90" />
+      <preference highway="track"         percent="95" />
+      <preference highway="cycleway"      percent="95" />
+      <preference highway="path"          percent="100" />
+      <preference highway="steps"         percent="80" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="50" />
+      <property type="multilane"     percent="25" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="55" />
+      <property type="bicycleroute"  percent="55" />
+    </properties>
+    <restrictions>
+      <oneway obey="0" /> 
+      <turns  obey="0" /> 
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="horse" transport="horse">
+    <speeds>
+      <speed highway="motorway"      kph="0" />
+      <speed highway="trunk"         kph="8" />
+      <speed highway="primary"       kph="8" />
+      <speed highway="secondary"     kph="8" />
+      <speed highway="tertiary"      kph="8" />
+      <speed highway="unclassified"  kph="8" />
+      <speed highway="residential"   kph="8" />
+      <speed highway="service"       kph="8" />
+      <speed highway="track"         kph="8" />
+      <speed highway="cycleway"      kph="8" />
+      <speed highway="path"          kph="8" />
+      <speed highway="steps"         kph="0" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="0" />
+      <preference highway="trunk"         percent="25" />
+      <preference highway="primary"       percent="50" />
+      <preference highway="secondary"     percent="50" />
+      <preference highway="tertiary"      percent="75" />
+      <preference highway="unclassified"  percent="75" />
+      <preference highway="residential"   percent="75" />
+      <preference highway="service"       percent="75" />
+      <preference highway="track"         percent="100" />
+      <preference highway="cycleway"      percent="90" />
+      <preference highway="path"          percent="100" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="20" />
+      <property type="multilane"     percent="25" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="50" />
+      <property type="bicycleroute"  percent="50" />
+    </properties>
+    <restrictions>
+      <oneway obey="1" /> 
+      <turns  obey="1" /> 
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="wheelchair" transport="wheelchair">
+    <speeds>
+      <speed highway="motorway"      kph="0" />
+      <speed highway="trunk"         kph="4" />
+      <speed highway="primary"       kph="4" />
+      <speed highway="secondary"     kph="4" />
+      <speed highway="tertiary"      kph="4" />
+      <speed highway="unclassified"  kph="4" />
+      <speed highway="residential"   kph="4" />
+      <speed highway="service"       kph="4" />
+      <speed highway="track"         kph="4" />
+      <speed highway="cycleway"      kph="4" />
+      <speed highway="path"          kph="4" />
+      <speed highway="steps"         kph="4" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="0" />
+      <preference highway="trunk"         percent="40" />
+      <preference highway="primary"       percent="50" />
+      <preference highway="secondary"     percent="60" />
+      <preference highway="tertiary"      percent="70" />
+      <preference highway="unclassified"  percent="80" />
+      <preference highway="residential"   percent="90" />
+      <preference highway="service"       percent="90" />
+      <preference highway="track"         percent="95" />
+      <preference highway="cycleway"      percent="95" />
+      <preference highway="path"          percent="100" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="90" />
+      <property type="multilane"     percent="25" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="55" />
+      <property type="bicycleroute"  percent="55" />
+    </properties>
+    <restrictions>
+      <oneway obey="0" /> 
+      <turns  obey="0" /> 
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="bicycle" transport="bicycle">
+    <speeds>
+      <speed highway="motorway"      kph="0" />
+      <speed highway="trunk"         kph="20" />
+      <speed highway="primary"       kph="20" />
+      <speed highway="secondary"     kph="20" />
+      <speed highway="tertiary"      kph="20" />
+      <speed highway="unclassified"  kph="20" />
+      <speed highway="residential"   kph="20" />
+      <speed highway="service"       kph="20" />
+      <speed highway="track"         kph="20" />
+      <speed highway="cycleway"      kph="20" />
+      <speed highway="path"          kph="20" />
+      <speed highway="steps"         kph="0" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="0" />
+      <preference highway="trunk"         percent="30" />
+      <preference highway="primary"       percent="70" />
+      <preference highway="secondary"     percent="80" />
+      <preference highway="tertiary"      percent="90" />
+      <preference highway="unclassified"  percent="90" />
+      <preference highway="residential"   percent="90" />
+      <preference highway="service"       percent="90" />
+      <preference highway="track"         percent="90" />
+      <preference highway="cycleway"      percent="100" />
+      <preference highway="path"          percent="90" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="50" />
+      <property type="multilane"     percent="25" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="50" />
+      <property type="bicycleroute"  percent="60" />
+    </properties>
+    <restrictions>
+      <oneway obey="1" /> 
+      <turns  obey="1" /> 
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="moped" transport="moped">
+    <speeds>
+      <speed highway="motorway"      kph="48" />
+      <speed highway="trunk"         kph="48" />
+      <speed highway="primary"       kph="48" />
+      <speed highway="secondary"     kph="48" />
+      <speed highway="tertiary"      kph="48" />
+      <speed highway="unclassified"  kph="48" />
+      <speed highway="residential"   kph="48" />
+      <speed highway="service"       kph="32" />
+      <speed highway="track"         kph="16" />
+      <speed highway="cycleway"      kph="0" />
+      <speed highway="path"          kph="0" />
+      <speed highway="steps"         kph="0" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="0" />
+      <preference highway="trunk"         percent="90" />
+      <preference highway="primary"       percent="100" />
+      <preference highway="secondary"     percent="90" />
+      <preference highway="tertiary"      percent="80" />
+      <preference highway="unclassified"  percent="70" />
+      <preference highway="residential"   percent="60" />
+      <preference highway="service"       percent="80" />
+      <preference highway="track"         percent="0" />
+      <preference highway="cycleway"      percent="0" />
+      <preference highway="path"          percent="0" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="100" />
+      <property type="multilane"     percent="35" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="50" />
+      <property type="bicycleroute"  percent="50" />
+    </properties>
+    <restrictions>
+      <oneway obey="1" /> 
+      <turns  obey="1" /> 
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="motorcycle" transport="motorcycle">
+    <speeds>
+      <speed highway="motorway"      kph="112" />
+      <speed highway="trunk"         kph="96" />
+      <speed highway="primary"       kph="96" />
+      <speed highway="secondary"     kph="88" />
+      <speed highway="tertiary"      kph="80" />
+      <speed highway="unclassified"  kph="64" />
+      <speed highway="residential"   kph="48" />
+      <speed highway="service"       kph="32" />
+      <speed highway="track"         kph="16" />
+      <speed highway="cycleway"      kph="0" />
+      <speed highway="path"          kph="0" />
+      <speed highway="steps"         kph="0" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="100" />
+      <preference highway="trunk"         percent="100" />
+      <preference highway="primary"       percent="90" />
+      <preference highway="secondary"     percent="80" />
+      <preference highway="tertiary"      percent="70" />
+      <preference highway="unclassified"  percent="60" />
+      <preference highway="residential"   percent="50" />
+      <preference highway="service"       percent="80" />
+      <preference highway="track"         percent="0" />
+      <preference highway="cycleway"      percent="0" />
+      <preference highway="path"          percent="0" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="100" />
+      <property type="multilane"     percent="60" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="50" />
+      <property type="bicycleroute"  percent="50" />
+    </properties>
+    <restrictions>
+      <oneway obey="1" /> 
+      <turns  obey="1" /> 
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="motorcar" transport="motorcar">
+    <speeds>
+      <speed highway="motorway"      kph="112" />
+      <speed highway="trunk"         kph="96" />
+      <speed highway="primary"       kph="96" />
+      <speed highway="secondary"     kph="88" />
+      <speed highway="tertiary"      kph="80" />
+      <speed highway="unclassified"  kph="64" />
+      <speed highway="residential"   kph="48" />
+      <speed highway="service"       kph="32" />
+      <speed highway="track"         kph="16" />
+      <speed highway="cycleway"      kph="0" />
+      <speed highway="path"          kph="0" />
+      <speed highway="steps"         kph="0" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="100" />
+      <preference highway="trunk"         percent="100" />
+      <preference highway="primary"       percent="90" />
+      <preference highway="secondary"     percent="80" />
+      <preference highway="tertiary"      percent="70" />
+      <preference highway="unclassified"  percent="60" />
+      <preference highway="residential"   percent="50" />
+      <preference highway="service"       percent="80" />
+      <preference highway="track"         percent="0" />
+      <preference highway="cycleway"      percent="0" />
+      <preference highway="path"          percent="0" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="100" />
+      <property type="multilane"     percent="60" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="45" />
+      <property type="bicycleroute"  percent="45" />
+    </properties>
+    <restrictions>
+      <oneway obey="1" /> 
+      <turns  obey="1" /> 
+      <weight limit="0.0" />
+      <height limit="0.0" />
+      <width  limit="0.0" />
+      <length limit="0.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="goods" transport="goods">
+    <speeds>
+      <speed highway="motorway"      kph="96" />
+      <speed highway="trunk"         kph="96" />
+      <speed highway="primary"       kph="96" />
+      <speed highway="secondary"     kph="88" />
+      <speed highway="tertiary"      kph="80" />
+      <speed highway="unclassified"  kph="64" />
+      <speed highway="residential"   kph="48" />
+      <speed highway="service"       kph="32" />
+      <speed highway="track"         kph="16" />
+      <speed highway="cycleway"      kph="0" />
+      <speed highway="path"          kph="0" />
+      <speed highway="steps"         kph="0" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="100" />
+      <preference highway="trunk"         percent="100" />
+      <preference highway="primary"       percent="90" />
+      <preference highway="secondary"     percent="80" />
+      <preference highway="tertiary"      percent="70" />
+      <preference highway="unclassified"  percent="60" />
+      <preference highway="residential"   percent="50" />
+      <preference highway="service"       percent="80" />
+      <preference highway="track"         percent="0" />
+      <preference highway="cycleway"      percent="0" />
+      <preference highway="path"          percent="0" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="100" />
+      <property type="multilane"     percent="60" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="45" />
+      <property type="bicycleroute"  percent="45" />
+    </properties>
+    <restrictions>
+      <oneway obey="1" /> 
+      <turns  obey="1" /> 
+      <weight limit="5.0" />
+      <height limit="2.5" />
+      <width  limit="2.0" />
+      <length limit="5.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="hgv" transport="hgv">
+    <speeds>
+      <speed highway="motorway"      kph="89" />
+      <speed highway="trunk"         kph="80" />
+      <speed highway="primary"       kph="80" />
+      <speed highway="secondary"     kph="80" />
+      <speed highway="tertiary"      kph="80" />
+      <speed highway="unclassified"  kph="64" />
+      <speed highway="residential"   kph="48" />
+      <speed highway="service"       kph="32" />
+      <speed highway="track"         kph="16" />
+      <speed highway="cycleway"      kph="0" />
+      <speed highway="path"          kph="0" />
+      <speed highway="steps"         kph="0" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="100" />
+      <preference highway="trunk"         percent="100" />
+      <preference highway="primary"       percent="90" />
+      <preference highway="secondary"     percent="80" />
+      <preference highway="tertiary"      percent="70" />
+      <preference highway="unclassified"  percent="60" />
+      <preference highway="residential"   percent="50" />
+      <preference highway="service"       percent="80" />
+      <preference highway="track"         percent="0" />
+      <preference highway="cycleway"      percent="0" />
+      <preference highway="path"          percent="0" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="100" />
+      <property type="multilane"     percent="60" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="45" />
+      <property type="bicycleroute"  percent="45" />
+    </properties>
+    <restrictions>
+      <oneway obey="1" /> 
+      <turns  obey="1" /> 
+      <weight limit="10.0" />
+      <height limit="3.0" />
+      <width  limit="2.5" />
+      <length limit="6.0" />
+    </restrictions>
+  </profile>
+
+  <profile name="psv" transport="psv">
+    <speeds>
+      <speed highway="motorway"      kph="89" />
+      <speed highway="trunk"         kph="80" />
+      <speed highway="primary"       kph="80" />
+      <speed highway="secondary"     kph="80" />
+      <speed highway="tertiary"      kph="80" />
+      <speed highway="unclassified"  kph="64" />
+      <speed highway="residential"   kph="48" />
+      <speed highway="service"       kph="32" />
+      <speed highway="track"         kph="16" />
+      <speed highway="cycleway"      kph="0" />
+      <speed highway="path"          kph="0" />
+      <speed highway="steps"         kph="0" />
+      <speed highway="ferry"         kph="10" />
+    </speeds>
+    <preferences>
+      <preference highway="motorway"      percent="100" />
+      <preference highway="trunk"         percent="100" />
+      <preference highway="primary"       percent="90" />
+      <preference highway="secondary"     percent="80" />
+      <preference highway="tertiary"      percent="70" />
+      <preference highway="unclassified"  percent="60" />
+      <preference highway="residential"   percent="50" />
+      <preference highway="service"       percent="80" />
+      <preference highway="track"         percent="0" />
+      <preference highway="cycleway"      percent="0" />
+      <preference highway="path"          percent="0" />
+      <preference highway="steps"         percent="0" />
+      <preference highway="ferry"         percent="20" />
+    </preferences>
+    <properties>
+      <property type="paved"         percent="100" />
+      <property type="multilane"     percent="60" />
+      <property type="bridge"        percent="50" />
+      <property type="tunnel"        percent="50" />
+      <property type="footroute"     percent="45" />
+      <property type="bicycleroute"  percent="45" />
+    </properties>
+    <restrictions>
+      <oneway obey="1" /> 
+      <turns  obey="1" /> 
+      <weight limit="15.0" />
+      <height limit="3.0" />
+      <width  limit="2.5" />
+      <length limit="6.0" />
+    </restrictions>
+  </profile>
+
+</routino-profiles>
diff --git a/src/xml/routino/routino-tagging-nomodify.xml b/src/xml/routino/routino-tagging-nomodify.xml
new file mode 100644
index 0000000..62f3bfe
--- /dev/null
+++ b/src/xml/routino/routino-tagging-nomodify.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!-- ============================================================
+     An XML format file containing Routino tagging rules - copy the input file
+     directly to the output with no modifications (e.g. importing a file dumped
+     by filedumper).
+
+     Part of the Routino routing software.
+     ============================================================
+     This file Copyright 2010, 2011 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<routino-tagging xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xsi:noNamespaceSchemaLocation="http://www.routino.org/xml/routino-tagging.xsd">
+
+  <!-- - - - - - - - - - - Node rules - - - - - - - - - - -->
+
+  <node>
+
+    <!-- Copy everything from input to output -->
+
+    <if>
+      <output />
+    </if>
+
+  </node>
+
+  <!-- - - - - - - - - - - Way rules - - - - - - - - - - -->
+
+  <way>
+
+    <!-- Copy everything from input to output -->
+
+    <if>
+      <output />
+    </if>
+
+  </way>
+
+  <!-- - - - - - - - - - - Relation rules - - - - - - - - - - -->
+
+  <relation>
+
+    <!-- Copy everything from input to output -->
+
+    <if>
+      <output />
+    </if>
+
+  </relation>
+
+</routino-tagging>
diff --git a/src/xml/routino/routino-tagging.xml b/src/xml/routino/routino-tagging.xml
new file mode 100644
index 0000000..e2c4321
--- /dev/null
+++ b/src/xml/routino/routino-tagging.xml
@@ -0,0 +1,1025 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!-- ============================================================
+     An XML format file containing Routino tagging rules
+
+     Part of the Routino routing software.
+     ============================================================
+     This file Copyright 2010-2015 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<routino-tagging xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xsi:noNamespaceSchemaLocation="http://www.routino.org/xml/routino-tagging.xsd">
+
+  <!-- - - - - - - - - - - Node rules - - - - - - - - - - -->
+
+  <node>
+
+    <!-- Note: The default is that all transport types are allowed past a barrier;
+               access must be specified to disallow each transport type. -->
+
+    <if k="barrier">
+
+      <!-- Not useful barrier types (too generic) -->
+
+      <if k="barrier" v="gate"      > <unset/> </if>
+      <if k="barrier" v="lift_gate" > <unset/> </if>
+      <if k="barrier" v="block"     > <unset/> </if>
+
+      <!-- Not useful barrier types (generic entrances through barrier ways) -->
+
+      <if k="barrier" v="entrance"  > <unset/> </if>
+      <if k="barrier" v="sally_port"> <unset/> </if>
+      <if k="barrier" v="toll_booth"> <unset/> </if>
+
+      <!-- Barrier types -->
+
+      <if k="barrier" v="kissing_gate">
+        <set v="foot_only"/>
+      </if>
+
+      <if k="barrier" v="footgate">
+        <set v="foot_only"/>
+      </if>
+
+      <if k="barrier" v="stile">
+        <set v="foot_only"/>
+      </if>
+
+      <if k="barrier" v="v_stile">
+        <set v="foot_only"/>
+      </if>
+
+      <if k="barrier" v="turnstile">
+        <set v="foot_only"/>
+      </if>
+
+      <if k="barrier" v="squeeze">
+        <set v="foot_only"/>
+      </if>
+
+      <if k="barrier" v="squeeze_stile">
+        <set v="foot_only"/>
+      </if>
+
+      <if k="barrier" v="foot_only">
+        <output k="horse"      v="no"/>
+        <output k="wheelchair" v="no"/>
+        <output k="bicycle"    v="no"/>
+        <output k="moped"      v="no"/>
+        <output k="motorcycle" v="no"/>
+        <output k="motorcar"   v="no"/>
+        <output k="goods"      v="no"/>
+        <output k="hgv"        v="no"/>
+        <output k="psv"        v="no"/>
+
+        <unset k="barrier"/>
+      </if>
+
+      <if k="barrier" v="horse_stile">
+        <set v="not_wheeled"/>
+      </if>
+
+      <if k="barrier" v="horse_jump">
+        <set v="not_wheeled"/>
+      </if>
+
+      <if k="barrier" v="step_over">
+        <set v="not_wheeled"/>
+      </if>
+
+      <if k="barrier" v="not_wheeled">
+        <output k="wheelchair" v="no"/>
+        <output k="bicycle"    v="no"/>
+        <output k="moped"      v="no"/>
+        <output k="motorcycle" v="no"/>
+        <output k="motorcar"   v="no"/>
+        <output k="goods"      v="no"/>
+        <output k="hgv"        v="no"/>
+        <output k="psv"        v="no"/>
+
+        <unset k="barrier"/>
+      </if>
+
+      <if k="barrier" v="horse_barrier">
+        <set v="no_horse"/>
+      </if>
+
+      <if k="barrier" v="cattle_grid">
+        <set v="no_horse"/>
+      </if>
+
+      <if k="barrier" v="no_horse">
+        <output k="horse"      v="no"/>
+
+        <unset k="barrier"/>
+      </if>
+
+      <if k="barrier" v="motorcycle_barrier">
+        <set v="no_motorised"/>
+      </if>
+
+      <if k="barrier" v="no_motorised">
+        <output k="moped"      v="no"/>
+        <output k="motorcycle" v="no"/>
+        <output k="motorcar"   v="no"/>
+        <output k="goods"      v="no"/>
+        <output k="hgv"        v="no"/>
+        <output k="psv"        v="no"/>
+
+        <unset k="barrier"/>
+      </if>
+
+      <if k="barrier" v="bollard">
+        <set v="not_2plus_wheels"/>
+      </if>
+
+      <if k="barrier" v="car_barrier">
+        <set v="not_2plus_wheels"/>
+      </if>
+
+      <if k="barrier" v="car_trap">
+        <set v="not_2plus_wheels"/>
+      </if>
+
+      <if k="barrier" v="not_2plus_wheels">
+        <output k="motorcar"   v="no"/>
+        <output k="goods"      v="no"/>
+        <output k="hgv"        v="no"/>
+        <output k="psv"        v="no"/>
+
+        <unset k="barrier"/>
+      </if>
+
+      <if k="barrier">
+        <logerror message="ignoring it"/>
+      </if>
+
+    </if> <!-- k="barrier" -->
+
+    <!-- Normalisation of access tags -->
+
+    <if v="designated"  > <set v="yes"/> </if>
+    <if v="permissive"  > <set v="yes"/> </if>
+    <if v="destination" > <set v="yes"/> </if>
+    <if v="true"        > <set v="yes"/> </if>
+    <if v="public"      > <set v="yes"/> </if>
+    <if v="official"    > <set v="yes"/> </if>
+                           
+    <if v="unsuitable"  > <set v="no"/> </if>
+    <if v="private"     > <set v="no"/> </if>
+    <if v="limited"     > <set v="no"/> </if>
+    <if v="restricted"  > <set v="no"/> </if>
+    <if v="agricultural"> <set v="no"/> </if>
+    <if v="forestry"    > <set v="no"/> </if>
+
+    <!-- Generic access permissions for all transport types (to override defaults) -->
+
+    <if k="access">
+
+      <ifnot k="access" v="yes">
+        <output k="foot"       v="no"/>
+        <output k="horse"      v="no"/>
+        <output k="wheelchair" v="no"/>
+        <output k="bicycle"    v="no"/>
+        <output k="moped"      v="no"/>
+        <output k="motorcycle" v="no"/>
+        <output k="motorcar"   v="no"/>
+        <output k="goods"      v="no"/>
+        <output k="hgv"        v="no"/>
+        <output k="psv"        v="no"/>
+
+        <if k="access" v="foot">
+          <set k="foot" v="yes"/>
+          <logerror k="access" message="using 'access' = 'no' ; 'foot' = 'yes'"/>
+          <set k="access" v="no"/>
+        </if>
+
+        <ifnot k="access" v="no">
+          <logerror k="access" message="using 'no'"/>
+        </ifnot>
+      </ifnot>
+
+    </if> <!-- k="access" -->
+
+    <!-- Generic access permissions for classes of transport types -->
+
+    <if k="vehicle">
+
+      <ifnot k="vehicle" v="yes">
+        <output k="bicycle"    v="no"/>
+        <output k="moped"      v="no"/>
+        <output k="motorcycle" v="no"/>
+        <output k="motorcar"   v="no"/>
+        <output k="goods"      v="no"/>
+        <output k="hgv"        v="no"/>
+        <output k="psv"        v="no"/>
+
+        <ifnot k="vehicle" v="no">
+          <logerror k="vehicle" message="using 'no'"/>
+        </ifnot>
+      </ifnot>
+
+    </if> <!-- k="vehicle" -->
+
+    <if k="motor_vehicle">
+
+      <ifnot k="motor_vehicle" v="yes">
+        <output k="moped"      v="no"/>
+        <output k="motorcycle" v="no"/>
+        <output k="motorcar"   v="no"/>
+        <output k="goods"      v="no"/>
+        <output k="hgv"        v="no"/>
+        <output k="psv"        v="no"/>
+
+        <ifnot k="motor_vehicle" v="no">
+          <logerror k="motor_vehicle" message="using 'no'"/>
+        </ifnot>
+      </ifnot>
+
+    </if> <!-- k="motor_vehicle" -->
+
+    <!-- Specific access rules (to override the generic ones) -->
+
+    <if k="foot"      > <output/> </if>
+    <if k="horse"     > <output/> </if>
+    <if k="wheelchair"> <output/> </if>
+    <if k="bicycle"   > <output/> </if>
+    <if k="moped"     > <output/> </if>
+    <if k="motorcycle"> <output/> </if>
+    <if k="motorcar"  > <output/> </if>
+    <if k="goods"     > <output/> </if>
+    <if k="hgv"       > <output/> </if>
+    <if k="psv"       > <output/> </if>
+
+    <!-- Mini-roundabouts  -->
+
+    <if k="highway" v="mini_roundabout">
+      <output k="roundabout" v="yes"/>
+    </if>
+
+    <if k="junction" v="roundabout">
+      <output k="roundabout" v="yes"/>
+    </if>
+
+  </node>
+
+  <!-- - - - - - - - - - - Way rules - - - - - - - - - - -->
+
+  <way>
+
+    <!-- Note: The default is that no transport type is allowed on any highway;
+               access must be specified to allow each transport type. -->
+
+    <if k="route" v="ferry">
+      <set k="highway" v="ferry"/>
+    </if>
+
+    <if k="highway">
+
+      <!-- Not useful highway types (future highways) -->
+
+      <if k="highway" v="construction"> <unset/> </if>
+      <if k="highway" v="planned"     > <unset/> </if>
+      <if k="highway" v="proposed"    > <unset/> </if>
+
+      <!-- Not useful highway types (previous highways) -->
+
+      <if k="highway" v="no"          > <unset/> </if>
+      <if k="highway" v="abandoned"   > <unset/> </if>
+      <if k="highway" v="disused"     > <unset/> </if>
+
+      <!-- Not useful highway types (limited use highways) -->
+
+      <if k="highway" v="raceway"     > <unset/> </if>
+
+      <!-- Highway types (includes default access and default properties) -->
+
+      <if k="highway" v="motorway_link">
+        <set v="motorway"/>
+      </if>
+
+      <if k="highway" v="motorway">
+        <output k="highway"/>
+
+        <output k="motorcycle" v="yes"/>
+        <output k="motorcar"   v="yes"/>
+        <output k="goods"      v="yes"/>
+        <output k="hgv"        v="yes"/>
+        <output k="psv"        v="yes"/>
+
+        <output k="paved"      v="yes"/>
+        <output k="multilane"  v="yes"/>
+        <output k="oneway"     v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="trunk_link">
+        <set v="trunk"/>
+      </if>
+
+      <if k="highway" v="trunk">
+        <output k="highway"/>
+
+        <output k="bicycle"    v="yes"/>
+        <output k="moped"      v="yes"/>
+        <output k="motorcycle" v="yes"/>
+        <output k="motorcar"   v="yes"/>
+        <output k="goods"      v="yes"/>
+        <output k="hgv"        v="yes"/>
+        <output k="psv"        v="yes"/>
+
+        <output k="paved"      v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="primary_link">
+        <set v="primary"/>
+      </if>
+
+      <if k="highway" v="primary">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="horse"      v="yes"/>
+        <output k="wheelchair" v="no"/>
+        <output k="bicycle"    v="yes"/>
+        <output k="moped"      v="yes"/>
+        <output k="motorcycle" v="yes"/>
+        <output k="motorcar"   v="yes"/>
+        <output k="goods"      v="yes"/>
+        <output k="hgv"        v="yes"/>
+        <output k="psv"        v="yes"/>
+
+        <output k="paved"      v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="secondary_link">
+        <set v="secondary"/>
+      </if>
+
+      <if k="highway" v="secondary">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="horse"      v="yes"/>
+        <output k="wheelchair" v="yes"/>
+        <output k="bicycle"    v="yes"/>
+        <output k="moped"      v="yes"/>
+        <output k="motorcycle" v="yes"/>
+        <output k="motorcar"   v="yes"/>
+        <output k="goods"      v="yes"/>
+        <output k="hgv"        v="yes"/>
+        <output k="psv"        v="yes"/>
+
+        <output k="paved"      v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="tertiary_link">
+        <set v="tertiary"/>
+      </if>
+
+      <if k="highway" v="tertiary">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="horse"      v="yes"/>
+        <output k="wheelchair" v="yes"/>
+        <output k="bicycle"    v="yes"/>
+        <output k="moped"      v="yes"/>
+        <output k="motorcycle" v="yes"/>
+        <output k="motorcar"   v="yes"/>
+        <output k="goods"      v="yes"/>
+        <output k="hgv"        v="yes"/>
+        <output k="psv"        v="yes"/>
+
+        <output k="paved"      v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="minor">
+        <set k="highway" v="unclassified"/>
+      </if>
+
+      <if k="highway" v="road">
+        <set k="highway" v="unclassified"/>
+      </if>
+
+      <if k="highway" v="unclassified">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="horse"      v="yes"/>
+        <output k="wheelchair" v="yes"/>
+        <output k="bicycle"    v="yes"/>
+        <output k="moped"      v="yes"/>
+        <output k="motorcycle" v="yes"/>
+        <output k="motorcar"   v="yes"/>
+        <output k="goods"      v="yes"/>
+        <output k="hgv"        v="yes"/>
+        <output k="psv"        v="yes"/>
+
+        <output k="paved"      v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="living_street">
+        <set k="highway" v="residential"/>
+      </if>
+
+      <if k="highway" v="residential">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="horse"      v="yes"/>
+        <output k="wheelchair" v="yes"/>
+        <output k="bicycle"    v="yes"/>
+        <output k="moped"      v="yes"/>
+        <output k="motorcycle" v="yes"/>
+        <output k="motorcar"   v="yes"/>
+        <output k="goods"      v="yes"/>
+        <output k="hgv"        v="yes"/>
+        <output k="psv"        v="yes"/>
+
+        <output k="paved"      v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="access">
+        <set k="highway" v="service"/>
+      </if>
+
+      <if k="highway" v="services">
+        <set k="highway" v="service"/>
+      </if>
+
+      <if k="highway" v="rest_area">
+        <set k="highway" v="service"/>
+      </if>
+
+      <if k="highway" v="layby">
+        <set k="highway" v="service"/>
+      </if>
+
+      <if k="highway" v="service">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="horse"      v="yes"/>
+        <output k="wheelchair" v="yes"/>
+        <output k="bicycle"    v="yes"/>
+        <output k="moped"      v="yes"/>
+        <output k="motorcycle" v="yes"/>
+        <output k="motorcar"   v="yes"/>
+        <output k="goods"      v="yes"/>
+        <output k="hgv"        v="yes"/>
+        <output k="psv"        v="yes"/>
+
+        <output k="paved"      v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="byway">
+        <set k="highway" v="track"/>
+      </if>
+
+      <if k="highway" v="unsurfaced">
+        <set k="highway" v="track"/>
+      </if>
+
+      <if k="highway" v="unpaved">
+        <set k="highway" v="track"/>
+      </if>
+
+      <if k="highway" v="track">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="horse"      v="yes"/>
+        <output k="bicycle"    v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="tracktype" v="grade1">
+        <output k="paved"      v="yes"/>
+      </if>
+
+      <if k="highway" v="cycleway">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="wheelchair" v="yes"/>
+        <output k="bicycle"    v="yes"/>
+
+        <output k="paved"      v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="footway">
+        <set k="highway" v="path"/>
+      </if>
+
+      <if k="highway" v="bridleway">
+        <set k="highway" v="path"/>
+
+        <output k="horse"      v="yes"/>
+        <output k="bicycle"    v="yes"/>
+      </if>
+
+      <if k="highway" v="pedestrian">
+        <set k="highway" v="path"/>
+
+        <output k="paved"      v="yes"/>
+      </if>
+
+      <if k="highway" v="walkway">
+        <set k="highway"  v="path"/>
+
+        <output k="paved"      v="yes"/>
+      </if>
+
+      <if k="highway" v="trail">
+        <set k="highway"  v="path"/>
+
+        <output k="paved"      v="no"/>
+      </if>
+
+      <if k="highway" v="path">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+        <output k="wheelchair" v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="steps">
+        <output k="highway"/>
+
+        <output k="foot"       v="yes"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <if k="highway" v="ferry">
+        <output k="highway"/>
+
+        <unset k="highway"/>
+      </if>
+
+      <!-- Unrecognised highway type -->
+
+      <if k="highway">
+        <logerror message="ignoring it"/>
+      </if>
+
+      <!-- Normalisation of access tags -->
+
+      <if v="designated"  > <set v="yes"/> </if>
+      <if v="permissive"  > <set v="yes"/> </if>
+      <if v="destination" > <set v="yes"/> </if>
+      <if v="true"        > <set v="yes"/> </if>
+      <if v="public"      > <set v="yes"/> </if>
+      <if v="customers"   > <set v="yes"/> </if>
+      <if v="customer"    > <set v="yes"/> </if>
+      <if v="official"    > <set v="yes"/> </if>
+                           
+      <if v="unsuitable"  > <set v="no"/> </if>
+      <if v="private"     > <set v="no"/> </if>
+      <if v="limited"     > <set v="no"/> </if>
+      <if v="restricted"  > <set v="no"/> </if>
+      <if v="agricultural"> <set v="no"/> </if>
+      <if v="forestry"    > <set v="no"/> </if>
+
+      <!-- Generic access restrictions for all transport types (to subtract from highway specific defaults) -->
+
+      <if k="access">
+
+        <ifnot k="access" v="yes">
+          <output k="foot"       v="no"/>
+          <output k="horse"      v="no"/>
+          <output k="wheelchair" v="no"/>
+          <output k="bicycle"    v="no"/>
+          <output k="moped"      v="no"/>
+          <output k="motorcycle" v="no"/>
+          <output k="motorcar"   v="no"/>
+          <output k="goods"      v="no"/>
+          <output k="hgv"        v="no"/>
+          <output k="psv"        v="no"/>
+
+          <if k="access" v="foot">
+            <set k="foot" v="yes"/>
+            <logerror k="access" message="using 'access' = 'no' ; 'foot' = 'yes'"/>
+            <set k="access" v="no"/>
+          </if>
+
+          <if k="access" v="wheelchair">
+            <set k="wheelchair" v="yes"/>
+            <logerror k="access" message="using 'access' = 'no' ; 'wheelchair' = 'yes'"/>
+            <set k="access" v="no"/>
+          </if>
+
+          <if k="access" v="motor_vehicle">
+            <set k="motor_vehicle" v="yes"/>
+            <logerror k="access" message="using 'access' = 'no' ; 'motor_vehicle' = 'yes'"/>
+            <set k="access" v="no"/>
+          </if>
+
+          <if k="access" v="hgv">
+            <set k="hgv" v="yes"/>
+            <logerror k="access" message="using 'access' = 'no' ; 'hgv' = 'yes'"/>
+            <set k="access" v="no"/>
+          </if>
+
+          <if k="access" v="bus">
+            <set v="psv" />
+          </if>
+
+          <if k="access" v="psv">
+            <set k="psv" v="yes"/>
+            <logerror k="access" message="using 'access' = 'no' ; 'psv' = 'yes'"/>
+            <set k="access" v="no"/>
+          </if>
+
+          <ifnot k="access" v="no">
+            <logerror k="access" message="using 'no'"/>
+          </ifnot>
+        </ifnot>
+
+      </if> <!-- k="access" -->
+
+      <!-- Access restrictions for classes of transport types (to subtract from highway specific defaults) -->
+
+      <if k="vehicle">
+
+        <ifnot k="vehicle" v="yes">
+          <output k="bicycle"    v="no"/>
+          <output k="moped"      v="no"/>
+          <output k="motorcycle" v="no"/>
+          <output k="motorcar"   v="no"/>
+          <output k="goods"      v="no"/>
+          <output k="hgv"        v="no"/>
+          <output k="psv"        v="no"/>
+
+          <ifnot k="vehicle" v="no">
+            <logerror k="vehicle" message="using 'no'"/>
+          </ifnot>
+        </ifnot>
+
+      </if> <!-- k="vehicle" -->
+
+      <if k="motor_vehicle">
+
+        <ifnot k="motor_vehicle" v="yes">
+          <output k="moped"      v="no"/>
+          <output k="motorcycle" v="no"/>
+          <output k="motorcar"   v="no"/>
+          <output k="goods"      v="no"/>
+          <output k="hgv"        v="no"/>
+          <output k="psv"        v="no"/>
+
+          <ifnot k="motor_vehicle" v="no">
+            <logerror k="motor_vehicle" message="using 'no'"/>
+          </ifnot>
+        </ifnot>
+
+      </if> <!-- k="motor_vehicle" -->
+
+      <!-- Other access permissions (to add to highway specific defaults with generic restrictions) -->
+
+      <if k="designation">
+
+        <if k="designation" v="restricted_byway">
+          <output k="foot"       v="yes"/>
+          <output k="horse"      v="yes"/>
+          <output k="wheelchair" v="yes"/>
+          <output k="bicycle"    v="yes"/>
+
+          <unset k="designation"/>
+        </if>
+
+        <if k="designation" v="public_byway">
+          <set v="byway_open_to_all_traffic"/>
+        </if>
+
+        <if k="designation" v="byway">
+          <set v="byway_open_to_all_traffic"/>
+        </if>
+
+        <if k="designation" v="byway_open_to_all_traffic">
+          <output k="foot"       v="yes"/>
+          <output k="horse"      v="yes"/>
+          <output k="wheelchair" v="yes"/>
+          <output k="bicycle"    v="yes"/>
+          <output k="moped"      v="yes"/>
+          <output k="motorcycle" v="yes"/>
+          <output k="motorcar"   v="yes"/>
+
+          <unset k="designation"/>
+        </if>
+
+        <if k="designation" v="permissive_bridleway">
+          <set v="bridleway"/>
+        </if>
+
+        <if k="designation" v="public_bridleway">
+          <set v="bridleway"/>
+        </if>
+
+        <if k="designation" v="bridleway">
+          <output k="foot"       v="yes"/>
+          <output k="horse"      v="yes"/>
+          <output k="wheelchair" v="yes"/>
+          <output k="bicycle"    v="yes"/>
+
+          <unset k="designation"/>
+        </if>
+
+        <if k="designation" v="public_cycleway">
+          <output k="foot"       v="yes"/>
+          <output k="wheelchair" v="yes"/>
+          <output k="bicycle"    v="yes"/>
+
+          <unset k="designation"/>
+        </if>
+
+        <if k="designation" v="permissive_footpath">
+          <set v="footpath"/>
+        </if>
+
+        <if k="designation" v="public_footpath">
+          <set v="footpath"/>
+        </if>
+
+        <if k="designation" v="footpath">
+          <output k="foot"       v="yes"/>
+          <output k="wheelchair" v="yes"/>
+
+          <unset k="designation"/>
+        </if>
+
+        <if k="designation">
+          <logerror message="ignoring it"/>
+        </if>
+
+      </if> <!-- k="designation" -->
+
+      <!-- Derived access rules (to override the generic ones) -->
+
+      <if k="motorroad" v="yes">
+        <output k="foot"       v="no"/>
+        <output k="horse"      v="no"/>
+        <output k="wheelchair" v="no"/>
+        <output k="bicycle"    v="no"/>
+        <output k="moped"      v="no"/>
+      </if>
+
+      <if k="footway">
+
+        <!-- Tags from http://taginfo.openstreetmap.org/keys/footway#values on 2013-02-09 -->
+
+        <if k="footway" v="sidewalk"> <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+        <if k="footway" v="both">     <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+        <if k="footway" v="left">     <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+        <if k="footway" v="right">    <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+        <if k="footway" v="yes">      <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+      </if>
+
+      <if k="sidewalk">
+
+        <!-- Tags from http://taginfo.openstreetmap.org/keys/sidewalk#values on 2013-02-09 -->
+
+        <if k="sidewalk" v="both">    <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+        <if k="sidewalk" v="left">    <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+        <if k="sidewalk" v="right">   <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+        <if k="sidewalk" v="yes">     <output k="foot" v="yes"/> <output k="wheelchair" v="yes"/> </if>
+      </if>
+
+      <if k="cycleway">
+
+        <!-- Tags from http://taginfo.openstreetmap.org/keys/cycleway#values on 2013-02-09 -->
+
+        <if k="cycleway" v="lane">   <output k="bicycle" v="yes"/> </if>
+        <if k="cycleway" v="track">  <output k="bicycle" v="yes"/> </if>
+        <if k="cycleway" v="shared"> <output k="bicycle" v="yes"/> </if>
+        <if k="cycleway" v="yes">    <output k="bicycle" v="yes"/> </if>
+
+        <if k="cycleway" v="opposite_lane">
+          <output k="bicycle" v="yes"/>
+          <output k="cyclebothways" v="yes"/>
+        </if>
+
+        <if k="cycleway" v="opposite_track">
+          <output k="bicycle" v="yes"/>
+          <output k="cyclebothways" v="yes"/>
+        </if>
+
+        <if k="cycleway" v="opposite">
+          <output k="bicycle" v="yes"/>
+          <output k="cyclebothways" v="yes"/>
+        </if>
+      </if>
+
+      <if k="oneway:bicycle" v="no">
+        <output k="bicycle" v="yes"/>
+        <output k="cyclebothways" v="yes"/>
+      </if>
+
+      <!-- Specific access rules (to override the generic ones) -->
+
+      <if k="foot"      > <output/> </if>
+      <if k="horse"     > <output/> </if>
+      <if k="wheelchair"> <output/> </if>
+      <if k="bicycle"   > <output/> </if>
+      <if k="moped"     > <output/> </if>
+      <if k="motorcycle"> <output/> </if>
+      <if k="motorcar"  > <output/> </if>
+      <if k="goods"     > <output/> </if>
+      <if k="hgv"       > <output/> </if>
+      <if k="psv"       > <output/> </if>
+
+      <!-- Normalisation of property tags -->
+
+      <if k="surface">
+
+        <!-- Tags from http://wiki.openstreetmap.org/wiki/Key:surface on 2012-11-21 -->
+
+        <if k="surface" v="asphalt">               <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="cobblestone">           <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="cobblestone:flattened"> <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="compacted">             <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="concrete">              <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="concrete:lanes">        <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="concrete:plates">       <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="dirt">                  <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="earth">                 <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="fine_gravel">           <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="grass">                 <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="grass_paver">           <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="gravel">                <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="ground">                <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="metal">                 <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="mud">                   <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="paved">                 <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="paving_stones">         <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="paving_stones:20">      <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="paving_stones:30">      <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="pebblestone">           <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="sand">                  <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="unpaved">               <set k="paved" v="no"/>  <unset k="surface"/> </if>
+        <if k="surface" v="wood">                  <set k="paved" v="no"/>  <unset k="surface"/> </if>
+
+        <!-- Other tags -->
+
+        <if k="surface" v="sealed">       <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="cement">       <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="tarmac">       <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="tar_and_chip"> <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="metalled">     <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="bricks">       <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="brick">        <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="brick_weave">  <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="setts">        <set k="paved" v="yes"/> <unset k="surface"/> </if>
+        <if k="surface" v="sett">         <set k="paved" v="yes"/> <unset k="surface"/> </if>
+
+        <if k="surface" v="unsealed">     <set k="paved" v="no"/> <unset k="surface"/> </if>
+        <if k="surface" v="soil">         <set k="paved" v="no"/> <unset k="surface"/> </if>
+        <if k="surface" v="stones">       <set k="paved" v="no"/> <unset k="surface"/> </if>
+        <if k="surface" v="stone">        <set k="paved" v="no"/> <unset k="surface"/> </if>
+        <if k="surface" v="pebbles">      <set k="paved" v="no"/> <unset k="surface"/> </if>
+        <if k="surface" v="hardcore">     <set k="paved" v="no"/> <unset k="surface"/> </if>
+        <if k="surface" v="bark">         <set k="paved" v="no"/> <unset k="surface"/> </if>
+
+        <if k="surface">
+          <logerror message="ignoring it"/>
+        </if>
+
+      </if> <!-- k="surface" -->
+
+      <if k="bridge">
+        <ifnot k="bridge" v="no">
+          <set k="bridge" v="yes"/>
+        </ifnot>
+      </if>
+
+      <if k="tunnel">
+        <ifnot k="tunnel" v="no">
+          <set k="tunnel" v="yes"/>
+        </ifnot>
+      </if>
+
+      <if k="junction" v="roundabout">
+        <output k="oneway"     v="yes"/>
+        <output k="roundabout" v="yes"/>
+      </if>
+
+      <!-- Specific property rules (to override the default ones) -->
+
+      <if k="paved"> <output/> </if>
+
+      <if k="lanes"> <output/> </if>
+
+      <if k="bridge"> <output/> </if>
+
+      <if k="tunnel"> <output/> </if>
+
+      <!-- Output the restriction tags -->
+
+      <if k="oneway"> <output/> </if>
+
+      <if k="maxspeed"> <output/> </if>
+
+      <if k="maxweight"> <output/> </if>
+      <if k="maxheight"> <output/> </if>
+      <if k="maxwidth" > <output/> </if>
+      <if k="maxlength"> <output/> </if>
+
+      <!-- Output the name and reference tags -->
+
+      <if k="name"> <output/> </if>
+      <if k="ref" > <output/> </if>
+
+      <!-- Output the area tag -->
+
+      <if k="area"> <output/> </if>
+
+    </if> <!-- k="highway" -->
+
+  </way>
+
+  <!-- - - - - - - - - - - Relation rules - - - - - - - - - - -->
+
+  <relation>
+
+    <if k="type">
+      <output/>
+    </if>
+
+    <!-- Copy route relations -->
+
+    <if k="route">
+
+      <if k="route" v="foot">
+        <output k="footroute" v="yes"/>
+      </if>
+
+      <if k="route" v="walking">
+        <output k="footroute" v="yes"/>
+      </if>
+
+      <if k="route" v="hiking">
+        <output k="footroute" v="yes"/>
+      </if>
+
+      <if k="route" v="foot;bicycle">
+        <output k="footroute"    v="yes"/>
+        <output k="bicycleroute" v="yes"/>
+      </if>
+
+      <if k="route" v="bicycle;foot">
+        <output k="footroute"    v="yes"/>
+        <output k="bicycleroute" v="yes"/>
+      </if>
+
+      <if k="route" v="bicycle">
+        <output k="bicycleroute" v="yes"/>
+      </if>
+
+    </if> <!-- k="route" -->
+
+    <!-- Pass through turn relations -->
+
+    <if k="restriction">
+      <output/>
+    </if>
+
+    <if k="except">
+
+      <if k="except" v="bus"> <set v="psv"/> </if>
+
+      <if k="except">
+        <output/>
+      </if>
+
+    </if>
+
+  </relation>
+
+</routino-tagging>
diff --git a/src/xml/routino/routino-translations.xml b/src/xml/routino/routino-translations.xml
new file mode 100644
index 0000000..25fa2a9
--- /dev/null
+++ b/src/xml/routino/routino-translations.xml
@@ -0,0 +1,577 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- ============================================================
+     An XML format file containing Routino output translations.
+
+     Part of the Routino routing software.
+     ============================================================
+     This file Copyright 2010-2014 Andrew M. Bishop
+
+     This program is free software: you can redistribute it and/or modify
+     it under the terms of the GNU Affero General Public License as published by
+     the Free Software Foundation, either version 3 of the License, or
+     (at your option) any later version.
+     ============================================================ -->
+
+<routino-translations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                      xsi:noNamespaceSchemaLocation="http://www.routino.org/xml/routino-translations.xsd">
+
+  <language lang="en">
+
+    <!-- Copyright of the data being routed, not of this file  -->
+    <copyright>
+      <creator string="Creator" text="Routino - http://www.routino.org/" />
+      <source  string="Source" text="Based on OpenStreetMap data from http://www.openstreetmap.org/" />
+      <license string="License" text="http://www.openstreetmap.org/copyright" />
+    </copyright>
+
+    <!-- Turn directions, 0 = ahead, -2 = left, +/-4 = behind, +2 = right -->
+    <turn direction="-4" string="Very sharp left" />
+    <turn direction="-3" string="Sharp left" />
+    <turn direction="-2" string="Left" />
+    <turn direction="-1" string="Slight left" />
+    <turn direction="0"  string="Straight on" />
+    <turn direction="1"  string="Slight right" />
+    <turn direction="2"  string="Right" />
+    <turn direction="3"  string="Sharp right" />
+    <turn direction="4"  string="Very sharp right" />
+
+    <!-- Heading directions, 0 = North, -2 = West, +/-4 = South, +2 = East -->
+    <heading direction="-4" string="South" />
+    <heading direction="-3" string="South-West" />
+    <heading direction="-2" string="West" />
+    <heading direction="-1" string="North-West" />
+    <heading direction="0"  string="North" />
+    <heading direction="1"  string="North-East" />
+    <heading direction="2"  string="East" />
+    <heading direction="3"  string="South-East" />
+    <heading direction="4"  string="South" />
+
+    <!-- Ordinals, 1 = first, 2 = second ... -->
+    <ordinal number="1"  string="First" />
+    <ordinal number="2"  string="Second" />
+    <ordinal number="3"  string="Third" />
+    <ordinal number="4"  string="Fourth" />
+    <ordinal number="5"  string="Fifth" />
+    <ordinal number="6"  string="Sixth" />
+    <ordinal number="7"  string="Seventh" />
+    <ordinal number="8"  string="Eighth" />
+    <ordinal number="9"  string="Ninth" />
+    <ordinal number="10" string="Tenth" />
+
+    <!-- Highway names -->
+    <highway type="motorway"     string="motorway" />
+    <highway type="trunk"        string="trunk road" />
+    <highway type="primary"      string="primary road" />
+    <highway type="secondary"    string="secondary road" />
+    <highway type="tertiary"     string="tertiary road" />
+    <highway type="unclassified" string="unclassified road" />
+    <highway type="residential"  string="residential road" />
+    <highway type="service"      string="service road" />
+    <highway type="track"        string="track" />
+    <highway type="cycleway"     string="cycleway" />
+    <highway type="path"         string="path" />
+    <highway type="steps"        string="steps" />
+    <highway type="ferry"        string="ferry" />
+
+    <!-- The type of route -->
+    <route type="shortest" string="Shortest" /> <!-- For the description and route name -->
+    <route type="quickest" string="Quickest" /> <!-- For the description and route name -->
+
+    <!-- HTML output -->
+    <output-html>
+      <waypoint type="waypoint"   string="Waypoint" /> <!-- For the chosen waypoints -->
+      <waypoint type="junction"   string="Junction" /> <!-- For the interesting junctions -->
+      <waypoint type="roundabout" string="Roundabout" /> <!-- For roundabouts -->
+
+      <title text="%s Route" /> <!-- %s = [shortest|quickest] -->
+
+      <start   string="Start" text="At %s, head %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [heading] -->
+      <node    string="At" text="%s, go %s heading %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [turn], 3rd %s = [heading] -->
+      <rbnode  string="Leave" text="%s, take the %s exit heading %s" /> <!-- 1st %s = [roundabout], 2nd %s = [first|second|...], 3rd %s = [heading] -->
+      <segment string="Follow" text="%s for %.3f km, %.1f min" /> <!-- 1st %s = street name -->
+      <stop    string="Stop" text="At %s" /> <!-- 1st %s = [waypoint|junction] -->
+      <total   string="Total" text="%.1f km, %.0f minutes" />
+    </output-html>
+
+    <!-- GPX output -->
+    <output-gpx>
+      <waypoint type="start" string="START" /> <!-- For the first route waypoint -->
+      <waypoint type="inter" string="INTER" /> <!-- For the intermediate route waypoints -->
+      <waypoint type="trip" string="TRIP" /> <!-- For the other route points -->
+      <waypoint type="finish" string="FINISH"/> <!-- For the last route waypoint -->
+
+      <desc  text="%s route between 'start' and 'finish' waypoints" /> <!-- %s = [shortest|quickest] -->
+      <name  text="%s route" /> <!-- %s = [shortest|quickest] -->
+      <step  text="%s on '%s' for %.3f km, %.1f min" /> <!-- 1st %s = [turn], 2nd %s = street name -->
+      <final text="Total Journey %.1f km, %.0f minutes" />
+    </output-gpx>
+
+  </language>
+
+  <language lang="de">
+
+    <!-- Copyright of the data being routed, not of this file  -->
+    <copyright>
+      <creator string="Urheber" text="Routino - http://www.routino.org/" />
+      <source  string="Quelle" text="Basierend auf OpenStreetMap-Daten, erhältlich via http://www.openstreetmap.org/" />
+      <license string="Lizenz" text="http://www.openstreetmap.org/copyright" />
+    </copyright>
+
+    <!-- Turn directions, 0 = ahead, -2 = left, +/-4 = behind, +2 = right -->
+    <turn direction="-4" string="Sehr scharf links" />
+    <turn direction="-3" string="Scharf links" />
+    <turn direction="-2" string="Links" />
+    <turn direction="-1" string="Halb links" />
+    <turn direction="0"  string="Geradeaus" />
+    <turn direction="1"  string="Halb rechts" />
+    <turn direction="2"  string="Rechts" />
+    <turn direction="3"  string="Scharf rechts" />
+    <turn direction="4"  string="Sehr scharf rechts" />
+
+    <!-- Heading directions, 0 = North, -2 = West, +/-4 = South, +2 = East -->
+    <heading direction="-4" string="Süd" />
+    <heading direction="-3" string="Süd-West" />
+    <heading direction="-2" string="West" />
+    <heading direction="-1" string="Nord-West" />
+    <heading direction="0"  string="Nord" />
+    <heading direction="1"  string="Nord-Ost" />
+    <heading direction="2"  string="Ost" />
+    <heading direction="3"  string="Süd-Ost" />
+    <heading direction="4"  string="Süd" />
+
+    <!-- Ordinals, 1 = first, 2 = second ... -->
+    <ordinal number="1"  string="Erste" />
+    <ordinal number="2"  string="Zweite" />
+    <ordinal number="3"  string="Dritte" />
+    <ordinal number="4"  string="Vierte" />
+    <ordinal number="5"  string="Fünfte" />
+    <ordinal number="6"  string="Sechste" />
+    <ordinal number="7"  string="Siebte" />
+    <ordinal number="8"  string="Achte" />
+    <ordinal number="9"  string="Neunte" />
+    <ordinal number="10" string="Zehnte" />
+
+    <!-- Highway names -->
+    <highway type="motorway"     string="Autobahn" />
+    <highway type="trunk"        string="Schnellstraße" />
+    <highway type="primary"      string="Bundesstraße" />
+    <highway type="secondary"    string="Landesstraße" />
+    <highway type="tertiary"     string="Kreisstraße" />
+    <highway type="unclassified" string="Nebenstraße" />
+    <highway type="residential"  string="Wohngebietsstraße" />
+    <highway type="service"      string="Erschließungsweg" />
+    <highway type="track"        string="Feld-/Waldweg" />
+    <highway type="cycleway"     string="Radweg" />
+    <highway type="path"         string="Weg/Pfad" />
+    <highway type="steps"        string="Treppe" />
+    <highway type="ferry"        string="Fähre" />
+
+    <!-- The type of route -->
+    <route type="shortest" string="Kürzeste" /> <!-- For the description and route name -->
+    <route type="quickest" string="Schnellste" /> <!-- For the description and route name -->
+
+    <!-- HTML output -->
+    <output-html>
+      <waypoint type="waypoint"   string="Wegpunkt" /> <!-- For the chosen waypoints -->
+      <waypoint type="junction"   string="Anschlussstelle" /> <!-- For the interesting junctions -->
+      <waypoint type="roundabout" string="Kreisverkehr" /> <!-- For roundabouts -->
+
+      <title text="%s Route" /> <!-- %s = [shortest|quickest] -->
+
+      <start   string="Start" text="Bei %s halten Sie sich Richtung %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [heading] -->
+      <node    string="Bei" text="Bei %s wenden Sie sich nach %s Richtung %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [turn], 3rd %s = [heading] -->
+      <rbnode  string="Verlassen Sie" text="%s, nehmen Sie die %s Ausfahrt Richtung %s" /> <!-- 1st %s = [roundabout], 2nd %s = [first|second|...], 3rd %s = [heading] -->
+      <segment string="Folgen" text="Folgen Sie der %s für %.3f km bzw. %.1f min" /> <!-- 1st %s = street name -->
+      <stop    string="Stop" text="Sie sind bei %s angekommen" /> <!-- 1st %s = [waypoint|junction] -->
+      <total   string="Gesamt" text="%.1f km, %.0f minuten" />
+    </output-html>
+
+    <!-- GPX output -->
+    <output-gpx>
+      <waypoint type="start" string="START" /> <!-- For the first route waypoint -->
+      <waypoint type="inter" string="INTER" /> <!-- For the intermediate route waypoints -->
+      <waypoint type="trip" string="TRIP" /> <!-- For the other route points -->
+      <waypoint type="finish" string="FINISH"/> <!-- For the last route waypoint -->
+
+      <desc  text="%s Strecke zwischen 'Start' und 'Ziel'" /> <!-- %s = [shortest|quickest] -->
+      <name  text="%s Strecke" /> <!-- %s = [shortest|quickest] -->
+      <step  text="%s auf '%s' für %.3f km, %.1f min" /> <!-- 1st %s = [turn], 2nd %s = street name -->
+      <final text="Gesamtstrecke %.1f km, %.0f minuten" />
+    </output-gpx>
+
+  </language>
+
+  <language lang="fr">
+
+    <!-- Copyright of the data being routed, not of this file  -->
+    <copyright>
+      <creator string="Créateur" text="Routino - http://www.routino.org/" />
+      <source  string="Source" text="Basé sur les données OpenStreetMap de http://www.openstreetmap.org/" />
+      <license string="License" text="http://www.openstreetmap.org/copyright" />
+    </copyright>
+
+    <!-- Turn directions, 0 = ahead, -2 = left, +/-4 = behind, +2 = right -->
+    <turn direction="-4" string="demi-tour à gauche" />
+    <turn direction="-3" string="Très à gauche" />
+    <turn direction="-2" string="à gauche" />
+    <turn direction="-1" string="Légèrement à gauche" />
+    <turn direction="0"  string="Tout droit" />
+    <turn direction="1"  string="légèrement à droite" />
+    <turn direction="2"  string="à droite" />
+    <turn direction="3"  string="très à droite" />
+    <turn direction="4"  string="demi-tour à droite" />
+
+    <!-- Heading directions, 0 = North, -2 = West, +/-4 = South, +2 = East -->
+    <heading direction="-4" string="Sud" />
+    <heading direction="-3" string="Dud-Ouest" />
+    <heading direction="-2" string="Ouest" />
+    <heading direction="-1" string="Nord-Ouest" />
+    <heading direction="0"  string="Nord" />
+    <heading direction="1"  string="Nord-Est" />
+    <heading direction="2"  string="Est" />
+    <heading direction="3"  string="Sud-Est" />
+    <heading direction="4"  string="Sud" />
+
+    <!-- Ordinals, 1 = first, 2 = second ... -->
+    <ordinal number="1"  string="Premier" />
+    <ordinal number="2"  string="Second" />
+    <ordinal number="3"  string="Troisième" />
+    <ordinal number="4"  string="Quatrième" />
+    <ordinal number="5"  string="Cinquième" />
+    <ordinal number="6"  string="Sixième" />
+    <ordinal number="7"  string="Septième" />
+    <ordinal number="8"  string="huitième" />
+    <ordinal number="9"  string="Neuvième" />
+    <ordinal number="10" string="Dixième" />
+
+    <!-- Highway names -->
+    <highway type="motorway"     string="autoroute" />
+    <highway type="trunk"        string="route de jonction" />
+    <highway type="primary"      string="route nationale" />
+    <highway type="secondary"    string="route départementale" />
+    <highway type="tertiary"     string="route locale" />
+    <highway type="unclassified" string="route non classifiée" />
+    <highway type="residential"  string="rue résidentielle" />
+    <highway type="service"      string="rue de service" />
+    <highway type="track"        string="chemin" />
+    <highway type="cycleway"     string="voie cyclable" />
+    <highway type="path"         string="sentier" />
+    <highway type="steps"        string="escalier" />
+    <highway type="ferry"        string="ferry" />
+
+    <!-- The type of route -->
+    <route type="shortest" string="le plus court" /> <!-- For the description and route name -->
+    <route type="quickest" string="le plus rapide" /> <!-- For the description and route name -->
+
+    <!-- HTML output -->
+    <output-html>
+      <waypoint type="waypoint"   string="Etape" /> <!-- For the chosen waypoints -->
+      <waypoint type="junction"   string="Croisement" /> <!-- For the interesting junctions -->
+      <waypoint type="roundabout" string="rond-point" /> <!-- For roundabouts -->
+
+      <title text="Itinéraire %s" /> <!-- %s = [shortest|quickest] -->
+
+      <start   string="Débute" text="à %s, direction %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [heading] -->
+      <node    string="à" text="%s, aller %s direction %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [turn], 3rd %s = [heading] -->
+      <rbnode  string="Quitter" text="%s, prendre le %s sortir direction %s" /> <!-- 1st %s = [roundabout], 2nd %s = [first|second|...], 3rd %s = [heading] -->
+      <segment string="Suivre" text="%s pendant %.3f km, %.1f min" /> <!-- 1st %s = street name -->
+      <stop    string="S'arrêter" text="à %s" /> <!-- 1st %s = [waypoint|junction] -->
+      <total   string="Total" text="%.1f km, %.0f minutes" />
+    </output-html>
+
+    <!-- GPX output -->
+    <output-gpx>
+      <waypoint type="start" string="DEBUT" /> <!-- For the first route waypoint -->
+      <waypoint type="inter" string="INTER" /> <!-- For the intermediate route waypoints -->
+      <waypoint type="trip" string="POINT" /> <!-- For the other route points -->
+      <waypoint type="finish" string="FINAL"/> <!-- For the last route waypoint -->
+
+      <desc  text="Itinéraire %s entre les étapes 'début' et 'fin'" /> <!-- %s = [shortest|quickest] -->
+      <name  text="Itinéraire %s" /> <!-- %s = [shortest|quickest] -->
+      <step  text="%s sur '%s' pendant %.3f km, %.1f min" /> <!-- 1st %s = [turn], 2nd %s = street name -->
+      <final text="Trajet total %.1f km, %.0f minutes" />
+    </output-gpx>
+
+  </language>
+
+  <language lang="hu">
+
+    <!-- Copyright of the data being routed, not of this file  -->
+    <copyright>
+      <creator string="Készítő" text="Routino - http://www.routino.org/" />
+      <source  string="Forrás" text="Openstreetmap adatok alapján http://www.openstreetmap.org/" />
+      <license string="Liszenc" text="http://www.openstreetmap.org/copyright" />
+    </copyright>
+
+    <!-- Turn directions, 0 = ahead, -2 = left, +/-4 = behind, +2 = right -->
+    <turn direction="-4" string="Nagyon élesen balra" />
+    <turn direction="-3" string="Élesen balra" />
+    <turn direction="-2" string="Balra" />
+    <turn direction="-1" string="Balra tarts" />
+    <turn direction="0"  string="Egyenesen" />
+    <turn direction="1"  string="Jobbra tarts" />
+    <turn direction="2"  string="Jobbra" />
+    <turn direction="3"  string="Élesen jobbra" />
+    <turn direction="4"  string="Nagyon élesen jobbra" />
+
+    <!-- Heading directions, 0 = North, -2 = West, +/-4 = South, +2 = East -->
+    <heading direction="-4" string="dél" />
+    <heading direction="-3" string="délnyugat" />
+    <heading direction="-2" string="nyugat" />
+    <heading direction="-1" string="északnyugat" />
+    <heading direction="0"  string="észak" />
+    <heading direction="1"  string="északkelet" />
+    <heading direction="2"  string="kelet" />
+    <heading direction="3"  string="délkelet" />
+    <heading direction="4"  string="dél" />
+
+    <!-- Ordinals, 1 = first, 2 = second ... -->
+    <ordinal number="1"  string="első" />
+    <ordinal number="2"  string="második" />
+    <ordinal number="3"  string="harmadik" />
+    <ordinal number="4"  string="negyedik" />
+    <ordinal number="5"  string="ötödik" />
+    <ordinal number="6"  string="hatodik" />
+    <ordinal number="7"  string="hetedik" />
+    <ordinal number="8"  string="nyolcadik" />
+    <ordinal number="9"  string="kilencedik" />
+    <ordinal number="10" string="tizedik" />
+
+    <!-- Highway names -->
+    <highway type="motorway"     string="autópálya" />
+    <highway type="trunk"        string="autóút" />
+    <highway type="primary"      string="főút" />
+    <highway type="secondary"    string="összekötőút" />
+    <highway type="tertiary"     string="bekötőút" />
+    <highway type="unclassified" string="egyéb közút" />
+    <highway type="residential"  string="lakóút" />
+    <highway type="service"      string="szervízút" />
+    <highway type="track"        string="földút" />
+    <highway type="cycleway"     string="kerékpárút" />
+    <highway type="path"         string="ösvény" />
+    <highway type="steps"        string="lépcső" />
+    <highway type="ferry"        string="komp" />
+
+    <!-- The type of route -->
+    <route type="shortest" string="Legrövidebb" /> <!-- For the description and route name -->
+    <route type="quickest" string="Leggyorsabb" /> <!-- For the description and route name -->
+
+    <!-- HTML output -->
+    <output-html>
+      <waypoint type="waypoint"   string="Útpont" /> <!-- For the chosen waypoints -->
+      <waypoint type="junction"   string="Kereszteződés" /> <!-- For the interesting junctions -->
+      <waypoint type="roundabout" string="Körforgalom" /> <!-- For roundabouts -->
+
+      <title text="%s útvonal" /> <!-- %s = [shortest|quickest] -->
+
+      <start   string="Indulás" text="%s, %s felé" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [heading] -->
+      <node    string="Itt" text="%s, menj %s %s felé" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [turn], 3rd %s = [heading] -->
+      <rbnode  string="Kijárat" text="%s, %s kijárat %s felé" /> <!-- 1st %s = [roundabout], 2nd %s = [first|second|...], 3rd %s = [heading] -->
+      <segment string="Erre" text="%s, %.3f km, %.1f perc" /> <!-- 1st %s = street name -->
+      <!-- TRANSLATION REQUIRED: stop    string="Cél" text="At %s" / --> <!-- 1st %s = [waypoint|junction] -->
+      <total   string="Összesen" text="%.1f km, %.0f perc" />
+    </output-html>
+
+    <!-- GPX output -->
+    <output-gpx>
+      <waypoint type="start" string="Indulás" /> <!-- For the first route waypoint -->
+      <!-- TRANSLATION REQUIRED: waypoint type="inter" string="INTER" / --> <!-- For the intermediate route waypoints -->
+      <waypoint type="trip" string="Utazás" /> <!-- For the other route points -->
+      <!-- TRANSLATION REQUIRED: waypoint type="finish" string="FINISH"/ --> <!-- For the last route waypoint -->
+
+      <desc  text="%s útvonal a kezdő és utolsó pont között" /> <!-- %s = [shortest|quickest] -->
+      <!-- TRANSLATION REQUIRED: name  text="%s route" / --> <!-- %s = [shortest|quickest] -->
+      <!-- TRANSLATION REQUIRED: step  text="%s on '%s' for %.3f km, %.1f min" / --> <!-- 1st %s = [turn], 2nd %s = street name -->
+      <final text="Az egész út %.1f km, %.0f perc" />
+    </output-gpx>
+
+  </language>
+
+  <language lang="nl">
+
+    <!-- Copyright of the data being routed, not of this file  -->
+    <copyright>
+      <creator string="Creator" text="Routino - http://www.routino.org/" />
+      <source  string="Source" text="Gebouwd op OpenStreetMap data van http://www.openstreetmap.org/" />
+      <license string="License" text="http://www.openstreetmap.org/copyright" />
+    </copyright>
+
+    <!-- Turn directions, 0 = ahead, -2 = left, +/-4 = behind, +2 = right -->
+    <turn direction="-4" string="Haarspeld naar links" />
+    <turn direction="-3" string="Scherp links" />
+    <turn direction="-2" string="Links" />
+    <turn direction="-1" string="Half links" />
+    <turn direction="0"  string="Rechtdoor" />
+    <turn direction="1"  string="Half rechts" />
+    <turn direction="2"  string="Rechts" />
+    <turn direction="3"  string="Scherp rechts" />
+    <turn direction="4"  string="Haarspeld naar rechts" />
+
+    <!-- Heading directions, 0 = North, -2 = West, +/-4 = South, +2 = East -->
+    <heading direction="-4" string="Zuid" />
+    <heading direction="-3" string="Zuid-West" />
+    <heading direction="-2" string="West" />
+    <heading direction="-1" string="Noord-West" />
+    <heading direction="0"  string="Noord" />
+    <heading direction="1"  string="Noord-Oost" />
+    <heading direction="2"  string="Oost" />
+    <heading direction="3"  string="Zuid-Oost" />
+    <heading direction="4"  string="Zuid" />
+
+    <!-- Ordinals, 1 = first, 2 = second ... -->
+    <ordinal number="1"  string="Eerste" />
+    <ordinal number="2"  string="Tweede" />
+    <ordinal number="3"  string="Derde" />
+    <ordinal number="4"  string="Vierde" />
+    <ordinal number="5"  string="Vijfde" />
+    <ordinal number="6"  string="Zesde" />
+    <ordinal number="7"  string="Zevende" />
+    <ordinal number="8"  string="Achtste" />
+    <ordinal number="9"  string="Negende" />
+    <ordinal number="10" string="Tiende" />
+
+    <!-- Highway names -->
+    <highway type="motorway"     string="Autostrade" />
+    <highway type="trunk"        string="Autoweg" />
+    <highway type="primary"      string="Provinciale weg" />
+    <highway type="secondary"    string="Nationale weg" />
+    <highway type="tertiary"     string="Doorgangsweg" />
+    <highway type="unclassified" string="Niet geclassificeerd" />
+    <highway type="residential"  string="Woongebied" />
+    <highway type="service"      string="Toegangsweg" />
+    <highway type="track"        string="Veldweg" />
+    <highway type="cycleway"     string="Fietspad" />
+    <highway type="path"         string="Pad" />
+    <highway type="steps"        string="Trap" />
+    <highway type="ferry"        string="Veerboot" />
+
+    <!-- The type of route -->
+    <route type="shortest" string="Kortste" /> <!-- For the description and route name -->
+    <route type="quickest" string="Snelste" /> <!-- For the description and route name -->
+
+    <!-- HTML output -->
+    <output-html>
+      <waypoint type="waypoint"   string="Punt" /> <!-- For the chosen waypoints -->
+      <waypoint type="junction"   string="de splitsing" /> <!-- For the interesting junctions -->
+      <waypoint type="roundabout" string="rotonde" /> <!-- For roundabouts -->
+
+      <title text="%s Route" /> <!-- %s = [shortest|quickest] -->
+
+      <start   string="Start" text="Bij %s neemt u de richting %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [heading] -->
+      <node    string="Bij" text="Bij %s gaat u %s richting %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [turn], 3rd %s = [heading] -->
+      <rbnode  string="Leave" text="Aan de %s, neem de %s afslag richting %s" /> <!-- 1st %s = [roundabout], 2nd %s = [first|second|...], 3rd %s = [heading] -->
+      <segment string="Volg" text="Volgt u de %s voor %.3f km %.1f min" /> <!-- 1st %s = street name -->
+      <stop    string="Stop" text="U bent bij  %s aangekomen" /> <!-- 1st %s = [waypoint|junction] -->
+      <total   string="Totaal" text="%.1f km, %.0f minuten" />
+    </output-html>
+
+    <!-- GPX output -->
+    <output-gpx>
+      <waypoint type="start" string="START" /> <!-- For the first route waypoint -->
+      <waypoint type="inter" string="INTER" /> <!-- For the intermediate route waypoints -->
+      <waypoint type="trip" string="TRIP" /> <!-- For the other route points -->
+      <waypoint type="finish" string="FINISH"/> <!-- For the last route waypoint -->
+
+      <desc  text="%s Route tussen 'Start' und 'Finish'" /> <!-- %s = [shortest|quickest] -->
+      <name  text="%s Route" /> <!-- %s = [shortest|quickest] -->
+      <step  text="%s op '%s' voor %.3f km, %.1f min" /> <!-- 1st %s = [turn], 2nd %s = street name -->
+      <final text="Totaal trip  %.1f km, %.0f minuten" />
+    </output-gpx>
+
+  </language>
+
+  <language lang="ru">
+
+    <!-- Copyright of the data being routed, not of this file  -->
+    <copyright>
+      <creator string="Автор" text="Routino - http://www.routino.org/" />
+      <source  string="Источник" text="Использованы данные OpenStreetMap http://www.openstreetmap.org/" />
+      <license string="Лицензия" text="http://www.openstreetmap.org/copyright" />
+    </copyright>
+
+    <!-- Turn directions, 0 = ahead, -2 = left, +/-4 = behind, +2 = right -->
+    <turn direction="-4" string="очень крутой поворот налево" />
+    <turn direction="-3" string="крутой поворот налево" />
+    <turn direction="-2" string="налево" />
+    <turn direction="-1" string="плавно налево" />
+    <turn direction="0"  string="прямо" />
+    <turn direction="1"  string="плавно направо" />
+    <turn direction="2"  string="направо" />
+    <turn direction="3"  string="крутой поворот направо" />
+    <turn direction="4"  string="очень крутой поворот направо" />
+
+    <!-- Heading directions, 0 = North, -2 = West, +/-4 = South, +2 = East -->
+    <heading direction="-4" string="юг" />
+    <heading direction="-3" string="юго-запад" />
+    <heading direction="-2" string="запад" />
+    <heading direction="-1" string="северо-запад" />
+    <heading direction="0"  string="север" />
+    <heading direction="1"  string="северо-восток" />
+    <heading direction="2"  string="восток" />
+    <heading direction="3"  string="юго-восток" />
+    <heading direction="4"  string="юг" />
+
+    <!-- Ordinals, 1 = first, 2 = second ... -->
+    <ordinal number="1"  string="Первый" />
+    <ordinal number="2"  string="Второй" />
+    <ordinal number="3"  string="Третий" />
+    <ordinal number="4"  string="Четвертый" />
+    <ordinal number="5"  string="Пятый" />
+    <ordinal number="6"  string="Шестой" />
+    <ordinal number="7"  string="Седьмой" />
+    <ordinal number="8"  string="Восьмой" />
+    <ordinal number="9"  string="Девятый" />
+    <ordinal number="10" string="Десятый" />
+
+    <!-- Highway names -->
+    <highway type="motorway"     string="автомагистраль" />
+    <highway type="trunk"        string="международная трасса" />
+    <highway type="primary"      string="дорога регионального значения" />
+    <highway type="secondary"    string="дорога областного значения" />
+    <highway type="tertiary"     string="дорога районного значения" />
+    <highway type="unclassified" string="дорога местного значения" />
+    <highway type="residential"  string="улица" />
+    <highway type="service"      string="проезд" />
+    <highway type="track"        string="дорога с/х назначения" />
+    <highway type="cycleway"     string="велодорожка" />
+    <highway type="path"         string="тропинка" />
+    <highway type="steps"        string="лестница" />
+    <highway type="ferry"        string="паром" />
+
+    <!-- The type of route -->
+    <route type="shortest" string="Короткий" /> <!-- For the description and route name -->
+    <route type="quickest" string="Быстрый" /> <!-- For the description and route name -->
+
+    <!-- HTML output -->
+    <output-html>
+      <waypoint type="waypoint"   string="путевая точка" /> <!-- For the chosen waypoints -->
+      <waypoint type="junction"   string="перекрестке" /> <!-- For the interesting junctions -->
+      <!-- TRANSLATION REQUIRED: waypoint type="roundabout" string="Roundabout" / --> <!-- For roundabouts -->
+
+      <title text="%s маршрут" /> <!-- %s = [shortest|quickest] -->
+
+      <start   string="Старт" text=" %s, на %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [heading] -->
+      <node    string="на" text="%s, %s,  на %s" /> <!-- 1st %s = [waypoint|junction], 2nd %s = [turn], 3rd %s = [heading] -->
+      <!-- TRANSLATION REQUIRED: rbnode  string="Покинуть" text="%s, take the %s exit heading %s" / --> <!-- 1st %s = [roundabout], 2nd %s = [first|second|...], 3rd %s = [heading] -->
+      <segment string="Следуйте" text="по %s %.3f км, %.1f мин" /> <!-- 1st %s = street name -->
+      <stop    string="Стоп" text=" %s" /> <!-- 1st %s = [waypoint|junction] -->
+      <total   string="Всего" text="%.1f км, %.0f минут" />
+    </output-html>
+
+    <!-- GPX output -->
+    <output-gpx>
+      <waypoint type="start" string="Старт" /> <!-- For the first route waypoint -->
+      <waypoint type="inter" string="INTER" /> <!-- For the intermediate route waypoints -->
+      <waypoint type="trip" string="TRIP" /> <!-- For the other route points -->
+      <waypoint type="finish" string="Финиш"/> <!-- For the last route waypoint -->
+
+      <desc  text="%s маршрут от 'Старта' до 'Финиша'" /> <!-- %s = [shortest|quickest] -->
+      <name  text="%s маршрут" /> <!-- %s = [shortest|quickest] -->
+      <step  text="на %s по '%s' %.3f км, %.1f мин" /> <!-- 1st %s = [turn], 2nd %s = street name -->
+      <final text="Всего - %.1f км, продолжительность - %.0f минут" />
+    </output-gpx>
+
+  </language>
+
+</routino-translations>
diff --git a/templates/header.h b/templates/header.h
index 7727f35..4bfb02b 100644
--- a/templates/header.h
+++ b/templates/header.h
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
diff --git a/templates/source.cpp b/templates/source.c
similarity index 88%
copy from templates/source.cpp
copy to templates/source.c
index 5306387..11ce1c4 100644
--- a/templates/source.cpp
+++ b/templates/source.c
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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
@@ -18,13 +18,3 @@
 
 #include "CLASSNAME.h"
 
-CLASSNAME::CLASSNAME()
-{
-
-}
-
-CLASSNAME::~CLASSNAME()
-{
-
-}
-
diff --git a/templates/source.cpp b/templates/source.cpp
index 5306387..62a8e8a 100644
--- a/templates/source.cpp
+++ b/templates/source.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************************************
-    Copyright (C) 2014 Oliver Eichler oliver.eichler at gmx.de
+    Copyright (C) 2014-2015 Oliver Eichler oliver.eichler at gmx.de
 
     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

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/qmapshack.git



More information about the Pkg-grass-devel mailing list