[osrm] 01/13: Imported Upstream version 4.5.0

Christopher Baines cbaines-guest at moszumanska.debian.org
Sat Apr 4 16:04:06 UTC 2015


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

cbaines-guest pushed a commit to branch master
in repository osrm.

commit 60426464adc792402dd530a3406d502135476ea9
Author: Christopher Baines <mail at cbaines.net>
Date:   Sat Apr 4 14:09:47 2015 +0100

    Imported Upstream version 4.5.0
---
 .gitignore                                         |   7 +-
 .travis.yml                                        |  18 +-
 Algorithms/BFSComponentExplorer.h                  | 148 ----
 Algorithms/ObjectToBase64.h                        |  99 ---
 Algorithms/StronglyConnectedComponents.h           | 447 ----------
 CMakeLists.txt                                     | 194 +++--
 Contractor/TemporaryStorage.cpp                    | 172 ----
 Contractor/TemporaryStorage.h                      |  96 ---
 DataStructures/DeallocatingVector.h                | 401 ---------
 DataStructures/NodeBasedGraph.h                    | 166 ----
 DataStructures/PhantomNodes.h                      | 173 ----
 Descriptors/GPXDescriptor.h                        | 100 ---
 Docs/webclient.txt                                 |   3 -
 Extractor/BaseParser.cpp                           | 139 ---
 Extractor/BaseParser.h                             |  67 --
 Extractor/ExtractionWay.h                          |  79 --
 Extractor/ExtractorCallbacks.cpp                   | 171 ----
 Extractor/ExtractorStructs.h                       | 114 ---
 Extractor/PBFParser.cpp                            | 664 ---------------
 Extractor/PBFParser.h                              | 103 ---
 Extractor/ScriptingEnvironment.cpp                 | 121 ---
 Extractor/XMLParser.cpp                            | 353 --------
 Extractor/XMLParser.h                              |  54 --
 Include/osrm/Coordinate.h                          |  34 +-
 Include/osrm/Header.h                              |   2 +-
 Include/osrm/RouteParameters.h                     |   9 +
 Library/OSRM.h                                     |   6 +-
 Library/OSRM_impl.cpp                              |  40 +-
 Library/OSRM_impl.h                                |  11 +-
 Plugins/ViaRoutePlugin.h                           | 173 ----
 README.md                                          |   7 +-
 Rakefile                                           |   9 +-
 Server/APIGrammar.h                                |   9 +-
 Server/Connection.cpp                              |   4 +-
 Server/Connection.h                                |   4 +-
 Server/DataStructures/BaseDataFacade.h             |  41 +-
 Server/DataStructures/InternalDataFacade.h         | 155 ++--
 Server/DataStructures/SharedDataFacade.h           | 171 ++--
 Server/DataStructures/SharedDataType.h             |  15 +-
 Server/Http/CompressionType.h                      |   2 +-
 Server/Http/Reply.cpp                              |   7 +-
 Server/RequestHandler.cpp                          |  31 +-
 Server/RequestHandler.h                            |   2 +-
 Server/RequestParser.cpp                           |  28 +-
 Server/RequestParser.h                             |   4 +-
 Server/Server.h                                    |  31 +-
 Server/ServerFactory.h                             |  49 --
 Tools/components.cpp                               | 136 ---
 UnitTests/Algorithms/DouglasPeuckerTest.cpp        | 109 +++
 .../algorithm_tests.cpp                            |  12 +-
 UnitTests/data_structures/BinaryHeapTest.cpp       | 178 ++++
 UnitTests/data_structures/RangeTableTest.cpp       | 131 +++
 UnitTests/data_structures/StaticGraphTest.cpp      | 191 +++++
 UnitTests/data_structures/StaticRTreeTest.cpp      | 488 +++++++++++
 .../datastructure_tests.cpp                        |  11 +-
 Util/Azimuth.h                                     |  73 --
 Util/BoostFileSystemFix.h                          |  17 +-
 Util/DataStoreOptions.h                            |  31 +-
 Util/FingerPrint.h                                 |   1 -
 Util/MercatorUtil.h                                |   8 +-
 Util/ProgramOptions.h                              | 197 +++--
 Util/SimpleLogger.h                                | 158 ----
 Util/StringUtil.h                                  | 318 -------
 Util/TimingUtil.h                                  |  39 -
 Util/{MachineInfo.h => bearing.cpp}                |  54 +-
 Util/{GitDescription.h => bearing.hpp}             |  13 +-
 Util/cast.hpp                                      | 188 ++++
 Util/{ComputeAngle.h => compute_angle.cpp}         |  20 +-
 Library/OSRM.h => Util/compute_angle.hpp           |  31 +-
 Util/{ContainerUtils.h => container.hpp}           |  57 +-
 Util/{FingerPrint.cpp.in => finger_print.cpp.in}   |  15 +-
 Library/OSRM.h => Util/floating_point.hpp          |  32 +-
 Util/{GitDescription.cpp.in => git_sha.cpp.in}     |   4 +-
 Util/{GitDescription.h => git_sha.hpp}             |   8 +-
 Util/{GraphLoader.h => graph_loader.hpp}           |  95 ++-
 .../SearchEngine.h => Util/integer_range.hpp       |  54 +-
 .../HashTable.h => Util/iterator_range.hpp         |  80 +-
 .../JSONContainer.h => Util/json_renderer.hpp      | 111 +--
 Util/{LuaUtil.h => lua_util.hpp}                   |   8 +-
 .../ScriptingEnvironment.h => Util/make_unique.hpp |  39 +-
 Include/osrm/Header.h => Util/osrm_exception.cpp   |  38 +-
 Util/{OSRMException.h => osrm_exception.hpp}       |  25 +-
 Util/range_algorithms.hpp                          |  42 +
 Util/simple_logger.cpp                             | 135 +++
 Server/RequestHandler.h => Util/simple_logger.hpp  |  55 +-
 Util/{StdHashExtensions.h => std_hash.hpp}         |  18 +-
 Util/string_util.hpp                               | 150 ++++
 Util/timing_util.hpp                               |  80 ++
 Util/xml_renderer.hpp                              | 140 +++
 algorithms/bfs_components.hpp                      | 174 ++++
 .../crc32_processor.hpp                            | 118 +--
 .../douglas_peucker.cpp                            |  97 +--
 .../douglas_peucker.hpp                            |  38 +-
 algorithms/object_encoder.hpp                      |  94 ++
 .../polyline_compressor.cpp                        |  70 +-
 .../polyline_compressor.hpp                        |  10 +-
 .../polyline_formatter.cpp                         |  50 +-
 .../polyline_formatter.hpp                         |  18 +-
 .../route_name_extraction.hpp                      |   6 +-
 algorithms/tiny_components.hpp                     | 253 ++++++
 appveyor.yml                                       |  15 +-
 benchmarks/static_rtree.cpp                        | 189 +++++
 cmake/CPackDebianConfig.cmake                      |  44 +
 cmake/FindDebArch.cmake                            |  19 +
 cmake/FingerPrint-Config.cmake                     |   6 +-
 cmake/check_luabind.cmake                          |  40 +
 cmake/postinst.in                                  |   2 +
 .../Contractor.h => contractor/contractor.hpp      | 224 +++--
 .../edge_based_graph_factory.cpp                   | 315 +++----
 .../edge_based_graph_factory.hpp                   |  44 +-
 .../geometry_compressor.cpp                        |  20 +-
 .../geometry_compressor.hpp                        |  14 +-
 contractor/processing_chain.cpp                    | 581 +++++++++++++
 contractor/processing_chain.hpp                    |  95 +++
 {DataStructures => data_structures}/Coordinate.cpp | 111 ++-
 .../InputReaderFactory.h                           |   0
 .../binary_heap.hpp                                |   7 +-
 .../concurrent_queue.hpp                           |  10 +-
 data_structures/deallocating_vector.hpp            | 313 +++++++
 .../dynamic_graph.hpp                              | 167 ++--
 .../edge_based_node.hpp                            |  57 +-
 .../external_memory_node.cpp                       |  30 +-
 .../external_memory_node.hpp                       |  28 +-
 data_structures/fixed_point_number.hpp             | 216 +++++
 .../hilbert_value.cpp                              |   4 +-
 .../hilbert_value.hpp                              |   8 +-
 .../import_edge.cpp                                |  10 +-
 .../import_edge.hpp                                |  15 +-
 .../json_container.hpp                             |  89 +-
 .../LRUCache.h => data_structures/lru_cache.hpp    |   8 +-
 data_structures/node_based_graph.hpp               | 271 ++++++
 .../node_id.hpp                                    |  24 +-
 .../original_edge_data.hpp                         |  20 +-
 .../Percent.h => data_structures/percent.hpp       |  10 +-
 data_structures/phantom_node.cpp                   | 124 +++
 data_structures/phantom_node.hpp                   | 129 +++
 .../QueryEdge.h => data_structures/query_edge.hpp  |  25 +-
 .../QueryNode.h => data_structures/query_node.hpp  |  36 +-
 .../range_table.hpp                                |  51 +-
 .../raw_route_data.hpp                             |  36 +-
 data_structures/rectangle.hpp                      | 199 +++++
 .../restriction.hpp                                |  84 +-
 .../restriction_map.cpp                            | 131 +--
 .../restriction_map.hpp                            |  97 ++-
 .../route_parameters.cpp                           |  30 +-
 .../search_engine.hpp                              |  16 +-
 .../search_engine_data.cpp                         |   4 +-
 .../search_engine_data.hpp                         |  14 +-
 .../segment_information.hpp                        |  22 +-
 .../shared_memory_factory.hpp                      |  25 +-
 .../shared_memory_vector_wrapper.hpp               |  18 +-
 .../static_graph.hpp                               |  79 +-
 .../static_kdtree.hpp                              |   8 +-
 .../static_rtree.hpp                               | 501 +++++++----
 .../travel_mode.hpp                                |  23 +-
 .../turn_instructions.hpp                          |  10 +-
 .../xor_fast_hash.hpp                              |  10 +-
 .../xor_fast_hash_storage.hpp                      |  16 +-
 datastore.cpp                                      | 196 ++---
 .../description_factory.cpp                        |  71 +-
 .../description_factory.hpp                        |  55 +-
 .../descriptor_base.hpp                            |  40 +-
 descriptors/gpx_descriptor.hpp                     |  92 ++
 .../json_descriptor.hpp                            | 120 +--
 Server/Http/CompressionType.h => extract.cpp       |  27 +-
 extractor.cpp                                      | 286 -------
 .../extraction_containers.cpp                      | 100 ++-
 .../extraction_containers.hpp                      |  29 +-
 .../extraction_helper_functions.hpp                |  25 +-
 .../extraction_node.hpp                            |  26 +-
 extractor/extraction_way.hpp                       | 120 +++
 extractor/extractor.cpp                            | 268 ++++++
 extractor/extractor.hpp                            |  13 +
 extractor/extractor_callbacks.cpp                  | 223 +++++
 .../extractor_callbacks.hpp                        |  23 +-
 extractor/extractor_options.cpp                    | 167 ++++
 .../extractor_options.hpp                          |  40 +-
 extractor/first_and_last_segment_of_way.hpp        |  88 ++
 .../internal_extractor_edge.hpp                    |  32 +-
 extractor/restriction_parser.cpp                   | 241 ++++++
 .../restriction_parser.hpp                         |  38 +-
 extractor/scripting_environment.cpp                | 146 ++++
 .../scripting_environment.hpp                      |  19 +-
 features/bicycle/mode.feature                      | 228 +++--
 features/bicycle/pushing.feature                   |  26 +-
 features/car/ferry.feature                         |  37 +-
 features/car/link.feature                          | 111 +++
 features/car/maxspeed.feature                      |  52 +-
 features/car/restrictions.feature                  |  69 ++
 features/car/speed.feature                         |  28 +-
 features/car/surface.feature                       | 141 +++
 features/foot/ferry.feature                        |  18 +-
 features/options/extract/files.feature             |   6 +-
 features/options/prepare/files.feature             |   6 +-
 features/options/routed/files.feature              |  13 +-
 features/step_definitions/data.rb                  |  16 +
 features/step_definitions/distance_matrix.rb       |  56 ++
 features/step_definitions/locate.rb                |   2 +-
 features/step_definitions/nearest.rb               |   2 +-
 features/step_definitions/options.rb               |  26 +-
 features/step_definitions/requests.rb              |  34 +-
 features/step_definitions/routability.rb           |  10 +-
 features/step_definitions/routing.rb               |  16 +-
 features/step_definitions/timestamp.rb             |   4 +-
 features/support/data.rb                           |  78 +-
 features/support/env.rb                            |  34 +-
 features/support/exceptions.rb                     |   6 +
 features/support/hash.rb                           |  26 +-
 features/support/hooks.rb                          |   6 +-
 features/support/launch.rb                         | 168 ++--
 features/support/log.rb                            |   6 +-
 features/support/route.rb                          |   5 +
 features/support/run.rb                            |  20 +-
 features/testbot/bad.feature                       |   2 +-
 features/testbot/basic.feature                     |   2 +-
 features/testbot/bearing.feature                   |   2 +-
 features/testbot/bearing_param.feature             |   2 +-
 features/testbot/compression.feature               |  22 +
 features/testbot/datastore.feature                 |  31 +
 features/testbot/distance.feature                  |  52 +-
 features/testbot/distance_matrix.feature           | 102 +++
 features/testbot/fastest.feature                   |   2 +-
 features/testbot/geometry.feature                  |   2 +-
 features/testbot/graph.feature                     |  21 +-
 features/testbot/load.feature                      |  63 ++
 features/testbot/loop.feature                      |   8 +-
 features/testbot/mode.feature                      | 227 ++++-
 features/testbot/oneway.feature                    |  64 +-
 features/testbot/origin.feature                    |   2 +-
 features/testbot/penalty.feature                   |   2 +-
 features/testbot/planetary.feature                 |   2 +-
 features/testbot/projection.feature                |   2 +-
 features/testbot/protobuffer.feature               |   2 +-
 features/testbot/snap.feature                      |   2 +-
 features/testbot/status.feature                    |   2 +-
 features/testbot/time.feature                      |   2 +-
 features/testbot/turns.feature                     |   2 +-
 features/testbot/utf.feature                       |   2 +-
 features/testbot/uturn.feature                     |  69 ++
 features/testbot/via.feature                       |  24 +-
 .../distance_table.hpp                             |  71 +-
 .../HelloWorldPlugin.h => plugins/hello_world.hpp  |  34 +-
 Plugins/LocatePlugin.h => plugins/locate.hpp       |  23 +-
 Plugins/NearestPlugin.h => plugins/nearest.hpp     |  70 +-
 Plugins/BasePlugin.h => plugins/plugin_base.hpp    |  16 +-
 Plugins/TimestampPlugin.h => plugins/timestamp.hpp |  14 +-
 plugins/viaroute.hpp                               | 190 +++++
 prepare.cpp                                        | 476 +----------
 profiles/bicycle.lua                               | 263 +++---
 profiles/car.lua                                   | 340 +++++---
 profiles/examples/postgis.lua                      |   4 +-
 profiles/foot.lua                                  | 128 +--
 profiles/lib/access.lua                            |   6 +-
 profiles/lib/maxspeed.lua                          |  17 +
 profiles/testbot.lua                               |  76 +-
 routed.cpp                                         |  45 +-
 .../alternative_path.hpp                           | 198 +++--
 .../many_to_many.hpp                               |  18 +-
 .../routing_base.hpp                               | 118 +--
 .../shortest_path.hpp                              | 115 +--
 taginfo.json                                       |  84 ++
 third_party/osmium/area/assembler.hpp              | 783 +++++++++++++++++
 .../osmium/area/detail/node_ref_segment.hpp        | 262 ++++++
 third_party/osmium/area/detail/proto_ring.hpp      | 274 ++++++
 third_party/osmium/area/detail/segment_list.hpp    | 216 +++++
 third_party/osmium/area/multipolygon_collector.hpp | 212 +++++
 third_party/osmium/area/problem_reporter.hpp       | 149 ++++
 .../osmium/area/problem_reporter_exception.hpp     |  96 +++
 third_party/osmium/area/problem_reporter_ogr.hpp   | 206 +++++
 .../osmium/area/problem_reporter_stream.hpp        |  96 +++
 third_party/osmium/builder/builder.hpp             | 220 +++++
 third_party/osmium/builder/builder_helper.hpp      | 103 +++
 third_party/osmium/builder/osm_object_builder.hpp  | 283 ++++++
 third_party/osmium/config/constexpr.hpp            |  43 +
 third_party/osmium/diff_handler.hpp                |  67 ++
 third_party/osmium/diff_iterator.hpp               | 129 +++
 third_party/osmium/diff_visitor.hpp                | 104 +++
 third_party/osmium/dynamic_handler.hpp             | 195 +++++
 third_party/osmium/experimental/flex_reader.hpp    | 131 +++
 third_party/osmium/geom/coordinates.hpp            |  97 +++
 third_party/osmium/geom/factory.hpp                | 328 +++++++
 third_party/osmium/geom/geojson.hpp                | 152 ++++
 third_party/osmium/geom/geos.hpp                   | 224 +++++
 third_party/osmium/geom/haversine.hpp              |  94 ++
 third_party/osmium/geom/mercator_projection.hpp    | 109 +++
 third_party/osmium/geom/ogr.hpp                    | 179 ++++
 third_party/osmium/geom/projection.hpp             | 159 ++++
 third_party/osmium/geom/relations.hpp              |  57 ++
 third_party/osmium/geom/util.hpp                   |  75 ++
 third_party/osmium/geom/wkb.hpp                    | 279 ++++++
 third_party/osmium/geom/wkt.hpp                    | 148 ++++
 third_party/osmium/handler.hpp                     | 101 +++
 third_party/osmium/handler/chain.hpp               | 128 +++
 third_party/osmium/handler/disk_store.hpp          | 111 +++
 third_party/osmium/handler/dump.hpp                | 294 +++++++
 .../osmium/handler/node_locations_for_ways.hpp     | 177 ++++
 third_party/osmium/handler/object_relations.hpp    | 106 +++
 .../osmium/index/detail/mmap_vector_anon.hpp       |  78 ++
 .../osmium/index/detail/mmap_vector_base.hpp       | 183 ++++
 .../osmium/index/detail/mmap_vector_file.hpp       |  82 ++
 third_party/osmium/index/detail/tmpfile.hpp        |  62 ++
 third_party/osmium/index/detail/typed_mmap.hpp     | 229 +++++
 third_party/osmium/index/index.hpp                 | 100 +++
 third_party/osmium/index/map.hpp                   | 155 ++++
 third_party/osmium/index/map/dummy.hpp             |  87 ++
 third_party/osmium/index/map/mmap_vector_anon.hpp  |  61 ++
 third_party/osmium/index/map/mmap_vector_file.hpp  |  57 ++
 third_party/osmium/index/map/sparse_table.hpp      | 140 +++
 third_party/osmium/index/map/stl_map.hpp           | 112 +++
 third_party/osmium/index/map/stl_vector.hpp        |  61 ++
 third_party/osmium/index/map/vector.hpp            | 208 +++++
 third_party/osmium/index/multimap.hpp              | 129 +++
 third_party/osmium/index/multimap/hybrid.hpp       | 199 +++++
 .../osmium/index/multimap/mmap_vector_anon.hpp     |  58 ++
 .../osmium/index/multimap/mmap_vector_file.hpp     |  54 ++
 third_party/osmium/index/multimap/stl_multimap.hpp | 151 ++++
 third_party/osmium/index/multimap/stl_vector.hpp   |  58 ++
 third_party/osmium/index/multimap/vector.hpp       | 151 ++++
 third_party/osmium/io/any_compression.hpp          |  39 +
 third_party/osmium/io/any_input.hpp                |  41 +
 third_party/osmium/io/any_output.hpp               |  42 +
 third_party/osmium/io/bzip2_compression.hpp        | 277 ++++++
 third_party/osmium/io/compression.hpp              | 279 ++++++
 third_party/osmium/io/detail/input_format.hpp      | 160 ++++
 third_party/osmium/io/detail/opl_output_format.hpp | 315 +++++++
 third_party/osmium/io/detail/output_format.hpp     | 156 ++++
 third_party/osmium/io/detail/pbf.hpp               | 100 +++
 third_party/osmium/io/detail/pbf_input_format.hpp  | 240 ++++++
 third_party/osmium/io/detail/pbf_output_format.hpp | 944 +++++++++++++++++++++
 third_party/osmium/io/detail/pbf_parser.hpp        | 449 ++++++++++
 third_party/osmium/io/detail/pbf_stringtable.hpp   | 204 +++++
 third_party/osmium/io/detail/read_thread.hpp       | 106 +++
 third_party/osmium/io/detail/read_write.hpp        | 156 ++++
 third_party/osmium/io/detail/write_thread.hpp      |  86 ++
 third_party/osmium/io/detail/xml_input_format.hpp  | 726 ++++++++++++++++
 third_party/osmium/io/detail/xml_output_format.hpp | 481 +++++++++++
 third_party/osmium/io/detail/zlib.hpp              |  99 +++
 third_party/osmium/io/error.hpp                    |  57 ++
 third_party/osmium/io/file.hpp                     | 343 ++++++++
 third_party/osmium/io/file_compression.hpp         |  72 ++
 third_party/osmium/io/file_format.hpp              |  78 ++
 third_party/osmium/io/gzip_compression.hpp         | 238 ++++++
 third_party/osmium/io/header.hpp                   | 122 +++
 third_party/osmium/io/input_iterator.hpp           | 139 +++
 third_party/osmium/io/opl_output.hpp               |  39 +
 third_party/osmium/io/output_iterator.hpp          | 116 +++
 third_party/osmium/io/overwrite.hpp                |  52 ++
 third_party/osmium/io/pbf_input.hpp                |  39 +
 third_party/osmium/io/pbf_output.hpp               |  39 +
 third_party/osmium/io/reader.hpp                   | 303 +++++++
 third_party/osmium/io/reader_iterator.hpp          |  51 ++
 third_party/osmium/io/writer.hpp                   | 145 ++++
 third_party/osmium/io/xml_input.hpp                |  39 +
 third_party/osmium/io/xml_output.hpp               |  39 +
 third_party/osmium/memory/buffer.hpp               | 534 ++++++++++++
 third_party/osmium/memory/collection.hpp           | 153 ++++
 third_party/osmium/memory/item.hpp                 | 179 ++++
 third_party/osmium/memory/item_iterator.hpp        | 234 +++++
 third_party/osmium/object_pointer_collection.hpp   | 112 +++
 third_party/osmium/osm.hpp                         |  48 ++
 third_party/osmium/osm/area.hpp                    | 193 +++++
 third_party/osmium/osm/box.hpp                     | 207 +++++
 third_party/osmium/osm/changeset.hpp               | 336 ++++++++
 third_party/osmium/osm/diff_object.hpp             | 156 ++++
 third_party/osmium/osm/entity.hpp                  |  74 ++
 third_party/osmium/osm/entity_bits.hpp             |  99 +++
 third_party/osmium/osm/item_type.hpp               | 173 ++++
 third_party/osmium/osm/location.hpp                | 285 +++++++
 third_party/osmium/osm/node.hpp                    |  76 ++
 third_party/osmium/osm/node_ref.hpp                | 173 ++++
 third_party/osmium/osm/node_ref_list.hpp           | 135 +++
 third_party/osmium/osm/object.hpp                  | 437 ++++++++++
 third_party/osmium/osm/object_comparisons.hpp      | 110 +++
 third_party/osmium/osm/relation.hpp                | 189 +++++
 third_party/osmium/osm/segment.hpp                 | 105 +++
 third_party/osmium/osm/tag.hpp                     | 140 +++
 third_party/osmium/osm/timestamp.hpp               | 169 ++++
 third_party/osmium/osm/types.hpp                   |  83 ++
 third_party/osmium/osm/undirected_segment.hpp      | 100 +++
 third_party/osmium/osm/way.hpp                     | 115 +++
 third_party/osmium/relations/collector.hpp         | 544 ++++++++++++
 .../osmium/relations/detail/member_meta.hpp        | 158 ++++
 .../osmium/relations/detail/relation_meta.hpp      | 136 +++
 third_party/osmium/tags/filter.hpp                 | 148 ++++
 third_party/osmium/tags/regex_filter.hpp           |  58 ++
 third_party/osmium/tags/taglist.hpp                |  67 ++
 third_party/osmium/thread/checked_task.hpp         | 106 +++
 third_party/osmium/thread/function_wrapper.hpp     | 110 +++
 third_party/osmium/thread/name.hpp                 |  61 ++
 third_party/osmium/thread/pool.hpp                 | 180 ++++
 third_party/osmium/thread/queue.hpp                | 178 ++++
 third_party/osmium/thread/sorted_queue.hpp         | 159 ++++
 third_party/osmium/thread/util.hpp                 |  87 ++
 third_party/osmium/util/cast.hpp                   |  72 ++
 third_party/osmium/util/compatibility.hpp          |  47 +
 third_party/osmium/util/config.hpp                 |  73 ++
 third_party/osmium/util/double.hpp                 |  91 ++
 third_party/osmium/util/options.hpp                | 155 ++++
 third_party/osmium/util/verbose_output.hpp         | 139 +++
 third_party/osmium/visitor.hpp                     | 255 ++++++
 third_party/variant/optional.hpp                   |  69 ++
 third_party/variant/recursive_wrapper.hpp          | 127 +++
 third_party/variant/variant.hpp                    | 740 ++++++++++++++++
 {Tools => tools}/.gitignore                        |   0
 tools/check-hsgr.cpp                               | 112 +++
 tools/components.cpp                               | 293 +++++++
 {Tools => tools}/io-benchmark.cpp                  | 112 +--
 {Tools => tools}/simpleclient.cpp                  |  30 +-
 tools/springclean.cpp                              | 102 +++
 {Tools => tools}/unlock_all_mutexes.cpp            |   9 +-
 typedefs.h                                         |  16 +-
 411 files changed, 36356 insertions(+), 9007 deletions(-)

diff --git a/.gitignore b/.gitignore
index 5642924..b905eea 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,8 +36,9 @@ Thumbs.db
 # build related files #
 #######################
 /build/
-/Util/FingerPrint.cpp
-/Util/GitDescription.cpp
+/Util/finger_print.cpp
+/Util/git_sha.cpp
+/cmake/postinst
 
 # Eclipse related files #
 #########################
@@ -79,6 +80,8 @@ stxxl.errlog
 /osrm-prepare
 /osrm-unlock-all
 /osrm-cli
+/osrm-check-hsgr
+/osrm-springclean
 /nohup.out
 
 # Sandbox folder #
diff --git a/.travis.yml b/.travis.yml
index 8817e38..643e00d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,13 +7,17 @@ install:
  - sudo apt-add-repository -y ppa:ubuntu-toolchain-r/test
  - sudo add-apt-repository -y ppa:boost-latest/ppa
  - sudo apt-get update >/dev/null
- - sudo apt-get -q install libprotoc-dev libprotobuf7 libprotobuf-dev libosmpbf-dev libbz2-dev libstxxl-dev libstxxl1 libxml2-dev libzip-dev lua5.1 liblua5.1-0-dev rubygems libtbb-dev
- - sudo apt-get -q install g++-4.7
+ - sudo apt-get -q install protobuf-compiler libprotoc-dev libprotobuf7 libprotobuf-dev libbz2-dev libstxxl-dev libstxxl1 libxml2-dev libzip-dev lua5.1 liblua5.1-0-dev rubygems libtbb-dev
+ - sudo apt-get -q install g++-4.8
  - sudo apt-get install libboost1.54-all-dev
- #luabind
+ # luabind
  - curl https://gist.githubusercontent.com/DennisOSRM/f2eb7b948e6fe1ae319e/raw/install-luabind.sh | sudo bash
- #osmosis
+ # osmosis
  - curl -s https://gist.githubusercontent.com/DennisOSRM/803a64a9178ec375069f/raw/ | sudo bash
+ # cmake
+ - curl -s https://gist.githubusercontent.com/DennisOSRM/5fad9bee5c7f09fd7fc9/raw/ | sudo bash
+ # osmpbf library
+ - curl -s https://gist.githubusercontent.com/DennisOSRM/13b1b4fe38a57ead850e/raw/install_osmpbf.sh | sudo bash
 before_script:
  - rvm use 1.9.3
  - gem install bundler
@@ -23,6 +27,8 @@ before_script:
  - cmake .. $CMAKEOPTIONS
 script:
  - make -j 2
+ - make -j 2 tests
+ - ./datastructure-tests
  - cd ..
  - cucumber -p verify
 after_script:
@@ -36,8 +42,8 @@ cache:
 - bundler
 - apt
 env:
- - CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++-4.7" OSRM_PORT=5000 OSRM_TIMEOUT=60
- - CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=g++-4.7" OSRM_PORT=5010 OSRM_TIMEOUT=60
+ - CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++-4.8" OSRM_PORT=5000 OSRM_TIMEOUT=60
+ - CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=g++-4.8" OSRM_PORT=5010 OSRM_TIMEOUT=60
 notifications:
  irc:
   channels:
diff --git a/Algorithms/BFSComponentExplorer.h b/Algorithms/BFSComponentExplorer.h
deleted file mode 100644
index 7bc7ecb..0000000
--- a/Algorithms/BFSComponentExplorer.h
+++ /dev/null
@@ -1,148 +0,0 @@
-#ifndef __BFS_COMPONENT_EXPLORER_H__
-#define __BFS_COMPONENT_EXPLORER_H__
-
-#include "../typedefs.h"
-#include "../DataStructures/DynamicGraph.h"
-#include "../DataStructures/RestrictionMap.h"
-
-#include <queue>
-#include <unordered_set>
-
-// Explores the components of the given graph while respecting turn restrictions
-// and barriers.
-template <typename GraphT> class BFSComponentExplorer
-{
-  public:
-    BFSComponentExplorer(const GraphT &dynamicGraph,
-                         const RestrictionMap &restrictions,
-                         const std::unordered_set<NodeID> &barrier_nodes)
-        : m_graph(dynamicGraph), m_restriction_map(restrictions), m_barrier_nodes(barrier_nodes)
-    {
-        BOOST_ASSERT(m_graph.GetNumberOfNodes() > 0);
-    }
-
-    /*!
-     * Returns the size of the component that the node belongs to.
-     */
-    inline unsigned int GetComponentSize(NodeID node)
-    {
-        BOOST_ASSERT(node < m_component_index_list.size());
-
-        return m_component_index_size[m_component_index_list[node]];
-    }
-
-    inline unsigned int GetNumberOfComponents() { return m_component_index_size.size(); }
-
-    /*!
-     * Computes the component sizes.
-     */
-    void run()
-    {
-        std::queue<std::pair<NodeID, NodeID>> bfs_queue;
-        unsigned current_component = 0;
-
-        BOOST_ASSERT(m_component_index_list.empty());
-        BOOST_ASSERT(m_component_index_size.empty());
-
-        unsigned num_nodes = m_graph.GetNumberOfNodes();
-
-        m_component_index_list.resize(num_nodes, std::numeric_limits<unsigned>::max());
-
-        BOOST_ASSERT(num_nodes > 0);
-
-        // put unexplorered node with parent pointer into queue
-        for (NodeID node = 0; node < num_nodes; ++node)
-        {
-            if (std::numeric_limits<unsigned>::max() == m_component_index_list[node])
-            {
-                unsigned size = ExploreComponent(bfs_queue, node, current_component);
-
-                // push size into vector
-                m_component_index_size.emplace_back(size);
-                ++current_component;
-            }
-        }
-    }
-
-  private:
-    /*!
-     * Explores the current component that starts at node using BFS.
-     */
-    inline unsigned ExploreComponent(std::queue<std::pair<NodeID, NodeID>> &bfs_queue,
-                                     NodeID node,
-                                     unsigned current_component)
-    {
-        /*
-           Graphical representation of variables:
-
-           u           v           w
-           *---------->*---------->*
-                            e2
-        */
-
-        bfs_queue.emplace(node, node);
-        // mark node as read
-        m_component_index_list[node] = current_component;
-
-        unsigned current_component_size = 1;
-
-        while (!bfs_queue.empty())
-        {
-            // fetch element from BFS queue
-            std::pair<NodeID, NodeID> current_queue_item = bfs_queue.front();
-            bfs_queue.pop();
-
-            const NodeID v = current_queue_item.first; // current node
-            const NodeID u = current_queue_item.second; // parent
-            // increment size counter of current component
-            ++current_component_size;
-            const bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end());
-            if (!is_barrier_node)
-            {
-                const NodeID to_node_of_only_restriction =
-                    m_restriction_map.CheckForEmanatingIsOnlyTurn(u, v);
-
-                for (auto e2 : m_graph.GetAdjacentEdgeRange(v))
-                {
-                    const NodeID w = m_graph.GetTarget(e2);
-
-                    if (to_node_of_only_restriction != std::numeric_limits<unsigned>::max() &&
-                        w != to_node_of_only_restriction)
-                    {
-                        // At an only_-restriction but not at the right turn
-                        continue;
-                    }
-
-                    if (u != w)
-                    {
-                        // only add an edge if turn is not a U-turn except
-                        // when it is at the end of a dead-end street.
-                        if (!m_restriction_map.CheckIfTurnIsRestricted(u, v, w))
-                        {
-                            // only add an edge if turn is not prohibited
-                            if (std::numeric_limits<unsigned>::max() == m_component_index_list[w])
-                            {
-                                // insert next (node, parent) only if w has
-                                // not yet been explored
-                                // mark node as read
-                                m_component_index_list[w] = current_component;
-                                bfs_queue.emplace(w, v);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        return current_component_size;
-    }
-
-    std::vector<unsigned> m_component_index_list;
-    std::vector<NodeID> m_component_index_size;
-
-    const GraphT &m_graph;
-    const RestrictionMap &m_restriction_map;
-    const std::unordered_set<NodeID> &m_barrier_nodes;
-};
-
-#endif
diff --git a/Algorithms/ObjectToBase64.h b/Algorithms/ObjectToBase64.h
deleted file mode 100644
index 2599283..0000000
--- a/Algorithms/ObjectToBase64.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef OBJECTTOBASE64_H_
-#define OBJECTTOBASE64_H_
-
-#include "../Util/StringUtil.h"
-
-#include <boost/assert.hpp>
-#include <boost/archive/iterators/base64_from_binary.hpp>
-#include <boost/archive/iterators/binary_from_base64.hpp>
-#include <boost/archive/iterators/transform_width.hpp>
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-typedef
-        boost::archive::iterators::base64_from_binary<
-            boost::archive::iterators::transform_width<const char *, 6, 8>
-        > base64_t;
-
-typedef
-        boost::archive::iterators::transform_width<
-            boost::archive::iterators::binary_from_base64<
-            std::string::const_iterator>, 8, 6
-        > binary_t;
-
-template<class ObjectT>
-static void EncodeObjectToBase64(const ObjectT & object, std::string& encoded) {
-    const char * char_ptr_to_object = (const char *)&object;
-    std::vector<unsigned char> data(sizeof(object));
-    std::copy(
-        char_ptr_to_object,
-        char_ptr_to_object + sizeof(ObjectT),
-        data.begin()
-    );
-
-    unsigned char number_of_padded_chars = 0; // is in {0,1,2};
-    while(data.size() % 3 != 0)  {
-      ++number_of_padded_chars;
-      data.push_back(0x00);
-    }
-
-    BOOST_ASSERT_MSG(
-        0 == data.size() % 3,
-        "base64 input data size is not a multiple of 3!"
-    );
-    encoded.resize(sizeof(ObjectT));
-    encoded.assign(
-        base64_t( &data[0] ),
-        base64_t( &data[0] + (data.size() - number_of_padded_chars) )
-    );
-    replaceAll(encoded, "+", "-");
-    replaceAll(encoded, "/", "_");
-}
-
-template<class ObjectT>
-static void DecodeObjectFromBase64(const std::string& input, ObjectT & object) {
-    try {
-    	std::string encoded(input);
-        //replace "-" with "+" and "_" with "/"
-        replaceAll(encoded, "-", "+");
-        replaceAll(encoded, "_", "/");
-
-        std::copy (
-            binary_t( encoded.begin() ),
-            binary_t( encoded.begin() + encoded.length() - 1),
-            (char *)&object
-        );
-
-    } catch(...) { }
-}
-
-#endif /* OBJECTTOBASE64_H_ */
diff --git a/Algorithms/StronglyConnectedComponents.h b/Algorithms/StronglyConnectedComponents.h
deleted file mode 100644
index e0c31f9..0000000
--- a/Algorithms/StronglyConnectedComponents.h
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef STRONGLYCONNECTEDCOMPONENTS_H_
-#define STRONGLYCONNECTEDCOMPONENTS_H_
-
-#include "../typedefs.h"
-#include "../DataStructures/DeallocatingVector.h"
-#include "../DataStructures/DynamicGraph.h"
-#include "../DataStructures/ImportEdge.h"
-#include "../DataStructures/QueryNode.h"
-#include "../DataStructures/Percent.h"
-#include "../DataStructures/Restriction.h"
-#include "../DataStructures/TurnInstructions.h"
-
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/StdHashExtensions.h"
-
-#include <osrm/Coordinate.h>
-
-#include <boost/assert.hpp>
-#include <boost/filesystem.hpp>
-
-#ifdef __APPLE__
-#include <gdal.h>
-#include <ogrsf_frmts.h>
-#else
-#include <gdal/gdal.h>
-#include <gdal/ogrsf_frmts.h>
-#endif
-
-#include <cstdint>
-
-#include <memory>
-#include <stack>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-class TarjanSCC
-{
-  private:
-    struct TarjanNode
-    {
-        TarjanNode() : index(UINT_MAX), low_link(UINT_MAX), on_stack(false) {}
-        unsigned index;
-        unsigned low_link;
-        bool on_stack;
-    };
-
-    struct TarjanEdgeData
-    {
-        int distance;
-        unsigned name_id : 31;
-        bool shortcut : 1;
-        short type;
-        bool forward : 1;
-        bool backward : 1;
-        bool reversedEdge : 1;
-    };
-
-    struct TarjanStackFrame
-    {
-        explicit TarjanStackFrame(NodeID v, NodeID parent) : v(v), parent(parent) {}
-        NodeID v;
-        NodeID parent;
-    };
-
-    typedef DynamicGraph<TarjanEdgeData> TarjanDynamicGraph;
-    typedef TarjanDynamicGraph::InputEdge TarjanEdge;
-    typedef std::pair<NodeID, NodeID> RestrictionSource;
-    typedef std::pair<NodeID, bool> restriction_target;
-    typedef std::vector<restriction_target> EmanatingRestrictionsVector;
-    typedef std::unordered_map<RestrictionSource, unsigned> RestrictionMap;
-
-    std::vector<NodeInfo> m_coordinate_list;
-    std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
-    std::shared_ptr<TarjanDynamicGraph> m_node_based_graph;
-    std::unordered_set<NodeID> m_barrier_node_list;
-    std::unordered_set<NodeID> m_traffic_light_list;
-    unsigned m_restriction_counter;
-    RestrictionMap m_restriction_map;
-
-  public:
-    TarjanSCC(int number_of_nodes,
-              std::vector<NodeBasedEdge> &input_edges,
-              std::vector<NodeID> &bn,
-              std::vector<NodeID> &tl,
-              std::vector<TurnRestriction> &irs,
-              std::vector<NodeInfo> &nI)
-        : m_coordinate_list(nI), m_restriction_counter(irs.size())
-    {
-        for (const TurnRestriction &restriction : irs)
-        {
-            std::pair<NodeID, NodeID> restrictionSource = {restriction.fromNode,
-                                                           restriction.viaNode};
-            unsigned index;
-            RestrictionMap::iterator restriction_iterator =
-                m_restriction_map.find(restrictionSource);
-            if (restriction_iterator == m_restriction_map.end())
-            {
-                index = m_restriction_bucket_list.size();
-                m_restriction_bucket_list.resize(index + 1);
-                m_restriction_map.emplace(restrictionSource, index);
-            }
-            else
-            {
-                index = restriction_iterator->second;
-                // Map already contains an is_only_*-restriction
-                if (m_restriction_bucket_list.at(index).begin()->second)
-                {
-                    continue;
-                }
-                else if (restriction.flags.isOnly)
-                {
-                    // We are going to insert an is_only_*-restriction. There can be only one.
-                    m_restriction_bucket_list.at(index).clear();
-                }
-            }
-
-            m_restriction_bucket_list.at(index)
-                .emplace_back(restriction.toNode, restriction.flags.isOnly);
-        }
-
-        m_barrier_node_list.insert(bn.begin(), bn.end());
-        m_traffic_light_list.insert(tl.begin(), tl.end());
-
-        DeallocatingVector<TarjanEdge> edge_list;
-        for (const NodeBasedEdge &input_edge : input_edges)
-        {
-            if (input_edge.source == input_edge.target)
-            {
-                continue;
-            }
-
-            TarjanEdge edge;
-            if (input_edge.forward)
-            {
-                edge.source = input_edge.source;
-                edge.target = input_edge.target;
-                edge.data.forward = input_edge.forward;
-                edge.data.backward = input_edge.backward;
-            }
-            else
-            {
-                edge.source = input_edge.target;
-                edge.target = input_edge.source;
-                edge.data.backward = input_edge.forward;
-                edge.data.forward = input_edge.backward;
-            }
-
-            edge.data.distance = (std::max)((int)input_edge.weight, 1);
-            BOOST_ASSERT(edge.data.distance > 0);
-            edge.data.shortcut = false;
-            edge.data.name_id = input_edge.name_id;
-            edge.data.type = input_edge.type;
-            edge.data.reversedEdge = false;
-            edge_list.push_back(edge);
-            if (edge.data.backward)
-            {
-                std::swap(edge.source, edge.target);
-                edge.data.forward = input_edge.backward;
-                edge.data.backward = input_edge.forward;
-                edge.data.reversedEdge = true;
-                edge_list.push_back(edge);
-            }
-        }
-        input_edges.shrink_to_fit();
-        BOOST_ASSERT_MSG(0 == input_edges.size() && 0 == input_edges.capacity(),
-                         "input edge vector not properly deallocated");
-
-        std::sort(edge_list.begin(), edge_list.end());
-        m_node_based_graph = std::make_shared<TarjanDynamicGraph>(number_of_nodes, edge_list);
-    }
-
-    ~TarjanSCC() { m_node_based_graph.reset(); }
-
-    void Run()
-    {
-        // remove files from previous run if exist
-        DeleteFileIfExists("component.dbf");
-        DeleteFileIfExists("component.shx");
-        DeleteFileIfExists("component.shp");
-
-        Percent p(m_node_based_graph->GetNumberOfNodes());
-
-        OGRRegisterAll();
-
-        const char *pszDriverName = "ESRI Shapefile";
-        OGRSFDriver *poDriver =
-            OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(pszDriverName);
-        if (nullptr == poDriver)
-        {
-            throw OSRMException("ESRI Shapefile driver not available");
-        }
-        OGRDataSource *poDS = poDriver->CreateDataSource("component.shp", nullptr);
-
-        if (nullptr == poDS)
-        {
-            throw OSRMException("Creation of output file failed");
-        }
-
-        OGRLayer *poLayer = poDS->CreateLayer("component", nullptr, wkbLineString, nullptr);
-
-        if (nullptr == poLayer)
-        {
-            throw OSRMException("Layer creation failed.");
-        }
-
-        // The following is a hack to distinguish between stuff that happens
-        // before the recursive call and stuff that happens after
-        std::stack<std::pair<bool, TarjanStackFrame>> recursion_stack;
-        // true = stuff before, false = stuff after call
-        std::stack<NodeID> tarjan_stack;
-        std::vector<unsigned> components_index(m_node_based_graph->GetNumberOfNodes(), UINT_MAX);
-        std::vector<NodeID> component_size_vector;
-        std::vector<TarjanNode> tarjan_node_list(m_node_based_graph->GetNumberOfNodes());
-        unsigned component_index = 0, size_of_current_component = 0;
-        int index = 0;
-        NodeID last_node = m_node_based_graph->GetNumberOfNodes();
-        for (NodeID node = 0; node < last_node; ++node)
-        {
-            if (UINT_MAX == components_index[node])
-            {
-                recursion_stack.emplace(true, TarjanStackFrame(node, node));
-            }
-
-            while (!recursion_stack.empty())
-            {
-                const bool before_recursion = recursion_stack.top().first;
-                TarjanStackFrame currentFrame = recursion_stack.top().second;
-                NodeID v = currentFrame.v;
-                recursion_stack.pop();
-
-                if (before_recursion)
-                {
-                    // Mark frame to handle tail of recursion
-                    recursion_stack.emplace(false, currentFrame);
-
-                    // Mark essential information for SCC
-                    tarjan_node_list[v].index = index;
-                    tarjan_node_list[v].low_link = index;
-                    tarjan_stack.push(v);
-                    tarjan_node_list[v].on_stack = true;
-                    ++index;
-
-                    // Traverse outgoing edges
-                    for (auto e2 : m_node_based_graph->GetAdjacentEdgeRange(v))
-                    {
-                        const TarjanDynamicGraph::NodeIterator vprime =
-                            m_node_based_graph->GetTarget(e2);
-                        if (UINT_MAX == tarjan_node_list[vprime].index)
-                        {
-                            recursion_stack.emplace(true, TarjanStackFrame(vprime, v));
-                        }
-                        else
-                        {
-                            if (tarjan_node_list[vprime].on_stack &&
-                                tarjan_node_list[vprime].index < tarjan_node_list[v].low_link)
-                            {
-                                tarjan_node_list[v].low_link = tarjan_node_list[vprime].index;
-                            }
-                        }
-                    }
-                }
-                else
-                {
-                    tarjan_node_list[currentFrame.parent].low_link =
-                        std::min(tarjan_node_list[currentFrame.parent].low_link,
-                                 tarjan_node_list[v].low_link);
-                    // after recursion, lets do cycle checking
-                    // Check if we found a cycle. This is the bottom part of the recursion
-                    if (tarjan_node_list[v].low_link == tarjan_node_list[v].index)
-                    {
-                        NodeID vprime;
-                        do
-                        {
-                            vprime = tarjan_stack.top();
-                            tarjan_stack.pop();
-                            tarjan_node_list[vprime].on_stack = false;
-                            components_index[vprime] = component_index;
-                            ++size_of_current_component;
-                        } while (v != vprime);
-
-                        component_size_vector.emplace_back(size_of_current_component);
-
-                        if (size_of_current_component > 1000)
-                        {
-                            SimpleLogger().Write() << "large component [" << component_index
-                                                   << "]=" << size_of_current_component;
-                        }
-
-                        ++component_index;
-                        size_of_current_component = 0;
-                    }
-                }
-            }
-        }
-
-        SimpleLogger().Write() << "identified: " << component_size_vector.size()
-                               << " many components, marking small components";
-
-        unsigned size_one_counter = std::count_if(component_size_vector.begin(),
-                                                  component_size_vector.end(),
-                                                  [] (unsigned value) { return 1 == value;});
-
-        SimpleLogger().Write() << "identified " << size_one_counter << " SCCs of size 1";
-
-        uint64_t total_network_distance = 0;
-        p.reinit(m_node_based_graph->GetNumberOfNodes());
-        NodeID last_u_node = m_node_based_graph->GetNumberOfNodes();
-        for (NodeID u = 0; u < last_u_node; ++u)
-        {
-            p.printIncrement();
-            for (auto e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
-            {
-                if (!m_node_based_graph->GetEdgeData(e1).reversedEdge)
-                {
-                    continue;
-                }
-                const TarjanDynamicGraph::NodeIterator v = m_node_based_graph->GetTarget(e1);
-
-                total_network_distance +=
-                    100 * FixedPointCoordinate::ApproximateDistance(m_coordinate_list[u].lat,
-                                                                    m_coordinate_list[u].lon,
-                                                                    m_coordinate_list[v].lat,
-                                                                    m_coordinate_list[v].lon);
-
-                if (SHRT_MAX != m_node_based_graph->GetEdgeData(e1).type)
-                {
-                    BOOST_ASSERT(e1 != UINT_MAX);
-                    BOOST_ASSERT(u != UINT_MAX);
-                    BOOST_ASSERT(v != UINT_MAX);
-
-                    const unsigned size_of_containing_component =
-                        std::min(component_size_vector[components_index[u]],
-                                 component_size_vector[components_index[v]]);
-
-                    // edges that end on bollard nodes may actually be in two distinct components
-                    if (size_of_containing_component < 10)
-                    {
-                        OGRLineString lineString;
-                        lineString.addPoint(m_coordinate_list[u].lon / COORDINATE_PRECISION,
-                                            m_coordinate_list[u].lat / COORDINATE_PRECISION);
-                        lineString.addPoint(m_coordinate_list[v].lon / COORDINATE_PRECISION,
-                                            m_coordinate_list[v].lat / COORDINATE_PRECISION);
-
-                        OGRFeature *poFeature = OGRFeature::CreateFeature(poLayer->GetLayerDefn());
-
-                        poFeature->SetGeometry(&lineString);
-                        if (OGRERR_NONE != poLayer->CreateFeature(poFeature))
-                        {
-                            throw OSRMException("Failed to create feature in shapefile.");
-                        }
-                        OGRFeature::DestroyFeature(poFeature);
-                    }
-                }
-            }
-        }
-        OGRDataSource::DestroyDataSource(poDS);
-        std::vector<NodeID>().swap(component_size_vector);
-        BOOST_ASSERT_MSG(0 == component_size_vector.size() && 0 == component_size_vector.capacity(),
-                         "component_size_vector not properly deallocated");
-
-        std::vector<NodeID>().swap(components_index);
-        BOOST_ASSERT_MSG(0 == components_index.size() && 0 == components_index.capacity(),
-                         "icomponents_index not properly deallocated");
-
-        SimpleLogger().Write() << "total network distance: " << (uint64_t)total_network_distance /
-                                                                    100 / 1000. << " km";
-    }
-
-  private:
-    unsigned CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const
-    {
-        std::pair<NodeID, NodeID> restriction_source = {u, v};
-        RestrictionMap::const_iterator restriction_iterator =
-            m_restriction_map.find(restriction_source);
-        if (restriction_iterator != m_restriction_map.end())
-        {
-            const unsigned index = restriction_iterator->second;
-            for (const RestrictionSource &restriction_target : m_restriction_bucket_list.at(index))
-            {
-                if (restriction_target.second)
-                {
-                    return restriction_target.first;
-                }
-            }
-        }
-        return UINT_MAX;
-    }
-
-    bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const
-    {
-        // only add an edge if turn is not a U-turn except it is the end of dead-end street.
-        std::pair<NodeID, NodeID> restriction_source = {u, v};
-        RestrictionMap::const_iterator restriction_iterator =
-            m_restriction_map.find(restriction_source);
-        if (restriction_iterator != m_restriction_map.end())
-        {
-            const unsigned index = restriction_iterator->second;
-            for (const restriction_target &restriction_target : m_restriction_bucket_list.at(index))
-            {
-                if (w == restriction_target.first)
-                {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    void DeleteFileIfExists(const std::string &file_name) const
-    {
-        if (boost::filesystem::exists(file_name))
-        {
-            boost::filesystem::remove(file_name);
-        }
-    }
-};
-
-#endif /* STRONGLYCONNECTEDCOMPONENTS_H_ */
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dc202c8..b6a40f9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,11 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.8)
+
+if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR AND NOT MSVC_IDE)
+  message(FATAL_ERROR "In-source builds are not allowed.
+Please create a directory and run cmake from there, passing the path to this source directory as the last argument.
+This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. Please delete them.")
+endif()
+
 project(OSRM)
 set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
 include(CheckCXXCompilerFlag)
@@ -20,43 +27,56 @@ if (WIN32 AND MSVC_VERSION LESS 1800)
   message(FATAL_ERROR "Building with Microsoft compiler needs Visual Studio 2013 or later (Express version works too)")
 endif()
 
-OPTION(WITH_TOOLS "Build ORSM tools" OFF)
+OPTION(WITH_TOOLS "Build OSRM tools" OFF)
+OPTION(BUILD_TOOLS "Build OSRM tools" OFF)
 
 include_directories(${CMAKE_SOURCE_DIR}/Include/)
+include_directories(${CMAKE_SOURCE_DIR}/third_party/)
 
-add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp FingerPrint.cpp.alwaysbuild
+add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/finger_print.cpp finger_print.cpp.alwaysbuild
   COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR}
     -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FingerPrint-Config.cmake
   DEPENDS
-    ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp.in
-  COMMENT "Configuring FingerPrint.cpp"
+    ${CMAKE_SOURCE_DIR}/Util/finger_print.cpp.in
+  COMMENT "Configuring finger_print.cpp"
   VERBATIM)
 
-add_custom_target(FingerPrintConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp)
+add_custom_target(FingerPrintConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/finger_print.cpp)
+add_custom_target(tests DEPENDS datastructure-tests algorithm-tests)
+add_custom_target(benchmarks DEPENDS rtree-bench)
 
-set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread)
+set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread unit_test_framework)
 
 configure_file(
-  ${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp.in
-  ${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp
+  ${CMAKE_SOURCE_DIR}/Util/git_sha.cpp.in
+  ${CMAKE_SOURCE_DIR}/Util/git_sha.cpp
 )
-file(GLOB ExtractorGlob Extractor/*.cpp)
-file(GLOB ImporterGlob DataStructures/Import*.cpp)
-add_library(IMPORT STATIC ${ImporterGlob})
-set(ExtractorSources extractor.cpp ${ExtractorGlob})
-add_executable(osrm-extract ${ExtractorSources})
+file(GLOB ExtractorGlob extractor/*.cpp)
+file(GLOB ImporterGlob data_structures/import_edge.cpp data_structures/external_memory_node.cpp)
+add_library(IMPORT OBJECT ${ImporterGlob})
+add_library(LOGGER OBJECT Util/simple_logger.cpp)
+add_library(PHANTOMNODE OBJECT data_structures/phantom_node.cpp)
+add_library(EXCEPTION OBJECT Util/osrm_exception.cpp)
 
-file(GLOB PrepareGlob Contractor/*.cpp DataStructures/HilbertValue.cpp DataStructures/RestrictionMap.cpp)
+set(ExtractorSources extract.cpp ${ExtractorGlob})
+add_executable(osrm-extract ${ExtractorSources} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION>)
+
+add_library(RESTRICTION OBJECT data_structures/restriction_map.cpp)
+
+file(GLOB PrepareGlob contractor/*.cpp data_structures/hilbert_value.cpp Util/compute_angle.cpp {RestrictionMapGlob})
 set(PrepareSources prepare.cpp ${PrepareGlob})
-add_executable(osrm-prepare ${PrepareSources})
+add_executable(osrm-prepare ${PrepareSources} $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:EXCEPTION>)
 
 file(GLOB ServerGlob Server/*.cpp)
-file(GLOB DescriptorGlob Descriptors/*.cpp)
-file(GLOB DatastructureGlob DataStructures/SearchEngineData.cpp DataStructures/RouteParameters.cpp)
-file(GLOB CoordinateGlob DataStructures/Coordinate.cpp)
-file(GLOB AlgorithmGlob Algorithms/*.cpp)
+file(GLOB DescriptorGlob descriptors/*.cpp)
+file(GLOB DatastructureGlob data_structures/search_engine_data.cpp data_structures/route_parameters.cpp Util/bearing.cpp)
+list(REMOVE_ITEM DatastructureGlob data_structures/Coordinate.cpp)
+file(GLOB CoordinateGlob data_structures/Coordinate.cpp)
+file(GLOB AlgorithmGlob algorithms/*.cpp)
 file(GLOB HttpGlob Server/Http/*.cpp)
 file(GLOB LibOSRMGlob Library/*.cpp)
+file(GLOB DataStructureTestsGlob UnitTests/data_structures/*.cpp data_structures/hilbert_value.cpp)
+file(GLOB AlgorithmTestsGlob UnitTests/Algorithms/*.cpp)
 
 set(
   OSRMSources
@@ -67,14 +87,21 @@ set(
   ${AlgorithmGlob}
   ${HttpGlob}
 )
-add_library(COORDLIB STATIC ${CoordinateGlob})
-add_library(FINGERPRINT STATIC Util/FingerPrint.cpp)
-add_library(OSRM ${OSRMSources} Util/GitDescription.cpp Util/FingerPrint.cpp)
-add_library(GITDESCRIPTION STATIC Util/GitDescription.cpp)
+add_library(COORDINATE OBJECT ${CoordinateGlob})
+add_library(FINGERPRINT OBJECT Util/finger_print.cpp)
+add_library(GITDESCRIPTION OBJECT Util/git_sha.cpp)
+add_library(OSRM ${OSRMSources} $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION>)
 add_dependencies(FINGERPRINT FingerPrintConfigure)
 
-add_executable(osrm-routed routed.cpp ${ServerGlob})
-add_executable(osrm-datastore datastore.cpp)
+add_executable(osrm-routed routed.cpp ${ServerGlob} $<TARGET_OBJECTS:EXCEPTION>)
+add_executable(osrm-datastore datastore.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION>)
+
+# Unit tests
+add_executable(datastructure-tests EXCLUDE_FROM_ALL UnitTests/datastructure_tests.cpp ${DataStructureTestsGlob} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION>)
+add_executable(algorithm-tests EXCLUDE_FROM_ALL UnitTests/algorithm_tests.cpp ${AlgorithmTestsGlob} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION>)
+
+# Benchmarks
+add_executable(rtree-bench EXCLUDE_FROM_ALL benchmarks/static_rtree.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION>)
 
 # Check the release mode
 if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
@@ -98,7 +125,7 @@ if(CMAKE_BUILD_TYPE MATCHES Release)
 
     # Since gcc 4.9 the LTO format is non-standart ('slim'), so we need to use the build-in tools
     if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND
-        NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0")
+        NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0" AND NOT MINGW)
       message(STATUS "Using gcc specific binutils for LTO.")
       set(CMAKE_AR     "/usr/bin/gcc-ar")
       set(CMAKE_RANLIB "/usr/bin/gcc-ranlib")
@@ -106,18 +133,27 @@ if(CMAKE_BUILD_TYPE MATCHES Release)
   endif (HAS_LTO_FLAG)
 endif()
 
+if (NOT WIN32)
+add_definitions(-DBOOST_TEST_DYN_LINK)
+endif()
+
 # Configuring compilers
 if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
   # using Clang
+  #  -Weverything -Wno-c++98-compat -Wno-shadow -Wno-exit-time-destructors
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wunreachable-code -pedantic -fPIC")
 elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+  set(COLOR_FLAG "-fdiagnostics-color=auto")
+  CHECK_CXX_COMPILER_FLAG("-fdiagnostics-color=auto" HAS_COLOR_FLAG)
+  if(NOT HAS_COLOR_FLAG)
+    set(COLOR_FLAG "")
+  endif()
   # using GCC
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -fPIC")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -fPIC ${COLOR_FLAG}")
   if (WIN32) # using mingw
-    add_definitions(-DM_PI=3.141592653589793238462643383) # define M_PI
+    add_definitions(-D_USE_MATH_DEFINES) # define M_PI, M_1_PI etc.
     add_definitions(-DWIN32)
     SET(OPTIONAL_SOCKET_LIBS ws2_32 wsock32)
-    SET(OPTIONAL_OMP_LIB gomp)
   endif()
 elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
   # using Intel C++
@@ -129,20 +165,11 @@ elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
   add_definitions(-DNOMINMAX) # avoid min and max macros that can break compilation
   add_definitions(-D_USE_MATH_DEFINES) # define M_PI
   add_definitions(-D_WIN32_WINNT=0x0501)
+  add_definitions(-DXML_STATIC)
+  find_library(ws2_32_LIBRARY_PATH ws2_32)
+  target_link_libraries(osrm-extract wsock32 ws2_32)
 endif()
 
-# disable partitioning of LTO process when possible (fixes Debian issues)
-set(LTO_PARTITION_FLAGS "")
-CHECK_CXX_COMPILER_FLAG("-flto-partition=none" HAS_LTO_PARTITION_FLAG)
-if    (HAS_LTO_PARTITION_FLAG)
-  set(LTO_PARTITION_FLAGS "${LTO_PARTITION_FLAGS} -flto-partition=none")
-endif (HAS_LTO_PARTITION_FLAG)
-
-# Add Link-Time-Optimization flags, if supported (GCC >= 4.7) and enabled
-set(CMAKE_CXX_FLAGS           "${CMAKE_CXX_FLAGS}           ${LTO_FLAGS}")
-set(CMAKE_EXE_LINKER_FLAGS    "${CMAKE_EXE_LINKER_FLAGS}    ${LTO_FLAGS} ${LTO_PARTITION_FLAGS}")
-set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LTO_FLAGS} ${LTO_PARTITION_FLAGS}")
-
 # Activate C++11
 if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
   ADD_DEFINITIONS(-std=c++11)
@@ -177,16 +204,23 @@ if(NOT Boost_FOUND)
 endif()
 include_directories(${Boost_INCLUDE_DIRS})
 
-target_link_libraries(OSRM ${Boost_LIBRARIES} COORDLIB)
-target_link_libraries(osrm-extract ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB IMPORT)
-target_link_libraries(osrm-prepare ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB IMPORT)
-target_link_libraries(osrm-routed ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM FINGERPRINT GITDESCRIPTION)
-target_link_libraries(osrm-datastore ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB)
+target_link_libraries(OSRM ${Boost_LIBRARIES})
+target_link_libraries(osrm-extract ${Boost_LIBRARIES})
+target_link_libraries(osrm-prepare ${Boost_LIBRARIES})
+target_link_libraries(osrm-routed ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
+target_link_libraries(osrm-datastore ${Boost_LIBRARIES})
+target_link_libraries(datastructure-tests ${Boost_LIBRARIES})
+target_link_libraries(algorithm-tests ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
+target_link_libraries(rtree-bench ${Boost_LIBRARIES})
 
 find_package(Threads REQUIRED)
-target_link_libraries(osrm-extract ${CMAKE_THREAD_LIBS_INIT} ${OPTIONAL_OMP_LIB})
+target_link_libraries(osrm-extract ${CMAKE_THREAD_LIBS_INIT})
 target_link_libraries(osrm-datastore ${CMAKE_THREAD_LIBS_INIT})
+target_link_libraries(osrm-prepare ${CMAKE_THREAD_LIBS_INIT})
 target_link_libraries(OSRM ${CMAKE_THREAD_LIBS_INIT})
+target_link_libraries(datastructure-tests ${CMAKE_THREAD_LIBS_INIT})
+target_link_libraries(algorithm-tests ${CMAKE_THREAD_LIBS_INIT})
+target_link_libraries(rtree-bench ${CMAKE_THREAD_LIBS_INIT})
 
 find_package(TBB REQUIRED)
 if(WIN32 AND CMAKE_BUILD_TYPE MATCHES Debug)
@@ -196,21 +230,14 @@ target_link_libraries(osrm-datastore ${TBB_LIBRARIES})
 target_link_libraries(osrm-extract ${TBB_LIBRARIES})
 target_link_libraries(osrm-prepare ${TBB_LIBRARIES})
 target_link_libraries(osrm-routed ${TBB_LIBRARIES})
+target_link_libraries(datastructure-tests ${TBB_LIBRARIES})
+target_link_libraries(algorithm-tests ${TBB_LIBRARIES})
+target_link_libraries(rtree-bench ${TBB_LIBRARIES})
 include_directories(${TBB_INCLUDE_DIR})
 
-find_package(Lua52)
-if(NOT LUA52_FOUND)
-  find_package(Lua51 REQUIRED)
-  if(NOT APPLE)
-    find_package(LuaJIT 5.1)
-  endif()
-else()
-  if(NOT APPLE)
-    find_package(LuaJIT 5.2)
-  endif()
-endif()
-
 find_package( Luabind REQUIRED )
+include(check_luabind)
+
 include_directories(${LUABIND_INCLUDE_DIR})
 target_link_libraries(osrm-extract ${LUABIND_LIBRARY})
 target_link_libraries(osrm-prepare ${LUABIND_LIBRARY})
@@ -224,9 +251,9 @@ else()
 endif()
 include_directories(${LUA_INCLUDE_DIR})
 
-find_package(LibXml2 REQUIRED)
-include_directories(${LIBXML2_INCLUDE_DIR})
-target_link_libraries(osrm-extract ${LIBXML2_LIBRARIES})
+find_package(EXPAT REQUIRED)
+include_directories(${EXPAT_INCLUDE_DIRS})
+target_link_libraries(osrm-extract ${EXPAT_LIBRARIES})
 
 find_package( STXXL REQUIRED )
 include_directories(${STXXL_INCLUDE_DIR})
@@ -234,6 +261,11 @@ target_link_libraries(OSRM ${STXXL_LIBRARY})
 target_link_libraries(osrm-extract ${STXXL_LIBRARY})
 target_link_libraries(osrm-prepare ${STXXL_LIBRARY})
 
+if(MINGW)
+  # STXXL needs OpenMP library
+  target_link_libraries(osrm-extract gomp)
+endif()
+
 find_package( OSMPBF REQUIRED )
 include_directories(${OSMPBF_INCLUDE_DIR})
 target_link_libraries(osrm-extract ${OSMPBF_LIBRARY})
@@ -253,29 +285,40 @@ include_directories(${ZLIB_INCLUDE_DIRS})
 target_link_libraries(osrm-extract ${ZLIB_LIBRARY})
 target_link_libraries(osrm-routed ${ZLIB_LIBRARY})
 
-if(WITH_TOOLS)
+if(WITH_TOOLS OR BUILD_TOOLS)
   message(STATUS "Activating OSRM internal tools")
   find_package(GDAL)
   if(GDAL_FOUND)
-    add_executable(osrm-components Tools/components.cpp)
-    target_link_libraries(osrm-components ${TBB_LIBRARIES} IMPORT)
+    add_executable(osrm-components tools/components.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:EXCEPTION>)
+    target_link_libraries(osrm-components ${TBB_LIBRARIES})
     include_directories(${GDAL_INCLUDE_DIR})
     target_link_libraries(
       osrm-components
-      ${GDAL_LIBRARIES} ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB)
+      ${GDAL_LIBRARIES} ${Boost_LIBRARIES})
+    install(TARGETS osrm-components DESTINATION bin)
   else()
     message(FATAL_ERROR "libgdal and/or development headers not found")
   endif()
-  add_executable(osrm-cli Tools/simpleclient.cpp)
-  target_link_libraries(osrm-cli ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM FINGERPRINT GITDESCRIPTION)
+  add_executable(osrm-cli tools/simpleclient.cpp $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:LOGGER>)
+  target_link_libraries(osrm-cli ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
   target_link_libraries(osrm-cli ${TBB_LIBRARIES})
-  add_executable(osrm-io-benchmark Tools/io-benchmark.cpp)
-  target_link_libraries(osrm-io-benchmark ${Boost_LIBRARIES} GITDESCRIPTION)
-  add_executable(osrm-unlock-all Tools/unlock_all_mutexes.cpp)
-  target_link_libraries(osrm-unlock-all ${Boost_LIBRARIES} GITDESCRIPTION)
+  add_executable(osrm-io-benchmark tools/io-benchmark.cpp $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:LOGGER>)
+  target_link_libraries(osrm-io-benchmark ${Boost_LIBRARIES})
+  add_executable(osrm-unlock-all tools/unlock_all_mutexes.cpp $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION>)
+  target_link_libraries(osrm-unlock-all ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
   if(UNIX AND NOT APPLE)
     target_link_libraries(osrm-unlock-all rt)
   endif()
+  add_executable(osrm-check-hsgr tools/check-hsgr.cpp $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER>)
+  target_link_libraries(osrm-check-hsgr ${Boost_LIBRARIES})
+  add_executable(osrm-springclean tools/springclean.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:EXCEPTION>)
+  target_link_libraries(osrm-springclean ${Boost_LIBRARIES})
+
+  install(TARGETS osrm-cli DESTINATION bin)
+  install(TARGETS osrm-io-benchmark DESTINATION bin)
+  install(TARGETS osrm-unlock-all DESTINATION bin)
+  install(TARGETS osrm-check-hsgr DESTINATION bin)
+  install(TARGETS osrm-springclean DESTINATION bin)
 endif()
 
 file(GLOB InstallGlob Include/osrm/*.h Library/OSRM.h)
@@ -305,3 +348,8 @@ endforeach ()
 
 configure_file(${CMAKE_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY)
 install(FILES ${PROJECT_BINARY_DIR}/libosrm.pc DESTINATION lib/pkgconfig)
+
+if(BUILD_DEBIAN_PACKAGE)
+  include(CPackDebianConfig)
+  include(CPack)
+endif()
diff --git a/Contractor/TemporaryStorage.cpp b/Contractor/TemporaryStorage.cpp
deleted file mode 100644
index f9d4287..0000000
--- a/Contractor/TemporaryStorage.cpp
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "TemporaryStorage.h"
-
-StreamData::StreamData()
-    : write_mode(true),
-      temp_path(boost::filesystem::unique_path(temp_directory / TemporaryFilePattern)),
-      temp_file(new boost::filesystem::fstream(
-          temp_path, std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary)),
-      readWriteMutex(std::make_shared<boost::mutex>())
-{
-    if (temp_file->fail())
-    {
-        throw OSRMException("temporary file could not be created");
-    }
-}
-
-TemporaryStorage::TemporaryStorage() { temp_directory = boost::filesystem::temp_directory_path(); }
-
-TemporaryStorage &TemporaryStorage::GetInstance()
-{
-    static TemporaryStorage static_instance;
-    return static_instance;
-}
-
-TemporaryStorage::~TemporaryStorage() { RemoveAll(); }
-
-void TemporaryStorage::RemoveAll()
-{
-    boost::mutex::scoped_lock lock(mutex);
-    for (unsigned slot_id = 0; slot_id < stream_data_list.size(); ++slot_id)
-    {
-        DeallocateSlot(slot_id);
-    }
-    stream_data_list.clear();
-}
-
-int TemporaryStorage::AllocateSlot()
-{
-    boost::mutex::scoped_lock lock(mutex);
-    try { stream_data_list.push_back(StreamData()); }
-    catch (boost::filesystem::filesystem_error &e) { Abort(e); }
-    CheckIfTemporaryDeviceFull();
-    return stream_data_list.size() - 1;
-}
-
-void TemporaryStorage::DeallocateSlot(const int slot_id)
-{
-    try
-    {
-        StreamData &data = stream_data_list[slot_id];
-        boost::mutex::scoped_lock lock(*data.readWriteMutex);
-        if (!boost::filesystem::exists(data.temp_path))
-        {
-            return;
-        }
-        if (data.temp_file->is_open())
-        {
-            data.temp_file->close();
-        }
-
-        boost::filesystem::remove(data.temp_path);
-    }
-    catch (boost::filesystem::filesystem_error &e) { Abort(e); }
-}
-
-void TemporaryStorage::WriteToSlot(const int slot_id, char *pointer, const std::size_t size)
-{
-    try
-    {
-        StreamData &data = stream_data_list[slot_id];
-        BOOST_ASSERT(data.write_mode);
-
-        boost::mutex::scoped_lock lock(*data.readWriteMutex);
-        BOOST_ASSERT_MSG(data.write_mode, "Writing after first read is not allowed");
-        if (1073741824 < data.buffer.size())
-        {
-            data.temp_file->write(&data.buffer[0], data.buffer.size());
-            // data.temp_file->write(pointer, size);
-            data.buffer.clear();
-            CheckIfTemporaryDeviceFull();
-        }
-        data.buffer.insert(data.buffer.end(), pointer, pointer + size);
-    }
-    catch (boost::filesystem::filesystem_error &e) { Abort(e); }
-}
-void TemporaryStorage::ReadFromSlot(const int slot_id, char *pointer, const std::size_t size)
-{
-    try
-    {
-        StreamData &data = stream_data_list[slot_id];
-        boost::mutex::scoped_lock lock(*data.readWriteMutex);
-        if (data.write_mode)
-        {
-            data.write_mode = false;
-            data.temp_file->write(&data.buffer[0], data.buffer.size());
-            data.buffer.clear();
-            data.temp_file->seekg(data.temp_file->beg);
-            BOOST_ASSERT(data.temp_file->beg == data.temp_file->tellg());
-        }
-        BOOST_ASSERT(!data.write_mode);
-        data.temp_file->read(pointer, size);
-    }
-    catch (boost::filesystem::filesystem_error &error) { Abort(error); }
-}
-
-uint64_t TemporaryStorage::GetFreeBytesOnTemporaryDevice()
-{
-    uint64_t value = -1;
-    try
-    {
-        boost::filesystem::path path = boost::filesystem::temp_directory_path();
-        boost::filesystem::space_info space_info = boost::filesystem::space(path);
-        value = space_info.free;
-    }
-    catch (boost::filesystem::filesystem_error &error) { Abort(error); }
-    return value;
-}
-
-void TemporaryStorage::CheckIfTemporaryDeviceFull()
-{
-    boost::filesystem::path path = boost::filesystem::temp_directory_path();
-    boost::filesystem::space_info space_info = boost::filesystem::space(path);
-    if ((1024 * 1024) > space_info.free)
-    {
-        throw OSRMException("temporary device is full");
-    }
-}
-
-boost::filesystem::fstream::pos_type TemporaryStorage::Tell(const int slot_id)
-{
-    boost::filesystem::fstream::pos_type position;
-    try
-    {
-        StreamData &data = stream_data_list[slot_id];
-        boost::mutex::scoped_lock lock(*data.readWriteMutex);
-        position = data.temp_file->tellp();
-    }
-    catch (boost::filesystem::filesystem_error &e) { Abort(e); }
-    return position;
-}
-
-void TemporaryStorage::Abort(const boost::filesystem::filesystem_error &error)
-{
-    RemoveAll();
-    throw OSRMException(error.what());
-}
diff --git a/Contractor/TemporaryStorage.h b/Contractor/TemporaryStorage.h
deleted file mode 100644
index ca8598b..0000000
--- a/Contractor/TemporaryStorage.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef TEMPORARYSTORAGE_H_
-#define TEMPORARYSTORAGE_H_
-
-#include "../Util/BoostFileSystemFix.h"
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-#include "../typedefs.h"
-
-#include <boost/assert.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
-#include <boost/thread/mutex.hpp>
-
-#include <cstdint>
-
-#include <vector>
-#include <fstream>
-#include <memory>
-
-struct StreamData
-{
-    bool write_mode;
-    boost::filesystem::path temp_path;
-    std::shared_ptr<boost::filesystem::fstream> temp_file;
-    std::shared_ptr<boost::mutex> readWriteMutex;
-    std::vector<char> buffer;
-
-    StreamData();
-};
-
-// This class implements a singleton file storage for temporary data.
-// temporary slots can be accessed by other objects through an int
-// On deallocation every slot gets deallocated
-//
-// Access is sequential, which means, that there is no random access
-// -> Data is written in first phase and reread in second.
-
-static boost::filesystem::path temp_directory;
-static std::string TemporaryFilePattern("OSRM-%%%%-%%%%-%%%%");
-class TemporaryStorage
-{
-  public:
-    static TemporaryStorage &GetInstance();
-    virtual ~TemporaryStorage();
-
-    int AllocateSlot();
-    void DeallocateSlot(const int slot_id);
-    void WriteToSlot(const int slot_id, char *pointer, const std::size_t size);
-    void ReadFromSlot(const int slot_id, char *pointer, const std::size_t size);
-    // returns the number of free bytes
-    uint64_t GetFreeBytesOnTemporaryDevice();
-    boost::filesystem::fstream::pos_type Tell(const int slot_id);
-    void RemoveAll();
-
-  private:
-    TemporaryStorage();
-    TemporaryStorage(TemporaryStorage const &) {};
-
-    TemporaryStorage &operator=(TemporaryStorage const &) { return *this; }
-
-    void Abort(const boost::filesystem::filesystem_error &e);
-    void CheckIfTemporaryDeviceFull();
-
-    // vector of file streams that is used to store temporary data
-    boost::mutex mutex;
-    std::vector<StreamData> stream_data_list;
-};
-
-#endif /* TEMPORARYSTORAGE_H_ */
diff --git a/DataStructures/DeallocatingVector.h b/DataStructures/DeallocatingVector.h
deleted file mode 100644
index 013cc1d..0000000
--- a/DataStructures/DeallocatingVector.h
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef DEALLOCATINGVECTOR_H_
-#define DEALLOCATINGVECTOR_H_
-
-#include <boost/assert.hpp>
-#include <cstring>
-#include <vector>
-
-template <typename ElementT,
-          std::size_t bucketSizeC = 8388608 / sizeof(ElementT),
-          bool DeallocateC = false>
-class DeallocatingVectorIterator : public std::iterator<std::random_access_iterator_tag, ElementT>
-{
-  protected:
-    class DeallocatingVectorIteratorState
-    {
-      private:
-        // make constructors explicit, so we do not mix random access and deallocation iterators.
-        DeallocatingVectorIteratorState();
-
-      public:
-        explicit DeallocatingVectorIteratorState(const DeallocatingVectorIteratorState &r)
-            : index(r.index), bucket_list(r.bucket_list)
-        {
-        }
-        explicit DeallocatingVectorIteratorState(const std::size_t idx,
-                                                 std::vector<ElementT *> &input_list)
-            : index(idx), bucket_list(input_list)
-        {
-        }
-        std::size_t index;
-        std::vector<ElementT *> &bucket_list;
-
-        inline bool operator!=(const DeallocatingVectorIteratorState &other)
-        {
-            return index != other.index;
-        }
-
-        inline bool operator==(const DeallocatingVectorIteratorState &other)
-        {
-            return index == other.index;
-        }
-
-        bool operator<(const DeallocatingVectorIteratorState &other) const
-        {
-            return index < other.index;
-        }
-
-        bool operator>(const DeallocatingVectorIteratorState &other) const
-        {
-            return index > other.index;
-        }
-
-        bool operator>=(const DeallocatingVectorIteratorState &other) const
-        {
-            return index >= other.index;
-        }
-
-        // This is a hack to make assignment operator possible with reference member
-        inline DeallocatingVectorIteratorState &operator=(const DeallocatingVectorIteratorState &a)
-        {
-            if (this != &a)
-            {
-                this->DeallocatingVectorIteratorState::
-                    ~DeallocatingVectorIteratorState();        // explicit non-virtual destructor
-                new (this) DeallocatingVectorIteratorState(a); // placement new
-            }
-            return *this;
-        }
-    };
-
-    DeallocatingVectorIteratorState current_state;
-
-  public:
-    typedef std::random_access_iterator_tag iterator_category;
-    typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::value_type
-    value_type;
-    typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::difference_type
-    difference_type;
-    typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::reference reference;
-    typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::pointer pointer;
-
-    DeallocatingVectorIterator() {}
-
-    template <typename T2>
-    explicit DeallocatingVectorIterator(const DeallocatingVectorIterator<T2> &r)
-        : current_state(r.current_state)
-    {
-    }
-
-    DeallocatingVectorIterator(std::size_t idx, std::vector<ElementT *> &input_list)
-        : current_state(idx, input_list)
-    {
-    }
-    explicit DeallocatingVectorIterator(const DeallocatingVectorIteratorState &r) : current_state(r) {}
-
-    template <typename T2>
-    DeallocatingVectorIterator &operator=(const DeallocatingVectorIterator<T2> &r)
-    {
-        if (DeallocateC)
-        {
-            BOOST_ASSERT(false);
-        }
-        current_state = r.current_state;
-        return *this;
-    }
-
-    inline DeallocatingVectorIterator &operator++()
-    { // prefix
-        ++current_state.index;
-        return *this;
-    }
-
-    inline DeallocatingVectorIterator &operator--()
-    { // prefix
-        if (DeallocateC)
-        {
-            BOOST_ASSERT(false);
-        }
-        --current_state.index;
-        return *this;
-    }
-
-    inline DeallocatingVectorIterator operator++(int)
-    { // postfix
-        DeallocatingVectorIteratorState my_state(current_state);
-        current_state.index++;
-        return DeallocatingVectorIterator(my_state);
-    }
-    inline DeallocatingVectorIterator operator--(int)
-    { // postfix
-        if (DeallocateC)
-        {
-            BOOST_ASSERT(false);
-        }
-        DeallocatingVectorIteratorState my_state(current_state);
-        current_state.index--;
-        return DeallocatingVectorIterator(my_state);
-    }
-
-    inline DeallocatingVectorIterator operator+(const difference_type &n) const
-    {
-        DeallocatingVectorIteratorState my_state(current_state);
-        my_state.index += n;
-        return DeallocatingVectorIterator(my_state);
-    }
-
-    inline DeallocatingVectorIterator &operator+=(const difference_type &n)
-    {
-        current_state.index += n;
-        return *this;
-    }
-
-    inline DeallocatingVectorIterator operator-(const difference_type &n) const
-    {
-        if (DeallocateC)
-        {
-            BOOST_ASSERT(false);
-        }
-        DeallocatingVectorIteratorState my_state(current_state);
-        my_state.index -= n;
-        return DeallocatingVectorIterator(my_state);
-    }
-
-    inline DeallocatingVectorIterator &operator-=(const difference_type &n) const
-    {
-        if (DeallocateC)
-        {
-            BOOST_ASSERT(false);
-        }
-        current_state.index -= n;
-        return *this;
-    }
-
-    inline reference operator*() const
-    {
-        std::size_t current_bucket = current_state.index / bucketSizeC;
-        std::size_t current_index = current_state.index % bucketSizeC;
-        return (current_state.bucket_list[current_bucket][current_index]);
-    }
-
-    inline pointer operator->() const
-    {
-        std::size_t current_bucket = current_state.index / bucketSizeC;
-        std::size_t current_index = current_state.index % bucketSizeC;
-        return &(current_state.bucket_list[current_bucket][current_index]);
-    }
-
-    inline bool operator!=(const DeallocatingVectorIterator &other)
-    {
-        return current_state != other.current_state;
-    }
-
-    inline bool operator==(const DeallocatingVectorIterator &other)
-    {
-        return current_state == other.current_state;
-    }
-
-    inline bool operator<(const DeallocatingVectorIterator &other) const
-    {
-        return current_state < other.current_state;
-    }
-
-    inline bool operator>(const DeallocatingVectorIterator &other) const
-    {
-        return current_state > other.current_state;
-    }
-
-    inline bool operator>=(const DeallocatingVectorIterator &other) const
-    {
-        return current_state >= other.current_state;
-    }
-
-    difference_type operator-(const DeallocatingVectorIterator &other)
-    {
-        if (DeallocateC)
-        {
-            BOOST_ASSERT(false);
-        }
-        return current_state.index - other.current_state.index;
-    }
-};
-
-template <typename ElementT, std::size_t bucketSizeC = 8388608 / sizeof(ElementT)>
-class DeallocatingVector
-{
-  private:
-    std::size_t current_size;
-    std::vector<ElementT *> bucket_list;
-
-  public:
-    typedef ElementT value_type;
-    typedef DeallocatingVectorIterator<ElementT, bucketSizeC, false> iterator;
-    typedef DeallocatingVectorIterator<ElementT, bucketSizeC, false> const_iterator;
-
-    // this iterator deallocates all buckets that have been visited. Iterators to visited objects
-    // become invalid.
-    typedef DeallocatingVectorIterator<ElementT, bucketSizeC, true> deallocation_iterator;
-
-    DeallocatingVector() : current_size(0)
-    {
-        // initial bucket
-        bucket_list.emplace_back(new ElementT[bucketSizeC]);
-    }
-
-    ~DeallocatingVector() { clear(); }
-
-    inline void swap(DeallocatingVector<ElementT, bucketSizeC> &other)
-    {
-        std::swap(current_size, other.current_size);
-        bucket_list.swap(other.bucket_list);
-    }
-
-    inline void clear()
-    {
-        // Delete[]'ing ptr's to all Buckets
-        for (unsigned i = 0; i < bucket_list.size(); ++i)
-        {
-            if (nullptr != bucket_list[i])
-            {
-                delete[] bucket_list[i];
-                bucket_list[i] = nullptr;
-            }
-        }
-        // Removing all ptrs from vector
-        std::vector<ElementT *>().swap(bucket_list);
-        current_size = 0;
-    }
-
-    inline void push_back(const ElementT &element)
-    {
-        const std::size_t current_capacity = capacity();
-        if (current_size == current_capacity)
-        {
-            bucket_list.push_back(new ElementT[bucketSizeC]);
-        }
-
-        std::size_t current_index = size() % bucketSizeC;
-        bucket_list.back()[current_index] = element;
-        ++current_size;
-    }
-
-    inline void emplace_back(const ElementT &&element)
-    {
-        const std::size_t current_capacity = capacity();
-        if (current_size == current_capacity)
-        {
-            bucket_list.push_back(new ElementT[bucketSizeC]);
-        }
-
-        const std::size_t current_index = size() % bucketSizeC;
-        bucket_list.back()[current_index] = element;
-        ++current_size;
-    }
-
-    inline void reserve(const std::size_t) const
-    {
-        // don't do anything
-    }
-
-    inline void resize(const std::size_t new_size)
-    {
-        if (new_size > current_size)
-        {
-            while (capacity() < new_size)
-            {
-                bucket_list.push_back(new ElementT[bucketSizeC]);
-            }
-            current_size = new_size;
-        }
-        if (new_size < current_size)
-        {
-            const std::size_t number_of_necessary_buckets = 1 + (new_size / bucketSizeC);
-
-            for (std::size_t i = number_of_necessary_buckets; i < bucket_list.size(); ++i)
-            {
-                delete[] bucket_list[i];
-            }
-            bucket_list.resize(number_of_necessary_buckets);
-            current_size = new_size;
-        }
-    }
-
-    inline std::size_t size() const { return current_size; }
-
-    inline std::size_t capacity() const { return bucket_list.size() * bucketSizeC; }
-
-    inline iterator begin() { return iterator(static_cast<std::size_t>(0), bucket_list); }
-
-    inline iterator end() { return iterator(size(), bucket_list); }
-
-    inline deallocation_iterator dbegin()
-    {
-        return deallocation_iterator(static_cast<std::size_t>(0), bucket_list);
-    }
-
-    inline deallocation_iterator dend() { return deallocation_iterator(size(), bucket_list); }
-
-    inline const_iterator begin() const
-    {
-        return const_iterator(static_cast<std::size_t>(0), bucket_list);
-    }
-
-    inline const_iterator end() const { return const_iterator(size(), bucket_list); }
-
-    inline ElementT &operator[](const std::size_t index)
-    {
-        std::size_t _bucket = index / bucketSizeC;
-        std::size_t _index = index % bucketSizeC;
-        return (bucket_list[_bucket][_index]);
-    }
-
-    const inline ElementT &operator[](const std::size_t index) const
-    {
-        std::size_t _bucket = index / bucketSizeC;
-        std::size_t _index = index % bucketSizeC;
-        return (bucket_list[_bucket][_index]);
-    }
-
-    inline ElementT &back()
-    {
-        std::size_t _bucket = current_size / bucketSizeC;
-        std::size_t _index = current_size % bucketSizeC;
-        return (bucket_list[_bucket][_index]);
-    }
-
-    const inline ElementT &back() const
-    {
-        std::size_t _bucket = current_size / bucketSizeC;
-        std::size_t _index = current_size % bucketSizeC;
-        return (bucket_list[_bucket][_index]);
-    }
-};
-
-#endif /* DEALLOCATINGVECTOR_H_ */
diff --git a/DataStructures/NodeBasedGraph.h b/DataStructures/NodeBasedGraph.h
deleted file mode 100644
index 98393fb..0000000
--- a/DataStructures/NodeBasedGraph.h
+++ /dev/null
@@ -1,166 +0,0 @@
-#ifndef __NODE_BASED_GRAPH_H__
-#define __NODE_BASED_GRAPH_H__
-
-#include "DynamicGraph.h"
-#include "ImportEdge.h"
-#include "../Util/SimpleLogger.h"
-
-#include <tbb/parallel_sort.h>
-
-#include <memory>
-
-struct NodeBasedEdgeData
-{
-    NodeBasedEdgeData()
-        : distance(INVALID_EDGE_WEIGHT), edgeBasedNodeID(SPECIAL_NODEID),
-          nameID(std::numeric_limits<unsigned>::max()), type(std::numeric_limits<short>::max()),
-          isAccessRestricted(false), shortcut(false), forward(false), backward(false),
-          roundabout(false), ignore_in_grid(false), contraFlow(false)
-    {
-    }
-
-    int distance;
-    unsigned edgeBasedNodeID;
-    unsigned nameID;
-    short type;
-    bool isAccessRestricted : 1;
-    bool shortcut : 1;
-    bool forward : 1;
-    bool backward : 1;
-    bool roundabout : 1;
-    bool ignore_in_grid : 1;
-    bool contraFlow : 1;
-
-    void SwapDirectionFlags()
-    {
-        bool temp_flag = forward;
-        forward = backward;
-        backward = temp_flag;
-    }
-
-    bool IsEqualTo(const NodeBasedEdgeData &other) const
-    {
-        return (forward == other.forward) && (backward == other.backward) &&
-               (nameID == other.nameID) && (ignore_in_grid == other.ignore_in_grid) &&
-               (contraFlow == other.contraFlow);
-    }
-};
-
-typedef DynamicGraph<NodeBasedEdgeData> NodeBasedDynamicGraph;
-
-// Factory method to create NodeBasedDynamicGraph from ImportEdges
-inline std::shared_ptr<NodeBasedDynamicGraph>
-NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge> &input_edge_list)
-{
-    static_assert(sizeof(NodeBasedEdgeData) == 16, "changing node based edge data size changes memory consumption");
-    // tbb::parallel_sort(input_edge_list.begin(), input_edge_list.end());
-
-    DeallocatingVector<NodeBasedDynamicGraph::InputEdge> edges_list;
-    NodeBasedDynamicGraph::InputEdge edge;
-    for (const ImportEdge &import_edge : input_edge_list)
-    {
-        if (import_edge.forward)
-        {
-            edge.source = import_edge.source;
-            edge.target = import_edge.target;
-            edge.data.forward = import_edge.forward;
-            edge.data.backward = import_edge.backward;
-        }
-        else
-        {
-            edge.source = import_edge.target;
-            edge.target = import_edge.source;
-            edge.data.backward = import_edge.forward;
-            edge.data.forward = import_edge.backward;
-        }
-
-        if (edge.source == edge.target)
-        {
-            continue;
-        }
-
-        edge.data.distance = (std::max)((int)import_edge.weight, 1);
-        BOOST_ASSERT(edge.data.distance > 0);
-        edge.data.shortcut = false;
-        edge.data.roundabout = import_edge.roundabout;
-        edge.data.ignore_in_grid = import_edge.in_tiny_cc;
-        edge.data.nameID = import_edge.name_id;
-        edge.data.type = import_edge.type;
-        edge.data.isAccessRestricted = import_edge.access_restricted;
-        edge.data.contraFlow = import_edge.contra_flow;
-        edges_list.push_back(edge);
-
-        if (!import_edge.is_split)
-        {
-            using std::swap; // enable ADL
-            swap(edge.source, edge.target);
-            edge.data.SwapDirectionFlags();
-            edges_list.push_back(edge);
-        }
-    }
-
-    // remove duplicate edges
-    std::sort(edges_list.begin(), edges_list.end());
-    NodeID edge_count = 0;
-    for (NodeID i = 0; i < edges_list.size(); )
-    {
-        const NodeID source = edges_list[i].source;
-        const NodeID target = edges_list[i].target;
-        // remove eigenloops
-        if (source == target)
-        {
-            i++;
-            continue;
-        }
-        NodeBasedDynamicGraph::InputEdge forward_edge;
-        NodeBasedDynamicGraph::InputEdge reverse_edge;
-        forward_edge = reverse_edge = edges_list[i];
-        forward_edge.data.forward = reverse_edge.data.backward = true;
-        forward_edge.data.backward = reverse_edge.data.forward = false;
-        forward_edge.data.shortcut = reverse_edge.data.shortcut = false;
-        forward_edge.data.distance = reverse_edge.data.distance =
-            std::numeric_limits<int>::max();
-        // remove parallel edges
-        while (i < edges_list.size() && edges_list[i].source == source && edges_list[i].target == target)
-        {
-            if (edges_list[i].data.forward)
-            {
-                forward_edge.data.distance =
-                    std::min(edges_list[i].data.distance, forward_edge.data.distance);
-            }
-            if (edges_list[i].data.backward)
-            {
-                reverse_edge.data.distance =
-                    std::min(edges_list[i].data.distance, reverse_edge.data.distance);
-            }
-            ++i;
-        }
-        // merge edges (s,t) and (t,s) into bidirectional edge
-        if (forward_edge.data.distance == reverse_edge.data.distance)
-        {
-            if ((int)forward_edge.data.distance != std::numeric_limits<int>::max())
-            {
-                forward_edge.data.backward = true;
-                edges_list[edge_count++] = forward_edge;
-            }
-        }
-        else
-        { // insert seperate edges
-            if (((int)forward_edge.data.distance) != std::numeric_limits<int>::max())
-            {
-                edges_list[edge_count++] = forward_edge;
-            }
-            if ((int)reverse_edge.data.distance != std::numeric_limits<int>::max())
-            {
-                edges_list[edge_count++] = reverse_edge;
-            }
-        }
-    }
-    edges_list.resize(edge_count);
-    SimpleLogger().Write() << "merged " << edges_list.size() - edge_count << " edges out of " << edges_list.size();
-
-    auto graph = std::make_shared<NodeBasedDynamicGraph>(number_of_nodes, edges_list);
-    return graph;
-}
-
-#endif // __NODE_BASED_GRAPH_H__
diff --git a/DataStructures/PhantomNodes.h b/DataStructures/PhantomNodes.h
deleted file mode 100644
index 2a2a924..0000000
--- a/DataStructures/PhantomNodes.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef PHANTOM_NODES_H
-#define PHANTOM_NODES_H
-
-#include <osrm/Coordinate.h>
-#include "../Util/SimpleLogger.h"
-#include "../typedefs.h"
-
-#include <vector>
-
-struct PhantomNode
-{
-    PhantomNode(NodeID forward_node_id, NodeID reverse_node_id, unsigned name_id,
-                int forward_weight, int reverse_weight, int forward_offset, int reverse_offset,
-                unsigned packed_geometry_id, FixedPointCoordinate &location,
-                unsigned short fwd_segment_position) :
-        forward_node_id(forward_node_id),
-        reverse_node_id(reverse_node_id),
-        name_id(name_id),
-        forward_weight(forward_weight),
-        reverse_weight(reverse_weight),
-        forward_offset(forward_offset),
-        reverse_offset(reverse_offset),
-        packed_geometry_id(packed_geometry_id),
-        location(location),
-        fwd_segment_position(fwd_segment_position)
-    { }
-
-    PhantomNode() :
-        forward_node_id(SPECIAL_NODEID),
-        reverse_node_id(SPECIAL_NODEID),
-        name_id(std::numeric_limits<unsigned>::max()),
-        forward_weight(INVALID_EDGE_WEIGHT),
-        reverse_weight(INVALID_EDGE_WEIGHT),
-        forward_offset(0),
-        reverse_offset(0),
-        packed_geometry_id(SPECIAL_EDGEID),
-        fwd_segment_position(0)
-    { }
-
-    NodeID forward_node_id;
-    NodeID reverse_node_id;
-    unsigned name_id;
-    int forward_weight;
-    int reverse_weight;
-    int forward_offset;
-    int reverse_offset;
-    unsigned packed_geometry_id;
-    FixedPointCoordinate location;
-    unsigned short fwd_segment_position;
-
-    int GetForwardWeightPlusOffset() const
-    {
-        if (SPECIAL_NODEID == forward_node_id)
-        {
-            return 0;
-        }
-        const int result = (forward_offset + forward_weight);
-        return result;
-    }
-
-    int GetReverseWeightPlusOffset() const
-    {
-        if (SPECIAL_NODEID == reverse_node_id)
-        {
-            return 0;
-        }
-        const int result = (reverse_offset + reverse_weight);
-        return result;
-    }
-
-    bool isBidirected() const
-    {
-        return (forward_node_id != SPECIAL_NODEID) &&
-               (reverse_node_id != SPECIAL_NODEID);
-    }
-
-    bool IsCompressed() const
-    {
-        return (forward_offset != 0) || (reverse_offset != 0);
-    }
-
-    bool isValid(const unsigned numberOfNodes) const
-    {
-        return
-            location.isValid() &&
-            (
-                (forward_node_id < numberOfNodes) ||
-                (reverse_node_id < numberOfNodes)
-            ) &&
-            (
-                (forward_weight != INVALID_EDGE_WEIGHT) ||
-                (reverse_weight != INVALID_EDGE_WEIGHT)
-            ) &&
-            (name_id != std::numeric_limits<unsigned>::max()
-        );
-    }
-
-    bool isValid() const
-    {
-        return location.isValid() &&
-               (name_id != std::numeric_limits<unsigned>::max());
-    }
-
-    bool operator==(const PhantomNode & other) const
-    {
-        return location == other.location;
-    }
-};
-
-typedef std::vector<std::vector<PhantomNode>> PhantomNodeArray;
-
-struct PhantomNodeLists
-{
-    std::vector<PhantomNode> source_phantom_list;
-    std::vector<PhantomNode> target_phantom_list;
-};
-
-struct PhantomNodes
-{
-    PhantomNode source_phantom;
-    PhantomNode target_phantom;
-};
-
-inline std::ostream& operator<<(std::ostream &out, const PhantomNodes & pn)
-{
-    out << "source_coord: " << pn.source_phantom.location        << "\n";
-    out << "target_coord: " << pn.target_phantom.location        << std::endl;
-    return out;
-}
-
-inline std::ostream& operator<<(std::ostream &out, const PhantomNode & pn)
-{
-    out <<  "node1: " << pn.forward_node_id      << ", " <<
-            "node2: " << pn.reverse_node_id      << ", " <<
-            "name: "  << pn.name_id              << ", " <<
-            "fwd-w: " << pn.forward_weight       << ", " <<
-            "rev-w: " << pn.reverse_weight       << ", " <<
-            "fwd-o: " << pn.forward_offset       << ", " <<
-            "rev-o: " << pn.reverse_offset       << ", " <<
-            "geom: "  << pn.packed_geometry_id   << ", " <<
-            "pos: "   << pn.fwd_segment_position << ", " <<
-            "loc: "   << pn.location;
-    return out;
-}
-
-#endif // PHANTOM_NODES_H
diff --git a/Descriptors/GPXDescriptor.h b/Descriptors/GPXDescriptor.h
deleted file mode 100644
index 50efd9a..0000000
--- a/Descriptors/GPXDescriptor.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef GPX_DESCRIPTOR_H
-#define GPX_DESCRIPTOR_H
-
-#include "BaseDescriptor.h"
-
-template <class DataFacadeT> class GPXDescriptor : public BaseDescriptor<DataFacadeT>
-{
-  private:
-    DescriptorConfig config;
-    FixedPointCoordinate current;
-    DataFacadeT * facade;
-
-    void AddRoutePoint(const FixedPointCoordinate & coordinate, std::vector<char> & output)
-    {
-        const std::string route_point_head = "<rtept lat=\"";
-        const std::string route_point_middle = " lon=\"";
-        const std::string route_point_tail = "\"></rtept>";
-
-        std::string tmp;
-
-        FixedPointCoordinate::convertInternalLatLonToString(coordinate.lat, tmp);
-        output.insert(output.end(), route_point_head.begin(), route_point_head.end());
-        output.insert(output.end(), tmp.begin(), tmp.end());
-        output.push_back('\"');
-
-        FixedPointCoordinate::convertInternalLatLonToString(coordinate.lon, tmp);
-        output.insert(output.end(), route_point_middle.begin(), route_point_middle.end());
-        output.insert(output.end(), tmp.begin(), tmp.end());
-        output.insert(output.end(), route_point_tail.begin(), route_point_tail.end());
-    }
-
-  public:
-    GPXDescriptor(DataFacadeT *facade) : facade(facade) {}
-
-    void SetConfig(const DescriptorConfig &c) { config = c; }
-
-    // TODO: reorder parameters
-    void Run(const RawRouteData &raw_route, http::Reply &reply)
-    {
-        std::string header("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
-                           "<gpx creator=\"OSRM Routing Engine\" version=\"1.1\" "
-                           "xmlns=\"http://www.topografix.com/GPX/1/1\" "
-                           "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
-                           "xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd"
-                           "\">"
-                           "<metadata><copyright author=\"Project OSRM\"><license>Data (c)"
-                           " OpenStreetMap contributors (ODbL)</license></copyright>"
-                           "</metadata>"
-                           "<rte>");
-        reply.content.insert(reply.content.end(), header.begin(), header.end());
-        const bool found_route = (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT) &&
-                                 (!raw_route.unpacked_path_segments.front().empty());
-        if (found_route)
-        {
-            AddRoutePoint(raw_route.segment_end_coordinates.front().source_phantom.location, reply.content);
-
-            for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments)
-            {
-                for (const PathData &path_data : path_data_vector)
-                {
-                    const FixedPointCoordinate current_coordinate =
-                        facade->GetCoordinateOfNode(path_data.node);
-                    AddRoutePoint(current_coordinate, reply.content);
-                }
-            }
-            AddRoutePoint(raw_route.segment_end_coordinates.back().target_phantom.location, reply.content);
-
-        }
-        std::string footer("</rte></gpx>");
-        reply.content.insert(reply.content.end(), footer.begin(), footer.end());
-    }
-};
-#endif // GPX_DESCRIPTOR_H
diff --git a/Docs/webclient.txt b/Docs/webclient.txt
deleted file mode 100644
index 55fcd15..0000000
--- a/Docs/webclient.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-The javascript based web client is a seperate project available at
-
-https://github.com/DennisSchiefer/Project-OSRM-Web
\ No newline at end of file
diff --git a/Extractor/BaseParser.cpp b/Extractor/BaseParser.cpp
deleted file mode 100644
index 4ab090f..0000000
--- a/Extractor/BaseParser.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "BaseParser.h"
-#include "ExtractionWay.h"
-#include "ScriptingEnvironment.h"
-
-#include "../DataStructures/ImportNode.h"
-#include "../Util/LuaUtil.h"
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-
-#include <boost/algorithm/string.hpp>
-#include <boost/algorithm/string/regex.hpp>
-#include <boost/ref.hpp>
-#include <boost/regex.hpp>
-
-BaseParser::BaseParser(ExtractorCallbacks *extractor_callbacks,
-                       ScriptingEnvironment &scripting_environment)
-    : extractor_callbacks(extractor_callbacks),
-      lua_state(scripting_environment.getLuaState()),
-      scripting_environment(scripting_environment), use_turn_restrictions(true)
-{
-    ReadUseRestrictionsSetting();
-    ReadRestrictionExceptions();
-}
-
-void BaseParser::ReadUseRestrictionsSetting()
-{
-    if (0 != luaL_dostring(lua_state, "return use_turn_restrictions\n"))
-    {
-        throw OSRMException("ERROR occured in scripting block");
-    }
-    if (lua_isboolean(lua_state, -1))
-    {
-        use_turn_restrictions = lua_toboolean(lua_state, -1);
-    }
-    if (use_turn_restrictions)
-    {
-        SimpleLogger().Write() << "Using turn restrictions";
-    }
-    else
-    {
-        SimpleLogger().Write() << "Ignoring turn restrictions";
-    }
-}
-
-void BaseParser::ReadRestrictionExceptions()
-{
-    if (lua_function_exists(lua_state, "get_exceptions"))
-    {
-        // get list of turn restriction exceptions
-        luabind::call_function<void>(
-            lua_state, "get_exceptions", boost::ref(restriction_exceptions));
-        const unsigned exception_count = restriction_exceptions.size();
-        SimpleLogger().Write() << "Found " << exception_count
-                               << " exceptions to turn restrictions:";
-        for (const std::string &str : restriction_exceptions)
-        {
-            SimpleLogger().Write() << "  " << str;
-        }
-    }
-    else
-    {
-        SimpleLogger().Write() << "Found no exceptions to turn restrictions";
-    }
-}
-
-void BaseParser::report_errors(lua_State *lua_state, const int status) const
-{
-    if (0 != status)
-    {
-        std::cerr << "-- " << lua_tostring(lua_state, -1) << std::endl;
-        lua_pop(lua_state, 1); // remove error message
-    }
-}
-
-void BaseParser::ParseNodeInLua(ImportNode &node, lua_State *local_lua_state)
-{
-    luabind::call_function<void>(local_lua_state, "node_function", boost::ref(node));
-}
-
-void BaseParser::ParseWayInLua(ExtractionWay &way, lua_State *local_lua_state)
-{
-    luabind::call_function<void>(local_lua_state, "way_function", boost::ref(way));
-}
-
-bool BaseParser::ShouldIgnoreRestriction(const std::string &except_tag_string) const
-{
-    // should this restriction be ignored? yes if there's an overlap between:
-    // a) the list of modes in the except tag of the restriction
-    //    (except_tag_string), eg: except=bus;bicycle
-    // b) the lua profile defines a hierachy of modes,
-    //    eg: [access, vehicle, bicycle]
-
-    if (except_tag_string.empty())
-    {
-        return false;
-    }
-
-    // Be warned, this is quadratic work here, but we assume that
-    // only a few exceptions are actually defined.
-    std::vector<std::string> exceptions;
-    boost::algorithm::split_regex(exceptions, except_tag_string, boost::regex("[;][ ]*"));
-    for (std::string &current_string : exceptions)
-    {
-        const auto string_iterator =
-            std::find(restriction_exceptions.begin(), restriction_exceptions.end(), current_string);
-        if (restriction_exceptions.end() != string_iterator)
-        {
-            return true;
-        }
-    }
-    return false;
-}
diff --git a/Extractor/BaseParser.h b/Extractor/BaseParser.h
deleted file mode 100644
index b18da34..0000000
--- a/Extractor/BaseParser.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef BASEPARSER_H_
-#define BASEPARSER_H_
-
-#include <string>
-#include <vector>
-
-struct lua_State;
-class ExtractorCallbacks;
-class ScriptingEnvironment;
-struct ExtractionWay;
-struct ImportNode;
-
-class BaseParser
-{
-  public:
-    BaseParser() = delete;
-    BaseParser(const BaseParser &) = delete;
-    BaseParser(ExtractorCallbacks *extractor_callbacks,
-               ScriptingEnvironment &scripting_environment);
-    virtual ~BaseParser() {}
-    virtual bool ReadHeader() = 0;
-    virtual bool Parse() = 0;
-
-    virtual void ParseNodeInLua(ImportNode &node, lua_State *lua_state);
-    virtual void ParseWayInLua(ExtractionWay &way, lua_State *lua_state);
-    virtual void report_errors(lua_State *lua_state, const int status) const;
-
-  protected:
-    virtual void ReadUseRestrictionsSetting();
-    virtual void ReadRestrictionExceptions();
-    virtual bool ShouldIgnoreRestriction(const std::string &except_tag_string) const;
-
-    ExtractorCallbacks *extractor_callbacks;
-    lua_State *lua_state;
-    ScriptingEnvironment &scripting_environment;
-    std::vector<std::string> restriction_exceptions;
-    bool use_turn_restrictions;
-};
-
-#endif /* BASEPARSER_H_ */
diff --git a/Extractor/ExtractionWay.h b/Extractor/ExtractionWay.h
deleted file mode 100644
index 6c3c93d..0000000
--- a/Extractor/ExtractionWay.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef EXTRACTION_WAY_H
-#define EXTRACTION_WAY_H
-
-#include "../DataStructures/HashTable.h"
-#include "../typedefs.h"
-
-#include <string>
-#include <vector>
-
-struct ExtractionWay
-{
-    ExtractionWay() { Clear(); }
-
-    inline void Clear()
-    {
-        id = SPECIAL_NODEID;
-        nameID = INVALID_NAMEID;
-        path.clear();
-        keyVals.Clear();
-        direction = ExtractionWay::notSure;
-        speed = -1;
-        backward_speed = -1;
-        duration = -1;
-        type = -1;
-        access = true;
-        roundabout = false;
-        isAccessRestricted = false;
-        ignoreInGrid = false;
-    }
-
-    enum Directions
-    { notSure = 0,
-      oneway,
-      bidirectional,
-      opposite };
-    unsigned id;
-    unsigned nameID;
-    double speed;
-    double backward_speed;
-    double duration;
-    Directions direction;
-    std::string name;
-    short type;
-    bool access;
-    bool roundabout;
-    bool isAccessRestricted;
-    bool ignoreInGrid;
-    std::vector<NodeID> path;
-    HashTable<std::string, std::string> keyVals;
-};
-
-#endif // EXTRACTION_WAY_H
diff --git a/Extractor/ExtractorCallbacks.cpp b/Extractor/ExtractorCallbacks.cpp
deleted file mode 100644
index 5e27817..0000000
--- a/Extractor/ExtractorCallbacks.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "ExtractorCallbacks.h"
-#include "ExtractionContainers.h"
-#include "ExtractionWay.h"
-
-#include "../DataStructures/Restriction.h"
-#include "../DataStructures/ImportNode.h"
-#include "../Util/SimpleLogger.h"
-
-#include <osrm/Coordinate.h>
-
-#include <limits>
-#include <string>
-#include <vector>
-
-ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containers,
-                                       std::unordered_map<std::string, NodeID> &string_map)
-    : string_map(string_map), external_memory(extraction_containers)
-{
-}
-
-/** warning: caller needs to take care of synchronization! */
-void ExtractorCallbacks::ProcessNode(const ExternalMemoryNode &n)
-{
-    if (n.lat <= 85 * COORDINATE_PRECISION && n.lat >= -85 * COORDINATE_PRECISION)
-    {
-        external_memory.all_nodes_list.push_back(n);
-    }
-}
-
-bool ExtractorCallbacks::ProcessRestriction(const InputRestrictionContainer &restriction)
-{
-    external_memory.restrictions_list.push_back(restriction);
-    return true;
-}
-
-/** warning: caller needs to take care of synchronization! */
-void ExtractorCallbacks::ProcessWay(ExtractionWay &parsed_way)
-{
-    if ((0 >= parsed_way.speed) && (0 >= parsed_way.duration))
-    { // Only true if the way is specified by the speed profile
-        return;
-    }
-
-    if (parsed_way.path.size() <= 1)
-    { // safe-guard against broken data
-        return;
-    }
-
-    if (std::numeric_limits<unsigned>::max() == parsed_way.id)
-    {
-        SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << parsed_way.id
-                                       << " of size " << parsed_way.path.size();
-        return;
-    }
-
-    if (0 < parsed_way.duration)
-    {
-        // TODO: iterate all way segments and set duration corresponding to the length of each
-        // segment
-        parsed_way.speed = parsed_way.duration / (parsed_way.path.size() - 1);
-    }
-
-    if (std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.speed))
-    {
-        SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << parsed_way.id;
-        return;
-    }
-
-    // Get the unique identifier for the street name
-    const auto &string_map_iterator = string_map.find(parsed_way.name);
-    if (string_map.end() == string_map_iterator)
-    {
-        parsed_way.nameID = external_memory.name_list.size();
-        external_memory.name_list.push_back(parsed_way.name);
-        string_map.insert(std::make_pair(parsed_way.name, parsed_way.nameID));
-    }
-    else
-    {
-        parsed_way.nameID = string_map_iterator->second;
-    }
-
-    if (ExtractionWay::opposite == parsed_way.direction)
-    {
-        std::reverse(parsed_way.path.begin(), parsed_way.path.end());
-        parsed_way.direction = ExtractionWay::oneway;
-    }
-
-    const bool split_edge =
-        (parsed_way.backward_speed > 0) && (parsed_way.speed != parsed_way.backward_speed);
-
-    for (unsigned n = 0; n < (parsed_way.path.size() - 1); ++n)
-    {
-        external_memory.all_edges_list.push_back(InternalExtractorEdge(
-            parsed_way.path[n],
-            parsed_way.path[n + 1],
-            parsed_way.type,
-            (split_edge ? ExtractionWay::oneway : parsed_way.direction),
-            parsed_way.speed,
-            parsed_way.nameID,
-            parsed_way.roundabout,
-            parsed_way.ignoreInGrid,
-            (0 < parsed_way.duration),
-            parsed_way.isAccessRestricted,
-            false,
-            split_edge));
-        external_memory.used_node_id_list.push_back(parsed_way.path[n]);
-    }
-    external_memory.used_node_id_list.push_back(parsed_way.path.back());
-
-    // The following information is needed to identify start and end segments of restrictions
-    external_memory.way_start_end_id_list.push_back(
-        WayIDStartAndEndEdge(parsed_way.id,
-                             parsed_way.path[0],
-                             parsed_way.path[1],
-                             parsed_way.path[parsed_way.path.size() - 2],
-                             parsed_way.path.back()));
-
-    if (split_edge)
-    { // Only true if the way should be split
-        std::reverse(parsed_way.path.begin(), parsed_way.path.end());
-        for (std::vector<NodeID>::size_type n = 0; n < parsed_way.path.size() - 1; ++n)
-        {
-            external_memory.all_edges_list.push_back(
-                InternalExtractorEdge(parsed_way.path[n],
-                                      parsed_way.path[n + 1],
-                                      parsed_way.type,
-                                      ExtractionWay::oneway,
-                                      parsed_way.backward_speed,
-                                      parsed_way.nameID,
-                                      parsed_way.roundabout,
-                                      parsed_way.ignoreInGrid,
-                                      (0 < parsed_way.duration),
-                                      parsed_way.isAccessRestricted,
-                                      (ExtractionWay::oneway == parsed_way.direction),
-                                      split_edge));
-        }
-        external_memory.way_start_end_id_list.push_back(
-            WayIDStartAndEndEdge(parsed_way.id,
-                                 parsed_way.path[0],
-                                 parsed_way.path[1],
-                                 parsed_way.path[parsed_way.path.size() - 2],
-                                 parsed_way.path.back()));
-    }
-}
diff --git a/Extractor/ExtractorStructs.h b/Extractor/ExtractorStructs.h
deleted file mode 100644
index 51a74c3..0000000
--- a/Extractor/ExtractorStructs.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef EXTRACTORSTRUCTS_H_
-#define EXTRACTORSTRUCTS_H_
-
-#include "../DataStructures/HashTable.h"
-#include "../DataStructures/ImportNode.h"
-#include "../typedefs.h"
-
-#include <limits>
-#include <string>
-
-struct ExtractorRelation
-{
-    ExtractorRelation() : type(unknown) {}
-    enum
-    { unknown = 0,
-      ferry,
-      turnRestriction } type;
-    HashTable<std::string, std::string> keyVals;
-};
-
-struct WayIDStartAndEndEdge
-{
-    unsigned wayID;
-    NodeID firstStart;
-    NodeID firstTarget;
-    NodeID lastStart;
-    NodeID lastTarget;
-    WayIDStartAndEndEdge()
-        : wayID(std::numeric_limits<unsigned>::max()), firstStart(std::numeric_limits<unsigned>::max()), firstTarget(std::numeric_limits<unsigned>::max()), lastStart(std::numeric_limits<unsigned>::max()),
-          lastTarget(std::numeric_limits<unsigned>::max())
-    {
-    }
-
-    explicit WayIDStartAndEndEdge(unsigned w, NodeID fs, NodeID ft, NodeID ls, NodeID lt)
-        : wayID(w), firstStart(fs), firstTarget(ft), lastStart(ls), lastTarget(lt)
-    {
-    }
-
-    static WayIDStartAndEndEdge min_value()
-    {
-        return WayIDStartAndEndEdge((std::numeric_limits<unsigned>::min)(),
-                                    (std::numeric_limits<unsigned>::min)(),
-                                    (std::numeric_limits<unsigned>::min)(),
-                                    (std::numeric_limits<unsigned>::min)(),
-                                    (std::numeric_limits<unsigned>::min)());
-    }
-    static WayIDStartAndEndEdge max_value()
-    {
-        return WayIDStartAndEndEdge((std::numeric_limits<unsigned>::max)(),
-                                    (std::numeric_limits<unsigned>::max)(),
-                                    (std::numeric_limits<unsigned>::max)(),
-                                    (std::numeric_limits<unsigned>::max)(),
-                                    (std::numeric_limits<unsigned>::max)());
-    }
-};
-
-struct CmpWayByID
-{
-    typedef WayIDStartAndEndEdge value_type;
-    bool operator()(const WayIDStartAndEndEdge &a, const WayIDStartAndEndEdge &b) const
-    {
-        return a.wayID < b.wayID;
-    }
-    value_type max_value() { return WayIDStartAndEndEdge::max_value(); }
-    value_type min_value() { return WayIDStartAndEndEdge::min_value(); }
-};
-
-struct Cmp
-{
-    typedef NodeID value_type;
-    bool operator()(const NodeID left, const NodeID right) const { return left < right; }
-    value_type max_value() { return 0xffffffff; }
-    value_type min_value() { return 0x0; }
-};
-
-struct CmpNodeByID
-{
-    typedef ExternalMemoryNode value_type;
-    bool operator()(const ExternalMemoryNode &left, const ExternalMemoryNode &right) const
-    {
-        return left.node_id < right.node_id;
-    }
-    value_type max_value() { return ExternalMemoryNode::max_value(); }
-    value_type min_value() { return ExternalMemoryNode::min_value(); }
-};
-
-#endif /* EXTRACTORSTRUCTS_H_ */
diff --git a/Extractor/PBFParser.cpp b/Extractor/PBFParser.cpp
deleted file mode 100644
index 1abc480..0000000
--- a/Extractor/PBFParser.cpp
+++ /dev/null
@@ -1,664 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "PBFParser.h"
-
-#include "ExtractionWay.h"
-#include "ExtractorCallbacks.h"
-#include "ScriptingEnvironment.h"
-
-#include "../DataStructures/HashTable.h"
-#include "../DataStructures/ImportNode.h"
-#include "../DataStructures/Restriction.h"
-#include "../Util/MachineInfo.h"
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-#include "../typedefs.h"
-
-#include <boost/assert.hpp>
-
-#include <tbb/parallel_for.h>
-#include <tbb/task_scheduler_init.h>
-
-#include <osrm/Coordinate.h>
-
-#include <zlib.h>
-
-#include <functional>
-#include <limits>
-#include <thread>
-
-PBFParser::PBFParser(const char *fileName,
-                     ExtractorCallbacks *extractor_callbacks,
-                     ScriptingEnvironment &scripting_environment,
-                     unsigned num_threads)
-    : BaseParser(extractor_callbacks, scripting_environment)
-{
-    if (0 == num_threads)
-    {
-        num_parser_threads = tbb::task_scheduler_init::default_num_threads();
-    }
-    else
-    {
-        num_parser_threads = num_threads;
-    }
-
-    GOOGLE_PROTOBUF_VERIFY_VERSION;
-    // TODO: What is the bottleneck here? Filling the queue or reading the stuff from disk?
-    // NOTE: With Lua scripting, it is parsing the stuff. I/O is virtually for free.
-
-    // Max 2500 items in queue, hardcoded.
-    thread_data_queue = std::make_shared<ConcurrentQueue<ParserThreadData *>>(2500);
-    input.open(fileName, std::ios::in | std::ios::binary);
-
-    if (!input)
-    {
-        throw OSRMException("pbf file not found.");
-    }
-
-    block_count = 0;
-    group_count = 0;
-}
-
-PBFParser::~PBFParser()
-{
-    if (input.is_open())
-    {
-        input.close();
-    }
-
-    // Clean up any leftover ThreadData objects in the queue
-    ParserThreadData *thread_data;
-    while (thread_data_queue->try_pop(thread_data))
-    {
-        delete thread_data;
-    }
-    google::protobuf::ShutdownProtobufLibrary();
-
-    SimpleLogger().Write(logDEBUG) << "parsed " << block_count << " blocks from pbf with "
-                                   << group_count << " groups";
-}
-
-inline bool PBFParser::ReadHeader()
-{
-    ParserThreadData init_data;
-    /** read Header */
-    if (!readPBFBlobHeader(input, &init_data))
-    {
-        return false;
-    }
-
-    if (readBlob(input, &init_data))
-    {
-        if (!init_data.PBFHeaderBlock.ParseFromArray(&(init_data.charBuffer[0]),
-                                                     static_cast<int>(init_data.charBuffer.size())))
-        {
-            std::cerr << "[error] Header not parseable!" << std::endl;
-            return false;
-        }
-
-        const auto feature_size = init_data.PBFHeaderBlock.required_features_size();
-        for (int i = 0; i < feature_size; ++i)
-        {
-            const std::string &feature = init_data.PBFHeaderBlock.required_features(i);
-            bool supported = false;
-            if ("OsmSchema-V0.6" == feature)
-            {
-                supported = true;
-            }
-            else if ("DenseNodes" == feature)
-            {
-                supported = true;
-            }
-
-            if (!supported)
-            {
-                std::cerr << "[error] required feature not supported: " << feature.data()
-                          << std::endl;
-                return false;
-            }
-        }
-    }
-    else
-    {
-        std::cerr << "[error] blob not loaded!" << std::endl;
-    }
-    return true;
-}
-
-inline void PBFParser::ReadData()
-{
-    bool keep_running = true;
-    do
-    {
-        ParserThreadData *thread_data = new ParserThreadData();
-        keep_running = readNextBlock(input, thread_data);
-
-        if (keep_running)
-        {
-            thread_data_queue->push(thread_data);
-        }
-        else
-        {
-            // No more data to read, parse stops when nullptr encountered
-            thread_data_queue->push(nullptr);
-            delete thread_data;
-        }
-    } while (keep_running);
-}
-
-inline void PBFParser::ParseData()
-{
-    tbb::task_scheduler_init init(num_parser_threads);
-
-    while (true)
-    {
-        ParserThreadData *thread_data;
-        thread_data_queue->wait_and_pop(thread_data);
-        if (nullptr == thread_data)
-        {
-            thread_data_queue->push(nullptr); // Signal end of data for other threads
-            break;
-        }
-
-        loadBlock(thread_data);
-
-        int group_size = thread_data->PBFprimitiveBlock.primitivegroup_size();
-        for (int i = 0; i < group_size; ++i)
-        {
-            thread_data->currentGroupID = i;
-            loadGroup(thread_data);
-
-            if (thread_data->entityTypeIndicator == TypeNode)
-            {
-                parseNode(thread_data);
-            }
-            if (thread_data->entityTypeIndicator == TypeWay)
-            {
-                parseWay(thread_data);
-            }
-            if (thread_data->entityTypeIndicator == TypeRelation)
-            {
-                parseRelation(thread_data);
-            }
-            if (thread_data->entityTypeIndicator == TypeDenseNode)
-            {
-                parseDenseNode(thread_data);
-            }
-        }
-
-        delete thread_data;
-        thread_data = nullptr;
-    }
-}
-
-inline bool PBFParser::Parse()
-{
-    // Start the read and parse threads
-    std::thread read_thread(std::bind(&PBFParser::ReadData, this));
-
-    // Open several parse threads that are synchronized before call to
-    std::thread parse_thread(std::bind(&PBFParser::ParseData, this));
-
-    // Wait for the threads to finish
-    read_thread.join();
-    parse_thread.join();
-
-    return true;
-}
-
-inline void PBFParser::parseDenseNode(ParserThreadData *thread_data)
-{
-    const OSMPBF::DenseNodes &dense =
-        thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).dense();
-    int denseTagIndex = 0;
-    int64_t m_lastDenseID = 0;
-    int64_t m_lastDenseLatitude = 0;
-    int64_t m_lastDenseLongitude = 0;
-
-    const int number_of_nodes = dense.id_size();
-    std::vector<ImportNode> extracted_nodes_vector(number_of_nodes);
-    for (int i = 0; i < number_of_nodes; ++i)
-    {
-        m_lastDenseID += dense.id(i);
-        m_lastDenseLatitude += dense.lat(i);
-        m_lastDenseLongitude += dense.lon(i);
-        extracted_nodes_vector[i].node_id = static_cast<NodeID>(m_lastDenseID);
-        extracted_nodes_vector[i].lat = static_cast<int>(
-            COORDINATE_PRECISION *
-            ((double)m_lastDenseLatitude * thread_data->PBFprimitiveBlock.granularity() +
-             thread_data->PBFprimitiveBlock.lat_offset()) /
-            NANO);
-        extracted_nodes_vector[i].lon = static_cast<int>(
-            COORDINATE_PRECISION *
-            ((double)m_lastDenseLongitude * thread_data->PBFprimitiveBlock.granularity() +
-             thread_data->PBFprimitiveBlock.lon_offset()) /
-            NANO);
-        while (denseTagIndex < dense.keys_vals_size())
-        {
-            const int tagValue = dense.keys_vals(denseTagIndex);
-            if (0 == tagValue)
-            {
-                ++denseTagIndex;
-                break;
-            }
-            const int keyValue = dense.keys_vals(denseTagIndex + 1);
-            const std::string &key = thread_data->PBFprimitiveBlock.stringtable().s(tagValue);
-            const std::string &value = thread_data->PBFprimitiveBlock.stringtable().s(keyValue);
-            extracted_nodes_vector[i].keyVals.Add(std::move(key), std::move(value));
-            denseTagIndex += 2;
-        }
-    }
-
-    tbb::parallel_for(tbb::blocked_range<size_t>(0, extracted_nodes_vector.size()),
-                      [this, &extracted_nodes_vector](const tbb::blocked_range<size_t> &range)
-                      {
-        lua_State *lua_state = this->scripting_environment.getLuaState();
-        for (size_t i = range.begin(); i != range.end(); ++i)
-        {
-            ImportNode &import_node = extracted_nodes_vector[i];
-            ParseNodeInLua(import_node, lua_state);
-        }
-    });
-
-    for (const ImportNode &import_node : extracted_nodes_vector)
-    {
-        extractor_callbacks->ProcessNode(import_node);
-    }
-}
-
-inline void PBFParser::parseNode(ParserThreadData *)
-{
-    throw OSRMException("Parsing of simple nodes not supported. PBF should use dense nodes");
-}
-
-inline void PBFParser::parseRelation(ParserThreadData *thread_data)
-{
-    // TODO: leave early, if relation is not a restriction
-    // TODO: reuse rawRestriction container
-    if (!use_turn_restrictions)
-    {
-        return;
-    }
-    const OSMPBF::PrimitiveGroup &group =
-        thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID);
-
-    for (int i = 0, relation_size = group.relations_size(); i < relation_size; ++i)
-    {
-        std::string except_tag_string;
-        const OSMPBF::Relation &inputRelation =
-            thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).relations(i);
-        bool is_restriction = false;
-        bool is_only_restriction = false;
-        for (int k = 0, endOfKeys = inputRelation.keys_size(); k < endOfKeys; ++k)
-        {
-            const std::string &key =
-                thread_data->PBFprimitiveBlock.stringtable().s(inputRelation.keys(k));
-            const std::string &val =
-                thread_data->PBFprimitiveBlock.stringtable().s(inputRelation.vals(k));
-            if ("type" == key)
-            {
-                if ("restriction" == val)
-                {
-                    is_restriction = true;
-                }
-                else
-                {
-                    break;
-                }
-            }
-            if (("restriction" == key) && (val.find("only_") == 0))
-            {
-                is_only_restriction = true;
-            }
-            if ("except" == key)
-            {
-                except_tag_string = val;
-            }
-        }
-
-        if (is_restriction && ShouldIgnoreRestriction(except_tag_string))
-        {
-            continue;
-        }
-
-        if (is_restriction)
-        {
-            int64_t last_ref = 0;
-            InputRestrictionContainer current_restriction_container(is_only_restriction);
-            for (int rolesIndex = 0, last_role = inputRelation.roles_sid_size();
-                 rolesIndex < last_role;
-                 ++rolesIndex)
-            {
-                const std::string &role = thread_data->PBFprimitiveBlock.stringtable().s(
-                    inputRelation.roles_sid(rolesIndex));
-                last_ref += inputRelation.memids(rolesIndex);
-
-                if (!("from" == role || "to" == role || "via" == role))
-                {
-                    continue;
-                }
-
-                switch (inputRelation.types(rolesIndex))
-                {
-                case 0: // node
-                    if ("from" == role || "to" == role)
-                    { // Only via should be a node
-                        continue;
-                    }
-                    BOOST_ASSERT("via" == role);
-                    if (std::numeric_limits<unsigned>::max() !=
-                        current_restriction_container.viaNode)
-                    {
-                        current_restriction_container.viaNode =
-                            std::numeric_limits<unsigned>::max();
-                    }
-                    BOOST_ASSERT(std::numeric_limits<unsigned>::max() ==
-                                 current_restriction_container.viaNode);
-                    current_restriction_container.restriction.viaNode =
-                        static_cast<NodeID>(last_ref);
-                    break;
-                case 1: // way
-                    BOOST_ASSERT("from" == role || "to" == role || "via" == role);
-                    if ("from" == role)
-                    {
-                        current_restriction_container.fromWay = static_cast<EdgeID>(last_ref);
-                    }
-                    if ("to" == role)
-                    {
-                        current_restriction_container.toWay = static_cast<EdgeID>(last_ref);
-                    }
-                    if ("via" == role)
-                    {
-                        BOOST_ASSERT(current_restriction_container.restriction.toNode ==
-                                     std::numeric_limits<unsigned>::max());
-                        current_restriction_container.viaNode = static_cast<NodeID>(last_ref);
-                    }
-                    break;
-                case 2: // relation, not used. relations relating to relations are evil.
-                    continue;
-                    BOOST_ASSERT(false);
-                    break;
-
-                default: // should not happen
-                    BOOST_ASSERT(false);
-                    break;
-                }
-            }
-            if (!extractor_callbacks->ProcessRestriction(current_restriction_container))
-            {
-                std::cerr << "[PBFParser] relation not parsed" << std::endl;
-            }
-        }
-    }
-}
-
-inline void PBFParser::parseWay(ParserThreadData *thread_data)
-{
-    const int number_of_ways =
-        thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).ways_size();
-    std::vector<ExtractionWay> parsed_way_vector(number_of_ways);
-    for (int i = 0; i < number_of_ways; ++i)
-    {
-        const OSMPBF::Way &input_way =
-            thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).ways(i);
-        parsed_way_vector[i].id = static_cast<EdgeID>(input_way.id());
-        unsigned node_id_in_path = 0;
-        const auto number_of_referenced_nodes = input_way.refs_size();
-        for (auto j = 0; j < number_of_referenced_nodes; ++j)
-        {
-            node_id_in_path += static_cast<NodeID>(input_way.refs(j));
-            parsed_way_vector[i].path.push_back(node_id_in_path);
-        }
-        BOOST_ASSERT(input_way.keys_size() == input_way.vals_size());
-        const auto number_of_keys = input_way.keys_size();
-        for (auto j = 0; j < number_of_keys; ++j)
-        {
-            const std::string &key =
-                thread_data->PBFprimitiveBlock.stringtable().s(input_way.keys(j));
-            const std::string &val =
-                thread_data->PBFprimitiveBlock.stringtable().s(input_way.vals(j));
-            parsed_way_vector[i].keyVals.Add(std::move(key), std::move(val));
-        }
-    }
-
-    // TODO: investigate if schedule guided will be handled by tbb automatically
-    tbb::parallel_for(tbb::blocked_range<size_t>(0, parsed_way_vector.size()),
-                      [this, &parsed_way_vector](const tbb::blocked_range<size_t> &range)
-                      {
-        lua_State *lua_state = this->scripting_environment.getLuaState();
-        for (size_t i = range.begin(); i != range.end(); i++)
-        {
-            ExtractionWay &extraction_way = parsed_way_vector[i];
-            if (2 <= extraction_way.path.size())
-            {
-                ParseWayInLua(extraction_way, lua_state);
-            }
-        }
-    });
-
-    for (ExtractionWay &extraction_way : parsed_way_vector)
-    {
-        if (2 <= extraction_way.path.size())
-        {
-            extractor_callbacks->ProcessWay(extraction_way);
-        }
-    }
-}
-
-inline void PBFParser::loadGroup(ParserThreadData *thread_data)
-{
-#ifndef NDEBUG
-    ++group_count;
-#endif
-
-    const OSMPBF::PrimitiveGroup &group =
-        thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID);
-    thread_data->entityTypeIndicator = TypeDummy;
-    if (0 != group.nodes_size())
-    {
-        thread_data->entityTypeIndicator = TypeNode;
-    }
-    if (0 != group.ways_size())
-    {
-        thread_data->entityTypeIndicator = TypeWay;
-    }
-    if (0 != group.relations_size())
-    {
-        thread_data->entityTypeIndicator = TypeRelation;
-    }
-    if (group.has_dense())
-    {
-        thread_data->entityTypeIndicator = TypeDenseNode;
-        BOOST_ASSERT(0 != group.dense().id_size());
-    }
-    BOOST_ASSERT(thread_data->entityTypeIndicator != TypeDummy);
-}
-
-inline void PBFParser::loadBlock(ParserThreadData *thread_data)
-{
-    ++block_count;
-    thread_data->currentGroupID = 0;
-    thread_data->currentEntityID = 0;
-}
-
-inline bool PBFParser::readPBFBlobHeader(std::fstream &stream, ParserThreadData *thread_data)
-{
-    int size(0);
-    stream.read((char *)&size, sizeof(int));
-    size = SwapEndian(size);
-    if (stream.eof())
-    {
-        return false;
-    }
-    if (size > MAX_BLOB_HEADER_SIZE || size < 0)
-    {
-        return false;
-    }
-    char *data = new char[size];
-    stream.read(data, size * sizeof(data[0]));
-
-    bool dataSuccessfullyParsed = (thread_data->PBFBlobHeader).ParseFromArray(data, size);
-    delete[] data;
-    return dataSuccessfullyParsed;
-}
-
-inline bool PBFParser::unpackZLIB(ParserThreadData *thread_data)
-{
-    auto raw_size = thread_data->PBFBlob.raw_size();
-    char *unpacked_data_array = new char[raw_size];
-    z_stream compressed_data_stream;
-    compressed_data_stream.next_in = (unsigned char *)thread_data->PBFBlob.zlib_data().data();
-    compressed_data_stream.avail_in = thread_data->PBFBlob.zlib_data().size();
-    compressed_data_stream.next_out = (unsigned char *)unpacked_data_array;
-    compressed_data_stream.avail_out = raw_size;
-    compressed_data_stream.zalloc = Z_NULL;
-    compressed_data_stream.zfree = Z_NULL;
-    compressed_data_stream.opaque = Z_NULL;
-    int return_code = inflateInit(&compressed_data_stream);
-    if (return_code != Z_OK)
-    {
-        std::cerr << "[error] failed to init zlib stream" << std::endl;
-        delete[] unpacked_data_array;
-        return false;
-    }
-
-    return_code = inflate(&compressed_data_stream, Z_FINISH);
-    if (return_code != Z_STREAM_END)
-    {
-        std::cerr << "[error] failed to inflate zlib stream" << std::endl;
-        std::cerr << "[error] Error type: " << return_code << std::endl;
-        delete[] unpacked_data_array;
-        return false;
-    }
-
-    return_code = inflateEnd(&compressed_data_stream);
-    if (return_code != Z_OK)
-    {
-        std::cerr << "[error] failed to deinit zlib stream" << std::endl;
-        delete[] unpacked_data_array;
-        return false;
-    }
-
-    thread_data->charBuffer.clear();
-    thread_data->charBuffer.resize(raw_size);
-    std::copy(unpacked_data_array, unpacked_data_array + raw_size, thread_data->charBuffer.begin());
-    delete[] unpacked_data_array;
-    return true;
-}
-
-inline bool PBFParser::unpackLZMA(ParserThreadData *) { return false; }
-
-inline bool PBFParser::readBlob(std::fstream &stream, ParserThreadData *thread_data)
-{
-    if (stream.eof())
-    {
-        return false;
-    }
-
-    const int size = thread_data->PBFBlobHeader.datasize();
-    if (size < 0 || size > MAX_BLOB_SIZE)
-    {
-        std::cerr << "[error] invalid Blob size:" << size << std::endl;
-        return false;
-    }
-
-    char *data = new char[size];
-    stream.read(data, sizeof(data[0]) * size);
-
-    if (!thread_data->PBFBlob.ParseFromArray(data, size))
-    {
-        std::cerr << "[error] failed to parse blob" << std::endl;
-        delete[] data;
-        return false;
-    }
-
-    if (thread_data->PBFBlob.has_raw())
-    {
-        const std::string &data = thread_data->PBFBlob.raw();
-        thread_data->charBuffer.clear();
-        thread_data->charBuffer.resize(data.size());
-        std::copy(data.begin(), data.end(), thread_data->charBuffer.begin());
-    }
-    else if (thread_data->PBFBlob.has_zlib_data())
-    {
-        if (!unpackZLIB(thread_data))
-        {
-            std::cerr << "[error] zlib data encountered that could not be unpacked" << std::endl;
-            delete[] data;
-            return false;
-        }
-    }
-    else if (thread_data->PBFBlob.has_lzma_data())
-    {
-        if (!unpackLZMA(thread_data))
-        {
-            std::cerr << "[error] lzma data encountered that could not be unpacked" << std::endl;
-        }
-        delete[] data;
-        return false;
-    }
-    else
-    {
-        std::cerr << "[error] Blob contains no data" << std::endl;
-        delete[] data;
-        return false;
-    }
-    delete[] data;
-    return true;
-}
-
-bool PBFParser::readNextBlock(std::fstream &stream, ParserThreadData *thread_data)
-{
-    if (stream.eof())
-    {
-        return false;
-    }
-
-    if (!readPBFBlobHeader(stream, thread_data))
-    {
-        return false;
-    }
-
-    if (thread_data->PBFBlobHeader.type() != "OSMData")
-    {
-        return false;
-    }
-
-    if (!readBlob(stream, thread_data))
-    {
-        return false;
-    }
-
-    if (!thread_data->PBFprimitiveBlock.ParseFromArray(&(thread_data->charBuffer[0]),
-                                                       thread_data->charBuffer.size()))
-    {
-        std::cerr << "failed to parse PrimitiveBlock" << std::endl;
-        return false;
-    }
-    return true;
-}
diff --git a/Extractor/PBFParser.h b/Extractor/PBFParser.h
deleted file mode 100644
index c65a29d..0000000
--- a/Extractor/PBFParser.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef PBFPARSER_H_
-#define PBFPARSER_H_
-
-#include "BaseParser.h"
-#include "../DataStructures/ConcurrentQueue.h"
-
-#include <osmpbf/fileformat.pb.h>
-#include <osmpbf/osmformat.pb.h>
-
-#include <fstream>
-#include <memory>
-
-class PBFParser : public BaseParser
-{
-
-    enum EntityType
-    { TypeDummy = 0,
-      TypeNode = 1,
-      TypeWay = 2,
-      TypeRelation = 4,
-      TypeDenseNode = 8 };
-
-    struct ParserThreadData
-    {
-        int currentGroupID;
-        int currentEntityID;
-        EntityType entityTypeIndicator;
-
-        OSMPBF::BlobHeader PBFBlobHeader;
-        OSMPBF::Blob PBFBlob;
-
-        OSMPBF::HeaderBlock PBFHeaderBlock;
-        OSMPBF::PrimitiveBlock PBFprimitiveBlock;
-
-        std::vector<char> charBuffer;
-    };
-
-  public:
-    PBFParser(const char *file_name,
-              ExtractorCallbacks *extractor_callbacks,
-              ScriptingEnvironment &scripting_environment,
-              unsigned num_parser_threads = 0);
-    virtual ~PBFParser();
-
-    inline bool ReadHeader();
-    inline bool Parse();
-
-  private:
-    inline void ReadData();
-    inline void ParseData();
-    inline void parseDenseNode(ParserThreadData *thread_data);
-    inline void parseNode(ParserThreadData *thread_data);
-    inline void parseRelation(ParserThreadData *thread_data);
-    inline void parseWay(ParserThreadData *thread_data);
-
-    inline void loadGroup(ParserThreadData *thread_data);
-    inline void loadBlock(ParserThreadData *thread_data);
-    inline bool readPBFBlobHeader(std::fstream &stream, ParserThreadData *thread_data);
-    inline bool unpackZLIB(ParserThreadData *thread_data);
-    inline bool unpackLZMA(ParserThreadData *thread_data);
-    inline bool readBlob(std::fstream &stream, ParserThreadData *thread_data);
-    inline bool readNextBlock(std::fstream &stream, ParserThreadData *thread_data);
-
-    static const int NANO = 1000 * 1000 * 1000;
-    static const int MAX_BLOB_HEADER_SIZE = 64 * 1024;
-    static const int MAX_BLOB_SIZE = 32 * 1024 * 1024;
-
-    unsigned group_count;
-    unsigned block_count;
-
-    std::fstream input; // the input stream to parse
-    std::shared_ptr<ConcurrentQueue<ParserThreadData *>> thread_data_queue;
-    unsigned num_parser_threads;
-};
-
-#endif /* PBFPARSER_H_ */
diff --git a/Extractor/ScriptingEnvironment.cpp b/Extractor/ScriptingEnvironment.cpp
deleted file mode 100644
index 01dee39..0000000
--- a/Extractor/ScriptingEnvironment.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "ScriptingEnvironment.h"
-
-#include "ExtractionHelperFunctions.h"
-#include "ExtractionWay.h"
-#include "../DataStructures/ImportNode.h"
-#include "../Util/LuaUtil.h"
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-#include "../typedefs.h"
-
-ScriptingEnvironment::ScriptingEnvironment() {}
-ScriptingEnvironment::ScriptingEnvironment(const char *file_name)
-: file_name(file_name)
-{
-    SimpleLogger().Write() << "Using script " << file_name;
-}
-
-void ScriptingEnvironment::initLuaState(lua_State* lua_state)
-{
-    luabind::open(lua_state);
-    // open utility libraries string library;
-    luaL_openlibs(lua_state);
-
-    luaAddScriptFolderToLoadPath(lua_state, file_name.c_str());
-
-    // Add our function to the state's global scope
-    luabind::module(lua_state)[
-        luabind::def("print", LUA_print<std::string>),
-        luabind::def("durationIsValid", durationIsValid),
-        luabind::def("parseDuration", parseDuration)
-    ];
-
-    luabind::module(lua_state)[luabind::class_<HashTable<std::string, std::string>>("keyVals")
-                                    .def("Add", &HashTable<std::string, std::string>::Add)
-                                    .def("Find", &HashTable<std::string, std::string>::Find)
-                                    .def("Holds", &HashTable<std::string, std::string>::Holds)];
-
-    luabind::module(lua_state)[luabind::class_<ImportNode>("Node")
-                                    .def(luabind::constructor<>())
-                                    .def_readwrite("lat", &ImportNode::lat)
-                                    .def_readwrite("lon", &ImportNode::lon)
-                                    .def_readonly("id", &ImportNode::node_id)
-                                    .def_readwrite("bollard", &ImportNode::bollard)
-                                    .def_readwrite("traffic_light", &ImportNode::trafficLight)
-                                    .def_readwrite("tags", &ImportNode::keyVals)];
-
-    luabind::module(lua_state)
-        [luabind::class_<ExtractionWay>("Way")
-             .def(luabind::constructor<>())
-             .def_readonly("id", &ExtractionWay::id)
-             .def_readwrite("name", &ExtractionWay::name)
-             .def_readwrite("speed", &ExtractionWay::speed)
-             .def_readwrite("backward_speed", &ExtractionWay::backward_speed)
-             .def_readwrite("duration", &ExtractionWay::duration)
-             .def_readwrite("type", &ExtractionWay::type)
-             .def_readwrite("access", &ExtractionWay::access)
-             .def_readwrite("roundabout", &ExtractionWay::roundabout)
-             .def_readwrite("is_access_restricted", &ExtractionWay::isAccessRestricted)
-             .def_readwrite("ignore_in_grid", &ExtractionWay::ignoreInGrid)
-             .def_readwrite("tags", &ExtractionWay::keyVals)
-             .def_readwrite("direction", &ExtractionWay::direction)
-             .enum_("constants")[
-                 luabind::value("notSure", 0),
-                 luabind::value("oneway", 1),
-                 luabind::value("bidirectional", 2),
-                 luabind::value("opposite", 3)
-             ]];
-
-    // fails on c++11/OS X 10.9
-    luabind::module(lua_state)[luabind::class_<std::vector<std::string>>("vector").def(
-        "Add",
-        static_cast<void (std::vector<std::string>::*)(const std::string &)>(
-            &std::vector<std::string>::push_back))];
-
-    if (0 != luaL_dofile(lua_state, file_name.c_str()))
-    {
-        throw OSRMException("ERROR occured in scripting block");
-    }
-}
-
-lua_State *ScriptingEnvironment::getLuaState()
-{
-    bool initialized = false;
-    auto& ref = script_contexts.local(initialized);
-    if (!initialized)
-    {
-        std::shared_ptr<lua_State> state(luaL_newstate(), lua_close);
-        ref = state;
-        initLuaState(ref.get());
-    }
-
-    return ref.get();
-}
-
diff --git a/Extractor/XMLParser.cpp b/Extractor/XMLParser.cpp
deleted file mode 100644
index 3a5446e..0000000
--- a/Extractor/XMLParser.cpp
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "XMLParser.h"
-
-#include "ExtractionWay.h"
-#include "ExtractorCallbacks.h"
-
-#include "../DataStructures/HashTable.h"
-#include "../DataStructures/ImportNode.h"
-#include "../DataStructures/InputReaderFactory.h"
-#include "../DataStructures/Restriction.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/StringUtil.h"
-#include "../typedefs.h"
-
-#include <osrm/Coordinate.h>
-
-XMLParser::XMLParser(const char *filename,
-                     ExtractorCallbacks *extractor_callbacks,
-                     ScriptingEnvironment &scripting_environment)
-    : BaseParser(extractor_callbacks, scripting_environment)
-{
-    inputReader = inputReaderFactory(filename);
-}
-
-bool XMLParser::ReadHeader() { return xmlTextReaderRead(inputReader) == 1; }
-bool XMLParser::Parse()
-{
-    while (xmlTextReaderRead(inputReader) == 1)
-    {
-        const int type = xmlTextReaderNodeType(inputReader);
-
-        // 1 is Element
-        if (type != 1)
-        {
-            continue;
-        }
-
-        xmlChar *currentName = xmlTextReaderName(inputReader);
-        if (currentName == nullptr)
-        {
-            continue;
-        }
-
-        if (xmlStrEqual(currentName, (const xmlChar *)"node") == 1)
-        {
-            ImportNode current_node = ReadXMLNode();
-            ParseNodeInLua(current_node, lua_state);
-            extractor_callbacks->ProcessNode(current_node);
-        }
-
-        if (xmlStrEqual(currentName, (const xmlChar *)"way") == 1)
-        {
-            ExtractionWay way = ReadXMLWay();
-            ParseWayInLua(way, lua_state);
-            extractor_callbacks->ProcessWay(way);
-        }
-        if (use_turn_restrictions && xmlStrEqual(currentName, (const xmlChar *)"relation") == 1)
-        {
-            InputRestrictionContainer current_restriction = ReadXMLRestriction();
-            if ((UINT_MAX != current_restriction.fromWay) &&
-                !extractor_callbacks->ProcessRestriction(current_restriction))
-            {
-                std::cerr << "[XMLParser] restriction not parsed" << std::endl;
-            }
-        }
-        xmlFree(currentName);
-    }
-    return true;
-}
-
-InputRestrictionContainer XMLParser::ReadXMLRestriction()
-{
-
-    InputRestrictionContainer restriction;
-
-    if (xmlTextReaderIsEmptyElement(inputReader) == 1)
-    {
-        return restriction;
-    }
-
-    std::string except_tag_string;
-    const int depth = xmlTextReaderDepth(inputReader);
-    while (xmlTextReaderRead(inputReader) == 1)
-    {
-        const int child_type = xmlTextReaderNodeType(inputReader);
-        if (child_type != 1 && child_type != 15)
-        {
-            continue;
-        }
-        const int child_depth = xmlTextReaderDepth(inputReader);
-        xmlChar *child_name = xmlTextReaderName(inputReader);
-        if (child_name == nullptr)
-        {
-            continue;
-        }
-        if (depth == child_depth && child_type == 15 &&
-            xmlStrEqual(child_name, (const xmlChar *)"relation") == 1)
-        {
-            xmlFree(child_name);
-            break;
-        }
-        if (child_type != 1)
-        {
-            xmlFree(child_name);
-            continue;
-        }
-
-        if (xmlStrEqual(child_name, (const xmlChar *)"tag") == 1)
-        {
-            xmlChar *key = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
-            xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
-            if (key != nullptr && value != nullptr)
-            {
-                if (xmlStrEqual(key, (const xmlChar *)"restriction") &&
-                    StringStartsWith((const char *)value, "only_"))
-                {
-                    restriction.restriction.flags.isOnly = true;
-                }
-                if (xmlStrEqual(key, (const xmlChar *)"except"))
-                {
-                    except_tag_string = (const char *)value;
-                }
-            }
-
-            if (key != nullptr)
-            {
-                xmlFree(key);
-            }
-            if (value != nullptr)
-            {
-                xmlFree(value);
-            }
-        }
-        else if (xmlStrEqual(child_name, (const xmlChar *)"member") == 1)
-        {
-            xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
-            if (ref != nullptr)
-            {
-                xmlChar *role = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"role");
-                xmlChar *type = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"type");
-
-                if (xmlStrEqual(role, (const xmlChar *)"to") &&
-                    xmlStrEqual(type, (const xmlChar *)"way"))
-                {
-                    restriction.toWay = StringToUint((const char *)ref);
-                }
-                if (xmlStrEqual(role, (const xmlChar *)"from") &&
-                    xmlStrEqual(type, (const xmlChar *)"way"))
-                {
-                    restriction.fromWay = StringToUint((const char *)ref);
-                }
-                if (xmlStrEqual(role, (const xmlChar *)"via") &&
-                    xmlStrEqual(type, (const xmlChar *)"node"))
-                {
-                    restriction.restriction.viaNode = StringToUint((const char *)ref);
-                }
-
-                if (nullptr != type)
-                {
-                    xmlFree(type);
-                }
-                if (nullptr != role)
-                {
-                    xmlFree(role);
-                }
-                if (nullptr != ref)
-                {
-                    xmlFree(ref);
-                }
-            }
-        }
-        xmlFree(child_name);
-    }
-
-    if (ShouldIgnoreRestriction(except_tag_string))
-    {
-        restriction.fromWay = UINT_MAX; // workaround to ignore the restriction
-    }
-    return restriction;
-}
-
-ExtractionWay XMLParser::ReadXMLWay()
-{
-    ExtractionWay way;
-    if (xmlTextReaderIsEmptyElement(inputReader) == 1)
-    {
-        return way;
-    }
-    const int depth = xmlTextReaderDepth(inputReader);
-    while (xmlTextReaderRead(inputReader) == 1)
-    {
-        const int child_type = xmlTextReaderNodeType(inputReader);
-        if (child_type != 1 && child_type != 15)
-        {
-            continue;
-        }
-        const int child_depth = xmlTextReaderDepth(inputReader);
-        xmlChar *child_name = xmlTextReaderName(inputReader);
-        if (child_name == nullptr)
-        {
-            continue;
-        }
-
-        if (depth == child_depth && child_type == 15 &&
-            xmlStrEqual(child_name, (const xmlChar *)"way") == 1)
-        {
-            xmlChar *node_id = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
-            way.id = StringToUint((char *)node_id);
-            xmlFree(node_id);
-            xmlFree(child_name);
-            break;
-        }
-        if (child_type != 1)
-        {
-            xmlFree(child_name);
-            continue;
-        }
-
-        if (xmlStrEqual(child_name, (const xmlChar *)"tag") == 1)
-        {
-            xmlChar *key = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
-            xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
-
-            if (key != nullptr && value != nullptr)
-            {
-                way.keyVals.Add(std::string((char *)key), std::string((char *)value));
-            }
-            if (key != nullptr)
-            {
-                xmlFree(key);
-            }
-            if (value != nullptr)
-            {
-                xmlFree(value);
-            }
-        }
-        else if (xmlStrEqual(child_name, (const xmlChar *)"nd") == 1)
-        {
-            xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
-            if (ref != nullptr)
-            {
-                way.path.push_back(StringToUint((const char *)ref));
-                xmlFree(ref);
-            }
-        }
-        xmlFree(child_name);
-    }
-    return way;
-}
-
-ImportNode XMLParser::ReadXMLNode()
-{
-    ImportNode node;
-
-    xmlChar *attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lat");
-    if (attribute != nullptr)
-    {
-        node.lat = static_cast<int>(COORDINATE_PRECISION * StringToDouble((const char *)attribute));
-        xmlFree(attribute);
-    }
-    attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lon");
-    if (attribute != nullptr)
-    {
-        node.lon = static_cast<int>(COORDINATE_PRECISION * StringToDouble((const char *)attribute));
-        xmlFree(attribute);
-    }
-    attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
-    if (attribute != nullptr)
-    {
-        node.node_id = StringToUint((const char *)attribute);
-        xmlFree(attribute);
-    }
-
-    if (xmlTextReaderIsEmptyElement(inputReader) == 1)
-    {
-        return node;
-    }
-    const int depth = xmlTextReaderDepth(inputReader);
-    while (xmlTextReaderRead(inputReader) == 1)
-    {
-        const int child_type = xmlTextReaderNodeType(inputReader);
-        // 1 = Element, 15 = EndElement
-        if (child_type != 1 && child_type != 15)
-        {
-            continue;
-        }
-        const int child_depth = xmlTextReaderDepth(inputReader);
-        xmlChar *child_name = xmlTextReaderName(inputReader);
-        if (child_name == nullptr)
-        {
-            continue;
-        }
-
-        if (depth == child_depth && child_type == 15 &&
-            xmlStrEqual(child_name, (const xmlChar *)"node") == 1)
-        {
-            xmlFree(child_name);
-            break;
-        }
-        if (child_type != 1)
-        {
-            xmlFree(child_name);
-            continue;
-        }
-
-        if (xmlStrEqual(child_name, (const xmlChar *)"tag") == 1)
-        {
-            xmlChar *key = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
-            xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
-            if (key != nullptr && value != nullptr)
-            {
-                node.keyVals.Add(std::string((char *)(key)), std::string((char *)(value)));
-            }
-            if (key != nullptr)
-            {
-                xmlFree(key);
-            }
-            if (value != nullptr)
-            {
-                xmlFree(value);
-            }
-        }
-
-        xmlFree(child_name);
-    }
-    return node;
-}
diff --git a/Extractor/XMLParser.h b/Extractor/XMLParser.h
deleted file mode 100644
index 178747a..0000000
--- a/Extractor/XMLParser.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef XMLPARSER_H_
-#define XMLPARSER_H_
-
-#include "BaseParser.h"
-#include "../DataStructures/Restriction.h"
-
-#include <libxml/xmlreader.h>
-
-class ExtractorCallbacks;
-
-class XMLParser : public BaseParser
-{
-  public:
-    XMLParser(const char *filename,
-              ExtractorCallbacks *extractor_callbacks,
-              ScriptingEnvironment &scripting_environment);
-    bool ReadHeader();
-    bool Parse();
-
-  private:
-    InputRestrictionContainer ReadXMLRestriction();
-    ExtractionWay ReadXMLWay();
-    ImportNode ReadXMLNode();
-    xmlTextReaderPtr inputReader;
-};
-
-#endif /* XMLPARSER_H_ */
diff --git a/Include/osrm/Coordinate.h b/Include/osrm/Coordinate.h
index dc05855..baac61f 100644
--- a/Include/osrm/Coordinate.h
+++ b/Include/osrm/Coordinate.h
@@ -28,22 +28,32 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef FIXED_POINT_COORDINATE_H_
 #define FIXED_POINT_COORDINATE_H_
 
-#include <functional>
 #include <iosfwd> //for std::ostream
 #include <string>
+#include <type_traits>
 
-const float COORDINATE_PRECISION = 1000000.f;
-
+namespace
+{
+constexpr float COORDINATE_PRECISION = 1000000.f;
+}
 struct FixedPointCoordinate
 {
     int lat;
     int lon;
 
     FixedPointCoordinate();
-    explicit FixedPointCoordinate(int lat, int lon);
+    FixedPointCoordinate(int lat, int lon);
+
+    template<class T>
+    FixedPointCoordinate(const T &coordinate) : lat(coordinate.lat), lon(coordinate.lon)
+    {
+        static_assert(std::is_same<decltype(lat), decltype(coordinate.lat)>::value, "coordinate types incompatible");
+        static_assert(std::is_same<decltype(lon), decltype(coordinate.lon)>::value, "coordinate types incompatible");
+    }
+
     void Reset();
     bool isSet() const;
-    bool isValid() const;
+    bool is_valid() const;
     bool operator==(const FixedPointCoordinate &other) const;
 
     static double
@@ -55,10 +65,8 @@ struct FixedPointCoordinate
     static float ApproximateEuclideanDistance(const FixedPointCoordinate &first_coordinate,
                                               const FixedPointCoordinate &second_coordinate);
 
-    static float ApproximateEuclideanDistance(const int lat1,
-                                              const int lon1,
-                                              const int lat2,
-                                              const int lon2);
+    static float
+    ApproximateEuclideanDistance(const int lat1, const int lon1, const int lat2, const int lon2);
 
     static float ApproximateSquaredEuclideanDistance(const FixedPointCoordinate &first_coordinate,
                                                      const FixedPointCoordinate &second_coordinate);
@@ -81,10 +89,10 @@ struct FixedPointCoordinate
                                               FixedPointCoordinate &nearest_location,
                                               float &ratio);
 
-    static int OrderedPerpendicularDistanceApproximation(const FixedPointCoordinate& segment_source,
-                                                         const FixedPointCoordinate& segment_target,
-                                                         const FixedPointCoordinate& query_location);
-
+    static int
+    OrderedPerpendicularDistanceApproximation(const FixedPointCoordinate &segment_source,
+                                              const FixedPointCoordinate &segment_target,
+                                              const FixedPointCoordinate &query_location);
 
     static float GetBearing(const FixedPointCoordinate &A, const FixedPointCoordinate &B);
 
diff --git a/Include/osrm/Header.h b/Include/osrm/Header.h
index de0b2ab..d126c4c 100644
--- a/Include/osrm/Header.h
+++ b/Include/osrm/Header.h
@@ -37,7 +37,7 @@ struct Header
 {
     Header& operator=(const Header& other) = default;
     Header(const std::string & name, const std::string & value) : name(name), value(value) {}
-    Header(const Header && other) : name(std::move(other.name)), value(std::move(other.value)) {}
+    Header(Header && other) : name(std::move(other.name)), value(std::move(other.value)) {}
 
     void Clear()
     {
diff --git a/Include/osrm/RouteParameters.h b/Include/osrm/RouteParameters.h
index 89a1774..fd570a1 100644
--- a/Include/osrm/RouteParameters.h
+++ b/Include/osrm/RouteParameters.h
@@ -40,9 +40,15 @@ struct RouteParameters
     RouteParameters();
 
     void setZoomLevel(const short level);
+    
+    void setNumberOfResults(const short number);
 
     void setAlternateRouteFlag(const bool flag);
 
+    void setUTurn(const bool flag);
+
+    void setAllUTurns(const bool flag);
+
     void setDeprecatedAPIFlag(const std::string &);
 
     void setChecksum(const unsigned check_sum);
@@ -71,12 +77,15 @@ struct RouteParameters
     bool geometry;
     bool compression;
     bool deprecatedAPI;
+    bool uturn_default;
     unsigned check_sum;
+    short num_results;
     std::string service;
     std::string output_format;
     std::string jsonp_parameter;
     std::string language;
     std::vector<std::string> hints;
+    std::vector<bool> uturns;
     std::vector<FixedPointCoordinate> coordinates;
 };
 
diff --git a/Library/OSRM.h b/Library/OSRM.h
index 16b9977..372e82c 100644
--- a/Library/OSRM.h
+++ b/Library/OSRM.h
@@ -30,6 +30,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <osrm/ServerPaths.h>
 
+#include <memory>
+
 class OSRM_impl;
 struct RouteParameters;
 
@@ -41,10 +43,10 @@ class Reply;
 class OSRM
 {
   private:
-    OSRM_impl *OSRM_pimpl_;
+    std::unique_ptr<OSRM_impl> OSRM_pimpl_;
 
   public:
-    explicit OSRM(const ServerPaths &paths, const bool use_shared_memory = false);
+    explicit OSRM(ServerPaths paths, const bool use_shared_memory = false);
     ~OSRM();
     void RunQuery(RouteParameters &route_parameters, http::Reply &reply);
 };
diff --git a/Library/OSRM_impl.cpp b/Library/OSRM_impl.cpp
index 5c20b5a..40fef68 100644
--- a/Library/OSRM_impl.cpp
+++ b/Library/OSRM_impl.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -34,18 +34,19 @@ namespace boost { namespace interprocess { class named_mutex; } }
 #include <osrm/RouteParameters.h>
 #include <osrm/ServerPaths.h>
 
-#include "../Plugins/BasePlugin.h"
-#include "../Plugins/DistanceTablePlugin.h"
-#include "../Plugins/HelloWorldPlugin.h"
-#include "../Plugins/LocatePlugin.h"
-#include "../Plugins/NearestPlugin.h"
-#include "../Plugins/TimestampPlugin.h"
-#include "../Plugins/ViaRoutePlugin.h"
+#include "../plugins/distance_table.hpp"
+#include "../plugins/hello_world.hpp"
+#include "../plugins/locate.hpp"
+#include "../plugins/nearest.hpp"
+#include "../plugins/timestamp.hpp"
+#include "../plugins/viaroute.hpp"
 #include "../Server/DataStructures/BaseDataFacade.h"
 #include "../Server/DataStructures/InternalDataFacade.h"
 #include "../Server/DataStructures/SharedBarriers.h"
 #include "../Server/DataStructures/SharedDataFacade.h"
-#include "../Util/SimpleLogger.h"
+#include "../Util/make_unique.hpp"
+#include "../Util/ProgramOptions.h"
+#include "../Util/simple_logger.hpp"
 
 #include <boost/assert.hpp>
 #include <boost/interprocess/sync/named_condition.hpp>
@@ -56,16 +57,17 @@ namespace boost { namespace interprocess { class named_mutex; } }
 #include <utility>
 #include <vector>
 
-OSRM_impl::OSRM_impl(const ServerPaths &server_paths, const bool use_shared_memory)
-    : use_shared_memory(use_shared_memory)
+OSRM_impl::OSRM_impl(ServerPaths server_paths, const bool use_shared_memory)
 {
     if (use_shared_memory)
     {
-        barrier = new SharedBarriers();
+        barrier = osrm::make_unique<SharedBarriers>();
         query_data_facade = new SharedDataFacade<QueryEdge::EdgeData>();
     }
     else
     {
+        // populate base path
+        populate_base_path(server_paths);
         query_data_facade = new InternalDataFacade<QueryEdge::EdgeData>(server_paths);
     }
 
@@ -85,10 +87,6 @@ OSRM_impl::~OSRM_impl()
     {
         delete plugin_pointer.second;
     }
-    if (use_shared_memory)
-    {
-        delete barrier;
-    }
 }
 
 void OSRM_impl::RegisterPlugin(BasePlugin *plugin)
@@ -108,7 +106,7 @@ void OSRM_impl::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
     if (plugin_map.end() != iter)
     {
         reply.status = http::Reply::ok;
-        if (use_shared_memory)
+        if (barrier)
         {
             // lock update pending
             boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock(
@@ -129,7 +127,7 @@ void OSRM_impl::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
         }
 
         iter->second->HandleRequest(route_parameters, reply);
-        if (use_shared_memory)
+        if (barrier)
         {
             // lock query
             boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
@@ -154,12 +152,12 @@ void OSRM_impl::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
 
 // proxy code for compilation firewall
 
-OSRM::OSRM(const ServerPaths &paths, const bool use_shared_memory)
-    : OSRM_pimpl_(new OSRM_impl(paths, use_shared_memory))
+OSRM::OSRM(ServerPaths paths, const bool use_shared_memory)
+    : OSRM_pimpl_(osrm::make_unique<OSRM_impl>(paths, use_shared_memory))
 {
 }
 
-OSRM::~OSRM() { delete OSRM_pimpl_; }
+OSRM::~OSRM() { OSRM_pimpl_.reset(); }
 
 void OSRM::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
 {
diff --git a/Library/OSRM_impl.h b/Library/OSRM_impl.h
index 8ad98bb..e8b47df 100644
--- a/Library/OSRM_impl.h
+++ b/Library/OSRM_impl.h
@@ -34,8 +34,9 @@ struct RouteParameters;
 
 #include <osrm/ServerPaths.h>
 
-#include "../DataStructures/QueryEdge.h"
+#include "../data_structures/query_edge.hpp"
 
+#include <memory>
 #include <unordered_map>
 #include <string>
 
@@ -45,10 +46,10 @@ template <class EdgeDataT> class BaseDataFacade;
 class OSRM_impl
 {
   private:
-    typedef std::unordered_map<std::string, BasePlugin *> PluginMap;
+    using PluginMap = std::unordered_map<std::string, BasePlugin *>;
 
   public:
-    OSRM_impl(const ServerPaths &paths, const bool use_shared_memory);
+    OSRM_impl(ServerPaths paths, const bool use_shared_memory);
     OSRM_impl(const OSRM_impl &) = delete;
     virtual ~OSRM_impl();
     void RunQuery(RouteParameters &route_parameters, http::Reply &reply);
@@ -56,8 +57,8 @@ class OSRM_impl
   private:
     void RegisterPlugin(BasePlugin *plugin);
     PluginMap plugin_map;
-    bool use_shared_memory;
-    SharedBarriers *barrier;
+    // will only be initialized if shared memory is used
+    std::unique_ptr<SharedBarriers> barrier;
     // base class pointer to the objects
     BaseDataFacade<QueryEdge::EdgeData> *query_data_facade;
 };
diff --git a/Plugins/ViaRoutePlugin.h b/Plugins/ViaRoutePlugin.h
deleted file mode 100644
index b82d514..0000000
--- a/Plugins/ViaRoutePlugin.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef VIA_ROUTE_PLUGIN_H
-#define VIA_ROUTE_PLUGIN_H
-
-#include "BasePlugin.h"
-
-#include "../Algorithms/ObjectToBase64.h"
-
-#include "../DataStructures/QueryEdge.h"
-#include "../DataStructures/SearchEngine.h"
-#include "../Descriptors/BaseDescriptor.h"
-#include "../Descriptors/GPXDescriptor.h"
-#include "../Descriptors/JSONDescriptor.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/StringUtil.h"
-#include "../Util/TimingUtil.h"
-
-#include <cstdlib>
-
-#include <algorithm>
-#include <memory>
-#include <unordered_map>
-#include <string>
-#include <vector>
-
-template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
-{
-  private:
-    std::unordered_map<std::string, unsigned> descriptor_table;
-    std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
-
-  public:
-    explicit ViaRoutePlugin(DataFacadeT *facade) : descriptor_string("viaroute"), facade(facade)
-    {
-        search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
-
-        descriptor_table.emplace("json", 0);
-        descriptor_table.emplace("gpx", 1);
-        // descriptor_table.emplace("geojson", 2);
-    }
-
-    virtual ~ViaRoutePlugin() {}
-
-    const std::string GetDescriptor() const { return descriptor_string; }
-
-    void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
-    {
-        // check number of parameters
-        if (2 > route_parameters.coordinates.size() ||
-            std::any_of(begin(route_parameters.coordinates),
-                        end(route_parameters.coordinates),
-                        [&](FixedPointCoordinate coordinate)
-                        { return !coordinate.isValid(); }))
-        {
-            reply = http::Reply::StockReply(http::Reply::badRequest);
-            return;
-        }
-
-        RawRouteData raw_route;
-        raw_route.check_sum = facade->GetCheckSum();
-        for (const FixedPointCoordinate &coordinate : route_parameters.coordinates)
-        {
-            raw_route.raw_via_node_coordinates.emplace_back(coordinate);
-        }
-
-        std::vector<PhantomNode> phantom_node_vector(raw_route.raw_via_node_coordinates.size());
-        const bool checksum_OK = (route_parameters.check_sum == raw_route.check_sum);
-
-        for (unsigned i = 0; i < raw_route.raw_via_node_coordinates.size(); ++i)
-        {
-            if (checksum_OK && i < route_parameters.hints.size() &&
-                !route_parameters.hints[i].empty())
-            {
-                DecodeObjectFromBase64(route_parameters.hints[i], phantom_node_vector[i]);
-                if (phantom_node_vector[i].isValid(facade->GetNumberOfNodes()))
-                {
-                    continue;
-                }
-            }
-            facade->FindPhantomNodeForCoordinate(raw_route.raw_via_node_coordinates[i],
-                                                 phantom_node_vector[i],
-                                                 route_parameters.zoom_level);
-        }
-
-        PhantomNodes current_phantom_node_pair;
-        for (unsigned i = 0; i < phantom_node_vector.size() - 1; ++i)
-        {
-            current_phantom_node_pair.source_phantom = phantom_node_vector[i];
-            current_phantom_node_pair.target_phantom = phantom_node_vector[i + 1];
-            raw_route.segment_end_coordinates.emplace_back(current_phantom_node_pair);
-        }
-
-        const bool is_alternate_requested = route_parameters.alternate_route;
-        const bool is_only_one_segment = (1 == raw_route.segment_end_coordinates.size());
-        if (is_alternate_requested && is_only_one_segment)
-        {
-            search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
-                                                raw_route);
-        }
-        else
-        {
-            search_engine_ptr->shortest_path(raw_route.segment_end_coordinates, raw_route);
-        }
-
-        if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
-        {
-            SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
-        }
-        reply.status = http::Reply::ok;
-
-        DescriptorConfig descriptor_config;
-
-        auto iter = descriptor_table.find(route_parameters.output_format);
-        unsigned descriptor_type = (iter != descriptor_table.end() ? iter->second : 0);
-
-        descriptor_config.zoom_level = route_parameters.zoom_level;
-        descriptor_config.instructions = route_parameters.print_instructions;
-        descriptor_config.geometry = route_parameters.geometry;
-        descriptor_config.encode_geometry = route_parameters.compression;
-
-        std::shared_ptr<BaseDescriptor<DataFacadeT>> descriptor;
-        switch (descriptor_type)
-        {
-        // case 0:
-        //     descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>();
-        //     break;
-        case 1:
-            descriptor = std::make_shared<GPXDescriptor<DataFacadeT>>(facade);
-            break;
-        // case 2:
-        //      descriptor = std::make_shared<GEOJSONDescriptor<DataFacadeT>>();
-        //      break;
-        default:
-            descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>(facade);
-            break;
-        }
-
-        descriptor->SetConfig(descriptor_config);
-        descriptor->Run(raw_route, reply);
-    }
-
-  private:
-    std::string descriptor_string;
-    DataFacadeT *facade;
-};
-
-#endif // VIA_ROUTE_PLUGIN_H
diff --git a/README.md b/README.md
index 1c77f72..624cc1d 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 For instructions on how to compile and run OSRM, please consult the Wiki at
 
-https://github.com/DennisOSRM/Project-OSRM/wiki
+https://github.com/Project-OSRM/osrm-backend/wiki
 
 or use our free and daily updated online service at
 
@@ -35,6 +35,7 @@ When using the code in a (scientific) publication, please cite
 
 | build config |  branch | status |
 |:-------------|:--------|:------------|
-| Project OSRM | master  | [![Build Status](https://travis-ci.org/DennisOSRM/Project-OSRM.png?branch=master)](https://travis-ci.org/DennisOSRM/Project-OSRM) |
-| Project OSRM | develop | [![Build Status](https://travis-ci.org/DennisOSRM/Project-OSRM.png?branch=develop)](https://travis-ci.org/DennisOSRM/Project-OSRM) |
+| Linux        | master  | [![Build Status](https://travis-ci.org/Project-OSRM/osrm-backend.png?branch=master)](https://travis-ci.org/DennisOSRM/Project-OSRM) |
+| Linux        | develop | [![Build Status](https://travis-ci.org/Project-OSRM/osrm-backend.png?branch=develop)](https://travis-ci.org/DennisOSRM/Project-OSRM) |
+| Windows      | master/develop | [![Build status](https://ci.appveyor.com/api/projects/status/4iuo3s9gxprmcjjh)](https://ci.appveyor.com/project/DennisOSRM/osrm-backend) |
 | LUAbind fork | master  | [![Build Status](https://travis-ci.org/DennisOSRM/luabind.png?branch=master)](https://travis-ci.org/DennisOSRM/luabind) |
diff --git a/Rakefile b/Rakefile
index 1c2ce9d..1c848bb 100644
--- a/Rakefile
+++ b/Rakefile
@@ -6,7 +6,7 @@ require 'sys/proctable'
 
 BUILD_FOLDER = 'build'
 DATA_FOLDER = 'sandbox'
-PROFILE = 'examples/postgis'
+PROFILE = 'bicycle'
 OSRM_PORT = 5000
 PROFILES_FOLDER = '../profiles'
 
@@ -181,3 +181,10 @@ end
 desc "Stop, reprocess and restart."
 task :update => [:down,:process,:up] do
 end
+
+
+desc "Remove test cache files."
+task :sweep do
+  system "rm test/cache/*"
+end
+
diff --git a/Server/APIGrammar.h b/Server/APIGrammar.h
index 4c339d0..83a5cd0 100644
--- a/Server/APIGrammar.h
+++ b/Server/APIGrammar.h
@@ -39,8 +39,8 @@ struct APIGrammar : qi::grammar<Iterator>
 {
     explicit APIGrammar(HandlerT * h) : APIGrammar::base_type(api_call), handler(h)
     {
-        api_call = qi::lit('/') >> string[boost::bind(&HandlerT::setService, handler, ::_1)] >> *(query);
-        query    = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | cmp | language | instruction | geometry | alt_route | old_API) ) ;
+        api_call = qi::lit('/') >> string[boost::bind(&HandlerT::setService, handler, ::_1)] >> *(query) >> -(uturns);
+        query    = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | u | cmp | language | instruction | geometry | alt_route | old_API | num_results) ) ;
 
         zoom        = (-qi::lit('&')) >> qi::lit('z')            >> '=' >> qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
         output      = (-qi::lit('&')) >> qi::lit("output")       >> '=' >> string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)];
@@ -51,9 +51,12 @@ struct APIGrammar : qi::grammar<Iterator>
         cmp         = (-qi::lit('&')) >> qi::lit("compression")  >> '=' >> qi::bool_[boost::bind(&HandlerT::setCompressionFlag, handler, ::_1)];
         location    = (-qi::lit('&')) >> qi::lit("loc")          >> '=' >> (qi::double_ >> qi::lit(',') >> qi::double_)[boost::bind(&HandlerT::addCoordinate, handler, ::_1)];
         hint        = (-qi::lit('&')) >> qi::lit("hint")         >> '=' >> stringwithDot[boost::bind(&HandlerT::addHint, handler, ::_1)];
+        u           = (-qi::lit('&')) >> qi::lit("u")            >> '=' >> qi::bool_[boost::bind(&HandlerT::setUTurn, handler, ::_1)];
+        uturns      = (-qi::lit('&')) >> qi::lit("uturns")       >> '=' >> qi::bool_[boost::bind(&HandlerT::setAllUTurns, handler, ::_1)];
         language    = (-qi::lit('&')) >> qi::lit("hl")           >> '=' >> string[boost::bind(&HandlerT::setLanguage, handler, ::_1)];
         alt_route   = (-qi::lit('&')) >> qi::lit("alt")          >> '=' >> qi::bool_[boost::bind(&HandlerT::setAlternateRouteFlag, handler, ::_1)];
         old_API     = (-qi::lit('&')) >> qi::lit("geomformat")   >> '=' >> string[boost::bind(&HandlerT::setDeprecatedAPIFlag, handler, ::_1)];
+        num_results = (-qi::lit('&')) >> qi::lit("num_results")  >> '=' >> qi::short_[boost::bind(&HandlerT::setNumberOfResults, handler, ::_1)];
 
         string            = +(qi::char_("a-zA-Z"));
         stringwithDot     = +(qi::char_("a-zA-Z0-9_.-"));
@@ -63,7 +66,7 @@ struct APIGrammar : qi::grammar<Iterator>
     qi::rule<Iterator> api_call, query;
     qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location, hint,
                                       stringwithDot, stringwithPercent, language, instruction, geometry,
-                                      cmp, alt_route, old_API;
+                                      cmp, alt_route, u, uturns, old_API, num_results;
 
     HandlerT * handler;
 };
diff --git a/Server/Connection.cpp b/Server/Connection.cpp
index 674fe62..82402a6 100644
--- a/Server/Connection.cpp
+++ b/Server/Connection.cpp
@@ -69,10 +69,10 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
     CompressionType compression_type(noCompression);
     boost::tribool result;
     boost::tie(result, boost::tuples::ignore) =
-        request_parser.Parse(request,
+        RequestParser().Parse(request,
                               incoming_data_buffer.data(),
                               incoming_data_buffer.data() + bytes_transferred,
-                              &compression_type);
+                              compression_type);
 
     // the request has been parsed
     if (result)
diff --git a/Server/Connection.h b/Server/Connection.h
index bc03c15..41b06d3 100644
--- a/Server/Connection.h
+++ b/Server/Connection.h
@@ -28,7 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef CONNECTION_H
 #define CONNECTION_H
 
-#include "RequestParser.h"
+// #include "RequestParser.h"
 #include "Http/CompressionType.h"
 #include "Http/Request.h"
 
@@ -40,7 +40,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <boost/version.hpp>
 
  #include <memory>
- #include <string>
  #include <vector>
 
 //workaround for incomplete std::shared_ptr compatibility in old boost versions
@@ -97,7 +96,6 @@ class Connection : public std::enable_shared_from_this<Connection>
     RequestHandler &request_handler;
     boost::array<char, 8192> incoming_data_buffer;
     Request request;
-    RequestParser request_parser;
     Reply reply;
 };
 
diff --git a/Server/DataStructures/BaseDataFacade.h b/Server/DataStructures/BaseDataFacade.h
index 7897ca4..3ea391c 100644
--- a/Server/DataStructures/BaseDataFacade.h
+++ b/Server/DataStructures/BaseDataFacade.h
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -30,21 +30,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // Exposes all data access interfaces to the algorithms via base class ptr
 
-#include "../../DataStructures/EdgeBasedNode.h"
-#include "../../DataStructures/ImportNode.h"
-#include "../../DataStructures/PhantomNodes.h"
-#include "../../DataStructures/TurnInstructions.h"
-#include "../../Util/OSRMException.h"
-#include "../../Util/StringUtil.h"
+#include "../../data_structures/edge_based_node.hpp"
+#include "../../data_structures/external_memory_node.hpp"
+#include "../../data_structures/phantom_node.hpp"
+#include "../../data_structures/turn_instructions.hpp"
+#include "../../Util/integer_range.hpp"
+#include "../../Util/osrm_exception.hpp"
+#include "../../Util/string_util.hpp"
 #include "../../typedefs.h"
 
-#include <boost/range/irange.hpp>
-
 #include <osrm/Coordinate.h>
 
 #include <string>
 
-typedef decltype(boost::irange(0u,0u)) EdgeRange;
+typedef osrm::range<EdgeID> EdgeRange;
 
 template <class EdgeDataT> class BaseDataFacade
 {
@@ -63,9 +62,9 @@ template <class EdgeDataT> class BaseDataFacade
 
     virtual NodeID GetTarget(const EdgeID e) const = 0;
 
-    virtual EdgeDataT &GetEdgeData(const EdgeID e) = 0;
+    // virtual EdgeDataT &GetEdgeData(const EdgeID e) = 0;
 
-    // virtual const EdgeDataT &GetEdgeData( const EdgeID e ) const = 0;
+    virtual const EdgeDataT &GetEdgeData(const EdgeID e) const = 0;
 
     virtual EdgeID BeginEdges(const NodeID n) const = 0;
 
@@ -93,18 +92,20 @@ template <class EdgeDataT> class BaseDataFacade
 
     virtual TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const = 0;
 
+    virtual TravelMode GetTravelModeForEdgeID(const unsigned id) const = 0;
+
     virtual bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
                                                     FixedPointCoordinate &result,
-                                                    const unsigned zoom_level = 18) const = 0;
+                                                    const unsigned zoom_level = 18) = 0;
 
-    virtual bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
-                                              PhantomNode &resulting_phantom_node,
-                                              const unsigned zoom_level) const = 0;
+    virtual bool
+    IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+                                            std::vector<PhantomNode> &resulting_phantom_node_vector,
+                                            const unsigned number_of_results) = 0;
 
-    virtual bool IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
-                                              std::vector<PhantomNode> &resulting_phantom_node_vector,
-                                              const unsigned zoom_level,
-                                              const unsigned number_of_results) const = 0;
+    virtual bool
+    IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+                                            PhantomNode &resulting_phantom_node) = 0;
 
     virtual unsigned GetCheckSum() const = 0;
 
diff --git a/Server/DataStructures/InternalDataFacade.h b/Server/DataStructures/InternalDataFacade.h
index c2055bb..d4f715c 100644
--- a/Server/DataStructures/InternalDataFacade.h
+++ b/Server/DataStructures/InternalDataFacade.h
@@ -32,19 +32,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "BaseDataFacade.h"
 
-#include "../../DataStructures/OriginalEdgeData.h"
-#include "../../DataStructures/QueryNode.h"
-#include "../../DataStructures/QueryEdge.h"
-#include "../../DataStructures/SharedMemoryVectorWrapper.h"
-#include "../../DataStructures/StaticGraph.h"
-#include "../../DataStructures/StaticRTree.h"
-#include "../../DataStructures/RangeTable.h"
+#include "../../data_structures/original_edge_data.hpp"
+#include "../../data_structures/query_node.hpp"
+#include "../../data_structures/query_edge.hpp"
+#include "../../data_structures/shared_memory_vector_wrapper.hpp"
+#include "../../data_structures/static_graph.hpp"
+#include "../../data_structures/static_rtree.hpp"
+#include "../../data_structures/range_table.hpp"
 #include "../../Util/BoostFileSystemFix.h"
-#include "../../Util/GraphLoader.h"
-#include "../../Util/ProgramOptions.h"
-#include "../../Util/SimpleLogger.h"
+#include "../../Util/graph_loader.hpp"
+#include "../../Util/simple_logger.hpp"
 
 #include <osrm/Coordinate.h>
+#include <osrm/ServerPaths.h>
 
 template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<EdgeDataT>
 {
@@ -66,13 +66,16 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
     ShM<NodeID, false>::vector m_via_node_list;
     ShM<unsigned, false>::vector m_name_ID_list;
     ShM<TurnInstruction, false>::vector m_turn_instruction_list;
+    ShM<TravelMode, false>::vector m_travel_mode_list;
     ShM<char, false>::vector m_names_char_list;
-    ShM<bool, false>::vector m_egde_is_compressed;
+    ShM<bool, false>::vector m_edge_is_compressed;
     ShM<unsigned, false>::vector m_geometry_indices;
     ShM<unsigned, false>::vector m_geometry_list;
 
-    std::shared_ptr<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>>
-    m_static_rtree;
+    boost::thread_specific_ptr<
+        StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>> m_static_rtree;
+    boost::filesystem::path ram_index_path;
+    boost::filesystem::path file_index_path;
     RangeTable<16, false> m_name_table;
 
     void LoadTimestamp(const boost::filesystem::path &timestamp_path)
@@ -123,14 +126,14 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
     {
         boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
 
-        NodeInfo current_node;
+        QueryNode current_node;
         unsigned number_of_coordinates = 0;
         nodes_input_stream.read((char *)&number_of_coordinates, sizeof(unsigned));
         m_coordinate_list =
             std::make_shared<std::vector<FixedPointCoordinate>>(number_of_coordinates);
         for (unsigned i = 0; i < number_of_coordinates; ++i)
         {
-            nodes_input_stream.read((char *)&current_node, sizeof(NodeInfo));
+            nodes_input_stream.read((char *)&current_node, sizeof(QueryNode));
             m_coordinate_list->at(i) = FixedPointCoordinate(current_node.lat, current_node.lon);
             BOOST_ASSERT((std::abs(m_coordinate_list->at(i).lat) >> 30) == 0);
             BOOST_ASSERT((std::abs(m_coordinate_list->at(i).lon) >> 30) == 0);
@@ -143,7 +146,8 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
         m_via_node_list.resize(number_of_edges);
         m_name_ID_list.resize(number_of_edges);
         m_turn_instruction_list.resize(number_of_edges);
-        m_egde_is_compressed.resize(number_of_edges);
+        m_travel_mode_list.resize(number_of_edges);
+        m_edge_is_compressed.resize(number_of_edges);
 
         unsigned compressed = 0;
 
@@ -154,8 +158,9 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
             m_via_node_list[i] = current_edge_data.via_node;
             m_name_ID_list[i] = current_edge_data.name_id;
             m_turn_instruction_list[i] = current_edge_data.turn_instruction;
-            m_egde_is_compressed[i] = current_edge_data.compressed_geometry;
-            if (m_egde_is_compressed[i])
+            m_travel_mode_list[i] = current_edge_data.travel_mode;
+            m_edge_is_compressed[i] = current_edge_data.compressed_geometry;
+            if (m_edge_is_compressed[i])
             {
                 ++compressed;
             }
@@ -192,13 +197,12 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
         geometry_stream.close();
     }
 
-    void LoadRTree(const boost::filesystem::path &ram_index_path,
-                   const boost::filesystem::path &file_index_path)
+    void LoadRTree()
     {
         BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
 
-        m_static_rtree = std::make_shared<StaticRTree<RTreeLeaf>>(
-            ram_index_path, file_index_path, m_coordinate_list);
+        m_static_rtree.reset(
+            new StaticRTree<RTreeLeaf>(ram_index_path, file_index_path, m_coordinate_list));
     }
 
     void LoadStreetNames(const boost::filesystem::path &names_file)
@@ -220,7 +224,7 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
     }
 
   public:
-    ~InternalDataFacade()
+    virtual ~InternalDataFacade()
     {
         delete m_query_graph;
         m_static_rtree.reset();
@@ -231,31 +235,31 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
         // generate paths of data files
         if (server_paths.find("hsgrdata") == server_paths.end())
         {
-            throw OSRMException("no hsgr file given in ini file");
+            throw osrm::exception("no hsgr file given in ini file");
         }
         if (server_paths.find("ramindex") == server_paths.end())
         {
-            throw OSRMException("no ram index file given in ini file");
+            throw osrm::exception("no ram index file given in ini file");
         }
         if (server_paths.find("fileindex") == server_paths.end())
         {
-            throw OSRMException("no leaf index file given in ini file");
+            throw osrm::exception("no leaf index file given in ini file");
         }
         if (server_paths.find("geometries") == server_paths.end())
         {
-            throw OSRMException("no geometries file given in ini file");
+            throw osrm::exception("no geometries file given in ini file");
         }
         if (server_paths.find("nodesdata") == server_paths.end())
         {
-            throw OSRMException("no nodes file given in ini file");
+            throw osrm::exception("no nodes file given in ini file");
         }
         if (server_paths.find("edgesdata") == server_paths.end())
         {
-            throw OSRMException("no edges file given in ini file");
+            throw osrm::exception("no edges file given in ini file");
         }
         if (server_paths.find("namesdata") == server_paths.end())
         {
-            throw OSRMException("no names file given in ini file");
+            throw osrm::exception("no names file given in ini file");
         }
 
         ServerPaths::const_iterator paths_iterator = server_paths.find("hsgrdata");
@@ -266,10 +270,10 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
         const boost::filesystem::path &timestamp_path = paths_iterator->second;
         paths_iterator = server_paths.find("ramindex");
         BOOST_ASSERT(server_paths.end() != paths_iterator);
-        const boost::filesystem::path &ram_index_path = paths_iterator->second;
+        ram_index_path = paths_iterator->second;
         paths_iterator = server_paths.find("fileindex");
         BOOST_ASSERT(server_paths.end() != paths_iterator);
-        const boost::filesystem::path &file_index_path = paths_iterator->second;
+        file_index_path = paths_iterator->second;
         paths_iterator = server_paths.find("nodesdata");
         BOOST_ASSERT(server_paths.end() != paths_iterator);
         const boost::filesystem::path &nodes_data_path = paths_iterator->second;
@@ -287,7 +291,7 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
         SimpleLogger().Write() << "loading graph data";
         AssertPathExists(hsgr_path);
         LoadGraph(hsgr_path);
-        SimpleLogger().Write() << "loading egde information";
+        SimpleLogger().Write() << "loading edge information";
         AssertPathExists(nodes_data_path);
         AssertPathExists(edges_data_path);
         LoadNodeAndEdgeInformation(nodes_data_path, edges_data_path);
@@ -297,7 +301,6 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
         SimpleLogger().Write() << "loading r-tree";
         AssertPathExists(ram_index_path);
         AssertPathExists(file_index_path);
-        LoadRTree(ram_index_path, file_index_path);
         SimpleLogger().Write() << "loading timestamp";
         LoadTimestamp(timestamp_path);
         SimpleLogger().Write() << "loading street names";
@@ -306,90 +309,112 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
     }
 
     // search graph access
-    unsigned GetNumberOfNodes() const { return m_query_graph->GetNumberOfNodes(); }
+    unsigned GetNumberOfNodes() const final { return m_query_graph->GetNumberOfNodes(); }
 
-    unsigned GetNumberOfEdges() const { return m_query_graph->GetNumberOfEdges(); }
+    unsigned GetNumberOfEdges() const final { return m_query_graph->GetNumberOfEdges(); }
 
-    unsigned GetOutDegree(const NodeID n) const { return m_query_graph->GetOutDegree(n); }
+    unsigned GetOutDegree(const NodeID n) const final { return m_query_graph->GetOutDegree(n); }
 
-    NodeID GetTarget(const EdgeID e) const { return m_query_graph->GetTarget(e); }
+    NodeID GetTarget(const EdgeID e) const final { return m_query_graph->GetTarget(e); }
 
-    EdgeDataT &GetEdgeData(const EdgeID e) { return m_query_graph->GetEdgeData(e); }
+    // EdgeDataT &GetEdgeData(const EdgeID e) final { return m_query_graph->GetEdgeData(e); }
 
-    const EdgeDataT &GetEdgeData(const EdgeID e) const { return m_query_graph->GetEdgeData(e); }
+    EdgeDataT &GetEdgeData(const EdgeID e) const final { return m_query_graph->GetEdgeData(e); }
 
-    EdgeID BeginEdges(const NodeID n) const { return m_query_graph->BeginEdges(n); }
+    EdgeID BeginEdges(const NodeID n) const final { return m_query_graph->BeginEdges(n); }
 
-    EdgeID EndEdges(const NodeID n) const { return m_query_graph->EndEdges(n); }
+    EdgeID EndEdges(const NodeID n) const final { return m_query_graph->EndEdges(n); }
 
-    EdgeRange GetAdjacentEdgeRange(const NodeID node) const
+    EdgeRange GetAdjacentEdgeRange(const NodeID node) const final
     {
         return m_query_graph->GetAdjacentEdgeRange(node);
     };
 
     // searches for a specific edge
-    EdgeID FindEdge(const NodeID from, const NodeID to) const
+    EdgeID FindEdge(const NodeID from, const NodeID to) const final
     {
         return m_query_graph->FindEdge(from, to);
     }
 
-    EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const
+    EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const final
     {
         return m_query_graph->FindEdgeInEitherDirection(from, to);
     }
 
-    EdgeID FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const
+    EdgeID FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const final
     {
         return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
     }
 
     // node and edge information access
-    FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const
+    FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const final
     {
         return m_coordinate_list->at(id);
     };
 
-    bool EdgeIsCompressed(const unsigned id) const { return m_egde_is_compressed.at(id); }
+    bool EdgeIsCompressed(const unsigned id) const { return m_edge_is_compressed.at(id); }
 
-    TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const
+    TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const final
     {
         return m_turn_instruction_list.at(id);
     }
 
+    TravelMode GetTravelModeForEdgeID(const unsigned id) const
+    {
+      return m_travel_mode_list.at(id);
+    }
+
     bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
                                             FixedPointCoordinate &result,
-                                            const unsigned zoom_level = 18) const
+                                            const unsigned zoom_level = 18) final
     {
+        if (!m_static_rtree.get())
+        {
+            LoadRTree();
+        }
+
         return m_static_rtree->LocateClosestEndPointForCoordinate(
             input_coordinate, result, zoom_level);
     }
 
-    bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
-                                      PhantomNode &resulting_phantom_node,
-                                      const unsigned zoom_level) const
+    bool
+    IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+                                            PhantomNode &resulting_phantom_node) final
     {
-        return m_static_rtree->FindPhantomNodeForCoordinate(
-            input_coordinate, resulting_phantom_node, zoom_level);
+        std::vector<PhantomNode> resulting_phantom_node_vector;
+        auto result = IncrementalFindPhantomNodeForCoordinate(input_coordinate,
+                                                              resulting_phantom_node_vector,
+                                                              1);
+        if (result)
+        {
+            BOOST_ASSERT(!resulting_phantom_node_vector.empty());
+            resulting_phantom_node = resulting_phantom_node_vector.front();
+        }
+        return result;
     }
 
     bool
     IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
                                             std::vector<PhantomNode> &resulting_phantom_node_vector,
-                                            const unsigned zoom_level,
-                                            const unsigned number_of_results) const
+                                            const unsigned number_of_results) final
     {
+        if (!m_static_rtree.get())
+        {
+            LoadRTree();
+        }
+
         return m_static_rtree->IncrementalFindPhantomNodeForCoordinate(
-            input_coordinate, resulting_phantom_node_vector, zoom_level, number_of_results);
+            input_coordinate, resulting_phantom_node_vector, number_of_results);
     }
 
-    unsigned GetCheckSum() const { return m_check_sum; }
+    unsigned GetCheckSum() const final { return m_check_sum; }
 
-    unsigned GetNameIndexFromEdgeID(const unsigned id) const
+    unsigned GetNameIndexFromEdgeID(const unsigned id) const final
     {
         return m_name_ID_list.at(id);
     };
 
-    void GetName(const unsigned name_id, std::string &result) const
+    void GetName(const unsigned name_id, std::string &result) const final
     {
         if (UINT_MAX == name_id)
         {
@@ -408,13 +433,13 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
         }
     }
 
-    virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const
+    virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const final
     {
         return m_via_node_list.at(id);
     }
 
-    virtual void GetUncompressedGeometry(const unsigned id, std::vector<unsigned> &result_nodes)
-        const
+    virtual void GetUncompressedGeometry(const unsigned id,
+                                         std::vector<unsigned> &result_nodes) const final
     {
         const unsigned begin = m_geometry_indices.at(id);
         const unsigned end = m_geometry_indices.at(id + 1);
@@ -424,7 +449,7 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
             result_nodes.begin(), m_geometry_list.begin() + begin, m_geometry_list.begin() + end);
     }
 
-    std::string GetTimestamp() const { return m_timestamp; }
+    std::string GetTimestamp() const final { return m_timestamp; }
 };
 
 #endif // INTERNAL_DATA_FACADE
diff --git a/Server/DataStructures/SharedDataFacade.h b/Server/DataStructures/SharedDataFacade.h
index a2cb990..9120f82 100644
--- a/Server/DataStructures/SharedDataFacade.h
+++ b/Server/DataStructures/SharedDataFacade.h
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -33,12 +33,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "BaseDataFacade.h"
 #include "SharedDataType.h"
 
-#include "../../DataStructures/RangeTable.h"
-#include "../../DataStructures/StaticGraph.h"
-#include "../../DataStructures/StaticRTree.h"
+#include "../../data_structures/range_table.hpp"
+#include "../../data_structures/static_graph.hpp"
+#include "../../data_structures/static_rtree.hpp"
 #include "../../Util/BoostFileSystemFix.h"
-#include "../../Util/ProgramOptions.h"
-#include "../../Util/SimpleLogger.h"
+#include "../../Util/make_unique.hpp"
+#include "../../Util/simple_logger.hpp"
 
 #include <algorithm>
 #include <memory>
@@ -55,8 +55,9 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
     typedef typename RangeTable<16, true>::BlockT NameIndexBlock;
     typedef typename QueryGraph::InputEdge InputEdge;
     typedef typename super::RTreeLeaf RTreeLeaf;
-    typedef typename StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>::TreeNode
-    RTreeNode;
+    using SharedRTree = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>;
+    using TimeStampedRTreePair = std::pair<unsigned, std::shared_ptr<SharedRTree>>;
+    using RTreeNode = typename SharedRTree::TreeNode;
 
     SharedDataLayout *data_layout;
     char *shared_memory;
@@ -67,24 +68,24 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
     unsigned CURRENT_TIMESTAMP;
 
     unsigned m_check_sum;
-    unsigned m_number_of_nodes;
-    std::shared_ptr<QueryGraph> m_query_graph;
-    std::shared_ptr<SharedMemory> m_layout_memory;
-    std::shared_ptr<SharedMemory> m_large_memory;
+    std::unique_ptr<QueryGraph> m_query_graph;
+    std::unique_ptr<SharedMemory> m_layout_memory;
+    std::unique_ptr<SharedMemory> m_large_memory;
     std::string m_timestamp;
 
     std::shared_ptr<ShM<FixedPointCoordinate, true>::vector> m_coordinate_list;
     ShM<NodeID, true>::vector m_via_node_list;
     ShM<unsigned, true>::vector m_name_ID_list;
     ShM<TurnInstruction, true>::vector m_turn_instruction_list;
+    ShM<TravelMode, true>::vector m_travel_mode_list;
     ShM<char, true>::vector m_names_char_list;
     ShM<unsigned, true>::vector m_name_begin_indices;
-    ShM<bool, true>::vector m_egde_is_compressed;
+    ShM<bool, true>::vector m_edge_is_compressed;
     ShM<unsigned, true>::vector m_geometry_indices;
     ShM<unsigned, true>::vector m_geometry_list;
 
-    std::shared_ptr<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>>
-    m_static_rtree;
+    boost::thread_specific_ptr<std::pair<unsigned, std::shared_ptr<SharedRTree>>> m_static_rtree;
+    boost::filesystem::path file_index_path;
 
     std::shared_ptr<RangeTable<16, true>> m_name_table;
 
@@ -105,23 +106,22 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
                   m_timestamp.begin());
     }
 
-    void LoadRTree(const boost::filesystem::path &file_index_path)
+    void LoadRTree()
     {
         BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
 
         RTreeNode *tree_ptr =
             data_layout->GetBlockPtr<RTreeNode>(shared_memory, SharedDataLayout::R_SEARCH_TREE);
-        m_static_rtree =
-            std::make_shared<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>>(
+        m_static_rtree.reset(new TimeStampedRTreePair(CURRENT_TIMESTAMP,
+            osrm::make_unique<SharedRTree>(
                 tree_ptr,
                 data_layout->num_entries[SharedDataLayout::R_SEARCH_TREE],
                 file_index_path,
-                m_coordinate_list);
+                m_coordinate_list)));
     }
 
     void LoadGraph()
     {
-        m_number_of_nodes = data_layout->num_entries[SharedDataLayout::GRAPH_NODE_LIST];
         GraphNode *graph_nodes_ptr =
             data_layout->GetBlockPtr<GraphNode>(shared_memory, SharedDataLayout::GRAPH_NODE_LIST);
 
@@ -140,9 +140,16 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
 
         FixedPointCoordinate *coordinate_list_ptr = data_layout->GetBlockPtr<FixedPointCoordinate>(
             shared_memory, SharedDataLayout::COORDINATE_LIST);
-        m_coordinate_list = std::make_shared<ShM<FixedPointCoordinate, true>::vector>(
+        m_coordinate_list = osrm::make_unique<ShM<FixedPointCoordinate, true>::vector>(
             coordinate_list_ptr, data_layout->num_entries[SharedDataLayout::COORDINATE_LIST]);
 
+        TravelMode *travel_mode_list_ptr = data_layout->GetBlockPtr<TravelMode>(
+            shared_memory, SharedDataLayout::TRAVEL_MODE);
+        typename ShM<TravelMode, true>::vector travel_mode_list(
+            travel_mode_list_ptr,
+            data_layout->num_entries[SharedDataLayout::TRAVEL_MODE]);
+        m_travel_mode_list.swap(travel_mode_list);
+
         TurnInstruction *turn_instruction_list_ptr = data_layout->GetBlockPtr<TurnInstruction>(
             shared_memory, SharedDataLayout::TURN_INSTRUCTION);
         typename ShM<TurnInstruction, true>::vector turn_instruction_list(
@@ -181,8 +188,8 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
             data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::NAME_CHAR_LIST);
         typename ShM<char, true>::vector names_char_list(
             names_list_ptr, data_layout->num_entries[SharedDataLayout::NAME_CHAR_LIST]);
-        m_name_table = std::make_shared<RangeTable<16, true>>(
-            name_offsets, name_blocks, names_char_list.size());
+        m_name_table = osrm::make_unique<RangeTable<16, true>>(
+            name_offsets, name_blocks, static_cast<unsigned>(names_char_list.size()));
 
         m_names_char_list.swap(names_char_list);
     }
@@ -191,10 +198,10 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
     {
         unsigned *geometries_compressed_ptr = data_layout->GetBlockPtr<unsigned>(
             shared_memory, SharedDataLayout::GEOMETRIES_INDICATORS);
-        typename ShM<bool, true>::vector egde_is_compressed(
+        typename ShM<bool, true>::vector edge_is_compressed(
             geometries_compressed_ptr,
             data_layout->num_entries[SharedDataLayout::GEOMETRIES_INDICATORS]);
-        m_egde_is_compressed.swap(egde_is_compressed);
+        m_edge_is_compressed.swap(edge_is_compressed);
 
         unsigned *geometries_index_ptr =
             data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::GEOMETRIES_INDEX);
@@ -210,11 +217,12 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
     }
 
   public:
+    virtual ~SharedDataFacade() {}
+
     SharedDataFacade()
     {
         data_timestamp_ptr = (SharedDataTimestamp *)SharedMemoryFactory::Get(
                                  CURRENT_REGIONS, sizeof(SharedDataTimestamp), false, false)->Ptr();
-
         CURRENT_LAYOUT = LAYOUT_NONE;
         CURRENT_DATA = DATA_NONE;
         CURRENT_TIMESTAMP = 0;
@@ -244,17 +252,13 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
             m_large_memory.reset(SharedMemoryFactory::Get(CURRENT_DATA));
             shared_memory = (char *)(m_large_memory->Ptr());
 
-            std::ofstream out("debug.bin");
-            out.write(shared_memory, data_layout->GetSizeOfLayout());
-            out.close();
-
             const char *file_index_ptr =
                 data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::FILE_INDEX_PATH);
-            boost::filesystem::path file_index_path(file_index_ptr);
+            file_index_path = boost::filesystem::path(file_index_ptr);
             if (!boost::filesystem::exists(file_index_path))
             {
                 SimpleLogger().Write(logDEBUG) << "Leaf file name " << file_index_path.string();
-                throw OSRMException("Could not load leaf index file."
+                throw osrm::exception("Could not load leaf index file."
                                     "Is any data loaded into shared memory?");
             }
 
@@ -262,65 +266,72 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
             LoadChecksum();
             LoadNodeAndEdgeInformation();
             LoadGeometries();
-            LoadRTree(file_index_path);
             LoadTimestamp();
             LoadViaNodeList();
             LoadNames();
 
             data_layout->PrintInformation();
+
+            SimpleLogger().Write() << "number of geometries: " << m_coordinate_list->size();
+            for (unsigned i = 0; i < m_coordinate_list->size(); ++i)
+            {
+                if (!GetCoordinateOfNode(i).is_valid())
+                {
+                    SimpleLogger().Write() << "coordinate " << i << " not valid";
+                }
+            }
         }
     }
 
     // search graph access
-    unsigned GetNumberOfNodes() const { return m_query_graph->GetNumberOfNodes(); }
-
-    unsigned GetNumberOfEdges() const { return m_query_graph->GetNumberOfEdges(); }
+    unsigned GetNumberOfNodes() const final { return m_query_graph->GetNumberOfNodes(); }
 
-    unsigned GetOutDegree(const NodeID n) const { return m_query_graph->GetOutDegree(n); }
+    unsigned GetNumberOfEdges() const final { return m_query_graph->GetNumberOfEdges(); }
 
-    NodeID GetTarget(const EdgeID e) const { return m_query_graph->GetTarget(e); }
+    unsigned GetOutDegree(const NodeID n) const final { return m_query_graph->GetOutDegree(n); }
 
-    EdgeDataT &GetEdgeData(const EdgeID e) { return m_query_graph->GetEdgeData(e); }
+    NodeID GetTarget(const EdgeID e) const final { return m_query_graph->GetTarget(e); }
 
-    // const EdgeDataT &GetEdgeData( const EdgeID e ) const {
-    //     return m_query_graph->GetEdgeData(e);
-    // }
+    EdgeDataT &GetEdgeData(const EdgeID e) const final { return m_query_graph->GetEdgeData(e); }
 
-    EdgeID BeginEdges(const NodeID n) const { return m_query_graph->BeginEdges(n); }
+    EdgeID BeginEdges(const NodeID n) const final { return m_query_graph->BeginEdges(n); }
 
-    EdgeID EndEdges(const NodeID n) const { return m_query_graph->EndEdges(n); }
+    EdgeID EndEdges(const NodeID n) const final { return m_query_graph->EndEdges(n); }
 
-    EdgeRange GetAdjacentEdgeRange(const NodeID node) const
+    EdgeRange GetAdjacentEdgeRange(const NodeID node) const final
     {
         return m_query_graph->GetAdjacentEdgeRange(node);
     };
 
     // searches for a specific edge
-    EdgeID FindEdge(const NodeID from, const NodeID to) const
+    EdgeID FindEdge(const NodeID from, const NodeID to) const final
     {
         return m_query_graph->FindEdge(from, to);
     }
 
-    EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const
+    EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const final
     {
         return m_query_graph->FindEdgeInEitherDirection(from, to);
     }
 
-    EdgeID FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const
+    EdgeID FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const final
     {
         return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
     }
 
     // node and edge information access
-    FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const
+    FixedPointCoordinate GetCoordinateOfNode(const NodeID id) const final
     {
         return m_coordinate_list->at(id);
     };
 
-    virtual bool EdgeIsCompressed(const unsigned id) const { return m_egde_is_compressed.at(id); }
+    virtual bool EdgeIsCompressed(const unsigned id) const final
+    {
+        return m_edge_is_compressed.at(id);
+    }
 
-    virtual void GetUncompressedGeometry(const unsigned id, std::vector<unsigned> &result_nodes)
-        const
+    virtual void GetUncompressedGeometry(const unsigned id,
+                                         std::vector<unsigned> &result_nodes) const final
     {
         const unsigned begin = m_geometry_indices.at(id);
         const unsigned end = m_geometry_indices.at(id + 1);
@@ -330,50 +341,72 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
             result_nodes.begin(), m_geometry_list.begin() + begin, m_geometry_list.begin() + end);
     }
 
-    virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const
+    virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const final
     {
         return m_via_node_list.at(id);
     }
 
-    TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const
+    TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const final
     {
         return m_turn_instruction_list.at(id);
     }
 
+    TravelMode GetTravelModeForEdgeID(const unsigned id) const
+    {
+        return m_travel_mode_list.at(id);
+    }
+
     bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
                                             FixedPointCoordinate &result,
-                                            const unsigned zoom_level = 18) const
+                                            const unsigned zoom_level = 18) final
     {
-        return m_static_rtree->LocateClosestEndPointForCoordinate(
+        if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+        {
+            LoadRTree();
+        }
+
+        return m_static_rtree->second->LocateClosestEndPointForCoordinate(
             input_coordinate, result, zoom_level);
     }
 
-    bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
-                                      PhantomNode &resulting_phantom_node,
-                                      const unsigned zoom_level) const
+    bool
+    IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+                                            PhantomNode &resulting_phantom_node) final
     {
-        return m_static_rtree->FindPhantomNodeForCoordinate(
-            input_coordinate, resulting_phantom_node, zoom_level);
+        std::vector<PhantomNode> resulting_phantom_node_vector;
+        auto result = IncrementalFindPhantomNodeForCoordinate(input_coordinate,
+                                                              resulting_phantom_node_vector,
+                                                              1);
+        if (result)
+        {
+            BOOST_ASSERT(!resulting_phantom_node_vector.empty());
+            resulting_phantom_node = resulting_phantom_node_vector.front();
+        }
+        return result;
     }
 
     bool
     IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
                                             std::vector<PhantomNode> &resulting_phantom_node_vector,
-                                            const unsigned zoom_level,
-                                            const unsigned number_of_results) const
+                                            const unsigned number_of_results) final
     {
-        return m_static_rtree->IncrementalFindPhantomNodeForCoordinate(
-            input_coordinate, resulting_phantom_node_vector, zoom_level, number_of_results);
+        if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+        {
+            LoadRTree();
+        }
+
+        return m_static_rtree->second->IncrementalFindPhantomNodeForCoordinate(
+            input_coordinate, resulting_phantom_node_vector, number_of_results);
     }
 
-    unsigned GetCheckSum() const { return m_check_sum; }
+    unsigned GetCheckSum() const final { return m_check_sum; }
 
-    unsigned GetNameIndexFromEdgeID(const unsigned id) const
+    unsigned GetNameIndexFromEdgeID(const unsigned id) const final
     {
         return m_name_ID_list.at(id);
     };
 
-    void GetName(const unsigned name_id, std::string &result) const
+    void GetName(const unsigned name_id, std::string &result) const final
     {
         if (UINT_MAX == name_id)
         {
@@ -392,7 +425,7 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
         }
     }
 
-    std::string GetTimestamp() const { return m_timestamp; }
+    std::string GetTimestamp() const final { return m_timestamp; }
 };
 
 #endif // SHARED_DATA_FACADE_H
diff --git a/Server/DataStructures/SharedDataType.h b/Server/DataStructures/SharedDataType.h
index 98bdfd5..6357fd7 100644
--- a/Server/DataStructures/SharedDataType.h
+++ b/Server/DataStructures/SharedDataType.h
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -28,15 +28,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef SHARED_DATA_TYPE_H_
 #define SHARED_DATA_TYPE_H_
 
-#include "../../Util/OSRMException.h"
-#include "../../Util/SimpleLogger.h"
+#include "../../Util/osrm_exception.hpp"
+#include "../../Util/simple_logger.hpp"
 
 #include <cstdint>
 
 #include <array>
 
 // Added at the start and end of each block as sanity check
-constexpr char CANARY[] = "OSRM";
+static const char CANARY[] = "OSRM";
 
 struct SharedDataLayout
 {
@@ -50,6 +50,7 @@ struct SharedDataLayout
         GRAPH_EDGE_LIST,
         COORDINATE_LIST,
         TURN_INSTRUCTION,
+        TRAVEL_MODE,
         R_SEARCH_TREE,
         GEOMETRIES_INDEX,
         GEOMETRIES_LIST,
@@ -82,6 +83,7 @@ struct SharedDataLayout
         SimpleLogger().Write(logDEBUG) << "timestamp_length:           " << num_entries[TIMESTAMP];
         SimpleLogger().Write(logDEBUG) << "coordinate_list_size:       " << num_entries[COORDINATE_LIST];
         SimpleLogger().Write(logDEBUG) << "turn_instruction_list_size: " << num_entries[TURN_INSTRUCTION];
+        SimpleLogger().Write(logDEBUG) << "travel_mode_list_size:      " << num_entries[TRAVEL_MODE];
         SimpleLogger().Write(logDEBUG) << "r_search_tree_size:         " << num_entries[R_SEARCH_TREE];
         SimpleLogger().Write(logDEBUG) << "geometries_indicators:      " << num_entries[GEOMETRIES_INDICATORS]
                                        << "/" << ((num_entries[GEOMETRIES_INDICATORS] / 8) + 1);
@@ -98,6 +100,7 @@ struct SharedDataLayout
         SimpleLogger().Write(logDEBUG) << "GRAPH_EDGE_LIST      " << ": " << GetBlockSize(GRAPH_EDGE_LIST      );
         SimpleLogger().Write(logDEBUG) << "COORDINATE_LIST      " << ": " << GetBlockSize(COORDINATE_LIST      );
         SimpleLogger().Write(logDEBUG) << "TURN_INSTRUCTION     " << ": " << GetBlockSize(TURN_INSTRUCTION     );
+        SimpleLogger().Write(logDEBUG) << "TRAVEL_MODE          " << ": " << GetBlockSize(TRAVEL_MODE          );
         SimpleLogger().Write(logDEBUG) << "R_SEARCH_TREE        " << ": " << GetBlockSize(R_SEARCH_TREE        );
         SimpleLogger().Write(logDEBUG) << "GEOMETRIES_INDEX     " << ": " << GetBlockSize(GEOMETRIES_INDEX     );
         SimpleLogger().Write(logDEBUG) << "GEOMETRIES_LIST      " << ": " << GetBlockSize(GEOMETRIES_LIST      );
@@ -159,11 +162,11 @@ struct SharedDataLayout
             bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
             if (!start_canary_alive)
             {
-                throw OSRMException("Start canary of block corrupted.");
+                throw osrm::exception("Start canary of block corrupted.");
             }
             if (!end_canary_alive)
             {
-                throw OSRMException("End canary of block corrupted.");
+                throw osrm::exception("End canary of block corrupted.");
             }
         }
 
diff --git a/Server/Http/CompressionType.h b/Server/Http/CompressionType.h
index 74d0b62..3836cd7 100644
--- a/Server/Http/CompressionType.h
+++ b/Server/Http/CompressionType.h
@@ -36,6 +36,6 @@ enum CompressionType
   gzipRFC1952,
   deflateRFC1951 };
 
-} // namespace http
+}
 
 #endif // COMPRESSION_TYPE_H
diff --git a/Server/Http/Reply.cpp b/Server/Http/Reply.cpp
index b3247ec..e2cf0ae 100644
--- a/Server/Http/Reply.cpp
+++ b/Server/Http/Reply.cpp
@@ -27,7 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <osrm/Reply.h>
 
-#include "../../Util/StringUtil.h"
+#include "../../Util/cast.hpp"
 
 namespace http
 {
@@ -38,7 +38,7 @@ void Reply::SetSize(const unsigned size)
     {
         if ("Content-Length" == h.name)
         {
-            h.value = UintToString(size);
+            h.value = cast::integral_to_string(size);
         }
     }
 }
@@ -87,8 +87,7 @@ Reply Reply::StockReply(Reply::status_type status)
     const std::string status_string = reply.ToString(status);
     reply.content.insert(reply.content.end(), status_string.begin(), status_string.end());
     reply.headers.emplace_back("Access-Control-Allow-Origin", "*");
-    reply.headers.emplace_back("Content-Length",
-                               UintToString(static_cast<unsigned>(reply.content.size())));
+    reply.headers.emplace_back("Content-Length", cast::integral_to_string(reply.content.size()));
     reply.headers.emplace_back("Content-Type", "text/html");
     return reply;
 }
diff --git a/Server/RequestHandler.cpp b/Server/RequestHandler.cpp
index 36a2808..b1178ba 100644
--- a/Server/RequestHandler.cpp
+++ b/Server/RequestHandler.cpp
@@ -25,14 +25,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "APIGrammar.h"
 #include "RequestHandler.h"
+
+#include "APIGrammar.h"
 #include "Http/Request.h"
 
-#include "../DataStructures/JSONContainer.h"
+#include "../data_structures/json_container.hpp"
 #include "../Library/OSRM.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/StringUtil.h"
+#include "../Util/json_renderer.hpp"
+#include "../Util/simple_logger.hpp"
+#include "../Util/string_util.hpp"
 #include "../typedefs.h"
 
 #include <osrm/Reply.h>
@@ -61,17 +63,17 @@ void RequestHandler::handle_request(const http::Request &req, http::Reply &reply
         //     req.agent << ( 0 == req.agent.length() ? "- " :" ") << request;
 
         time_t ltime;
-        struct tm *Tm;
+        struct tm *time_stamp;
 
         ltime = time(nullptr);
-        Tm = localtime(&ltime);
+        time_stamp = localtime(&ltime);
 
         // log timestamp
-        SimpleLogger().Write() << (Tm->tm_mday < 10 ? "0" : "") << Tm->tm_mday << "-"
-                               << (Tm->tm_mon + 1 < 10 ? "0" : "") << (Tm->tm_mon + 1) << "-"
-                               << 1900 + Tm->tm_year << " " << (Tm->tm_hour < 10 ? "0" : "")
-                               << Tm->tm_hour << ":" << (Tm->tm_min < 10 ? "0" : "") << Tm->tm_min
-                               << ":" << (Tm->tm_sec < 10 ? "0" : "") << Tm->tm_sec << " "
+        SimpleLogger().Write() << (time_stamp->tm_mday < 10 ? "0" : "") << time_stamp->tm_mday << "-"
+                               << (time_stamp->tm_mon + 1 < 10 ? "0" : "") << (time_stamp->tm_mon + 1) << "-"
+                               << 1900 + time_stamp->tm_year << " " << (time_stamp->tm_hour < 10 ? "0" : "")
+                               << time_stamp->tm_hour << ":" << (time_stamp->tm_min < 10 ? "0" : "") << time_stamp->tm_min
+                               << ":" << (time_stamp->tm_sec < 10 ? "0" : "") << time_stamp->tm_sec << " "
                                << req.endpoint.to_string() << " " << req.referrer
                                << (0 == req.referrer.length() ? "- " : " ") << req.agent
                                << (0 == req.agent.length() ? "- " : " ") << request;
@@ -87,11 +89,11 @@ void RequestHandler::handle_request(const http::Request &req, http::Reply &reply
         {
             reply = http::Reply::StockReply(http::Reply::badRequest);
             reply.content.clear();
-            const unsigned position = static_cast<unsigned>(std::distance(request.begin(), iter));
+            const auto position = std::distance(request.begin(), iter);
             JSON::Object json_result;
             json_result.values["status"] = 400;
             std::string message = "Query string malformed close to position ";
-            message += UintToString(position);
+            message += cast::integral_to_string(position);
             json_result.values["status_message"] = message;
             JSON::render(reply.content, json_result);
             return;
@@ -112,8 +114,7 @@ void RequestHandler::handle_request(const http::Request &req, http::Reply &reply
         }
 
         // set headers
-        reply.headers.emplace_back("Content-Length",
-                                   UintToString(static_cast<unsigned>(reply.content.size())));
+        reply.headers.emplace_back("Content-Length", cast::integral_to_string(reply.content.size()));
         if ("gpx" == route_parameters.output_format)
         { // gpx file
             reply.headers.emplace_back("Content-Type", "application/gpx+xml; charset=UTF-8");
diff --git a/Server/RequestHandler.h b/Server/RequestHandler.h
index 462c34f..7263dad 100644
--- a/Server/RequestHandler.h
+++ b/Server/RequestHandler.h
@@ -44,7 +44,7 @@ class RequestHandler
 {
 
   public:
-    typedef APIGrammar<std::string::iterator, RouteParameters> APIGrammarParser;
+    using APIGrammarParser = APIGrammar<std::string::iterator, RouteParameters>;
 
     RequestHandler();
     RequestHandler(const RequestHandler &) = delete;
diff --git a/Server/RequestParser.cpp b/Server/RequestParser.cpp
index cad05b9..a599381 100644
--- a/Server/RequestParser.cpp
+++ b/Server/RequestParser.cpp
@@ -25,9 +25,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "Http/Request.h"
 #include "RequestParser.h"
 
+#include "Http/Request.h"
+
 namespace http
 {
 
@@ -36,7 +37,7 @@ RequestParser::RequestParser() : state_(method_start), header({"", ""}) {}
 void RequestParser::Reset() { state_ = method_start; }
 
 boost::tuple<boost::tribool, char *>
-RequestParser::Parse(Request &req, char *begin, char *end, http::CompressionType *compression_type)
+RequestParser::Parse(Request &req, char *begin, char *end, http::CompressionType &compression_type)
 {
     while (begin != end)
     {
@@ -51,7 +52,7 @@ RequestParser::Parse(Request &req, char *begin, char *end, http::CompressionType
 }
 
 boost::tribool
-RequestParser::consume(Request &req, char input, http::CompressionType *compression_type)
+RequestParser::consume(Request &req, char input, http::CompressionType &compression_type)
 {
     switch (state_)
     {
@@ -177,11 +178,11 @@ RequestParser::consume(Request &req, char input, http::CompressionType *compress
             /* giving gzip precedence over deflate */
             if (header.value.find("deflate") != std::string::npos)
             {
-                *compression_type = deflateRFC1951;
+                compression_type = deflateRFC1951;
             }
             if (header.value.find("gzip") != std::string::npos)
             {
-                *compression_type = gzipRFC1952;
+                compression_type = gzipRFC1952;
             }
         }
 
@@ -264,18 +265,21 @@ RequestParser::consume(Request &req, char input, http::CompressionType *compress
         return false;
     default: // expecting_newline_3:
         return (input == '\n');
-    // default:
-    //     return false;
+        // default:
+        //     return false;
     }
 }
 
-inline bool RequestParser::isChar(int c) { return c >= 0 && c <= 127; }
+inline bool RequestParser::isChar(int character) { return character >= 0 && character <= 127; }
 
-inline bool RequestParser::isCTL(int c) { return (c >= 0 && c <= 31) || (c == 127); }
+inline bool RequestParser::isCTL(int character)
+{
+    return (character >= 0 && character <= 31) || (character == 127);
+}
 
-inline bool RequestParser::isTSpecial(int c)
+inline bool RequestParser::isTSpecial(int character)
 {
-    switch (c)
+    switch (character)
     {
     case '(':
     case ')':
@@ -302,5 +306,5 @@ inline bool RequestParser::isTSpecial(int c)
     }
 }
 
-inline bool RequestParser::isDigit(int c) { return c >= '0' && c <= '9'; }
+inline bool RequestParser::isDigit(int character) { return character >= '0' && character <= '9'; }
 }
diff --git a/Server/RequestParser.h b/Server/RequestParser.h
index 4b74d83..7f302a2 100644
--- a/Server/RequestParser.h
+++ b/Server/RequestParser.h
@@ -46,10 +46,10 @@ class RequestParser
     void Reset();
 
     boost::tuple<boost::tribool, char *>
-    Parse(Request &req, char *begin, char *end, CompressionType *compressionType);
+    Parse(Request &req, char *begin, char *end, CompressionType &compression_type);
 
   private:
-    boost::tribool consume(Request &req, char input, CompressionType *compressionType);
+    boost::tribool consume(Request &req, char input, CompressionType &compression_type);
 
     inline bool isChar(int c);
 
diff --git a/Server/Server.h b/Server/Server.h
index be18c3b..8e0b101 100644
--- a/Server/Server.h
+++ b/Server/Server.h
@@ -28,14 +28,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef SERVER_H
 #define SERVER_H
 
-#include "../Util/StringUtil.h"
-
 #include "Connection.h"
 #include "RequestHandler.h"
 
+#include "../Util/cast.hpp"
+#include "../Util/make_unique.hpp"
+#include "../Util/simple_logger.hpp"
+
 #include <boost/asio.hpp>
 #include <boost/bind.hpp>
 
+#include <zlib.h>
+
 #include <functional>
 #include <memory>
 #include <thread>
@@ -44,11 +48,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 class Server
 {
   public:
+
+    // Note: returns a shared instead of a unique ptr as it is captured in a lambda somewhere else
+    static std::shared_ptr<Server> CreateServer(std::string &ip_address, int ip_port, unsigned requested_num_threads)
+    {
+        SimpleLogger().Write() << "http 1.1 compression handled by zlib version " << zlibVersion();
+        const unsigned hardware_threads = std::max(1u, std::thread::hardware_concurrency());
+        const unsigned real_num_threads = std::min(hardware_threads, requested_num_threads);
+        return std::make_shared<Server>(ip_address, ip_port, real_num_threads);
+    }
+
     explicit Server(const std::string &address, const int port, const unsigned thread_pool_size)
         : thread_pool_size(thread_pool_size), acceptor(io_service),
-          new_connection(new http::Connection(io_service, request_handler)), request_handler()
+          new_connection(std::make_shared<http::Connection>(io_service, request_handler)), request_handler()
     {
-        const std::string port_string = IntToString(port);
+        const std::string port_string = cast::integral_to_string(port);
 
         boost::asio::ip::tcp::resolver resolver(io_service);
         boost::asio::ip::tcp::resolver::query query(address, port_string);
@@ -63,9 +77,6 @@ class Server
             boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
     }
 
-    Server() = delete;
-    Server(const Server &) = delete;
-
     void Run()
     {
         std::vector<std::shared_ptr<std::thread>> threads;
@@ -75,9 +86,9 @@ class Server
                 boost::bind(&boost::asio::io_service::run, &io_service));
             threads.push_back(thread);
         }
-        for (unsigned i = 0; i < threads.size(); ++i)
+        for (auto thread : threads)
         {
-            threads[i]->join();
+            thread->join();
         }
     }
 
@@ -91,7 +102,7 @@ class Server
         if (!e)
         {
             new_connection->start();
-            new_connection.reset(new http::Connection(io_service, request_handler));
+            new_connection = std::make_shared<http::Connection>(io_service, request_handler);
             acceptor.async_accept(
                 new_connection->socket(),
                 boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
diff --git a/Server/ServerFactory.h b/Server/ServerFactory.h
deleted file mode 100644
index 5e037cf..0000000
--- a/Server/ServerFactory.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef SERVER_FACTORY_H
-#define SERVER_FACTORY_H
-
-#include "Server.h"
-#include "../Util/SimpleLogger.h"
-
-#include <zlib.h>
-
-struct ServerFactory
-{
-    ServerFactory() = delete;
-    ServerFactory(const ServerFactory &) = delete;
-    static Server *CreateServer(std::string &ip_address, int ip_port, unsigned requested_num_threads)
-    {
-        SimpleLogger().Write() << "http 1.1 compression handled by zlib version " << zlibVersion();
-        const unsigned hardware_threads = std::max(1u, std::thread::hardware_concurrency());
-        const unsigned real_num_threads = std::min(hardware_threads, requested_num_threads);
-        return new Server(ip_address, ip_port, real_num_threads);
-    }
-};
-
-#endif // SERVER_FACTORY_H
diff --git a/Tools/components.cpp b/Tools/components.cpp
deleted file mode 100644
index 945d94f..0000000
--- a/Tools/components.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "../typedefs.h"
-#include "../Algorithms/StronglyConnectedComponents.h"
-#include "../DataStructures/DynamicGraph.h"
-#include "../DataStructures/QueryEdge.h"
-#include "../DataStructures/TurnInstructions.h"
-#include "../Util/GraphLoader.h"
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/FingerPrint.h"
-
-#include <fstream>
-#include <memory>
-#include <string>
-#include <vector>
-
-typedef QueryEdge::EdgeData EdgeData;
-typedef DynamicGraph<EdgeData>::InputEdge InputEdge;
-
-std::vector<NodeInfo> internal_to_external_node_map;
-std::vector<TurnRestriction> restrictions_vector;
-std::vector<NodeID> bollard_node_IDs_vector;
-std::vector<NodeID> traffic_light_node_IDs_vector;
-
-int main(int argc, char *argv[])
-{
-    LogPolicy::GetInstance().Unmute();
-    if (argc < 3)
-    {
-        SimpleLogger().Write(logWARNING) << "usage:\n" << argv[0] << " <osrm> <osrm.restrictions>";
-        return -1;
-    }
-
-    try
-    {
-        SimpleLogger().Write() << "Using restrictions from file: " << argv[2];
-        std::ifstream restriction_ifstream(argv[2], std::ios::binary);
-        const FingerPrint fingerprint_orig;
-        FingerPrint fingerprint_loaded;
-        restriction_ifstream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
-
-        if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
-        {
-            SimpleLogger().Write(logWARNING) << argv[2] << " was prepared with a different build. "
-                                                           "Reprocess to get rid of this warning.";
-        }
-
-        if (!restriction_ifstream.good())
-        {
-            throw OSRMException("Could not access <osrm-restrictions> files");
-        }
-        uint32_t usable_restriction_count = 0;
-        restriction_ifstream.read((char *)&usable_restriction_count, sizeof(uint32_t));
-        restrictions_vector.resize(usable_restriction_count);
-
-        if (usable_restriction_count>0)
-        {
-            restriction_ifstream.read((char *)&(restrictions_vector[0]),
-                                 usable_restriction_count * sizeof(TurnRestriction));
-        }
-        restriction_ifstream.close();
-
-        std::ifstream input_stream;
-        input_stream.open(argv[1], std::ifstream::in | std::ifstream::binary);
-
-        if (!input_stream.is_open())
-        {
-            throw OSRMException("Cannot open osrm file");
-        }
-
-        std::vector<ImportEdge> edge_list;
-        const NodeID number_of_nodes = readBinaryOSRMGraphFromStream(input_stream,
-                                                                     edge_list,
-                                                                     bollard_node_IDs_vector,
-                                                                     traffic_light_node_IDs_vector,
-                                                                     &internal_to_external_node_map,
-                                                                     restrictions_vector);
-        input_stream.close();
-
-        BOOST_ASSERT_MSG(restrictions_vector.size() == usable_restriction_count,
-                         "size of restrictions_vector changed");
-
-        SimpleLogger().Write() << restrictions_vector.size() << " restrictions, "
-                               << bollard_node_IDs_vector.size() << " bollard nodes, "
-                               << traffic_light_node_IDs_vector.size() << " traffic lights";
-
-        /***
-         * Building an edge-expanded graph from node-based input an turn
-         * restrictions
-         */
-
-        SimpleLogger().Write() << "Starting SCC graph traversal";
-        std::shared_ptr<TarjanSCC> tarjan =
-            std::make_shared<TarjanSCC>(number_of_nodes,
-                                        edge_list,
-                                        bollard_node_IDs_vector,
-                                        traffic_light_node_IDs_vector,
-                                        restrictions_vector,
-                                        internal_to_external_node_map);
-        std::vector<ImportEdge>().swap(edge_list);
-
-        tarjan->Run();
-        SimpleLogger().Write() << "finished component analysis";
-    }
-    catch (const std::exception &e)
-    {
-        SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
-    }
-    return 0;
-}
diff --git a/UnitTests/Algorithms/DouglasPeuckerTest.cpp b/UnitTests/Algorithms/DouglasPeuckerTest.cpp
new file mode 100644
index 0000000..27818e5
--- /dev/null
+++ b/UnitTests/Algorithms/DouglasPeuckerTest.cpp
@@ -0,0 +1,109 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "../../algorithms/douglas_peucker.hpp"
+#include "../../data_structures/segment_information.hpp"
+#include "../../Include/osrm/Coordinate.h"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/mpl/list.hpp>
+
+#include <iostream>
+
+BOOST_AUTO_TEST_SUITE(douglas_peucker)
+
+SegmentInformation getTestInfo(int lat, int lon, bool necessary)
+{
+    return SegmentInformation(FixedPointCoordinate(lat, lon),
+                              0, 0, 0, TurnInstruction::HeadOn, necessary, false, 0);
+}
+
+BOOST_AUTO_TEST_CASE(all_necessary_test)
+{
+    /*
+     *     x
+     *    / \
+     *   x   \
+     *  /     \
+     * x       x
+     */
+    std::vector<SegmentInformation> info = {
+        getTestInfo(5, 5, true),
+        getTestInfo(6, 6, true),
+        getTestInfo(10, 10, true),
+        getTestInfo(5, 15, true)
+    };
+    DouglasPeucker dp;
+    for (unsigned z = 0; z < DOUGLAS_PEUCKER_THRESHOLDS.size(); z++)
+    {
+        dp.Run(info, z);
+        for (const auto& i : info)
+        {
+            BOOST_CHECK_EQUAL(i.necessary, true);
+        }
+    }
+}
+
+BOOST_AUTO_TEST_CASE(remove_second_node_test)
+{
+    DouglasPeucker dp;
+    for (unsigned z = 0; z < DOUGLAS_PEUCKER_THRESHOLDS.size(); z++)
+    {
+        /*
+         *   x--x
+         *   |   \
+         * x-x    x
+         *        |
+         *        x
+         */
+        std::vector<SegmentInformation> info = {
+            getTestInfo(5  * COORDINATE_PRECISION,
+                        5  * COORDINATE_PRECISION, true),
+            getTestInfo(5  * COORDINATE_PRECISION,
+                        5  * COORDINATE_PRECISION + DOUGLAS_PEUCKER_THRESHOLDS[z], false),
+            getTestInfo(10 * COORDINATE_PRECISION,
+                        10 * COORDINATE_PRECISION, false),
+            getTestInfo(10 * COORDINATE_PRECISION,
+                        10 + COORDINATE_PRECISION + DOUGLAS_PEUCKER_THRESHOLDS[z] * 2, false),
+            getTestInfo(5  * COORDINATE_PRECISION,
+                        15 * COORDINATE_PRECISION, false),
+            getTestInfo(5  * COORDINATE_PRECISION + DOUGLAS_PEUCKER_THRESHOLDS[z],
+                        15 * COORDINATE_PRECISION, true),
+        };
+        BOOST_TEST_MESSAGE("Threshold (" << z << "): " << DOUGLAS_PEUCKER_THRESHOLDS[z]);
+        dp.Run(info, z);
+        BOOST_CHECK_EQUAL(info[0].necessary, true);
+        BOOST_CHECK_EQUAL(info[1].necessary, false);
+        BOOST_CHECK_EQUAL(info[2].necessary, true);
+        BOOST_CHECK_EQUAL(info[3].necessary, true);
+        BOOST_CHECK_EQUAL(info[4].necessary, false);
+        BOOST_CHECK_EQUAL(info[5].necessary, true);
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Util/GitDescription.h b/UnitTests/algorithm_tests.cpp
similarity index 85%
copy from Util/GitDescription.h
copy to UnitTests/algorithm_tests.cpp
index d3a00f4..216a713 100644
--- a/Util/GitDescription.h
+++ b/UnitTests/algorithm_tests.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,9 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef GIT_DESCRIPTION_H
-#define GIT_DESCRIPTION_H
+#define BOOST_TEST_MODULE algorithm tests
 
-extern char g_GIT_DESCRIPTION[];
+#include <boost/test/unit_test.hpp>
+
+/*
+ * This file will contain an automatically generated main function.
+ */
 
-#endif //GIT_DESCRIPTION_H
diff --git a/UnitTests/data_structures/BinaryHeapTest.cpp b/UnitTests/data_structures/BinaryHeapTest.cpp
new file mode 100644
index 0000000..9cfdae2
--- /dev/null
+++ b/UnitTests/data_structures/BinaryHeapTest.cpp
@@ -0,0 +1,178 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "../../data_structures/binary_heap.hpp"
+#include "../../typedefs.h"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/mpl/list.hpp>
+
+#include <random>
+
+BOOST_AUTO_TEST_SUITE(binary_heap)
+
+struct TestData
+{
+    unsigned value;
+};
+
+typedef NodeID TestNodeID;
+typedef int TestKey;
+typedef int TestWeight;
+typedef boost::mpl::list<ArrayStorage<TestNodeID, TestKey>,
+                         MapStorage<TestNodeID, TestKey>,
+                         UnorderedMapStorage<TestNodeID, TestKey>> storage_types;
+
+template <unsigned NUM_ELEM> struct RandomDataFixture
+{
+    RandomDataFixture()
+    {
+        for (unsigned i = 0; i < NUM_ELEM; i++)
+        {
+            data.push_back(TestData{i * 3});
+            weights.push_back((i + 1) * 100);
+            ids.push_back(i);
+            order.push_back(i);
+        }
+
+        // Choosen by a fair W20 dice roll
+        std::mt19937 g(15);
+
+        std::shuffle(order.begin(), order.end(), g);
+    }
+
+    std::vector<TestData> data;
+    std::vector<TestWeight> weights;
+    std::vector<TestNodeID> ids;
+    std::vector<unsigned> order;
+};
+
+constexpr unsigned NUM_NODES = 100;
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(insert_test, T, storage_types, RandomDataFixture<NUM_NODES>)
+{
+    BinaryHeap<TestNodeID, TestKey, TestWeight, TestData, T> heap(NUM_NODES);
+
+    TestWeight min_weight = std::numeric_limits<TestWeight>::max();
+    TestNodeID min_id;
+
+    for (unsigned idx : order)
+    {
+        BOOST_CHECK(!heap.WasInserted(ids[idx]));
+
+        heap.Insert(ids[idx], weights[idx], data[idx]);
+
+        BOOST_CHECK(heap.WasInserted(ids[idx]));
+
+        if (weights[idx] < min_weight)
+        {
+            min_weight = weights[idx];
+            min_id = ids[idx];
+        }
+        BOOST_CHECK_EQUAL(min_id, heap.Min());
+    }
+
+    for (auto id : ids)
+    {
+        const auto &d = heap.GetData(id);
+        BOOST_CHECK_EQUAL(d.value, data[id].value);
+
+        const auto &w = heap.GetKey(id);
+        BOOST_CHECK_EQUAL(w, weights[id]);
+    }
+}
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(delete_min_test, T, storage_types, RandomDataFixture<NUM_NODES>)
+{
+    BinaryHeap<TestNodeID, TestKey, TestWeight, TestData, T> heap(NUM_NODES);
+
+    for (unsigned idx : order)
+    {
+        heap.Insert(ids[idx], weights[idx], data[idx]);
+    }
+
+    for (auto id : ids)
+    {
+        BOOST_CHECK(!heap.WasRemoved(id));
+
+        BOOST_CHECK_EQUAL(heap.Min(), id);
+        BOOST_CHECK_EQUAL(id, heap.DeleteMin());
+        if (id + 1 < NUM_NODES)
+            BOOST_CHECK_EQUAL(heap.Min(), id + 1);
+
+        BOOST_CHECK(heap.WasRemoved(id));
+    }
+}
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(delete_all_test, T, storage_types, RandomDataFixture<NUM_NODES>)
+{
+    BinaryHeap<TestNodeID, TestKey, TestWeight, TestData, T> heap(NUM_NODES);
+
+    for (unsigned idx : order)
+    {
+        heap.Insert(ids[idx], weights[idx], data[idx]);
+    }
+
+    heap.DeleteAll();
+
+    BOOST_CHECK(heap.Empty());
+}
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(decrease_key_test, T, storage_types, RandomDataFixture<10>)
+{
+    BinaryHeap<TestNodeID, TestKey, TestWeight, TestData, T> heap(10);
+
+    for (unsigned idx : order)
+    {
+        heap.Insert(ids[idx], weights[idx], data[idx]);
+    }
+
+    std::vector<TestNodeID> rids(ids);
+    std::reverse(rids.begin(), rids.end());
+
+    for (auto id : rids)
+    {
+        TestNodeID min_id = heap.Min();
+        TestWeight min_weight = heap.GetKey(min_id);
+
+        // decrease weight until we reach min weight
+        while (weights[id] > min_weight)
+        {
+            heap.DecreaseKey(id, weights[id]);
+            BOOST_CHECK_EQUAL(heap.Min(), min_id);
+            weights[id]--;
+        }
+
+        // make weight smaller than min
+        weights[id] -= 2;
+        heap.DecreaseKey(id, weights[id]);
+        BOOST_CHECK_EQUAL(heap.Min(), id);
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/UnitTests/data_structures/RangeTableTest.cpp b/UnitTests/data_structures/RangeTableTest.cpp
new file mode 100644
index 0000000..9c92532
--- /dev/null
+++ b/UnitTests/data_structures/RangeTableTest.cpp
@@ -0,0 +1,131 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "../../data_structures/range_table.hpp"
+#include "../../typedefs.h"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include <numeric>
+
+constexpr unsigned BLOCK_SIZE = 16;
+typedef RangeTable<BLOCK_SIZE, false> TestRangeTable;
+
+BOOST_AUTO_TEST_SUITE(range_table)
+
+void ConstructionTest(std::vector<unsigned> lengths, std::vector<unsigned> offsets)
+{
+    BOOST_ASSERT(lengths.size() == offsets.size() - 1);
+
+    TestRangeTable table(lengths);
+
+    for (unsigned i = 0; i < lengths.size(); i++)
+    {
+        auto range = table.GetRange(i);
+        BOOST_CHECK_EQUAL(range.front(), offsets[i]);
+        BOOST_CHECK_EQUAL(range.back() + 1, offsets[i + 1]);
+    }
+}
+
+void
+ComputeLengthsOffsets(std::vector<unsigned> &lengths, std::vector<unsigned> &offsets, unsigned num)
+{
+    lengths.resize(num);
+    offsets.resize(num + 1);
+    std::iota(lengths.begin(), lengths.end(), 1);
+    offsets[0] = 0;
+    std::partial_sum(lengths.begin(), lengths.end(), offsets.begin() + 1);
+
+    std::stringstream l_ss;
+    l_ss << "Lengths: ";
+    for (auto l : lengths)
+        l_ss << l << ", ";
+    BOOST_TEST_MESSAGE(l_ss.str());
+    std::stringstream o_ss;
+    o_ss << "Offsets: ";
+    for (auto o : offsets)
+        o_ss << o << ", ";
+    BOOST_TEST_MESSAGE(o_ss.str());
+}
+
+BOOST_AUTO_TEST_CASE(serialization_test)
+{
+    std::vector<unsigned> lengths;
+    std::vector<unsigned> offsets;
+    ComputeLengthsOffsets(lengths, offsets, (BLOCK_SIZE + 1) * 10);
+
+    TestRangeTable in_table(lengths);
+    TestRangeTable out_table;
+
+    std::stringstream ss;
+    ss << in_table;
+    ss >> out_table;
+
+    for (unsigned i = 0; i < lengths.size(); i++)
+    {
+        auto range = out_table.GetRange(i);
+        BOOST_CHECK_EQUAL(range.front(), offsets[i]);
+        BOOST_CHECK_EQUAL(range.back() + 1, offsets[i + 1]);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(construction_test)
+{
+    // only offset empty block
+    ConstructionTest({1}, {0, 1});
+    // first block almost full => sentinel is last element of block
+    // [0] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, (16)}
+    std::vector<unsigned> almost_full_lengths;
+    std::vector<unsigned> almost_full_offsets;
+    ComputeLengthsOffsets(almost_full_lengths, almost_full_offsets, BLOCK_SIZE);
+    ConstructionTest(almost_full_lengths, almost_full_offsets);
+
+    // first block full => sentinel is offset of new block, next block empty
+    // [0]     {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
+    // [(153)] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+    std::vector<unsigned> full_lengths;
+    std::vector<unsigned> full_offsets;
+    ComputeLengthsOffsets(full_lengths, full_offsets, BLOCK_SIZE + 1);
+    ConstructionTest(full_lengths, full_offsets);
+
+    // first block full and offset of next block not sentinel, but the first differential value
+    // [0]   {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
+    // [153] {(17), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+    std::vector<unsigned> over_full_lengths;
+    std::vector<unsigned> over_full_offsets;
+    ComputeLengthsOffsets(over_full_lengths, over_full_offsets, BLOCK_SIZE + 2);
+    ConstructionTest(over_full_lengths, over_full_offsets);
+
+    // test multiple blocks
+    std::vector<unsigned> multiple_lengths;
+    std::vector<unsigned> multiple_offsets;
+    ComputeLengthsOffsets(multiple_lengths, multiple_offsets, (BLOCK_SIZE + 1) * 10);
+    ConstructionTest(multiple_lengths, multiple_offsets);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/UnitTests/data_structures/StaticGraphTest.cpp b/UnitTests/data_structures/StaticGraphTest.cpp
new file mode 100644
index 0000000..4f82f8e
--- /dev/null
+++ b/UnitTests/data_structures/StaticGraphTest.cpp
@@ -0,0 +1,191 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "../../data_structures/static_graph.hpp"
+#include "../../typedefs.h"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/mpl/list.hpp>
+
+#include <random>
+#include <unordered_map>
+
+BOOST_AUTO_TEST_SUITE(static_graph)
+
+struct TestData
+{
+    EdgeID id;
+    bool shortcut;
+    unsigned distance;
+};
+
+struct TestEdge
+{
+    unsigned source;
+    unsigned target;
+    unsigned distance;
+};
+
+typedef StaticGraph<TestData> TestStaticGraph;
+typedef TestStaticGraph::NodeArrayEntry TestNodeArrayEntry;
+typedef TestStaticGraph::EdgeArrayEntry TestEdgeArrayEntry;
+typedef TestStaticGraph::InputEdge TestInputEdge;
+
+constexpr unsigned TEST_NUM_NODES = 100;
+constexpr unsigned TEST_NUM_EDGES = 500;
+// Choosen by a fair W20 dice roll (this value is completely arbitrary)
+constexpr unsigned RANDOM_SEED = 15;
+
+template <unsigned NUM_NODES, unsigned NUM_EDGES> struct RandomArrayEntryFixture
+{
+    RandomArrayEntryFixture()
+    {
+        std::mt19937 g(RANDOM_SEED);
+
+        std::uniform_int_distribution<> edge_udist(0, NUM_EDGES - 1);
+        std::vector<unsigned> offsets;
+        for (unsigned i = 0; i < NUM_NODES; i++)
+        {
+            offsets.push_back(edge_udist(g));
+        }
+        std::sort(offsets.begin(), offsets.end());
+        // add sentinel
+        offsets.push_back(offsets.back());
+
+        // extract interval lengths
+        for (unsigned i = 0; i < offsets.size() - 1; i++)
+        {
+            lengths.push_back(offsets[i + 1] - offsets[i]);
+        }
+        lengths.push_back(NUM_EDGES - offsets[NUM_NODES - 1]);
+
+        for (auto offset : offsets)
+        {
+            nodes.emplace_back(TestNodeArrayEntry{offset});
+        }
+
+        std::uniform_int_distribution<> lengths_udist(0, 100000);
+        std::uniform_int_distribution<> node_udist(0, NUM_NODES - 1);
+        for (unsigned i = 0; i < NUM_EDGES; i++)
+        {
+            edges.emplace_back(
+                TestEdgeArrayEntry{static_cast<unsigned>(node_udist(g)),
+                                   TestData{i, false, static_cast<unsigned>(lengths_udist(g))}});
+        }
+
+        for (unsigned i = 0; i < NUM_NODES; i++)
+            order.push_back(i);
+        std::shuffle(order.begin(), order.end(), g);
+    }
+
+    typename ShM<TestNodeArrayEntry, false>::vector nodes;
+    typename ShM<TestEdgeArrayEntry, false>::vector edges;
+    std::vector<unsigned> lengths;
+    std::vector<unsigned> order;
+};
+
+typedef RandomArrayEntryFixture<TEST_NUM_NODES, TEST_NUM_EDGES> TestRandomArrayEntryFixture;
+
+BOOST_FIXTURE_TEST_CASE(array_test, TestRandomArrayEntryFixture)
+{
+    auto nodes_copy = nodes;
+
+    TestStaticGraph graph(nodes, edges);
+
+    BOOST_CHECK_EQUAL(graph.GetNumberOfEdges(), TEST_NUM_EDGES);
+    BOOST_CHECK_EQUAL(graph.GetNumberOfNodes(), TEST_NUM_NODES);
+
+    for (auto idx : order)
+    {
+        BOOST_CHECK_EQUAL(graph.BeginEdges((NodeID)idx), nodes_copy[idx].first_edge);
+        BOOST_CHECK_EQUAL(graph.EndEdges((NodeID)idx), nodes_copy[idx + 1].first_edge);
+        BOOST_CHECK_EQUAL(graph.GetOutDegree((NodeID)idx), lengths[idx]);
+    }
+}
+
+TestStaticGraph GraphFromEdgeList(const std::vector<TestEdge> &edges)
+{
+    std::vector<TestInputEdge> input_edges;
+    unsigned i = 0;
+    unsigned num_nodes = 0;
+    for (const auto &e : edges)
+    {
+        input_edges.push_back(TestInputEdge{e.source, e.target, TestData{i++, false, e.distance}});
+
+        num_nodes = std::max(num_nodes, std::max(e.source, e.target));
+    }
+
+    return TestStaticGraph(num_nodes, input_edges);
+}
+
+BOOST_AUTO_TEST_CASE(find_test)
+{
+    /*
+     *  (0) -1-> (1)
+     *  ^ ^
+     *  2 1
+     *  | |
+     *  (3) -4-> (4)
+     *      <-3-
+     */
+    TestStaticGraph simple_graph = GraphFromEdgeList({TestEdge{0, 1, 1},
+                                                      TestEdge{3, 0, 2},
+                                                      TestEdge{3, 4, 4},
+                                                      TestEdge{4, 3, 3},
+                                                      TestEdge{3, 0, 1}});
+
+    auto eit = simple_graph.FindEdge(0, 1);
+    BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 0);
+
+    eit = simple_graph.FindEdge(1, 0);
+    BOOST_CHECK_EQUAL(eit, SPECIAL_EDGEID);
+
+    eit = simple_graph.FindEdgeInEitherDirection(1, 0);
+    BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 0);
+
+    bool reverse = false;
+    eit = simple_graph.FindEdgeIndicateIfReverse(1, 0, reverse);
+    BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 0);
+    BOOST_CHECK(reverse);
+
+    eit = simple_graph.FindEdge(3, 1);
+    BOOST_CHECK_EQUAL(eit, SPECIAL_EDGEID);
+    eit = simple_graph.FindEdge(0, 4);
+    BOOST_CHECK_EQUAL(eit, SPECIAL_EDGEID);
+
+    eit = simple_graph.FindEdge(3, 4);
+    BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 2);
+    eit = simple_graph.FindEdgeInEitherDirection(3, 4);
+    // I think this is wrong behaviour! Should be 3.
+    BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 2);
+
+    eit = simple_graph.FindEdge(3, 0);
+    BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 4);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/UnitTests/data_structures/StaticRTreeTest.cpp b/UnitTests/data_structures/StaticRTreeTest.cpp
new file mode 100644
index 0000000..cf3dfd0
--- /dev/null
+++ b/UnitTests/data_structures/StaticRTreeTest.cpp
@@ -0,0 +1,488 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "../../data_structures/static_rtree.hpp"
+#include "../../data_structures/query_node.hpp"
+#include "../../data_structures/edge_based_node.hpp"
+#include "../../Util/floating_point.hpp"
+#include "../../typedefs.h"
+
+#include <osrm/Coordinate.h>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/mpl/list.hpp>
+
+#include <random>
+#include <unordered_set>
+
+BOOST_AUTO_TEST_SUITE(static_rtree)
+
+constexpr uint32_t TEST_BRANCHING_FACTOR = 8;
+constexpr uint32_t TEST_LEAF_NODE_SIZE = 64;
+
+typedef EdgeBasedNode TestData;
+typedef StaticRTree<TestData,
+                    std::vector<FixedPointCoordinate>,
+                    false,
+                    TEST_BRANCHING_FACTOR,
+                    TEST_LEAF_NODE_SIZE> TestStaticRTree;
+
+// Choosen by a fair W20 dice roll (this value is completely arbitrary)
+constexpr unsigned RANDOM_SEED = 42;
+static const int32_t WORLD_MIN_LAT = -90 * COORDINATE_PRECISION;
+static const int32_t WORLD_MAX_LAT = 90 * COORDINATE_PRECISION;
+static const int32_t WORLD_MIN_LON = -180 * COORDINATE_PRECISION;
+static const int32_t WORLD_MAX_LON = 180 * COORDINATE_PRECISION;
+
+class LinearSearchNN
+{
+  public:
+    LinearSearchNN(const std::shared_ptr<std::vector<FixedPointCoordinate>> &coords,
+                   const std::vector<TestData> &edges)
+        : coords(coords), edges(edges)
+    {
+    }
+
+    bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
+                                            FixedPointCoordinate &result_coordinate)
+    {
+        float min_dist = std::numeric_limits<float>::max();
+        FixedPointCoordinate min_coord;
+        for (const TestData &e : edges)
+        {
+            const FixedPointCoordinate &start = coords->at(e.u);
+            const FixedPointCoordinate &end = coords->at(e.v);
+            float distance = FixedPointCoordinate::ApproximateEuclideanDistance(
+                input_coordinate.lat, input_coordinate.lon, start.lat, start.lon);
+            if (distance < min_dist)
+            {
+                min_coord = start;
+                min_dist = distance;
+            }
+
+            distance = FixedPointCoordinate::ApproximateEuclideanDistance(
+                input_coordinate.lat, input_coordinate.lon, end.lat, end.lon);
+            if (distance < min_dist)
+            {
+                min_coord = end;
+                min_dist = distance;
+            }
+        }
+
+        result_coordinate = min_coord;
+        return result_coordinate.is_valid();
+    }
+
+    bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+                                      PhantomNode &result_phantom_node,
+                                      const unsigned zoom_level)
+    {
+        float min_dist = std::numeric_limits<float>::max();
+        TestData nearest_edge;
+        for (const TestData &e : edges)
+        {
+            if (e.component_id != 0)
+                continue;
+
+            float current_ratio = 0.;
+            FixedPointCoordinate nearest;
+            const float current_perpendicular_distance =
+                FixedPointCoordinate::ComputePerpendicularDistance(
+                    coords->at(e.u), coords->at(e.v), input_coordinate, nearest, current_ratio);
+
+            if ((current_perpendicular_distance < min_dist) &&
+                !osrm::epsilon_compare(current_perpendicular_distance, min_dist))
+            { // found a new minimum
+                min_dist = current_perpendicular_distance;
+                result_phantom_node = {e.forward_edge_based_node_id,
+                                       e.reverse_edge_based_node_id,
+                                       e.name_id,
+                                       e.forward_weight,
+                                       e.reverse_weight,
+                                       e.forward_offset,
+                                       e.reverse_offset,
+                                       e.packed_geometry_id,
+                                       e.component_id,
+                                       nearest,
+                                       e.fwd_segment_position,
+                                       e.forward_travel_mode,
+                                       e.backward_travel_mode};
+                nearest_edge = e;
+            }
+        }
+
+        if (result_phantom_node.location.is_valid())
+        {
+            // Hack to fix rounding errors and wandering via nodes.
+            if (1 == std::abs(input_coordinate.lon - result_phantom_node.location.lon))
+            {
+                result_phantom_node.location.lon = input_coordinate.lon;
+            }
+            if (1 == std::abs(input_coordinate.lat - result_phantom_node.location.lat))
+            {
+                result_phantom_node.location.lat = input_coordinate.lat;
+            }
+
+            const float distance_1 = FixedPointCoordinate::ApproximateEuclideanDistance(
+                coords->at(nearest_edge.u), result_phantom_node.location);
+            const float distance_2 = FixedPointCoordinate::ApproximateEuclideanDistance(
+                coords->at(nearest_edge.u), coords->at(nearest_edge.v));
+            const float ratio = std::min(1.f, distance_1 / distance_2);
+
+            if (SPECIAL_NODEID != result_phantom_node.forward_node_id)
+            {
+                result_phantom_node.forward_weight *= ratio;
+            }
+            if (SPECIAL_NODEID != result_phantom_node.reverse_node_id)
+            {
+                result_phantom_node.reverse_weight *= (1. - ratio);
+            }
+        }
+
+        return result_phantom_node.location.is_valid();
+    }
+
+  private:
+    const std::shared_ptr<std::vector<FixedPointCoordinate>> &coords;
+    const std::vector<TestData> &edges;
+};
+
+template <unsigned NUM_NODES, unsigned NUM_EDGES> struct RandomGraphFixture
+{
+    struct TupleHash
+    {
+        typedef std::pair<unsigned, unsigned> argument_type;
+        typedef std::size_t result_type;
+
+        result_type operator()(const argument_type &t) const
+        {
+            std::size_t val{0};
+            boost::hash_combine(val, t.first);
+            boost::hash_combine(val, t.second);
+            return val;
+        }
+    };
+
+    RandomGraphFixture() : coords(std::make_shared<std::vector<FixedPointCoordinate>>())
+    {
+        BOOST_TEST_MESSAGE("Constructing " << NUM_NODES << " nodes and " << NUM_EDGES << " edges.");
+
+        std::mt19937 g(RANDOM_SEED);
+
+        std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
+        std::uniform_int_distribution<> lon_udist(WORLD_MIN_LON, WORLD_MAX_LON);
+
+        for (unsigned i = 0; i < NUM_NODES; i++)
+        {
+            int lat = lat_udist(g);
+            int lon = lon_udist(g);
+            nodes.emplace_back(QueryNode(lat, lon, i));
+            coords->emplace_back(FixedPointCoordinate(lat, lon));
+        }
+
+        std::uniform_int_distribution<> edge_udist(0, nodes.size() - 1);
+
+        std::unordered_set<std::pair<unsigned, unsigned>, TupleHash> used_edges;
+
+        while (edges.size() < NUM_EDGES)
+        {
+            TestData data;
+            data.u = edge_udist(g);
+            data.v = edge_udist(g);
+            if (used_edges.find(std::pair<unsigned, unsigned>(
+                    std::min(data.u, data.v), std::max(data.u, data.v))) == used_edges.end())
+            {
+                data.component_id = 0;
+                edges.emplace_back(data);
+                used_edges.emplace(std::min(data.u, data.v), std::max(data.u, data.v));
+            }
+        }
+    }
+
+    std::vector<QueryNode> nodes;
+    std::shared_ptr<std::vector<FixedPointCoordinate>> coords;
+    std::vector<TestData> edges;
+};
+
+struct GraphFixture
+{
+    GraphFixture(const std::vector<std::pair<float, float>> &input_coords,
+                 const std::vector<std::pair<unsigned, unsigned>> &input_edges)
+        : coords(std::make_shared<std::vector<FixedPointCoordinate>>())
+    {
+
+        for (unsigned i = 0; i < input_coords.size(); i++)
+        {
+            FixedPointCoordinate c(input_coords[i].first * COORDINATE_PRECISION,
+                                   input_coords[i].second * COORDINATE_PRECISION);
+            coords->emplace_back(c);
+            nodes.emplace_back(QueryNode(c.lat, c.lon, i));
+        }
+
+        for (const auto &pair : input_edges)
+        {
+            TestData d;
+            d.u = pair.first;
+            d.v = pair.second;
+            edges.emplace_back(d);
+        }
+    }
+
+    std::vector<QueryNode> nodes;
+    std::shared_ptr<std::vector<FixedPointCoordinate>> coords;
+    std::vector<TestData> edges;
+};
+
+typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * 3, TEST_LEAF_NODE_SIZE / 2>
+TestRandomGraphFixture_LeafHalfFull;
+typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * 5, TEST_LEAF_NODE_SIZE>
+TestRandomGraphFixture_LeafFull;
+typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * 10, TEST_LEAF_NODE_SIZE * 2>
+TestRandomGraphFixture_TwoLeaves;
+typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR * 3,
+                           TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR>
+TestRandomGraphFixture_Branch;
+typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR * 3,
+                           TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR * 2>
+TestRandomGraphFixture_MultipleLevels;
+
+template <typename RTreeT>
+void simple_verify_rtree(RTreeT &rtree,
+                         const std::shared_ptr<std::vector<FixedPointCoordinate>> &coords,
+                         const std::vector<TestData> &edges)
+{
+    BOOST_TEST_MESSAGE("Verify end points");
+    for (const auto &e : edges)
+    {
+        FixedPointCoordinate result_u, result_v;
+        const FixedPointCoordinate &pu = coords->at(e.u);
+        const FixedPointCoordinate &pv = coords->at(e.v);
+        bool found_u = rtree.LocateClosestEndPointForCoordinate(pu, result_u, 1);
+        bool found_v = rtree.LocateClosestEndPointForCoordinate(pv, result_v, 1);
+        BOOST_CHECK(found_u && found_v);
+        float dist_u = FixedPointCoordinate::ApproximateEuclideanDistance(
+            result_u.lat, result_u.lon, pu.lat, pu.lon);
+        BOOST_CHECK_LE(dist_u, std::numeric_limits<float>::epsilon());
+        float dist_v = FixedPointCoordinate::ApproximateEuclideanDistance(
+            result_v.lat, result_v.lon, pv.lat, pv.lon);
+        BOOST_CHECK_LE(dist_v, std::numeric_limits<float>::epsilon());
+    }
+}
+
+template <typename RTreeT>
+void sampling_verify_rtree(RTreeT &rtree, LinearSearchNN &lsnn, unsigned num_samples)
+{
+    std::mt19937 g(RANDOM_SEED);
+    std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
+    std::uniform_int_distribution<> lon_udist(WORLD_MIN_LON, WORLD_MAX_LON);
+    std::vector<FixedPointCoordinate> queries;
+    for (unsigned i = 0; i < num_samples; i++)
+    {
+        queries.emplace_back(FixedPointCoordinate(lat_udist(g), lon_udist(g)));
+    }
+
+    BOOST_TEST_MESSAGE("Sampling queries");
+    for (const auto &q : queries)
+    {
+        FixedPointCoordinate result_rtree;
+        rtree.LocateClosestEndPointForCoordinate(q, result_rtree, 1);
+        FixedPointCoordinate result_ln;
+        lsnn.LocateClosestEndPointForCoordinate(q, result_ln);
+        BOOST_CHECK_EQUAL(result_ln, result_rtree);
+
+        PhantomNode phantom_rtree;
+        rtree.FindPhantomNodeForCoordinate(q, phantom_rtree, 1);
+        PhantomNode phantom_ln;
+        lsnn.FindPhantomNodeForCoordinate(q, phantom_ln, 1);
+        BOOST_CHECK_EQUAL(phantom_rtree, phantom_ln);
+    }
+}
+
+template <typename FixtureT, typename RTreeT = TestStaticRTree>
+void build_rtree(const std::string &prefix,
+                 FixtureT *fixture,
+                 std::string &leaves_path,
+                 std::string &nodes_path)
+{
+    nodes_path = prefix + ".ramIndex";
+    leaves_path = prefix + ".fileIndex";
+    const std::string coords_path = prefix + ".nodes";
+
+    boost::filesystem::ofstream node_stream(coords_path, std::ios::binary);
+    const unsigned num_nodes = fixture->nodes.size();
+    node_stream.write((char *)&num_nodes, sizeof(unsigned));
+    node_stream.write((char *)&(fixture->nodes[0]), num_nodes * sizeof(QueryNode));
+    node_stream.close();
+
+    RTreeT r(fixture->edges, nodes_path, leaves_path, fixture->nodes);
+}
+
+template <typename FixtureT, typename RTreeT = TestStaticRTree>
+void construction_test(const std::string &prefix, FixtureT *fixture)
+{
+    std::string leaves_path;
+    std::string nodes_path;
+    build_rtree<FixtureT, RTreeT>(prefix, fixture, leaves_path, nodes_path);
+    RTreeT rtree(nodes_path, leaves_path, fixture->coords);
+    LinearSearchNN lsnn(fixture->coords, fixture->edges);
+
+    simple_verify_rtree(rtree, fixture->coords, fixture->edges);
+    sampling_verify_rtree(rtree, lsnn, 100);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_half_leaf_test, TestRandomGraphFixture_LeafHalfFull)
+{
+    construction_test("test_1", this);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_full_leaf_test, TestRandomGraphFixture_LeafFull)
+{
+    construction_test("test_2", this);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_two_leaves_test, TestRandomGraphFixture_TwoLeaves)
+{
+    construction_test("test_3", this);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_branch_test, TestRandomGraphFixture_Branch)
+{
+    construction_test("test_4", this);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_multiple_levels_test, TestRandomGraphFixture_MultipleLevels)
+{
+    construction_test("test_5", this);
+}
+
+/*
+ * Bug: If you querry a point that lies between two BBs that have a gap,
+ * one BB will be pruned, even if it could contain a nearer match.
+ */
+BOOST_AUTO_TEST_CASE(regression_test)
+{
+    typedef std::pair<float, float> Coord;
+    typedef std::pair<unsigned, unsigned> Edge;
+    GraphFixture fixture({
+                          Coord(40.0, 0.0),
+                          Coord(35.0, 5.0),
+
+                          Coord(5.0, 5.0),
+                          Coord(0.0, 10.0),
+
+                          Coord(20.0, 10.0),
+                          Coord(20.0, 5.0),
+
+                          Coord(40.0, 100.0),
+                          Coord(35.0, 105.0),
+
+                          Coord(5.0, 105.0),
+                          Coord(0.0, 110.0),
+                         },
+                         {Edge(0, 1), Edge(2, 3), Edge(4, 5), Edge(6, 7), Edge(8, 9)});
+
+    typedef StaticRTree<TestData, std::vector<FixedPointCoordinate>, false, 2, 3> MiniStaticRTree;
+
+    std::string leaves_path;
+    std::string nodes_path;
+    build_rtree<GraphFixture, MiniStaticRTree>(
+        "test_regression", &fixture, leaves_path, nodes_path);
+    MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords);
+
+    // query a node just right of the center of the gap
+    FixedPointCoordinate input(20.0 * COORDINATE_PRECISION, 55.1 * COORDINATE_PRECISION);
+    FixedPointCoordinate result;
+    rtree.LocateClosestEndPointForCoordinate(input, result, 1);
+    FixedPointCoordinate result_ln;
+    LinearSearchNN lsnn(fixture.coords, fixture.edges);
+    lsnn.LocateClosestEndPointForCoordinate(input, result_ln);
+
+    // TODO: reactivate
+    // BOOST_CHECK_EQUAL(result_ln, result);
+}
+
+void TestRectangle(double width, double height, double center_lat, double center_lon)
+{
+    FixedPointCoordinate center(center_lat * COORDINATE_PRECISION,
+                                center_lon * COORDINATE_PRECISION);
+
+    TestStaticRTree::RectangleT rect;
+    rect.min_lat = center.lat - height / 2.0 * COORDINATE_PRECISION;
+    rect.max_lat = center.lat + height / 2.0 * COORDINATE_PRECISION;
+    rect.min_lon = center.lon - width / 2.0 * COORDINATE_PRECISION;
+    rect.max_lon = center.lon + width / 2.0 * COORDINATE_PRECISION;
+
+    unsigned offset = 5 * COORDINATE_PRECISION;
+    FixedPointCoordinate north(rect.max_lat + offset, center.lon);
+    FixedPointCoordinate south(rect.min_lat - offset, center.lon);
+    FixedPointCoordinate west(center.lat, rect.min_lon - offset);
+    FixedPointCoordinate east(center.lat, rect.max_lon + offset);
+    FixedPointCoordinate north_east(rect.max_lat + offset, rect.max_lon + offset);
+    FixedPointCoordinate north_west(rect.max_lat + offset, rect.min_lon - offset);
+    FixedPointCoordinate south_east(rect.min_lat - offset, rect.max_lon + offset);
+    FixedPointCoordinate south_west(rect.min_lat - offset, rect.min_lon - offset);
+
+    /* Distance to line segments of rectangle */
+    BOOST_CHECK_EQUAL(rect.GetMinDist(north),
+                      FixedPointCoordinate::ApproximateEuclideanDistance(
+                          north, FixedPointCoordinate(rect.max_lat, north.lon)));
+    BOOST_CHECK_EQUAL(rect.GetMinDist(south),
+                      FixedPointCoordinate::ApproximateEuclideanDistance(
+                          south, FixedPointCoordinate(rect.min_lat, south.lon)));
+    BOOST_CHECK_EQUAL(rect.GetMinDist(west),
+                      FixedPointCoordinate::ApproximateEuclideanDistance(
+                          west, FixedPointCoordinate(west.lat, rect.min_lon)));
+    BOOST_CHECK_EQUAL(rect.GetMinDist(east),
+                      FixedPointCoordinate::ApproximateEuclideanDistance(
+                          east, FixedPointCoordinate(east.lat, rect.max_lon)));
+
+    /* Distance to corner points */
+    BOOST_CHECK_EQUAL(rect.GetMinDist(north_east),
+                      FixedPointCoordinate::ApproximateEuclideanDistance(
+                          north_east, FixedPointCoordinate(rect.max_lat, rect.max_lon)));
+    BOOST_CHECK_EQUAL(rect.GetMinDist(north_west),
+                      FixedPointCoordinate::ApproximateEuclideanDistance(
+                          north_west, FixedPointCoordinate(rect.max_lat, rect.min_lon)));
+    BOOST_CHECK_EQUAL(rect.GetMinDist(south_east),
+                      FixedPointCoordinate::ApproximateEuclideanDistance(
+                          south_east, FixedPointCoordinate(rect.min_lat, rect.max_lon)));
+    BOOST_CHECK_EQUAL(rect.GetMinDist(south_west),
+                      FixedPointCoordinate::ApproximateEuclideanDistance(
+                          south_west, FixedPointCoordinate(rect.min_lat, rect.min_lon)));
+}
+
+BOOST_AUTO_TEST_CASE(rectangle_test)
+{
+    TestRectangle(10, 10, 5, 5);
+    TestRectangle(10, 10, -5, 5);
+    TestRectangle(10, 10, 5, -5);
+    TestRectangle(10, 10, -5, -5);
+    TestRectangle(10, 10, 0, 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Util/GitDescription.h b/UnitTests/datastructure_tests.cpp
similarity index 85%
copy from Util/GitDescription.h
copy to UnitTests/datastructure_tests.cpp
index d3a00f4..ab39d8d 100644
--- a/Util/GitDescription.h
+++ b/UnitTests/datastructure_tests.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,9 +25,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef GIT_DESCRIPTION_H
-#define GIT_DESCRIPTION_H
+#define BOOST_TEST_MODULE datastructure tests
 
-extern char g_GIT_DESCRIPTION[];
+#include <boost/test/unit_test.hpp>
 
-#endif //GIT_DESCRIPTION_H
+/*
+ * This file will contain an automatically generated main function.
+ */
diff --git a/Util/Azimuth.h b/Util/Azimuth.h
deleted file mode 100644
index c4bf815..0000000
--- a/Util/Azimuth.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef AZIMUTH_H
-#define AZIMUTH_H
-
-#include <string>
-
-struct Azimuth
-{
-    static std::string Get(const double heading)
-    {
-        if (heading <= 202.5)
-        {
-            if (heading >= 0 && heading <= 22.5)
-            {
-                return "N";
-            }
-            if (heading > 22.5 && heading <= 67.5)
-            {
-                return "NE";
-            }
-            if (heading > 67.5 && heading <= 112.5)
-            {
-                return "E";
-            }
-            if (heading > 112.5 && heading <= 157.5)
-            {
-                return "SE";
-            }
-            return "S";
-        }
-        if (heading > 202.5 && heading <= 247.5)
-        {
-            return "SW";
-        }
-        if (heading > 247.5 && heading <= 292.5)
-        {
-            return "W";
-        }
-        if (heading > 292.5 && heading <= 337.5)
-        {
-            return "NW";
-        }
-        return "N";
-    }
-};
-
-#endif // AZIMUTH_H
diff --git a/Util/BoostFileSystemFix.h b/Util/BoostFileSystemFix.h
index 1e1e98e..aeab380 100644
--- a/Util/BoostFileSystemFix.h
+++ b/Util/BoostFileSystemFix.h
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -28,12 +28,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef BOOST_FILE_SYSTEM_FIX_H
 #define BOOST_FILE_SYSTEM_FIX_H
 
-#include "OSRMException.h"
-#include "SimpleLogger.h"
+#include "osrm_exception.hpp"
 
-#include <boost/any.hpp>
+// #include <boost/any.hpp>
 #include <boost/filesystem.hpp>
-#include <boost/program_options.hpp>
+// #include <boost/program_options.hpp>
 
 // This is one big workaround for latest boost renaming woes.
 
@@ -60,12 +59,10 @@ namespace filesystem
 //     boost::program_options::validators::check_first_occurrence(v);
 //     const std::string & input_string =
 //         boost::program_options::validators::get_single_string(values);
-//     // SimpleLogger().Write() << "validator called for " << input_string;
-//     // SimpleLogger().Write() << "validator called for " << input_string;
 //     if(boost::filesystem::is_regular_file(input_string)) {
 //         v = boost::any(boost::filesystem::path(input_string));
 //     } else {
-//         throw OSRMException(input_string + " not found");
+//         throw osrm::exception(input_string + " not found");
 //     }
 // }
 
@@ -121,7 +118,7 @@ portable_canonical(const boost::filesystem::path &relative_path,
 inline path temp_directory_path()
 {
     char *buffer;
-    buffer = tmpnam(NULL);
+    buffer = tmpnam(nullptr);
 
     return path(buffer);
 }
@@ -140,7 +137,7 @@ inline void AssertPathExists(const boost::filesystem::path &path)
 {
     if (!boost::filesystem::is_regular_file(path))
     {
-        throw OSRMException(path.string() + " not found.");
+        throw osrm::exception(path.string() + " not found.");
     }
 }
 
diff --git a/Util/DataStoreOptions.h b/Util/DataStoreOptions.h
index 7a76bfb..389c723 100644
--- a/Util/DataStoreOptions.h
+++ b/Util/DataStoreOptions.h
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -29,10 +29,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define DATA_STORE_OPTIONS_H
 
 #include "BoostFileSystemFix.h"
-#include "GitDescription.h"
+#include "git_sha.hpp"
 #include "IniFileUtil.h"
-#include "OSRMException.h"
-#include "SimpleLogger.h"
+#include "osrm_exception.hpp"
+#include "simple_logger.hpp"
 
 #include <osrm/ServerPaths.h>
 
@@ -43,7 +43,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <string>
 
 // generate boost::program_options object for the routing part
-inline bool GenerateDataStoreOptions(const int argc, const char *argv[], ServerPaths &paths, bool & springclean)
+bool GenerateDataStoreOptions(const int argc, const char *argv[], ServerPaths &paths)
 {
     // declare a group of options that will be allowed only on command line
     boost::program_options::options_description generic_options("Options");
@@ -122,11 +122,6 @@ inline bool GenerateDataStoreOptions(const int argc, const char *argv[], ServerP
         return false;
     }
 
-    if (option_variables.count("springclean"))
-    {
-        springclean = true;
-        return true;
-    }
     boost::program_options::notify(option_variables);
 
     const bool parameter_present = (paths.find("hsgrdata") != paths.end() &&
@@ -226,56 +221,56 @@ inline bool GenerateDataStoreOptions(const int argc, const char *argv[], ServerP
     path_iterator = paths.find("hsgrdata");
     if (path_iterator == paths.end() || path_iterator->second.string().empty())
     {
-        throw OSRMException(".hsgr file must be specified");
+        throw osrm::exception(".hsgr file must be specified");
     }
     AssertPathExists(path_iterator->second);
 
     path_iterator = paths.find("nodesdata");
     if (path_iterator == paths.end() || path_iterator->second.string().empty())
     {
-        throw OSRMException(".nodes file must be specified");
+        throw osrm::exception(".nodes file must be specified");
     }
     AssertPathExists(path_iterator->second);
 
     path_iterator = paths.find("edgesdata");
     if (path_iterator == paths.end() || path_iterator->second.string().empty())
     {
-        throw OSRMException(".edges file must be specified");
+        throw osrm::exception(".edges file must be specified");
     }
     AssertPathExists(path_iterator->second);
 
     path_iterator = paths.find("geometry");
     if (path_iterator == paths.end() || path_iterator->second.string().empty())
     {
-        throw OSRMException(".geometry file must be specified");
+        throw osrm::exception(".geometry file must be specified");
     }
     AssertPathExists(path_iterator->second);
 
     path_iterator = paths.find("ramindex");
     if (path_iterator == paths.end() || path_iterator->second.string().empty())
     {
-        throw OSRMException(".ramindex file must be specified");
+        throw osrm::exception(".ramindex file must be specified");
     }
     AssertPathExists(path_iterator->second);
 
     path_iterator = paths.find("fileindex");
     if (path_iterator == paths.end() || path_iterator->second.string().empty())
     {
-        throw OSRMException(".fileindex file must be specified");
+        throw osrm::exception(".fileindex file must be specified");
     }
     AssertPathExists(path_iterator->second);
 
     path_iterator = paths.find("namesdata");
     if (path_iterator == paths.end() || path_iterator->second.string().empty())
     {
-        throw OSRMException(".names file must be specified");
+        throw osrm::exception(".names file must be specified");
     }
     AssertPathExists(path_iterator->second);
 
     path_iterator = paths.find("timestamp");
     if (path_iterator == paths.end() || path_iterator->second.string().empty())
     {
-        throw OSRMException(".timestamp file must be specified");
+        throw osrm::exception(".timestamp file must be specified");
     }
 
     return true;
diff --git a/Util/FingerPrint.h b/Util/FingerPrint.h
index c61fe36..5fd04b6 100644
--- a/Util/FingerPrint.h
+++ b/Util/FingerPrint.h
@@ -42,7 +42,6 @@ class FingerPrint
     bool TestGraphUtil(const FingerPrint &other) const;
     bool TestPrepare(const FingerPrint &other) const;
     bool TestRTree(const FingerPrint &other) const;
-    bool TestNodeInfo(const FingerPrint &other) const;
     bool TestQueryObjects(const FingerPrint &other) const;
 
   private:
diff --git a/Util/MercatorUtil.h b/Util/MercatorUtil.h
index 31d1139..b4a15b7 100644
--- a/Util/MercatorUtil.h
+++ b/Util/MercatorUtil.h
@@ -30,14 +30,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <cmath>
 
-inline float y2lat(const float a)
+inline double y2lat(const double a)
 {
-    return 180.f * static_cast<float>(M_1_PI) * (2.f * std::atan(std::exp(a * static_cast<float>(M_PI) / 180.f)) - static_cast<float>(M_PI_2));
+    return 180. * M_1_PI * (2. * std::atan(std::exp(a * M_PI / 180.)) - M_PI_2);
 }
 
-inline float lat2y(const float a)
+inline double lat2y(const double a)
 {
-    return 180.f * static_cast<float>(M_1_PI) * std::log(std::tan(static_cast<float>(M_PI_4) + a * (static_cast<float>(M_PI) / 180.f) / 2.f));
+    return 180. * M_1_PI * std::log(std::tan(M_PI_4 + a * (M_PI / 180.) / 2.));
 }
 
 #endif // MERCATOR_UTIL_H
diff --git a/Util/ProgramOptions.h b/Util/ProgramOptions.h
index c6e5448..3329b31 100644
--- a/Util/ProgramOptions.h
+++ b/Util/ProgramOptions.h
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -28,10 +28,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef PROGAM_OPTIONS_H
 #define PROGAM_OPTIONS_H
 
-#include "GitDescription.h"
+#include "git_sha.hpp"
 #include "IniFileUtil.h"
-#include "OSRMException.h"
-#include "SimpleLogger.h"
+#include "osrm_exception.hpp"
+#include "simple_logger.hpp"
 
 #include <osrm/ServerPaths.h>
 
@@ -45,6 +45,104 @@ const static unsigned INIT_OK_START_ENGINE = 0;
 const static unsigned INIT_OK_DO_NOT_START_ENGINE = 1;
 const static unsigned INIT_FAILED = -1;
 
+inline void populate_base_path(ServerPaths &server_paths)
+{
+    // populate the server_path object
+    auto path_iterator = server_paths.find("base");
+
+    // if a base path has been set, we populate it.
+    if (path_iterator != server_paths.end())
+    {
+        const std::string base_string = path_iterator->second.string();
+        SimpleLogger().Write() << "populating base path: " << base_string;
+
+        server_paths["hsgrdata"] = base_string + ".hsgr";
+        BOOST_ASSERT(server_paths.find("hsgrdata") != server_paths.end());
+        server_paths["nodesdata"] = base_string + ".nodes";
+        BOOST_ASSERT(server_paths.find("nodesdata") != server_paths.end());
+        server_paths["edgesdata"] = base_string + ".edges";
+        BOOST_ASSERT(server_paths.find("edgesdata") != server_paths.end());
+        server_paths["geometries"] = base_string + ".geometry";
+        BOOST_ASSERT(server_paths.find("geometries") != server_paths.end());
+        server_paths["ramindex"] = base_string + ".ramIndex";
+        BOOST_ASSERT(server_paths.find("ramindex") != server_paths.end());
+        server_paths["fileindex"] = base_string + ".fileIndex";
+        BOOST_ASSERT(server_paths.find("fileindex") != server_paths.end());
+        server_paths["namesdata"] = base_string + ".names";
+        BOOST_ASSERT(server_paths.find("namesdata") != server_paths.end());
+        server_paths["timestamp"] = base_string + ".timestamp";
+        BOOST_ASSERT(server_paths.find("timestamp") != server_paths.end());
+    }
+
+    // check if files are give and whether they exist at all
+    path_iterator = server_paths.find("hsgrdata");
+    if (path_iterator == server_paths.end() ||
+        !boost::filesystem::is_regular_file(path_iterator->second))
+    {
+        if (path_iterator == server_paths.end())
+        {
+            SimpleLogger().Write() << "hsgrdata unset";
+        }
+        if (!boost::filesystem::is_regular_file(path_iterator->second))
+        {
+            SimpleLogger().Write() << "not a regular file";
+        }
+
+        throw osrm::exception(".hsgr not found: " + path_iterator->second.string());
+    }
+
+    path_iterator = server_paths.find("nodesdata");
+    if (path_iterator == server_paths.end() ||
+        !boost::filesystem::is_regular_file(path_iterator->second))
+    {
+        throw osrm::exception(".nodes not found");
+    }
+
+    path_iterator = server_paths.find("edgesdata");
+    if (path_iterator == server_paths.end() ||
+        !boost::filesystem::is_regular_file(path_iterator->second))
+    {
+        throw osrm::exception(".edges not found");
+    }
+
+    path_iterator = server_paths.find("geometries");
+    if (path_iterator == server_paths.end() ||
+        !boost::filesystem::is_regular_file(path_iterator->second))
+    {
+        throw osrm::exception(".geometry not found");
+    }
+
+    path_iterator = server_paths.find("ramindex");
+    if (path_iterator == server_paths.end() ||
+        !boost::filesystem::is_regular_file(path_iterator->second))
+    {
+        throw osrm::exception(".ramIndex not found");
+    }
+
+    path_iterator = server_paths.find("fileindex");
+    if (path_iterator == server_paths.end() ||
+        !boost::filesystem::is_regular_file(path_iterator->second))
+    {
+        throw osrm::exception(".fileIndex not found");
+    }
+
+    path_iterator = server_paths.find("namesdata");
+    if (path_iterator == server_paths.end() ||
+        !boost::filesystem::is_regular_file(path_iterator->second))
+    {
+        throw osrm::exception(".namesIndex not found");
+    }
+
+    SimpleLogger().Write() << "HSGR file:\t" << server_paths["hsgrdata"];
+    SimpleLogger().Write(logDEBUG) << "Nodes file:\t" << server_paths["nodesdata"];
+    SimpleLogger().Write(logDEBUG) << "Edges file:\t" << server_paths["edgesdata"];
+    SimpleLogger().Write(logDEBUG) << "Geometry file:\t" << server_paths["geometries"];
+    SimpleLogger().Write(logDEBUG) << "RAM file:\t" << server_paths["ramindex"];
+    SimpleLogger().Write(logDEBUG) << "Index file:\t" << server_paths["fileindex"];
+    SimpleLogger().Write(logDEBUG) << "Names file:\t" << server_paths["namesdata"];
+    SimpleLogger().Write(logDEBUG) << "Timestamp file:\t" << server_paths["timestamp"];
+}
+
 // generate boost::program_options object for the routing part
 inline unsigned GenerateServerProgramOptions(const int argc,
                                              const char *argv[],
@@ -55,7 +153,6 @@ inline unsigned GenerateServerProgramOptions(const int argc,
                                              bool &use_shared_memory,
                                              bool &trial)
 {
-
     // declare a group of options that will be allowed only on command line
     boost::program_options::options_description generic_options("Options");
     generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
@@ -164,99 +261,11 @@ inline unsigned GenerateServerProgramOptions(const int argc,
 
     if (1 > requested_num_threads)
     {
-        throw OSRMException("Number of threads must be a positive number");
+        throw osrm::exception("Number of threads must be a positive number");
     }
 
     if (!use_shared_memory && option_variables.count("base"))
     {
-        path_iterator = paths.find("base");
-        BOOST_ASSERT(paths.end() != path_iterator);
-        std::string base_string = path_iterator->second.string();
-
-        path_iterator = paths.find("hsgrdata");
-        if (path_iterator != paths.end() &&
-            !boost::filesystem::is_regular_file(path_iterator->second))
-        {
-            path_iterator->second = base_string + ".hsgr";
-        }
-        else
-        {
-            throw OSRMException(base_string + ".hsgr not found");
-        }
-
-        path_iterator = paths.find("nodesdata");
-        if (path_iterator != paths.end() &&
-            !boost::filesystem::is_regular_file(path_iterator->second))
-        {
-            path_iterator->second = base_string + ".nodes";
-        }
-        else
-        {
-            throw OSRMException(base_string + ".nodes not found");
-        }
-
-        path_iterator = paths.find("edgesdata");
-        if (path_iterator != paths.end() &&
-            !boost::filesystem::is_regular_file(path_iterator->second))
-        {
-            path_iterator->second = base_string + ".edges";
-        }
-        else
-        {
-            throw OSRMException(base_string + ".edges not found");
-        }
-
-        path_iterator = paths.find("geometries");
-        if (path_iterator != paths.end() &&
-            !boost::filesystem::is_regular_file(path_iterator->second))
-        {
-            path_iterator->second = base_string + ".geometry";
-        }
-        else
-        {
-            throw OSRMException(base_string + ".geometry not found");
-        }
-
-        path_iterator = paths.find("ramindex");
-        if (path_iterator != paths.end() &&
-            !boost::filesystem::is_regular_file(path_iterator->second))
-        {
-            path_iterator->second = base_string + ".ramIndex";
-        }
-        else
-        {
-            throw OSRMException(base_string + ".ramIndex not found");
-        }
-
-        path_iterator = paths.find("fileindex");
-        if (path_iterator != paths.end() &&
-            !boost::filesystem::is_regular_file(path_iterator->second))
-        {
-            path_iterator->second = base_string + ".fileIndex";
-        }
-        else
-        {
-            throw OSRMException(base_string + ".fileIndex not found");
-        }
-
-        path_iterator = paths.find("namesdata");
-        if (path_iterator != paths.end() &&
-            !boost::filesystem::is_regular_file(path_iterator->second))
-        {
-            path_iterator->second = base_string + ".names";
-        }
-        else
-        {
-            throw OSRMException(base_string + ".namesIndex not found");
-        }
-
-        path_iterator = paths.find("timestamp");
-        if (path_iterator != paths.end() &&
-            !boost::filesystem::is_regular_file(path_iterator->second))
-        {
-            path_iterator->second = base_string + ".timestamp";
-        }
-
         return INIT_OK_START_ENGINE;
     }
     if (use_shared_memory && !option_variables.count("base"))
diff --git a/Util/SimpleLogger.h b/Util/SimpleLogger.h
deleted file mode 100644
index a234c96..0000000
--- a/Util/SimpleLogger.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef SIMPLE_LOGGER_H
-#define SIMPLE_LOGGER_H
-
-#include <boost/assert.hpp>
-
-#include <cstdio>
-
-#ifdef _MSC_VER
-#include <io.h>
-#define isatty _isatty
-#define fileno _fileno
-#else
-#include <unistd.h>
-#endif
-
-#include <ostream>
-#include <iostream>
-#include <mutex>
-#include <sstream>
-
-enum LogLevel
-{ logINFO,
-  logWARNING,
-  logDEBUG };
-
-const char COL_RESET[] = "\x1b[0m";
-const char RED[] = "\x1b[31m";
-const char GREEN[] = "\x1b[32m";
-const char YELLOW[] = "\x1b[33m";
-const char BLUE[] = "\x1b[34m";
-const char MAGENTA[] = "\x1b[35m";
-const char CYAN[] = "\x1b[36m";
-
-class LogPolicy
-{
-  public:
-    void Unmute() { m_is_mute = false; }
-
-    void Mute() { m_is_mute = true; }
-
-    bool IsMute() const { return m_is_mute; }
-
-    static LogPolicy &GetInstance()
-    {
-        static LogPolicy runningInstance;
-        return runningInstance;
-    }
-
-    LogPolicy(const LogPolicy &) = delete;
-
-  private:
-    LogPolicy() : m_is_mute(true) {}
-    bool m_is_mute;
-};
-
-class SimpleLogger
-{
-  public:
-    SimpleLogger() : level(logINFO) {}
-
-    std::mutex& get_mutex()
-    {
-        static std::mutex m;
-        return m;
-    }
-
-
-    std::ostringstream &Write(LogLevel l = logINFO)
-    {
-        std::lock_guard<std::mutex> lock(get_mutex());
-        try
-        {
-            level = l;
-            os << "[";
-            switch (level)
-            {
-            case logINFO:
-                os << "info";
-                break;
-            case logWARNING:
-                os << "warn";
-                break;
-            case logDEBUG:
-#ifndef NDEBUG
-                os << "debug";
-#endif
-                break;
-            default:
-                BOOST_ASSERT_MSG(false, "should not happen");
-                break;
-            }
-            os << "] ";
-        }
-        catch (...) {}
-        return os;
-    }
-
-    virtual ~SimpleLogger()
-    {
-        std::lock_guard<std::mutex> lock(get_mutex());
-        if (!LogPolicy::GetInstance().IsMute())
-        {
-            const bool is_terminal = ( 0 != isatty(fileno(stdout)) ? true : false);
-            switch (level)
-            {
-            case logINFO:
-                std::cout << os.str() << (is_terminal ? COL_RESET : "") << std::endl;
-                break;
-            case logWARNING:
-                std::cerr << (is_terminal ? RED : "") << os.str() << (is_terminal ? COL_RESET : "")
-                          << std::endl;
-                break;
-            case logDEBUG:
-#ifndef NDEBUG
-                std::cout << (is_terminal ? YELLOW : "") << os.str()
-                          << (is_terminal ? COL_RESET : "") << std::endl;
-#endif
-                break;
-            default:
-                BOOST_ASSERT_MSG(false, "should not happen");
-                break;
-            }
-        }
-    }
-
-  private:
-    LogLevel level;
-    std::ostringstream os;
-};
-
-#endif /* SIMPLE_LOGGER_H */
diff --git a/Util/StringUtil.h b/Util/StringUtil.h
deleted file mode 100644
index 68a9ac9..0000000
--- a/Util/StringUtil.h
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef STRINGUTIL_H
-#define STRINGUTIL_H
-
-#include <boost/algorithm/string.hpp>
-#include <boost/spirit/include/karma.hpp>
-#include <boost/spirit/include/qi.hpp>
-
-#include <cstdio>
-#include <cctype>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-// precision:  position after decimal point
-// length: maximum number of digits including comma and decimals
-// work with negative values to prevent overflowing when taking -value
-template <int length, int precision> static inline char *printInt(char *buffer, int value)
-{
-    bool minus = true;
-    if (value > 0)
-    {
-        minus = false;
-        value = -value;
-    }
-    buffer += length - 1;
-    for (int i = 0; i < precision; i++)
-    {
-        *buffer = '0' - (value % 10);
-        value /= 10;
-        buffer--;
-    }
-    *buffer = '.';
-    buffer--;
-    for (int i = precision + 1; i < length; i++)
-    {
-        *buffer = '0' - (value % 10);
-        value /= 10;
-        if (value == 0)
-            break;
-        buffer--;
-    }
-    if (minus)
-    {
-        buffer--;
-        *buffer = '-';
-    }
-    return buffer;
-}
-
-// convert scoped enums to integers
-template <typename Enumeration>
-auto as_integer(Enumeration const value)
-    -> typename std::underlying_type<Enumeration>::type
-{
-    return static_cast<typename std::underlying_type<Enumeration>::type>(value);
-}
-
-static inline std::string IntToString(const int value)
-{
-    std::string output;
-    std::back_insert_iterator<std::string> sink(output);
-    boost::spirit::karma::generate(sink, boost::spirit::karma::int_, value);
-    return output;
-}
-
-static inline std::string UintToString(const unsigned value)
-{
-    std::string output;
-    std::back_insert_iterator<std::string> sink(output);
-    boost::spirit::karma::generate(sink, boost::spirit::karma::uint_, value);
-    return output;
-}
-
-static inline void int64ToString(const int64_t value, std::string &output)
-{
-    output.clear();
-    std::back_insert_iterator<std::string> sink(output);
-    boost::spirit::karma::generate(sink, boost::spirit::karma::long_long, value);
-}
-
-static inline int StringToInt(const std::string &input)
-{
-    auto first_digit = input.begin();
-    // Delete any trailing white-spaces
-    while (first_digit != input.end() && std::isspace(*first_digit))
-    {
-        ++first_digit;
-    }
-    int value = 0;
-    boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::int_, value);
-    return value;
-}
-
-static inline unsigned StringToUint(const std::string &input)
-{
-    auto first_digit = input.begin();
-    // Delete any trailing white-spaces
-    while (first_digit != input.end() && std::isspace(*first_digit))
-    {
-        ++first_digit;
-    }
-    unsigned value = 0;
-    boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::uint_, value);
-    return value;
-}
-
-static inline uint64_t StringToInt64(const std::string &input)
-{
-    auto first_digit = input.begin();
-    // Delete any trailing white-spaces
-    while (first_digit != input.end() && std::isspace(*first_digit))
-    {
-        ++first_digit;
-    }
-    uint64_t value = 0;
-    boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::long_long, value);
-    return value;
-}
-
-// source: http://tinodidriksen.com/2011/05/28/cpp-convert-string-to-double-speed/
-static inline double StringToDouble(const char *p)
-{
-    double r = 0.0;
-    bool neg = false;
-    if (*p == '-')
-    {
-        neg = true;
-        ++p;
-    }
-    while (*p >= '0' && *p <= '9')
-    {
-        r = (r * 10.0) + (*p - '0');
-        ++p;
-    }
-    if (*p == '.')
-    {
-        double f = 0.0;
-        int n = 0;
-        ++p;
-        while (*p >= '0' && *p <= '9')
-        {
-            f = (f * 10.0) + (*p - '0');
-            ++p;
-            ++n;
-        }
-        r += f / std::pow(10.0, n);
-    }
-    if (neg)
-    {
-        r = -r;
-    }
-    return r;
-}
-
-template <typename T>
-struct scientific_policy : boost::spirit::karma::real_policies<T>
-{
-    //  we want the numbers always to be in fixed format
-    static int floatfield(T n) { return boost::spirit::karma::real_policies<T>::fmtflags::fixed; }
-    static unsigned int precision(T) { return 6; }
-};
-typedef
-boost::spirit::karma::real_generator<double, scientific_policy<double> >
-science_type;
-
-static inline std::string FixedDoubleToString(const double value)
-{
-    std::string output;
-    std::back_insert_iterator<std::string> sink(output);
-    boost::spirit::karma::generate(sink, science_type(), value);
-    if (output.size() >= 2 && output[output.size()-2] == '.' && output[output.size()-1] == '0')
-    {
-        output.resize(output.size()-2);
-    }
-    return output;
-}
-
-static inline std::string DoubleToString(const double value)
-{
-    std::string output;
-    std::back_insert_iterator<std::string> sink(output);
-    boost::spirit::karma::generate(sink, value);
-    return output;
-}
-
-static inline void doubleToStringWithTwoDigitsBehindComma(const double value, std::string &output)
-{
-    // The largest 32-bit integer is 4294967295, that is 10 chars
-    // On the safe side, add 1 for sign, and 1 for trailing zero
-    char buffer[12];
-    sprintf(buffer, "%g", value);
-    output = buffer;
-}
-
-inline void replaceAll(std::string &s, const std::string &sub, const std::string &other)
-{
-    boost::replace_all(s, sub, other);
-}
-
-inline std::string EscapeJSONString(const std::string &input)
-{
-    std::string output;
-    output.reserve(input.size());
-    for (auto iter = input.begin(); iter != input.end(); ++iter)
-    {
-        switch (iter[0])
-        {
-        case '\\':
-            output += "\\\\";
-            break;
-        case '"':
-            output += "\\\"";
-            break;
-        case '/':
-            output += "\\/";
-            break;
-        case '\b':
-            output += "\\b";
-            break;
-        case '\f':
-            output += "\\f";
-            break;
-        case '\n':
-            output += "\\n";
-            break;
-        case '\r':
-            output += "\\r";
-            break;
-        case '\t':
-            output += "\\t";
-            break;
-        default:
-            output += *iter;
-            break;
-        }
-    }
-    return output;
-}
-
-static std::string originals[] = {"&", "\"", "<", ">", "'", "[", "]", "\\"};
-static std::string entities[] = {"&", """, "<", ">",
-                                 "'", "&91;",   "&93;", " \"};
-
-inline std::size_t URIDecode(const std::string &input, std::string &output)
-{
-    auto src_iter = input.begin();
-    output.resize(input.size() + 1);
-    std::size_t decoded_length = 0;
-    for (decoded_length = 0; src_iter != input.end(); ++decoded_length)
-    {
-        if (src_iter[0] == '%' && src_iter[1] && src_iter[2] && isxdigit(src_iter[1]) &&
-            isxdigit(src_iter[2]))
-        {
-            std::string::value_type a = src_iter[1];
-            std::string::value_type b = src_iter[2];
-            a -= src_iter[1] < 58 ? 48 : src_iter[1] < 71 ? 55 : 87;
-            b -= src_iter[2] < 58 ? 48 : src_iter[2] < 71 ? 55 : 87;
-            output[decoded_length] = 16 * a + b;
-            src_iter += 3;
-            continue;
-        }
-        output[decoded_length] = *src_iter++;
-    }
-    output.resize(decoded_length);
-    return decoded_length;
-}
-
-inline std::size_t URIDecodeInPlace(std::string &URI) { return URIDecode(URI, URI); }
-
-inline bool StringStartsWith(const std::string &input, const std::string &prefix)
-{
-    return boost::starts_with(input, prefix);
-}
-
-inline std::string GetRandomString()
-{
-    std::string s;
-    s.resize(128);
-    static const char alphanum[] = "0123456789"
-                                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                                   "abcdefghijklmnopqrstuvwxyz";
-
-    for (int i = 0; i < 127; ++i)
-    {
-        s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
-    }
-    s[127] = 0;
-    return s;
-}
-
-#endif // STRINGUTIL_H
diff --git a/Util/TimingUtil.h b/Util/TimingUtil.h
deleted file mode 100644
index c1505ce..0000000
--- a/Util/TimingUtil.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef TIMINGUTIL_H
-#define TIMINGUTIL_H
-
-#include <chrono>
-
-#define TIMER_START(_X) auto _X##_start = std::chrono::steady_clock::now(), _X##_stop = _X##_start
-#define TIMER_STOP(_X) _X##_stop = std::chrono::steady_clock::now()
-#define TIMER_MSEC(_X) std::chrono::duration_cast<std::chrono::milliseconds>(_X##_stop - _X##_start).count()
-#define TIMER_SEC(_X) (0.001*std::chrono::duration_cast<std::chrono::milliseconds>(_X##_stop - _X##_start).count())
-#define TIMER_MIN(_X) std::chrono::duration_cast<std::chrono::minutes>(_X##_stop - _X##_start).count()
-
-#endif // TIMINGUTIL_H
diff --git a/Util/MachineInfo.h b/Util/bearing.cpp
similarity index 65%
rename from Util/MachineInfo.h
rename to Util/bearing.cpp
index c5cb052..1cdcf30 100644
--- a/Util/MachineInfo.h
+++ b/Util/bearing.cpp
@@ -25,33 +25,41 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef MACHINE_INFO_H
-#define MACHINE_INFO_H
+#include "bearing.hpp"
 
-enum Endianness
-{ LittleEndian = 1,
-  BigEndian = 2 };
-
-// Function is optimized to a single 'mov eax,1' on GCC, clang and icc using -O3
-inline Endianness GetMachineEndianness()
+std::string Bearing::Get(const double heading)
 {
-    int i(1);
-    char *p = (char *)&i;
-    if (1 == p[0])
+    if (heading <= 202.5)
     {
-        return LittleEndian;
+        if (heading >= 0. && heading <= 22.5)
+        {
+            return "N";
+        }
+        if (heading > 22.5 && heading <= 67.5)
+        {
+            return "NE";
+        }
+        if (heading > 67.5 && heading <= 112.5)
+        {
+            return "E";
+        }
+        if (heading > 112.5 && heading <= 157.5)
+        {
+            return "SE";
+        }
+        return "S";
     }
-    return BigEndian;
-}
-
-// Reverses Network Byte Order into something usable, compiles down to a bswap-mov combination
-inline unsigned SwapEndian(unsigned x)
-{
-    if (GetMachineEndianness() == LittleEndian)
+    if (heading > 202.5 && heading <= 247.5)
     {
-        return ((x >> 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x << 24));
+        return "SW";
     }
-    return x;
+    if (heading > 247.5 && heading <= 292.5)
+    {
+        return "W";
+    }
+    if (heading > 292.5 && heading <= 337.5)
+    {
+        return "NW";
+    }
+    return "N";
 }
-
-#endif // MACHINE_INFO_H
diff --git a/Util/GitDescription.h b/Util/bearing.hpp
similarity index 89%
copy from Util/GitDescription.h
copy to Util/bearing.hpp
index d3a00f4..a30ec2f 100644
--- a/Util/GitDescription.h
+++ b/Util/bearing.hpp
@@ -25,9 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef GIT_DESCRIPTION_H
-#define GIT_DESCRIPTION_H
+#ifndef BEARING_HPP_
+#define BEARING_HPP_
 
-extern char g_GIT_DESCRIPTION[];
+#include <string>
 
-#endif //GIT_DESCRIPTION_H
+struct Bearing
+{
+    static std::string Get(const double heading);
+};
+
+#endif // BEARING_HPP_
diff --git a/Util/cast.hpp b/Util/cast.hpp
new file mode 100644
index 0000000..9d09761
--- /dev/null
+++ b/Util/cast.hpp
@@ -0,0 +1,188 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef CAST_HPP
+#define CAST_HPP
+
+#include <boost/spirit/include/karma.hpp>
+#include <boost/spirit/include/qi.hpp>
+
+#include <string>
+#include <type_traits>
+
+struct cast
+{
+    // convert scoped enums to integers
+    template <typename Enumeration>
+    static auto enum_to_underlying(Enumeration const value) -> typename std::underlying_type<Enumeration>::type
+    {
+        return static_cast<typename std::underlying_type<Enumeration>::type>(value);
+    }
+
+    template <typename Number>
+    static typename std::enable_if<std::is_integral<Number>::value, std::string>::type
+    integral_to_string(const Number value)
+    {
+        std::string output;
+        std::back_insert_iterator<std::string> sink(output);
+
+        if (8 == sizeof(Number))
+        {
+            boost::spirit::karma::generate(sink, boost::spirit::karma::long_long, value);
+        }
+        else
+        {
+            if (std::is_signed<Number>::value)
+            {
+                boost::spirit::karma::generate(sink, boost::spirit::karma::int_, value);
+            }
+            else
+            {
+                boost::spirit::karma::generate(sink, boost::spirit::karma::uint_, value);
+            }
+        }
+        return output;
+    }
+
+    static int string_to_int(const std::string &input)
+    {
+        auto first_digit = input.begin();
+        // Delete any trailing white-spaces
+        while (first_digit != input.end() && std::isspace(*first_digit))
+        {
+            ++first_digit;
+        }
+        int value = 0;
+        boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::int_, value);
+        return value;
+    }
+
+    static unsigned string_to_uint(const std::string &input)
+    {
+        auto first_digit = input.begin();
+        // Delete any trailing white-spaces
+        while (first_digit != input.end() && (std::isspace(*first_digit) || '-' == *first_digit))
+        {
+            ++first_digit;
+        }
+        unsigned value = 0;
+        boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::uint_, value);
+        return value;
+    }
+
+    static uint64_t string_to_uint64(const std::string &input)
+    {
+        auto first_digit = input.begin();
+        // Delete any trailing white-spaces
+        while (first_digit != input.end() && std::isspace(*first_digit))
+        {
+            ++first_digit;
+        }
+        uint64_t value = 0;
+        boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::long_long, value);
+        return value;
+    }
+
+    // source: http://tinodidriksen.com/2011/05/28/cpp-convert-string-to-double-speed/
+    static double string_to_double(const char *p)
+    {
+        double r = 0.0;
+        bool neg = false;
+        if (*p == '-')
+        {
+            neg = true;
+            ++p;
+        }
+        while (*p >= '0' && *p <= '9')
+        {
+            r = (r * 10.0) + (*p - '0');
+            ++p;
+        }
+        if (*p == '.')
+        {
+            double f = 0.0;
+            int n = 0;
+            ++p;
+            while (*p >= '0' && *p <= '9')
+            {
+                f = (f * 10.0) + (*p - '0');
+                ++p;
+                ++n;
+            }
+            r += f / std::pow(10.0, n);
+        }
+        if (neg)
+        {
+            r = -r;
+        }
+        return r;
+    }
+
+    template <typename T> struct scientific_policy : boost::spirit::karma::real_policies<T>
+    {
+        //  we want the numbers always to be in fixed format
+        static int floatfield(T)
+        {
+            return boost::spirit::karma::real_policies<T>::fmtflags::fixed;
+        }
+        static unsigned int precision(T) { return 6; }
+    };
+    typedef boost::spirit::karma::real_generator<double, scientific_policy<double>> science_type;
+
+    static std::string double_fixed_to_string(const double value)
+    {
+        std::string output;
+        std::back_insert_iterator<std::string> sink(output);
+        boost::spirit::karma::generate(sink, science_type(), value);
+        if (output.size() >= 2 && output[output.size() - 2] == '.' &&
+            output[output.size() - 1] == '0')
+        {
+            output.resize(output.size() - 2);
+        }
+        return output;
+    }
+
+    static std::string double_to_string(const double value)
+    {
+        std::string output;
+        std::back_insert_iterator<std::string> sink(output);
+        boost::spirit::karma::generate(sink, value);
+        return output;
+    }
+
+    static void double_with_two_digits_to_string(const double value,
+                                                              std::string &output)
+    {
+        // The largest 32-bit integer is 4294967295, that is 10 chars
+        // On the safe side, add 1 for sign, and 1 for trailing zero
+        char buffer[12];
+        sprintf(buffer, "%g", value);
+        output = buffer;
+    }
+};
+
+#endif // CAST_HPP
diff --git a/Util/ComputeAngle.h b/Util/compute_angle.cpp
similarity index 77%
rename from Util/ComputeAngle.h
rename to Util/compute_angle.cpp
index 02f678a..b6350e4 100644
--- a/Util/ComputeAngle.h
+++ b/Util/compute_angle.cpp
@@ -25,33 +25,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef COMPUTE_ANGLE_H
-#define COMPUTE_ANGLE_H
+#include "compute_angle.hpp"
 
 #include "TrigonometryTables.h"
 #include "../Util/MercatorUtil.h"
 #include <osrm/Coordinate.h>
 
-#include <boost/assert.hpp>
 #include <cmath>
 
-/* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/
-template <class CoordinateT>
-inline static double GetAngleBetweenThreeFixedPointCoordinates(const CoordinateT &A,
-                                                               const CoordinateT &C,
-                                                               const CoordinateT &B)
+double ComputeAngle::OfThreeFixedPointCoordinates(const FixedPointCoordinate &A,
+                                                  const FixedPointCoordinate &C,
+                                                  const FixedPointCoordinate &B)
 {
     const double v1x = (A.lon - C.lon) / COORDINATE_PRECISION;
     const double v1y = lat2y(A.lat / COORDINATE_PRECISION) - lat2y(C.lat / COORDINATE_PRECISION);
     const double v2x = (B.lon - C.lon) / COORDINATE_PRECISION;
     const double v2y = lat2y(B.lat / COORDINATE_PRECISION) - lat2y(C.lat / COORDINATE_PRECISION);
 
-    double angle = (atan2_lookup(v2y, v2x) - atan2_lookup(v1y, v1x)) * 180 / M_PI;
-    while (angle < 0)
+    double angle = (atan2_lookup(v2y, v2x) - atan2_lookup(v1y, v1x)) * 180. / M_PI;
+    while (angle < 0.)
     {
-        angle += 360;
+        angle += 360.;
     }
     return angle;
 }
-
-#endif // COMPUTE_ANGLE_H
diff --git a/Library/OSRM.h b/Util/compute_angle.hpp
similarity index 73%
copy from Library/OSRM.h
copy to Util/compute_angle.hpp
index 16b9977..72c861a 100644
--- a/Library/OSRM.h
+++ b/Util/compute_angle.hpp
@@ -25,28 +25,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef OSRM_H
-#define OSRM_H
+#ifndef COMPUTE_ANGLE_HPP
+#define COMPUTE_ANGLE_HPP
 
-#include <osrm/ServerPaths.h>
+struct FixedPointCoordinate;
+struct NodeInfo;
 
-class OSRM_impl;
-struct RouteParameters;
-
-namespace http
-{
-class Reply;
-}
-
-class OSRM
+struct ComputeAngle
 {
-  private:
-    OSRM_impl *OSRM_pimpl_;
-
-  public:
-    explicit OSRM(const ServerPaths &paths, const bool use_shared_memory = false);
-    ~OSRM();
-    void RunQuery(RouteParameters &route_parameters, http::Reply &reply);
+    /* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/
+    static double OfThreeFixedPointCoordinates(const FixedPointCoordinate &A,
+                                               const FixedPointCoordinate &C,
+                                               const FixedPointCoordinate &B);
 };
-
-#endif // OSRM_H
+#endif // COMPUTE_ANGLE_HPP
diff --git a/Util/ContainerUtils.h b/Util/container.hpp
similarity index 57%
rename from Util/ContainerUtils.h
rename to Util/container.hpp
index 2517545..343ebe9 100644
--- a/Util/ContainerUtils.h
+++ b/Util/container.hpp
@@ -25,47 +25,58 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef CONTAINERUTILS_H_
-#define CONTAINERUTILS_H_
+#ifndef CONTAINER_HPP_
+#define CONTAINER_HPP_
 
 #include <algorithm>
+#include <iterator>
 #include <vector>
 
-template <typename T> inline void sort_unique_resize(std::vector<T> &vector)
+namespace osrm
+{
+template <typename T> void sort_unique_resize(std::vector<T> &vector)
 {
     std::sort(vector.begin(), vector.end());
     const auto number_of_unique_elements = std::unique(vector.begin(), vector.end()) - vector.begin();
     vector.resize(number_of_unique_elements);
 }
 
-template <typename T> inline void sort_unique_resize_shrink_vector(std::vector<T> &vector)
-{
-    sort_unique_resize(vector);
-    std::vector<T>().swap(vector);
-}
+// template <typename T> inline void sort_unique_resize_shrink_vector(std::vector<T> &vector)
+// {
+//     sort_unique_resize(vector);
+//     vector.shrink_to_fit();
+// }
 
-template <typename T> inline void remove_consecutive_duplicates_from_vector(std::vector<T> &vector)
-{
-    const auto number_of_unique_elements = std::unique(vector.begin(), vector.end()) - vector.begin();
-    vector.resize(number_of_unique_elements);
-}
+// template <typename T> inline void remove_consecutive_duplicates_from_vector(std::vector<T> &vector)
+// {
+//     const auto number_of_unique_elements = std::unique(vector.begin(), vector.end()) - vector.begin();
+//     vector.resize(number_of_unique_elements);
+// }
 
-template <typename FwdIter, typename Func>
-Func for_each_pair(FwdIter iter_begin, FwdIter iter_end, Func func)
+template <typename ForwardIterator, typename Function>
+Function for_each_pair(ForwardIterator begin, ForwardIterator end, Function function)
 {
-    if (iter_begin == iter_end)
+    if (begin == end)
     {
-        return func;
+        return function;
     }
 
-    FwdIter iter_next = iter_begin;
-    ++iter_next;
+    auto next = begin;
+    next = std::next(next);
 
-    for (; iter_next != iter_end; ++iter_begin, ++iter_next)
+    while (next != end)
     {
-        func(*iter_begin, *iter_next);
+        function(*begin, *next);
+        begin = std::next(begin); next = std::next(next);
     }
-    return func;
+    return function;
 }
 
-#endif /* CONTAINERUTILS_H_ */
+template <class ContainerT, typename Function>
+Function for_each_pair(ContainerT &container, Function function)
+{
+    return for_each_pair(std::begin(container), std::end(container), function);
+}
+
+}
+#endif /* CONTAINER_HPP_ */
diff --git a/Util/FingerPrint.cpp.in b/Util/finger_print.cpp.in
similarity index 87%
rename from Util/FingerPrint.cpp.in
rename to Util/finger_print.cpp.in
index d1ce4f0..c73756e 100644
--- a/Util/FingerPrint.cpp.in
+++ b/Util/finger_print.cpp.in
@@ -27,12 +27,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "FingerPrint.h"
 
-#include "OSRMException.h"
+#include "osrm_exception.hpp"
 
 #include <boost/uuid/name_generator.hpp>
 
-#include <cstring>
-
 #include <algorithm>
 #include <string>
 
@@ -47,8 +45,7 @@ FingerPrint::FingerPrint() : magic_number(1297240911)
     md5_prepare[32] = md5_tree[32] = md5_graph[32] = md5_objects[32] = '\0';
 
     boost::uuids::name_generator gen(named_uuid);
-    std::string temp_string(__DATE__);
-    temp_string += __TIME__;
+    std::string temp_string;
 
     std::memcpy(md5_prepare, MD5PREPARE, strlen(MD5PREPARE));
     temp_string += md5_prepare;
@@ -73,7 +70,7 @@ bool FingerPrint::TestGraphUtil(const FingerPrint &other) const
 {
     if (!other.IsMagicNumberOK())
     {
-        throw OSRMException("hsgr input file misses magic number. Check or reprocess the file");
+        throw osrm::exception("hsgr input file misses magic number. Check or reprocess the file");
     }
     return std::equal(md5_graph, md5_graph + 32, other.md5_graph);
 }
@@ -82,7 +79,7 @@ bool FingerPrint::TestPrepare(const FingerPrint &other) const
 {
     if (!other.IsMagicNumberOK())
     {
-        throw OSRMException("osrm input file misses magic number. Check or reprocess the file");
+        throw osrm::exception("osrm input file misses magic number. Check or reprocess the file");
     }
     return std::equal(md5_prepare, md5_prepare + 32, other.md5_prepare);
 }
@@ -91,7 +88,7 @@ bool FingerPrint::TestRTree(const FingerPrint &other) const
 {
     if (!other.IsMagicNumberOK())
     {
-        throw OSRMException("r-tree input file misses magic number. Check or reprocess the file");
+        throw osrm::exception("r-tree input file misses magic number. Check or reprocess the file");
     }
     return std::equal(md5_tree, md5_tree + 32, other.md5_tree);
 }
@@ -100,7 +97,7 @@ bool FingerPrint::TestQueryObjects(const FingerPrint &other) const
 {
     if (!other.IsMagicNumberOK())
     {
-        throw OSRMException("missing magic number. Check or reprocess the file");
+        throw osrm::exception("missing magic number. Check or reprocess the file");
     }
     return std::equal(md5_objects, md5_objects + 32, other.md5_objects);
 }
diff --git a/Library/OSRM.h b/Util/floating_point.hpp
similarity index 75%
copy from Library/OSRM.h
copy to Util/floating_point.hpp
index 16b9977..5c48102 100644
--- a/Library/OSRM.h
+++ b/Util/floating_point.hpp
@@ -1,5 +1,4 @@
 /*
-
 Copyright (c) 2013, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
@@ -25,28 +24,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef OSRM_H
-#define OSRM_H
+#ifndef FLOATING_POINT_HPP
+#define FLOATING_POINT_HPP
 
-#include <osrm/ServerPaths.h>
+#include <cmath>
 
-class OSRM_impl;
-struct RouteParameters;
+#include <limits>
+#include <type_traits>
 
-namespace http
+namespace osrm
 {
-class Reply;
-}
-
-class OSRM
+template <typename FloatT> bool epsilon_compare(const FloatT number1, const FloatT number2)
 {
-  private:
-    OSRM_impl *OSRM_pimpl_;
-
-  public:
-    explicit OSRM(const ServerPaths &paths, const bool use_shared_memory = false);
-    ~OSRM();
-    void RunQuery(RouteParameters &route_parameters, http::Reply &reply);
-};
+    static_assert(std::is_floating_point<FloatT>::value, "type must be floating point");
+    return (std::abs(number1 - number2) < std::numeric_limits<FloatT>::epsilon());
+}
+}
 
-#endif // OSRM_H
+#endif // FLOATING_POINT_HPP
diff --git a/Util/GitDescription.cpp.in b/Util/git_sha.cpp.in
similarity index 94%
rename from Util/GitDescription.cpp.in
rename to Util/git_sha.cpp.in
index 6f4ba7e..5b19337 100644
--- a/Util/GitDescription.cpp.in
+++ b/Util/git_sha.cpp.in
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,5 +25,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
+#include "git_sha.hpp"
+
 #define GIT_DESCRIPTION "${GIT_DESCRIPTION}"
 char g_GIT_DESCRIPTION[] = GIT_DESCRIPTION;
diff --git a/Util/GitDescription.h b/Util/git_sha.hpp
similarity index 90%
rename from Util/GitDescription.h
rename to Util/git_sha.hpp
index d3a00f4..d1f18a6 100644
--- a/Util/GitDescription.h
+++ b/Util/git_sha.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,9 +25,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef GIT_DESCRIPTION_H
-#define GIT_DESCRIPTION_H
+#ifndef GIT_SHA_HPP
+#define GIT_SHA_HPP
 
 extern char g_GIT_DESCRIPTION[];
 
-#endif //GIT_DESCRIPTION_H
+#endif //GIT_SHA_HPP
diff --git a/Util/GraphLoader.h b/Util/graph_loader.hpp
similarity index 84%
rename from Util/GraphLoader.h
rename to Util/graph_loader.hpp
index 612332b..5ab8eba 100644
--- a/Util/GraphLoader.h
+++ b/Util/graph_loader.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -28,12 +28,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef GRAPHLOADER_H
 #define GRAPHLOADER_H
 
-#include "OSRMException.h"
-#include "../DataStructures/ImportNode.h"
-#include "../DataStructures/ImportEdge.h"
-#include "../DataStructures/QueryNode.h"
-#include "../DataStructures/Restriction.h"
-#include "../Util/SimpleLogger.h"
+#include "osrm_exception.hpp"
+#include "../data_structures/external_memory_node.hpp"
+#include "../data_structures/import_edge.hpp"
+#include "../data_structures/query_node.hpp"
+#include "../data_structures/restriction.hpp"
+#include "../Util/simple_logger.hpp"
 #include "../Util/FingerPrint.h"
 #include "../typedefs.h"
 
@@ -57,7 +57,7 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
                                      std::vector<EdgeT> &edge_list,
                                      std::vector<NodeID> &barrier_node_list,
                                      std::vector<NodeID> &traffic_light_node_list,
-                                     std::vector<NodeInfo> *int_to_ext_node_id_map,
+                                     std::vector<QueryNode> *int_to_ext_node_id_map,
                                      std::vector<TurnRestriction> &restriction_list)
 {
     const FingerPrint fingerprint_orig;
@@ -70,23 +70,23 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
                                             "Reprocess to get rid of this warning.";
     }
 
-    NodeID n, source, target;
-    EdgeID m;
-    short dir; // direction (0 = open, 1 = forward, 2+ = open)
     std::unordered_map<NodeID, NodeID> ext_to_int_id_map;
+
+    NodeID n;
     input_stream.read((char *)&n, sizeof(NodeID));
     SimpleLogger().Write() << "Importing n = " << n << " nodes ";
+
     ExternalMemoryNode current_node;
     for (NodeID i = 0; i < n; ++i)
     {
         input_stream.read((char *)&current_node, sizeof(ExternalMemoryNode));
         int_to_ext_node_id_map->emplace_back(current_node.lat, current_node.lon, current_node.node_id);
         ext_to_int_id_map.emplace(current_node.node_id, i);
-        if (current_node.bollard)
+        if (current_node.barrier)
         {
             barrier_node_list.emplace_back(i);
         }
-        if (current_node.trafficLight)
+        if (current_node.traffic_lights)
         {
             traffic_light_node_list.emplace_back(i);
         }
@@ -95,41 +95,47 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
     // tighten vector sizes
     barrier_node_list.shrink_to_fit();
     traffic_light_node_list.shrink_to_fit();
-    input_stream.read((char *)&m, sizeof(unsigned));
-    SimpleLogger().Write() << " and " << m << " edges ";
+
+    // renumber nodes in turn restrictions
     for (TurnRestriction &current_restriction : restriction_list)
     {
-        auto internal_id_iter = ext_to_int_id_map.find(current_restriction.fromNode);
+        auto internal_id_iter = ext_to_int_id_map.find(current_restriction.from.node);
         if (internal_id_iter == ext_to_int_id_map.end())
         {
             SimpleLogger().Write(logDEBUG) << "Unmapped from Node of restriction";
             continue;
         }
-        current_restriction.fromNode = internal_id_iter->second;
+        current_restriction.from.node = internal_id_iter->second;
 
-        internal_id_iter = ext_to_int_id_map.find(current_restriction.viaNode);
+        internal_id_iter = ext_to_int_id_map.find(current_restriction.via.node);
         if (internal_id_iter == ext_to_int_id_map.end())
         {
             SimpleLogger().Write(logDEBUG) << "Unmapped via node of restriction";
             continue;
         }
-        current_restriction.viaNode = internal_id_iter->second;
+        current_restriction.via.node = internal_id_iter->second;
 
-        internal_id_iter = ext_to_int_id_map.find(current_restriction.toNode);
+        internal_id_iter = ext_to_int_id_map.find(current_restriction.to.node);
         if (internal_id_iter == ext_to_int_id_map.end())
         {
             SimpleLogger().Write(logDEBUG) << "Unmapped to node of restriction";
             continue;
         }
-        current_restriction.toNode = internal_id_iter->second;
+        current_restriction.to.node = internal_id_iter->second;
     }
 
-    edge_list.reserve(m);
     EdgeWeight weight;
-    short type;
-    NodeID nameID;
+    NodeID source, target;
+    unsigned nameID;
     int length;
-    bool is_roundabout, ignore_in_grid, is_access_restricted, is_contra_flow, is_split;
+    short dir; // direction (0 = open, 1 = forward, 2+ = open)
+    bool is_roundabout, ignore_in_grid, is_access_restricted, is_split;
+    TravelMode travel_mode;
+
+    EdgeID m;
+    input_stream.read((char *)&m, sizeof(unsigned));
+    edge_list.reserve(m);
+    SimpleLogger().Write() << " and " << m << " edges ";
 
     for (EdgeID i = 0; i < m; ++i)
     {
@@ -138,12 +144,11 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
         input_stream.read((char *)&length, sizeof(int));
         input_stream.read((char *)&dir, sizeof(short));
         input_stream.read((char *)&weight, sizeof(int));
-        input_stream.read((char *)&type, sizeof(short));
         input_stream.read((char *)&nameID, sizeof(unsigned));
         input_stream.read((char *)&is_roundabout, sizeof(bool));
         input_stream.read((char *)&ignore_in_grid, sizeof(bool));
         input_stream.read((char *)&is_access_restricted, sizeof(bool));
-        input_stream.read((char *)&is_contra_flow, sizeof(bool));
+        input_stream.read((char *)&travel_mode, sizeof(TravelMode));
         input_stream.read((char *)&is_split, sizeof(bool));
 
         BOOST_ASSERT_MSG(length > 0, "loaded null length edge");
@@ -161,8 +166,6 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
             forward = false;
         }
 
-        BOOST_ASSERT(type >= 0);
-
         // translate the external NodeIDs to internal IDs
         auto internal_id_iter = ext_to_int_id_map.find(source);
         if (ext_to_int_id_map.find(source) == ext_to_int_id_map.end())
@@ -182,7 +185,8 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
             continue;
         }
         target = internal_id_iter->second;
-        BOOST_ASSERT_MSG(source != UINT_MAX && target != UINT_MAX, "nonexisting source or target");
+        BOOST_ASSERT_MSG(source != SPECIAL_NODEID && target != SPECIAL_NODEID,
+                         "nonexisting source or target");
 
         if (source > target)
         {
@@ -196,15 +200,16 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
                                weight,
                                forward,
                                backward,
-                               type,
                                is_roundabout,
                                ignore_in_grid,
                                is_access_restricted,
-                               is_contra_flow,
+                               travel_mode,
                                is_split);
     }
+    ext_to_int_id_map.clear();
 
     tbb::parallel_sort(edge_list.begin(), edge_list.end());
+
     for (unsigned i = 1; i < edge_list.size(); ++i)
     {
         if ((edge_list[i - 1].target == edge_list[i].target) &&
@@ -215,22 +220,22 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
                 (edge_list[i - 1].backward == edge_list[i].backward);
             const bool edge_flags_are_superset1 =
                 (edge_list[i - 1].forward && edge_list[i - 1].backward) &&
-                (edge_list[i].backward != edge_list[i].backward);
+                (edge_list[i].forward != edge_list[i].backward);
             const bool edge_flags_are_superset_2 =
                 (edge_list[i].forward && edge_list[i].backward) &&
-                (edge_list[i - 1].backward != edge_list[i - 1].backward);
+                (edge_list[i - 1].forward != edge_list[i - 1].backward);
 
             if (edge_flags_equivalent)
             {
                 edge_list[i].weight = std::min(edge_list[i - 1].weight, edge_list[i].weight);
-                edge_list[i - 1].source = UINT_MAX;
+                edge_list[i - 1].source = SPECIAL_NODEID;
             }
             else if (edge_flags_are_superset1)
             {
                 if (edge_list[i - 1].weight <= edge_list[i].weight)
                 {
                     // edge i-1 is smaller and goes in both directions. Throw away the other edge
-                    edge_list[i].source = UINT_MAX;
+                    edge_list[i].source = SPECIAL_NODEID;
                 }
                 else
                 {
@@ -252,16 +257,16 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
                 else
                 {
                     // edge i is smaller and goes in both direction. Throw away edge i-1
-                    edge_list[i - 1].source = UINT_MAX;
+                    edge_list[i - 1].source = SPECIAL_NODEID;
                 }
             }
         }
     }
-    const auto new_end_iter = std::remove_if(edge_list.begin(),
-                                       edge_list.end(),
-                                       [](const EdgeT &edge)
-                                       { return edge.source == SPECIAL_NODEID; });
-    ext_to_int_id_map.clear();
+    const auto new_end_iter = std::remove_if(edge_list.begin(), edge_list.end(), [] (const EdgeT &edge)
+                                        {
+                                            return edge.source == SPECIAL_NODEID ||
+                                                   edge.target == SPECIAL_NODEID;
+                                        });
     edge_list.erase(new_end_iter, edge_list.end()); // remove excess candidates.
     edge_list.shrink_to_fit();
     SimpleLogger().Write() << "Graph loaded ok and has " << edge_list.size() << " edges";
@@ -276,11 +281,11 @@ unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
 {
     if (!boost::filesystem::exists(hsgr_file))
     {
-        throw OSRMException("hsgr file does not exist");
+        throw osrm::exception("hsgr file does not exist");
     }
     if (0 == boost::filesystem::file_size(hsgr_file))
     {
-        throw OSRMException("hsgr file is empty");
+        throw osrm::exception("hsgr file is empty");
     }
 
     boost::filesystem::ifstream hsgr_input_stream(hsgr_file, std::ios::binary);
@@ -304,7 +309,7 @@ unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
                            << ", number_of_edges: " << number_of_edges;
 
     // BOOST_ASSERT_MSG( 0 != number_of_edges, "number of edges is zero");
-    node_list.resize(number_of_nodes + 1);
+    node_list.resize(number_of_nodes);
     hsgr_input_stream.read((char *)&(node_list[0]), number_of_nodes * sizeof(NodeT));
 
     edge_list.resize(number_of_edges);
diff --git a/DataStructures/SearchEngine.h b/Util/integer_range.hpp
similarity index 54%
copy from DataStructures/SearchEngine.h
copy to Util/integer_range.hpp
index 58f5e77..030b2fa 100644
--- a/DataStructures/SearchEngine.h
+++ b/Util/integer_range.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2013,2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,36 +25,46 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef SEARCHENGINE_H
-#define SEARCHENGINE_H
-
-#include "SearchEngineData.h"
-#include "../RoutingAlgorithms/AlternativePathRouting.h"
-#include "../RoutingAlgorithms/ManyToManyRouting.h"
-#include "../RoutingAlgorithms/ShortestPathRouting.h"
+#ifndef INTEGER_RANGE_HPP
+#define INTEGER_RANGE_HPP
 
 #include <type_traits>
 
-template <class DataFacadeT> class SearchEngine
+namespace osrm
+{
+
+template <typename Integer> class range
 {
   private:
-    DataFacadeT *facade;
-    SearchEngineData engine_working_data;
+    Integer last;
+    Integer iter;
 
   public:
-    ShortestPathRouting<DataFacadeT> shortest_path;
-    AlternativeRouting<DataFacadeT> alternative_path;
-    ManyToManyRouting<DataFacadeT> distance_table;
-
-    explicit SearchEngine(DataFacadeT *facade)
-        : facade(facade), shortest_path(facade, engine_working_data),
-          alternative_path(facade, engine_working_data), distance_table(facade, engine_working_data)
+    range(Integer start, Integer end) : last(end), iter(start)
     {
-        static_assert(!std::is_pointer<DataFacadeT>::value, "don't instantiate with ptr type");
-        static_assert(std::is_object<DataFacadeT>::value, "don't instantiate with void, function, or reference");
+        static_assert(std::is_integral<Integer>::value, "range type must be integral");
     }
 
-    ~SearchEngine() {}
+    // Iterable functions
+    const range &begin() const { return *this; }
+    const range &end() const { return *this; }
+    Integer front() const { return iter; }
+    Integer back() const { return last - 1; }
+
+    // Iterator functions
+    bool operator!=(const range &) const { return iter < last; }
+    void operator++() { ++iter; }
+    Integer operator*() const { return iter; }
 };
 
-#endif // SEARCHENGINE_H
+// convenience function to construct an integer range with type deduction
+template <typename Integer>
+range<Integer> irange(const Integer first,
+                      const Integer last,
+                      typename std::enable_if<std::is_integral<Integer>::value>::type * = 0)
+{
+    return range<Integer>(first, last);
+}
+}
+
+#endif // INTEGER_RANGE_HPP
diff --git a/DataStructures/HashTable.h b/Util/iterator_range.hpp
similarity index 55%
rename from DataStructures/HashTable.h
rename to Util/iterator_range.hpp
index 199c6df..a057d7c 100644
--- a/DataStructures/HashTable.h
+++ b/Util/iterator_range.hpp
@@ -25,54 +25,48 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef HASH_TABLE_H
-#define HASH_TABLE_H
+#ifndef RANGE_HPP_
+#define RANGE_HPP_
 
-#include <vector>
-
-template <typename Key, typename Value>
-class HashTable
+namespace osrm
+{
+namespace util
+{
+template <typename Iterator> class Range
 {
-  private:
-    typedef std::pair<Key, Value> KeyValPair;
-    std::vector<KeyValPair> table;
-
   public:
-    HashTable() {}
+    Range(Iterator begin, Iterator end) : begin_(begin), end_(end) {}
 
-    inline void Add(Key const &key, Value const &value)
-    {
-        table.emplace_back(std::move(key), std::move(value));
-    }
+    Iterator begin() const { return begin_; }
+    Iterator end() const { return end_; }
 
-    inline void Clear()
-    {
-        table.clear();
-    }
+  private:
+    Iterator begin_;
+    Iterator end_;
+};
 
-    inline const Value Find(Key const &key) const
-    {
-        for (const auto &key_val_pair : table)
-        {
-            if (key_val_pair.first == key)
-            {
-                return key_val_pair.second;
-            }
-        }
-        return Value();
-    }
+// Convenience functions for template parameter inference,
+// akin to std::make_pair.
 
-    inline const bool Holds(Key const &key) const
-    {
-        for (const auto &key_val_pair : table)
-        {
-            if (key_val_pair.first == key)
-            {
-                return true;
-            }
-        }
-        return false;
-    }
-};
+template <typename Iterator> Range<Iterator> range(Iterator begin, Iterator end)
+{
+    return Range<Iterator>(begin, end);
+}
+
+template <typename Reversable>
+Range<typename Reversable::reverse_iterator> reverse(Reversable *reversable)
+{
+    return Range<typename Reversable::reverse_iterator>(reversable->rbegin(), reversable->rend());
+}
+
+template <typename ConstReversable>
+Range<typename ConstReversable::const_reverse_iterator>
+const_reverse(const ConstReversable *const_reversable)
+{
+    return Range<typename ConstReversable::const_reverse_iterator>(const_reversable->crbegin(),
+                                                                   const_reversable->crend());
+}
+}
+}
 
-#endif /* HASH_TABLE_H */
+#endif // RANGE_HPP_
diff --git a/DataStructures/JSONContainer.h b/Util/json_renderer.hpp
similarity index 66%
rename from DataStructures/JSONContainer.h
rename to Util/json_renderer.hpp
index 47dc34b..dd6089c 100644
--- a/DataStructures/JSONContainer.h
+++ b/Util/json_renderer.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,79 +25,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-// based on https://svn.apache.org/repos/asf/mesos/tags/release-0.9.0-incubating-RC0/src/common/json.hpp
+// based on
+// https://svn.apache.org/repos/asf/mesos/tags/release-0.9.0-incubating-RC0/src/common/json.hpp
 
-#ifndef JSON_CONTAINER_H
-#define JSON_CONTAINER_H
+#ifndef JSON_RENDERER_HPP
+#define JSON_RENDERER_HPP
 
-#include "../Util/StringUtil.h"
+#include "../data_structures/json_container.hpp"
+#include "cast.hpp"
 
-#include <boost/variant.hpp>
+namespace JSON {
 
-#include <iostream>
-#include <vector>
-#include <string>
-#include <unordered_map>
-
-namespace JSON
-{
-
-struct String;
-struct Number;
-struct Object;
-struct Array;
-struct True;
-struct False;
-struct Null;
-
-typedef boost::variant<boost::recursive_wrapper<String>,
-                       boost::recursive_wrapper<Number>,
-                       boost::recursive_wrapper<Object>,
-                       boost::recursive_wrapper<Array>,
-                       boost::recursive_wrapper<True>,
-                       boost::recursive_wrapper<False>,
-                       boost::recursive_wrapper<Null> > Value;
-
-struct String
-{
-    String() {}
-    String(const char *value) : value(value) {}
-    String(const std::string &value) : value(value) {}
-    std::string value;
-};
-
-struct Number
-{
-    Number() {}
-    Number(double value) : value(value) {}
-    double value;
-};
-
-struct Object
-{
-    std::unordered_map<std::string, Value> values;
-};
-
-struct Array
-{
-    std::vector<Value> values;
-};
-
-struct True
-{
-};
-
-struct False
-{
-};
-
-struct Null
+struct Renderer : mapbox::util::static_visitor<>
 {
-};
-
-struct Renderer : boost::static_visitor<>
-{
-    Renderer(std::ostream &_out) : out(_out) {}
+    explicit Renderer(std::ostream &_out) : out(_out) {}
 
     void operator()(const String &string) const { out << "\"" << string.value << "\""; }
 
@@ -114,7 +55,7 @@ struct Renderer : boost::static_visitor<>
         while (iterator != object.values.end())
         {
             out << "\"" << (*iterator).first << "\":";
-            boost::apply_visitor(Renderer(out), (*iterator).second);
+            mapbox::util::apply_visitor(Renderer(out), (*iterator).second);
             if (++iterator != object.values.end())
             {
                 out << ",";
@@ -130,7 +71,7 @@ struct Renderer : boost::static_visitor<>
         iterator = array.values.begin();
         while (iterator != array.values.end())
         {
-            boost::apply_visitor(Renderer(out), *iterator);
+            mapbox::util::apply_visitor(Renderer(out), *iterator);
             if (++iterator != array.values.end())
             {
                 out << ",";
@@ -149,11 +90,12 @@ struct Renderer : boost::static_visitor<>
     std::ostream &out;
 };
 
-struct ArrayRenderer : boost::static_visitor<>
+struct ArrayRenderer : mapbox::util::static_visitor<>
 {
-    ArrayRenderer(std::vector<char> &_out) : out(_out) {}
+    explicit ArrayRenderer(std::vector<char> &_out) : out(_out) {}
 
-    void operator()(const String &string) const {
+    void operator()(const String &string) const
+    {
         out.push_back('\"');
         out.insert(out.end(), string.value.begin(), string.value.end());
         out.push_back('\"');
@@ -161,7 +103,7 @@ struct ArrayRenderer : boost::static_visitor<>
 
     void operator()(const Number &number) const
     {
-        const std::string number_string = FixedDoubleToString(number.value);
+        const std::string number_string = cast::double_fixed_to_string(number.value);
         out.insert(out.end(), number_string.begin(), number_string.end());
     }
 
@@ -176,7 +118,7 @@ struct ArrayRenderer : boost::static_visitor<>
             out.push_back('\"');
             out.push_back(':');
 
-            boost::apply_visitor(ArrayRenderer(out), (*iterator).second);
+            mapbox::util::apply_visitor(ArrayRenderer(out), (*iterator).second);
             if (++iterator != object.values.end())
             {
                 out.push_back(',');
@@ -192,7 +134,7 @@ struct ArrayRenderer : boost::static_visitor<>
         iterator = array.values.begin();
         while (iterator != array.values.end())
         {
-            boost::apply_visitor(ArrayRenderer(out), *iterator);
+            mapbox::util::apply_visitor(ArrayRenderer(out), *iterator);
             if (++iterator != array.values.end())
             {
                 out.push_back(',');
@@ -201,17 +143,20 @@ struct ArrayRenderer : boost::static_visitor<>
         out.push_back(']');
     }
 
-    void operator()(const True &) const {
+    void operator()(const True &) const
+    {
         const std::string temp("true");
         out.insert(out.end(), temp.begin(), temp.end());
     }
 
-    void operator()(const False &) const {
+    void operator()(const False &) const
+    {
         const std::string temp("false");
         out.insert(out.end(), temp.begin(), temp.end());
     }
 
-    void operator()(const Null &) const {
+    void operator()(const Null &) const
+    {
         const std::string temp("null");
         out.insert(out.end(), temp.begin(), temp.end());
     }
@@ -223,15 +168,15 @@ struct ArrayRenderer : boost::static_visitor<>
 inline void render(std::ostream &out, const Object &object)
 {
     Value value = object;
-    boost::apply_visitor(Renderer(out), value);
+    mapbox::util::apply_visitor(Renderer(out), value);
 }
 
 inline void render(std::vector<char> &out, const Object &object)
 {
     Value value = object;
-    boost::apply_visitor(ArrayRenderer(out), value);
+    mapbox::util::apply_visitor(ArrayRenderer(out), value);
 }
 
 } // namespace JSON
 
-#endif // JSON_CONTAINER_H
+#endif // JSON_RENDERER_HPP
diff --git a/Util/LuaUtil.h b/Util/lua_util.hpp
similarity index 95%
rename from Util/LuaUtil.h
rename to Util/lua_util.hpp
index 5c502c9..f367949 100644
--- a/Util/LuaUtil.h
+++ b/Util/lua_util.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef LUA_UTIL_H
-#define LUA_UTIL_H
+#ifndef LUA_UTIL_HPP
+#define LUA_UTIL_HPP
 
 extern "C" {
 #include <lua.h>
@@ -63,4 +63,4 @@ inline void luaAddScriptFolderToLoadPath(lua_State *lua_state, const char *file_
     luaL_dostring(lua_state, lua_code.c_str());
 }
 
-#endif // LUA_UTIL_H
+#endif // LUA_UTIL_HPP
diff --git a/Extractor/ScriptingEnvironment.h b/Util/make_unique.hpp
similarity index 64%
copy from Extractor/ScriptingEnvironment.h
copy to Util/make_unique.hpp
index 2b1fffe..07786fe 100644
--- a/Extractor/ScriptingEnvironment.h
+++ b/Util/make_unique.hpp
@@ -25,28 +25,33 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef SCRIPTINGENVIRONMENT_H_
-#define SCRIPTINGENVIRONMENT_H_
+#ifndef MAKE_UNIQUE_H_
+#define MAKE_UNIQUE_H_
 
-#include <string>
+#include <cstdlib>
 #include <memory>
-#include <tbb/enumerable_thread_specific.h>
+#include <type_traits>
 
-struct lua_State;
-
-class ScriptingEnvironment
+namespace osrm
 {
-  public:
-    ScriptingEnvironment();
-    explicit ScriptingEnvironment(const char *file_name);
+// Taken from http://msdn.microsoft.com/en-us/library/dn439780.asp
+// Note, that the snippet was broken there and needed minor massaging
 
-    lua_State *getLuaState();
+// make_unique<T>
+template <class T, class... Types> std::unique_ptr<T> make_unique(Types &&... Args)
+{
+    return (std::unique_ptr<T>(new T(std::forward<Types>(Args)...)));
+}
 
-  private:
-    void initLuaState(lua_State* lua_state);
+// make_unique<T[]>
+template <class T> std::unique_ptr<T[]> make_unique(std::size_t Size)
+{
+    return (std::unique_ptr<T>(new T[Size]()));
+}
 
-    std::string file_name;
-    tbb::enumerable_thread_specific<std::shared_ptr<lua_State>> script_contexts;
-};
+// make_unique<T[N]> disallowed
+template <class T, class... Types>
+typename std::enable_if<std::extent<T>::value != 0, void>::type make_unique(Types &&...) = delete;
+}
 
-#endif /* SCRIPTINGENVIRONMENT_H_ */
+#endif //MAKE_UNIQUE_H_
diff --git a/Include/osrm/Header.h b/Util/osrm_exception.cpp
similarity index 61%
copy from Include/osrm/Header.h
copy to Util/osrm_exception.cpp
index de0b2ab..ebdac6d 100644
--- a/Include/osrm/Header.h
+++ b/Util/osrm_exception.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,29 +25,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef HTTP_HEADER_H
-#define HTTP_HEADER_H
+#include "osrm_exception.hpp"
 
-#include <string>
-#include <algorithm>
-
-namespace http
-{
-struct Header
+namespace osrm
 {
-    Header& operator=(const Header& other) = default;
-    Header(const std::string & name, const std::string & value) : name(name), value(value) {}
-    Header(const Header && other) : name(std::move(other.name)), value(std::move(other.value)) {}
-
-    void Clear()
-    {
-        name.clear();
-        value.clear();
-    }
-
-    std::string name;
-    std::string value;
-};
+    // This function exists to 'anchor' the class, and stop the compiler from
+    // copying vtable and RTTI info into every object file that includes
+    // this header. (Caught by -Wweak-vtables under Clang.)
+
+    // More information from the LLVM Coding Standards:
+    // If a class is defined in a header file and has a vtable (either it has
+    // virtual methods or it derives from classes with virtual methods), it must
+    // always have at least one out-of-line virtual method in the class. Without
+    // this, the compiler will copy the vtable and RTTI into every .o file that
+    // #includes the header, bloating .o file sizes and increasing link times.
+    void exception::anchor() const { }
 }
-
-#endif // HTTP_HEADER_H
diff --git a/Util/OSRMException.h b/Util/osrm_exception.hpp
similarity index 67%
rename from Util/OSRMException.h
rename to Util/osrm_exception.hpp
index f4f4290..ac5044a 100644
--- a/Util/OSRMException.h
+++ b/Util/osrm_exception.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,22 +25,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef OSRM_EXCEPTION_H
-#define OSRM_EXCEPTION_H
+#ifndef OSRM_EXCEPTION_HPP
+#define OSRM_EXCEPTION_HPP
 
 #include <exception>
 #include <string>
 
-class OSRMException : public std::exception
+namespace osrm
+{
+class exception final : public std::exception
 {
   public:
-    explicit OSRMException(const char *message) : message(message) {}
-    explicit OSRMException(const std::string &message) : message(message) {}
-    virtual ~OSRMException() throw() {}
+    explicit exception(const char *message) : message(message) {}
+    explicit exception(const std::string &message) : message(message) {}
 
   private:
-    virtual const char *what() const throw() { return message.c_str(); }
+    // This function exists to 'anchor' the class, and stop the compiler from
+    // copying vtable and RTTI info into every object file that includes
+    // this header. (Caught by -Wweak-vtables under Clang.)
+    virtual void anchor() const;
+    const char *what() const noexcept { return message.c_str(); }
     const std::string message;
 };
-
-#endif /* OSRM_EXCEPTION_H */
+}
+#endif /* OSRM_EXCEPTION_HPP */
diff --git a/Util/range_algorithms.hpp b/Util/range_algorithms.hpp
new file mode 100644
index 0000000..208236e
--- /dev/null
+++ b/Util/range_algorithms.hpp
@@ -0,0 +1,42 @@
+/*
+    open source routing machine
+    Copyright (C) Dennis Luxen, others 2010
+
+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
+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 Affero General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+or see http://www.gnu.org/licenses/agpl.txt.
+ */
+
+#ifndef RANGE_ALGORITHMS_HPP
+#define RANGE_ALGORITHMS_HPP
+
+#include <algorithm>
+
+namespace osrm {
+
+template<class Container>
+auto max_element(const Container & c) -> decltype(std::max_element(c.begin(), c.end()))
+{
+    return std::max_element(c.begin(), c.end());
+}
+
+template<class Container>
+auto max_element(const Container & c) -> decltype(std::max_element(c.cbegin(), c.cend()))
+{
+    return std::max_element(c.cbegin(), c.cend());
+}
+
+}
+
+#endif // RANGE_ALGORITHMS_HPP
diff --git a/Util/simple_logger.cpp b/Util/simple_logger.cpp
new file mode 100644
index 0000000..dbbf348
--- /dev/null
+++ b/Util/simple_logger.cpp
@@ -0,0 +1,135 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "simple_logger.hpp"
+
+#include "osrm_exception.hpp"
+
+#include <boost/assert.hpp>
+
+#include <cstdio>
+
+#ifdef _MSC_VER
+#include <io.h>
+#define isatty _isatty
+#define fileno _fileno
+#else
+#include <unistd.h>
+#endif
+
+#include <ostream>
+#include <iostream>
+#include <mutex>
+
+namespace
+{
+static const char COL_RESET[] { "\x1b[0m"};
+static const char RED[] { "\x1b[31m"};
+#ifndef NDEBUG
+static const char YELLOW[] { "\x1b[33m"};
+#endif
+// static const char GREEN[] { "\x1b[32m"};
+// static const char BLUE[] { "\x1b[34m"};
+// static const char MAGENTA[] { "\x1b[35m"};
+// static const char CYAN[] { "\x1b[36m"};
+}
+
+void LogPolicy::Unmute() { m_is_mute = false; }
+
+void LogPolicy::Mute() { m_is_mute = true; }
+
+bool LogPolicy::IsMute() const { return m_is_mute; }
+
+LogPolicy &LogPolicy::GetInstance()
+{
+    static LogPolicy runningInstance;
+    return runningInstance;
+}
+
+SimpleLogger::SimpleLogger() : level(logINFO) {}
+
+std::mutex &SimpleLogger::get_mutex()
+{
+    static std::mutex mtx;
+    return mtx;
+}
+
+std::ostringstream &SimpleLogger::Write(LogLevel lvl)
+{
+    std::lock_guard<std::mutex> lock(get_mutex());
+    try
+    {
+        level = lvl;
+        os << "[";
+        switch (level)
+        {
+        case logWARNING:
+            os << "warn";
+            break;
+        case logDEBUG:
+#ifndef NDEBUG
+            os << "debug";
+#endif
+            break;
+        default: //logINFO:
+            os << "info";
+            break;
+        }
+        os << "] ";
+    }
+    catch (const std::exception &e)
+    {
+        // encapsulate in osrm::exception
+        throw osrm::exception(std::string(e.what()) + ", getting ostringstream");
+    }
+    return os;
+}
+
+SimpleLogger::~SimpleLogger()
+{
+    std::lock_guard<std::mutex> lock(get_mutex());
+    if (!LogPolicy::GetInstance().IsMute())
+    {
+        const bool is_terminal = static_cast<bool>(isatty(fileno(stdout)));
+        switch (level)
+        {
+        case logWARNING:
+            std::cerr << (is_terminal ? RED : "") << os.str() << (is_terminal ? COL_RESET : "")
+                      << std::endl;
+            break;
+        case logDEBUG:
+#ifndef NDEBUG
+            std::cout << (is_terminal ? YELLOW : "") << os.str() << (is_terminal ? COL_RESET : "")
+                      << std::endl;
+#endif
+            break;
+        default: //logINFO:
+            std::cout << os.str() << (is_terminal ? COL_RESET : "") << std::endl;
+            break;
+        }
+    }
+}
diff --git a/Server/RequestHandler.h b/Util/simple_logger.hpp
similarity index 67%
copy from Server/RequestHandler.h
copy to Util/simple_logger.hpp
index 462c34f..077fa2e 100644
--- a/Server/RequestHandler.h
+++ b/Util/simple_logger.hpp
@@ -25,35 +25,50 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef REQUEST_HANDLER_H
-#define REQUEST_HANDLER_H
+#ifndef SIMPLE_LOGGER_HPP
+#define SIMPLE_LOGGER_HPP
 
-#include <string>
+#include <atomic>
+#include <mutex>
+#include <sstream>
 
-template <typename Iterator, class HandlerT> struct APIGrammar;
-struct RouteParameters;
-class OSRM;
-
-namespace http
+enum LogLevel
 {
-class Reply;
-struct Request;
-}
+    logINFO,
+    logWARNING,
+    logDEBUG
+};
 
-class RequestHandler
+class LogPolicy
 {
-
   public:
-    typedef APIGrammar<std::string::iterator, RouteParameters> APIGrammarParser;
+    void Unmute();
+
+    void Mute();
+
+    bool IsMute() const;
+
+    static LogPolicy &GetInstance();
 
-    RequestHandler();
-    RequestHandler(const RequestHandler &) = delete;
+    LogPolicy(const LogPolicy &) = delete;
+
+  private:
+    LogPolicy() : m_is_mute(true) {}
+    std::atomic<bool> m_is_mute;
+};
+
+class SimpleLogger
+{
+  public:
+    SimpleLogger();
 
-    void handle_request(const http::Request &req, http::Reply &rep);
-    void RegisterRoutingMachine(OSRM *osrm);
+    virtual ~SimpleLogger();
+    std::mutex &get_mutex();
+    std::ostringstream &Write(LogLevel l = logINFO);
 
   private:
-    OSRM *routing_machine;
+    std::ostringstream os;
+    LogLevel level;
 };
 
-#endif // REQUEST_HANDLER_H
+#endif /* SIMPLE_LOGGER_HPP */
diff --git a/Util/StdHashExtensions.h b/Util/std_hash.hpp
similarity index 86%
rename from Util/StdHashExtensions.h
rename to Util/std_hash.hpp
index 50cd337..59c4ad9 100644
--- a/Util/StdHashExtensions.h
+++ b/Util/std_hash.hpp
@@ -25,39 +25,43 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef STD_HASH_EXTENSIONS_H
-#define STD_HASH_EXTENSIONS_H
+#ifndef STD_HASH_HPP
+#define STD_HASH_HPP
 
 #include <functional>
 
 // this is largely inspired by boost's hash combine as can be found in
 // "The C++ Standard Library" 2nd Edition. Nicolai M. Josuttis. 2012.
+
+namespace {
+
 template<typename T>
-inline void hash_combine(std::size_t &seed, const T& val)
+void hash_combine(std::size_t &seed, const T& val)
 {
     seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
 }
 
 template<typename T>
-inline void hash_val(std::size_t &seed, const T& val)
+void hash_val(std::size_t &seed, const T& val)
 {
     hash_combine(seed, val);
 }
 
 template<typename T, typename ... Types>
-inline void hash_val(std::size_t &seed, const T& val, const Types& ... args)
+void hash_val(std::size_t &seed, const T& val, const Types& ... args)
 {
     hash_combine(seed, val);
     hash_val(seed, args ...);
 }
 
 template<typename ... Types>
-inline std::size_t hash_val( const Types&... args)
+std::size_t hash_val(const Types&... args)
 {
     std::size_t seed = 0;
     hash_val(seed, args...);
     return seed;
 }
+}
 
 namespace std
 {
@@ -70,4 +74,4 @@ template <typename T1, typename T2> struct hash<std::pair<T1, T2>>
 };
 }
 
-#endif // STD_HASH_EXTENSIONS_H
+#endif // STD_HASH_HPP
diff --git a/Util/string_util.hpp b/Util/string_util.hpp
new file mode 100644
index 0000000..08af554
--- /dev/null
+++ b/Util/string_util.hpp
@@ -0,0 +1,150 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef STRING_UTIL_HPP
+#define STRING_UTIL_HPP
+
+#include <boost/algorithm/string.hpp>
+
+#include <cctype>
+
+#include <random>
+#include <string>
+#include <vector>
+
+// precision:  position after decimal point
+// length: maximum number of digits including comma and decimals
+// work with negative values to prevent overflowing when taking -value
+template <int length, int precision> static inline char *printInt(char *buffer, int value)
+{
+    bool minus = true;
+    if (value > 0)
+    {
+        minus = false;
+        value = -value;
+    }
+    buffer += length - 1;
+    for (int i = 0; i < precision; i++)
+    {
+        *buffer = '0' - (value % 10);
+        value /= 10;
+        buffer--;
+    }
+    *buffer = '.';
+    buffer--;
+    for (int i = precision + 1; i < length; i++)
+    {
+        *buffer = '0' - (value % 10);
+        value /= 10;
+        if (value == 0)
+            break;
+        buffer--;
+    }
+    if (minus)
+    {
+        buffer--;
+        *buffer = '-';
+    }
+    return buffer;
+}
+
+inline void replaceAll(std::string &s, const std::string &sub, const std::string &other)
+{
+    boost::replace_all(s, sub, other);
+}
+
+inline std::string EscapeJSONString(const std::string &input)
+{
+    std::string output;
+    output.reserve(input.size());
+    for (auto iter = input.begin(); iter != input.end(); ++iter)
+    {
+        switch (iter[0])
+        {
+        case '\\':
+            output += "\\\\";
+            break;
+        case '"':
+            output += "\\\"";
+            break;
+        case '/':
+            output += "\\/";
+            break;
+        case '\b':
+            output += "\\b";
+            break;
+        case '\f':
+            output += "\\f";
+            break;
+        case '\n':
+            output += "\\n";
+            break;
+        case '\r':
+            output += "\\r";
+            break;
+        case '\t':
+            output += "\\t";
+            break;
+        default:
+            output += *iter;
+            break;
+        }
+    }
+    return output;
+}
+
+static std::string originals[] = {"&", "\"", "<", ">", "'", "[", "]", "\\"};
+static std::string entities[] = {
+    "&", """, "<", ">", "'", "&91;", "&93;", " \"};
+
+inline std::size_t URIDecode(const std::string &input, std::string &output)
+{
+    auto src_iter = input.begin();
+    output.resize(input.size() + 1);
+    std::size_t decoded_length = 0;
+    for (decoded_length = 0; src_iter != input.end(); ++decoded_length)
+    {
+        if (src_iter[0] == '%' && src_iter[1] && src_iter[2] && isxdigit(src_iter[1]) &&
+            isxdigit(src_iter[2]))
+        {
+            std::string::value_type a = src_iter[1];
+            std::string::value_type b = src_iter[2];
+            a -= src_iter[1] < 58 ? 48 : src_iter[1] < 71 ? 55 : 87;
+            b -= src_iter[2] < 58 ? 48 : src_iter[2] < 71 ? 55 : 87;
+            output[decoded_length] = 16 * a + b;
+            src_iter += 3;
+            continue;
+        }
+        output[decoded_length] = *src_iter++;
+    }
+    output.resize(decoded_length);
+    return decoded_length;
+}
+
+inline std::size_t URIDecodeInPlace(std::string &URI) { return URIDecode(URI, URI); }
+
+#endif // STRING_UTIL_HPP
diff --git a/Util/timing_util.hpp b/Util/timing_util.hpp
new file mode 100644
index 0000000..1bbea47
--- /dev/null
+++ b/Util/timing_util.hpp
@@ -0,0 +1,80 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TIMING_UTIL_HPP
+#define TIMING_UTIL_HPP
+
+#include <atomic>
+#include <chrono>
+#include <cstdint>
+#include <mutex>
+#include <unordered_map>
+
+struct GlobalTimer
+{
+    GlobalTimer() : time(0) {}
+    std::atomic<uint64_t> time;
+};
+
+class GlobalTimerFactory
+{
+public:
+    static GlobalTimerFactory& get()
+    {
+        static GlobalTimerFactory instance;
+        return instance;
+    }
+
+    GlobalTimer& getGlobalTimer(const std::string& name)
+    {
+        std::lock_guard<std::mutex> lock(map_mutex);
+        return timer_map[name];
+    }
+
+private:
+    std::mutex map_mutex;
+    std::unordered_map<std::string, GlobalTimer> timer_map;
+};
+
+#define GLOBAL_TIMER_AQUIRE(_X) auto& _X##_global_timer = GlobalTimerFactory::get().getGlobalTimer(#_X)
+#define GLOBAL_TIMER_RESET(_X) _X##_global_timer.time = 0
+#define GLOBAL_TIMER_START(_X) TIMER_START(_X)
+#define GLOBAL_TIMER_STOP(_X) TIMER_STOP(_X); _X##_global_timer.time += TIMER_NSEC(_X)
+#define GLOBAL_TIMER_NSEC(_X) static_cast<double>(_X##_global_timer.time)
+#define GLOBAL_TIMER_USEC(_X) (_X##_global_timer.time / 1000.0)
+#define GLOBAL_TIMER_MSEC(_X) (_X##_global_timer.time / 1000.0 / 1000.0)
+#define GLOBAL_TIMER_SEC(_X) (_X##_global_timer.time  / 1000.0 / 1000.0 / 1000.0)
+
+#define TIMER_START(_X) auto _X##_start = std::chrono::steady_clock::now(), _X##_stop = _X##_start
+#define TIMER_STOP(_X) _X##_stop = std::chrono::steady_clock::now()
+#define TIMER_NSEC(_X) std::chrono::duration_cast<std::chrono::nanoseconds>(_X##_stop - _X##_start).count()
+#define TIMER_USEC(_X) std::chrono::duration_cast<std::chrono::microseconds>(_X##_stop - _X##_start).count()
+#define TIMER_MSEC(_X) (0.000001*std::chrono::duration_cast<std::chrono::nanoseconds>(_X##_stop - _X##_start).count())
+#define TIMER_SEC(_X)  (0.000001*std::chrono::duration_cast<std::chrono::microseconds>(_X##_stop - _X##_start).count())
+#define TIMER_MIN(_X) std::chrono::duration_cast<std::chrono::minutes>(_X##_stop - _X##_start).count()
+
+#endif // TIMING_UTIL_HPP
diff --git a/Util/xml_renderer.hpp b/Util/xml_renderer.hpp
new file mode 100644
index 0000000..46e0501
--- /dev/null
+++ b/Util/xml_renderer.hpp
@@ -0,0 +1,140 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef XML_RENDERER_HPP
+#define XML_RENDERER_HPP
+
+#include "../data_structures/json_container.hpp"
+#include "cast.hpp"
+
+namespace JSON {
+
+struct XMLToArrayRenderer : mapbox::util::static_visitor<>
+{
+    explicit XMLToArrayRenderer(std::vector<char> &_out) : out(_out) {}
+
+    void operator()(const String &string) const
+    {
+        out.push_back('\"');
+        out.insert(out.end(), string.value.begin(), string.value.end());
+        out.push_back('\"');
+    }
+
+    void operator()(const Number &number) const
+    {
+        const std::string number_string = cast::double_fixed_to_string(number.value);
+        out.insert(out.end(), number_string.begin(), number_string.end());
+    }
+
+    void operator()(const Object &object) const
+    {
+        auto iterator = object.values.begin();
+        while (iterator != object.values.end())
+        {
+            if (iterator->first.at(0) != '_')
+            {
+                out.push_back('<');
+                out.insert(out.end(), (*iterator).first.begin(), (*iterator).first.end());
+            }
+            else
+            {
+                out.push_back(' ');
+                out.insert(out.end(), ++(*iterator).first.begin(), (*iterator).first.end());
+                out.push_back('=');
+
+            }
+            mapbox::util::apply_visitor(XMLToArrayRenderer(out), (*iterator).second);
+            if (iterator->first.at(0) != '_')
+            {
+                out.push_back('/');
+                out.push_back('>');
+            }
+            ++iterator;
+        }
+    }
+
+    void operator()(const Array &array) const
+    {
+        std::vector<Value>::const_iterator iterator;
+        iterator = array.values.begin();
+        while (iterator != array.values.end())
+        {
+            mapbox::util::apply_visitor(XMLToArrayRenderer(out), *iterator);
+            ++iterator;
+        }
+    }
+
+    void operator()(const True &) const
+    {
+        const std::string temp("true");
+        out.insert(out.end(), temp.begin(), temp.end());
+    }
+
+    void operator()(const False &) const
+    {
+        const std::string temp("false");
+        out.insert(out.end(), temp.begin(), temp.end());
+    }
+
+    void operator()(const Null &) const
+    {
+        const std::string temp("null");
+        out.insert(out.end(), temp.begin(), temp.end());
+    }
+
+  private:
+    std::vector<char> &out;
+};
+
+template<class JSONObject>
+inline void xml_render(std::vector<char> &out, const JSONObject &object)
+{
+    Value value = object;
+    mapbox::util::apply_visitor(XMLToArrayRenderer(out), value);
+}
+
+template<class JSONObject>
+inline void gpx_render(std::vector<char> &out, const JSONObject &object)
+{
+    // add header
+
+    const std::string header {"<?xml version=\"1.0\" encoding=\"UTF-8\"?><gpx creator=\"OSRM Routing Engine\""
+     " version=\"1.1\" xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:xsi=\"http:"
+     "//www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.topogr"
+     "afix.com/GPX/1/1 gpx.xsd\"><metadata><copyright author=\"Project OSRM\"><lice"
+     "nse>Data (c) OpenStreetMap contributors (ODbL)</license></copyright></metadat"
+     "a><rte>"};
+    out.insert(out.end(), header.begin(), header.end());
+
+    xml_render(out, object);
+
+    const std::string footer {"</rte></gpx>"};
+    out.insert(out.end(), footer.begin(), footer.end());
+}
+} // namespace JSON
+
+#endif // XML_RENDERER_HPP
diff --git a/algorithms/bfs_components.hpp b/algorithms/bfs_components.hpp
new file mode 100644
index 0000000..57be635
--- /dev/null
+++ b/algorithms/bfs_components.hpp
@@ -0,0 +1,174 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef BFS_COMPONENTS_HPP_
+#define BFS_COMPONENTS_HPP_
+
+#include "../typedefs.h"
+#include "../data_structures/restriction_map.hpp"
+
+#include <queue>
+#include <unordered_set>
+
+// Explores the components of the given graph while respecting turn restrictions
+// and barriers.
+template <typename GraphT> class BFSComponentExplorer
+{
+  public:
+    BFSComponentExplorer(const GraphT &dynamic_graph,
+                         const RestrictionMap &restrictions,
+                         const std::unordered_set<NodeID> &barrier_nodes)
+        : m_graph(dynamic_graph), m_restriction_map(restrictions), m_barrier_nodes(barrier_nodes)
+    {
+        BOOST_ASSERT(m_graph.GetNumberOfNodes() > 0);
+    }
+
+    /*!
+     * Returns the size of the component that the node belongs to.
+     */
+    unsigned int GetComponentSize(const NodeID node) const
+    {
+        BOOST_ASSERT(node < m_component_index_list.size());
+
+        return m_component_index_size[m_component_index_list[node]];
+    }
+
+    unsigned int GetNumberOfComponents() { return m_component_index_size.size(); }
+
+    /*!
+     * Computes the component sizes.
+     */
+    void run()
+    {
+        std::queue<std::pair<NodeID, NodeID>> bfs_queue;
+        unsigned current_component = 0;
+
+        BOOST_ASSERT(m_component_index_list.empty());
+        BOOST_ASSERT(m_component_index_size.empty());
+
+        unsigned num_nodes = m_graph.GetNumberOfNodes();
+
+        m_component_index_list.resize(num_nodes, std::numeric_limits<unsigned>::max());
+
+        BOOST_ASSERT(num_nodes > 0);
+
+        // put unexplorered node with parent pointer into queue
+        for (NodeID node = 0; node < num_nodes; ++node)
+        {
+            if (std::numeric_limits<unsigned>::max() == m_component_index_list[node])
+            {
+                unsigned size = ExploreComponent(bfs_queue, node, current_component);
+
+                // push size into vector
+                m_component_index_size.emplace_back(size);
+                ++current_component;
+            }
+        }
+    }
+
+  private:
+    /*!
+     * Explores the current component that starts at node using BFS.
+     */
+    unsigned ExploreComponent(std::queue<std::pair<NodeID, NodeID>> &bfs_queue,
+                                     NodeID node,
+                                     unsigned current_component)
+    {
+        /*
+           Graphical representation of variables:
+
+           u           v           w
+           *---------->*---------->*
+                            e2
+        */
+
+        bfs_queue.emplace(node, node);
+        // mark node as read
+        m_component_index_list[node] = current_component;
+
+        unsigned current_component_size = 1;
+
+        while (!bfs_queue.empty())
+        {
+            // fetch element from BFS queue
+            std::pair<NodeID, NodeID> current_queue_item = bfs_queue.front();
+            bfs_queue.pop();
+
+            const NodeID v = current_queue_item.first; // current node
+            const NodeID u = current_queue_item.second; // parent
+            // increment size counter of current component
+            ++current_component_size;
+            if (m_barrier_nodes.find(v) != m_barrier_nodes.end())
+            {
+                continue;
+            }
+            const NodeID to_node_of_only_restriction =
+                m_restriction_map.CheckForEmanatingIsOnlyTurn(u, v);
+
+            for (auto e2 : m_graph.GetAdjacentEdgeRange(v))
+            {
+                const NodeID w = m_graph.GetTarget(e2);
+
+                if (to_node_of_only_restriction != std::numeric_limits<unsigned>::max() &&
+                    w != to_node_of_only_restriction)
+                {
+                    // At an only_-restriction but not at the right turn
+                    continue;
+                }
+
+                if (u != w)
+                {
+                    // only add an edge if turn is not a U-turn except
+                    // when it is at the end of a dead-end street.
+                    if (!m_restriction_map.CheckIfTurnIsRestricted(u, v, w))
+                    {
+                        // only add an edge if turn is not prohibited
+                        if (std::numeric_limits<unsigned>::max() == m_component_index_list[w])
+                        {
+                            // insert next (node, parent) only if w has
+                            // not yet been explored
+                            // mark node as read
+                            m_component_index_list[w] = current_component;
+                            bfs_queue.emplace(w, v);
+                        }
+                    }
+                }
+            }
+        }
+
+        return current_component_size;
+    }
+
+    std::vector<unsigned> m_component_index_list;
+    std::vector<NodeID> m_component_index_size;
+
+    const GraphT &m_graph;
+    const RestrictionMap &m_restriction_map;
+    const std::unordered_set<NodeID> &m_barrier_nodes;
+};
+
+#endif // BFS_COMPONENTS_HPP_
diff --git a/Algorithms/IteratorBasedCRC32.h b/algorithms/crc32_processor.hpp
similarity index 64%
rename from Algorithms/IteratorBasedCRC32.h
rename to algorithms/crc32_processor.hpp
index 84a404a..a68514d 100644
--- a/Algorithms/IteratorBasedCRC32.h
+++ b/algorithms/crc32_processor.hpp
@@ -28,44 +28,59 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ITERATOR_BASED_CRC32_H
 #define ITERATOR_BASED_CRC32_H
 
-#include "../Util/SimpleLogger.h"
-
-#include <iostream>
-
 #if defined(__x86_64__) && !defined(__MINGW64__)
 #include <cpuid.h>
-#else
+#endif
+
 #include <boost/crc.hpp> // for boost::crc_32_type
 
-inline void __get_cpuid(int param, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx)
-{
-    *ecx = 0;
-}
-#endif
+#include <iterator>
 
-template <class ContainerT> class IteratorbasedCRC32
+class IteratorbasedCRC32
 {
-  private:
-    typedef typename ContainerT::iterator IteratorType;
-    unsigned crc;
+  public:
+    bool using_hardware() const { return use_hardware_implementation; }
 
-    bool use_SSE42_CRC_function;
+    IteratorbasedCRC32() : crc(0) { use_hardware_implementation = detect_hardware_support(); }
 
-#if !defined(__x86_64__)
-    boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> CRC32_processor;
-#endif
-    unsigned SoftwareBasedCRC32(char *str, unsigned len)
+    template <class Iterator> unsigned operator()(Iterator iter, const Iterator end)
     {
-#if !defined(__x86_64__)
-        CRC32_processor.process_bytes(str, len);
-        return CRC32_processor.checksum();
-#else
-        return 0;
-#endif
+        unsigned crc = 0;
+        while (iter != end)
+        {
+            using value_type = typename std::iterator_traits<Iterator>::value_type;
+            char *data = (char *)(&(*iter));
+
+            if (use_hardware_implementation)
+            {
+                crc = compute_in_hardware(data, sizeof(value_type));
+            }
+            else
+            {
+                crc = compute_in_software(data, sizeof(value_type));
+            }
+            ++iter;
+        }
+        return crc;
+    }
+
+  private:
+    bool detect_hardware_support() const
+    {
+        static const int sse42_bit = 0x00100000;
+        const unsigned ecx = cpuid();
+        const bool sse42_found = (ecx & sse42_bit) != 0;
+        return sse42_found;
+    }
+
+    unsigned compute_in_software(char *str, unsigned len)
+    {
+        crc_processor.process_bytes(str, len);
+        return crc_processor.checksum();
     }
 
     // adapted from http://byteworm.com/2010/10/13/crc32/
-    unsigned SSE42BasedCRC32(char *str, unsigned len)
+    unsigned compute_in_hardware(char *str, unsigned len)
     {
 #if defined(__x86_64__)
         unsigned q = len / sizeof(unsigned);
@@ -101,44 +116,31 @@ template <class ContainerT> class IteratorbasedCRC32
         return ecx;
     }
 
-    bool DetectNativeCRC32Support()
+#if defined(__MINGW64__) || defined(_MSC_VER)
+    inline void
+    __get_cpuid(int param, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx) const
     {
-        static const int SSE42_BIT = 0x00100000;
-        const unsigned ecx = cpuid();
-        const bool has_SSE42 = (ecx & SSE42_BIT) != 0;
-        if (has_SSE42)
-        {
-            SimpleLogger().Write() << "using hardware based CRC32 computation";
-        }
-        else
-        {
-            SimpleLogger().Write() << "using software based CRC32 computation";
-        }
-        return has_SSE42;
+        *ecx = 0;
     }
+#endif
 
-  public:
-    IteratorbasedCRC32() : crc(0) { use_SSE42_CRC_function = DetectNativeCRC32Support(); }
+    boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> crc_processor;
+    unsigned crc;
+    bool use_hardware_implementation;
+};
 
-    unsigned operator()(IteratorType iter, const IteratorType end)
+struct RangebasedCRC32
+{
+    template<typename Iteratable>
+    unsigned operator()(const Iteratable &iterable)
     {
-        unsigned crc = 0;
-        while (iter != end)
-        {
-            char *data = reinterpret_cast<char *>(&(*iter));
-
-            if (use_SSE42_CRC_function)
-            {
-                crc = SSE42BasedCRC32(data, sizeof(typename ContainerT::value_type));
-            }
-            else
-            {
-                crc = SoftwareBasedCRC32(data, sizeof(typename ContainerT::value_type));
-            }
-            ++iter;
-        }
-        return crc;
+        return crc32(std::begin(iterable), std::end(iterable));
     }
+
+    bool using_hardware() const { return crc32.using_hardware(); }
+
+  private:
+    IteratorbasedCRC32 crc32;
 };
 
 #endif /* ITERATOR_BASED_CRC32_H */
diff --git a/Algorithms/DouglasPeucker.cpp b/algorithms/douglas_peucker.cpp
similarity index 60%
rename from Algorithms/DouglasPeucker.cpp
rename to algorithms/douglas_peucker.cpp
index 2e647fc..362f0a5 100644
--- a/Algorithms/DouglasPeucker.cpp
+++ b/algorithms/douglas_peucker.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,11 +25,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include <osrm/Coordinate.h>
+#include "douglas_peucker.hpp"
+
+#include "../data_structures/segment_information.hpp"
+#include "../Util/integer_range.hpp"
 
-#include "DouglasPeucker.h"
-#include "../DataStructures/SegmentInformation.h"
-#include "../Util/SimpleLogger.h"
+#include <osrm/Coordinate.h>
 
 #include <boost/assert.hpp>
 
@@ -37,6 +38,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <algorithm>
 
+namespace
+{
 struct CoordinatePairCalculator
 {
     CoordinatePairCalculator() = delete;
@@ -78,62 +81,42 @@ struct CoordinatePairCalculator
     float second_lat;
     float second_lon;
 };
-
-DouglasPeucker::DouglasPeucker()
-    : douglas_peucker_thresholds({512440, // z0
-                                  256720, // z1
-                                  122560, // z2
-                                  56780,  // z3
-                                  28800,  // z4
-                                  14400,  // z5
-                                  7200,   // z6
-                                  3200,   // z7
-                                  2400,   // z8
-                                  1000,   // z9
-                                  600,    // z10
-                                  120,    // z11
-                                  60,     // z12
-                                  45,     // z13
-                                  36,     // z14
-                                  20,     // z15
-                                  8,      // z16
-                                  6,      // z17
-                                  4       // z18
-      })
-{
 }
 
 void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level)
 {
-    // check if input data is invalid
-    BOOST_ASSERT_MSG(!input_geometry.empty(), "geometry invalid");
+    Run(std::begin(input_geometry), std::end(input_geometry), zoom_level);
+}
 
-    if (input_geometry.size() < 2)
+void DouglasPeucker::Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level)
+{
+    unsigned size = std::distance(begin, end);
+    if (size < 2)
     {
         return;
     }
 
-    input_geometry.front().necessary = true;
-    input_geometry.back().necessary = true;
+    begin->necessary = true;
+    std::prev(end)->necessary = true;
 
     {
-        BOOST_ASSERT_MSG(zoom_level < 19, "unsupported zoom level");
-        unsigned left_border = 0;
-        unsigned right_border = 1;
+        BOOST_ASSERT_MSG(zoom_level < DOUGLAS_PEUCKER_THRESHOLDS.size(), "unsupported zoom level");
+        RandomAccessIt left_border = begin;
+        RandomAccessIt right_border = std::next(begin);
         // Sweep over array and identify those ranges that need to be checked
         do
         {
             // traverse list until new border element found
-            if (input_geometry[right_border].necessary)
+            if (right_border->necessary)
             {
                 // sanity checks
-                BOOST_ASSERT(input_geometry[left_border].necessary);
-                BOOST_ASSERT(input_geometry[right_border].necessary);
+                BOOST_ASSERT(left_border->necessary);
+                BOOST_ASSERT(right_border->necessary);
                 recursion_stack.emplace(left_border, right_border);
                 left_border = right_border;
             }
             ++right_border;
-        } while (right_border < input_geometry.size());
+        } while (right_border != end);
     }
 
     // mark locations as 'necessary' by divide-and-conquer
@@ -143,40 +126,40 @@ void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const
         const GeometryRange pair = recursion_stack.top();
         recursion_stack.pop();
         // sanity checks
-        BOOST_ASSERT_MSG(input_geometry[pair.first].necessary, "left border mus be necessary");
-        BOOST_ASSERT_MSG(input_geometry[pair.second].necessary, "right border must be necessary");
-        BOOST_ASSERT_MSG(pair.second < input_geometry.size(), "right border outside of geometry");
-        BOOST_ASSERT_MSG(pair.first < pair.second, "left border on the wrong side");
+        BOOST_ASSERT_MSG(pair.first->necessary, "left border must be necessary");
+        BOOST_ASSERT_MSG(pair.second->necessary, "right border must be necessary");
+        BOOST_ASSERT_MSG(std::distance(pair.second, end) > 0, "right border outside of geometry");
+        BOOST_ASSERT_MSG(std::distance(pair.first, pair.second) >= 0,
+                         "left border on the wrong side");
 
         int max_int_distance = 0;
-        unsigned farthest_entry_index = pair.second;
-        const CoordinatePairCalculator DistCalc(input_geometry[pair.first].location,
-                                                input_geometry[pair.second].location);
+        auto farthest_entry_it = pair.second;
+        const CoordinatePairCalculator dist_calc(pair.first->location, pair.second->location);
 
         // sweep over range to find the maximum
-        for (unsigned i = pair.first + 1; i < pair.second; ++i)
+        for (auto it = std::next(pair.first); it != pair.second; ++it)
         {
-            const int distance = DistCalc(input_geometry[i].location);
+            const int distance = dist_calc(it->location);
             // found new feasible maximum?
-            if (distance > max_int_distance && distance > douglas_peucker_thresholds[zoom_level])
+            if (distance > max_int_distance && distance > DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
             {
-                farthest_entry_index = i;
+                farthest_entry_it = it;
                 max_int_distance = distance;
             }
         }
 
         // check if maximum violates a zoom level dependent threshold
-        if (max_int_distance > douglas_peucker_thresholds[zoom_level])
+        if (max_int_distance > DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
         {
             //  mark idx as necessary
-            input_geometry[farthest_entry_index].necessary = true;
-            if (1 < (farthest_entry_index - pair.first))
+            farthest_entry_it->necessary = true;
+            if (1 < std::distance(pair.first, farthest_entry_it))
             {
-                recursion_stack.emplace(pair.first, farthest_entry_index);
+                recursion_stack.emplace(pair.first, farthest_entry_it);
             }
-            if (1 < (pair.second - farthest_entry_index))
+            if (1 < std::distance(farthest_entry_it, pair.second))
             {
-                recursion_stack.emplace(farthest_entry_index, pair.second);
+                recursion_stack.emplace(farthest_entry_it, pair.second);
             }
         }
     }
diff --git a/Algorithms/DouglasPeucker.h b/algorithms/douglas_peucker.hpp
similarity index 71%
rename from Algorithms/DouglasPeucker.h
rename to algorithms/douglas_peucker.hpp
index d0f295c..417e80a 100644
--- a/Algorithms/DouglasPeucker.h
+++ b/algorithms/douglas_peucker.hpp
@@ -25,12 +25,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef DOUGLASPEUCKER_H_
-#define DOUGLASPEUCKER_H_
+#ifndef DOUGLAS_PEUCKER_HPP_
+#define DOUGLAS_PEUCKER_HPP_
 
 #include <stack>
-#include <utility>
 #include <vector>
+#include <array>
 
 /* This class object computes the bitvector of indicating generalized input
  * points according to the (Ramer-)Douglas-Peucker algorithm.
@@ -41,18 +41,40 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct SegmentInformation;
 
+static const std::array<int, 19> DOUGLAS_PEUCKER_THRESHOLDS {{
+    512440, // z0
+    256720, // z1
+    122560, // z2
+    56780,  // z3
+    28800,  // z4
+    14400,  // z5
+    7200,   // z6
+    3200,   // z7
+    2400,   // z8
+    1000,   // z9
+    600,    // z10
+    120,    // z11
+    60,     // z12
+    45,     // z13
+    36,     // z14
+    20,     // z15
+    8,      // z16
+    6,      // z17
+    4       // z18
+}};
+
 class DouglasPeucker
 {
-  private:
-    std::vector<int> douglas_peucker_thresholds;
+  public:
+    using RandomAccessIt = std::vector<SegmentInformation>::iterator;
 
-    typedef std::pair<unsigned, unsigned> GeometryRange;
+    using GeometryRange = std::pair<RandomAccessIt, RandomAccessIt>;
     // Stack to simulate the recursion
     std::stack<GeometryRange> recursion_stack;
 
   public:
-    DouglasPeucker();
+    void Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level);
     void Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level);
 };
 
-#endif /* DOUGLASPEUCKER_H_ */
+#endif /* DOUGLAS_PEUCKER_HPP_ */
diff --git a/algorithms/object_encoder.hpp b/algorithms/object_encoder.hpp
new file mode 100644
index 0000000..af6e0d9
--- /dev/null
+++ b/algorithms/object_encoder.hpp
@@ -0,0 +1,94 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef OBJECT_ENCODER_HPP
+#define OBJECT_ENCODER_HPP
+
+#include "../Util/string_util.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/archive/iterators/base64_from_binary.hpp>
+#include <boost/archive/iterators/binary_from_base64.hpp>
+#include <boost/archive/iterators/transform_width.hpp>
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+struct ObjectEncoder
+{
+    using base64_t = boost::archive::iterators::base64_from_binary<
+        boost::archive::iterators::transform_width<const char *, 6, 8>>;
+
+    using binary_t = boost::archive::iterators::transform_width<
+        boost::archive::iterators::binary_from_base64<std::string::const_iterator>,
+        8,
+        6>;
+
+    template <class ObjectT>
+    static void EncodeToBase64(const ObjectT &object, std::string &encoded)
+    {
+        const char *char_ptr_to_object = (const char *)&object;
+        std::vector<unsigned char> data(sizeof(object));
+        std::copy(char_ptr_to_object, char_ptr_to_object + sizeof(ObjectT), data.begin());
+
+        unsigned char number_of_padded_chars = 0; // is in {0,1,2};
+        while (data.size() % 3 != 0)
+        {
+            ++number_of_padded_chars;
+            data.push_back(0x00);
+        }
+
+        BOOST_ASSERT_MSG(0 == data.size() % 3, "base64 input data size is not a multiple of 3!");
+        encoded.resize(sizeof(ObjectT));
+        encoded.assign(base64_t(&data[0]),
+                       base64_t(&data[0] + (data.size() - number_of_padded_chars)));
+        replaceAll(encoded, "+", "-");
+        replaceAll(encoded, "/", "_");
+    }
+
+    template <class ObjectT>
+    static void DecodeFromBase64(const std::string &input, ObjectT &object)
+    {
+        try
+        {
+            std::string encoded(input);
+            // replace "-" with "+" and "_" with "/"
+            replaceAll(encoded, "-", "+");
+            replaceAll(encoded, "_", "/");
+
+            std::copy(binary_t(encoded.begin()),
+                      binary_t(encoded.begin() + encoded.length() - 1),
+                      (char *)&object);
+        }
+        catch (...)
+        {
+        }
+    }
+};
+
+#endif /* OBJECT_ENCODER_HPP */
diff --git a/Algorithms/PolylineCompressor.cpp b/algorithms/polyline_compressor.cpp
similarity index 51%
rename from Algorithms/PolylineCompressor.cpp
rename to algorithms/polyline_compressor.cpp
index a34f8c7..2f2972b 100644
--- a/Algorithms/PolylineCompressor.cpp
+++ b/algorithms/polyline_compressor.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,16 +25,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "PolylineCompressor.h"
-#include "../DataStructures/SegmentInformation.h"
+#include "polyline_compressor.hpp"
+#include "../data_structures/segment_information.hpp"
 
 #include <osrm/Coordinate.h>
 
-void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output)
-    const
+std::string PolylineCompressor::encode_vector(std::vector<int> &numbers) const
 {
-    const unsigned end = static_cast<unsigned>(numbers.size());
-    for (unsigned i = 0; i < end; ++i)
+    std::string output;
+    const auto end = numbers.size();
+    for (std::size_t i = 0; i < end; ++i)
     {
         numbers[i] <<= 1;
         if (numbers[i] < 0)
@@ -44,12 +44,14 @@ void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers, std
     }
     for (const int number : numbers)
     {
-        encodeNumber(number, output);
+        output += encode_number(number);
     }
+    return output;
 }
 
-void PolylineCompressor::encodeNumber(int number_to_encode, std::string &output) const
+std::string PolylineCompressor::encode_number(int number_to_encode) const
 {
+    std::string output;
     while (number_to_encode >= 0x20)
     {
         const int next_value = (0x20 | (number_to_encode & 0x1f)) + 63;
@@ -67,52 +69,30 @@ void PolylineCompressor::encodeNumber(int number_to_encode, std::string &output)
     {
         output += static_cast<char>(number_to_encode);
     }
+    return output;
 }
 
-JSON::String PolylineCompressor::printEncodedString(const std::vector<SegmentInformation> &polyline)
-    const
+std::string
+PolylineCompressor::get_encoded_string(const std::vector<SegmentInformation> &polyline) const
 {
-    std::string output;
-    std::vector<int> delta_numbers;
-    if (!polyline.empty())
+    if (polyline.empty())
     {
-        FixedPointCoordinate last_coordinate = polyline[0].location;
-        delta_numbers.emplace_back(last_coordinate.lat);
-        delta_numbers.emplace_back(last_coordinate.lon);
-        // iterate after skipping the first, already handled, segment
-        for (auto it = ++polyline.cbegin(); it != polyline.cend(); ++it)
-        {
-            const auto &segment = *it;
-            if (segment.necessary)
-            {
-                int lat_diff = segment.location.lat - last_coordinate.lat;
-                int lon_diff = segment.location.lon - last_coordinate.lon;
-                delta_numbers.emplace_back(lat_diff);
-                delta_numbers.emplace_back(lon_diff);
-                last_coordinate = segment.location;
-            }
-        }
-        encodeVectorSignedNumber(delta_numbers, output);
+        return {};
     }
-    JSON::String return_value(output);
-    return return_value;
-}
 
-JSON::Array
-PolylineCompressor::printUnencodedString(const std::vector<SegmentInformation> &polyline) const
-{
-    JSON::Array json_geometry_array;
+    std::vector<int> delta_numbers;
+    delta_numbers.reserve((polyline.size() - 1) * 2);
+    FixedPointCoordinate previous_coordinate = {0, 0};
     for (const auto &segment : polyline)
     {
         if (segment.necessary)
         {
-            std::string tmp, output;
-            FixedPointCoordinate::convertInternalLatLonToString(segment.location.lat, tmp);
-            output += (tmp + ",");
-            FixedPointCoordinate::convertInternalLatLonToString(segment.location.lon, tmp);
-            output += tmp;
-            json_geometry_array.values.push_back(output);
+            const int lat_diff = segment.location.lat - previous_coordinate.lat;
+            const int lon_diff = segment.location.lon - previous_coordinate.lon;
+            delta_numbers.emplace_back(lat_diff);
+            delta_numbers.emplace_back(lon_diff);
+            previous_coordinate = segment.location;
         }
     }
-    return json_geometry_array;
+    return encode_vector(delta_numbers);
 }
diff --git a/Algorithms/PolylineCompressor.h b/algorithms/polyline_compressor.hpp
similarity index 79%
copy from Algorithms/PolylineCompressor.h
copy to algorithms/polyline_compressor.hpp
index 5472bd8..8bff4a0 100644
--- a/Algorithms/PolylineCompressor.h
+++ b/algorithms/polyline_compressor.hpp
@@ -30,22 +30,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct SegmentInformation;
 
-#include "../DataStructures/JSONContainer.h"
-
 #include <string>
 #include <vector>
 
 class PolylineCompressor
 {
   private:
-    void encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output) const;
+    std::string encode_vector(std::vector<int> &numbers) const;
 
-    void encodeNumber(int number_to_encode, std::string &output) const;
+    std::string encode_number(const int number_to_encode) const;
 
   public:
-    JSON::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
-
-    JSON::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
+    std::string get_encoded_string(const std::vector<SegmentInformation> &polyline) const;
 };
 
 #endif /* POLYLINECOMPRESSOR_H_ */
diff --git a/DataStructures/ImportNode.cpp b/algorithms/polyline_formatter.cpp
similarity index 59%
copy from DataStructures/ImportNode.cpp
copy to algorithms/polyline_formatter.cpp
index 8975d40..d72496a 100644
--- a/DataStructures/ImportNode.cpp
+++ b/algorithms/polyline_formatter.cpp
@@ -25,40 +25,32 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "ImportNode.h"
+#include "polyline_formatter.hpp"
 
-#include <limits>
+#include "polyline_compressor.hpp"
+#include "../data_structures/segment_information.hpp"
 
-ExternalMemoryNode::ExternalMemoryNode(
-    int lat, int lon, unsigned int node_id, bool bollard, bool traffic_light)
-    : NodeInfo(lat, lon, node_id), bollard(bollard), trafficLight(traffic_light)
-{
-}
-
-ExternalMemoryNode::ExternalMemoryNode() : bollard(false), trafficLight(false)
-{
-}
-
-ExternalMemoryNode ExternalMemoryNode::min_value()
-{
-    return ExternalMemoryNode(0, 0, 0, false, false);
-}
+#include <osrm/Coordinate.h>
 
-ExternalMemoryNode ExternalMemoryNode::max_value()
+JSON::String
+PolylineFormatter::printEncodedString(const std::vector<SegmentInformation> &polyline) const
 {
-    return ExternalMemoryNode(std::numeric_limits<int>::max(),
-                              std::numeric_limits<int>::max(),
-                              std::numeric_limits<unsigned>::max(),
-                              false,
-                              false);
+    return JSON::String(PolylineCompressor().get_encoded_string(polyline));
 }
 
-void ImportNode::Clear()
+JSON::Array
+PolylineFormatter::printUnencodedString(const std::vector<SegmentInformation> &polyline) const
 {
-    keyVals.Clear();
-    lat = 0;
-    lon = 0;
-    node_id = 0;
-    bollard = false;
-    trafficLight = false;
+    JSON::Array json_geometry_array;
+    for (const auto &segment : polyline)
+    {
+        if (segment.necessary)
+        {
+            JSON::Array json_coordinate;
+            json_coordinate.values.push_back(segment.location.lat / COORDINATE_PRECISION);
+            json_coordinate.values.push_back(segment.location.lon / COORDINATE_PRECISION);
+            json_geometry_array.values.push_back(json_coordinate);
+        }
+    }
+    return json_geometry_array;
 }
diff --git a/Algorithms/PolylineCompressor.h b/algorithms/polyline_formatter.hpp
similarity index 78%
copy from Algorithms/PolylineCompressor.h
copy to algorithms/polyline_formatter.hpp
index 5472bd8..1d4744d 100644
--- a/Algorithms/PolylineCompressor.h
+++ b/algorithms/polyline_formatter.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,27 +25,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef POLYLINECOMPRESSOR_H_
-#define POLYLINECOMPRESSOR_H_
+#ifndef POLYLINE_FORMATTER_HPP
+#define POLYLINE_FORMATTER_HPP
 
 struct SegmentInformation;
 
-#include "../DataStructures/JSONContainer.h"
+#include "../data_structures/json_container.hpp"
 
 #include <string>
 #include <vector>
 
-class PolylineCompressor
+struct PolylineFormatter
 {
-  private:
-    void encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output) const;
-
-    void encodeNumber(int number_to_encode, std::string &output) const;
-
-  public:
     JSON::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
 
     JSON::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
 };
 
-#endif /* POLYLINECOMPRESSOR_H_ */
+#endif /* POLYLINE_FORMATTER_HPP */
diff --git a/Algorithms/ExtractRouteNames.h b/algorithms/route_name_extraction.hpp
similarity index 98%
rename from Algorithms/ExtractRouteNames.h
rename to algorithms/route_name_extraction.hpp
index 5c1b860..519452f 100644
--- a/Algorithms/ExtractRouteNames.h
+++ b/algorithms/route_name_extraction.hpp
@@ -54,7 +54,7 @@ template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
 
         for (const SegmentT &segment : segment_list)
         {
-            if (segment.name_id != blocked_name_id && segment.length > result_segment.length)
+            if (segment.name_id != blocked_name_id && segment.length > result_segment.length && segment.name_id != 0)
             {
                 result_segment = segment;
             }
@@ -111,7 +111,7 @@ template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
                   shortest_path_set_difference.end(),
                   length_comperator);
         shortest_segment_2 =
-            PickNextLongestSegment(shortest_path_set_difference, shortest_path_segments[0].name_id);
+            PickNextLongestSegment(shortest_path_set_difference, shortest_segment_1.name_id);
 
         // compute the set difference (for alternative path) depending on names between shortest and
         // alternative
@@ -138,7 +138,7 @@ template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
         if (!alternative_path_segments.empty())
         {
             alternative_segment_2 = PickNextLongestSegment(alternative_path_set_difference,
-                                                       alternative_path_segments[0].name_id);
+                                                       alternative_segment_1.name_id);
         }
 
         // move the segments into the order in which they occur.
diff --git a/algorithms/tiny_components.hpp b/algorithms/tiny_components.hpp
new file mode 100644
index 0000000..5cf5a75
--- /dev/null
+++ b/algorithms/tiny_components.hpp
@@ -0,0 +1,253 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TINY_COMPONENTS_HPP
+#define TINY_COMPONENTS_HPP
+
+#include "../typedefs.h"
+#include "../data_structures/deallocating_vector.hpp"
+#include "../data_structures/import_edge.hpp"
+#include "../data_structures/query_node.hpp"
+#include "../data_structures/percent.hpp"
+#include "../data_structures/restriction.hpp"
+#include "../data_structures/restriction_map.hpp"
+#include "../data_structures/turn_instructions.hpp"
+
+#include "../Util/integer_range.hpp"
+#include "../Util/simple_logger.hpp"
+#include "../Util/std_hash.hpp"
+#include "../Util/timing_util.hpp"
+
+#include <osrm/Coordinate.h>
+
+#include <boost/assert.hpp>
+
+#include <tbb/parallel_sort.h>
+
+
+#include <cstdint>
+
+#include <memory>
+#include <stack>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+template <typename GraphT>
+class TarjanSCC
+{
+    struct TarjanStackFrame
+    {
+        explicit TarjanStackFrame(NodeID v, NodeID parent) : v(v), parent(parent) {}
+        NodeID v;
+        NodeID parent;
+    };
+
+    struct TarjanNode
+    {
+        TarjanNode() : index(SPECIAL_NODEID), low_link(SPECIAL_NODEID), on_stack(false) {}
+        unsigned index;
+        unsigned low_link;
+        bool on_stack;
+    };
+
+    std::vector<unsigned> components_index;
+    std::vector<NodeID> component_size_vector;
+    std::shared_ptr<GraphT> m_node_based_graph;
+    std::unordered_set<NodeID> barrier_node_set;
+    RestrictionMap m_restriction_map;
+    unsigned size_one_counter;
+
+  public:
+    template<class ContainerT>
+    TarjanSCC(std::shared_ptr<GraphT> graph,
+              const RestrictionMap &restrictions,
+              const ContainerT &barrier_node_list)
+        : components_index(graph->GetNumberOfNodes(), SPECIAL_NODEID),
+          m_node_based_graph(graph), m_restriction_map(restrictions),
+          size_one_counter(0)
+    {
+        barrier_node_set.insert(std::begin(barrier_node_list), std::end(barrier_node_list));
+        BOOST_ASSERT(m_node_based_graph->GetNumberOfNodes() > 0);
+    }
+
+    void run()
+    {
+        TIMER_START(SCC_RUN);
+        // The following is a hack to distinguish between stuff that happens
+        // before the recursive call and stuff that happens after
+        std::stack<TarjanStackFrame> recursion_stack;
+        // true = stuff before, false = stuff after call
+        std::stack<NodeID> tarjan_stack;
+        std::vector<TarjanNode> tarjan_node_list(m_node_based_graph->GetNumberOfNodes());
+        unsigned component_index = 0, size_of_current_component = 0;
+        int index = 0;
+        const NodeID last_node = m_node_based_graph->GetNumberOfNodes();
+        std::vector<bool> processing_node_before_recursion(m_node_based_graph->GetNumberOfNodes(), true);
+        for(const NodeID node : osrm::irange(0u, last_node))
+        {
+            if (SPECIAL_NODEID == components_index[node])
+            {
+                recursion_stack.emplace(TarjanStackFrame(node, node));
+            }
+
+            while (!recursion_stack.empty())
+            {
+                TarjanStackFrame currentFrame = recursion_stack.top();
+                const NodeID u = currentFrame.parent;
+                const NodeID v = currentFrame.v;
+                recursion_stack.pop();
+
+                const bool before_recursion = processing_node_before_recursion[v];
+
+                if (before_recursion && tarjan_node_list[v].index != UINT_MAX)
+                {
+                    continue;
+                }
+
+                if (before_recursion)
+                {
+                    // Mark frame to handle tail of recursion
+                    recursion_stack.emplace(currentFrame);
+                    processing_node_before_recursion[v] = false;
+
+                    // Mark essential information for SCC
+                    tarjan_node_list[v].index = index;
+                    tarjan_node_list[v].low_link = index;
+                    tarjan_stack.push(v);
+                    tarjan_node_list[v].on_stack = true;
+                    ++index;
+
+                    const NodeID to_node_of_only_restriction =
+                        m_restriction_map.CheckForEmanatingIsOnlyTurn(u, v);
+
+                    for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(v))
+                    {
+                        const auto vprime = m_node_based_graph->GetTarget(current_edge);
+
+                        // Traverse outgoing edges
+                        if (barrier_node_set.find(v) != barrier_node_set.end() &&
+                            u != vprime)
+                        {
+                            // continue;
+                        }
+
+
+                        if (to_node_of_only_restriction != std::numeric_limits<unsigned>::max() &&
+                            vprime == to_node_of_only_restriction)
+                        {
+                            // At an only_-restriction but not at the right turn
+                            // continue;
+                        }
+
+                        if (m_restriction_map.CheckIfTurnIsRestricted(u, v, vprime))
+                        {
+                            // continue;
+                        }
+
+                        if (SPECIAL_NODEID == tarjan_node_list[vprime].index)
+                        {
+                            recursion_stack.emplace(TarjanStackFrame(vprime, v));
+                        }
+                        else
+                        {
+                            if (tarjan_node_list[vprime].on_stack &&
+                                tarjan_node_list[vprime].index < tarjan_node_list[v].low_link)
+                            {
+                                tarjan_node_list[v].low_link = tarjan_node_list[vprime].index;
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    processing_node_before_recursion[v] = true;
+                    tarjan_node_list[currentFrame.parent].low_link =
+                        std::min(tarjan_node_list[currentFrame.parent].low_link,
+                                 tarjan_node_list[v].low_link);
+                    // after recursion, lets do cycle checking
+                    // Check if we found a cycle. This is the bottom part of the recursion
+                    if (tarjan_node_list[v].low_link == tarjan_node_list[v].index)
+                    {
+                        NodeID vprime;
+                        do
+                        {
+                            vprime = tarjan_stack.top();
+                            tarjan_stack.pop();
+                            tarjan_node_list[vprime].on_stack = false;
+                            components_index[vprime] = component_index;
+                            ++size_of_current_component;
+                        } while (v != vprime);
+
+                        component_size_vector.emplace_back(size_of_current_component);
+
+                        if (size_of_current_component > 1000)
+                        {
+                            SimpleLogger().Write() << "large component [" << component_index
+                                                   << "]=" << size_of_current_component;
+                        }
+
+                        ++component_index;
+                        size_of_current_component = 0;
+                    }
+                }
+            }
+        }
+
+        TIMER_STOP(SCC_RUN);
+        SimpleLogger().Write() << "SCC run took: " << TIMER_MSEC(SCC_RUN)/1000. << "s";
+
+        size_one_counter = std::count_if(component_size_vector.begin(),
+                                         component_size_vector.end(),
+                                         [](unsigned value)
+                                         {
+            return 1 == value;
+        });
+    }
+
+    std::size_t get_number_of_components() const
+    {
+        return component_size_vector.size();
+    }
+
+    unsigned get_size_one_count() const
+    {
+        return size_one_counter;
+    }
+
+    unsigned get_component_size(const NodeID node) const
+    {
+        return component_size_vector[components_index[node]];
+    }
+
+    unsigned get_component_id(const NodeID node) const
+    {
+        return components_index[node];
+    }
+};
+
+#endif /* TINY_COMPONENTS_HPP */
diff --git a/appveyor.yml b/appveyor.yml
index 7d6f835..e650e1a 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -23,6 +23,7 @@ platform: x64
 
 install:
   # by default, all script lines are interpreted as batch
+  - nuget install protobuf
   - cd c:\projects\osrm
   - curl -O http://build.project-osrm.org/libs_osrm_%Configuration%.7z
   - 7z x libs_osrm_%Configuration%.7z | find ":"
@@ -33,12 +34,22 @@ build_script:
   - cd build
   - echo Running cmake...
   - call "%VS120COMNTOOLS%\..\..\VC\vcvarsall.bat" x86_amd64
+  - SET PATH=C:\Program Files (x86)\MSBuild\12.0\bin\;%PATH%
   - SET P=c:/projects/osrm
   - set TBB_INSTALL_DIR=%P%/tbb
   - set TBB_ARCH_PLATFORM=intel64/vc12
-  - cmake .. -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=%Configuration% -DBZIP2_INCLUDE_DIR=%P%/libs/include -DBZIP2_LIBRARIES=%P%/libs/lib/libbz2.lib -DCMAKE_INSTALL_PREFIX=%P%/libs -DBOOST_ROOT=%P%/boost_min -DBoost_USE_STATIC_LIBS=ON
-  - nmake
+  - cmake .. -G "Visual Studio 12 Win64" -DCMAKE_BUILD_TYPE=%Configuration% -DCMAKE_INSTALL_PREFIX=%P%/libs -DBOOST_ROOT=%P%/boost_min -DBoost_ADDITIONAL_VERSIONS=1.57 -DBoost_USE_STATIC_LIBS=ON -T CTP_Nov2013
+  - msbuild /clp:Verbosity=minimal /nologo OSRM.sln
+  - msbuild /clp:Verbosity=minimal /nologo tests.vcxproj
+  - cd %Configuration%
   - if "%APPVEYOR_REPO_BRANCH%"=="develop" (7z a %P%/osrm_%Configuration%.zip *.exe *.pdb %P%/libs/bin/*.dll -tzip)
+  - cd ..\..\profiles
+  - echo disk=c:\temp\stxxl,10000,wincall > .stxxl.txt
+  - if "%APPVEYOR_REPO_BRANCH%"=="develop" (7z a %P%/osrm_%Configuration%.zip * -tzip)
+  - set PATH=%PATH%;c:/projects/osrm/libs/bin
+  - cd c:/projects/osrm/build/%Configuration%
+  - datastructure-tests.exe
+  - algorithm-tests.exe
 
 test: off
 
diff --git a/benchmarks/static_rtree.cpp b/benchmarks/static_rtree.cpp
new file mode 100644
index 0000000..7a24cfc
--- /dev/null
+++ b/benchmarks/static_rtree.cpp
@@ -0,0 +1,189 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "../data_structures/original_edge_data.hpp"
+#include "../data_structures/query_node.hpp"
+#include "../data_structures/shared_memory_vector_wrapper.hpp"
+#include "../data_structures/static_rtree.hpp"
+#include "../data_structures/edge_based_node.hpp"
+#include "../Util/BoostFileSystemFix.h"
+
+#include <osrm/Coordinate.h>
+
+#include <random>
+
+// Choosen by a fair W20 dice roll (this value is completely arbitrary)
+constexpr unsigned RANDOM_SEED = 13;
+constexpr int32_t WORLD_MIN_LAT = -90 * COORDINATE_PRECISION;
+constexpr int32_t WORLD_MAX_LAT = 90 * COORDINATE_PRECISION;
+constexpr int32_t WORLD_MIN_LON = -180 * COORDINATE_PRECISION;
+constexpr int32_t WORLD_MAX_LON = 180 * COORDINATE_PRECISION;
+
+using RTreeLeaf = EdgeBasedNode;
+using FixedPointCoordinateListPtr = std::shared_ptr<std::vector<FixedPointCoordinate>>;
+using BenchStaticRTree = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>;
+
+FixedPointCoordinateListPtr LoadCoordinates(const boost::filesystem::path &nodes_file)
+{
+    boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
+
+    QueryNode current_node;
+    unsigned coordinate_count = 0;
+    nodes_input_stream.read((char *)&coordinate_count, sizeof(unsigned));
+    auto coords = std::make_shared<std::vector<FixedPointCoordinate>>(coordinate_count);
+    for (unsigned i = 0; i < coordinate_count; ++i)
+    {
+        nodes_input_stream.read((char *)&current_node, sizeof(QueryNode));
+        coords->at(i) = FixedPointCoordinate(current_node.lat, current_node.lon);
+        BOOST_ASSERT((std::abs(coords->at(i).lat) >> 30) == 0);
+        BOOST_ASSERT((std::abs(coords->at(i).lon) >> 30) == 0);
+    }
+    nodes_input_stream.close();
+    return coords;
+}
+
+void Benchmark(BenchStaticRTree &rtree, unsigned num_queries)
+{
+    std::mt19937 mt_rand(RANDOM_SEED);
+    std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
+    std::uniform_int_distribution<> lon_udist(WORLD_MIN_LON, WORLD_MAX_LON);
+    std::vector<FixedPointCoordinate> queries;
+    for (unsigned i = 0; i < num_queries; i++)
+    {
+        queries.emplace_back(FixedPointCoordinate(lat_udist(mt_rand), lon_udist(mt_rand)));
+    }
+
+    {
+        const unsigned num_results = 5;
+        std::cout << "#### IncrementalFindPhantomNodeForCoordinate : " << num_results
+                  << " phantom nodes"
+                  << "\n";
+
+        TIMER_START(query_phantom);
+        std::vector<PhantomNode> phantom_node_vector;
+        for (const auto &q : queries)
+        {
+            phantom_node_vector.clear();
+            rtree.IncrementalFindPhantomNodeForCoordinate(
+                q, phantom_node_vector, 3, num_results);
+            phantom_node_vector.clear();
+            rtree.IncrementalFindPhantomNodeForCoordinate(
+                q, phantom_node_vector, 17, num_results);
+        }
+        TIMER_STOP(query_phantom);
+
+        std::cout << "Took " << TIMER_MSEC(query_phantom) << " msec for " << num_queries
+                  << " queries."
+                  << "\n";
+        std::cout << TIMER_MSEC(query_phantom) / ((double)num_queries) << " msec/query."
+                  << "\n";
+
+        std::cout << "#### LocateClosestEndPointForCoordinate"
+                  << "\n";
+    }
+
+    TIMER_START(query_endpoint);
+    FixedPointCoordinate result;
+    for (const auto &q : queries)
+    {
+        rtree.LocateClosestEndPointForCoordinate(q, result, 3);
+    }
+    TIMER_STOP(query_endpoint);
+
+    std::cout << "Took " << TIMER_MSEC(query_endpoint) << " msec for " << num_queries << " queries."
+              << "\n";
+    std::cout << TIMER_MSEC(query_endpoint) / ((double)num_queries) << " msec/query."
+              << "\n";
+
+    std::cout << "#### FindPhantomNodeForCoordinate"
+              << "\n";
+
+    TIMER_START(query_node);
+    for (const auto &q : queries)
+    {
+        PhantomNode phantom;
+        rtree.FindPhantomNodeForCoordinate(q, phantom, 3);
+    }
+    TIMER_STOP(query_node);
+
+    std::cout << "Took " << TIMER_MSEC(query_node) << " msec for " << num_queries
+              << " queries."
+              << "\n";
+    std::cout << TIMER_MSEC(query_node) / ((double)num_queries) << " msec/query."
+              << "\n";
+
+    {
+        const unsigned num_results = 1;
+        std::cout << "#### IncrementalFindPhantomNodeForCoordinate : " << num_results
+                  << " phantom nodes"
+                  << "\n";
+
+        TIMER_START(query_phantom);
+        std::vector<PhantomNode> phantom_node_vector;
+        for (const auto &q : queries)
+        {
+            phantom_node_vector.clear();
+            rtree.IncrementalFindPhantomNodeForCoordinate(
+                q, phantom_node_vector, 3, num_results);
+            phantom_node_vector.clear();
+            rtree.IncrementalFindPhantomNodeForCoordinate(
+                q, phantom_node_vector, 17, num_results);
+        }
+        TIMER_STOP(query_phantom);
+
+        std::cout << "Took " << TIMER_MSEC(query_phantom) << " msec for " << num_queries
+                  << " queries."
+                  << "\n";
+        std::cout << TIMER_MSEC(query_phantom) / ((double)num_queries) << " msec/query."
+                  << "\n";
+
+        std::cout << "#### LocateClosestEndPointForCoordinate"
+                  << "\n";
+    }
+}
+
+int main(int argc, char **argv)
+{
+    if (argc < 4)
+    {
+        std::cout << "./rtree-bench file.ramIndex file.fileIndx file.nodes"
+                  << "\n";
+        return 1;
+    }
+
+    const char *ramPath = argv[1];
+    const char *filePath = argv[2];
+    const char *nodesPath = argv[3];
+
+    auto coords = LoadCoordinates(nodesPath);
+
+    BenchStaticRTree rtree(ramPath, filePath, coords);
+
+    Benchmark(rtree, 10000);
+
+    return 0;
+}
diff --git a/cmake/CPackDebianConfig.cmake b/cmake/CPackDebianConfig.cmake
new file mode 100644
index 0000000..065c429
--- /dev/null
+++ b/cmake/CPackDebianConfig.cmake
@@ -0,0 +1,44 @@
+IF(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
+  MESSAGE(FATAL_ERROR "Cannot configure CPack to generate Debian packages on non-linux systems.")
+ENDIF()
+
+INCLUDE(FindDebArch)
+
+SET(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md")
+SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENCE.TXT")
+SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CPACK_RESOURCE_FILE_README}")
+SET(CPACK_PACKAGE_VERSION_MAJOR "0")
+SET(CPACK_PACKAGE_VERSION_MINOR "4")
+SET(CPACK_PACKAGE_VERSION_PATCH "3")
+
+SET(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
+
+string(TOLOWER "${CMAKE_PROJECT_NAME}" LOWER_PROJECT_NAME)
+SET(CPACK_PACKAGE_FILE_NAME "${LOWER_PROJECT_NAME}_${CPACK_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
+SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${LOWER_PROJECT_NAME}_${CPACK_PACKAGE_VERSION}_orig")
+SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Open Source Routing Machine (OSRM).")
+SET(CPACK_PACKAGE_DESCRIPTION "Open Source Routing Machine (OSRM) is a routing engine.")
+
+# To create a proper Debian/Ubuntu package, the following CMake
+# options should be used:
+
+SET(CPACK_STRIP_FILES "TRUE")
+SET(CPACK_INCLUDE_TOPLEVEL_DIRECTORY "FALSE")
+SET(CPACK_GENERATOR "DEB")
+
+SET(CPACK_DEBIAN_PACKAGE_NAME        "${CPACK_PACKAGE_NAME}${VERSION_SUFFIX}")
+SET(CPACK_DEBIAN_PACKAGE_VERSION     "${CPACK_PACKAGE_VERSION}${CPACK_PACKAGE_REVISION}")
+SET(CPACK_DEBIAN_PACKAGE_MAINTAINER  "Dennis Luxen <info at project-osrm.org>")
+SET(CPACK_DEBIAN_PACKAGE_PRIORITY    "optional")
+SET(CPACK_DEBIAN_PACKAGE_SECTION     "devel")
+SET(CPACK_DEBIAN_PACKAGE_DESCRIPTION "Open Source Routing Machine (OSRM) is a high-performance routing engine.
+  It combines sophisticated routing algorithms with the open and free data of the OpenStreetMap."
+)
+SET(CPACK_DEBIAN_PACKAGE_DEPENDS     "libc6-dev, libprotobuf-dev, libosmpbf-dev, libbz2-1.0, libstxxl1, libxml2, libzip2, liblua5.1-0, libtbb2, libboost-all-dev")
+
+file(GLOB_RECURSE ProfileGlob ${CMAKE_SOURCE_DIR}/profiles/*)
+install(FILES ${ProfileGlob} DESTINATION "share/doc/${LOWER_PROJECT_NAME}/profiles")
+CONFIGURE_FILE (${CMAKE_SOURCE_DIR}/cmake/postinst.in postinst)
+set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_BINARY_DIR}/postinst;${CMAKE_CURRENT_BINARY_DIR}/copyright;")
+
+MESSAGE(STATUS "Debian Package: ${CPACK_DEBIAN_PACKAGE_NAME} (${CPACK_DEBIAN_PACKAGE_VERSION}) [${CPACK_PACKAGE_FILE_NAME}.deb]")
diff --git a/cmake/FindDebArch.cmake b/cmake/FindDebArch.cmake
new file mode 100644
index 0000000..5b405bc
--- /dev/null
+++ b/cmake/FindDebArch.cmake
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2013	Emmanuel Roullit <emmanuel.roullit at gmail.com>
+#
+
+IF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
+  FIND_PROGRAM(DPKG_CMD dpkg)
+  IF(NOT DPKG_CMD)
+    EXECUTE_PROCESS(COMMAND uname -p
+      OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+    )
+    MESSAGE(STATUS "Can not find dpkg in your path, default to uname -p: ${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.")
+  ELSE(NOT DPKG_CMD)
+    EXECUTE_PROCESS(COMMAND "${DPKG_CMD}" --print-architecture
+      OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+    )
+  ENDIF(NOT DPKG_CMD)
+ENDIF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
diff --git a/cmake/FingerPrint-Config.cmake b/cmake/FingerPrint-Config.cmake
index 7b45d5c..710368d 100644
--- a/cmake/FingerPrint-Config.cmake
+++ b/cmake/FingerPrint-Config.cmake
@@ -3,8 +3,8 @@ if (EXISTS ${OLDFILE})
 	file(REMOVE_RECURSE ${OLDFILE})
 endif()
 file(MD5 ${SOURCE_DIR}/prepare.cpp MD5PREPARE)
-file(MD5 ${SOURCE_DIR}/DataStructures/StaticRTree.h MD5RTREE)
-file(MD5 ${SOURCE_DIR}/Util/GraphLoader.h MD5GRAPH)
+file(MD5 ${SOURCE_DIR}/data_structures/static_rtree.hpp MD5RTREE)
+file(MD5 ${SOURCE_DIR}/Util/graph_loader.hpp MD5GRAPH)
 file(MD5 ${SOURCE_DIR}/Server/DataStructures/InternalDataFacade.h MD5OBJECTS)
 
-CONFIGURE_FILE( ${SOURCE_DIR}/Util/FingerPrint.cpp.in ${SOURCE_DIR}/Util/FingerPrint.cpp )
+CONFIGURE_FILE( ${SOURCE_DIR}/Util/finger_print.cpp.in ${SOURCE_DIR}/Util/finger_print.cpp )
diff --git a/cmake/check_luabind.cmake b/cmake/check_luabind.cmake
new file mode 100644
index 0000000..18f0656
--- /dev/null
+++ b/cmake/check_luabind.cmake
@@ -0,0 +1,40 @@
+INCLUDE (CheckCXXSourceCompiles)
+unset(LUABIND_WORKS CACHE)
+unset(LUABIND51_WORKS CACHE)
+set (LUABIND_CHECK_SRC "#include  \"lua.h\"\n#include <luabind/luabind.hpp>\n int main() { lua_State *myLuaState = luaL_newstate(); luabind::open(myLuaState);  return 0;}")
+set (CMAKE_TRY_COMPILE_CONFIGURATION ${CMAKE_BUILD_TYPE})
+set (CMAKE_REQUIRED_INCLUDES "${Boost_INCLUDE_DIR};${LUABIND_INCLUDE_DIR};${LUA_INCLUDE_DIR}")
+set (CMAKE_REQUIRED_LIBRARIES "${LUABIND_LIBRARY};${LUA_LIBRARY}")
+
+find_package(Lua52)
+if(NOT APPLE)
+  find_package(LuaJIT 5.2)
+endif()
+if(LUA52_FOUND)
+  set (CMAKE_REQUIRED_INCLUDES "${Boost_INCLUDE_DIR};${LUABIND_INCLUDE_DIR};${LUA_INCLUDE_DIR}")
+  set (CMAKE_REQUIRED_LIBRARIES "${LUABIND_LIBRARY};${LUA_LIBRARY}")
+  CHECK_CXX_SOURCE_COMPILES("${LUABIND_CHECK_SRC}" LUABIND_WORKS)
+endif()
+
+if(LUABIND_WORKS)
+  message(STATUS "Luabind/Lua5.2 combination working with ${LUA_LIBRARY}")
+else()
+  message(STATUS "Luabind/Lua5.2 not feasible, falling back to Lua 5.1.")
+  unset(LUA_FOUND CACHE)
+  unset(LUA_INCLUDE_DIR CACHE)
+  unset(LUA_LIBRARY CACHE)
+  find_package(Lua51 REQUIRED)
+  if(NOT APPLE)
+    find_package(LuaJIT 5.1)
+  endif()
+  set (CMAKE_REQUIRED_INCLUDES "${Boost_INCLUDE_DIR};${LUABIND_INCLUDE_DIR};${LUA_INCLUDE_DIR}")
+  set (CMAKE_REQUIRED_LIBRARIES "${LUABIND_LIBRARY};${LUA_LIBRARY}")
+
+  CHECK_CXX_SOURCE_COMPILES("${LUABIND_CHECK_SRC}" LUABIND51_WORKS)
+
+  if(LUABIND51_WORKS)
+    message(STATUS "Luabind works with Lua 5.1 at ${LUA_LIBRARY}")
+  else()
+    message(FATAL_ERROR	"Luabind does not work with Lua 5.1 at ${LUA_LIBRARY}, no working Luabind found")
+  endif()
+endif()
diff --git a/cmake/postinst.in b/cmake/postinst.in
new file mode 100644
index 0000000..92f2fde
--- /dev/null
+++ b/cmake/postinst.in
@@ -0,0 +1,2 @@
+#/usr/bin/env bash
+ln -s /usr/share/doc/@CMAKE_PROJECT_NAME@/profiles/car.lua @CMAKE_INSTALL_PREFIX@/profile.lua
diff --git a/Contractor/Contractor.h b/contractor/contractor.hpp
similarity index 83%
rename from Contractor/Contractor.h
rename to contractor/contractor.hpp
index a879607..c8c107c 100644
--- a/Contractor/Contractor.h
+++ b/contractor/contractor.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,22 +25,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef CONTRACTOR_H
-#define CONTRACTOR_H
-
-#include "TemporaryStorage.h"
-#include "../DataStructures/BinaryHeap.h"
-#include "../DataStructures/DeallocatingVector.h"
-#include "../DataStructures/DynamicGraph.h"
-#include "../DataStructures/Percent.h"
-#include "../DataStructures/XORFastHash.h"
-#include "../DataStructures/XORFastHashStorage.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/StringUtil.h"
-#include "../Util/TimingUtil.h"
+#ifndef CONTRACTOR_HPP
+#define CONTRACTOR_HPP
+
+#include "../data_structures/binary_heap.hpp"
+#include "../data_structures/deallocating_vector.hpp"
+#include "../data_structures/dynamic_graph.hpp"
+#include "../data_structures/percent.hpp"
+#include "../data_structures/query_edge.hpp"
+#include "../data_structures/xor_fast_hash.hpp"
+#include "../data_structures/xor_fast_hash_storage.hpp"
+#include "../Util/integer_range.hpp"
+#include "../Util/simple_logger.hpp"
+#include "../Util/timing_util.hpp"
+#include "../typedefs.h"
 
 #include <boost/assert.hpp>
 
+#include <stxxl/vector>
+
 #include <tbb/enumerable_thread_specific.h>
 #include <tbb/parallel_for.h>
 #include <tbb/parallel_sort.h>
@@ -60,15 +63,15 @@ class Contractor
               is_original_via_node_ID(false)
         {
         }
-        ContractorEdgeData(unsigned _distance,
-                           unsigned _originalEdges,
-                           unsigned _id,
-                           bool _shortcut,
-                           bool _forward,
-                           bool _backward)
-            : distance(_distance), id(_id),
-              originalEdges(std::min((unsigned)1 << 28, _originalEdges)), shortcut(_shortcut),
-              forward(_forward), backward(_backward), is_original_via_node_ID(false)
+        ContractorEdgeData(unsigned distance,
+                           unsigned original_edges,
+                           unsigned id,
+                           bool shortcut,
+                           bool forward,
+                           bool backward)
+            : distance(distance), id(id),
+              originalEdges(std::min((unsigned)1 << 28, original_edges)), shortcut(shortcut),
+              forward(forward), backward(backward), is_original_via_node_ID(false)
         {
         }
         unsigned distance;
@@ -88,19 +91,18 @@ class Contractor
         ContractorHeapData(short h, bool t) : hop(h), target(t) {}
     };
 
-    typedef DynamicGraph<ContractorEdgeData> ContractorGraph;
-    //    typedef BinaryHeap< NodeID, NodeID, int, ContractorHeapData, ArrayStorage<NodeID, NodeID>
-    //    > ContractorHeap;
-    typedef BinaryHeap<NodeID, NodeID, int, ContractorHeapData, XORFastHashStorage<NodeID, NodeID>>
-    ContractorHeap;
-    typedef ContractorGraph::InputEdge ContractorEdge;
+    using ContractorGraph = DynamicGraph<ContractorEdgeData>;
+    //    using ContractorHeap = BinaryHeap<NodeID, NodeID, int, ContractorHeapData, ArrayStorage<NodeID, NodeID>
+    //    >;
+    using ContractorHeap = BinaryHeap<NodeID, NodeID, int, ContractorHeapData, XORFastHashStorage<NodeID, NodeID>>;
+    using ContractorEdge = ContractorGraph::InputEdge;
 
     struct ContractorThreadData
     {
         ContractorHeap heap;
         std::vector<ContractorEdge> inserted_edges;
         std::vector<NodeID> neighbours;
-        ContractorThreadData(NodeID nodes) : heap(nodes) {}
+        explicit ContractorThreadData(NodeID nodes) : heap(nodes) {}
     };
 
     struct NodePriorityData
@@ -132,7 +134,7 @@ class Contractor
 
     struct ThreadDataContainer
     {
-        ThreadDataContainer(int number_of_nodes) : number_of_nodes(number_of_nodes)  {}
+        explicit ThreadDataContainer(int number_of_nodes) : number_of_nodes(number_of_nodes)  {}
 
         inline ContractorThreadData* getThreadData()
         {
@@ -147,7 +149,7 @@ class Contractor
         }
 
         int number_of_nodes;
-        typedef tbb::enumerable_thread_specific<std::shared_ptr<ContractorThreadData>> EnumerableThreadData;
+        using EnumerableThreadData = tbb::enumerable_thread_specific<std::shared_ptr<ContractorThreadData>>;
         EnumerableThreadData data;
     };
 
@@ -156,41 +158,38 @@ class Contractor
     {
         std::vector<ContractorEdge> edges;
         edges.reserve(input_edge_list.size() * 2);
-        temp_edge_counter = 0;
 
-        auto diter = input_edge_list.dbegin();
-        auto dend = input_edge_list.dend();
-
-        ContractorEdge new_edge;
-        while (diter != dend)
+        const auto dend = input_edge_list.dend();
+        for (auto diter = input_edge_list.dbegin(); diter != dend; ++diter)
         {
-            new_edge.source = diter->source;
-            new_edge.target = diter->target;
-            new_edge.data = { static_cast<unsigned int>(std::max(diter->weight, 1)),
-                              1,
-                              diter->edge_id,
-                              false,
-                              diter->forward,
-                              diter->backward};
-
-            BOOST_ASSERT_MSG(new_edge.data.distance > 0, "edge distance < 1");
+            BOOST_ASSERT_MSG(static_cast<unsigned int>(std::max(diter->weight, 1)) > 0, "edge distance < 1");
 #ifndef NDEBUG
-            if (new_edge.data.distance > 24 * 60 * 60 * 10)
+            if (static_cast<unsigned int>(std::max(diter->weight, 1)) > 24 * 60 * 60 * 10)
             {
                 SimpleLogger().Write(logWARNING) << "Edge weight large -> "
-                                                 << new_edge.data.distance;
+                                                 << static_cast<unsigned int>(std::max(diter->weight, 1));
             }
 #endif
-            edges.push_back(new_edge);
-            std::swap(new_edge.source, new_edge.target);
-            new_edge.data.forward = diter->backward;
-            new_edge.data.backward = diter->forward;
-            edges.push_back(new_edge);
-            ++diter;
+            edges.emplace_back(diter->source, diter->target,
+                static_cast<unsigned int>(std::max(diter->weight, 1)),
+                1,
+                diter->edge_id,
+                false,
+                diter->forward ? true : false,
+                diter->backward ? true : false);
+
+            edges.emplace_back(diter->target, diter->source,
+                static_cast<unsigned int>(std::max(diter->weight, 1)),
+                1,
+                diter->edge_id,
+                false,
+                diter->backward ? true : false,
+                diter->forward ? true : false);
         }
         // clear input vector
-        edges.shrink_to_fit();
         input_edge_list.clear();
+        edges.shrink_to_fit();
+
         tbb::parallel_sort(edges.begin(), edges.end());
         NodeID edge = 0;
         for (NodeID i = 0; i < edges.size();)
@@ -201,7 +200,7 @@ class Contractor
             // remove eigenloops
             if (source == target)
             {
-                i++;
+                ++i;
                 continue;
             }
             ContractorEdge forward_edge;
@@ -280,13 +279,10 @@ class Contractor
         //            << "); via: " << contractor_graph->GetEdgeData(i).via;
         //        }
 
-        // Create temporary file
-
-        edge_storage_slot = TemporaryStorage::GetInstance().AllocateSlot();
         std::cout << "contractor finished initalization" << std::endl;
     }
 
-    ~Contractor() { TemporaryStorage::GetInstance().DeallocateSlot(edge_storage_slot); }
+    ~Contractor() { }
 
     void Run()
     {
@@ -362,7 +358,7 @@ class Contractor
 
                 // build forward and backward renumbering map and remap ids in remaining_nodes and
                 // Priorities.
-                for (unsigned new_node_id = 0; new_node_id < remaining_nodes.size(); ++new_node_id)
+                for (const auto new_node_id : osrm::irange<std::size_t>(0, remaining_nodes.size()))
                 {
                     // create renumbering maps in both directions
                     orig_node_id_to_new_id_map[new_node_id] = remaining_nodes[new_node_id].id;
@@ -371,9 +367,8 @@ class Contractor
                         node_priorities[remaining_nodes[new_node_id].id];
                     remaining_nodes[new_node_id].id = new_node_id;
                 }
-                TemporaryStorage &temporary_storage = TemporaryStorage::GetInstance();
                 // walk over all nodes
-                for (unsigned i = 0; i < contractor_graph->GetNumberOfNodes(); ++i)
+                for (const auto i : osrm::irange<std::size_t>(0, contractor_graph->GetNumberOfNodes()))
                 {
                     const NodeID source = i;
                     for (auto current_edge : contractor_graph->GetAdjacentEdgeRange(source))
@@ -381,26 +376,20 @@ class Contractor
                         ContractorGraph::EdgeData &data =
                             contractor_graph->GetEdgeData(current_edge);
                         const NodeID target = contractor_graph->GetTarget(current_edge);
-                        if (UINT_MAX == new_node_id_from_orig_id_map[i])
+                        if (SPECIAL_NODEID == new_node_id_from_orig_id_map[i])
                         {
-                            // Save edges of this node w/o renumbering.
-                            temporary_storage.WriteToSlot(
-                                edge_storage_slot, (char *)&source, sizeof(NodeID));
-                            temporary_storage.WriteToSlot(
-                                edge_storage_slot, (char *)&target, sizeof(NodeID));
-                            temporary_storage.WriteToSlot(edge_storage_slot,
-                                                          (char *)&data,
-                                                          sizeof(ContractorGraph::EdgeData));
-                            ++temp_edge_counter;
+                            external_edge_list.push_back({source, target, data});
                         }
                         else
                         {
                             // node is not yet contracted.
                             // add (renumbered) outgoing edges to new DynamicGraph.
-                            ContractorEdge new_edge;
-                            new_edge.source = new_node_id_from_orig_id_map[source];
-                            new_edge.target = new_node_id_from_orig_id_map[target];
-                            new_edge.data = data;
+                            ContractorEdge new_edge = {
+                                new_node_id_from_orig_id_map[source],
+                                new_node_id_from_orig_id_map[target],
+                                data
+                            };
+
                             new_edge.data.is_original_via_node_ID = true;
                             BOOST_ASSERT_MSG(UINT_MAX != new_node_id_from_orig_id_map[source],
                                              "new source id not resolveable");
@@ -569,7 +558,7 @@ class Contractor
         if (contractor_graph->GetNumberOfNodes())
         {
             Edge new_edge;
-            for (NodeID node = 0; node < number_of_nodes; ++node)
+            for (const auto node : osrm::irange(0u, number_of_nodes))
             {
                 p.printStatus(node);
                 for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
@@ -611,29 +600,9 @@ class Contractor
         orig_node_id_to_new_id_map.shrink_to_fit();
 
         BOOST_ASSERT(0 == orig_node_id_to_new_id_map.capacity());
-        TemporaryStorage &temporary_storage = TemporaryStorage::GetInstance();
-        // loads edges of graph before renumbering, no need for further numbering action.
-        NodeID source;
-        NodeID target;
-        ContractorGraph::EdgeData data;
-
-        Edge restored_edge;
-        for (unsigned i = 0; i < temp_edge_counter; ++i)
-        {
-            temporary_storage.ReadFromSlot(edge_storage_slot, (char *)&source, sizeof(NodeID));
-            temporary_storage.ReadFromSlot(edge_storage_slot, (char *)&target, sizeof(NodeID));
-            temporary_storage.ReadFromSlot(
-                edge_storage_slot, (char *)&data, sizeof(ContractorGraph::EdgeData));
-            restored_edge.source = source;
-            restored_edge.target = target;
-            restored_edge.data.distance = data.distance;
-            restored_edge.data.shortcut = data.shortcut;
-            restored_edge.data.id = data.id;
-            restored_edge.data.forward = data.forward;
-            restored_edge.data.backward = data.backward;
-            edges.push_back(restored_edge);
-        }
-        temporary_storage.DeallocateSlot(edge_storage_slot);
+
+        edges.append(external_edge_list.begin(), external_edge_list.end());
+        external_edge_list.clear();
     }
 
   private:
@@ -648,7 +617,7 @@ class Contractor
 
         int nodes = 0;
         unsigned number_of_targets_found = 0;
-        while (heap.Size() > 0)
+        while (!heap.Empty())
         {
             const NodeID node = heap.DeleteMin();
             const int distance = heap.GetKey(node);
@@ -658,12 +627,12 @@ class Contractor
             {
                 return;
             }
-            // Destination settled?
             if (distance > max_distance)
             {
                 return;
             }
 
+            // Destination settled?
             if (heap.GetData(node).target)
             {
                 ++number_of_targets_found;
@@ -731,7 +700,7 @@ class Contractor
 
     template <bool RUNSIMULATION>
     inline bool
-    ContractNode(ContractorThreadData *data, NodeID node, ContractionStats *stats = nullptr)
+    ContractNode(ContractorThreadData *data, const NodeID node, ContractionStats *stats = nullptr)
     {
         ContractorHeap &heap = data->heap;
         int inserted_edges_size = data->inserted_edges.size();
@@ -803,21 +772,19 @@ class Contractor
                     }
                     else
                     {
-                        ContractorEdge new_edge;
-                        new_edge.source = source;
-                        new_edge.target = target;
-                        new_edge.data =
-                            ContractorEdgeData(path_distance,
-                                               out_data.originalEdges + in_data.originalEdges,
-                                               node /*, 0, in_data.turnInstruction*/,
-                                               true,
-                                               true,
-                                               false);
-                        inserted_edges.push_back(new_edge);
-                        std::swap(new_edge.source, new_edge.target);
-                        new_edge.data.forward = false;
-                        new_edge.data.backward = true;
-                        inserted_edges.push_back(new_edge);
+                        inserted_edges.emplace_back(source, target, path_distance,
+                                                    out_data.originalEdges + in_data.originalEdges,
+                                                    node,
+                                                    true,
+                                                    true,
+                                                    false);
+
+                        inserted_edges.emplace_back(target, source, path_distance,
+                                                    out_data.originalEdges + in_data.originalEdges,
+                                                    node,
+                                                    true,
+                                                    false,
+                                                    true);
                     }
                 }
             }
@@ -879,7 +846,7 @@ class Contractor
         std::sort(neighbours.begin(), neighbours.end());
         neighbours.resize(std::unique(neighbours.begin(), neighbours.end()) - neighbours.begin());
 
-        for (int i = 0, e = (int)neighbours.size(); i < e; ++i)
+        for (const auto i : osrm::irange<std::size_t>(0, neighbours.size()))
         {
             contractor_graph->DeleteEdgesTo(neighbours[i], node);
         }
@@ -917,7 +884,7 @@ class Contractor
     }
 
     inline bool IsNodeIndependent(
-        const std::vector<float> &priorities /*, const std::vector< NodePriorityData >& node_data*/,
+        const std::vector<float> &priorities,
         ContractorThreadData *const data,
         NodeID node) const
     {
@@ -963,7 +930,7 @@ class Contractor
                     continue;
                 }
                 const float target_priority = priorities[target];
-                assert(target_priority >= 0);
+                BOOST_ASSERT(target_priority >= 0);
                 // found a neighbour with lower priority?
                 if (priority > target_priority)
                 {
@@ -983,8 +950,8 @@ class Contractor
     // This bias function takes up 22 assembly instructions in total on X86
     inline bool bias(const NodeID a, const NodeID b) const
     {
-        unsigned short hasha = fast_hash(a);
-        unsigned short hashb = fast_hash(b);
+        const unsigned short hasha = fast_hash(a);
+        const unsigned short hashb = fast_hash(b);
 
         // The compiler optimizes that to conditional register flags but without branching
         // statements!
@@ -997,10 +964,9 @@ class Contractor
 
     std::shared_ptr<ContractorGraph> contractor_graph;
     std::vector<ContractorGraph::InputEdge> contracted_edge_list;
-    unsigned edge_storage_slot;
-    uint64_t temp_edge_counter;
+    stxxl::vector<QueryEdge> external_edge_list;
     std::vector<NodeID> orig_node_id_to_new_id_map;
     XORFastHash fast_hash;
 };
 
-#endif // CONTRACTOR_H
+#endif // CONTRACTOR_HPP
diff --git a/Contractor/EdgeBasedGraphFactory.cpp b/contractor/edge_based_graph_factory.cpp
similarity index 72%
rename from Contractor/EdgeBasedGraphFactory.cpp
rename to contractor/edge_based_graph_factory.cpp
index 1e4e381..144b1fa 100644
--- a/Contractor/EdgeBasedGraphFactory.cpp
+++ b/contractor/edge_based_graph_factory.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,17 +25,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "EdgeBasedGraphFactory.h"
-#include "../Algorithms/BFSComponentExplorer.h"
-#include "../DataStructures/Percent.h"
-#include "../Util/ComputeAngle.h"
-#include "../Util/LuaUtil.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/TimingUtil.h"
+#include "edge_based_graph_factory.hpp"
+#include "../algorithms/tiny_components.hpp"
+#include "../data_structures/percent.hpp"
+#include "../Util/compute_angle.hpp"
+#include "../Util/integer_range.hpp"
+#include "../Util/lua_util.hpp"
+#include "../Util/simple_logger.hpp"
+#include "../Util/timing_util.hpp"
 
 #include <boost/assert.hpp>
 
 #include <fstream>
+#include <iomanip>
 #include <limits>
 
 EdgeBasedGraphFactory::EdgeBasedGraphFactory(
@@ -43,14 +45,13 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(
     std::unique_ptr<RestrictionMap> restriction_map,
     std::vector<NodeID> &barrier_node_list,
     std::vector<NodeID> &traffic_light_node_list,
-    std::vector<NodeInfo> &m_node_info_list,
+    std::vector<QueryNode> &node_info_list,
     SpeedProfileProperties &speed_profile)
     : speed_profile(speed_profile),
       m_number_of_edge_based_nodes(std::numeric_limits<unsigned>::max()),
-      m_node_info_list(m_node_info_list), m_node_based_graph(node_based_graph),
-      m_restriction_map(std::move(restriction_map)), max_id(0)
+      m_node_info_list(node_info_list), m_node_based_graph(node_based_graph),
+      m_restriction_map(std::move(restriction_map)), max_id(0), removed_node_count(0)
 {
-
     // insert into unordered sets for fast lookup
     m_barrier_nodes.insert(barrier_node_list.begin(), barrier_node_list.end());
     m_traffic_lights.insert(traffic_light_node_list.begin(), traffic_light_node_list.end());
@@ -77,33 +78,31 @@ void EdgeBasedGraphFactory::GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes)
 }
 
 void
-EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool belongs_to_tiny_cc)
+EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u,
+                                           const NodeID node_v,
+                                           const unsigned component_id)
 {
     // merge edges together into one EdgeBasedNode
-    BOOST_ASSERT(u != SPECIAL_NODEID);
-    BOOST_ASSERT(v != SPECIAL_NODEID);
-    BOOST_ASSERT(e1 != SPECIAL_EDGEID);
+    BOOST_ASSERT(node_u != SPECIAL_NODEID);
+    BOOST_ASSERT(node_v != SPECIAL_NODEID);
 
-#ifndef NDEBUG
     // find forward edge id and
-    const EdgeID e1b = m_node_based_graph->FindEdge(u, v);
-    BOOST_ASSERT(e1 == e1b);
-#endif
-
+    const EdgeID e1 = m_node_based_graph->FindEdge(node_u, node_v);
     BOOST_ASSERT(e1 != SPECIAL_EDGEID);
+
     const EdgeData &forward_data = m_node_based_graph->GetEdgeData(e1);
 
     // find reverse edge id and
-    const EdgeID e2 = m_node_based_graph->FindEdge(v, u);
+    const EdgeID e2 = m_node_based_graph->FindEdge(node_v, node_u);
 
 #ifndef NDEBUG
-    if (e2 == m_node_based_graph->EndEdges(v))
+    if (e2 == m_node_based_graph->EndEdges(node_v))
     {
-        SimpleLogger().Write(logWARNING) << "Did not find edge (" << v << "," << u << ")";
+        SimpleLogger().Write(logWARNING) << "Did not find edge (" << node_v << "," << node_u << ")";
     }
 #endif
     BOOST_ASSERT(e2 != SPECIAL_EDGEID);
-    BOOST_ASSERT(e2 < m_node_based_graph->EndEdges(v));
+    BOOST_ASSERT(e2 < m_node_based_graph->EndEdges(node_v));
     const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(e2);
 
     if (forward_data.edgeBasedNodeID == SPECIAL_NODEID &&
@@ -125,6 +124,8 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
             m_geometry_compressor.GetBucketReference(e2);
         BOOST_ASSERT(forward_geometry.size() == reverse_geometry.size());
         BOOST_ASSERT(0 != forward_geometry.size());
+        const unsigned geometry_size = static_cast<unsigned>(forward_geometry.size());
+        BOOST_ASSERT(geometry_size > 1);
 
         // reconstruct bidirectional edge with individual weights and put each into the NN index
 
@@ -135,7 +136,7 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
         // TODO: move to lambda function with C++11
         int temp_sum = 0;
 
-        for (unsigned i = 0; i < forward_geometry.size(); ++i)
+        for (const auto i : osrm::irange(0u, geometry_size))
         {
             forward_dist_prefix_sum[i] = temp_sum;
             temp_sum += forward_geometry[i].second;
@@ -144,20 +145,16 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
         }
 
         temp_sum = 0;
-        for (unsigned i = 0; i < reverse_geometry.size(); ++i)
+        for (const auto i : osrm::irange(0u, geometry_size))
         {
             temp_sum += reverse_geometry[reverse_geometry.size() - 1 - i].second;
             reverse_dist_prefix_sum[i] = reverse_data.distance - temp_sum;
-            BOOST_ASSERT(reverse_data.distance >= temp_sum);
+            // BOOST_ASSERT(reverse_data.distance >= temp_sum);
         }
 
-        BOOST_ASSERT(forward_geometry.size() == reverse_geometry.size());
-
-        const unsigned geometry_size = forward_geometry.size();
-        BOOST_ASSERT(geometry_size > 1);
-        NodeID current_edge_source_coordinate_id = u;
+        NodeID current_edge_source_coordinate_id = node_u;
 
-        if (forward_data.edgeBasedNodeID != SPECIAL_NODEID)
+        if (SPECIAL_NODEID != forward_data.edgeBasedNodeID)
         {
             max_id = std::max(forward_data.edgeBasedNodeID, max_id);
         }
@@ -167,7 +164,7 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
         }
 
         // traverse arrays from start and end respectively
-        for (unsigned i = 0; i < geometry_size; ++i)
+        for (const auto i : osrm::irange(0u, geometry_size))
         {
             BOOST_ASSERT(current_edge_source_coordinate_id ==
                          reverse_geometry[geometry_size - 1 - i].first);
@@ -181,24 +178,26 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
                                                 current_edge_target_coordinate_id,
                                                 forward_data.nameID,
                                                 forward_geometry[i].second,
-                                                reverse_geometry[i].second,
+                                                reverse_geometry[geometry_size - 1 - i].second,
                                                 forward_dist_prefix_sum[i],
                                                 reverse_dist_prefix_sum[i],
                                                 m_geometry_compressor.GetPositionForID(e1),
+                                                component_id,
                                                 i,
-                                                belongs_to_tiny_cc);
+                                                forward_data.travel_mode,
+                                                reverse_data.travel_mode);
             current_edge_source_coordinate_id = current_edge_target_coordinate_id;
 
             BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
 
-            BOOST_ASSERT(u != m_edge_based_node_list.back().u ||
-                         v != m_edge_based_node_list.back().v);
+            BOOST_ASSERT(node_u != m_edge_based_node_list.back().u ||
+                         node_v != m_edge_based_node_list.back().v);
 
-            BOOST_ASSERT(u != m_edge_based_node_list.back().v ||
-                         v != m_edge_based_node_list.back().u);
+            BOOST_ASSERT(node_u != m_edge_based_node_list.back().v ||
+                         node_v != m_edge_based_node_list.back().u);
         }
 
-        BOOST_ASSERT(current_edge_source_coordinate_id == v);
+        BOOST_ASSERT(current_edge_source_coordinate_id == node_v);
         BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
     }
     else
@@ -225,18 +224,20 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
         BOOST_ASSERT(forward_data.edgeBasedNodeID != SPECIAL_NODEID ||
                      reverse_data.edgeBasedNodeID != SPECIAL_NODEID);
 
-        m_edge_based_node_list.emplace_back(EdgeBasedNode(forward_data.edgeBasedNodeID,
-                                                          reverse_data.edgeBasedNodeID,
-                                                          u,
-                                                          v,
-                                                          forward_data.nameID,
-                                                          forward_data.distance,
-                                                          reverse_data.distance,
-                                                          0,
-                                                          0,
-                                                          SPECIAL_EDGEID,
-                                                          0,
-                                                          belongs_to_tiny_cc));
+        m_edge_based_node_list.emplace_back(forward_data.edgeBasedNodeID,
+                                            reverse_data.edgeBasedNodeID,
+                                            node_u,
+                                            node_v,
+                                            forward_data.nameID,
+                                            forward_data.distance,
+                                            reverse_data.distance,
+                                            0,
+                                            0,
+                                            SPECIAL_EDGEID,
+                                            component_id,
+                                            0,
+                                            forward_data.travel_mode,
+                                            reverse_data.travel_mode);
         BOOST_ASSERT(!m_edge_based_node_list.back().IsCompressed());
     }
 }
@@ -289,61 +290,60 @@ void EdgeBasedGraphFactory::CompressGeometry()
     const unsigned original_number_of_nodes = m_node_based_graph->GetNumberOfNodes();
     const unsigned original_number_of_edges = m_node_based_graph->GetNumberOfEdges();
 
-    Percent p(original_number_of_nodes);
-    unsigned removed_node_count = 0;
+    Percent progress(original_number_of_nodes);
 
-    for (NodeID v = 0; v < original_number_of_nodes; ++v)
+    for (const NodeID node_v : osrm::irange(0u, original_number_of_nodes))
     {
-        p.printStatus(v);
+        progress.printStatus(node_v);
 
         // only contract degree 2 vertices
-        if (2 != m_node_based_graph->GetOutDegree(v))
+        if (2 != m_node_based_graph->GetOutDegree(node_v))
         {
             continue;
         }
 
         // don't contract barrier node
-        if (m_barrier_nodes.end() != m_barrier_nodes.find(v))
+        if (m_barrier_nodes.end() != m_barrier_nodes.find(node_v))
         {
             continue;
         }
 
         // check if v is a via node for a turn restriction, i.e. a 'directed' barrier node
-        if (m_restriction_map->IsViaNode(v))
+        if (m_restriction_map->IsViaNode(node_v))
         {
             continue;
         }
 
         const bool reverse_edge_order =
-            !(m_node_based_graph->GetEdgeData(m_node_based_graph->BeginEdges(v)).forward);
-        const EdgeID forward_e2 = m_node_based_graph->BeginEdges(v) + reverse_edge_order;
+            !(m_node_based_graph->GetEdgeData(m_node_based_graph->BeginEdges(node_v)).forward);
+        const EdgeID forward_e2 = m_node_based_graph->BeginEdges(node_v) + reverse_edge_order;
         BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
-        const EdgeID reverse_e2 = m_node_based_graph->BeginEdges(v) + 1 - reverse_edge_order;
+        const EdgeID reverse_e2 = m_node_based_graph->BeginEdges(node_v) + 1 - reverse_edge_order;
         BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2);
 
         const EdgeData &fwd_edge_data2 = m_node_based_graph->GetEdgeData(forward_e2);
         const EdgeData &rev_edge_data2 = m_node_based_graph->GetEdgeData(reverse_e2);
 
-        const NodeID w = m_node_based_graph->GetTarget(forward_e2);
-        BOOST_ASSERT(SPECIAL_NODEID != w);
-        BOOST_ASSERT(v != w);
-        const NodeID u = m_node_based_graph->GetTarget(reverse_e2);
-        BOOST_ASSERT(SPECIAL_NODEID != u);
-        BOOST_ASSERT(u != v);
+        const NodeID node_w = m_node_based_graph->GetTarget(forward_e2);
+        BOOST_ASSERT(SPECIAL_NODEID != node_w);
+        BOOST_ASSERT(node_v != node_w);
+        const NodeID node_u = m_node_based_graph->GetTarget(reverse_e2);
+        BOOST_ASSERT(SPECIAL_NODEID != node_u);
+        BOOST_ASSERT(node_u != node_v);
 
-        const EdgeID forward_e1 = m_node_based_graph->FindEdge(u, v);
-        BOOST_ASSERT(m_node_based_graph->EndEdges(u) != forward_e1);
+        const EdgeID forward_e1 = m_node_based_graph->FindEdge(node_u, node_v);
+        BOOST_ASSERT(m_node_based_graph->EndEdges(node_u) != forward_e1);
         BOOST_ASSERT(SPECIAL_EDGEID != forward_e1);
-        BOOST_ASSERT(v == m_node_based_graph->GetTarget(forward_e1));
-        const EdgeID reverse_e1 = m_node_based_graph->FindEdge(w, v);
+        BOOST_ASSERT(node_v == m_node_based_graph->GetTarget(forward_e1));
+        const EdgeID reverse_e1 = m_node_based_graph->FindEdge(node_w, node_v);
         BOOST_ASSERT(SPECIAL_EDGEID != reverse_e1);
-        BOOST_ASSERT(v == m_node_based_graph->GetTarget(reverse_e1));
+        BOOST_ASSERT(node_v == m_node_based_graph->GetTarget(reverse_e1));
 
         const EdgeData &fwd_edge_data1 = m_node_based_graph->GetEdgeData(forward_e1);
         const EdgeData &rev_edge_data1 = m_node_based_graph->GetEdgeData(reverse_e1);
 
-        if ((m_node_based_graph->FindEdge(u, w) != m_node_based_graph->EndEdges(u)) ||
-            (m_node_based_graph->FindEdge(w, u) != m_node_based_graph->EndEdges(w)))
+        if ((m_node_based_graph->FindEdge(node_u, node_w) != m_node_based_graph->EndEdges(node_u)) ||
+            (m_node_based_graph->FindEdge(node_w, node_u) != m_node_based_graph->EndEdges(node_w)))
         {
             continue;
         }
@@ -366,7 +366,7 @@ void EdgeBasedGraphFactory::CompressGeometry()
             BOOST_ASSERT(0 != forward_weight2);
 
             const bool add_traffic_signal_penalty =
-                (m_traffic_lights.find(v) != m_traffic_lights.end());
+                (m_traffic_lights.find(node_v) != m_traffic_lights.end());
 
             // add weight of e2's to e1
             m_node_based_graph->GetEdgeData(forward_e1).distance += fwd_edge_data2.distance;
@@ -374,43 +374,47 @@ void EdgeBasedGraphFactory::CompressGeometry()
             if (add_traffic_signal_penalty)
             {
                 m_node_based_graph->GetEdgeData(forward_e1).distance +=
-                    speed_profile.trafficSignalPenalty;
+                    speed_profile.traffic_signal_penalty;
                 m_node_based_graph->GetEdgeData(reverse_e1).distance +=
-                    speed_profile.trafficSignalPenalty;
+                    speed_profile.traffic_signal_penalty;
             }
 
             // extend e1's to targets of e2's
-            m_node_based_graph->SetTarget(forward_e1, w);
-            m_node_based_graph->SetTarget(reverse_e1, u);
+            m_node_based_graph->SetTarget(forward_e1, node_w);
+            m_node_based_graph->SetTarget(reverse_e1, node_u);
 
             // remove e2's (if bidir, otherwise only one)
-            m_node_based_graph->DeleteEdge(v, forward_e2);
-            m_node_based_graph->DeleteEdge(v, reverse_e2);
+            m_node_based_graph->DeleteEdge(node_v, forward_e2);
+            m_node_based_graph->DeleteEdge(node_v, reverse_e2);
 
             // update any involved turn restrictions
-            m_restriction_map->FixupStartingTurnRestriction(u, v, w);
-            m_restriction_map->FixupArrivingTurnRestriction(u, v, w);
+            m_restriction_map->FixupStartingTurnRestriction(node_u, node_v, node_w);
+            m_restriction_map->FixupArrivingTurnRestriction(node_u, node_v,
+                                                            node_w,
+                                                            m_node_based_graph);
 
-            m_restriction_map->FixupStartingTurnRestriction(w, v, u);
-            m_restriction_map->FixupArrivingTurnRestriction(w, v, u);
+            m_restriction_map->FixupStartingTurnRestriction(node_w, node_v, node_u);
+            m_restriction_map->FixupArrivingTurnRestriction(node_w,
+                                                            node_v,
+                                                            node_u, m_node_based_graph);
 
             // store compressed geometry in container
             m_geometry_compressor.CompressEdge(
                 forward_e1,
                 forward_e2,
-                v,
-                w,
+                node_v,
+                node_w,
                 forward_weight1 +
-                    (add_traffic_signal_penalty ? speed_profile.trafficSignalPenalty : 0),
+                    (add_traffic_signal_penalty ? speed_profile.traffic_signal_penalty : 0),
                 forward_weight2);
             m_geometry_compressor.CompressEdge(
                 reverse_e1,
                 reverse_e2,
-                v,
-                u,
+                node_v,
+                node_u,
                 reverse_weight1,
                 reverse_weight2 +
-                    (add_traffic_signal_penalty ? speed_profile.trafficSignalPenalty : 0));
+                    (add_traffic_signal_penalty ? speed_profile.traffic_signal_penalty : 0));
             ++removed_node_count;
 
             BOOST_ASSERT(m_node_based_graph->GetEdgeData(forward_e1).nameID ==
@@ -422,7 +426,8 @@ void EdgeBasedGraphFactory::CompressGeometry()
 
     unsigned new_node_count = 0;
     unsigned new_edge_count = 0;
-    for (unsigned i = 0; i < m_node_based_graph->GetNumberOfNodes(); ++i)
+
+    for(const auto i : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
     {
         if (m_node_based_graph->GetOutDegree(i) > 0)
         {
@@ -438,16 +443,15 @@ void EdgeBasedGraphFactory::CompressGeometry()
 }
 
 /**
- * Writes the id of the edge in the edge expanded graph (into the egde in the node based graph)
+ * Writes the id of the edge in the edge expanded graph (into the edge in the node based graph)
  */
 void EdgeBasedGraphFactory::RenumberEdges()
 {
     // renumber edge based node IDs
     unsigned numbered_edges_count = 0;
-    for (NodeID current_node = 0; current_node < m_node_based_graph->GetNumberOfNodes();
-         ++current_node)
+    for (const auto current_node : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
     {
-        for (EdgeID current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
+        for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
         {
             EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
             if (!edge_data.forward)
@@ -470,33 +474,31 @@ void EdgeBasedGraphFactory::RenumberEdges()
  */
 void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
 {
-    SimpleLogger().Write() << "Identifying components of the road network";
+    SimpleLogger().Write() << "Identifying components of the (compressed) road network";
 
     // Run a BFS on the undirected graph and identify small components
-    BFSComponentExplorer<NodeBasedDynamicGraph> component_explorer(
-        *m_node_based_graph, *m_restriction_map, m_barrier_nodes);
+    TarjanSCC<NodeBasedDynamicGraph> component_explorer(
+        m_node_based_graph, *m_restriction_map, m_barrier_nodes);
 
     component_explorer.run();
 
-    SimpleLogger().Write() << "identified: " << component_explorer.GetNumberOfComponents()
-                           << " many components";
+    SimpleLogger().Write() << "identified: " << component_explorer.get_number_of_components() - removed_node_count
+                           << " (compressed) components";
+    SimpleLogger().Write() << "identified " << component_explorer.get_size_one_count() - removed_node_count
+                           << " (compressed) SCCs of size 1";
     SimpleLogger().Write() << "generating edge-expanded nodes";
 
-    Percent p(m_node_based_graph->GetNumberOfNodes());
+    Percent progress(m_node_based_graph->GetNumberOfNodes());
 
     // loop over all edges and generate new set of nodes
-    for (NodeID u = 0, end = m_node_based_graph->GetNumberOfNodes(); u < end; ++u)
+    for (const auto u : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
     {
         BOOST_ASSERT(u != SPECIAL_NODEID);
         BOOST_ASSERT(u < m_node_based_graph->GetNumberOfNodes());
-        p.printIncrement();
+        progress.printStatus(u);
         for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
         {
             const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
-            if (edge_data.edgeBasedNodeID == SPECIAL_NODEID)
-            {
-                // continue;
-            }
             BOOST_ASSERT(e1 != SPECIAL_EDGEID);
             const NodeID v = m_node_based_graph->GetTarget(e1);
 
@@ -508,15 +510,30 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
             }
 
             BOOST_ASSERT(u < v);
-            BOOST_ASSERT(edge_data.type != SHRT_MAX);
 
             // Note: edges that end on barrier nodes or on a turn restriction
             // may actually be in two distinct components. We choose the smallest
-            const unsigned size_of_component = std::min(component_explorer.GetComponentSize(u),
-                                                        component_explorer.GetComponentSize(v));
+            const unsigned size_of_component = std::min(component_explorer.get_component_size(u),
+                                                        component_explorer.get_component_size(v));
+
+            const unsigned id_of_smaller_component = [u,v,&component_explorer] {
+                if (component_explorer.get_component_size(u) < component_explorer.get_component_size(v))
+                {
+                    return component_explorer.get_component_id(u);
+                }
+                return component_explorer.get_component_id(v);
+            }();
 
             const bool component_is_tiny = (size_of_component < 1000);
-            InsertEdgeBasedNode(u, v, e1, component_is_tiny);
+
+            if (edge_data.edgeBasedNodeID == SPECIAL_NODEID)
+            {
+                InsertEdgeBasedNode(v, u, (component_is_tiny ? id_of_smaller_component + 1 : 0));
+            }
+            else
+            {
+                InsertEdgeBasedNode(u, v, (component_is_tiny ? id_of_smaller_component + 1 : 0));
+            }
         }
     }
 
@@ -552,11 +569,12 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
     unsigned skipped_barrier_turns_counter = 0;
     unsigned compressed = 0;
 
-    Percent p(m_node_based_graph->GetNumberOfNodes());
+    Percent progress(m_node_based_graph->GetNumberOfNodes());
 
-    for (NodeID u = 0, end = m_node_based_graph->GetNumberOfNodes(); u < end; ++u)
+    for (const auto u : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
     {
-        for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
+        progress.printStatus(u);
+        for (const EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
         {
             if (!m_node_based_graph->GetEdgeData(e1).forward)
             {
@@ -569,7 +587,7 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
                 m_restriction_map->CheckForEmanatingIsOnlyTurn(u, v);
             const bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end());
 
-            for (EdgeID e2 : m_node_based_graph->GetAdjacentEdgeRange(v))
+            for (const EdgeID e2 : m_node_based_graph->GetAdjacentEdgeRange(v))
             {
                 if (!m_node_based_graph->GetEdgeData(e2).forward)
                 {
@@ -625,15 +643,27 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
                 unsigned distance = edge_data1.distance;
                 if (m_traffic_lights.find(v) != m_traffic_lights.end())
                 {
-                    distance += speed_profile.trafficSignalPenalty;
+                    distance += speed_profile.traffic_signal_penalty;
                 }
-                const double angle = GetAngleBetweenThreeFixedPointCoordinates(
-                m_node_info_list[u], m_node_info_list[v], m_node_info_list[w]);
-                const int turn_penalty = GetTurnPenalty(angle, lua_state);
-                TurnInstruction turn_instruction = AnalyzeTurn(u, v, w, angle);
+
+                // unpack last node of first segment if packed
+                const auto first_coordinate = m_node_info_list[(m_geometry_compressor.HasEntryForID(e1) ?
+                                        m_geometry_compressor.GetLastNodeIDOfBucket(e1) :
+                                        u)];
+
+                // unpack first node of second segment if packed
+                const auto third_coordinate = m_node_info_list[(m_geometry_compressor.HasEntryForID(e2) ?
+                                        m_geometry_compressor.GetFirstNodeIDOfBucket(e2) :
+                                        w)];
+
+                const double turn_angle = ComputeAngle::OfThreeFixedPointCoordinates(
+                    first_coordinate, m_node_info_list[v], third_coordinate);
+
+                const int turn_penalty = GetTurnPenalty(turn_angle, lua_state);
+                TurnInstruction turn_instruction = AnalyzeTurn(u, v, w, turn_angle);
                 if (turn_instruction == TurnInstruction::UTurn)
                 {
-                    distance += speed_profile.uTurnPenalty;
+                    distance += speed_profile.u_turn_penalty;
                 }
                 distance += turn_penalty;
 
@@ -648,7 +678,8 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
                     (edge_is_compressed ? m_geometry_compressor.GetPositionForID(e1) : v),
                     edge_data1.nameID,
                     turn_instruction,
-                    edge_is_compressed);
+                    edge_is_compressed,
+                    edge_data2.travel_mode);
 
                 ++original_edges_counter;
 
@@ -668,7 +699,6 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
                                                                   false));
             }
         }
-        p.printIncrement();
     }
     FlushVectorToStream(edge_data_file, original_edge_data_vector);
 
@@ -702,37 +732,28 @@ int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) co
     return 0;
 }
 
-TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u,
-                                                   const NodeID v,
-                                                   const NodeID w,
-                                                   double angle)
+TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID node_u,
+                                                   const NodeID node_v,
+                                                   const NodeID node_w,
+                                                   const double angle)
     const
 {
-    if (u == w)
+    if (node_u == node_w)
     {
         return TurnInstruction::UTurn;
     }
 
-    const EdgeID edge1 = m_node_based_graph->FindEdge(u, v);
-    const EdgeID edge2 = m_node_based_graph->FindEdge(v, w);
+    const EdgeID edge1 = m_node_based_graph->FindEdge(node_u, node_v);
+    const EdgeID edge2 = m_node_based_graph->FindEdge(node_v, node_w);
 
     const EdgeData &data1 = m_node_based_graph->GetEdgeData(edge1);
     const EdgeData &data2 = m_node_based_graph->GetEdgeData(edge2);
 
-    if (!data1.contraFlow && data2.contraFlow)
-    {
-        return TurnInstruction::EnterAgainstAllowedDirection;
-    }
-    if (data1.contraFlow && !data2.contraFlow)
-    {
-        return TurnInstruction::LeaveAgainstAllowedDirection;
-    }
-
     // roundabouts need to be handled explicitely
     if (data1.roundabout && data2.roundabout)
     {
         // Is a turn possible? If yes, we stay on the roundabout!
-        if (1 == m_node_based_graph->GetDirectedOutDegree(v))
+        if (1 == m_node_based_graph->GetDirectedOutDegree(node_v))
         {
             // No turn possible.
             return TurnInstruction::NoTurn;
@@ -760,11 +781,7 @@ TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u,
     {
         // TODO: Here we should also do a small graph exploration to check for
         //      more complex situations
-        if (0 != data1.nameID)
-        {
-            return TurnInstruction::NoTurn;
-        }
-        else if (m_node_based_graph->GetOutDegree(v) <= 2)
+        if (0 != data1.nameID || m_node_based_graph->GetOutDegree(node_v) <= 2)
         {
             return TurnInstruction::NoTurn;
         }
diff --git a/Contractor/EdgeBasedGraphFactory.h b/contractor/edge_based_graph_factory.hpp
similarity index 76%
rename from Contractor/EdgeBasedGraphFactory.h
rename to contractor/edge_based_graph_factory.hpp
index cf489c5..95b65ba 100644
--- a/Contractor/EdgeBasedGraphFactory.h
+++ b/contractor/edge_based_graph_factory.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -27,18 +27,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 //  This class constructs the edge-expanded routing graph
 
-#ifndef EDGEBASEDGRAPHFACTORY_H_
-#define EDGEBASEDGRAPHFACTORY_H_
+#ifndef EDGE_BASED_GRAPH_FACTORY_HPP_
+#define EDGE_BASED_GRAPH_FACTORY_HPP_
 
+#include "geometry_compressor.hpp"
 #include "../typedefs.h"
-#include "../DataStructures/DeallocatingVector.h"
-#include "../DataStructures/EdgeBasedNode.h"
-#include "../DataStructures/OriginalEdgeData.h"
-#include "../DataStructures/QueryNode.h"
-#include "../DataStructures/TurnInstructions.h"
-#include "../DataStructures/NodeBasedGraph.h"
-#include "../DataStructures/RestrictionMap.h"
-#include "GeometryCompressor.h"
+#include "../data_structures/deallocating_vector.hpp"
+#include "../data_structures/edge_based_node.hpp"
+#include "../data_structures/original_edge_data.hpp"
+#include "../data_structures/query_node.hpp"
+#include "../data_structures/turn_instructions.hpp"
+#include "../data_structures/node_based_graph.hpp"
+#include "../data_structures/restriction_map.hpp"
 
 #include <algorithm>
 #include <iosfwd>
@@ -63,7 +63,7 @@ class EdgeBasedGraphFactory
                                    std::unique_ptr<RestrictionMap> restricion_map,
                                    std::vector<NodeID> &barrier_node_list,
                                    std::vector<NodeID> &traffic_light_node_list,
-                                   std::vector<NodeInfo> &m_node_info_list,
+                                   std::vector<QueryNode> &node_info_list,
                                    SpeedProfileProperties &speed_profile);
 
     void Run(const std::string &original_edge_data_filename,
@@ -74,7 +74,7 @@ class EdgeBasedGraphFactory
 
     void GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes);
 
-    TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, double angle) const;
+    TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, const double angle) const;
 
     int GetTurnPenalty(double angle, lua_State *lua_state) const;
 
@@ -83,21 +83,21 @@ class EdgeBasedGraphFactory
     struct SpeedProfileProperties
     {
         SpeedProfileProperties()
-            : trafficSignalPenalty(0), uTurnPenalty(0), has_turn_penalty_function(false)
+            : traffic_signal_penalty(0), u_turn_penalty(0), has_turn_penalty_function(false)
         {
         }
 
-        int trafficSignalPenalty;
-        int uTurnPenalty;
+        int traffic_signal_penalty;
+        int u_turn_penalty;
         bool has_turn_penalty_function;
     } speed_profile;
 
   private:
-    typedef NodeBasedDynamicGraph::EdgeData EdgeData;
+    using EdgeData = NodeBasedDynamicGraph::EdgeData;
 
     unsigned m_number_of_edge_based_nodes;
 
-    std::vector<NodeInfo> m_node_info_list;
+    std::vector<QueryNode> m_node_info_list;
     std::vector<EdgeBasedNode> m_edge_based_node_list;
     DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
 
@@ -115,12 +115,14 @@ class EdgeBasedGraphFactory
     void GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
                                    lua_State *lua_state);
 
-    void InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool belongsToTinyComponent);
+    void InsertEdgeBasedNode(const NodeID u, const NodeID v, const unsigned component_id);
 
     void FlushVectorToStream(std::ofstream &edge_data_file,
                              std::vector<OriginalEdgeData> &original_edge_data_vector) const;
 
-    unsigned max_id;
+    NodeID max_id;
+    std::size_t removed_node_count;
+
 };
 
-#endif /* EDGEBASEDGRAPHFACTORY_H_ */
+#endif /* EDGE_BASED_GRAPH_FACTORY_HPP_ */
diff --git a/Contractor/GeometryCompressor.cpp b/contractor/geometry_compressor.cpp
similarity index 93%
rename from Contractor/GeometryCompressor.cpp
rename to contractor/geometry_compressor.cpp
index 7c51910..9458c44 100644
--- a/Contractor/GeometryCompressor.cpp
+++ b/contractor/geometry_compressor.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "GeometryCompressor.h"
-#include "../Util/SimpleLogger.h"
+#include "geometry_compressor.hpp"
+#include "../Util/simple_logger.hpp"
 
 #include <boost/assert.hpp>
 #include <boost/filesystem.hpp>
@@ -225,3 +225,17 @@ GeometryCompressor::GetBucketReference(const EdgeID edge_id) const
     const unsigned index = m_edge_id_to_list_index_map.at(edge_id);
     return m_compressed_geometries.at(index);
 }
+
+    NodeID GeometryCompressor::GetFirstNodeIDOfBucket(const EdgeID edge_id) const
+    {
+        const auto &bucket = GetBucketReference(edge_id);
+        BOOST_ASSERT(bucket.size() >= 2);
+        return bucket[1].first;
+    }
+    NodeID GeometryCompressor::GetLastNodeIDOfBucket(const EdgeID edge_id) const
+    {
+        const auto &bucket = GetBucketReference(edge_id);
+        BOOST_ASSERT(bucket.size() >= 2);
+        return bucket[bucket.size()-2].first;
+    }
+
diff --git a/Contractor/GeometryCompressor.h b/contractor/geometry_compressor.hpp
similarity index 86%
copy from Contractor/GeometryCompressor.h
copy to contractor/geometry_compressor.hpp
index 7c4fba4..dd5748d 100644
--- a/Contractor/GeometryCompressor.h
+++ b/contractor/geometry_compressor.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,6 +25,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
+#ifndef GEOMETRY_COMPRESSOR_HPP_
+#define GEOMETRY_COMPRESSOR_HPP_
+
 #include "../typedefs.h"
 
 #include <unordered_map>
@@ -32,13 +35,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <string>
 #include <vector>
 
-#ifndef GEOMETRY_COMPRESSOR_H
-#define GEOMETRY_COMPRESSOR_H
-
 class GeometryCompressor
 {
   public:
-    typedef std::pair<NodeID, EdgeWeight> CompressedNode;
+    using CompressedNode = std::pair<NodeID, EdgeWeight>;
 
     GeometryCompressor();
     void CompressEdge(const EdgeID surviving_edge_id,
@@ -54,6 +54,8 @@ class GeometryCompressor
     unsigned GetPositionForID(const EdgeID edge_id) const;
     const std::vector<GeometryCompressor::CompressedNode> &
     GetBucketReference(const EdgeID edge_id) const;
+    NodeID GetFirstNodeIDOfBucket(const EdgeID edge_id) const;
+    NodeID GetLastNodeIDOfBucket(const EdgeID edge_id) const;
 
   private:
     void IncreaseFreeList();
@@ -62,4 +64,4 @@ class GeometryCompressor
     std::unordered_map<EdgeID, unsigned> m_edge_id_to_list_index_map;
 };
 
-#endif // GEOMETRY_COMPRESSOR_H
+#endif // GEOMETRY_COMPRESSOR_HPP_
diff --git a/contractor/processing_chain.cpp b/contractor/processing_chain.cpp
new file mode 100644
index 0000000..23d406b
--- /dev/null
+++ b/contractor/processing_chain.cpp
@@ -0,0 +1,581 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "processing_chain.hpp"
+
+#include "contractor.hpp"
+
+#include "../algorithms/crc32_processor.hpp"
+#include "../data_structures/deallocating_vector.hpp"
+#include "../data_structures/static_rtree.hpp"
+#include "../data_structures/restriction_map.hpp"
+
+#include "../Util/git_sha.hpp"
+#include "../Util/graph_loader.hpp"
+#include "../Util/integer_range.hpp"
+#include "../Util/lua_util.hpp"
+#include "../Util/make_unique.hpp"
+#include "../Util/osrm_exception.hpp"
+#include "../Util/simple_logger.hpp"
+#include "../Util/string_util.hpp"
+#include "../Util/timing_util.hpp"
+#include "../typedefs.h"
+
+#include <boost/filesystem/fstream.hpp>
+#include <boost/program_options.hpp>
+
+#include <tbb/task_scheduler_init.h>
+#include <tbb/parallel_sort.h>
+
+#include <chrono>
+#include <memory>
+#include <string>
+#include <thread>
+#include <vector>
+
+Prepare::Prepare() : requested_num_threads(1) {}
+
+Prepare::~Prepare() {}
+
+int Prepare::Process(int argc, char *argv[])
+{
+    LogPolicy::GetInstance().Unmute();
+    TIMER_START(preparing);
+    TIMER_START(expansion);
+
+    if (!ParseArguments(argc, argv))
+    {
+        return 0;
+    }
+    if (!boost::filesystem::is_regular_file(input_path))
+    {
+        SimpleLogger().Write(logWARNING) << "Input file " << input_path.string() << " not found!";
+        return 1;
+    }
+
+    if (!boost::filesystem::is_regular_file(profile_path))
+    {
+        SimpleLogger().Write(logWARNING) << "Profile " << profile_path.string() << " not found!";
+        return 1;
+    }
+
+    if (1 > requested_num_threads)
+    {
+        SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
+        return 1;
+    }
+
+    const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
+
+    SimpleLogger().Write() << "Input file: " << input_path.filename().string();
+    SimpleLogger().Write() << "Restrictions file: " << restrictions_path.filename().string();
+    SimpleLogger().Write() << "Profile: " << profile_path.filename().string();
+    SimpleLogger().Write() << "Threads: " << requested_num_threads;
+    if (recommended_num_threads != requested_num_threads)
+    {
+        SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
+                                         << recommended_num_threads
+                                         << "! This setting may have performance side-effects.";
+    }
+
+    tbb::task_scheduler_init init(requested_num_threads);
+
+    LogPolicy::GetInstance().Unmute();
+
+    FingerPrint fingerprint_orig;
+    CheckRestrictionsFile(fingerprint_orig);
+
+    boost::filesystem::ifstream input_stream(input_path, std::ios::in | std::ios::binary);
+
+    node_filename = input_path.string() + ".nodes";
+    edge_out = input_path.string() + ".edges";
+    geometry_filename = input_path.string() + ".geometry";
+    graph_out = input_path.string() + ".hsgr";
+    rtree_nodes_path = input_path.string() + ".ramIndex";
+    rtree_leafs_path = input_path.string() + ".fileIndex";
+
+    /*** Setup Scripting Environment ***/
+    // Create a new lua state
+    lua_State *lua_state = luaL_newstate();
+
+    // Connect LuaBind to this lua state
+    luabind::open(lua_state);
+
+    EdgeBasedGraphFactory::SpeedProfileProperties speed_profile;
+
+    if (!SetupScriptingEnvironment(lua_state, speed_profile))
+    {
+        return 1;
+    }
+
+#ifdef WIN32
+#pragma message("Memory consumption on Windows can be higher due to different bit packing")
+#else
+    static_assert(sizeof(ImportEdge) == 20,
+                  "changing ImportEdge type has influence on memory consumption!");
+#endif
+    NodeID number_of_node_based_nodes =
+        readBinaryOSRMGraphFromStream(input_stream,
+                                      edge_list,
+                                      barrier_node_list,
+                                      traffic_light_list,
+                                      &internal_to_external_node_map,
+                                      restriction_list);
+    input_stream.close();
+
+    if (edge_list.empty())
+    {
+        SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
+        return 1;
+    }
+
+    SimpleLogger().Write() << restriction_list.size() << " restrictions, "
+                           << barrier_node_list.size() << " bollard nodes, "
+                           << traffic_light_list.size() << " traffic lights";
+
+    std::vector<EdgeBasedNode> node_based_edge_list;
+    unsigned number_of_edge_based_nodes = 0;
+    DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
+
+    // init node_based_edge_list, edge_based_edge_list by edgeList
+    number_of_edge_based_nodes = BuildEdgeExpandedGraph(lua_state,
+                                                        number_of_node_based_nodes,
+                                                        node_based_edge_list,
+                                                        edge_based_edge_list,
+                                                        speed_profile);
+    lua_close(lua_state);
+
+    TIMER_STOP(expansion);
+
+    BuildRTree(node_based_edge_list);
+
+    RangebasedCRC32 crc32;
+    if (crc32.using_hardware())
+    {
+        SimpleLogger().Write() << "using hardware based CRC32 computation";
+    }
+    else
+    {
+        SimpleLogger().Write() << "using software based CRC32 computation";
+    }
+
+    const unsigned crc32_value = crc32(node_based_edge_list);
+    node_based_edge_list.clear();
+    node_based_edge_list.shrink_to_fit();
+    SimpleLogger().Write() << "CRC32: " << crc32_value;
+
+    WriteNodeMapping();
+
+    /***
+     * Contracting the edge-expanded graph
+     */
+
+    SimpleLogger().Write() << "initializing contractor";
+    auto contractor =
+        osrm::make_unique<Contractor>(number_of_edge_based_nodes, edge_based_edge_list);
+
+    TIMER_START(contraction);
+    contractor->Run();
+    TIMER_STOP(contraction);
+
+    SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
+
+    DeallocatingVector<QueryEdge> contracted_edge_list;
+    contractor->GetEdges(contracted_edge_list);
+    contractor.reset();
+
+    /***
+     * Sorting contracted edges in a way that the static query graph can read some in in-place.
+     */
+
+    tbb::parallel_sort(contracted_edge_list.begin(), contracted_edge_list.end());
+    const unsigned contracted_edge_count = contracted_edge_list.size();
+    SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count
+                           << " edges";
+
+    boost::filesystem::ofstream hsgr_output_stream(graph_out, std::ios::binary);
+    hsgr_output_stream.write((char *)&fingerprint_orig, sizeof(FingerPrint));
+    const unsigned max_used_node_id = 1 + [&contracted_edge_list]
+    {
+        unsigned tmp_max = 0;
+        for (const QueryEdge &edge : contracted_edge_list)
+        {
+            BOOST_ASSERT(SPECIAL_NODEID != edge.source);
+            BOOST_ASSERT(SPECIAL_NODEID != edge.target);
+            tmp_max = std::max(tmp_max, edge.source);
+            tmp_max = std::max(tmp_max, edge.target);
+        }
+        return tmp_max;
+    }();
+
+    SimpleLogger().Write(logDEBUG) << "input graph has " << number_of_edge_based_nodes << " nodes";
+    SimpleLogger().Write(logDEBUG) << "contracted graph has " << max_used_node_id << " nodes";
+
+    std::vector<StaticGraph<EdgeData>::NodeArrayEntry> node_array;
+    node_array.resize(number_of_edge_based_nodes + 1);
+
+    SimpleLogger().Write() << "Building node array";
+    StaticGraph<EdgeData>::EdgeIterator edge = 0;
+    StaticGraph<EdgeData>::EdgeIterator position = 0;
+    StaticGraph<EdgeData>::EdgeIterator last_edge = edge;
+
+    // initializing 'first_edge'-field of nodes:
+    for (const auto node : osrm::irange(0u, max_used_node_id))
+    {
+        last_edge = edge;
+        while ((edge < contracted_edge_count) && (contracted_edge_list[edge].source == node))
+        {
+            ++edge;
+        }
+        node_array[node].first_edge = position; //=edge
+        position += edge - last_edge;           // remove
+    }
+
+    for (const auto sentinel_counter : osrm::irange<unsigned>(max_used_node_id, node_array.size()))
+    {
+        // sentinel element, guarded against underflow
+        node_array[sentinel_counter].first_edge = contracted_edge_count;
+    }
+
+    SimpleLogger().Write() << "Serializing node array";
+
+    const unsigned node_array_size = node_array.size();
+    // serialize crc32, aka checksum
+    hsgr_output_stream.write((char *)&crc32_value, sizeof(unsigned));
+    // serialize number of nodes
+    hsgr_output_stream.write((char *)&node_array_size, sizeof(unsigned));
+    // serialize number of edges
+    hsgr_output_stream.write((char *)&contracted_edge_count, sizeof(unsigned));
+    // serialize all nodes
+    if (node_array_size > 0)
+    {
+        hsgr_output_stream.write((char *)&node_array[0],
+                                 sizeof(StaticGraph<EdgeData>::NodeArrayEntry) * node_array_size);
+    }
+    // serialize all edges
+
+    SimpleLogger().Write() << "Building edge array";
+    edge = 0;
+    int number_of_used_edges = 0;
+
+    StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
+    for (const auto edge : osrm::irange<std::size_t>(0, contracted_edge_list.size()))
+    {
+        // no eigen loops
+        BOOST_ASSERT(contracted_edge_list[edge].source != contracted_edge_list[edge].target);
+        current_edge.target = contracted_edge_list[edge].target;
+        current_edge.data = contracted_edge_list[edge].data;
+
+        // every target needs to be valid
+        BOOST_ASSERT(current_edge.target < max_used_node_id);
+#ifndef NDEBUG
+        if (current_edge.data.distance <= 0)
+        {
+            SimpleLogger().Write(logWARNING) << "Edge: " << edge
+                                             << ",source: " << contracted_edge_list[edge].source
+                                             << ", target: " << contracted_edge_list[edge].target
+                                             << ", dist: " << current_edge.data.distance;
+
+            SimpleLogger().Write(logWARNING) << "Failed at adjacency list of node "
+                                             << contracted_edge_list[edge].source << "/"
+                                             << node_array.size() - 1;
+            return 1;
+        }
+#endif
+        hsgr_output_stream.write((char *)&current_edge,
+                                 sizeof(StaticGraph<EdgeData>::EdgeArrayEntry));
+
+        ++number_of_used_edges;
+    }
+    hsgr_output_stream.close();
+
+    TIMER_STOP(preparing);
+
+    SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
+    SimpleLogger().Write() << "Expansion  : " << (number_of_node_based_nodes / TIMER_SEC(expansion))
+                           << " nodes/sec and "
+                           << (number_of_edge_based_nodes / TIMER_SEC(expansion)) << " edges/sec";
+
+    SimpleLogger().Write() << "Contraction: "
+                           << (number_of_edge_based_nodes / TIMER_SEC(contraction))
+                           << " nodes/sec and " << number_of_used_edges / TIMER_SEC(contraction)
+                           << " edges/sec";
+
+    node_array.clear();
+    SimpleLogger().Write() << "finished preprocessing";
+
+    return 0;
+}
+
+/**
+ \brief Parses command line arguments
+ \param argc count of arguments
+ \param argv array of arguments
+ \param result [out] value for exit return value
+ \return true if everything is ok, false if need to terminate execution
+*/
+bool Prepare::ParseArguments(int argc, char *argv[])
+{
+    // declare a group of options that will be allowed only on command line
+    boost::program_options::options_description generic_options("Options");
+    generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
+        "config,c",
+        boost::program_options::value<boost::filesystem::path>(&config_file_path)
+            ->default_value("contractor.ini"),
+        "Path to a configuration file.");
+
+    // declare a group of options that will be allowed both on command line and in config file
+    boost::program_options::options_description config_options("Configuration");
+    config_options.add_options()(
+        "restrictions,r",
+        boost::program_options::value<boost::filesystem::path>(&restrictions_path),
+        "Restrictions file in .osrm.restrictions format")(
+        "profile,p",
+        boost::program_options::value<boost::filesystem::path>(&profile_path)
+            ->default_value("profile.lua"),
+        "Path to LUA routing profile")(
+        "threads,t",
+        boost::program_options::value<unsigned int>(&requested_num_threads)
+            ->default_value(tbb::task_scheduler_init::default_num_threads()),
+        "Number of threads to use");
+
+    // hidden options, will be allowed both on command line and in config file, but will not be
+    // shown to the user
+    boost::program_options::options_description hidden_options("Hidden options");
+    hidden_options.add_options()(
+        "input,i",
+        boost::program_options::value<boost::filesystem::path>(&input_path),
+        "Input file in .osm, .osm.bz2 or .osm.pbf format");
+
+    // positional option
+    boost::program_options::positional_options_description positional_options;
+    positional_options.add("input", 1);
+
+    // combine above options for parsing
+    boost::program_options::options_description cmdline_options;
+    cmdline_options.add(generic_options).add(config_options).add(hidden_options);
+
+    boost::program_options::options_description config_file_options;
+    config_file_options.add(config_options).add(hidden_options);
+
+    boost::program_options::options_description visible_options(
+        "Usage: " + boost::filesystem::basename(argv[0]) + " <input.osrm> [options]");
+    visible_options.add(generic_options).add(config_options);
+
+    // parse command line options
+    boost::program_options::variables_map option_variables;
+    boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
+                                      .options(cmdline_options)
+                                      .positional(positional_options)
+                                      .run(),
+                                  option_variables);
+
+    const auto& temp_config_path = option_variables["config"].as<boost::filesystem::path>();
+    if (boost::filesystem::is_regular_file(temp_config_path))
+    {
+        boost::program_options::store(boost::program_options::parse_config_file<char>(temp_config_path.string().c_str(), cmdline_options, true),
+                                      option_variables);
+    }
+
+    if (option_variables.count("version"))
+    {
+        SimpleLogger().Write() << g_GIT_DESCRIPTION;
+        return false;
+    }
+
+    if (option_variables.count("help"))
+    {
+        SimpleLogger().Write() << "\n" << visible_options;
+        return false;
+    }
+
+    boost::program_options::notify(option_variables);
+
+    if (!option_variables.count("restrictions"))
+    {
+        restrictions_path = std::string(input_path.string() + ".restrictions");
+    }
+
+    if (!option_variables.count("input"))
+    {
+        SimpleLogger().Write() << "\n" << visible_options;
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ \brief Loads and checks file UUIDs
+*/
+void Prepare::CheckRestrictionsFile(FingerPrint &fingerprint_orig)
+{
+    boost::filesystem::ifstream restriction_stream(restrictions_path, std::ios::binary);
+    FingerPrint fingerprint_loaded;
+    unsigned number_of_usable_restrictions = 0;
+    restriction_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
+    if (!fingerprint_loaded.TestPrepare(fingerprint_orig))
+    {
+        SimpleLogger().Write(logWARNING) << ".restrictions was prepared with different build.\n"
+                                            "Reprocess to get rid of this warning.";
+    }
+
+    restriction_stream.read((char *)&number_of_usable_restrictions, sizeof(unsigned));
+    restriction_list.resize(number_of_usable_restrictions);
+    if (number_of_usable_restrictions > 0)
+    {
+        restriction_stream.read((char *)&(restriction_list[0]),
+                                number_of_usable_restrictions * sizeof(TurnRestriction));
+    }
+    restriction_stream.close();
+}
+
+/**
+    \brief Setups scripting environment (lua-scripting)
+    Also initializes speed profile.
+*/
+bool
+Prepare::SetupScriptingEnvironment(lua_State *lua_state,
+                                   EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile)
+{
+    // open utility libraries string library;
+    luaL_openlibs(lua_state);
+
+    // adjust lua load path
+    luaAddScriptFolderToLoadPath(lua_state, profile_path.string().c_str());
+
+    // Now call our function in a lua script
+    if (0 != luaL_dofile(lua_state, profile_path.string().c_str()))
+    {
+        std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
+        return false;
+    }
+
+    if (0 != luaL_dostring(lua_state, "return traffic_signal_penalty\n"))
+    {
+        std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
+        return false;
+    }
+    speed_profile.traffic_signal_penalty = 10 * lua_tointeger(lua_state, -1);
+    SimpleLogger().Write(logDEBUG)
+        << "traffic_signal_penalty: " << speed_profile.traffic_signal_penalty;
+
+    if (0 != luaL_dostring(lua_state, "return u_turn_penalty\n"))
+    {
+        std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
+        return false;
+    }
+
+    speed_profile.u_turn_penalty = 10 * lua_tointeger(lua_state, -1);
+    speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function");
+
+    return true;
+}
+
+/**
+ \brief Building an edge-expanded graph from node-based input and turn restrictions
+*/
+std::size_t
+Prepare::BuildEdgeExpandedGraph(lua_State *lua_state,
+                                NodeID number_of_node_based_nodes,
+                                std::vector<EdgeBasedNode> &node_based_edge_list,
+                                DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
+                                EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile)
+{
+    SimpleLogger().Write() << "Generating edge-expanded graph representation";
+    std::shared_ptr<NodeBasedDynamicGraph> node_based_graph =
+        NodeBasedDynamicGraphFromImportEdges(number_of_node_based_nodes, edge_list);
+    std::unique_ptr<RestrictionMap> restriction_map = osrm::make_unique<RestrictionMap>(restriction_list);
+    std::shared_ptr<EdgeBasedGraphFactory> edge_based_graph_factory =
+        std::make_shared<EdgeBasedGraphFactory>(node_based_graph,
+                                                std::move(restriction_map),
+                                                barrier_node_list,
+                                                traffic_light_list,
+                                                internal_to_external_node_map,
+                                                speed_profile);
+    edge_list.clear();
+    edge_list.shrink_to_fit();
+
+    edge_based_graph_factory->Run(edge_out, geometry_filename, lua_state);
+
+    restriction_list.clear();
+    restriction_list.shrink_to_fit();
+    barrier_node_list.clear();
+    barrier_node_list.shrink_to_fit();
+    traffic_light_list.clear();
+    traffic_light_list.shrink_to_fit();
+
+    const std::size_t number_of_edge_based_nodes =
+        edge_based_graph_factory->GetNumberOfEdgeBasedNodes();
+
+    BOOST_ASSERT(number_of_edge_based_nodes != std::numeric_limits<unsigned>::max());
+#ifndef WIN32
+    static_assert(sizeof(EdgeBasedEdge) == 16,
+                  "changing ImportEdge type has influence on memory consumption!");
+#endif
+
+    edge_based_graph_factory->GetEdgeBasedEdges(edge_based_edge_list);
+    edge_based_graph_factory->GetEdgeBasedNodes(node_based_edge_list);
+
+    edge_based_graph_factory.reset();
+    node_based_graph.reset();
+
+    return number_of_edge_based_nodes;
+}
+
+/**
+  \brief Writing info on original (node-based) nodes
+ */
+void Prepare::WriteNodeMapping()
+{
+    SimpleLogger().Write() << "writing node map ...";
+    boost::filesystem::ofstream node_stream(node_filename, std::ios::binary);
+    const unsigned size_of_mapping = internal_to_external_node_map.size();
+    node_stream.write((char *)&size_of_mapping, sizeof(unsigned));
+    if (size_of_mapping > 0)
+    {
+        node_stream.write((char *)&(internal_to_external_node_map[0]),
+                          size_of_mapping * sizeof(QueryNode));
+    }
+    node_stream.close();
+    internal_to_external_node_map.clear();
+    internal_to_external_node_map.shrink_to_fit();
+}
+
+/**
+    \brief Building rtree-based nearest-neighbor data structure
+
+    Saves info to files: '.ramIndex' and '.fileIndex'.
+ */
+void Prepare::BuildRTree(std::vector<EdgeBasedNode> &node_based_edge_list)
+{
+    SimpleLogger().Write() << "building r-tree ...";
+    StaticRTree<EdgeBasedNode>(node_based_edge_list,
+                               rtree_nodes_path.c_str(),
+                               rtree_leafs_path.c_str(),
+                               internal_to_external_node_map);
+}
diff --git a/contractor/processing_chain.hpp b/contractor/processing_chain.hpp
new file mode 100644
index 0000000..933213a
--- /dev/null
+++ b/contractor/processing_chain.hpp
@@ -0,0 +1,95 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef PROCESSING_CHAIN_HPP
+#define PROCESSING_CHAIN_HPP
+
+#include "edge_based_graph_factory.hpp"
+#include "../data_structures/query_edge.hpp"
+#include "../data_structures/static_graph.hpp"
+
+class FingerPrint;
+struct EdgeBasedNode;
+struct lua_State;
+
+#include <boost/filesystem.hpp>
+
+#include <vector>
+
+/**
+    \brief class of 'prepare' utility.
+ */
+class Prepare
+{
+  public:
+    using EdgeData = QueryEdge::EdgeData;
+    using InputEdge = DynamicGraph<EdgeData>::InputEdge;
+    using StaticEdge = StaticGraph<EdgeData>::InputEdge;
+
+    explicit Prepare();
+    Prepare(const Prepare &) = delete;
+    ~Prepare();
+
+    int Process(int argc, char *argv[]);
+
+  protected:
+    bool ParseArguments(int argc, char *argv[]);
+    void CheckRestrictionsFile(FingerPrint &fingerprint_orig);
+    bool SetupScriptingEnvironment(lua_State *myLuaState,
+                                   EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile);
+    std::size_t BuildEdgeExpandedGraph(lua_State *myLuaState,
+                                       NodeID nodeBasedNodeNumber,
+                                       std::vector<EdgeBasedNode> &nodeBasedEdgeList,
+                                       DeallocatingVector<EdgeBasedEdge> &edgeBasedEdgeList,
+                                       EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile);
+    void WriteNodeMapping();
+    void BuildRTree(std::vector<EdgeBasedNode> &node_based_edge_list);
+
+  private:
+    std::vector<QueryNode> internal_to_external_node_map;
+    std::vector<TurnRestriction> restriction_list;
+    std::vector<NodeID> barrier_node_list;
+    std::vector<NodeID> traffic_light_list;
+    std::vector<ImportEdge> edge_list;
+
+    unsigned requested_num_threads;
+    boost::filesystem::path config_file_path;
+    boost::filesystem::path input_path;
+    boost::filesystem::path restrictions_path;
+    boost::filesystem::path preinfo_path;
+    boost::filesystem::path profile_path;
+
+    std::string node_filename;
+    std::string edge_out;
+    std::string info_out;
+    std::string geometry_filename;
+    std::string graph_out;
+    std::string rtree_nodes_path;
+    std::string rtree_leafs_path;
+};
+
+#endif // PROCESSING_CHAIN_HPP
diff --git a/DataStructures/Coordinate.cpp b/data_structures/Coordinate.cpp
similarity index 80%
rename from DataStructures/Coordinate.cpp
rename to data_structures/Coordinate.cpp
index 9c453e7..4305256 100644
--- a/DataStructures/Coordinate.cpp
+++ b/data_structures/Coordinate.cpp
@@ -27,8 +27,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <osrm/Coordinate.h>
 #include "../Util/MercatorUtil.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/StringUtil.h"
+#ifndef NDEBUG
+#include "../Util/simple_logger.hpp"
+#endif
+#include "../Util/string_util.hpp"
 
 #include <boost/assert.hpp>
 
@@ -70,7 +72,7 @@ bool FixedPointCoordinate::isSet() const
 {
     return (std::numeric_limits<int>::min() != lat) && (std::numeric_limits<int>::min() != lon);
 }
-bool FixedPointCoordinate::isValid() const
+bool FixedPointCoordinate::is_valid() const
 {
     if (lat > 90 * COORDINATE_PRECISION || lat < -90 * COORDINATE_PRECISION ||
         lon > 180 * COORDINATE_PRECISION || lon < -180 * COORDINATE_PRECISION)
@@ -157,12 +159,12 @@ FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &s
                                                    const FixedPointCoordinate &point)
 {
     // initialize values
-    const float x_value = lat2y(point.lat / COORDINATE_PRECISION);
+    const float x_value = static_cast<float>(lat2y(point.lat / COORDINATE_PRECISION));
     const float y_value = point.lon / COORDINATE_PRECISION;
-    const float a = lat2y(source_coordinate.lat / COORDINATE_PRECISION);
-    const float b = source_coordinate.lon / COORDINATE_PRECISION;
-    const float c = lat2y(target_coordinate.lat / COORDINATE_PRECISION);
-    const float d = target_coordinate.lon / COORDINATE_PRECISION;
+    float a = static_cast<float>(lat2y(source_coordinate.lat / COORDINATE_PRECISION));
+    float b = source_coordinate.lon / COORDINATE_PRECISION;
+    float c = static_cast<float>(lat2y(target_coordinate.lat / COORDINATE_PRECISION));
+    float d = target_coordinate.lon / COORDINATE_PRECISION;
     float p, q;
     if (std::abs(a - c) > std::numeric_limits<float>::epsilon())
     {
@@ -178,15 +180,36 @@ FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &s
         q = y_value;
     }
 
-    float nY = (d * p - c * q) / (a * d - b * c);
-    // discretize the result to coordinate precision. it's a hack!
-    if (std::abs(nY) < (1.f / COORDINATE_PRECISION))
+    float ratio;
+    bool inverse_ratio = false;
+
+    // straight line segment on equator
+    if (std::abs(c) < std::numeric_limits<float>::epsilon() &&
+        std::abs(a) < std::numeric_limits<float>::epsilon())
     {
-        nY = 0.f;
+        ratio = (q - b) / (d - b);
+    }
+    else
+    {
+        if (std::abs(c) < std::numeric_limits<float>::epsilon())
+        {
+            // swap start/end
+            std::swap(a, c);
+            std::swap(b, d);
+            inverse_ratio = true;
+        }
+
+        float nY = (d * p - c * q) / (a * d - b * c);
+        // discretize the result to coordinate precision. it's a hack!
+        if (std::abs(nY) < (1.f / COORDINATE_PRECISION))
+        {
+            nY = 0.f;
+        }
+
+        // compute ratio
+        ratio = (p - nY * a) / c;
     }
 
-    // compute ratio
-    float ratio = (p - nY * a) / c;
     if (std::isnan(ratio))
     {
         ratio = (target_coordinate == point ? 1.f : 0.f);
@@ -200,7 +223,13 @@ FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &s
         ratio = 1.f;
     }
 
-    //compute the nearest location
+    // we need to do this, if we switched start/end coordinates
+    if (inverse_ratio)
+    {
+        ratio = 1.0f - ratio;
+    }
+
+    // compute the nearest location
     FixedPointCoordinate nearest_location;
     BOOST_ASSERT(!std::isnan(ratio));
     if (ratio <= 0.f)
@@ -216,7 +245,8 @@ FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &s
         nearest_location.lat = static_cast<int>(y2lat(p) * COORDINATE_PRECISION);
         nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
     }
-    BOOST_ASSERT(nearest_location.isValid());
+
+    BOOST_ASSERT(nearest_location.is_valid());
     return FixedPointCoordinate::ApproximateEuclideanDistance(point, nearest_location);
 }
 
@@ -226,19 +256,19 @@ float FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordin
                                                          FixedPointCoordinate &nearest_location,
                                                          float &ratio)
 {
-    BOOST_ASSERT(query_location.isValid());
+    BOOST_ASSERT(query_location.is_valid());
 
     // initialize values
-    const float x = lat2y(query_location.lat / COORDINATE_PRECISION);
-    const float y = query_location.lon / COORDINATE_PRECISION;
-    const float a = lat2y(segment_source.lat / COORDINATE_PRECISION);
-    const float b = segment_source.lon / COORDINATE_PRECISION;
-    const float c = lat2y(segment_target.lat / COORDINATE_PRECISION);
-    const float d = segment_target.lon / COORDINATE_PRECISION;
-    float p, q /*,mX*/, nY;
-    if (std::abs(a - c) > std::numeric_limits<float>::epsilon())
+    const double x = lat2y(query_location.lat / COORDINATE_PRECISION);
+    const double y = query_location.lon / COORDINATE_PRECISION;
+    const double a = lat2y(segment_source.lat / COORDINATE_PRECISION);
+    const double b = segment_source.lon / COORDINATE_PRECISION;
+    const double c = lat2y(segment_target.lat / COORDINATE_PRECISION);
+    const double d = segment_target.lon / COORDINATE_PRECISION;
+    double p, q /*,mX*/, nY;
+    if (std::abs(a - c) > std::numeric_limits<double>::epsilon())
     {
-        const float m = (d - b) / (c - a); // slope
+        const double m = (d - b) / (c - a); // slope
         // Projection of (x,y) on line joining (a,b) and (c,d)
         p = ((x + (m * y)) + (m * m * a - m * b)) / (1.f + m * m);
         q = b + m * (p - a);
@@ -264,11 +294,11 @@ float FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordin
     {
         ratio = (segment_target == query_location ? 1.f : 0.f);
     }
-    else if (std::abs(ratio) <= std::numeric_limits<float>::epsilon())
+    else if (std::abs(ratio) <= std::numeric_limits<double>::epsilon())
     {
-        ratio = 0.;
+        ratio = 0.f;
     }
-    else if (std::abs(ratio - 1.f) <= std::numeric_limits<float>::epsilon())
+    else if (std::abs(ratio - 1.f) <= std::numeric_limits<double>::epsilon())
     {
         ratio = 1.f;
     }
@@ -279,7 +309,7 @@ float FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordin
     {
         nearest_location = segment_source;
     }
-    else if (ratio >= 1.)
+    else if (ratio >= 1.f)
     {
         nearest_location = segment_target;
     }
@@ -289,7 +319,7 @@ float FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordin
         nearest_location.lat = static_cast<int>(y2lat(p) * COORDINATE_PRECISION);
         nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
     }
-    BOOST_ASSERT(nearest_location.isValid());
+    BOOST_ASSERT(nearest_location.is_valid());
 
     const float approximate_distance =
         FixedPointCoordinate::ApproximateEuclideanDistance(query_location, nearest_location);
@@ -337,7 +367,8 @@ void FixedPointCoordinate::Output(std::ostream &out) const
 float FixedPointCoordinate::GetBearing(const FixedPointCoordinate &first_coordinate,
                                        const FixedPointCoordinate &second_coordinate)
 {
-    const float lon_diff = second_coordinate.lon / COORDINATE_PRECISION - first_coordinate.lon / COORDINATE_PRECISION;
+    const float lon_diff =
+        second_coordinate.lon / COORDINATE_PRECISION - first_coordinate.lon / COORDINATE_PRECISION;
     const float lon_delta = DegreeToRadian(lon_diff);
     const float lat1 = DegreeToRadian(first_coordinate.lat / COORDINATE_PRECISION);
     const float lat2 = DegreeToRadian(second_coordinate.lat / COORDINATE_PRECISION);
@@ -379,9 +410,15 @@ float FixedPointCoordinate::GetBearing(const FixedPointCoordinate &other) const
     return result;
 }
 
-float FixedPointCoordinate::DegreeToRadian(const float degree) { return degree * (static_cast<float>(M_PI) / 180.f); }
+float FixedPointCoordinate::DegreeToRadian(const float degree)
+{
+    return degree * (static_cast<float>(M_PI) / 180.f);
+}
 
-float FixedPointCoordinate::RadianToDegree(const float radian) { return radian * (180.f * static_cast<float>(M_1_PI)); }
+float FixedPointCoordinate::RadianToDegree(const float radian)
+{
+    return radian * (180.f * static_cast<float>(M_1_PI));
+}
 
 // This distance computation does integer arithmetic only and is a lot faster than
 // the other distance function which are numerically correct('ish).
@@ -392,11 +429,11 @@ int FixedPointCoordinate::OrderedPerpendicularDistanceApproximation(
     const FixedPointCoordinate &segment_target)
 {
     // initialize values
-    const float x = lat2y(input_point.lat / COORDINATE_PRECISION);
+    const float x = static_cast<float>(lat2y(input_point.lat / COORDINATE_PRECISION));
     const float y = input_point.lon / COORDINATE_PRECISION;
-    const float a = lat2y(segment_source.lat / COORDINATE_PRECISION);
+    const float a = static_cast<float>(lat2y(segment_source.lat / COORDINATE_PRECISION));
     const float b = segment_source.lon / COORDINATE_PRECISION;
-    const float c = lat2y(segment_target.lat / COORDINATE_PRECISION);
+    const float c = static_cast<float>(lat2y(segment_target.lat / COORDINATE_PRECISION));
     const float d = segment_target.lon / COORDINATE_PRECISION;
 
     float p, q;
diff --git a/DataStructures/InputReaderFactory.h b/data_structures/InputReaderFactory.h
similarity index 100%
rename from DataStructures/InputReaderFactory.h
rename to data_structures/InputReaderFactory.h
diff --git a/DataStructures/BinaryHeap.h b/data_structures/binary_heap.hpp
similarity index 98%
rename from DataStructures/BinaryHeap.h
rename to data_structures/binary_heap.hpp
index 00d3782..049f12f 100644
--- a/DataStructures/BinaryHeap.h
+++ b/data_structures/binary_heap.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -36,6 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <type_traits>
 #include <unordered_map>
 #include <vector>
+#include <cstring>
 
 template <typename NodeID, typename Key> class ArrayStorage
 {
@@ -99,8 +100,8 @@ class BinaryHeap
     void operator=(const BinaryHeap &right);
 
   public:
-    typedef Weight WeightType;
-    typedef Data DataType;
+    using WeightType = Weight;
+    using DataType = Data;
 
     explicit BinaryHeap(size_t maxID) : node_index(maxID) { Clear(); }
 
diff --git a/DataStructures/ConcurrentQueue.h b/data_structures/concurrent_queue.hpp
similarity index 94%
rename from DataStructures/ConcurrentQueue.h
rename to data_structures/concurrent_queue.hpp
index 9d5b366..b3d4e1a 100644
--- a/DataStructures/ConcurrentQueue.h
+++ b/data_structures/concurrent_queue.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,10 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef CONCURRENT_QUEUE_H
-#define CONCURRENT_QUEUE_H
-
-#include "../typedefs.h"
+#ifndef CONCURRENT_QUEUE_HPP
+#define CONCURRENT_QUEUE_HPP
 
 #include <boost/circular_buffer.hpp>
 #include <condition_variable>
@@ -82,4 +80,4 @@ template <typename Data> class ConcurrentQueue
     std::condition_variable m_not_full;
 };
 
-#endif // CONCURRENT_QUEUE_H
+#endif // CONCURRENT_QUEUE_HPP
diff --git a/data_structures/deallocating_vector.hpp b/data_structures/deallocating_vector.hpp
new file mode 100644
index 0000000..415fa69
--- /dev/null
+++ b/data_structures/deallocating_vector.hpp
@@ -0,0 +1,313 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef DEALLOCATINGVECTOR_H_
+#define DEALLOCATINGVECTOR_H_
+
+#include "../Util/integer_range.hpp"
+
+#include <boost/iterator/iterator_facade.hpp>
+
+#include <utility>
+#include <vector>
+
+template <typename ElementT> struct DeallocatingVectorIteratorState
+{
+    DeallocatingVectorIteratorState() : index(-1), bucket_list(nullptr) {}
+    explicit DeallocatingVectorIteratorState(const DeallocatingVectorIteratorState &r)
+        : index(r.index), bucket_list(r.bucket_list)
+    {
+    }
+    explicit DeallocatingVectorIteratorState(const std::size_t idx,
+                                             std::vector<ElementT *> *input_list)
+        : index(idx), bucket_list(input_list)
+    {
+    }
+    std::size_t index;
+    std::vector<ElementT *> *bucket_list;
+
+    inline DeallocatingVectorIteratorState &operator=(const DeallocatingVectorIteratorState &other)
+    {
+        index = other.index;
+        bucket_list = other.bucket_list;
+        return *this;
+    }
+};
+
+template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK>
+class DeallocatingVectorIterator
+    : public boost::iterator_facade<DeallocatingVectorIterator<ElementT, ELEMENTS_PER_BLOCK>,
+                                    ElementT,
+                                    std::random_access_iterator_tag>
+{
+    DeallocatingVectorIteratorState<ElementT> current_state;
+
+  public:
+    DeallocatingVectorIterator() {}
+    DeallocatingVectorIterator(std::size_t idx, std::vector<ElementT *> *input_list)
+        : current_state(idx, input_list)
+    {
+    }
+
+    friend class boost::iterator_core_access;
+
+    void advance(std::size_t n) { current_state.index += n; }
+
+    void increment() { advance(1); }
+
+    void decrement() { advance(-1); }
+
+    bool equal(DeallocatingVectorIterator const &other) const
+    {
+        return current_state.index == other.current_state.index;
+    }
+
+    std::ptrdiff_t distance_to(DeallocatingVectorIterator const &other) const
+    {
+        // it is important to implement it 'other minus this'. otherwise sorting breaks
+        return other.current_state.index - current_state.index;
+    }
+
+    ElementT &dereference() const
+    {
+        const std::size_t current_bucket = current_state.index / ELEMENTS_PER_BLOCK;
+        const std::size_t current_index = current_state.index % ELEMENTS_PER_BLOCK;
+        return (current_state.bucket_list->at(current_bucket)[current_index]);
+    }
+
+    ElementT &operator[](const std::size_t index) const
+    {
+        const std::size_t current_bucket = (index + current_state.index) / ELEMENTS_PER_BLOCK;
+        const std::size_t current_index = (index + current_state.index) % ELEMENTS_PER_BLOCK;
+        return (current_state.bucket_list->at(current_bucket)[current_index]);
+    }
+};
+
+template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK>
+class DeallocatingVectorRemoveIterator
+    : public boost::iterator_facade<DeallocatingVectorRemoveIterator<ElementT, ELEMENTS_PER_BLOCK>,
+                                    ElementT,
+                                    boost::forward_traversal_tag>
+{
+    DeallocatingVectorIteratorState<ElementT> current_state;
+
+  public:
+    DeallocatingVectorRemoveIterator(std::size_t idx, std::vector<ElementT *> *input_list)
+        : current_state(idx, input_list)
+    {
+    }
+
+    friend class boost::iterator_core_access;
+
+    void increment()
+    {
+        const std::size_t old_bucket = current_state.index / ELEMENTS_PER_BLOCK;
+
+        ++current_state.index;
+        const std::size_t new_bucket = current_state.index / ELEMENTS_PER_BLOCK;
+        if (old_bucket != new_bucket)
+        {
+            // delete old bucket entry
+            if (nullptr != current_state.bucket_list->at(old_bucket))
+            {
+                delete[] current_state.bucket_list->at(old_bucket);
+                current_state.bucket_list->at(old_bucket) = nullptr;
+            }
+        }
+    }
+
+    bool equal(DeallocatingVectorRemoveIterator const &other) const
+    {
+        return current_state.index == other.current_state.index;
+    }
+
+    std::ptrdiff_t distance_to(DeallocatingVectorRemoveIterator const &other) const
+    {
+        return other.current_state.index - current_state.index;
+    }
+
+    ElementT &dereference() const
+    {
+        const std::size_t current_bucket = current_state.index / ELEMENTS_PER_BLOCK;
+        const std::size_t current_index = current_state.index % ELEMENTS_PER_BLOCK;
+        return (current_state.bucket_list->at(current_bucket)[current_index]);
+    }
+};
+
+template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK = 8388608 / sizeof(ElementT)>
+class DeallocatingVector
+{
+    std::size_t current_size;
+    std::vector<ElementT *> bucket_list;
+
+  public:
+    using iterator = DeallocatingVectorIterator<ElementT, ELEMENTS_PER_BLOCK>;
+    using const_iterator = DeallocatingVectorIterator<ElementT, ELEMENTS_PER_BLOCK>;
+
+    // this forward-only iterator deallocates all buckets that have been visited
+    using deallocation_iterator = DeallocatingVectorRemoveIterator<ElementT, ELEMENTS_PER_BLOCK>;
+
+    DeallocatingVector() : current_size(0) { bucket_list.emplace_back(new ElementT[ELEMENTS_PER_BLOCK]); }
+
+    ~DeallocatingVector() { clear(); }
+
+    inline void swap(DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK> &other)
+    {
+        std::swap(current_size, other.current_size);
+        bucket_list.swap(other.bucket_list);
+    }
+
+    inline void clear()
+    {
+        // Delete[]'ing ptr's to all Buckets
+        for (auto bucket : bucket_list)
+        {
+            if (nullptr != bucket)
+            {
+                delete[] bucket;
+                bucket = nullptr;
+            }
+        }
+        bucket_list.clear(); bucket_list.shrink_to_fit();
+        current_size = 0;
+    }
+
+    inline void push_back(const ElementT &element)
+    {
+        const std::size_t current_capacity = capacity();
+        if (current_size == current_capacity)
+        {
+            bucket_list.push_back(new ElementT[ELEMENTS_PER_BLOCK]);
+        }
+
+        std::size_t current_index = size() % ELEMENTS_PER_BLOCK;
+        bucket_list.back()[current_index] = element;
+        ++current_size;
+    }
+
+    template <typename... Ts> inline void emplace_back(Ts &&... element)
+    {
+        const std::size_t current_capacity = capacity();
+        if (current_size == current_capacity)
+        {
+            bucket_list.push_back(new ElementT[ELEMENTS_PER_BLOCK]);
+        }
+
+        const std::size_t current_index = size() % ELEMENTS_PER_BLOCK;
+        bucket_list.back()[current_index] = ElementT(std::forward<Ts>(element)...);
+        ++current_size;
+    }
+
+    inline void reserve(const std::size_t) const { /* don't do anything */ }
+
+    inline void resize(const std::size_t new_size)
+    {
+        if (new_size >= current_size)
+        {
+            while (capacity() < new_size)
+            {
+                bucket_list.push_back(new ElementT[ELEMENTS_PER_BLOCK]);
+            }
+        }
+        else
+        {   // down-size
+            const std::size_t number_of_necessary_buckets = 1 + (new_size / ELEMENTS_PER_BLOCK);
+            for (const auto bucket_index : osrm::irange(number_of_necessary_buckets, bucket_list.size()))
+            {
+                if (nullptr != bucket_list[bucket_index])
+                {
+                    delete[] bucket_list[bucket_index];
+                }
+            }
+            bucket_list.resize(number_of_necessary_buckets);
+        }
+        current_size = new_size;
+    }
+
+    inline std::size_t size() const { return current_size; }
+
+    inline std::size_t capacity() const { return bucket_list.size() * ELEMENTS_PER_BLOCK; }
+
+    inline iterator begin() { return iterator(static_cast<std::size_t>(0), &bucket_list); }
+
+    inline iterator end() { return iterator(size(), &bucket_list); }
+
+    inline deallocation_iterator dbegin()
+    {
+        return deallocation_iterator(static_cast<std::size_t>(0), &bucket_list);
+    }
+
+    inline deallocation_iterator dend() { return deallocation_iterator(size(), &bucket_list); }
+
+    inline const_iterator begin() const
+    {
+        return const_iterator(static_cast<std::size_t>(0), &bucket_list);
+    }
+
+    inline const_iterator end() const { return const_iterator(size(), &bucket_list); }
+
+    inline ElementT &operator[](const std::size_t index)
+    {
+        const std::size_t _bucket = index / ELEMENTS_PER_BLOCK;
+        const std::size_t _index = index % ELEMENTS_PER_BLOCK;
+        return (bucket_list[_bucket][_index]);
+    }
+
+    const inline ElementT &operator[](const std::size_t index) const
+    {
+        const std::size_t _bucket = index / ELEMENTS_PER_BLOCK;
+        const std::size_t _index = index % ELEMENTS_PER_BLOCK;
+        return (bucket_list[_bucket][_index]);
+    }
+
+    inline ElementT &back()
+    {
+        const std::size_t _bucket = current_size / ELEMENTS_PER_BLOCK;
+        const std::size_t _index = current_size % ELEMENTS_PER_BLOCK;
+        return (bucket_list[_bucket][_index]);
+    }
+
+    const inline ElementT &back() const
+    {
+        const std::size_t _bucket = current_size / ELEMENTS_PER_BLOCK;
+        const std::size_t _index = current_size % ELEMENTS_PER_BLOCK;
+        return (bucket_list[_bucket][_index]);
+    }
+
+    template<class InputIterator>
+    const inline void append(InputIterator first, const InputIterator last)
+    {
+        InputIterator position = first;
+        while (position != last)
+        {
+            push_back(*position);
+            ++position;
+        }
+    }
+};
+
+#endif /* DEALLOCATINGVECTOR_H_ */
diff --git a/DataStructures/DynamicGraph.h b/data_structures/dynamic_graph.hpp
similarity index 53%
rename from DataStructures/DynamicGraph.h
rename to data_structures/dynamic_graph.hpp
index 3dc48b6..7244d1e 100644
--- a/DataStructures/DynamicGraph.h
+++ b/data_structures/dynamic_graph.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,13 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef DYNAMICGRAPH_H
-#define DYNAMICGRAPH_H
+#ifndef DYNAMICGRAPH_HPP
+#define DYNAMICGRAPH_HPP
 
-#include "../DataStructures/DeallocatingVector.h"
+#include "deallocating_vector.hpp"
+#include "../Util/integer_range.hpp"
 
 #include <boost/assert.hpp>
-#include <boost/range/irange.hpp>
 
 #include <cstdint>
 
@@ -43,10 +43,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 template <typename EdgeDataT> class DynamicGraph
 {
   public:
-    typedef decltype(boost::irange(0u,0u)) EdgeRange;
-    typedef EdgeDataT EdgeData;
-    typedef unsigned NodeIterator;
-    typedef unsigned EdgeIterator;
+    using EdgeData = EdgeDataT;
+    using NodeIterator = unsigned;
+    using EdgeIterator = unsigned;
+    using EdgeRange = osrm::range<EdgeIterator>;
 
     class InputEdge
     {
@@ -54,57 +54,62 @@ template <typename EdgeDataT> class DynamicGraph
         NodeIterator source;
         NodeIterator target;
         EdgeDataT data;
+
+        InputEdge() : source(std::numeric_limits<NodeIterator>::max()), target(std::numeric_limits<NodeIterator>::max()) { }
+
+        template<typename... Ts>
+        InputEdge(NodeIterator source, NodeIterator target, Ts &&...data) : source(source), target(target), data(std::forward<Ts>(data)...) { }
+
         bool operator<(const InputEdge &right) const
         {
             if (source != right.source)
+            {
                 return source < right.source;
+            }
             return target < right.target;
         }
     };
 
     // Constructs an empty graph with a given number of nodes.
-    explicit DynamicGraph(int32_t nodes) : m_numNodes(nodes), m_numEdges(0)
+    explicit DynamicGraph(NodeIterator nodes) : number_of_nodes(nodes), number_of_edges(0)
     {
-        m_nodes.reserve(m_numNodes);
-        m_nodes.resize(m_numNodes);
+        node_list.reserve(number_of_nodes);
+        node_list.resize(number_of_nodes);
 
-        m_edges.reserve(m_numNodes * 1.1);
-        m_edges.resize(m_numNodes);
+        edge_list.reserve(number_of_nodes * 1.1);
+        edge_list.resize(number_of_nodes);
     }
 
-    template <class ContainerT> DynamicGraph(const int32_t nodes, const ContainerT &graph)
+    template <class ContainerT> DynamicGraph(const NodeIterator nodes, const ContainerT &graph)
     {
-        m_numNodes = nodes;
-        m_numEdges = (EdgeIterator)graph.size();
-        m_nodes.reserve(m_numNodes + 1);
-        m_nodes.resize(m_numNodes + 1);
+        number_of_nodes = nodes;
+        number_of_edges = (EdgeIterator)graph.size();
+        node_list.reserve(number_of_nodes + 1);
+        node_list.resize(number_of_nodes + 1);
         EdgeIterator edge = 0;
         EdgeIterator position = 0;
-        for (NodeIterator node = 0; node < m_numNodes; ++node)
+        for (const auto node : osrm::irange(0u, number_of_nodes))
         {
             EdgeIterator lastEdge = edge;
-            while (edge < m_numEdges && graph[edge].source == node)
+            while (edge < number_of_edges && graph[edge].source == node)
             {
                 ++edge;
             }
-            m_nodes[node].firstEdge = position;
-            m_nodes[node].edges = edge - lastEdge;
-            position += m_nodes[node].edges;
+            node_list[node].firstEdge = position;
+            node_list[node].edges = edge - lastEdge;
+            position += node_list[node].edges;
         }
-        m_nodes.back().firstEdge = position;
-        m_edges.reserve(static_cast<std::size_t>(position * 1.1));
-        m_edges.resize(position);
+        node_list.back().firstEdge = position;
+        edge_list.reserve(static_cast<std::size_t>(edge_list.size() * 1.1));
+        edge_list.resize(position);
         edge = 0;
-        for (NodeIterator node = 0; node < m_numNodes; ++node)
+        for (const auto node : osrm::irange(0u, number_of_nodes))
         {
-            for (EdgeIterator i = m_nodes[node].firstEdge,
-                              e = m_nodes[node].firstEdge + m_nodes[node].edges;
-                 i != e;
-                 ++i)
+            for (const auto i : osrm::irange(node_list[node].firstEdge,
+                                              node_list[node].firstEdge + node_list[node].edges))
             {
-                m_edges[i].target = graph[edge].target;
-                m_edges[i].data = graph[edge].data;
-                BOOST_ASSERT_MSG(graph[edge].data.distance > 0, "edge distance invalid");
+                edge_list[i].target = graph[edge].target;
+                edge_list[i].data = graph[edge].data;
                 ++edge;
             }
         }
@@ -112,16 +117,16 @@ template <typename EdgeDataT> class DynamicGraph
 
     ~DynamicGraph() {}
 
-    unsigned GetNumberOfNodes() const { return m_numNodes; }
+    unsigned GetNumberOfNodes() const { return number_of_nodes; }
 
-    unsigned GetNumberOfEdges() const { return m_numEdges; }
+    unsigned GetNumberOfEdges() const { return number_of_edges; }
 
-    unsigned GetOutDegree(const NodeIterator n) const { return m_nodes[n].edges; }
+    unsigned GetOutDegree(const NodeIterator n) const { return node_list[n].edges; }
 
     unsigned GetDirectedOutDegree(const NodeIterator n) const
     {
         unsigned degree = 0;
-        for(EdgeIterator edge = BeginEdges(n); edge < EndEdges(n); ++edge)
+        for (const auto edge : osrm::irange(BeginEdges(n), EndEdges(n)))
         {
             if (GetEdgeData(edge).forward)
             {
@@ -131,66 +136,76 @@ template <typename EdgeDataT> class DynamicGraph
         return degree;
     }
 
-    NodeIterator GetTarget(const EdgeIterator e) const { return NodeIterator(m_edges[e].target); }
+    NodeIterator GetTarget(const EdgeIterator e) const { return NodeIterator(edge_list[e].target); }
 
-    void SetTarget(const EdgeIterator e, const NodeIterator n) { m_edges[e].target = n; }
+    void SetTarget(const EdgeIterator e, const NodeIterator n) { edge_list[e].target = n; }
 
-    EdgeDataT &GetEdgeData(const EdgeIterator e) { return m_edges[e].data; }
+    EdgeDataT &GetEdgeData(const EdgeIterator e) { return edge_list[e].data; }
 
-    const EdgeDataT &GetEdgeData(const EdgeIterator e) const { return m_edges[e].data; }
+    const EdgeDataT &GetEdgeData(const EdgeIterator e) const { return edge_list[e].data; }
 
     EdgeIterator BeginEdges(const NodeIterator n) const
     {
-        return EdgeIterator(m_nodes[n].firstEdge);
+        return EdgeIterator(node_list[n].firstEdge);
     }
 
     EdgeIterator EndEdges(const NodeIterator n) const
     {
-        return EdgeIterator(m_nodes[n].firstEdge + m_nodes[n].edges);
+        return EdgeIterator(node_list[n].firstEdge + node_list[n].edges);
     }
 
     EdgeRange GetAdjacentEdgeRange(const NodeIterator node) const
     {
-        return boost::irange(BeginEdges(node), EndEdges(node));
+        return osrm::irange(BeginEdges(node), EndEdges(node));
+    }
+
+    NodeIterator InsertNode()
+    {
+        node_list.emplace_back(node_list.back());
+        number_of_nodes += 1;
+
+        return number_of_nodes;
     }
 
     // adds an edge. Invalidates edge iterators for the source node
     EdgeIterator InsertEdge(const NodeIterator from, const NodeIterator to, const EdgeDataT &data)
     {
-        Node &node = m_nodes[from];
+        Node &node = node_list[from];
         EdgeIterator newFirstEdge = node.edges + node.firstEdge;
-        if (newFirstEdge >= m_edges.size() || !isDummy(newFirstEdge))
+        if (newFirstEdge >= edge_list.size() || !isDummy(newFirstEdge))
         {
             if (node.firstEdge != 0 && isDummy(node.firstEdge - 1))
             {
                 node.firstEdge--;
-                m_edges[node.firstEdge] = m_edges[node.firstEdge + node.edges];
+                edge_list[node.firstEdge] = edge_list[node.firstEdge + node.edges];
             }
             else
             {
-                EdgeIterator newFirstEdge = (EdgeIterator)m_edges.size();
+                EdgeIterator newFirstEdge = (EdgeIterator)edge_list.size();
                 unsigned newSize = node.edges * 1.1 + 2;
-                EdgeIterator requiredCapacity = newSize + m_edges.size();
-                EdgeIterator oldCapacity = m_edges.capacity();
+                EdgeIterator requiredCapacity = newSize + edge_list.size();
+                EdgeIterator oldCapacity = edge_list.capacity();
                 if (requiredCapacity >= oldCapacity)
                 {
-                    m_edges.reserve(requiredCapacity * 1.1);
+                    edge_list.reserve(requiredCapacity * 1.1);
                 }
-                m_edges.resize(m_edges.size() + newSize);
-                for (EdgeIterator i = 0; i < node.edges; ++i)
+                edge_list.resize(edge_list.size() + newSize);
+                for (const auto i : osrm::irange(0u, node.edges))
                 {
-                    m_edges[newFirstEdge + i] = m_edges[node.firstEdge + i];
+                    edge_list[newFirstEdge + i] = edge_list[node.firstEdge + i];
                     makeDummy(node.firstEdge + i);
                 }
-                for (EdgeIterator i = node.edges + 1; i < newSize; ++i)
+                for (const auto i : osrm::irange(node.edges + 1, newSize))
+                {
                     makeDummy(newFirstEdge + i);
+                }
                 node.firstEdge = newFirstEdge;
             }
         }
-        Edge &edge = m_edges[node.firstEdge + node.edges];
+        Edge &edge = edge_list[node.firstEdge + node.edges];
         edge.target = to;
         edge.data = data;
-        ++m_numEdges;
+        ++number_of_edges;
         ++node.edges;
         return EdgeIterator(node.firstEdge + node.edges);
     }
@@ -198,14 +213,14 @@ template <typename EdgeDataT> class DynamicGraph
     // removes an edge. Invalidates edge iterators for the source node
     void DeleteEdge(const NodeIterator source, const EdgeIterator e)
     {
-        Node &node = m_nodes[source];
-        --m_numEdges;
+        Node &node = node_list[source];
+        --number_of_edges;
         --node.edges;
         BOOST_ASSERT(std::numeric_limits<unsigned>::max() != node.edges);
         const unsigned last = node.firstEdge + node.edges;
         BOOST_ASSERT(std::numeric_limits<unsigned>::max() != last);
         // swap with last edge
-        m_edges[e] = m_edges[last];
+        edge_list[e] = edge_list[last];
         makeDummy(last);
     }
 
@@ -215,19 +230,19 @@ template <typename EdgeDataT> class DynamicGraph
         int32_t deleted = 0;
         for (EdgeIterator i = BeginEdges(source), iend = EndEdges(source); i < iend - deleted; ++i)
         {
-            if (m_edges[i].target == target)
+            if (edge_list[i].target == target)
             {
                 do
                 {
                     deleted++;
-                    m_edges[i] = m_edges[iend - deleted];
+                    edge_list[i] = edge_list[iend - deleted];
                     makeDummy(iend - deleted);
-                } while (i < iend - deleted && m_edges[i].target == target);
+                } while (i < iend - deleted && edge_list[i].target == target);
             }
         }
 
-        m_numEdges -= deleted;
-        m_nodes[source].edges -= deleted;
+        number_of_edges -= deleted;
+        node_list[source].edges -= deleted;
 
         return deleted;
     }
@@ -235,9 +250,9 @@ template <typename EdgeDataT> class DynamicGraph
     // searches for a specific edge
     EdgeIterator FindEdge(const NodeIterator from, const NodeIterator to) const
     {
-        for (EdgeIterator i = BeginEdges(from), iend = EndEdges(from); i != iend; ++i)
+        for (const auto i : osrm::irange(BeginEdges(from), EndEdges(from)))
         {
-            if (to == m_edges[i].target)
+            if (to == edge_list[i].target)
             {
                 return i;
             }
@@ -248,12 +263,12 @@ template <typename EdgeDataT> class DynamicGraph
   protected:
     bool isDummy(const EdgeIterator edge) const
     {
-        return m_edges[edge].target == (std::numeric_limits<NodeIterator>::max)();
+        return edge_list[edge].target == (std::numeric_limits<NodeIterator>::max)();
     }
 
     void makeDummy(const EdgeIterator edge)
     {
-        m_edges[edge].target = (std::numeric_limits<NodeIterator>::max)();
+        edge_list[edge].target = (std::numeric_limits<NodeIterator>::max)();
     }
 
     struct Node
@@ -270,11 +285,11 @@ template <typename EdgeDataT> class DynamicGraph
         EdgeDataT data;
     };
 
-    NodeIterator m_numNodes;
-    std::atomic_uint m_numEdges;
+    NodeIterator number_of_nodes;
+    std::atomic_uint number_of_edges;
 
-    std::vector<Node> m_nodes;
-    DeallocatingVector<Edge> m_edges;
+    std::vector<Node> node_list;
+    DeallocatingVector<Edge> edge_list;
 };
 
-#endif // DYNAMICGRAPH_H
+#endif // DYNAMICGRAPH_HPP
diff --git a/DataStructures/EdgeBasedNode.h b/data_structures/edge_based_node.hpp
similarity index 58%
rename from DataStructures/EdgeBasedNode.h
rename to data_structures/edge_based_node.hpp
index 90f8b7c..98746d9 100644
--- a/DataStructures/EdgeBasedNode.h
+++ b/data_structures/edge_based_node.hpp
@@ -1,7 +1,34 @@
-#ifndef EDGE_BASED_NODE_H
-#define EDGE_BASED_NODE_H
+/*
 
-#include "../Util/SimpleLogger.h"
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef EDGE_BASED_NODE_HPP
+#define EDGE_BASED_NODE_HPP
+
+#include "../data_structures/travel_mode.hpp"
 #include "../typedefs.h"
 
 #include <osrm/Coordinate.h>
@@ -12,7 +39,6 @@
 
 struct EdgeBasedNode
 {
-
     EdgeBasedNode() :
         forward_edge_based_node_id(SPECIAL_NODEID),
         reverse_edge_based_node_id(SPECIAL_NODEID),
@@ -24,8 +50,10 @@ struct EdgeBasedNode
         forward_offset(0),
         reverse_offset(0),
         packed_geometry_id(SPECIAL_EDGEID),
+        component_id(-1),
         fwd_segment_position( std::numeric_limits<unsigned short>::max() ),
-        is_in_tiny_cc(false)
+        forward_travel_mode(TRAVEL_MODE_INACCESSIBLE),
+        backward_travel_mode(TRAVEL_MODE_INACCESSIBLE)
     { }
 
     explicit EdgeBasedNode(
@@ -39,8 +67,10 @@ struct EdgeBasedNode
         int forward_offset,
         int reverse_offset,
         unsigned packed_geometry_id,
+        unsigned component_id,
         unsigned short fwd_segment_position,
-        bool belongs_to_tiny_component
+        TravelMode forward_travel_mode,
+        TravelMode backward_travel_mode
     ) :
         forward_edge_based_node_id(forward_edge_based_node_id),
         reverse_edge_based_node_id(reverse_edge_based_node_id),
@@ -52,8 +82,10 @@ struct EdgeBasedNode
         forward_offset(forward_offset),
         reverse_offset(reverse_offset),
         packed_geometry_id(packed_geometry_id),
+        component_id(component_id),
         fwd_segment_position(fwd_segment_position),
-        is_in_tiny_cc(belongs_to_tiny_component)
+        forward_travel_mode(forward_travel_mode),
+        backward_travel_mode(backward_travel_mode)
     {
         BOOST_ASSERT((forward_edge_based_node_id != SPECIAL_NODEID) ||
                      (reverse_edge_based_node_id != SPECIAL_NODEID));
@@ -73,6 +105,11 @@ struct EdgeBasedNode
         return packed_geometry_id != SPECIAL_EDGEID;
     }
 
+    bool is_in_tiny_cc() const
+    {
+        return 0 != component_id;
+    }
+
     NodeID forward_edge_based_node_id; // needed for edge-expanded graph
     NodeID reverse_edge_based_node_id; // needed for edge-expanded graph
     NodeID u;   // indices into the coordinates array
@@ -83,8 +120,10 @@ struct EdgeBasedNode
     int forward_offset; // prefix sum of the weight up the edge TODO: short must suffice
     int reverse_offset; // prefix sum of the weight from the edge TODO: short must suffice
     unsigned packed_geometry_id; // if set, then the edge represents a packed geometry
+    unsigned component_id;
     unsigned short fwd_segment_position; // segment id in a compressed geometry
-    bool is_in_tiny_cc;
+    TravelMode forward_travel_mode : 4;
+    TravelMode backward_travel_mode : 4;
 };
 
-#endif //EDGE_BASED_NODE_H
+#endif //EDGE_BASED_NODE_HPP
diff --git a/DataStructures/ImportNode.cpp b/data_structures/external_memory_node.cpp
similarity index 70%
rename from DataStructures/ImportNode.cpp
rename to data_structures/external_memory_node.cpp
index 8975d40..cd6271b 100644
--- a/DataStructures/ImportNode.cpp
+++ b/data_structures/external_memory_node.cpp
@@ -25,19 +25,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "ImportNode.h"
+#include "external_memory_node.hpp"
 
 #include <limits>
 
 ExternalMemoryNode::ExternalMemoryNode(
-    int lat, int lon, unsigned int node_id, bool bollard, bool traffic_light)
-    : NodeInfo(lat, lon, node_id), bollard(bollard), trafficLight(traffic_light)
+    int lat, int lon, unsigned int node_id, bool barrier, bool traffic_lights)
+    : QueryNode(lat, lon, node_id), barrier(barrier), traffic_lights(traffic_lights)
 {
 }
 
-ExternalMemoryNode::ExternalMemoryNode() : bollard(false), trafficLight(false)
-{
-}
+ExternalMemoryNode::ExternalMemoryNode() : barrier(false), traffic_lights(false) {}
 
 ExternalMemoryNode ExternalMemoryNode::min_value()
 {
@@ -53,12 +51,18 @@ ExternalMemoryNode ExternalMemoryNode::max_value()
                               false);
 }
 
-void ImportNode::Clear()
+bool ExternalMemoryNodeSTXXLCompare::operator()(const ExternalMemoryNode &left,
+                                                const ExternalMemoryNode &right) const
+{
+    return left.node_id < right.node_id;
+}
+
+ExternalMemoryNodeSTXXLCompare::value_type ExternalMemoryNodeSTXXLCompare::max_value()
+{
+    return ExternalMemoryNode::max_value();
+}
+
+ExternalMemoryNodeSTXXLCompare::value_type ExternalMemoryNodeSTXXLCompare::min_value()
 {
-    keyVals.Clear();
-    lat = 0;
-    lon = 0;
-    node_id = 0;
-    bollard = false;
-    trafficLight = false;
+    return ExternalMemoryNode::min_value();
 }
diff --git a/DataStructures/ImportNode.h b/data_structures/external_memory_node.hpp
similarity index 70%
copy from DataStructures/ImportNode.h
copy to data_structures/external_memory_node.hpp
index b8a9451..f88a23e 100644
--- a/DataStructures/ImportNode.h
+++ b/data_structures/external_memory_node.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,17 +25,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef IMPORTNODE_H_
-#define IMPORTNODE_H_
+#ifndef EXTERNAL_MEMORY_NODE_HPP_
+#define EXTERNAL_MEMORY_NODE_HPP_
 
-#include "QueryNode.h"
-#include "../DataStructures/HashTable.h"
+#include "query_node.hpp"
 
 #include <string>
 
-struct ExternalMemoryNode : NodeInfo
+struct ExternalMemoryNode : QueryNode
 {
-    ExternalMemoryNode(int lat, int lon, unsigned int id, bool bollard, bool traffic_light);
+    ExternalMemoryNode(int lat, int lon, NodeID id, bool barrier, bool traffic_light);
 
     ExternalMemoryNode();
 
@@ -43,15 +42,16 @@ struct ExternalMemoryNode : NodeInfo
 
     static ExternalMemoryNode max_value();
 
-    bool bollard;
-    bool trafficLight;
+    bool barrier;
+    bool traffic_lights;
 };
 
-struct ImportNode : public ExternalMemoryNode
+struct ExternalMemoryNodeSTXXLCompare
 {
-    HashTable<std::string, std::string> keyVals;
-
-    inline void Clear();
+    using value_type = ExternalMemoryNode;
+    bool operator()(const ExternalMemoryNode &left, const ExternalMemoryNode &right) const;
+    value_type max_value();
+    value_type min_value();
 };
 
-#endif /* IMPORTNODE_H_ */
+#endif /* EXTERNAL_MEMORY_NODE_HPP_ */
diff --git a/data_structures/fixed_point_number.hpp b/data_structures/fixed_point_number.hpp
new file mode 100644
index 0000000..eab6850
--- /dev/null
+++ b/data_structures/fixed_point_number.hpp
@@ -0,0 +1,216 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef FIXED_POINT_NUMBER_HPP
+#define FIXED_POINT_NUMBER_HPP
+
+#include <cmath>
+#include <cstdint>
+
+#include <iostream>
+#include <limits>
+#include <type_traits>
+#include <utility>
+
+namespace osrm
+{
+
+// implements an binary based fixed point number type
+template <unsigned FractionalBitSize,
+          bool use_64_bits = false,
+          bool is_unsigned = false,
+          bool truncate_results = false>
+class FixedPointNumber
+{
+    static_assert(FractionalBitSize > 0, "FractionalBitSize must be greater than 0");
+    static_assert(FractionalBitSize <= 32, "FractionalBitSize must at most 32");
+
+    typename std::conditional<use_64_bits, int64_t, int32_t>::type m_fixed_point_state;
+    constexpr static const decltype(m_fixed_point_state) PRECISION = 1 << FractionalBitSize;
+
+    // state signage encapsulates whether the state should either represent a
+    // signed or an unsigned floating point number
+    using state_signage =
+        typename std::conditional<is_unsigned,
+                                  typename std::make_unsigned<decltype(m_fixed_point_state)>::type,
+                                  decltype(m_fixed_point_state)>::type;
+
+  public:
+    FixedPointNumber() : m_fixed_point_state(0) {}
+
+    // the type is either initialized with a floating point value or an
+    // integral state. Anything else will throw at compile-time.
+    template <class T>
+    constexpr FixedPointNumber(const T &&input) noexcept
+        : m_fixed_point_state(static_cast<decltype(m_fixed_point_state)>(
+              std::round(std::forward<const T>(input) * PRECISION)))
+    {
+        static_assert(
+            std::is_floating_point<T>::value || std::is_integral<T>::value,
+            "FixedPointNumber needs to be initialized with floating point or integral value");
+    }
+
+    // get max value
+    template <typename T,
+              typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
+    constexpr static auto max() noexcept -> T
+    {
+        return static_cast<T>(std::numeric_limits<state_signage>::max()) / PRECISION;
+    }
+
+    // get min value
+    template <typename T,
+              typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
+    constexpr static auto min() noexcept -> T
+    {
+        return static_cast<T>(1) / PRECISION;
+    }
+
+    // get lowest value
+    template <typename T,
+              typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
+    constexpr static auto lowest() noexcept -> T
+    {
+        return static_cast<T>(std::numeric_limits<state_signage>::min()) / PRECISION;
+    }
+
+    // cast to floating point type T, return value
+    template <typename T,
+              typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
+    explicit operator const T() const noexcept
+    {
+        // casts to external type (signed or unsigned) and then to float
+        return static_cast<T>(static_cast<state_signage>(m_fixed_point_state)) / PRECISION;
+    }
+
+    // warn about cast to integral type T, its disabled for good reason
+    template <typename T, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
+    explicit operator T() const
+    {
+        static_assert(std::is_integral<T>::value,
+                      "casts to integral types have been disabled on purpose");
+    }
+
+    // compare, ie. sort fixed-point numbers
+    bool operator<(const FixedPointNumber &other) const noexcept
+    {
+        return m_fixed_point_state < other.m_fixed_point_state;
+    }
+
+    // equality, ie. sort fixed-point numbers
+    bool operator==(const FixedPointNumber &other) const noexcept
+    {
+        return m_fixed_point_state == other.m_fixed_point_state;
+    }
+
+    bool operator!=(const FixedPointNumber &other) const { return !(*this == other); }
+    bool operator>(const FixedPointNumber &other) const { return other < *this; }
+    bool operator<=(const FixedPointNumber &other) const { return !(other < *this); }
+    bool operator>=(const FixedPointNumber &other) const { return !(*this < other); }
+
+    // arithmetic operators
+    FixedPointNumber operator+(const FixedPointNumber &other) const noexcept
+    {
+        FixedPointNumber tmp = *this;
+        tmp.m_fixed_point_state += other.m_fixed_point_state;
+        return tmp;
+    }
+
+    FixedPointNumber &operator+=(const FixedPointNumber &other) noexcept
+    {
+        this->m_fixed_point_state += other.m_fixed_point_state;
+        return *this;
+    }
+
+    FixedPointNumber operator-(const FixedPointNumber &other) const noexcept
+    {
+        FixedPointNumber tmp = *this;
+        tmp.m_fixed_point_state -= other.m_fixed_point_state;
+        return tmp;
+    }
+
+    FixedPointNumber &operator-=(const FixedPointNumber &other) noexcept
+    {
+        this->m_fixed_point_state -= other.m_fixed_point_state;
+        return *this;
+    }
+
+    FixedPointNumber operator*(const FixedPointNumber &other) const noexcept
+    {
+        int64_t temp = this->m_fixed_point_state;
+        temp *= other.m_fixed_point_state;
+
+        // rounding!
+        if (!truncate_results)
+        {
+            temp = temp + ((temp & 1 << (FractionalBitSize - 1)) << 1);
+        }
+        temp >>= FractionalBitSize;
+        FixedPointNumber tmp;
+        tmp.m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
+        return tmp;
+    }
+
+    FixedPointNumber &operator*=(const FixedPointNumber &other) noexcept
+    {
+        int64_t temp = this->m_fixed_point_state;
+        temp *= other.m_fixed_point_state;
+
+        // rounding!
+        if (!truncate_results)
+        {
+            temp = temp + ((temp & 1 << (FractionalBitSize - 1)) << 1);
+        }
+        temp >>= FractionalBitSize;
+        this->m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
+        return *this;
+    }
+
+    FixedPointNumber operator/(const FixedPointNumber &other) const noexcept
+    {
+        int64_t temp = this->m_fixed_point_state;
+        temp <<= FractionalBitSize;
+        temp /= static_cast<int64_t>(other.m_fixed_point_state);
+        FixedPointNumber tmp;
+        tmp.m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
+        return tmp;
+    }
+
+    FixedPointNumber &operator/=(const FixedPointNumber &other) noexcept
+    {
+        int64_t temp = this->m_fixed_point_state;
+        temp <<= FractionalBitSize;
+        temp /= static_cast<int64_t>(other.m_fixed_point_state);
+        FixedPointNumber tmp;
+        this->m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
+        return *this;
+    }
+};
+
+static_assert(4 == sizeof(FixedPointNumber<1>), "FP19 has wrong size != 4");
+}
+#endif // FIXED_POINT_NUMBER_HPP
diff --git a/DataStructures/HilbertValue.cpp b/data_structures/hilbert_value.cpp
similarity index 97%
rename from DataStructures/HilbertValue.cpp
rename to data_structures/hilbert_value.cpp
index 9cb88c7..216b7c5 100644
--- a/DataStructures/HilbertValue.cpp
+++ b/data_structures/hilbert_value.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,7 +25,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "HilbertValue.h"
+#include "hilbert_value.hpp"
 
 #include <osrm/Coordinate.h>
 
diff --git a/DataStructures/HilbertValue.h b/data_structures/hilbert_value.hpp
similarity index 92%
rename from DataStructures/HilbertValue.h
rename to data_structures/hilbert_value.hpp
index 9de2372..e194029 100644
--- a/DataStructures/HilbertValue.h
+++ b/data_structures/hilbert_value.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef HILBERTVALUE_H_
-#define HILBERTVALUE_H_
+#ifndef HILBERT_VALUE_HPP
+#define HILBERT_VALUE_HPP
 
 #include <cstdint>
 
@@ -46,4 +46,4 @@ class HilbertCode
     inline void TransposeCoordinate(uint32_t *X) const;
 };
 
-#endif /* HILBERTVALUE_H_ */
+#endif /* HILBERT_VALUE_HPP */
diff --git a/DataStructures/ImportEdge.cpp b/data_structures/import_edge.cpp
similarity index 93%
rename from DataStructures/ImportEdge.cpp
rename to data_structures/import_edge.cpp
index 0d04b9f..55f5f16 100644
--- a/DataStructures/ImportEdge.cpp
+++ b/data_structures/import_edge.cpp
@@ -25,7 +25,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "ImportEdge.h"
+#include "import_edge.hpp"
 
 #include <boost/assert.hpp>
 
@@ -52,17 +52,15 @@ NodeBasedEdge::NodeBasedEdge(NodeID source,
                              EdgeWeight weight,
                              bool forward,
                              bool backward,
-                             short type,
                              bool roundabout,
                              bool in_tiny_cc,
                              bool access_restricted,
-                             bool contra_flow,
+                             TravelMode travel_mode,
                              bool is_split)
-    : source(source), target(target), name_id(name_id), weight(weight), type(type),
+    : source(source), target(target), name_id(name_id), weight(weight),
       forward(forward), backward(backward), roundabout(roundabout), in_tiny_cc(in_tiny_cc),
-      access_restricted(access_restricted), contra_flow(contra_flow), is_split(is_split)
+      access_restricted(access_restricted), is_split(is_split), travel_mode(travel_mode)
 {
-    BOOST_ASSERT_MSG(type > 0, "negative edge type");
 }
 
 bool EdgeBasedEdge::operator<(const EdgeBasedEdge &other) const
diff --git a/DataStructures/ImportEdge.h b/data_structures/import_edge.hpp
similarity index 91%
rename from DataStructures/ImportEdge.h
rename to data_structures/import_edge.hpp
index f79a484..f9004d4 100644
--- a/DataStructures/ImportEdge.h
+++ b/data_structures/import_edge.hpp
@@ -25,9 +25,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef IMPORT_EDGE_H
-#define IMPORT_EDGE_H
+#ifndef IMPORT_EDGE_HPP
+#define IMPORT_EDGE_HPP
 
+#include "../data_structures/travel_mode.hpp"
 #include "../typedefs.h"
 
 struct NodeBasedEdge
@@ -40,25 +41,23 @@ struct NodeBasedEdge
                            EdgeWeight weight,
                            bool forward,
                            bool backward,
-                           short type,
                            bool roundabout,
                            bool in_tiny_cc,
                            bool access_restricted,
-                           bool contra_flow,
+                           TravelMode travel_mode,
                            bool is_split);
 
     NodeID source;
     NodeID target;
     NodeID name_id;
     EdgeWeight weight;
-    short type;
     bool forward : 1;
     bool backward : 1;
     bool roundabout : 1;
     bool in_tiny_cc : 1;
     bool access_restricted : 1;
-    bool contra_flow : 1;
     bool is_split : 1;
+    TravelMode travel_mode : 4;
 
     NodeBasedEdge() = delete;
 };
@@ -87,6 +86,6 @@ struct EdgeBasedEdge
     bool backward : 1;
 };
 
-typedef NodeBasedEdge ImportEdge;
+using ImportEdge = NodeBasedEdge;
 
-#endif /* IMPORT_EDGE_H */
+#endif /* IMPORT_EDGE_HPP */
diff --git a/Contractor/GeometryCompressor.h b/data_structures/json_container.hpp
similarity index 55%
rename from Contractor/GeometryCompressor.h
rename to data_structures/json_container.hpp
index 7c4fba4..9bbbec4 100644
--- a/Contractor/GeometryCompressor.h
+++ b/data_structures/json_container.hpp
@@ -25,41 +25,70 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "../typedefs.h"
+// based on
+// https://svn.apache.org/repos/asf/mesos/tags/release-0.9.0-incubating-RC0/src/common/json.hpp
 
-#include <unordered_map>
+#ifndef JSON_CONTAINER_H
+#define JSON_CONTAINER_H
 
-#include <string>
+#include <variant/variant.hpp>
+
+#include <iostream>
 #include <vector>
+#include <string>
+#include <unordered_map>
+
+namespace JSON
+{
 
-#ifndef GEOMETRY_COMPRESSOR_H
-#define GEOMETRY_COMPRESSOR_H
+struct Object;
+struct Array;
 
-class GeometryCompressor
+struct String
 {
-  public:
-    typedef std::pair<NodeID, EdgeWeight> CompressedNode;
-
-    GeometryCompressor();
-    void CompressEdge(const EdgeID surviving_edge_id,
-                      const EdgeID removed_edge_id,
-                      const NodeID via_node_id,
-                      const NodeID target_node,
-                      const EdgeWeight weight1,
-                      const EdgeWeight weight2);
-
-    bool HasEntryForID(const EdgeID edge_id) const;
-    void PrintStatistics() const;
-    void SerializeInternalVector(const std::string &path) const;
-    unsigned GetPositionForID(const EdgeID edge_id) const;
-    const std::vector<GeometryCompressor::CompressedNode> &
-    GetBucketReference(const EdgeID edge_id) const;
-
-  private:
-    void IncreaseFreeList();
-    std::vector<std::vector<CompressedNode>> m_compressed_geometries;
-    std::vector<unsigned> m_free_list;
-    std::unordered_map<EdgeID, unsigned> m_edge_id_to_list_index_map;
+    String() {}
+    String(const char *value) : value(value) {}
+    String(const std::string &value) : value(value) {}
+    std::string value;
 };
 
-#endif // GEOMETRY_COMPRESSOR_H
+struct Number
+{
+    Number() {}
+    Number(double value) : value(static_cast<double>(value)) {}
+    double value;
+};
+
+struct True
+{
+};
+
+struct False
+{
+};
+
+struct Null
+{
+};
+
+using Value = mapbox::util::variant<String,
+                                    Number,
+                                    mapbox::util::recursive_wrapper<Object>,
+                                    mapbox::util::recursive_wrapper<Array>,
+                                    True,
+                                    False,
+                                    Null>;
+
+struct Object
+{
+    std::unordered_map<std::string, Value> values;
+};
+
+struct Array
+{
+    std::vector<Value> values;
+};
+
+} // namespace JSON
+
+#endif // JSON_CONTAINER_H
diff --git a/DataStructures/LRUCache.h b/data_structures/lru_cache.hpp
similarity index 96%
rename from DataStructures/LRUCache.h
rename to data_structures/lru_cache.hpp
index 75b9139..cdbeb38 100644
--- a/DataStructures/LRUCache.h
+++ b/data_structures/lru_cache.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef LRUCACHE_H
-#define LRUCACHE_H
+#ifndef LRUCACHE_HPP
+#define LRUCACHE_HPP
 
 #include <list>
 #include <unordered_map>
@@ -94,4 +94,4 @@ template <typename KeyT, typename ValueT> class LRUCache
     }
     unsigned Size() const { return itemsInCache.size(); }
 };
-#endif // LRUCACHE_H
+#endif // LRUCACHE_HPP
diff --git a/data_structures/node_based_graph.hpp b/data_structures/node_based_graph.hpp
new file mode 100644
index 0000000..8fe7b75
--- /dev/null
+++ b/data_structures/node_based_graph.hpp
@@ -0,0 +1,271 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef NODE_BASED_GRAPH_HPP
+#define NODE_BASED_GRAPH_HPP
+
+#include "dynamic_graph.hpp"
+#include "import_edge.hpp"
+#include "../Util/simple_logger.hpp"
+
+#include <tbb/parallel_sort.h>
+
+#include <memory>
+
+struct NodeBasedEdgeData
+{
+    NodeBasedEdgeData()
+        : distance(INVALID_EDGE_WEIGHT), edgeBasedNodeID(SPECIAL_NODEID),
+          nameID(std::numeric_limits<unsigned>::max()),
+          isAccessRestricted(false), shortcut(false), forward(false), backward(false),
+          roundabout(false), ignore_in_grid(false), travel_mode(TRAVEL_MODE_INACCESSIBLE)
+    {
+    }
+
+    int distance;
+    unsigned edgeBasedNodeID;
+    unsigned nameID;
+    bool isAccessRestricted : 1;
+    bool shortcut : 1;
+    bool forward : 1;
+    bool backward : 1;
+    bool roundabout : 1;
+    bool ignore_in_grid : 1;
+    TravelMode travel_mode : 4;
+
+    void SwapDirectionFlags()
+    {
+        bool temp_flag = forward;
+        forward = backward;
+        backward = temp_flag;
+    }
+
+    bool IsEqualTo(const NodeBasedEdgeData &other) const
+    {
+        return (forward == other.forward) && (backward == other.backward) &&
+               (nameID == other.nameID) && (ignore_in_grid == other.ignore_in_grid) &&
+               (travel_mode == other.travel_mode);
+    }
+};
+
+struct SimpleEdgeData
+{
+    SimpleEdgeData() : capacity(0) {}
+    EdgeWeight capacity;
+};
+
+using NodeBasedDynamicGraph = DynamicGraph<NodeBasedEdgeData>;
+using SimpleNodeBasedDynamicGraph = DynamicGraph<SimpleEdgeData>;
+
+// Factory method to create NodeBasedDynamicGraph from ImportEdges
+inline std::shared_ptr<NodeBasedDynamicGraph>
+NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge> &input_edge_list)
+{
+    static_assert(sizeof(NodeBasedEdgeData) == 16, "changing node based edge data size changes memory consumption");
+
+    DeallocatingVector<NodeBasedDynamicGraph::InputEdge> edges_list;
+    NodeBasedDynamicGraph::InputEdge edge;
+    for (const ImportEdge &import_edge : input_edge_list)
+    {
+        if (import_edge.forward)
+        {
+            edge.source = import_edge.source;
+            edge.target = import_edge.target;
+            edge.data.forward = import_edge.forward;
+            edge.data.backward = import_edge.backward;
+        }
+        else
+        {
+            edge.source = import_edge.target;
+            edge.target = import_edge.source;
+            edge.data.backward = import_edge.forward;
+            edge.data.forward = import_edge.backward;
+        }
+
+        if (edge.source == edge.target)
+        {
+            continue;
+        }
+
+        edge.data.distance = (std::max)((int)import_edge.weight, 1);
+        BOOST_ASSERT(edge.data.distance > 0);
+        edge.data.shortcut = false;
+        edge.data.roundabout = import_edge.roundabout;
+        edge.data.ignore_in_grid = import_edge.in_tiny_cc;
+        edge.data.nameID = import_edge.name_id;
+        edge.data.isAccessRestricted = import_edge.access_restricted;
+        edge.data.travel_mode = import_edge.travel_mode;
+
+        edges_list.push_back(edge);
+
+        if (!import_edge.is_split)
+        {
+            using std::swap; // enable ADL
+            swap(edge.source, edge.target);
+            edge.data.SwapDirectionFlags();
+            edges_list.push_back(edge);
+        }
+    }
+
+    // remove duplicate edges
+    tbb::parallel_sort(edges_list.begin(), edges_list.end());
+    NodeID edge_count = 0;
+    for (NodeID i = 0; i < edges_list.size(); )
+    {
+        const NodeID source = edges_list[i].source;
+        const NodeID target = edges_list[i].target;
+        // remove eigenloops
+        if (source == target)
+        {
+            i++;
+            continue;
+        }
+        NodeBasedDynamicGraph::InputEdge forward_edge;
+        NodeBasedDynamicGraph::InputEdge reverse_edge;
+        forward_edge = reverse_edge = edges_list[i];
+        forward_edge.data.forward = reverse_edge.data.backward = true;
+        forward_edge.data.backward = reverse_edge.data.forward = false;
+        forward_edge.data.shortcut = reverse_edge.data.shortcut = false;
+        forward_edge.data.distance = reverse_edge.data.distance =
+            std::numeric_limits<int>::max();
+        // remove parallel edges
+        while (i < edges_list.size() && edges_list[i].source == source && edges_list[i].target == target)
+        {
+            if (edges_list[i].data.forward)
+            {
+                forward_edge.data.distance =
+                    std::min(edges_list[i].data.distance, forward_edge.data.distance);
+            }
+            if (edges_list[i].data.backward)
+            {
+                reverse_edge.data.distance =
+                    std::min(edges_list[i].data.distance, reverse_edge.data.distance);
+            }
+            ++i;
+        }
+        // merge edges (s,t) and (t,s) into bidirectional edge
+        if (forward_edge.data.distance == reverse_edge.data.distance)
+        {
+            if ((int)forward_edge.data.distance != std::numeric_limits<int>::max())
+            {
+                forward_edge.data.backward = true;
+                edges_list[edge_count++] = forward_edge;
+            }
+        }
+        else
+        { // insert seperate edges
+            if (((int)forward_edge.data.distance) != std::numeric_limits<int>::max())
+            {
+                edges_list[edge_count++] = forward_edge;
+            }
+            if ((int)reverse_edge.data.distance != std::numeric_limits<int>::max())
+            {
+                edges_list[edge_count++] = reverse_edge;
+            }
+        }
+    }
+    edges_list.resize(edge_count);
+    SimpleLogger().Write() << "merged " << edges_list.size() - edge_count << " edges out of " << edges_list.size();
+
+    auto graph = std::make_shared<NodeBasedDynamicGraph>(static_cast<NodeBasedDynamicGraph::NodeIterator>(number_of_nodes), edges_list);
+    return graph;
+}
+
+template<class SimpleEdgeT>
+inline std::shared_ptr<SimpleNodeBasedDynamicGraph>
+SimpleNodeBasedDynamicGraphFromEdges(int number_of_nodes, std::vector<SimpleEdgeT> &input_edge_list)
+{
+    static_assert(sizeof(NodeBasedEdgeData) == 16, "changing node based edge data size changes memory consumption");
+    tbb::parallel_sort(input_edge_list.begin(), input_edge_list.end());
+
+    DeallocatingVector<SimpleNodeBasedDynamicGraph::InputEdge> edges_list;
+    SimpleNodeBasedDynamicGraph::InputEdge edge;
+    edge.data.capacity = 1;
+    for (const SimpleEdgeT &import_edge : input_edge_list)
+    {
+        if (import_edge.source == import_edge.target)
+        {
+            continue;
+        }
+        edge.source = import_edge.source;
+        edge.target = import_edge.target;
+        edges_list.push_back(edge);
+        std::swap(edge.source, edge.target);
+        edges_list.push_back(edge);
+    }
+
+     // remove duplicate edges
+    tbb::parallel_sort(edges_list.begin(), edges_list.end());
+    NodeID edge_count = 0;
+    for (NodeID i = 0; i < edges_list.size(); )
+    {
+        const NodeID source = edges_list[i].source;
+        const NodeID target = edges_list[i].target;
+        // remove eigenloops
+        if (source == target)
+        {
+            i++;
+            continue;
+        }
+        SimpleNodeBasedDynamicGraph::InputEdge forward_edge;
+        SimpleNodeBasedDynamicGraph::InputEdge reverse_edge;
+        forward_edge = reverse_edge = edges_list[i];
+        forward_edge.data.capacity = reverse_edge.data.capacity = INVALID_EDGE_WEIGHT;
+        // remove parallel edges
+        while (i < edges_list.size() && edges_list[i].source == source && edges_list[i].target == target)
+        {
+            forward_edge.data.capacity = std::min(edges_list[i].data.capacity, forward_edge.data.capacity);
+            reverse_edge.data.capacity = std::min(edges_list[i].data.capacity, reverse_edge.data.capacity);
+            ++i;
+        }
+        // merge edges (s,t) and (t,s) into bidirectional edge
+        if (forward_edge.data.capacity == reverse_edge.data.capacity)
+        {
+            if ((int)forward_edge.data.capacity != INVALID_EDGE_WEIGHT)
+            {
+                edges_list[edge_count++] = forward_edge;
+            }
+        }
+        else
+        { // insert seperate edges
+            if (((int)forward_edge.data.capacity) != INVALID_EDGE_WEIGHT)
+            {
+                edges_list[edge_count++] = forward_edge;
+            }
+            if ((int)reverse_edge.data.capacity != INVALID_EDGE_WEIGHT)
+            {
+                edges_list[edge_count++] = reverse_edge;
+            }
+        }
+    }
+    SimpleLogger().Write() << "merged " << edges_list.size() - edge_count << " edges out of " << edges_list.size();
+
+    auto graph = std::make_shared<SimpleNodeBasedDynamicGraph>(number_of_nodes, edges_list);
+    return graph;
+}
+
+#endif // NODE_BASED_GRAPH_HPP
diff --git a/Server/Http/CompressionType.h b/data_structures/node_id.hpp
similarity index 77%
copy from Server/Http/CompressionType.h
copy to data_structures/node_id.hpp
index 74d0b62..4f07809 100644
--- a/Server/Http/CompressionType.h
+++ b/data_structures/node_id.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,17 +25,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef COMPRESSION_TYPE_H
-#define COMPRESSION_TYPE_H
+#ifndef NODE_ID_HPP
+#define NODE_ID_HPP
 
-namespace http
-{
-
-enum CompressionType
-{ noCompression,
-  gzipRFC1952,
-  deflateRFC1951 };
+#include "../typedefs.h"
 
-} // namespace http
+struct Cmp
+{
+    using value_type = NodeID;
+    bool operator()(const NodeID left, const NodeID right) const { return left < right; }
+    value_type max_value() { return 0xffffffff; }
+    value_type min_value() { return 0x0; }
+};
 
-#endif // COMPRESSION_TYPE_H
+#endif // NODE_ID_HPP
diff --git a/DataStructures/OriginalEdgeData.h b/data_structures/original_edge_data.hpp
similarity index 79%
rename from DataStructures/OriginalEdgeData.h
rename to data_structures/original_edge_data.hpp
index f75aeda..b4fdfd9 100644
--- a/DataStructures/OriginalEdgeData.h
+++ b/data_structures/original_edge_data.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,10 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef ORIGINAL_EDGE_DATA_H
-#define ORIGINAL_EDGE_DATA_H
+#ifndef ORIGINAL_EDGE_DATA_HPP
+#define ORIGINAL_EDGE_DATA_HPP
 
-#include "TurnInstructions.h"
+#include "travel_mode.hpp"
+#include "turn_instructions.hpp"
 #include "../typedefs.h"
 
 #include <limits>
@@ -38,16 +39,18 @@ struct OriginalEdgeData
     explicit OriginalEdgeData(NodeID via_node,
                               unsigned name_id,
                               TurnInstruction turn_instruction,
-                              bool compressed_geometry)
+                              bool compressed_geometry,
+                              TravelMode travel_mode)
         : via_node(via_node), name_id(name_id), turn_instruction(turn_instruction),
-          compressed_geometry(compressed_geometry)
+          compressed_geometry(compressed_geometry), travel_mode(travel_mode)
     {
     }
 
     OriginalEdgeData()
         : via_node(std::numeric_limits<unsigned>::max()),
           name_id(std::numeric_limits<unsigned>::max()),
-          turn_instruction(TurnInstruction::NoTurn), compressed_geometry(false)
+          turn_instruction(TurnInstruction::NoTurn), compressed_geometry(false),
+          travel_mode(TRAVEL_MODE_INACCESSIBLE)
     {
     }
 
@@ -55,6 +58,7 @@ struct OriginalEdgeData
     unsigned name_id;
     TurnInstruction turn_instruction;
     bool compressed_geometry;
+    TravelMode travel_mode;
 };
 
-#endif // ORIGINAL_EDGE_DATA_H
+#endif // ORIGINAL_EDGE_DATA_HPP
diff --git a/DataStructures/Percent.h b/data_structures/percent.hpp
similarity index 93%
rename from DataStructures/Percent.h
rename to data_structures/percent.hpp
index f201fc8..0c4e152 100644
--- a/DataStructures/Percent.h
+++ b/data_structures/percent.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef PERCENT_H
-#define PERCENT_H
+#ifndef PERCENT_HPP
+#define PERCENT_HPP
 
 #include <iostream>
 #include <atomic>
@@ -53,7 +53,7 @@ class Percent
         if (current_value >= m_next_threshold)
         {
             m_next_threshold += m_percent_interval;
-            printPercent(current_value / (double)m_max_value * 100);
+            printPercent(current_value / static_cast<double>(m_max_value) * 100.);
         }
         if (current_value + 1 == m_max_value)
             std::cout << " 100%" << std::endl;
@@ -98,4 +98,4 @@ class Percent
     }
 };
 
-#endif // PERCENT_H
+#endif // PERCENT_HPP
diff --git a/data_structures/phantom_node.cpp b/data_structures/phantom_node.cpp
new file mode 100644
index 0000000..413c0d7
--- /dev/null
+++ b/data_structures/phantom_node.cpp
@@ -0,0 +1,124 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "phantom_node.hpp"
+
+PhantomNode::PhantomNode(NodeID forward_node_id, NodeID reverse_node_id, unsigned name_id,
+            int forward_weight, int reverse_weight, int forward_offset, int reverse_offset,
+            unsigned packed_geometry_id, unsigned component_id, FixedPointCoordinate &location,
+            unsigned short fwd_segment_position,
+            TravelMode forward_travel_mode, TravelMode backward_travel_mode) :
+    forward_node_id(forward_node_id),
+    reverse_node_id(reverse_node_id),
+    name_id(name_id),
+    forward_weight(forward_weight),
+    reverse_weight(reverse_weight),
+    forward_offset(forward_offset),
+    reverse_offset(reverse_offset),
+    packed_geometry_id(packed_geometry_id),
+    component_id(component_id),
+    location(location),
+    fwd_segment_position(fwd_segment_position),
+    forward_travel_mode(forward_travel_mode),
+    backward_travel_mode(backward_travel_mode)
+{ }
+
+PhantomNode::PhantomNode() :
+    forward_node_id(SPECIAL_NODEID),
+    reverse_node_id(SPECIAL_NODEID),
+    name_id(std::numeric_limits<unsigned>::max()),
+    forward_weight(INVALID_EDGE_WEIGHT),
+    reverse_weight(INVALID_EDGE_WEIGHT),
+    forward_offset(0),
+    reverse_offset(0),
+    packed_geometry_id(SPECIAL_EDGEID),
+    component_id(-1),
+    fwd_segment_position(0),
+    forward_travel_mode(TRAVEL_MODE_INACCESSIBLE),
+    backward_travel_mode(TRAVEL_MODE_INACCESSIBLE)
+{ }
+
+int PhantomNode::GetForwardWeightPlusOffset() const
+{
+    if (SPECIAL_NODEID == forward_node_id)
+    {
+        return 0;
+    }
+    return forward_offset + forward_weight;
+}
+
+int PhantomNode::GetReverseWeightPlusOffset() const
+{
+    if (SPECIAL_NODEID == reverse_node_id)
+    {
+        return 0;
+    }
+    return reverse_offset + reverse_weight;
+}
+
+bool PhantomNode::is_bidirected() const
+{
+    return (forward_node_id != SPECIAL_NODEID) &&
+           (reverse_node_id != SPECIAL_NODEID);
+}
+
+bool PhantomNode::is_compressed() const
+{
+    return (forward_offset != 0) || (reverse_offset != 0);
+}
+
+bool PhantomNode::is_valid(const unsigned number_of_nodes) const
+{
+    return
+        location.is_valid() &&
+        (
+            (forward_node_id < number_of_nodes) ||
+            (reverse_node_id < number_of_nodes)
+        ) &&
+        (
+            (forward_weight != INVALID_EDGE_WEIGHT) ||
+            (reverse_weight != INVALID_EDGE_WEIGHT)
+        ) &&
+        (name_id != INVALID_NAMEID
+    );
+}
+
+bool PhantomNode::is_in_tiny_component() const
+{
+    return component_id != 0;
+}
+
+bool PhantomNode::is_valid() const
+{
+    return location.is_valid() &&
+           (name_id != INVALID_NAMEID);
+}
+
+bool PhantomNode::operator==(const PhantomNode & other) const
+{
+    return location == other.location;
+}
diff --git a/data_structures/phantom_node.hpp b/data_structures/phantom_node.hpp
new file mode 100644
index 0000000..9286fb9
--- /dev/null
+++ b/data_structures/phantom_node.hpp
@@ -0,0 +1,129 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef PHANTOM_NODES_H
+#define PHANTOM_NODES_H
+
+#include <osrm/Coordinate.h>
+#include "../data_structures/travel_mode.hpp"
+#include "../typedefs.h"
+
+#include <iostream>
+#include <vector>
+
+struct PhantomNode
+{
+    PhantomNode(NodeID forward_node_id,
+                NodeID reverse_node_id,
+                unsigned name_id,
+                int forward_weight,
+                int reverse_weight,
+                int forward_offset,
+                int reverse_offset,
+                unsigned packed_geometry_id,
+                unsigned component_id,
+                FixedPointCoordinate &location,
+                unsigned short fwd_segment_position,
+                TravelMode forward_travel_mode,
+                TravelMode backward_travel_mode);
+
+    PhantomNode();
+
+    NodeID forward_node_id;
+    NodeID reverse_node_id;
+    unsigned name_id;
+    int forward_weight;
+    int reverse_weight;
+    int forward_offset;
+    int reverse_offset;
+    unsigned packed_geometry_id;
+    unsigned component_id;
+    FixedPointCoordinate location;
+    unsigned short fwd_segment_position;
+    TravelMode forward_travel_mode : 4;
+    TravelMode backward_travel_mode : 4;
+
+    int GetForwardWeightPlusOffset() const;
+
+    int GetReverseWeightPlusOffset() const;
+
+    bool is_bidirected() const;
+
+    bool is_compressed() const;
+
+    bool is_valid(const unsigned numberOfNodes) const;
+
+    bool is_valid() const;
+
+    bool is_in_tiny_component() const;
+
+    bool operator==(const PhantomNode & other) const;
+};
+
+using PhantomNodeArray = std::vector<std::vector<PhantomNode>>;
+
+class phantom_node_pair : public std::pair<PhantomNode, PhantomNode>
+{
+
+};
+
+struct PhantomNodeLists
+{
+    std::vector<PhantomNode> source_phantom_list;
+    std::vector<PhantomNode> target_phantom_list;
+};
+
+struct PhantomNodes
+{
+    PhantomNode source_phantom;
+    PhantomNode target_phantom;
+};
+
+inline std::ostream& operator<<(std::ostream &out, const PhantomNodes & pn)
+{
+    out << "source_coord: " << pn.source_phantom.location << "\n";
+    out << "target_coord: " << pn.target_phantom.location << std::endl;
+    return out;
+}
+
+inline std::ostream& operator<<(std::ostream &out, const PhantomNode & pn)
+{
+    out <<  "node1: " << pn.forward_node_id      << ", " <<
+            "node2: " << pn.reverse_node_id      << ", " <<
+            "name: "  << pn.name_id              << ", " <<
+            "fwd-w: " << pn.forward_weight       << ", " <<
+            "rev-w: " << pn.reverse_weight       << ", " <<
+            "fwd-o: " << pn.forward_offset       << ", " <<
+            "rev-o: " << pn.reverse_offset       << ", " <<
+            "geom: "  << pn.packed_geometry_id   << ", " <<
+            "comp: "  << pn.component_id         << ", " <<
+            "pos: "   << pn.fwd_segment_position << ", " <<
+            "loc: "   << pn.location;
+    return out;
+}
+
+#endif // PHANTOM_NODES_H
diff --git a/DataStructures/QueryEdge.h b/data_structures/query_edge.hpp
similarity index 75%
rename from DataStructures/QueryEdge.h
rename to data_structures/query_edge.hpp
index b84c180..84a7f15 100644
--- a/DataStructures/QueryEdge.h
+++ b/data_structures/query_edge.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef QUERYEDGE_H_
-#define QUERYEDGE_H_
+#ifndef QUERYEDGE_HPP_
+#define QUERYEDGE_HPP_
 
 #include "../typedefs.h"
 
@@ -36,6 +36,16 @@ struct QueryEdge
     NodeID target;
     struct EdgeData
     {
+        EdgeData() : id(0), shortcut(false), distance(0), forward(false), backward(false) {}
+
+        template <class OtherT> EdgeData(const OtherT &other)
+        {
+            distance = other.distance;
+            shortcut = other.shortcut;
+            id = other.id;
+            forward = other.forward;
+            backward = other.backward;
+        }
         NodeID id : 31;
         bool shortcut : 1;
         int distance : 30;
@@ -43,6 +53,13 @@ struct QueryEdge
         bool backward : 1;
     } data;
 
+    QueryEdge() : source(SPECIAL_NODEID), target(SPECIAL_NODEID) {}
+
+    QueryEdge(NodeID source, NodeID target, EdgeData data)
+        : source(source), target(target), data(data)
+    {
+    }
+
     bool operator<(const QueryEdge &right) const
     {
         if (source != right.source)
@@ -61,4 +78,4 @@ struct QueryEdge
     }
 };
 
-#endif /* QUERYEDGE_H_ */
+#endif /* QUERYEDGE_HPP_ */
diff --git a/DataStructures/QueryNode.h b/data_structures/query_node.hpp
similarity index 68%
rename from DataStructures/QueryNode.h
rename to data_structures/query_node.hpp
index ee6b278..7705df0 100644
--- a/DataStructures/QueryNode.h
+++ b/data_structures/query_node.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef QUERY_NODE_H
-#define QUERY_NODE_H
+#ifndef QUERY_NODE_HPP
+#define QUERY_NODE_HPP
 
 #include "../typedefs.h"
 
@@ -36,13 +36,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <limits>
 
-struct NodeInfo
+struct QueryNode
 {
-    typedef NodeID key_type; // type of NodeID
-    typedef int value_type; // type of lat,lons
+    using key_type = NodeID; // type of NodeID
+    using value_type = int; // type of lat,lons
 
-    explicit NodeInfo(int lat, int lon, NodeID node_id) : lat(lat), lon(lon), node_id(node_id) {}
-    NodeInfo()
+    explicit QueryNode(int lat, int lon, NodeID node_id) : lat(lat), lon(lon), node_id(node_id) {}
+    QueryNode()
         : lat(std::numeric_limits<int>::max()), lon(std::numeric_limits<int>::max()),
           node_id(std::numeric_limits<unsigned>::max())
     {
@@ -52,18 +52,18 @@ struct NodeInfo
     int lon;
     NodeID node_id;
 
-    static NodeInfo min_value()
+    static QueryNode min_value()
     {
-        return NodeInfo(static_cast<int>(-90 * COORDINATE_PRECISION),
-                        static_cast<int>(-180 * COORDINATE_PRECISION),
-                        std::numeric_limits<NodeID>::min());
+        return QueryNode(static_cast<int>(-90 * COORDINATE_PRECISION),
+                         static_cast<int>(-180 * COORDINATE_PRECISION),
+                         std::numeric_limits<NodeID>::min());
     }
 
-    static NodeInfo max_value()
+    static QueryNode max_value()
     {
-        return NodeInfo(static_cast<int>(90 * COORDINATE_PRECISION),
-                        static_cast<int>(180 * COORDINATE_PRECISION),
-                        std::numeric_limits<NodeID>::max());
+        return QueryNode(static_cast<int>(90 * COORDINATE_PRECISION),
+                         static_cast<int>(180 * COORDINATE_PRECISION),
+                         std::numeric_limits<NodeID>::max());
     }
 
     value_type operator[](const std::size_t n) const
@@ -78,8 +78,8 @@ struct NodeInfo
             break;
         }
         BOOST_ASSERT_MSG(false, "should not happen");
-        return std::numeric_limits<unsigned>::max();
+        return std::numeric_limits<int>::lowest();
     }
 };
 
-#endif // QUERY_NODE_H
+#endif // QUERY_NODE_HPP
diff --git a/DataStructures/RangeTable.h b/data_structures/range_table.hpp
similarity index 79%
rename from DataStructures/RangeTable.h
rename to data_structures/range_table.hpp
index f9ec254..eef268b 100644
--- a/DataStructures/RangeTable.h
+++ b/data_structures/range_table.hpp
@@ -1,10 +1,36 @@
-#ifndef __RANGE_TABLE_H__
-#define __RANGE_TABLE_H__
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
 
-#include "SharedMemoryFactory.h"
-#include "SharedMemoryVectorWrapper.h"
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include <boost/range/irange.hpp>
+*/
+
+#ifndef RANGE_TABLE_HPP
+#define RANGE_TABLE_HPP
+
+#include "../Util/integer_range.hpp"
+#include "shared_memory_factory.hpp"
+#include "shared_memory_vector_wrapper.hpp"
 
 #include <fstream>
 #include <vector>
@@ -37,10 +63,10 @@ class RangeTable
 {
 public:
 
-    typedef std::array<unsigned char, BLOCK_SIZE> BlockT;
-    typedef typename ShM<BlockT, USE_SHARED_MEMORY>::vector   BlockContainerT;
-    typedef typename ShM<unsigned, USE_SHARED_MEMORY>::vector OffsetContainerT;
-    typedef decltype(boost::irange(0u,0u))                    RangeT;
+    using BlockT = std::array<unsigned char, BLOCK_SIZE>;
+    using BlockContainerT = typename ShM<BlockT, USE_SHARED_MEMORY>::vector;
+    using OffsetContainerT = typename ShM<unsigned, USE_SHARED_MEMORY>::vector;
+    using RangeT = osrm::range<unsigned>;
 
     friend std::ostream& operator<< <>(std::ostream &out, const RangeTable &table);
     friend std::istream& operator>> <>(std::istream &in, RangeTable &table);
@@ -117,7 +143,8 @@ public:
         {
             // the last value is used as sentinel
             block_offsets.push_back(lengths_prefix_sum);
-            block_idx = (block_idx + 1) % BLOCK_SIZE;
+            block_idx = 1;
+            last_length = 0;
         }
 
         while (0 != block_idx)
@@ -166,7 +193,7 @@ public:
         BOOST_ASSERT(begin_idx < sum_lengths && end_idx <= sum_lengths);
         BOOST_ASSERT(begin_idx <= end_idx);
 
-        return boost::irange(begin_idx, end_idx);
+        return osrm::irange(begin_idx, end_idx);
     }
 private:
 
@@ -228,4 +255,4 @@ std::istream& operator>>(std::istream &in, RangeTable<BLOCK_SIZE, USE_SHARED_MEM
     return in;
 }
 
-#endif
+#endif //RANGE_TABLE_HPP
diff --git a/DataStructures/RawRouteData.h b/data_structures/raw_route_data.hpp
similarity index 73%
rename from DataStructures/RawRouteData.h
rename to data_structures/raw_route_data.hpp
index e034b43..f9242cf 100644
--- a/DataStructures/RawRouteData.h
+++ b/data_structures/raw_route_data.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,11 +25,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef RAW_ROUTE_DATA_H
-#define RAW_ROUTE_DATA_H
+#ifndef RAW_ROUTE_DATA_HPP
+#define RAW_ROUTE_DATA_HPP
 
-#include "../DataStructures/PhantomNodes.h"
-#include "../DataStructures/TurnInstructions.h"
+#include "../data_structures/phantom_node.hpp"
+#include "../data_structures/travel_mode.hpp"
+#include "../data_structures/turn_instructions.hpp"
 #include "../typedefs.h"
 
 #include <osrm/Coordinate.h>
@@ -41,18 +42,25 @@ struct PathData
     PathData()
         : node(SPECIAL_NODEID), name_id(INVALID_EDGE_WEIGHT),
           segment_duration(INVALID_EDGE_WEIGHT),
-          turn_instruction(TurnInstruction::NoTurn)
+          turn_instruction(TurnInstruction::NoTurn),
+          travel_mode(TRAVEL_MODE_INACCESSIBLE)
     {
     }
 
-    PathData(NodeID node, unsigned name_id, TurnInstruction turn_instruction, EdgeWeight segment_duration)
-        : node(node), name_id(name_id), segment_duration(segment_duration), turn_instruction(turn_instruction)
+    PathData(NodeID node,
+             unsigned name_id,
+             TurnInstruction turn_instruction,
+             EdgeWeight segment_duration,
+             TravelMode travel_mode)
+        : node(node), name_id(name_id), segment_duration(segment_duration), turn_instruction(turn_instruction),
+          travel_mode(travel_mode)
     {
     }
     NodeID node;
     unsigned name_id;
     EdgeWeight segment_duration;
     TurnInstruction turn_instruction;
+    TravelMode travel_mode : 4;
 };
 
 struct RawRouteData
@@ -60,21 +68,23 @@ struct RawRouteData
     std::vector<std::vector<PathData>> unpacked_path_segments;
     std::vector<PathData> unpacked_alternative;
     std::vector<PhantomNodes> segment_end_coordinates;
-    std::vector<FixedPointCoordinate> raw_via_node_coordinates;
     std::vector<bool> source_traversed_in_reverse;
     std::vector<bool> target_traversed_in_reverse;
     std::vector<bool> alt_source_traversed_in_reverse;
     std::vector<bool> alt_target_traversed_in_reverse;
-    unsigned check_sum;
     int shortest_path_length;
     int alternative_path_length;
 
-    RawRouteData()
-        : check_sum(SPECIAL_NODEID),
+    bool is_via_leg(const std::size_t leg) const
+    {
+        return (leg != unpacked_path_segments.size() - 1);
+    }
+
+    RawRouteData() :
           shortest_path_length(INVALID_EDGE_WEIGHT),
           alternative_path_length(INVALID_EDGE_WEIGHT)
     {
     }
 };
 
-#endif // RAW_ROUTE_DATA_H
+#endif // RAW_ROUTE_DATA_HPP
diff --git a/data_structures/rectangle.hpp b/data_structures/rectangle.hpp
new file mode 100644
index 0000000..2f6815c
--- /dev/null
+++ b/data_structures/rectangle.hpp
@@ -0,0 +1,199 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef RECTANGLE_HPP
+#define RECTANGLE_HPP
+
+#include <boost/assert.hpp>
+
+#include <algorithm>
+#include <cstdint>
+#include <limits>
+
+// TODO: Make template type, add tests
+struct RectangleInt2D
+{
+    RectangleInt2D() : min_lon(std::numeric_limits<int32_t>::max()),
+                       max_lon(std::numeric_limits<int32_t>::min()),
+                       min_lat(std::numeric_limits<int32_t>::max()),
+                       max_lat(std::numeric_limits<int32_t>::min()) {}
+
+    int32_t min_lon, max_lon;
+    int32_t min_lat, max_lat;
+
+    inline void MergeBoundingBoxes(const RectangleInt2D &other)
+    {
+        min_lon = std::min(min_lon, other.min_lon);
+        max_lon = std::max(max_lon, other.max_lon);
+        min_lat = std::min(min_lat, other.min_lat);
+        max_lat = std::max(max_lat, other.max_lat);
+        BOOST_ASSERT(min_lat != std::numeric_limits<int32_t>::min());
+        BOOST_ASSERT(min_lon != std::numeric_limits<int32_t>::min());
+        BOOST_ASSERT(max_lat != std::numeric_limits<int32_t>::min());
+        BOOST_ASSERT(max_lon != std::numeric_limits<int32_t>::min());
+    }
+
+    inline FixedPointCoordinate Centroid() const
+    {
+        FixedPointCoordinate centroid;
+        // The coordinates of the midpoints are given by:
+        // x = (x1 + x2) /2 and y = (y1 + y2) /2.
+        centroid.lon = (min_lon + max_lon) / 2;
+        centroid.lat = (min_lat + max_lat) / 2;
+        return centroid;
+    }
+
+    inline bool Intersects(const RectangleInt2D &other) const
+    {
+        FixedPointCoordinate upper_left(other.max_lat, other.min_lon);
+        FixedPointCoordinate upper_right(other.max_lat, other.max_lon);
+        FixedPointCoordinate lower_right(other.min_lat, other.max_lon);
+        FixedPointCoordinate lower_left(other.min_lat, other.min_lon);
+
+        return (Contains(upper_left) || Contains(upper_right) || Contains(lower_right) ||
+                Contains(lower_left));
+    }
+
+    inline float GetMinDist(const FixedPointCoordinate &location) const
+    {
+        const bool is_contained = Contains(location);
+        if (is_contained)
+        {
+            return 0.0f;
+        }
+
+        enum Direction
+        {
+            INVALID    = 0,
+            NORTH      = 1,
+            SOUTH      = 2,
+            EAST       = 4,
+            NORTH_EAST = 5,
+            SOUTH_EAST = 6,
+            WEST       = 8,
+            NORTH_WEST = 9,
+            SOUTH_WEST = 10
+        };
+
+        Direction d = INVALID;
+        if (location.lat > max_lat)
+            d = (Direction) (d | NORTH);
+        else if (location.lat < min_lat)
+            d = (Direction) (d | SOUTH);
+        if (location.lon > max_lon)
+            d = (Direction) (d | EAST);
+        else if (location.lon < min_lon)
+            d = (Direction) (d | WEST);
+
+        BOOST_ASSERT(d != INVALID);
+
+        float min_dist = std::numeric_limits<float>::max();
+        switch (d)
+        {
+            case NORTH:
+                min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, location.lon));
+                break;
+            case SOUTH:
+                min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, location.lon));
+                break;
+            case WEST:
+                min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, min_lon));
+                break;
+            case EAST:
+                min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, max_lon));
+                break;
+            case NORTH_EAST:
+                min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, max_lon));
+                break;
+            case NORTH_WEST:
+                min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, min_lon));
+                break;
+            case SOUTH_EAST:
+                min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, max_lon));
+                break;
+            case SOUTH_WEST:
+                min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, min_lon));
+                break;
+            default:
+                break;
+        }
+
+        BOOST_ASSERT(min_dist != std::numeric_limits<float>::max());
+
+        return min_dist;
+    }
+
+    inline float GetMinMaxDist(const FixedPointCoordinate &location) const
+    {
+        float min_max_dist = std::numeric_limits<float>::max();
+        // Get minmax distance to each of the four sides
+        const FixedPointCoordinate upper_left(max_lat, min_lon);
+        const FixedPointCoordinate upper_right(max_lat, max_lon);
+        const FixedPointCoordinate lower_right(min_lat, max_lon);
+        const FixedPointCoordinate lower_left(min_lat, min_lon);
+
+        min_max_dist = std::min(
+            min_max_dist,
+            std::max(
+                FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left),
+                FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right)));
+
+        min_max_dist = std::min(
+            min_max_dist,
+            std::max(
+                FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right),
+                FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right)));
+
+        min_max_dist = std::min(
+            min_max_dist,
+            std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right),
+                     FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left)));
+
+        min_max_dist = std::min(
+            min_max_dist,
+            std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left),
+                     FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left)));
+        return min_max_dist;
+    }
+
+    inline bool Contains(const FixedPointCoordinate &location) const
+    {
+        const bool lats_contained = (location.lat >= min_lat) && (location.lat <= max_lat);
+        const bool lons_contained = (location.lon >= min_lon) && (location.lon <= max_lon);
+        return lats_contained && lons_contained;
+    }
+
+    inline friend std::ostream &operator<<(std::ostream &out, const RectangleInt2D &rect)
+    {
+        out << rect.min_lat / COORDINATE_PRECISION << "," << rect.min_lon / COORDINATE_PRECISION
+            << " " << rect.max_lat / COORDINATE_PRECISION << ","
+            << rect.max_lon / COORDINATE_PRECISION;
+        return out;
+    }
+};
+
+#endif
diff --git a/DataStructures/Restriction.h b/data_structures/restriction.hpp
similarity index 56%
rename from DataStructures/Restriction.h
rename to data_structures/restriction.hpp
index 2b166f5..5f6e9b0 100644
--- a/DataStructures/Restriction.h
+++ b/data_structures/restriction.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef RESTRICTION_H
-#define RESTRICTION_H
+#ifndef RESTRICTION_HPP
+#define RESTRICTION_HPP
 
 #include "../typedefs.h"
 
@@ -34,19 +34,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct TurnRestriction
 {
-    NodeID viaNode;
-    NodeID fromNode;
-    NodeID toNode;
+    union WayOrNode
+    {
+        NodeID node;
+        EdgeID way;
+    };
+    WayOrNode via;
+    WayOrNode from;
+    WayOrNode to;
+
     struct Bits
     { // mostly unused
         Bits()
-            : isOnly(false), unused1(false), unused2(false), unused3(false), unused4(false),
+            : is_only(false), uses_via_way(false), unused2(false), unused3(false), unused4(false),
               unused5(false), unused6(false), unused7(false)
         {
         }
 
-        bool isOnly : 1;
-        bool unused1 : 1;
+        bool is_only : 1;
+        bool uses_via_way : 1;
         bool unused2 : 1;
         bool unused3 : 1;
         bool unused4 : 1;
@@ -55,57 +61,57 @@ struct TurnRestriction
         bool unused7 : 1;
     } flags;
 
-    explicit TurnRestriction(NodeID viaNode)
-        : viaNode(viaNode), fromNode(std::numeric_limits<unsigned>::max()),
-          toNode(std::numeric_limits<unsigned>::max())
+    explicit TurnRestriction(NodeID node)
     {
+        via.node = node;
+        from.node = SPECIAL_NODEID;
+        to.node = SPECIAL_NODEID;
     }
 
-    explicit TurnRestriction(const bool isOnly = false)
-        : viaNode(std::numeric_limits<unsigned>::max()),
-          fromNode(std::numeric_limits<unsigned>::max()),
-          toNode(std::numeric_limits<unsigned>::max())
+    explicit TurnRestriction(const bool is_only = false)
     {
-        flags.isOnly = isOnly;
+        via.node = SPECIAL_NODEID;
+        from.node = SPECIAL_NODEID;
+        to.node = SPECIAL_NODEID;
+        flags.is_only = is_only;
     }
 };
 
 struct InputRestrictionContainer
 {
-    EdgeID fromWay;
-    EdgeID toWay;
-    unsigned viaNode;
+    // EdgeID fromWay;
+    // EdgeID toWay;
+    // NodeID via_node;
     TurnRestriction restriction;
 
-    InputRestrictionContainer(EdgeID fromWay, EdgeID toWay, NodeID vn, unsigned vw)
-        : fromWay(fromWay), toWay(toWay), viaNode(vw)
+    InputRestrictionContainer(EdgeID fromWay, EdgeID toWay, EdgeID vw)
     {
-        restriction.viaNode = vn;
+        restriction.from.way = fromWay;
+        restriction.to.way = toWay;
+        restriction.via.way = vw;
     }
-    explicit InputRestrictionContainer(bool isOnly = false)
-        : fromWay(std::numeric_limits<unsigned>::max()),
-          toWay(std::numeric_limits<unsigned>::max()), viaNode(std::numeric_limits<unsigned>::max())
+    explicit InputRestrictionContainer(bool is_only = false)
     {
-        restriction.flags.isOnly = isOnly;
+        restriction.from.way = SPECIAL_EDGEID;
+        restriction.to.way = SPECIAL_EDGEID;
+        restriction.via.node = SPECIAL_NODEID;
+        restriction.flags.is_only = is_only;
     }
 
-    static InputRestrictionContainer min_value() { return InputRestrictionContainer(0, 0, 0, 0); }
+    static InputRestrictionContainer min_value() { return InputRestrictionContainer(0, 0, 0); }
     static InputRestrictionContainer max_value()
     {
-        return InputRestrictionContainer(std::numeric_limits<unsigned>::max(),
-                                         std::numeric_limits<unsigned>::max(),
-                                         std::numeric_limits<unsigned>::max(),
-                                         std::numeric_limits<unsigned>::max());
+        return InputRestrictionContainer(SPECIAL_EDGEID, SPECIAL_EDGEID, SPECIAL_EDGEID);
     }
 };
 
 struct CmpRestrictionContainerByFrom
 {
     typedef InputRestrictionContainer value_type;
-    inline bool operator()(const InputRestrictionContainer &a, const InputRestrictionContainer &b)
-        const
+    inline bool operator()(const InputRestrictionContainer &a,
+                           const InputRestrictionContainer &b) const
     {
-        return a.fromWay < b.fromWay;
+        return a.restriction.from.way < b.restriction.from.way;
     }
     inline value_type max_value() const { return InputRestrictionContainer::max_value(); }
     inline value_type min_value() const { return InputRestrictionContainer::min_value(); }
@@ -114,13 +120,13 @@ struct CmpRestrictionContainerByFrom
 struct CmpRestrictionContainerByTo
 {
     typedef InputRestrictionContainer value_type;
-    inline bool operator()(const InputRestrictionContainer &a, const InputRestrictionContainer &b)
-        const
+    inline bool operator()(const InputRestrictionContainer &a,
+                           const InputRestrictionContainer &b) const
     {
-        return a.toWay < b.toWay;
+        return a.restriction.to.way < b.restriction.to.way;
     }
     value_type max_value() const { return InputRestrictionContainer::max_value(); }
     value_type min_value() const { return InputRestrictionContainer::min_value(); }
 };
 
-#endif // RESTRICTION_H
+#endif // RESTRICTION_HPP
diff --git a/DataStructures/RestrictionMap.cpp b/data_structures/restriction_map.cpp
similarity index 56%
rename from DataStructures/RestrictionMap.cpp
rename to data_structures/restriction_map.cpp
index 1859b82..3c13d73 100644
--- a/DataStructures/RestrictionMap.cpp
+++ b/data_structures/restriction_map.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,105 +25,56 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "RestrictionMap.h"
-#include "NodeBasedGraph.h"
+#include "restriction_map.hpp"
 
-#include "../Util/SimpleLogger.h"
-
-bool RestrictionMap::IsViaNode(const NodeID node) const
-{
-    return m_no_turn_via_node_set.find(node) != m_no_turn_via_node_set.end();
-}
-
-RestrictionMap::RestrictionMap(const std::shared_ptr<NodeBasedDynamicGraph> &graph,
-                               const std::vector<TurnRestriction> &restriction_list)
-    : m_count(0), m_graph(graph)
-{
-    // decompose restriction consisting of a start, via and end node into a
-    // a pair of starting edge and a list of all end nodes
-    for (auto &restriction : restriction_list)
+RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_list)
+        : m_count(0)
     {
-        m_restriction_start_nodes.insert(restriction.fromNode);
-        m_no_turn_via_node_set.insert(restriction.viaNode);
+        // decompose restriction consisting of a start, via and end node into a
+        // a pair of starting edge and a list of all end nodes
+        for (auto &restriction : restriction_list)
+        {
+            m_restriction_start_nodes.insert(restriction.from.node);
+            m_no_turn_via_node_set.insert(restriction.via.node);
 
-        RestrictionSource restriction_source = {restriction.fromNode, restriction.viaNode};
+            RestrictionSource restriction_source = {restriction.from.node, restriction.via.node};
 
-        unsigned index;
-        auto restriction_iter = m_restriction_map.find(restriction_source);
-        if (restriction_iter == m_restriction_map.end())
-        {
-            index = m_restriction_bucket_list.size();
-            m_restriction_bucket_list.resize(index + 1);
-            m_restriction_map.emplace(restriction_source, index);
-        }
-        else
-        {
-            index = restriction_iter->second;
-            // Map already contains an is_only_*-restriction
-            if (m_restriction_bucket_list.at(index).begin()->is_only)
+            std::size_t index;
+            auto restriction_iter = m_restriction_map.find(restriction_source);
+            if (restriction_iter == m_restriction_map.end())
             {
-                continue;
+                index = m_restriction_bucket_list.size();
+                m_restriction_bucket_list.resize(index + 1);
+                m_restriction_map.emplace(restriction_source, index);
             }
-            else if (restriction.flags.isOnly)
+            else
             {
-                // We are going to insert an is_only_*-restriction. There can be only one.
-                m_count -= m_restriction_bucket_list.at(index).size();
-                m_restriction_bucket_list.at(index).clear();
+                index = restriction_iter->second;
+                // Map already contains an is_only_*-restriction
+                if (m_restriction_bucket_list.at(index).begin()->is_only)
+                {
+                    continue;
+                }
+                else if (restriction.flags.is_only)
+                {
+                    // We are going to insert an is_only_*-restriction. There can be only one.
+                    m_count -= m_restriction_bucket_list.at(index).size();
+                    m_restriction_bucket_list.at(index).clear();
+                }
             }
+            ++m_count;
+            m_restriction_bucket_list.at(index)
+                .emplace_back(restriction.to.node, restriction.flags.is_only);
         }
-        ++m_count;
-        m_restriction_bucket_list.at(index)
-            .emplace_back(restriction.toNode, restriction.flags.isOnly);
     }
-}
 
-// Replace end v with w in each turn restriction containing u as via node
-void RestrictionMap::FixupArrivingTurnRestriction(const NodeID node_u,
-                                                  const NodeID node_v,
-                                                  const NodeID node_w)
-{
-    BOOST_ASSERT(node_u != SPECIAL_NODEID);
-    BOOST_ASSERT(node_v != SPECIAL_NODEID);
-    BOOST_ASSERT(node_w != SPECIAL_NODEID);
-
-    if (!IsViaNode(node_u))
-    {
-        return;
-    }
 
-    // find all potential start edges. It is more efficent to get a (small) list
-    // of potential start edges than iterating over all buckets
-    std::vector<NodeID> predecessors;
-    for (const EdgeID current_edge_id : m_graph->GetAdjacentEdgeRange(node_u))
-    {
-        const EdgeData &edge_data = m_graph->GetEdgeData(current_edge_id);
-        const NodeID target = m_graph->GetTarget(current_edge_id);
-        if (edge_data.backward && (node_v != target))
-        {
-            predecessors.push_back(target);
-        }
-    }
-
-    for (const NodeID node_x : predecessors)
-    {
-        const auto restriction_iterator = m_restriction_map.find({node_x, node_u});
-        if (restriction_iterator == m_restriction_map.end())
-        {
-            continue;
-        }
-
-        const unsigned index = restriction_iterator->second;
-        auto &bucket = m_restriction_bucket_list.at(index);
-        for (RestrictionTarget &restriction_target : bucket)
-        {
-            if (node_v == restriction_target.target_node)
-            {
-                restriction_target.target_node = node_w;
-            }
-        }
-    }
+bool RestrictionMap::IsViaNode(const NodeID node) const
+{
+    return m_no_turn_via_node_set.find(node) != m_no_turn_via_node_set.end();
 }
 
+
 // Replaces start edge (v, w) with (u, w). Only start node changes.
 void RestrictionMap::FixupStartingTurnRestriction(const NodeID node_u,
                                                   const NodeID node_v,
@@ -163,11 +114,11 @@ NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID node_u, const No
         return SPECIAL_NODEID;
     }
 
-    auto restriction_iter = m_restriction_map.find({node_u, node_v});
+    const auto restriction_iter = m_restriction_map.find({node_u, node_v});
     if (restriction_iter != m_restriction_map.end())
     {
         const unsigned index = restriction_iter->second;
-        auto &bucket = m_restriction_bucket_list.at(index);
+        const auto &bucket = m_restriction_bucket_list.at(index);
         for (const RestrictionTarget &restriction_target : bucket)
         {
             if (restriction_target.is_only)
@@ -184,8 +135,6 @@ bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID node_u,
                                              const NodeID node_v,
                                              const NodeID node_w) const
 {
-    // return false;
-
     BOOST_ASSERT(node_u != SPECIAL_NODEID);
     BOOST_ASSERT(node_v != SPECIAL_NODEID);
     BOOST_ASSERT(node_w != SPECIAL_NODEID);
@@ -195,7 +144,7 @@ bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID node_u,
         return false;
     }
 
-    auto restriction_iter = m_restriction_map.find({node_u, node_v});
+    const auto restriction_iter = m_restriction_map.find({node_u, node_v});
     if (restriction_iter != m_restriction_map.end())
     {
         const unsigned index = restriction_iter->second;
diff --git a/DataStructures/RestrictionMap.h b/data_structures/restriction_map.hpp
similarity index 52%
rename from DataStructures/RestrictionMap.h
rename to data_structures/restriction_map.hpp
index 8207b80..7633faf 100644
--- a/DataStructures/RestrictionMap.h
+++ b/data_structures/restriction_map.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,19 +25,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef __RESTRICTION_MAP_H__
-#define __RESTRICTION_MAP_H__
+#ifndef RESTRICTION_MAP_HPP
+#define RESTRICTION_MAP_HPP
 
 #include <memory>
 
-#include "DynamicGraph.h"
-#include "Restriction.h"
-#include "NodeBasedGraph.h"
-#include "../Util/StdHashExtensions.h"
+#include "restriction.hpp"
+#include "../Util/std_hash.hpp"
 #include "../typedefs.h"
 
+#include <boost/assert.hpp>
+
 #include <unordered_map>
 #include <unordered_set>
+#include <vector>
 
 struct RestrictionSource
 {
@@ -95,26 +96,84 @@ template <> struct hash<RestrictionTarget>
 class RestrictionMap
 {
   public:
-    RestrictionMap(const std::shared_ptr<NodeBasedDynamicGraph> &graph,
-                   const std::vector<TurnRestriction> &input_restrictions_list);
+    RestrictionMap(const std::vector<TurnRestriction> &restriction_list);
+
+    // Replace end v with w in each turn restriction containing u as via node
+    template<class GraphT>
+    void FixupArrivingTurnRestriction(const NodeID node_u,
+                                      const NodeID node_v,
+                                      const NodeID node_w,
+                                      const std::shared_ptr<GraphT> &graph)
+    {
+        BOOST_ASSERT(node_u != SPECIAL_NODEID);
+        BOOST_ASSERT(node_v != SPECIAL_NODEID);
+        BOOST_ASSERT(node_w != SPECIAL_NODEID);
+
+        if (!IsViaNode(node_u))
+        {
+            return;
+        }
+
+        // find all potential start edges. It is more efficent to get a (small) list
+        // of potential start edges than iterating over all buckets
+        std::vector<NodeID> predecessors;
+        for (const EdgeID current_edge_id : graph->GetAdjacentEdgeRange(node_u))
+        {
+            const NodeID target = graph->GetTarget(current_edge_id);
+            if (node_v != target)
+            {
+                predecessors.push_back(target);
+            }
+        }
+
+        for (const NodeID node_x : predecessors)
+        {
+            const auto restriction_iterator = m_restriction_map.find({node_x, node_u});
+            if (restriction_iterator == m_restriction_map.end())
+            {
+                continue;
+            }
+
+            const unsigned index = restriction_iterator->second;
+            auto &bucket = m_restriction_bucket_list.at(index);
+            for (RestrictionTarget &restriction_target : bucket)
+            {
+                if (node_v == restriction_target.target_node)
+                {
+                    restriction_target.target_node = node_w;
+                }
+            }
+        }
+    }
 
-    void FixupArrivingTurnRestriction(const NodeID u, const NodeID v, const NodeID w);
-    void FixupStartingTurnRestriction(const NodeID u, const NodeID v, const NodeID w);
-    NodeID CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const;
-    bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const;
     bool IsViaNode(const NodeID node) const;
-    unsigned size()
+
+
+    // Replaces start edge (v, w) with (u, w). Only start node changes.
+    void FixupStartingTurnRestriction(const NodeID node_u,
+                                      const NodeID node_v,
+                                      const NodeID node_w);
+
+    // Check if edge (u, v) is the start of any turn restriction.
+    // If so returns id of first target node.
+    NodeID CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const;
+    // Checks if turn <u,v,w> is actually a turn restriction.
+    bool CheckIfTurnIsRestricted(const NodeID node_u,
+                                 const NodeID node_v,
+                                 const NodeID node_w) const;
+
+    std::size_t size()
     {
         return m_count;
     }
 
   private:
+    // check of node is the start of any restriction
     bool IsSourceNode(const NodeID node) const;
-    typedef std::vector<RestrictionTarget> EmanatingRestrictionsVector;
-    typedef NodeBasedDynamicGraph::EdgeData EdgeData;
 
-    unsigned m_count;
-    std::shared_ptr<NodeBasedDynamicGraph> m_graph;
+    using EmanatingRestrictionsVector = std::vector<RestrictionTarget>;
+
+    std::size_t m_count;
     //! index -> list of (target, isOnly)
     std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
     //! maps (start, via) -> bucket index
@@ -123,4 +182,4 @@ class RestrictionMap
     std::unordered_set<NodeID> m_no_turn_via_node_set;
 };
 
-#endif
+#endif //RESTRICTION_MAP_HPP
diff --git a/DataStructures/RouteParameters.cpp b/data_structures/route_parameters.cpp
similarity index 82%
rename from DataStructures/RouteParameters.cpp
rename to data_structures/route_parameters.cpp
index edc7311..1019a91 100644
--- a/DataStructures/RouteParameters.cpp
+++ b/data_structures/route_parameters.cpp
@@ -33,7 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 RouteParameters::RouteParameters()
     : zoom_level(18), print_instructions(false), alternate_route(true), geometry(true),
-      compression(true), deprecatedAPI(false), check_sum(-1)
+      compression(true), deprecatedAPI(false), uturn_default(false), check_sum(-1), num_results(1)
 {
 }
 
@@ -45,8 +45,36 @@ void RouteParameters::setZoomLevel(const short level)
     }
 }
 
+void RouteParameters::setNumberOfResults(const short number)
+{
+    if (number > 0 && number <= 100)
+    {
+        num_results = number;
+    }
+}
+
 void RouteParameters::setAlternateRouteFlag(const bool flag) { alternate_route = flag; }
 
+void RouteParameters::setUTurn(const bool flag)
+{
+    uturns.resize(coordinates.size(), uturn_default);
+    if (!uturns.empty())
+    {
+        uturns.back() = flag;
+    }
+}
+
+void RouteParameters::setAllUTurns(const bool flag)
+{
+    // if the flag flips the default, then we erase everything.
+    if (flag)
+    {
+        uturn_default = flag;
+        uturns.clear();
+        uturns.resize(coordinates.size(), uturn_default);
+    }
+}
+
 void RouteParameters::setDeprecatedAPIFlag(const std::string &) { deprecatedAPI = true; }
 
 void RouteParameters::setChecksum(const unsigned sum) { check_sum = sum; }
diff --git a/DataStructures/SearchEngine.h b/data_structures/search_engine.hpp
similarity index 86%
rename from DataStructures/SearchEngine.h
rename to data_structures/search_engine.hpp
index 58f5e77..0b2b888 100644
--- a/DataStructures/SearchEngine.h
+++ b/data_structures/search_engine.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,13 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef SEARCHENGINE_H
-#define SEARCHENGINE_H
+#ifndef SEARCH_ENGINE_HPP
+#define SEARCH_ENGINE_HPP
 
-#include "SearchEngineData.h"
-#include "../RoutingAlgorithms/AlternativePathRouting.h"
-#include "../RoutingAlgorithms/ManyToManyRouting.h"
-#include "../RoutingAlgorithms/ShortestPathRouting.h"
+#include "search_engine_data.hpp"
+#include "../routing_algorithms/alternative_path.hpp"
+#include "../routing_algorithms/many_to_many.hpp"
+#include "../routing_algorithms/shortest_path.hpp"
 
 #include <type_traits>
 
@@ -57,4 +57,4 @@ template <class DataFacadeT> class SearchEngine
     ~SearchEngine() {}
 };
 
-#endif // SEARCHENGINE_H
+#endif // SEARCH_ENGINE_HPP
diff --git a/DataStructures/SearchEngineData.cpp b/data_structures/search_engine_data.cpp
similarity index 97%
rename from DataStructures/SearchEngineData.cpp
rename to data_structures/search_engine_data.cpp
index a5e4bfc..810762a 100644
--- a/DataStructures/SearchEngineData.cpp
+++ b/data_structures/search_engine_data.cpp
@@ -25,9 +25,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "SearchEngineData.h"
+#include "search_engine_data.hpp"
 
-#include "BinaryHeap.h"
+#include "binary_heap.hpp"
 
 void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes)
 {
diff --git a/DataStructures/SearchEngineData.h b/data_structures/search_engine_data.hpp
similarity index 85%
rename from DataStructures/SearchEngineData.h
rename to data_structures/search_engine_data.hpp
index f0621e6..6c2efb1 100644
--- a/DataStructures/SearchEngineData.h
+++ b/data_structures/search_engine_data.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,13 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef SEARCH_ENGINE_DATA_H
-#define SEARCH_ENGINE_DATA_H
+#ifndef SEARCH_ENGINE_DATA_HPP
+#define SEARCH_ENGINE_DATA_HPP
 
 #include <boost/thread/tss.hpp>
 
 #include "../typedefs.h"
-#include "BinaryHeap.h"
+#include "binary_heap.hpp"
 
 struct HeapData
 {
@@ -41,8 +41,8 @@ struct HeapData
 
 struct SearchEngineData
 {
-    typedef BinaryHeap<NodeID, NodeID, int, HeapData, UnorderedMapStorage<NodeID, int>> QueryHeap;
-    typedef boost::thread_specific_ptr<QueryHeap> SearchEngineHeapPtr;
+    using QueryHeap = BinaryHeap<NodeID, NodeID, int, HeapData, UnorderedMapStorage<NodeID, int>>;
+    using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
 
     static SearchEngineHeapPtr forwardHeap;
     static SearchEngineHeapPtr backwardHeap;
@@ -58,4 +58,4 @@ struct SearchEngineData
     void InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes);
 };
 
-#endif // SEARCH_ENGINE_DATA_H
+#endif // SEARCH_ENGINE_DATA_HPP
diff --git a/DataStructures/SegmentInformation.h b/data_structures/segment_information.hpp
similarity index 78%
rename from DataStructures/SegmentInformation.h
rename to data_structures/segment_information.hpp
index f145804..dd1fc57 100644
--- a/DataStructures/SegmentInformation.h
+++ b/data_structures/segment_information.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -28,8 +28,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef SEGMENT_INFORMATION_H
 #define SEGMENT_INFORMATION_H
 
-#include "TurnInstructions.h"
+#include "turn_instructions.hpp"
 
+#include "../data_structures/travel_mode.hpp"
 #include "../typedefs.h"
 
 #include <osrm/Coordinate.h>
@@ -43,8 +44,9 @@ struct SegmentInformation
     float length;
     short bearing; // more than enough [0..3600] fits into 12 bits
     TurnInstruction turn_instruction;
-    bool necessary:1;
-    bool is_via_location:1;
+    TravelMode travel_mode;
+    bool necessary;
+    bool is_via_location;
 
     explicit SegmentInformation(const FixedPointCoordinate &location,
                                 const NodeID name_id,
@@ -52,9 +54,11 @@ struct SegmentInformation
                                 const float length,
                                 const TurnInstruction turn_instruction,
                                 const bool necessary,
-                                const bool is_via_location)
+                                const bool is_via_location,
+                                const TravelMode travel_mode)
         : location(location), name_id(name_id), duration(duration), length(length), bearing(0),
-          turn_instruction(turn_instruction), necessary(necessary), is_via_location(is_via_location)
+          turn_instruction(turn_instruction), travel_mode(travel_mode), necessary(necessary),
+          is_via_location(is_via_location)
     {
     }
 
@@ -62,9 +66,11 @@ struct SegmentInformation
                                 const NodeID name_id,
                                 const EdgeWeight duration,
                                 const float length,
-                                const TurnInstruction turn_instruction)
+                                const TurnInstruction turn_instruction,
+                                const TravelMode travel_mode)
         : location(location), name_id(name_id), duration(duration), length(length), bearing(0),
-          turn_instruction(turn_instruction), necessary(turn_instruction != TurnInstruction::NoTurn), is_via_location(false)
+          turn_instruction(turn_instruction), travel_mode(travel_mode),
+          necessary(turn_instruction != TurnInstruction::NoTurn), is_via_location(false)
     {
     }
 };
diff --git a/DataStructures/SharedMemoryFactory.h b/data_structures/shared_memory_factory.hpp
similarity index 95%
rename from DataStructures/SharedMemoryFactory.h
rename to data_structures/shared_memory_factory.hpp
index a07e125..dc714a6 100644
--- a/DataStructures/SharedMemoryFactory.h
+++ b/data_structures/shared_memory_factory.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,11 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef SHARED_MEMORY_FACTORY_H
-#define SHARED_MEMORY_FACTORY_H
+#ifndef SHARED_MEMORY_FACTORY_HPP
+#define SHARED_MEMORY_FACTORY_HPP
 
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
+#include "../Util/osrm_exception.hpp"
+#include "../Util/simple_logger.hpp"
 
 #include <boost/filesystem.hpp>
 #include <boost/filesystem/fstream.hpp>
@@ -196,12 +196,14 @@ class SharedMemory
 };
 #else
 // Windows - specific code
-class SharedMemory : boost::noncopyable
+class SharedMemory
 {
+    SharedMemory(const SharedMemory&) = delete;
     // Remove shared memory on destruction
-    class shm_remove : boost::noncopyable
+    class shm_remove
     {
       private:
+        shm_remove(const shm_remove&) = delete;
         char *m_shmid;
         bool m_initialized;
 
@@ -286,7 +288,6 @@ class SharedMemory : boost::noncopyable
   private:
     static void build_key(int id, char *key)
     {
-        OSRMLockFile lock_file;
         sprintf(key, "%s.%d", "osrm.lock", id);
     }
 
@@ -343,7 +344,7 @@ template <class LockFileT = OSRMLockFile> class SharedMemoryFactory_tmpl
             {
                 if (0 == size)
                 {
-                    throw OSRMException("lock file does not exist, exiting");
+                    throw osrm::exception("lock file does not exist, exiting");
                 }
                 else
                 {
@@ -357,7 +358,7 @@ template <class LockFileT = OSRMLockFile> class SharedMemoryFactory_tmpl
         {
             SimpleLogger().Write(logWARNING) << "caught exception: " << e.what() << ", code "
                                              << e.get_error_code();
-            throw OSRMException(e.what());
+            throw osrm::exception(e.what());
         }
     }
 
@@ -365,6 +366,6 @@ template <class LockFileT = OSRMLockFile> class SharedMemoryFactory_tmpl
     SharedMemoryFactory_tmpl(const SharedMemoryFactory_tmpl &) = delete;
 };
 
-typedef SharedMemoryFactory_tmpl<> SharedMemoryFactory;
+using SharedMemoryFactory = SharedMemoryFactory_tmpl<>;
 
-#endif /* SHARED_MEMORY_POINTER_FACTORY_H */
+#endif // SHARED_MEMORY_FACTORY_HPP
diff --git a/DataStructures/SharedMemoryVectorWrapper.h b/data_structures/shared_memory_vector_wrapper.hpp
similarity index 89%
rename from DataStructures/SharedMemoryVectorWrapper.h
rename to data_structures/shared_memory_vector_wrapper.hpp
index fe4baf3..d508e5f 100644
--- a/DataStructures/SharedMemoryVectorWrapper.h
+++ b/data_structures/shared_memory_vector_wrapper.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,10 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef SHARED_MEMORY_VECTOR_WRAPPER_H
-#define SHARED_MEMORY_VECTOR_WRAPPER_H
-
-#include "../Util/SimpleLogger.h"
+#ifndef SHARED_MEMORY_VECTOR_WRAPPER_HPP
+#define SHARED_MEMORY_VECTOR_WRAPPER_HPP
 
 #include <boost/assert.hpp>
 
@@ -78,7 +76,7 @@ template <typename DataT> class SharedMemoryWrapper
 
     void swap(SharedMemoryWrapper<DataT> &other)
     {
-        BOOST_ASSERT_MSG(m_size != 0 || other.size() != 0, "size invalid");
+        // BOOST_ASSERT_MSG(m_size != 0 || other.size() != 0, "size invalid");
         std::swap(m_size, other.m_size);
         std::swap(m_ptr, other.m_ptr);
     }
@@ -121,7 +119,7 @@ template <> class SharedMemoryWrapper<bool>
 
     void swap(SharedMemoryWrapper<bool> &other)
     {
-        BOOST_ASSERT_MSG(m_size != 0 || other.size() != 0, "size invalid");
+        // BOOST_ASSERT_MSG(m_size != 0 || other.size() != 0, "size invalid");
         std::swap(m_size, other.m_size);
         std::swap(m_ptr, other.m_ptr);
     }
@@ -148,9 +146,9 @@ template <> class SharedMemoryWrapper<bool>
 
 template <typename DataT, bool UseSharedMemory> struct ShM
 {
-    typedef typename std::conditional<UseSharedMemory,
+    using vector = typename std::conditional<UseSharedMemory,
                                       SharedMemoryWrapper<DataT>,
-                                      std::vector<DataT>>::type vector;
+                                      std::vector<DataT>>::type;
 };
 
-#endif // SHARED_MEMORY_VECTOR_WRAPPER_H
+#endif // SHARED_MEMORY_VECTOR_WRAPPER_HPP
diff --git a/DataStructures/StaticGraph.h b/data_structures/static_graph.hpp
similarity index 70%
rename from DataStructures/StaticGraph.h
rename to data_structures/static_graph.hpp
index 9210c87..05d65ee 100644
--- a/DataStructures/StaticGraph.h
+++ b/data_structures/static_graph.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,36 +25,40 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef STATIC_GRAPH_H
-#define STATIC_GRAPH_H
+#ifndef STATIC_GRAPH_HPP
+#define STATIC_GRAPH_HPP
 
-#include "../DataStructures/Percent.h"
-#include "../DataStructures/SharedMemoryVectorWrapper.h"
-#include "../Util/SimpleLogger.h"
+#include "percent.hpp"
+#include "shared_memory_vector_wrapper.hpp"
+#include "../Util/integer_range.hpp"
 #include "../typedefs.h"
 
 #include <boost/assert.hpp>
-#include <boost/range/irange.hpp>
 
 #include <tbb/parallel_sort.h>
 
 #include <algorithm>
 #include <limits>
+#include <utility>
 #include <vector>
 
 template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
 {
   public:
-    typedef decltype(boost::irange(0u,0u)) EdgeRange;
-    typedef NodeID NodeIterator;
-    typedef NodeID EdgeIterator;
-    typedef EdgeDataT EdgeData;
+    using NodeIterator = NodeID;
+    using EdgeIterator = NodeID;
+    using EdgeData = EdgeDataT;
+    using EdgeRange = osrm::range<EdgeIterator>;
+
     class InputEdge
     {
       public:
-        EdgeDataT data;
         NodeIterator source;
         NodeIterator target;
+        EdgeDataT data;
+
+        template<typename... Ts>
+        InputEdge(NodeIterator source, NodeIterator target, Ts &&...data) : source(source), target(target), data(std::forward<Ts>(data)...) { }
         bool operator<(const InputEdge &right) const
         {
             if (source != right.source)
@@ -79,18 +83,18 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
 
     EdgeRange GetAdjacentEdgeRange(const NodeID node) const
     {
-        return boost::irange(BeginEdges(node), EndEdges(node));
+        return osrm::irange(BeginEdges(node), EndEdges(node));
     }
 
     StaticGraph(const int nodes, std::vector<InputEdge> &graph)
     {
         tbb::parallel_sort(graph.begin(), graph.end());
         number_of_nodes = nodes;
-        number_of_edges = (EdgeIterator)graph.size();
+        number_of_edges = static_cast<EdgeIterator>(graph.size());
         node_array.resize(number_of_nodes + 1);
         EdgeIterator edge = 0;
         EdgeIterator position = 0;
-        for (NodeIterator node = 0; node <= number_of_nodes; ++node)
+        for (const auto node : osrm::irange(0u, number_of_nodes+1))
         {
             EdgeIterator last_edge = edge;
             while (edge < number_of_edges && graph[edge].source == node)
@@ -102,7 +106,7 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
         }
         edge_array.resize(position); //(edge)
         edge = 0;
-        for (NodeIterator node = 0; node < number_of_nodes; ++node)
+        for (const auto node : osrm::irange(0u, number_of_nodes))
         {
             EdgeIterator e = node_array[node + 1].first_edge;
             for (EdgeIterator i = node_array[node].first_edge; i != e; ++i)
@@ -118,51 +122,18 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
     StaticGraph(typename ShM<NodeArrayEntry, UseSharedMemory>::vector &nodes,
                 typename ShM<EdgeArrayEntry, UseSharedMemory>::vector &edges)
     {
-        number_of_nodes = nodes.size() - 1;
-        number_of_edges = edges.size();
+        number_of_nodes = static_cast<decltype(number_of_nodes)>(nodes.size() - 1);
+        number_of_edges = static_cast<decltype(number_of_edges)>(edges.size());
 
         node_array.swap(nodes);
         edge_array.swap(edges);
-
-#ifndef NDEBUG
-        Percent p(GetNumberOfNodes());
-        for (unsigned u = 0; u < GetNumberOfNodes(); ++u)
-        {
-            for (auto eid : GetAdjacentEdgeRange(u))
-            {
-                const EdgeData &data = GetEdgeData(eid);
-                if (!data.shortcut)
-                {
-                    continue;
-                }
-                const unsigned v = GetTarget(eid);
-                const EdgeID first_edge_id = FindEdgeInEitherDirection(u, data.id);
-                if (SPECIAL_EDGEID == first_edge_id)
-                {
-                    SimpleLogger().Write(logWARNING) << "cannot find first segment of edge ("
-                                                     << u << "," << data.id << "," << v
-                                                     << "), eid: " << eid;
-                    BOOST_ASSERT(false);
-                }
-                const EdgeID second_edge_id = FindEdgeInEitherDirection(data.id, v);
-                if (SPECIAL_EDGEID == second_edge_id)
-                {
-                    SimpleLogger().Write(logWARNING) << "cannot find second segment of edge ("
-                                                     << u << "," << data.id << "," << v
-                                                     << "), eid: " << eid;
-                    BOOST_ASSERT(false);
-                }
-            }
-            p.printIncrement();
-        }
-#endif
     }
 
-    unsigned GetNumberOfNodes() const { return number_of_nodes -1; }
+    unsigned GetNumberOfNodes() const { return number_of_nodes; }
 
     unsigned GetNumberOfEdges() const { return number_of_edges; }
 
-    unsigned GetOutDegree(const NodeIterator n) const { return BeginEdges(n) - EndEdges(n) - 1; }
+    unsigned GetOutDegree(const NodeIterator n) const { return EndEdges(n) - BeginEdges(n); }
 
     inline NodeIterator GetTarget(const EdgeIterator e) const
     {
@@ -230,4 +201,4 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
     typename ShM<EdgeArrayEntry, UseSharedMemory>::vector edge_array;
 };
 
-#endif // STATIC_GRAPH_H
+#endif // STATIC_GRAPH_HPP
diff --git a/DataStructures/StaticKDTree.h b/data_structures/static_kdtree.hpp
similarity index 98%
rename from DataStructures/StaticKDTree.h
rename to data_structures/static_kdtree.hpp
index e36eee9..b173d3a 100644
--- a/DataStructures/StaticKDTree.h
+++ b/data_structures/static_kdtree.hpp
@@ -27,8 +27,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // KD Tree coded by Christian Vetter, Monav Project
 
-#ifndef STATICKDTREE_H_INCLUDED
-#define STATICKDTREE_H_INCLUDED
+#ifndef STATICKDTREE_HPP
+#define STATICKDTREE_HPP
 
 #include <boost/assert.hpp>
 #include <vector>
@@ -211,7 +211,7 @@ class StaticKDTree
     }
 
   private:
-    typedef unsigned Iterator;
+    using Iterator = unsigned;
     struct Tree
     {
         Iterator left;
@@ -257,4 +257,4 @@ class StaticKDTree
 };
 }
 
-#endif // STATICKDTREE_H_INCLUDED
+#endif // STATICKDTREE_HPP
diff --git a/DataStructures/StaticRTree.h b/data_structures/static_rtree.hpp
similarity index 69%
rename from DataStructures/StaticRTree.h
rename to data_structures/static_rtree.hpp
index ce306ad..f670ca3 100644
--- a/DataStructures/StaticRTree.h
+++ b/data_structures/static_rtree.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,20 +25,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef STATICRTREE_H
-#define STATICRTREE_H
+#ifndef STATIC_RTREE_HPP
+#define STATIC_RTREE_HPP
 
-#include "DeallocatingVector.h"
-#include "HilbertValue.h"
-#include "PhantomNodes.h"
-#include "QueryNode.h"
-#include "SharedMemoryFactory.h"
-#include "SharedMemoryVectorWrapper.h"
+#include "deallocating_vector.hpp"
+#include "hilbert_value.hpp"
+#include "phantom_node.hpp"
+#include "query_node.hpp"
+#include "rectangle.hpp"
+#include "shared_memory_factory.hpp"
+#include "shared_memory_vector_wrapper.hpp"
 
+#include "../Util/floating_point.hpp"
+#include "../Util/integer_range.hpp"
 #include "../Util/MercatorUtil.h"
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/TimingUtil.h"
+#include "../Util/osrm_exception.hpp"
+#include "../Util/simple_logger.hpp"
+#include "../Util/timing_util.hpp"
 #include "../typedefs.h"
 
 #include <osrm/Coordinate.h>
@@ -47,11 +50,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <boost/filesystem.hpp>
 #include <boost/filesystem/fstream.hpp>
 #include <boost/thread.hpp>
-#include <boost/variant.hpp>
 
 #include <tbb/parallel_for.h>
 #include <tbb/parallel_sort.h>
 
+#include <variant/variant.hpp>
+
 #include <algorithm>
 #include <array>
 #include <limits>
@@ -60,16 +64,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <string>
 #include <vector>
 
-// tuning parameters
-const static uint32_t RTREE_BRANCHING_FACTOR = 64;
-const static uint32_t RTREE_LEAF_NODE_SIZE = 1024;
-
-static boost::thread_specific_ptr<boost::filesystem::ifstream> thread_local_rtree_stream;
-
 // Implements a static, i.e. packed, R-tree
 template <class EdgeDataT,
           class CoordinateListT = std::vector<FixedPointCoordinate>,
-          bool UseSharedMemory = false>
+          bool UseSharedMemory = false,
+          uint32_t BRANCHING_FACTOR=64,
+          uint32_t LEAF_NODE_SIZE=1024>
 class StaticRTree
 {
   public:
@@ -80,9 +80,9 @@ class StaticRTree
         int32_t min_lon, max_lon;
         int32_t min_lat, max_lat;
 
-        inline void InitializeMBRectangle(const std::array<EdgeDataT, RTREE_LEAF_NODE_SIZE> &objects,
+        inline void InitializeMBRectangle(const std::array<EdgeDataT, LEAF_NODE_SIZE> &objects,
                                           const uint32_t element_count,
-                                          const std::vector<NodeInfo> &coordinate_list)
+                                          const std::vector<QueryNode> &coordinate_list)
         {
             for (uint32_t i = 0; i < element_count; ++i)
             {
@@ -147,19 +147,64 @@ class StaticRTree
                 return 0.;
             }
 
+            enum Direction
+            {
+                INVALID    = 0,
+                NORTH      = 1,
+                SOUTH      = 2,
+                EAST       = 4,
+                NORTH_EAST = 5,
+                SOUTH_EAST = 6,
+                WEST       = 8,
+                NORTH_WEST = 9,
+                SOUTH_WEST = 10
+            };
+
+            Direction d = INVALID;
+            if (location.lat > max_lat)
+                d = (Direction) (d | NORTH);
+            else if (location.lat < min_lat)
+                d = (Direction) (d | SOUTH);
+            if (location.lon > max_lon)
+                d = (Direction) (d | EAST);
+            else if (location.lon < min_lon)
+                d = (Direction) (d | WEST);
+
+            BOOST_ASSERT(d != INVALID);
+
             float min_dist = std::numeric_limits<float>::max();
-            min_dist = std::min(min_dist,
-                                FixedPointCoordinate::ApproximateEuclideanDistance(
-                                    location.lat, location.lon, max_lat, min_lon));
-            min_dist = std::min(min_dist,
-                                FixedPointCoordinate::ApproximateEuclideanDistance(
-                                    location.lat, location.lon, max_lat, max_lon));
-            min_dist = std::min(min_dist,
-                                FixedPointCoordinate::ApproximateEuclideanDistance(
-                                    location.lat, location.lon, min_lat, max_lon));
-            min_dist = std::min(min_dist,
-                                FixedPointCoordinate::ApproximateEuclideanDistance(
-                                    location.lat, location.lon, min_lat, min_lon));
+            switch (d)
+            {
+                case NORTH:
+                    min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, location.lon));
+                    break;
+                case SOUTH:
+                    min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, location.lon));
+                    break;
+                case WEST:
+                    min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, min_lon));
+                    break;
+                case EAST:
+                    min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, max_lon));
+                    break;
+                case NORTH_EAST:
+                    min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, max_lon));
+                    break;
+                case NORTH_WEST:
+                    min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, min_lon));
+                    break;
+                case SOUTH_EAST:
+                    min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, max_lon));
+                    break;
+                case SOUTH_WEST:
+                    min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, min_lon));
+                    break;
+                default:
+                    break;
+            }
+
+            BOOST_ASSERT(min_dist != std::numeric_limits<float>::max());
+
             return min_dist;
         }
 
@@ -167,10 +212,10 @@ class StaticRTree
         {
             float min_max_dist = std::numeric_limits<float>::max();
             // Get minmax distance to each of the four sides
-            FixedPointCoordinate upper_left(max_lat, min_lon);
-            FixedPointCoordinate upper_right(max_lat, max_lon);
-            FixedPointCoordinate lower_right(min_lat, max_lon);
-            FixedPointCoordinate lower_left(min_lat, min_lon);
+            const FixedPointCoordinate upper_left(max_lat, min_lon);
+            const FixedPointCoordinate upper_right(max_lat, max_lon);
+            const FixedPointCoordinate lower_right(min_lat, max_lon);
+            const FixedPointCoordinate lower_left(min_lat, min_lon);
 
             min_max_dist = std::min(
                 min_max_dist,
@@ -198,8 +243,8 @@ class StaticRTree
 
         inline bool Contains(const FixedPointCoordinate &location) const
         {
-            const bool lats_contained = (location.lat > min_lat) && (location.lat < max_lat);
-            const bool lons_contained = (location.lon > min_lon) && (location.lon < max_lon);
+            const bool lats_contained = (location.lat >= min_lat) && (location.lat <= max_lat);
+            const bool lons_contained = (location.lon >= min_lon) && (location.lon <= max_lon);
             return lats_contained && lons_contained;
         }
 
@@ -212,7 +257,7 @@ class StaticRTree
         }
     };
 
-    typedef RectangleInt2D RectangleT;
+    using RectangleT = RectangleInt2D;
 
     struct TreeNode
     {
@@ -220,7 +265,7 @@ class StaticRTree
         RectangleT minimum_bounding_rectangle;
         uint32_t child_count : 31;
         bool child_is_on_disk : 1;
-        uint32_t children[RTREE_BRANCHING_FACTOR];
+        uint32_t children[BRANCHING_FACTOR];
     };
 
   private:
@@ -244,9 +289,9 @@ class StaticRTree
 
     struct LeafNode
     {
-        LeafNode() : object_count(0) {}
+        LeafNode() : object_count(0), objects() {}
         uint32_t object_count;
-        std::array<EdgeDataT, RTREE_LEAF_NODE_SIZE> objects;
+        std::array<EdgeDataT, LEAF_NODE_SIZE> objects;
     };
 
     struct QueryCandidate
@@ -265,7 +310,7 @@ class StaticRTree
         }
     };
 
-    typedef boost::variant<TreeNode, EdgeDataT> IncrementalQueryNodeType;
+    using IncrementalQueryNodeType = mapbox::util::variant<TreeNode, EdgeDataT>;
     struct IncrementalQueryCandidate
     {
         explicit IncrementalQueryCandidate(const float dist, const IncrementalQueryNodeType &node)
@@ -281,29 +326,15 @@ class StaticRTree
             return other.min_dist < min_dist;
         }
 
-        inline bool RepresentsTreeNode() const
-        {
-            return boost::apply_visitor(decide_type_visitor(), node);
-        }
-
         float min_dist;
         IncrementalQueryNodeType node;
-
-      private:
-        class decide_type_visitor : public boost::static_visitor<bool>
-        {
-          public:
-            bool operator()(const TreeNode &) const { return true; }
-
-            template<typename AnotherType>
-            bool operator()(const AnotherType &) const { return false; }
-        };
     };
 
     typename ShM<TreeNode, UseSharedMemory>::vector m_search_tree;
     uint64_t m_element_count;
     const std::string m_leaf_node_filename;
     std::shared_ptr<CoordinateListT> m_coordinate_list;
+    boost::filesystem::ifstream leaves_stream;
 
   public:
     StaticRTree() = delete;
@@ -313,7 +344,7 @@ class StaticRTree
     explicit StaticRTree(std::vector<EdgeDataT> &input_data_vector,
                          const std::string tree_node_filename,
                          const std::string leaf_node_filename,
-                         const std::vector<NodeInfo> &coordinate_list)
+                         const std::vector<QueryNode> &coordinate_list)
         : m_element_count(input_data_vector.size()), m_leaf_node_filename(leaf_node_filename)
     {
         SimpleLogger().Write() << "constructing r-tree of " << m_element_count
@@ -369,7 +400,7 @@ class StaticRTree
             TreeNode current_node;
             // SimpleLogger().Write() << "reading " << tree_size << " tree nodes in " <<
             // (sizeof(TreeNode)*tree_size) << " bytes";
-            for (uint32_t current_element_index = 0; RTREE_LEAF_NODE_SIZE > current_element_index;
+            for (uint32_t current_element_index = 0; LEAF_NODE_SIZE > current_element_index;
                  ++current_element_index)
             {
                 if (m_element_count > (processed_objects_count + current_element_index))
@@ -384,7 +415,7 @@ class StaticRTree
             }
 
             // generate tree node that resemble the objects in leaf and store it for next level
-            current_node.minimum_bounding_rectangle.InitializeMBRectangle(
+            InitializeMBRectangle(current_node.minimum_bounding_rectangle,
                 current_leaf.objects, current_leaf.object_count, coordinate_list);
             current_node.child_is_on_disk = true;
             current_node.children[0] = tree_nodes_in_level.size();
@@ -406,9 +437,9 @@ class StaticRTree
             while (processed_tree_nodes_in_level < tree_nodes_in_level.size())
             {
                 TreeNode parent_node;
-                // pack RTREE_BRANCHING_FACTOR elements into tree_nodes each
+                // pack BRANCHING_FACTOR elements into tree_nodes each
                 for (uint32_t current_child_node_index = 0;
-                     RTREE_BRANCHING_FACTOR > current_child_node_index;
+                     BRANCHING_FACTOR > current_child_node_index;
                      ++current_child_node_index)
                 {
                     if (processed_tree_nodes_in_level < tree_nodes_in_level.size())
@@ -480,11 +511,11 @@ class StaticRTree
 
         if (!boost::filesystem::exists(node_file))
         {
-            throw OSRMException("ram index file does not exist");
+            throw osrm::exception("ram index file does not exist");
         }
         if (0 == boost::filesystem::file_size(node_file))
         {
-            throw OSRMException("ram index file is empty");
+            throw osrm::exception("ram index file is empty");
         }
         boost::filesystem::ifstream tree_node_file(node_file, std::ios::binary);
 
@@ -500,23 +531,22 @@ class StaticRTree
         // open leaf node file and store thread specific pointer
         if (!boost::filesystem::exists(leaf_file))
         {
-            throw OSRMException("mem index file does not exist");
+            throw osrm::exception("mem index file does not exist");
         }
         if (0 == boost::filesystem::file_size(leaf_file))
         {
-            throw OSRMException("mem index file is empty");
+            throw osrm::exception("mem index file is empty");
         }
 
-        boost::filesystem::ifstream leaf_node_file(leaf_file, std::ios::binary);
-        leaf_node_file.read((char *)&m_element_count, sizeof(uint64_t));
-        leaf_node_file.close();
+        leaves_stream.open(leaf_file, std::ios::binary);
+        leaves_stream.read((char *)&m_element_count, sizeof(uint64_t));
 
         // SimpleLogger().Write() << tree_size << " nodes in search tree";
         // SimpleLogger().Write() << m_element_count << " elements in leafs";
     }
 
     explicit StaticRTree(TreeNode *tree_node_ptr,
-                         const uint32_t number_of_nodes,
+                         const uint64_t number_of_nodes,
                          const boost::filesystem::path &leaf_file,
                          std::shared_ptr<CoordinateListT> coordinate_list)
         : m_search_tree(tree_node_ptr, number_of_nodes), m_leaf_node_filename(leaf_file.string()),
@@ -525,21 +555,15 @@ class StaticRTree
         // open leaf node file and store thread specific pointer
         if (!boost::filesystem::exists(leaf_file))
         {
-            throw OSRMException("mem index file does not exist");
+            throw osrm::exception("mem index file does not exist");
         }
         if (0 == boost::filesystem::file_size(leaf_file))
         {
-            throw OSRMException("mem index file is empty");
+            throw osrm::exception("mem index file is empty");
         }
 
-        boost::filesystem::ifstream leaf_node_file(leaf_file, std::ios::binary);
-        leaf_node_file.read((char *)&m_element_count, sizeof(uint64_t));
-        leaf_node_file.close();
-
-        if (thread_local_rtree_stream.get())
-        {
-            thread_local_rtree_stream->close();
-        }
+        leaves_stream.open(leaf_file, std::ios::binary);
+        leaves_stream.read((char *)&m_element_count, sizeof(uint64_t));
 
         // SimpleLogger().Write() << tree_size << " nodes in search tree";
         // SimpleLogger().Write() << m_element_count << " elements in leafs";
@@ -576,7 +600,7 @@ class StaticRTree
                     for (uint32_t i = 0; i < current_leaf_node.object_count; ++i)
                     {
                         EdgeDataT const &current_edge = current_leaf_node.objects[i];
-                        if (ignore_tiny_components && current_edge.is_in_tiny_cc)
+                        if (ignore_tiny_components && current_edge.component_id != 0)
                         {
                             continue;
                         }
@@ -619,32 +643,163 @@ class StaticRTree
                 }
             }
         }
-        return result_coordinate.isValid();
+        return result_coordinate.is_valid();
     }
 
+
     // implementation of the Hjaltason/Samet query [3], a BFS traversal of the tree
+    // - searches for k elements nearest elements
+    // - continues to find the k+1st element from a big component if k elements
+    //   come from tiny components
     bool
     IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
                                             std::vector<PhantomNode> &result_phantom_node_vector,
-                                            const unsigned zoom_level,
-                                            const unsigned number_of_results,
-                                            const unsigned max_checked_segments = 4*RTREE_LEAF_NODE_SIZE)
+                                            const unsigned max_number_of_phantom_nodes,
+                                            const unsigned max_checked_elements = 4*LEAF_NODE_SIZE)
     {
-        // TIMER_START(samet);
-        // SimpleLogger().Write(logDEBUG) << "searching for " << number_of_results << " results";
-        std::vector<float> min_found_distances(number_of_results, std::numeric_limits<float>::max());
+        unsigned inspected_elements = 0;
+        unsigned number_of_elements_from_big_cc = 0;
+        unsigned number_of_elements_from_tiny_cc = 0;
 
-        unsigned dequeues = 0;
-        unsigned inspected_mbrs = 0;
-        unsigned loaded_leafs = 0;
-        unsigned inspected_segments = 0;
-        unsigned pruned_elements = 0;
-        unsigned ignored_segments = 0;
-        unsigned ignored_mbrs = 0;
+        // initialize queue with root element
+        std::priority_queue<IncrementalQueryCandidate> traversal_queue;
+        traversal_queue.emplace(0.f, m_search_tree[0]);
+
+        while (!traversal_queue.empty())
+        {
+            const IncrementalQueryCandidate current_query_node = traversal_queue.top();
+            traversal_queue.pop();
+
+            if (current_query_node.node.template is<TreeNode>())
+            { // current object is a tree node
+                const TreeNode & current_tree_node = current_query_node.node.template get<TreeNode>();
+                if (current_tree_node.child_is_on_disk)
+                {
+                    LeafNode current_leaf_node;
+                    LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
+
+                    // current object represents a block on disk
+                    for (const auto i : osrm::irange(0u, current_leaf_node.object_count))
+                    {
+                        const auto &current_edge = current_leaf_node.objects[i];
+                        const float current_perpendicular_distance =
+                            FixedPointCoordinate::ComputePerpendicularDistance(
+                                m_coordinate_list->at(current_edge.u),
+                                m_coordinate_list->at(current_edge.v),
+                                input_coordinate);
+                        // distance must be non-negative
+                        BOOST_ASSERT(0.f <= current_perpendicular_distance);
+
+                        // put element in queue
+                        traversal_queue.emplace(current_perpendicular_distance, current_edge);
+                    }
+                }
+                else
+                {
+                    // for each child mbr get a lower bound and enqueue it
+                    for (const auto i : osrm::irange(0u, current_tree_node.child_count))
+                    {
+                        const int32_t child_id = current_tree_node.children[i];
+                        const TreeNode &child_tree_node = m_search_tree[child_id];
+                        const RectangleT &child_rectangle = child_tree_node.minimum_bounding_rectangle;
+                        const float lower_bound_to_element = child_rectangle.GetMinDist(input_coordinate);
+                        BOOST_ASSERT(0.f <= lower_bound_to_element);
+
+                        traversal_queue.emplace(lower_bound_to_element, child_tree_node);
+                    }
+                }
+            }
+            else
+            { // current object is a leaf node
+                ++inspected_elements;
+                // inspecting an actual road segment
+                const EdgeDataT & current_segment = current_query_node.node.template get<EdgeDataT>();
+
+                // continue searching for the first segment from a big component
+                if (number_of_elements_from_big_cc == 0 &&
+                    number_of_elements_from_tiny_cc >= max_number_of_phantom_nodes &&
+                    current_segment.is_in_tiny_cc())
+                {
+                    continue;
+                }
+
+                // check if it is smaller than what we had before
+                float current_ratio = 0.f;
+                FixedPointCoordinate foot_point_coordinate_on_segment;
+                // const float current_perpendicular_distance =
+                    FixedPointCoordinate::ComputePerpendicularDistance(
+                        m_coordinate_list->at(current_segment.u),
+                        m_coordinate_list->at(current_segment.v),
+                        input_coordinate,
+                        foot_point_coordinate_on_segment,
+                        current_ratio);
+
+                // store phantom node in result vector
+                result_phantom_node_vector.emplace_back(
+                    current_segment.forward_edge_based_node_id,
+                    current_segment.reverse_edge_based_node_id,
+                    current_segment.name_id,
+                    current_segment.forward_weight,
+                    current_segment.reverse_weight,
+                    current_segment.forward_offset,
+                    current_segment.reverse_offset,
+                    current_segment.packed_geometry_id,
+                    current_segment.component_id,
+                    foot_point_coordinate_on_segment,
+                    current_segment.fwd_segment_position,
+                    current_segment.forward_travel_mode,
+                    current_segment.backward_travel_mode);
+
+                // Hack to fix rounding errors and wandering via nodes.
+                FixUpRoundingIssue(input_coordinate, result_phantom_node_vector.back());
+
+                // set forward and reverse weights on the phantom node
+                SetForwardAndReverseWeightsOnPhantomNode(current_segment,
+                                                         result_phantom_node_vector.back());
+
+                // update counts on what we found from which result class
+                if (current_segment.is_in_tiny_cc())
+                { // found an element in tiny component
+                    ++number_of_elements_from_tiny_cc;
+                }
+                else
+                { // found an element in a big component
+                    ++number_of_elements_from_big_cc;
+                }
+
+                // SimpleLogger().Write() << "result_phantom_node_vector.size(): " << result_phantom_node_vector.size();
+                // SimpleLogger().Write() << "max_number_of_phantom_nodes: " << max_number_of_phantom_nodes;
+                // SimpleLogger().Write() << "number_of_elements_from_big_cc: " << number_of_elements_from_big_cc;
+                // SimpleLogger().Write() << "number_of_elements_from_tiny_cc: " << number_of_elements_from_tiny_cc;
+                // SimpleLogger().Write() << "inspected_elements: " << inspected_elements;
+                // SimpleLogger().Write() << "max_checked_elements: " << max_checked_elements;
+            }
+
+            // stop the search by flushing the queue
+            if ((result_phantom_node_vector.size() >= max_number_of_phantom_nodes && number_of_elements_from_big_cc > 0) ||
+                inspected_elements >= max_checked_elements)
+            {
+                traversal_queue = std::priority_queue<IncrementalQueryCandidate>{};
+            }
+        }
+        // SimpleLogger().Write() << "inspected_elements: " << inspected_elements;
+        return !result_phantom_node_vector.empty();
+    }
+
+    // implementation of the Hjaltason/Samet query [3], a BFS traversal of the tree
+    bool
+    IncrementalFindPhantomNodeForCoordinateWithDistance(const FixedPointCoordinate &input_coordinate,
+                                                        std::vector<std::pair<PhantomNode, double>> &result_phantom_node_vector,
+                                                        const unsigned number_of_results,
+                                                        const unsigned max_checked_segments = 4*LEAF_NODE_SIZE)
+    {
+        std::vector<float> min_found_distances(number_of_results, std::numeric_limits<float>::max());
 
         unsigned number_of_results_found_in_big_cc = 0;
         unsigned number_of_results_found_in_tiny_cc = 0;
 
+        unsigned inspected_segments = 0;
+
         // initialize queue with root element
         std::priority_queue<IncrementalQueryCandidate> traversal_queue;
         traversal_queue.emplace(0.f, m_search_tree[0]);
@@ -654,28 +809,18 @@ class StaticRTree
             const IncrementalQueryCandidate current_query_node = traversal_queue.top();
             traversal_queue.pop();
 
-            ++dequeues;
-
             const float current_min_dist = min_found_distances[number_of_results-1];
 
             if (current_query_node.min_dist > current_min_dist)
             {
-                ++pruned_elements;
                 continue;
             }
 
             if (current_query_node.RepresentsTreeNode())
             {
-                const TreeNode & current_tree_node = boost::get<TreeNode>(current_query_node.node);
+                const TreeNode & current_tree_node = current_query_node.node.template get<TreeNode>();
                 if (current_tree_node.child_is_on_disk)
                 {
-                    ++loaded_leafs;
-                    // SimpleLogger().Write(logDEBUG) << "loading leaf: " << current_tree_node.children[0] << " w/ mbr [" <<
-                    //     current_tree_node.minimum_bounding_rectangle.min_lat/COORDINATE_PRECISION << "," <<
-                    //     current_tree_node.minimum_bounding_rectangle.min_lon/COORDINATE_PRECISION << "," <<
-                    //     current_tree_node.minimum_bounding_rectangle.max_lat/COORDINATE_PRECISION << "-" <<
-                    //     current_tree_node.minimum_bounding_rectangle.max_lon/COORDINATE_PRECISION << "]";
-
                     LeafNode current_leaf_node;
                     LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
                     // Add all objects from leaf into queue
@@ -694,23 +839,10 @@ class StaticRTree
                         {
                             traversal_queue.emplace(current_perpendicular_distance, current_edge);
                         }
-                        else
-                        {
-                            ++ignored_segments;
-                        }
                     }
-                    // SimpleLogger().Write(logDEBUG) << "added " << current_leaf_node.object_count << " roads into queue of " << traversal_queue.size();
                 }
                 else
                 {
-                    ++inspected_mbrs;
-                    // explore inner node
-                    // SimpleLogger().Write(logDEBUG) << "explore inner node w/ mbr [" <<
-                    //     current_tree_node.minimum_bounding_rectangle.min_lat/COORDINATE_PRECISION << "," <<
-                    //     current_tree_node.minimum_bounding_rectangle.min_lon/COORDINATE_PRECISION << "," <<
-                    //     current_tree_node.minimum_bounding_rectangle.max_lat/COORDINATE_PRECISION << "-" <<
-                    //     current_tree_node.minimum_bounding_rectangle.max_lon/COORDINATE_PRECISION << "," << "]";
-
                     // for each child mbr
                     for (uint32_t i = 0; i < current_tree_node.child_count; ++i)
                     {
@@ -727,10 +859,6 @@ class StaticRTree
                         {
                             traversal_queue.emplace(lower_bound_to_element, child_tree_node);
                         }
-                        else
-                        {
-                            ++ignored_mbrs;
-                        }
                     }
                     // SimpleLogger().Write(logDEBUG) << "added " << current_tree_node.child_count << " mbrs into queue of " << traversal_queue.size();
                 }
@@ -739,7 +867,7 @@ class StaticRTree
             {
                 ++inspected_segments;
                 // inspecting an actual road segment
-                const EdgeDataT & current_segment = boost::get<EdgeDataT>(current_query_node.node);
+                const EdgeDataT & current_segment = current_query_node.node.template get<EdgeDataT>();
 
                 // don't collect too many results from small components
                 if (number_of_results_found_in_big_cc == number_of_results && !current_segment.is_in_tiny_cc)
@@ -767,20 +895,21 @@ class StaticRTree
                 BOOST_ASSERT(0. <= current_perpendicular_distance);
 
                 if ((current_perpendicular_distance < current_min_dist) &&
-                    !EpsilonCompare(current_perpendicular_distance, current_min_dist))
+                    !osrm::epsilon_compare(current_perpendicular_distance, current_min_dist))
                 {
                     // store phantom node in result vector
                     result_phantom_node_vector.emplace_back(
                         current_segment.forward_edge_based_node_id,
-                         current_segment.reverse_edge_based_node_id,
-                         current_segment.name_id,
-                         current_segment.forward_weight,
-                         current_segment.reverse_weight,
-                         current_segment.forward_offset,
-                         current_segment.reverse_offset,
-                         current_segment.packed_geometry_id,
-                         foot_point_coordinate_on_segment,
-                         current_segment.fwd_segment_position);
+                        current_segment.reverse_edge_based_node_id,
+                        current_segment.name_id,
+                        current_segment.forward_weight,
+                        current_segment.reverse_weight,
+                        current_segment.forward_offset,
+                        current_segment.reverse_offset,
+                        current_segment.packed_geometry_id,
+                        foot_point_coordinate_on_segment,
+                        current_segment.fwd_segment_position,
+                        current_perpendicular_distance);
 
                     // Hack to fix rounding errors and wandering via nodes.
                     FixUpRoundingIssue(input_coordinate, result_phantom_node_vector.back());
@@ -813,40 +942,15 @@ class StaticRTree
             }
         }
 
-        // for (const PhantomNode& result_node : result_phantom_node_vector)
-        // {
-        //     SimpleLogger().Write(logDEBUG) << std::setprecision(8) << "found location " << result_node.forward_node_id << " at " << result_node.location;
-        // }
-        // SimpleLogger().Write(logDEBUG) << "dequeues: " << dequeues;
-        // SimpleLogger().Write(logDEBUG) << "inspected_mbrs: " << inspected_mbrs;
-        // SimpleLogger().Write(logDEBUG) << "loaded_leafs: " << loaded_leafs;
-        // SimpleLogger().Write(logDEBUG) << "inspected_segments: " << inspected_segments;
-        // SimpleLogger().Write(logDEBUG) << "pruned_elements: " << pruned_elements;
-        // SimpleLogger().Write(logDEBUG) << "ignored_segments: " << ignored_segments;
-        // SimpleLogger().Write(logDEBUG) << "ignored_mbrs: " << ignored_mbrs;
-
-        // SimpleLogger().Write(logDEBUG) << "number_of_results_found_in_big_cc: " << number_of_results_found_in_big_cc;
-        // SimpleLogger().Write(logDEBUG) << "number_of_results_found_in_tiny_cc: " << number_of_results_found_in_tiny_cc;
-        // TIMER_STOP(samet);
-        // SimpleLogger().Write() << "query took " << TIMER_MSEC(samet) << "ms";
-
-        // if we found an element in either category, then we are good
         return !result_phantom_node_vector.empty();
     }
 
+
+
     bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
                                       PhantomNode &result_phantom_node,
                                       const unsigned zoom_level)
     {
-
-        std::vector<PhantomNode> result_phantom_node_vector;
-        IncrementalFindPhantomNodeForCoordinate(input_coordinate, result_phantom_node_vector, zoom_level, 2);
-        // if (!result_phantom_node_vector.empty())
-        // {
-        //     result_phantom_node = result_phantom_node_vector.front();
-        // }
-        // return !result_phantom_node_vector.empty();
-
         const bool ignore_tiny_components = (zoom_level <= 14);
         EdgeDataT nearest_edge;
 
@@ -873,7 +977,7 @@ class StaticRTree
                     for (uint32_t i = 0; i < current_leaf_node.object_count; ++i)
                     {
                         const EdgeDataT &current_edge = current_leaf_node.objects[i];
-                        if (ignore_tiny_components && current_edge.is_in_tiny_cc)
+                        if (ignore_tiny_components && current_edge.component_id != 0)
                         {
                             continue;
                         }
@@ -891,7 +995,7 @@ class StaticRTree
                         BOOST_ASSERT(0. <= current_perpendicular_distance);
 
                         if ((current_perpendicular_distance < min_dist) &&
-                            !EpsilonCompare(current_perpendicular_distance, min_dist))
+                            !osrm::epsilon_compare(current_perpendicular_distance, min_dist))
                         { // found a new minimum
                             min_dist = current_perpendicular_distance;
                             result_phantom_node = {current_edge.forward_edge_based_node_id,
@@ -902,8 +1006,11 @@ class StaticRTree
                                                    current_edge.forward_offset,
                                                    current_edge.reverse_offset,
                                                    current_edge.packed_geometry_id,
+                                                   current_edge.component_id,
                                                    nearest,
-                                                   current_edge.fwd_segment_position};
+                                                   current_edge.fwd_segment_position,
+                                                   current_edge.forward_travel_mode,
+                                                   current_edge.backward_travel_mode};
                             nearest_edge = current_edge;
                         }
                     }
@@ -919,7 +1026,7 @@ class StaticRTree
             }
         }
 
-        if (result_phantom_node.location.isValid())
+        if (result_phantom_node.location.is_valid())
         {
             // Hack to fix rounding errors and wandering via nodes.
             FixUpRoundingIssue(input_coordinate, result_phantom_node);
@@ -927,7 +1034,7 @@ class StaticRTree
             // set forward and reverse weights on the phantom node
             SetForwardAndReverseWeightsOnPhantomNode(nearest_edge, result_phantom_node);
         }
-        return result_phantom_node.location.isValid();
+        return result_phantom_node.location.is_valid();
     }
 
   private:
@@ -941,13 +1048,20 @@ class StaticRTree
             m_coordinate_list->at(nearest_edge.u), m_coordinate_list->at(nearest_edge.v));
         const float ratio = std::min(1.f, distance_1 / distance_2);
 
+        using TreeWeightType = decltype(result_phantom_node.forward_weight);
+        static_assert(std::is_same<decltype(result_phantom_node.forward_weight),
+                                   decltype(result_phantom_node.reverse_weight)>::value,
+            "forward and reverse weight type in tree must be the same");
+
         if (SPECIAL_NODEID != result_phantom_node.forward_node_id)
         {
-            result_phantom_node.forward_weight *= ratio;
+            const auto new_weight = static_cast<TreeWeightType>(result_phantom_node.forward_weight * ratio);
+            result_phantom_node.forward_weight = new_weight;
         }
         if (SPECIAL_NODEID != result_phantom_node.reverse_node_id)
         {
-            result_phantom_node.reverse_weight *= (1.f - ratio);
+            const auto new_weight = static_cast<TreeWeightType>(result_phantom_node.reverse_weight * (1.f-ratio));
+            result_phantom_node.reverse_weight = new_weight;
         }
     }
 
@@ -997,22 +1111,21 @@ class StaticRTree
 
     inline void LoadLeafFromDisk(const uint32_t leaf_id, LeafNode &result_node)
     {
-        if (!thread_local_rtree_stream.get() || !thread_local_rtree_stream->is_open())
+        if (!leaves_stream.is_open())
         {
-            thread_local_rtree_stream.reset(new boost::filesystem::ifstream(
-                m_leaf_node_filename, std::ios::in | std::ios::binary));
+            leaves_stream.open(m_leaf_node_filename, std::ios::in | std::ios::binary);
         }
-        if (!thread_local_rtree_stream->good())
+        if (!leaves_stream.good())
         {
-            thread_local_rtree_stream->clear(std::ios::goodbit);
+            leaves_stream.clear(std::ios::goodbit);
             SimpleLogger().Write(logDEBUG) << "Resetting stale filestream";
         }
         const uint64_t seek_pos = sizeof(uint64_t) + leaf_id * sizeof(LeafNode);
-        thread_local_rtree_stream->seekg(seek_pos);
-        BOOST_ASSERT_MSG(thread_local_rtree_stream->good(),
+        leaves_stream.seekg(seek_pos);
+        BOOST_ASSERT_MSG(leaves_stream.good(),
                          "Seeking to position in leaf file failed.");
-        thread_local_rtree_stream->read((char *)&result_node, sizeof(LeafNode));
-        BOOST_ASSERT_MSG(thread_local_rtree_stream->good(), "Reading from leaf file failed.");
+        leaves_stream.read((char *)&result_node, sizeof(LeafNode));
+        BOOST_ASSERT_MSG(leaves_stream.good(), "Reading from leaf file failed.");
     }
 
     inline bool EdgesAreEquivalent(const FixedPointCoordinate &a,
@@ -1023,9 +1136,31 @@ class StaticRTree
         return (a == b && c == d) || (a == c && b == d) || (a == d && b == c);
     }
 
-    template <typename FloatT> inline bool EpsilonCompare(const FloatT d1, const FloatT d2) const
+    inline void InitializeMBRectangle(RectangleT& rectangle,
+                                      const std::array<EdgeDataT, LEAF_NODE_SIZE> &objects,
+                                      const uint32_t element_count,
+                                      const std::vector<QueryNode> &coordinate_list)
     {
-        return (std::abs(d1 - d2) < std::numeric_limits<FloatT>::epsilon());
+        for (uint32_t i = 0; i < element_count; ++i)
+        {
+            rectangle.min_lon = std::min(rectangle.min_lon,
+                               std::min(coordinate_list.at(objects[i].u).lon,
+                                        coordinate_list.at(objects[i].v).lon));
+            rectangle.max_lon = std::max(rectangle.max_lon,
+                               std::max(coordinate_list.at(objects[i].u).lon,
+                                        coordinate_list.at(objects[i].v).lon));
+
+            rectangle.min_lat = std::min(rectangle.min_lat,
+                               std::min(coordinate_list.at(objects[i].u).lat,
+                                        coordinate_list.at(objects[i].v).lat));
+            rectangle.max_lat = std::max(rectangle.max_lat,
+                               std::max(coordinate_list.at(objects[i].u).lat,
+                                        coordinate_list.at(objects[i].v).lat));
+        }
+        BOOST_ASSERT(rectangle.min_lat != std::numeric_limits<int>::min());
+        BOOST_ASSERT(rectangle.min_lon != std::numeric_limits<int>::min());
+        BOOST_ASSERT(rectangle.max_lat != std::numeric_limits<int>::min());
+        BOOST_ASSERT(rectangle.max_lon != std::numeric_limits<int>::min());
     }
 };
 
@@ -1033,4 +1168,4 @@ class StaticRTree
 //[2] "Nearest Neighbor Queries", N. Roussopulos et al; 1995; DOI: 10.1145/223784.223794
 //[3] "Distance Browsing in Spatial Databases"; G. Hjaltason, H. Samet; 1999; ACM Trans. DB Sys
 // Vol.24 No.2, pp.265-318
-#endif // STATICRTREE_H
+#endif // STATIC_RTREE_HPP
diff --git a/Server/Http/CompressionType.h b/data_structures/travel_mode.hpp
similarity index 81%
copy from Server/Http/CompressionType.h
copy to data_structures/travel_mode.hpp
index 74d0b62..345ec90 100644
--- a/Server/Http/CompressionType.h
+++ b/data_structures/travel_mode.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,17 +25,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef COMPRESSION_TYPE_H
-#define COMPRESSION_TYPE_H
+#ifndef TRAVEL_MODE_HPP
+#define TRAVEL_MODE_HPP
 
-namespace http
-{
-
-enum CompressionType
-{ noCompression,
-  gzipRFC1952,
-  deflateRFC1951 };
-
-} // namespace http
-
-#endif // COMPRESSION_TYPE_H
+namespace {
+using TravelMode = unsigned char;
+static const TravelMode TRAVEL_MODE_INACCESSIBLE = 0;
+static const TravelMode TRAVEL_MODE_DEFAULT = 1;
+}
+#endif /* TRAVEL_MODE_HPP */
diff --git a/DataStructures/TurnInstructions.h b/data_structures/turn_instructions.hpp
similarity index 92%
rename from DataStructures/TurnInstructions.h
rename to data_structures/turn_instructions.hpp
index 61de3b1..4b36658 100644
--- a/DataStructures/TurnInstructions.h
+++ b/data_structures/turn_instructions.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,13 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef TURN_INSTRUCTIONS_H
-#define TURN_INSTRUCTIONS_H
+#ifndef TURN_INSTRUCTIONS_HPP
+#define TURN_INSTRUCTIONS_HPP
 
 enum class TurnInstruction : unsigned char
 {
     NoTurn = 0, GoStraight, TurnSlightRight, TurnRight, TurnSharpRight, UTurn,
-    TurnSharpLeft, TurnLeft, TurnSlightLeft, ReachViaPoint, HeadOn, EnterRoundAbout,
+    TurnSharpLeft, TurnLeft, TurnSlightLeft, ReachViaLocation, HeadOn, EnterRoundAbout,
     LeaveRoundAbout, StayOnRoundAbout, StartAtEndOfStreet, ReachedYourDestination,
     EnterAgainstAllowedDirection, LeaveAgainstAllowedDirection,
     InverseAccessRestrictionFlag = 127,
@@ -87,4 +87,4 @@ struct TurnInstructionsClass
     }
 };
 
-#endif /* TURN_INSTRUCTIONS_H */
+#endif /* TURN_INSTRUCTIONS_HPP */
diff --git a/DataStructures/XORFastHash.h b/data_structures/xor_fast_hash.hpp
similarity index 95%
rename from DataStructures/XORFastHash.h
rename to data_structures/xor_fast_hash.hpp
index ee36830..1f6dc29 100644
--- a/DataStructures/XORFastHash.h
+++ b/data_structures/xor_fast_hash.hpp
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef XOR_FAST_HASH_H
-#define XOR_FAST_HASH_H
+#ifndef XOR_FAST_HASH_HPP
+#define XOR_FAST_HASH_HPP
 
 #include <algorithm>
 #include <vector>
@@ -70,7 +70,7 @@ class XORFastHash
 
     inline unsigned short operator()(const unsigned originalValue) const
     {
-        unsigned short lsb = ((originalValue) & 0xffff);
+        unsigned short lsb = ((originalValue)&0xffff);
         unsigned short msb = (((originalValue) >> 16) & 0xffff);
         return table1[lsb] ^ table2[msb];
     }
@@ -104,7 +104,7 @@ class XORMiniHash
     }
     unsigned char operator()(const unsigned originalValue) const
     {
-        unsigned char byte1 = ((originalValue) & 0xff);
+        unsigned char byte1 = ((originalValue)&0xff);
         unsigned char byte2 = ((originalValue >> 8) & 0xff);
         unsigned char byte3 = ((originalValue >> 16) & 0xff);
         unsigned char byte4 = ((originalValue >> 24) & 0xff);
@@ -112,4 +112,4 @@ class XORMiniHash
     }
 };
 
-#endif // XOR_FAST_HASH_H
+#endif // XOR_FAST_HASH_HPP
diff --git a/DataStructures/XORFastHashStorage.h b/data_structures/xor_fast_hash_storage.hpp
similarity index 88%
rename from DataStructures/XORFastHashStorage.h
rename to data_structures/xor_fast_hash_storage.hpp
index abdb9ac..1d84260 100644
--- a/DataStructures/XORFastHashStorage.h
+++ b/data_structures/xor_fast_hash_storage.hpp
@@ -25,10 +25,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef XOR_FAST_HASH_STORAGE_H
-#define XOR_FAST_HASH_STORAGE_H
+#ifndef XOR_FAST_HASH_STORAGE_HPP
+#define XOR_FAST_HASH_STORAGE_HPP
 
-#include "XORFastHash.h"
+#include "xor_fast_hash.hpp"
 
 #include <limits>
 #include <vector>
@@ -49,14 +49,14 @@ template <typename NodeID, typename Key> class XORFastHashStorage
 
         HashCell(const HashCell &other) : key(other.key), id(other.id), time(other.time) {}
 
-        inline operator Key() const { return key; }
+        operator Key() const { return key; }
 
-        inline void operator=(const Key &key_to_insert) { key = key_to_insert; }
+        void operator=(const Key &key_to_insert) { key = key_to_insert; }
     };
 
     explicit XORFastHashStorage(size_t) : positions(2 << 16), current_timestamp(0) {}
 
-    inline HashCell &operator[](const NodeID node)
+    HashCell &operator[](const NodeID node)
     {
         unsigned short position = fast_hasher(node);
         while ((positions[position].time == current_timestamp) && (positions[position].id != node))
@@ -69,7 +69,7 @@ template <typename NodeID, typename Key> class XORFastHashStorage
         return positions[position];
     }
 
-    inline void Clear()
+    void Clear()
     {
         ++current_timestamp;
         if (std::numeric_limits<unsigned>::max() == current_timestamp)
@@ -86,4 +86,4 @@ template <typename NodeID, typename Key> class XORFastHashStorage
     unsigned current_timestamp;
 };
 
-#endif // XOR_FAST_HASH_STORAGE_H
+#endif // XOR_FAST_HASH_STORAGE_HPP
diff --git a/datastore.cpp b/datastore.cpp
index 10d5bf5..d292004 100644
--- a/datastore.cpp
+++ b/datastore.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,28 +25,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "DataStructures/OriginalEdgeData.h"
-#include "DataStructures/RangeTable.h"
-#include "DataStructures/QueryEdge.h"
-#include "DataStructures/SharedMemoryFactory.h"
-#include "DataStructures/SharedMemoryVectorWrapper.h"
-#include "DataStructures/StaticGraph.h"
-#include "DataStructures/StaticRTree.h"
-#include "DataStructures/TurnInstructions.h"
+#include "data_structures/original_edge_data.hpp"
+#include "data_structures/range_table.hpp"
+#include "data_structures/query_edge.hpp"
+#include "data_structures/shared_memory_factory.hpp"
+#include "data_structures/shared_memory_vector_wrapper.hpp"
+#include "data_structures/static_graph.hpp"
+#include "data_structures/static_rtree.hpp"
+#include "data_structures/turn_instructions.hpp"
 #include "Server/DataStructures/BaseDataFacade.h"
 #include "Server/DataStructures/SharedDataType.h"
 #include "Server/DataStructures/SharedBarriers.h"
 #include "Util/BoostFileSystemFix.h"
 #include "Util/DataStoreOptions.h"
-#include "Util/SimpleLogger.h"
+#include "Util/simple_logger.hpp"
+#include "Util/osrm_exception.hpp"
 #include "Util/FingerPrint.h"
 #include "typedefs.h"
 
 #include <osrm/Coordinate.h>
 
-typedef BaseDataFacade<QueryEdge::EdgeData>::RTreeLeaf RTreeLeaf;
-typedef StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>::TreeNode RTreeNode;
-typedef StaticGraph<QueryEdge::EdgeData> QueryGraph;
+using RTreeLeaf = BaseDataFacade<QueryEdge::EdgeData>::RTreeLeaf;
+using RTreeNode = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>::TreeNode;
+using QueryGraph = StaticGraph<QueryEdge::EdgeData>;
 
 #ifdef __linux__
 #include <sys/mman.h>
@@ -60,21 +61,51 @@ typedef StaticGraph<QueryEdge::EdgeData> QueryGraph;
 #include <fstream>
 #include <string>
 
+// delete a shared memory region. report warning if it could not be deleted
+void delete_region(const SharedDataType region)
+{
+    if (SharedMemory::RegionExists(region) && !SharedMemory::Remove(region))
+    {
+        const std::string name = [&]
+        {
+            switch (region)
+            {
+            case CURRENT_REGIONS:
+                return "CURRENT_REGIONS";
+            case LAYOUT_1:
+                return "LAYOUT_1";
+            case DATA_1:
+                return "DATA_1";
+            case LAYOUT_2:
+                return "LAYOUT_2";
+            case DATA_2:
+                return "DATA_2";
+            case LAYOUT_NONE:
+                return "LAYOUT_NONE";
+            default: // DATA_NONE:
+                return "DATA_NONE";
+            }
+        }();
+
+        SimpleLogger().Write(logWARNING) << "could not delete shared memory region " << name;
+    }
+}
+
 int main(const int argc, const char *argv[])
 {
     LogPolicy::GetInstance().Unmute();
     SharedBarriers barrier;
 
-#ifdef __linux__
-    const bool lock_flags = MCL_CURRENT | MCL_FUTURE;
-    if (-1 == mlockall(lock_flags))
-    {
-        SimpleLogger().Write(logWARNING) << "Process " << argv[0] << " could not request RAM lock";
-    }
-#endif
-
     try
     {
+#ifdef __linux__
+        // try to disable swapping on Linux
+        const bool lock_flags = MCL_CURRENT | MCL_FUTURE;
+        if (-1 == mlockall(lock_flags))
+        {
+            SimpleLogger().Write(logWARNING) << "Process " << argv[0] << " could not request RAM lock";
+        }
+#endif
         try
         {
             boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock(
@@ -96,66 +127,38 @@ int main(const int argc, const char *argv[])
         SimpleLogger().Write(logDEBUG) << "Checking input parameters";
 
         ServerPaths server_paths;
-        bool springclean = false;
-        if (!GenerateDataStoreOptions(argc, argv, server_paths, springclean))
+        if (!GenerateDataStoreOptions(argc, argv, server_paths))
         {
             return 0;
         }
-        if (springclean)
-        {
-            SimpleLogger().Write() << "spring-cleaning all shared memory regions";
-            // find all existing shmem regions and remove them.
-            if (SharedMemory::RegionExists(DATA_1) && !SharedMemory::Remove(DATA_1))
-            {
-                SimpleLogger().Write(logWARNING) << "could not delete DATA_1";
-            }
-            if (SharedMemory::RegionExists(LAYOUT_1) && !SharedMemory::Remove(LAYOUT_1))
-            {
-                SimpleLogger().Write(logWARNING) << "could not delete LAYOUT_1";
-            }
-            if (SharedMemory::RegionExists(DATA_2) && !SharedMemory::Remove(DATA_2))
-            {
-                SimpleLogger().Write(logWARNING) << "could not delete DATA_2";
-            }
-            if (SharedMemory::RegionExists(LAYOUT_2) && !SharedMemory::Remove(LAYOUT_2))
-            {
-                SimpleLogger().Write(logWARNING) << "could not delete LAYOUT_2";
-            }
-            if (SharedMemory::RegionExists(CURRENT_REGIONS) &&
-                !SharedMemory::Remove(CURRENT_REGIONS))
-            {
-                SimpleLogger().Write(logWARNING) << "could not delete CURRENT_REGIONS";
-            }
-            return 0;
-        }
 
         if (server_paths.find("hsgrdata") == server_paths.end())
         {
-            throw OSRMException("no hsgr file found");
+            throw osrm::exception("no hsgr file found");
         }
         if (server_paths.find("ramindex") == server_paths.end())
         {
-            throw OSRMException("no ram index file found");
+            throw osrm::exception("no ram index file found");
         }
         if (server_paths.find("fileindex") == server_paths.end())
         {
-            throw OSRMException("no leaf index file found");
+            throw osrm::exception("no leaf index file found");
         }
         if (server_paths.find("nodesdata") == server_paths.end())
         {
-            throw OSRMException("no nodes file found");
+            throw osrm::exception("no nodes file found");
         }
         if (server_paths.find("edgesdata") == server_paths.end())
         {
-            throw OSRMException("no edges file found");
+            throw osrm::exception("no edges file found");
         }
         if (server_paths.find("namesdata") == server_paths.end())
         {
-            throw OSRMException("no names file found");
+            throw osrm::exception("no names file found");
         }
         if (server_paths.find("geometry") == server_paths.end())
         {
-            throw OSRMException("no geometry file found");
+            throw osrm::exception("no geometry file found");
         }
 
         ServerPaths::const_iterator paths_iterator = server_paths.find("hsgrdata");
@@ -193,27 +196,28 @@ int main(const int argc, const char *argv[])
         BOOST_ASSERT(!paths_iterator->second.empty());
         const boost::filesystem::path &geometries_data_path = paths_iterator->second;
 
-        // get the shared memory segment to use
-        bool use_first_segment = SharedMemory::RegionExists(LAYOUT_2);
-        const SharedDataType LAYOUT = [&]
+        // determine segment to use
+        bool segment2_in_use = SharedMemory::RegionExists(LAYOUT_2);
+        const SharedDataType layout_region = [&]
         {
-            if (use_first_segment)
-            {
-                return LAYOUT_1;
-            }
-            return LAYOUT_2;
+            return segment2_in_use ? LAYOUT_1 : LAYOUT_2;
         }();
-        const SharedDataType DATA = [&]
+        const SharedDataType data_region = [&]
         {
-            if (use_first_segment)
-            {
-                return DATA_1;
-            }
-            return DATA_2;
+            return segment2_in_use ? DATA_1 : DATA_2;
+        }();
+        const SharedDataType previous_layout_region = [&]
+        {
+            return segment2_in_use ? LAYOUT_2 : LAYOUT_1;
+        }();
+        const SharedDataType previous_data_region = [&]
+        {
+            return segment2_in_use ? DATA_2 : DATA_1;
         }();
 
         // Allocate a memory layout in shared memory, deallocate previous
-        SharedMemory *layout_memory = SharedMemoryFactory::Get(LAYOUT, sizeof(SharedDataLayout));
+        SharedMemory *layout_memory =
+            SharedMemoryFactory::Get(layout_region, sizeof(SharedDataLayout));
         SharedDataLayout *shared_layout_ptr = static_cast<SharedDataLayout *>(layout_memory->Ptr());
         shared_layout_ptr = new (layout_memory->Ptr()) SharedDataLayout();
 
@@ -246,6 +250,8 @@ int main(const int argc, const char *argv[])
                                                 number_of_original_edges);
         shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::NAME_ID_LIST,
                                                   number_of_original_edges);
+        shared_layout_ptr->SetBlockSize<TravelMode>(SharedDataLayout::TRAVEL_MODE,
+                                                    number_of_original_edges);
         shared_layout_ptr->SetBlockSize<TurnInstruction>(SharedDataLayout::TURN_INSTRUCTION,
                                                          number_of_original_edges);
         // note: there are 32 geometry indicators in one unsigned block
@@ -281,7 +287,7 @@ int main(const int argc, const char *argv[])
         // load graph edge size
         unsigned number_of_graph_edges = 0;
         hsgr_input_stream.read((char *)&number_of_graph_edges, sizeof(unsigned));
-        BOOST_ASSERT_MSG(0 != number_of_graph_edges, "number of graph edges is zero");
+        // BOOST_ASSERT_MSG(0 != number_of_graph_edges, "number of graph edges is zero");
         shared_layout_ptr->SetBlockSize<QueryGraph::EdgeArrayEntry>(
             SharedDataLayout::GRAPH_EDGE_LIST, number_of_graph_edges);
 
@@ -339,12 +345,11 @@ int main(const int argc, const char *argv[])
         geometry_input_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
         shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::GEOMETRIES_LIST,
                                                   number_of_compressed_geometries);
-
         // allocate shared memory block
         SimpleLogger().Write() << "allocating shared memory of "
                                << shared_layout_ptr->GetSizeOfLayout() << " bytes";
         SharedMemory *shared_memory =
-            SharedMemoryFactory::Get(DATA, shared_layout_ptr->GetSizeOfLayout());
+            SharedMemoryFactory::Get(data_region, shared_layout_ptr->GetSizeOfLayout());
         char *shared_memory_ptr = static_cast<char *>(shared_memory->Ptr());
 
         // read actual data into shared memory object //
@@ -405,6 +410,10 @@ int main(const int argc, const char *argv[])
         unsigned *name_id_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
             shared_memory_ptr, SharedDataLayout::NAME_ID_LIST);
 
+        TravelMode *travel_mode_ptr =
+            shared_layout_ptr->GetBlockPtr<TravelMode, true>(
+                shared_memory_ptr, SharedDataLayout::TRAVEL_MODE);
+
         TurnInstruction *turn_instructions_ptr =
             shared_layout_ptr->GetBlockPtr<TurnInstruction, true>(
                 shared_memory_ptr, SharedDataLayout::TURN_INSTRUCTION);
@@ -418,6 +427,7 @@ int main(const int argc, const char *argv[])
             edges_input_stream.read((char *)&(current_edge_data), sizeof(OriginalEdgeData));
             via_node_ptr[i] = current_edge_data.via_node;
             name_id_ptr[i] = current_edge_data.name_id;
+            travel_mode_ptr[i] = current_edge_data.travel_mode;
             turn_instructions_ptr[i] = current_edge_data.turn_instruction;
 
             const unsigned bucket = i / 32;
@@ -472,10 +482,10 @@ int main(const int argc, const char *argv[])
             shared_layout_ptr->GetBlockPtr<FixedPointCoordinate, true>(
                 shared_memory_ptr, SharedDataLayout::COORDINATE_LIST);
 
-        NodeInfo current_node;
+        QueryNode current_node;
         for (unsigned i = 0; i < coordinate_list_size; ++i)
         {
-            nodes_input_stream.read((char *)&current_node, sizeof(NodeInfo));
+            nodes_input_stream.read((char *)&current_node, sizeof(QueryNode));
             coordinates_ptr[i] = FixedPointCoordinate(current_node.lat, current_node.lon);
         }
         nodes_input_stream.close();
@@ -533,35 +543,11 @@ int main(const int argc, const char *argv[])
             barrier.no_running_queries_condition.wait(query_lock);
         }
 
-        data_timestamp_ptr->layout = LAYOUT;
-        data_timestamp_ptr->data = DATA;
+        data_timestamp_ptr->layout = layout_region;
+        data_timestamp_ptr->data = data_region;
         data_timestamp_ptr->timestamp += 1;
-        if (use_first_segment)
-        {
-            BOOST_ASSERT(DATA == DATA_1);
-            BOOST_ASSERT(LAYOUT == LAYOUT_1);
-            if (!SharedMemory::Remove(DATA_2))
-            {
-                SimpleLogger().Write(logWARNING) << "could not delete DATA_2";
-            }
-            if (!SharedMemory::Remove(LAYOUT_2))
-            {
-                SimpleLogger().Write(logWARNING) << "could not delete LAYOUT_2";
-            }
-        }
-        else
-        {
-            BOOST_ASSERT(DATA == DATA_2);
-            BOOST_ASSERT(LAYOUT == LAYOUT_2);
-            if (!SharedMemory::Remove(DATA_1))
-            {
-                SimpleLogger().Write(logWARNING) << "could not delete DATA_1";
-            }
-            if (!SharedMemory::Remove(LAYOUT_1))
-            {
-                SimpleLogger().Write(logWARNING) << "could not delete LAYOUT_1";
-            }
-        }
+        delete_region(previous_data_region);
+        delete_region(previous_layout_region);
         SimpleLogger().Write() << "all data loaded";
 
         shared_layout_ptr->PrintInformation();
diff --git a/Descriptors/DescriptionFactory.cpp b/descriptors/description_factory.cpp
similarity index 50%
rename from Descriptors/DescriptionFactory.cpp
rename to descriptors/description_factory.cpp
index 5c9cbef..075eff0 100644
--- a/Descriptors/DescriptionFactory.cpp
+++ b/descriptors/description_factory.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,18 +25,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "DescriptionFactory.h"
+#include "description_factory.hpp"
 
 #include <osrm/Coordinate.h>
 
 #include "../typedefs.h"
-#include "../Algorithms/PolylineCompressor.h"
-#include "../DataStructures/PhantomNodes.h"
-#include "../DataStructures/RawRouteData.h"
-#include "../DataStructures/SegmentInformation.h"
-#include "../DataStructures/TurnInstructions.h"
+#include "../algorithms/polyline_formatter.hpp"
+#include "../data_structures/raw_route_data.hpp"
+#include "../data_structures/turn_instructions.hpp"
 
-DescriptionFactory::DescriptionFactory() : entireLength(0) { via_indices.push_back(0); }
+DescriptionFactory::DescriptionFactory() : entire_length(0) { via_indices.push_back(0); }
 
 std::vector<unsigned> const &DescriptionFactory::GetViaIndices() const { return via_indices; }
 
@@ -45,44 +43,77 @@ void DescriptionFactory::SetStartSegment(const PhantomNode &source, const bool t
     start_phantom = source;
     const EdgeWeight segment_duration =
         (traversed_in_reverse ? source.reverse_weight : source.forward_weight);
-    AppendSegment(source.location,
-                  PathData(0, source.name_id, TurnInstruction::HeadOn, segment_duration));
+    const TravelMode travel_mode =
+        (traversed_in_reverse ? source.backward_travel_mode : source.forward_travel_mode);
+    AppendSegment(
+        source.location,
+        PathData(0, source.name_id, TurnInstruction::HeadOn, segment_duration, travel_mode));
     BOOST_ASSERT(path_description.back().duration == segment_duration);
 }
 
-void DescriptionFactory::SetEndSegment(const PhantomNode &target, const bool traversed_in_reverse)
+void DescriptionFactory::SetEndSegment(const PhantomNode &target,
+                                       const bool traversed_in_reverse,
+                                       const bool is_via_location)
 {
     target_phantom = target;
     const EdgeWeight segment_duration =
         (traversed_in_reverse ? target.reverse_weight : target.forward_weight);
-    path_description.emplace_back(
-        target.location, target.name_id, segment_duration, 0.f, TurnInstruction::NoTurn, true, true);
+    const TravelMode travel_mode =
+        (traversed_in_reverse ? target.backward_travel_mode : target.forward_travel_mode);
+    path_description.emplace_back(target.location,
+                                  target.name_id,
+                                  segment_duration,
+                                  0.f,
+                                  is_via_location ? TurnInstruction::ReachViaLocation
+                                                  : TurnInstruction::NoTurn,
+                                  true,
+                                  true,
+                                  travel_mode);
     BOOST_ASSERT(path_description.back().duration == segment_duration);
 }
 
 void DescriptionFactory::AppendSegment(const FixedPointCoordinate &coordinate,
                                        const PathData &path_point)
 {
-    if ((1 == path_description.size()) && (path_description.back().location == coordinate))
+    // if the start location is on top of a node, the first movement might be zero-length,
+    // in which case we dont' add a new description, but instead update the existing one
+    if ((1 == path_description.size()) && (path_description.front().location == coordinate))
     {
-        path_description.back().name_id = path_point.name_id;
+        if (path_point.segment_duration > 0)
+        {
+            path_description.front().name_id = path_point.name_id;
+            path_description.front().travel_mode = path_point.travel_mode;
+        }
         return;
     }
 
+    // make sure mode changes are announced, even when there otherwise is no turn
+    const TurnInstruction turn = [&]() -> TurnInstruction
+    {
+        if (TurnInstruction::NoTurn == path_point.turn_instruction &&
+            path_description.front().travel_mode != path_point.travel_mode &&
+            path_point.segment_duration > 0)
+        {
+            return TurnInstruction::GoStraight;
+        }
+        return path_point.turn_instruction;
+    }();
+
     path_description.emplace_back(coordinate,
                                   path_point.name_id,
                                   path_point.segment_duration,
-                                  0,
-                                  path_point.turn_instruction);
+                                  0.f,
+                                  turn,
+                                  path_point.travel_mode);
 }
 
-JSON::Value DescriptionFactory::AppendEncodedPolylineString(const bool return_encoded)
+JSON::Value DescriptionFactory::AppendGeometryString(const bool return_encoded)
 {
     if (return_encoded)
     {
-        return polyline_compressor.printEncodedString(path_description);
+        return PolylineFormatter().printEncodedString(path_description);
     }
-    return polyline_compressor.printUnencodedString(path_description);
+    return PolylineFormatter().printUnencodedString(path_description);
 }
 
 void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time)
diff --git a/Descriptors/DescriptionFactory.h b/descriptors/description_factory.hpp
similarity index 85%
rename from Descriptors/DescriptionFactory.h
rename to descriptors/description_factory.hpp
index d081bae..9b96dd2 100644
--- a/Descriptors/DescriptionFactory.h
+++ b/descriptors/description_factory.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,18 +25,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef DESCRIPTIONFACTORY_H_
-#define DESCRIPTIONFACTORY_H_
+#ifndef DESCRIPTION_FACTORY_HPP
+#define DESCRIPTION_FACTORY_HPP
 
-#include "../Algorithms/DouglasPeucker.h"
-#include "../Algorithms/PolylineCompressor.h"
-#include "../DataStructures/PhantomNodes.h"
-#include "../DataStructures/SegmentInformation.h"
-#include "../DataStructures/TurnInstructions.h"
+#include "../algorithms/douglas_peucker.hpp"
+#include "../data_structures/phantom_node.hpp"
+#include "../data_structures/json_container.hpp"
+#include "../data_structures/segment_information.hpp"
+#include "../data_structures/turn_instructions.hpp"
 #include "../typedefs.h"
 
+#include <boost/assert.hpp>
+
 #include <osrm/Coordinate.h>
 
+#include <cmath>
+
 #include <limits>
 #include <vector>
 
@@ -47,7 +51,6 @@ struct PathData;
 class DescriptionFactory
 {
     DouglasPeucker polyline_generalizer;
-    PolylineCompressor polyline_compressor;
     PhantomNode start_phantom, target_phantom;
 
     double DegreeToRadian(const double degree) const;
@@ -55,6 +58,8 @@ class DescriptionFactory
 
     std::vector<unsigned> via_indices;
 
+    double entire_length;
+
   public:
     struct RouteSummary
     {
@@ -67,22 +72,27 @@ class DescriptionFactory
         void BuildDurationAndLengthStrings(const double raw_distance, const unsigned raw_duration)
         {
             // compute distance/duration for route summary
-            distance = static_cast<unsigned>(round(raw_distance));
-            duration = static_cast<unsigned>(round(raw_duration / 10.));
+            distance = static_cast<unsigned>(std::round(raw_distance));
+            duration = static_cast<unsigned>(std::round(raw_duration / 10.));
         }
     } summary;
 
-    double entireLength;
-
     // I know, declaring this public is considered bad. I'm lazy
     std::vector<SegmentInformation> path_description;
     DescriptionFactory();
     void AppendSegment(const FixedPointCoordinate &coordinate, const PathData &data);
     void BuildRouteSummary(const double distance, const unsigned time);
     void SetStartSegment(const PhantomNode &start_phantom, const bool traversed_in_reverse);
-    void SetEndSegment(const PhantomNode &start_phantom, const bool traversed_in_reverse);
-    JSON::Value AppendEncodedPolylineString(const bool return_encoded);
-    std::vector<unsigned> const & GetViaIndices() const;
+    void SetEndSegment(const PhantomNode &start_phantom,
+                       const bool traversed_in_reverse,
+                       const bool is_via_location = false);
+    JSON::Value AppendGeometryString(const bool return_encoded);
+    std::vector<unsigned> const &GetViaIndices() const;
+
+    double get_entire_length() const
+    {
+        return entire_length;
+    }
 
     template <class DataFacadeT> void Run(const DataFacadeT *facade, const unsigned zoomLevel)
     {
@@ -150,7 +160,7 @@ class DescriptionFactory
 
         for (unsigned i = 1; i < path_description.size(); ++i)
         {
-            entireLength += path_description[i].length;
+            entire_length += path_description[i].length;
             segment_length += path_description[i].length;
             segment_duration += path_description[i].duration;
             path_description[segment_start_index].length = segment_length;
@@ -188,7 +198,7 @@ class DescriptionFactory
         }
 
         // Generalize poly line
-        polyline_generalizer.Run(path_description, zoomLevel);
+        polyline_generalizer.Run(path_description.begin(), path_description.end(), zoomLevel);
 
         // fix what needs to be fixed else
         unsigned necessary_pieces = 0; // a running index that counts the necessary pieces
@@ -198,18 +208,19 @@ class DescriptionFactory
             {
                 ++necessary_pieces;
                 if (path_description[i].is_via_location)
-                {   //mark the end of a leg
+                { // mark the end of a leg
                     via_indices.push_back(necessary_pieces);
                 }
-                const double angle = path_description[i+1].location.GetBearing(path_description[i].location);
+                const double angle =
+                    path_description[i + 1].location.GetBearing(path_description[i].location);
                 path_description[i].bearing = static_cast<unsigned>(angle * 10);
             }
         }
-        via_indices.push_back(necessary_pieces+1);
+        via_indices.push_back(necessary_pieces + 1);
         BOOST_ASSERT(via_indices.size() >= 2);
         // BOOST_ASSERT(0 != necessary_pieces || path_description.empty());
         return;
     }
 };
 
-#endif /* DESCRIPTIONFACTORY_H_ */
+#endif /* DESCRIPTION_FACTORY_HPP */
diff --git a/Descriptors/BaseDescriptor.h b/descriptors/descriptor_base.hpp
similarity index 66%
rename from Descriptors/BaseDescriptor.h
rename to descriptors/descriptor_base.hpp
index d06b9b6..31c08ea 100644
--- a/Descriptors/BaseDescriptor.h
+++ b/descriptors/descriptor_base.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,27 +25,53 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef BASE_DESCRIPTOR_H
-#define BASE_DESCRIPTOR_H
+#ifndef DESCRIPTOR_BASE_HPP
+#define DESCRIPTOR_BASE_HPP
 
-#include "../DataStructures/PhantomNodes.h"
-#include "../DataStructures/RawRouteData.h"
+#include "../data_structures/phantom_node.hpp"
+#include "../data_structures/raw_route_data.hpp"
 #include "../typedefs.h"
 
 #include <osrm/Reply.h>
 
 #include <string>
+#include <unordered_map>
 #include <vector>
 
+
+struct DescriptorTable : public std::unordered_map<std::string, unsigned>
+{
+    unsigned get_id(const std::string &key)
+    {
+        auto iter = find(key);
+        if (iter != end())
+        {
+            return iter->second;
+        }
+        return 0;
+    }
+};
+
+
 struct DescriptorConfig
 {
     DescriptorConfig() : instructions(true), geometry(true), encode_geometry(true), zoom_level(18)
     {
     }
+
+    template<class OtherT>
+    DescriptorConfig(const OtherT &other) : instructions(other.print_instructions),
+                                            geometry(other.geometry),
+                                            encode_geometry(other.compression),
+                                            zoom_level(other.zoom_level)
+    {
+        BOOST_ASSERT(zoom_level >= 0);
+    }
+
     bool instructions;
     bool geometry;
     bool encode_geometry;
-    unsigned short zoom_level;
+    short zoom_level;
 };
 
 template <class DataFacadeT> class BaseDescriptor
@@ -58,4 +84,4 @@ template <class DataFacadeT> class BaseDescriptor
     virtual void SetConfig(const DescriptorConfig &config) = 0;
 };
 
-#endif // BASE_DESCRIPTOR_H
+#endif // DESCRIPTOR_BASE_HPP
diff --git a/descriptors/gpx_descriptor.hpp b/descriptors/gpx_descriptor.hpp
new file mode 100644
index 0000000..2dd0034
--- /dev/null
+++ b/descriptors/gpx_descriptor.hpp
@@ -0,0 +1,92 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef GPX_DESCRIPTOR_HPP
+#define GPX_DESCRIPTOR_HPP
+
+#include "descriptor_base.hpp"
+#include "../data_structures/json_container.hpp"
+#include "../Util/xml_renderer.hpp"
+
+#include <iostream>
+
+template <class DataFacadeT> class GPXDescriptor final : public BaseDescriptor<DataFacadeT>
+{
+  private:
+    DescriptorConfig config;
+    DataFacadeT *facade;
+
+    void AddRoutePoint(const FixedPointCoordinate &coordinate, JSON::Array &json_result)
+    {
+        JSON::Object json_lat;
+        JSON::Object json_lon;
+        JSON::Array json_row;
+
+        std::string tmp;
+
+        FixedPointCoordinate::convertInternalLatLonToString(coordinate.lat, tmp);
+        json_lat.values["_lat"] = tmp;
+
+        FixedPointCoordinate::convertInternalLatLonToString(coordinate.lon, tmp);
+        json_lon.values["_lon"] = tmp;
+
+        json_row.values.push_back(json_lat);
+        json_row.values.push_back(json_lon);
+        JSON::Object entry;
+        entry.values["rtept"] = json_row;
+        json_result.values.push_back(entry);
+    }
+
+  public:
+    explicit GPXDescriptor(DataFacadeT *facade) : facade(facade) {}
+
+    void SetConfig(const DescriptorConfig &c) final { config = c; }
+
+    void Run(const RawRouteData &raw_route, http::Reply &reply) final
+    {
+        JSON::Array json_result;
+        if (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT)
+        {
+            AddRoutePoint(raw_route.segment_end_coordinates.front().source_phantom.location,
+                          json_result);
+
+            for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments)
+            {
+                for (const PathData &path_data : path_data_vector)
+                {
+                    const FixedPointCoordinate current_coordinate =
+                        facade->GetCoordinateOfNode(path_data.node);
+                    AddRoutePoint(current_coordinate, json_result);
+                }
+            }
+            AddRoutePoint(raw_route.segment_end_coordinates.back().target_phantom.location,
+                          json_result);
+        }
+        JSON::gpx_render(reply.content, json_result);
+    }
+};
+#endif // GPX_DESCRIPTOR_HPP
diff --git a/Descriptors/JSONDescriptor.h b/descriptors/json_descriptor.hpp
similarity index 77%
rename from Descriptors/JSONDescriptor.h
rename to descriptors/json_descriptor.hpp
index 938e4ef..2aae939 100644
--- a/Descriptors/JSONDescriptor.h
+++ b/descriptors/json_descriptor.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,23 +25,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef JSON_DESCRIPTOR_H_
-#define JSON_DESCRIPTOR_H_
-
-#include "BaseDescriptor.h"
-#include "DescriptionFactory.h"
-#include "../Algorithms/ObjectToBase64.h"
-#include "../Algorithms/ExtractRouteNames.h"
-#include "../DataStructures/JSONContainer.h"
-#include "../DataStructures/SegmentInformation.h"
-#include "../DataStructures/TurnInstructions.h"
-#include "../Util/Azimuth.h"
-#include "../Util/StringUtil.h"
-#include "../Util/TimingUtil.h"
+#ifndef JSON_DESCRIPTOR_HPP
+#define JSON_DESCRIPTOR_HPP
+
+#include "descriptor_base.hpp"
+#include "description_factory.hpp"
+#include "../algorithms/object_encoder.hpp"
+#include "../algorithms/route_name_extraction.hpp"
+#include "../data_structures/json_container.hpp"
+#include "../data_structures/segment_information.hpp"
+#include "../data_structures/turn_instructions.hpp"
+#include "../Util/bearing.hpp"
+#include "../Util/integer_range.hpp"
+#include "../Util/json_renderer.hpp"
+#include "../Util/simple_logger.hpp"
+#include "../Util/string_util.hpp"
+#include "../Util/timing_util.hpp"
 
 #include <algorithm>
 
-template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFacadeT>
+template <class DataFacadeT> class JSONDescriptor final : public BaseDescriptor<DataFacadeT>
 {
   private:
     DataFacadeT *facade;
@@ -69,13 +72,14 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
     ExtractRouteNames<DataFacadeT, Segment> GenerateRouteNames;
 
   public:
-    JSONDescriptor(DataFacadeT *facade) : facade(facade), entered_restricted_area_count(0) {}
+    explicit JSONDescriptor(DataFacadeT *facade) : facade(facade), entered_restricted_area_count(0) {}
 
-    void SetConfig(const DescriptorConfig &c) { config = c; }
+    void SetConfig(const DescriptorConfig &c) final { config = c; }
 
     unsigned DescribeLeg(const std::vector<PathData> route_leg,
                          const PhantomNodes &leg_phantoms,
-                         const bool target_traversed_in_reverse)
+                         const bool target_traversed_in_reverse,
+                         const bool is_via_leg)
     {
         unsigned added_element_count = 0;
         // Get all the coordinates for the computed route
@@ -86,13 +90,14 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
             description_factory.AppendSegment(current_coordinate, path_data);
             ++added_element_count;
         }
-        description_factory.SetEndSegment(leg_phantoms.target_phantom, target_traversed_in_reverse);
+        description_factory.SetEndSegment(
+            leg_phantoms.target_phantom, target_traversed_in_reverse, is_via_leg);
         ++added_element_count;
         BOOST_ASSERT((route_leg.size() + 1) == added_element_count);
         return added_element_count;
     }
 
-    void Run(const RawRouteData &raw_route, http::Reply &reply)
+    void Run(const RawRouteData &raw_route, http::Reply &reply) final
     {
         JSON::Object json_result;
         if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
@@ -118,14 +123,15 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
         json_result.values["status_message"] = "Found route between points";
 
         // for each unpacked segment add the leg to the description
-        for (unsigned i = 0; i < raw_route.unpacked_path_segments.size(); ++i)
+        for (const auto i : osrm::irange<std::size_t>(0, raw_route.unpacked_path_segments.size()))
         {
 #ifndef NDEBUG
             const int added_segments =
 #endif
                 DescribeLeg(raw_route.unpacked_path_segments[i],
                             raw_route.segment_end_coordinates[i],
-                            raw_route.target_traversed_in_reverse[i]);
+                            raw_route.target_traversed_in_reverse[i],
+                            raw_route.is_via_leg(i));
             BOOST_ASSERT(0 < added_segments);
         }
         description_factory.Run(facade, config.zoom_level);
@@ -133,7 +139,7 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
         if (config.geometry)
         {
             JSON::Value route_geometry =
-                description_factory.AppendEncodedPolylineString(config.encode_geometry);
+                description_factory.AppendGeometryString(config.encode_geometry);
             json_result.values["route_geometry"] = route_geometry;
         }
         if (config.instructions)
@@ -145,7 +151,7 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
                                     shortest_path_segments);
             json_result.values["route_instructions"] = json_route_instructions;
         }
-        description_factory.BuildRouteSummary(description_factory.entireLength,
+        description_factory.BuildRouteSummary(description_factory.get_entire_length(),
                                               raw_route.shortest_path_length);
         JSON::Object json_route_summary;
         json_route_summary.values["total_distance"] = description_factory.summary.distance;
@@ -201,13 +207,15 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
                 current = facade->GetCoordinateOfNode(path_data.node);
                 alternate_description_factory.AppendSegment(current, path_data);
             }
+            alternate_description_factory.SetEndSegment(
+                raw_route.segment_end_coordinates.back().target_phantom,
+                raw_route.alt_source_traversed_in_reverse.back());
             alternate_description_factory.Run(facade, config.zoom_level);
 
             if (config.geometry)
             {
                 JSON::Value alternate_geometry_string =
-                    alternate_description_factory.AppendEncodedPolylineString(
-                        config.encode_geometry);
+                    alternate_description_factory.AppendGeometryString(config.encode_geometry);
                 JSON::Array json_alternate_geometries_array;
                 json_alternate_geometries_array.values.push_back(alternate_geometry_string);
                 json_result.values["alternative_geometries"] = json_alternate_geometries_array;
@@ -225,7 +233,7 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
                 json_result.values["alternative_instructions"] = json_alt_instructions;
             }
             alternate_description_factory.BuildRouteSummary(
-                alternate_description_factory.entireLength, raw_route.alternative_path_length);
+                alternate_description_factory.get_entire_length(), raw_route.alternative_path_length);
 
             JSON::Object json_alternate_route_summary;
             JSON::Array json_alternate_route_summary_array;
@@ -272,15 +280,15 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
         }
 
         JSON::Object json_hint_object;
-        json_hint_object.values["checksum"] = raw_route.check_sum;
+        json_hint_object.values["checksum"] = facade->GetCheckSum();
         JSON::Array json_location_hint_array;
         std::string hint;
-        for (unsigned i = 0; i < raw_route.segment_end_coordinates.size(); ++i)
+        for (const auto i : osrm::irange<std::size_t>(0, raw_route.segment_end_coordinates.size()))
         {
-            EncodeObjectToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint);
+            ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint);
             json_location_hint_array.values.push_back(hint);
         }
-        EncodeObjectToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint);
+        ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint);
         json_location_hint_array.values.push_back(hint);
         json_hint_object.values["locations"] = json_location_hint_array;
         json_result.values["hint_data"] = json_hint_object;
@@ -300,7 +308,7 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
     {
         // Segment information has following format:
         //["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
-        unsigned necessary_segments_running_index = 1;
+        unsigned necessary_segments_running_index = 0;
         round_about.leave_at_exit = 0;
         round_about.name_id = 0;
         std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
@@ -324,16 +332,16 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
                     if (TurnInstruction::LeaveRoundAbout == current_instruction)
                     {
                         temp_instruction =
-                            IntToString(as_integer(TurnInstruction::EnterRoundAbout));
+                            cast::integral_to_string(cast::enum_to_underlying(TurnInstruction::EnterRoundAbout));
                         current_turn_instruction += temp_instruction;
                         current_turn_instruction += "-";
-                        temp_instruction = IntToString(round_about.leave_at_exit + 1);
+                        temp_instruction = cast::integral_to_string(round_about.leave_at_exit + 1);
                         current_turn_instruction += temp_instruction;
                         round_about.leave_at_exit = 0;
                     }
                     else
                     {
-                        temp_instruction = IntToString(as_integer(current_instruction));
+                        temp_instruction = cast::integral_to_string(cast::enum_to_underlying(current_instruction));
                         current_turn_instruction += temp_instruction;
                     }
                     json_instruction_row.values.push_back(current_turn_instruction);
@@ -344,13 +352,17 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
                     json_instruction_row.values.push_back(necessary_segments_running_index);
                     json_instruction_row.values.push_back(round(segment.duration / 10));
                     json_instruction_row.values.push_back(
-                        UintToString(static_cast<unsigned>(segment.length)) + "m");
-                    const double bearing_value = (segment.bearing / 10.) ;
-                    json_instruction_row.values.push_back(Azimuth::Get(bearing_value));
-                    json_instruction_row.values.push_back(static_cast<unsigned>(round(bearing_value)));
+                        cast::integral_to_string(static_cast<unsigned>(segment.length)) + "m");
+                    const double bearing_value = (segment.bearing / 10.);
+                    json_instruction_row.values.push_back(Bearing::Get(bearing_value));
+                    json_instruction_row.values.push_back(
+                        static_cast<unsigned>(round(bearing_value)));
+                    json_instruction_row.values.push_back(segment.travel_mode);
 
                     route_segments_list.emplace_back(
-                        segment.name_id, segment.length, route_segments_list.size());
+                        segment.name_id,
+                        static_cast<int>(segment.length),
+                        static_cast<unsigned>(route_segments_list.size()));
                     json_instruction_array.values.push_back(json_instruction_row);
                 }
             }
@@ -364,22 +376,18 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
             }
         }
 
-        // TODO: check if this in an invariant
-        if (INVALID_EDGE_WEIGHT != route_length)
-        {
-            JSON::Array json_last_instruction_row;
-            temp_instruction = IntToString(as_integer(TurnInstruction::ReachedYourDestination));
-            json_last_instruction_row.values.push_back(temp_instruction);
-            json_last_instruction_row.values.push_back("");
-            json_last_instruction_row.values.push_back(0);
-            json_last_instruction_row.values.push_back(necessary_segments_running_index - 1);
-            json_last_instruction_row.values.push_back(0);
-            json_last_instruction_row.values.push_back("0m");
-            json_last_instruction_row.values.push_back(Azimuth::Get(0.0));
-            json_last_instruction_row.values.push_back(0.);
-            json_instruction_array.values.push_back(json_last_instruction_row);
-        }
+        JSON::Array json_last_instruction_row;
+        temp_instruction = cast::integral_to_string(cast::enum_to_underlying(TurnInstruction::ReachedYourDestination));
+        json_last_instruction_row.values.push_back(temp_instruction);
+        json_last_instruction_row.values.push_back("");
+        json_last_instruction_row.values.push_back(0);
+        json_last_instruction_row.values.push_back(necessary_segments_running_index - 1);
+        json_last_instruction_row.values.push_back(0);
+        json_last_instruction_row.values.push_back("0m");
+        json_last_instruction_row.values.push_back(Bearing::Get(0.0));
+        json_last_instruction_row.values.push_back(0.);
+        json_instruction_array.values.push_back(json_last_instruction_row);
     }
 };
 
-#endif /* JSON_DESCRIPTOR_H_ */
+#endif /* JSON_DESCRIPTOR_HPP */
diff --git a/Server/Http/CompressionType.h b/extract.cpp
similarity index 78%
copy from Server/Http/CompressionType.h
copy to extract.cpp
index 74d0b62..2ad1f7a 100644
--- a/Server/Http/CompressionType.h
+++ b/extract.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,17 +25,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef COMPRESSION_TYPE_H
-#define COMPRESSION_TYPE_H
+#include "extractor/extractor.hpp"
+#include "Util/simple_logger.hpp"
 
-namespace http
+int main (int argc, char *argv[])
 {
-
-enum CompressionType
-{ noCompression,
-  gzipRFC1952,
-  deflateRFC1951 };
-
-} // namespace http
-
-#endif // COMPRESSION_TYPE_H
+    try
+    {
+        return Extractor().Run(argc, argv);
+    }
+    catch (const std::exception &e)
+    {
+        SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+    }
+
+}
diff --git a/extractor.cpp b/extractor.cpp
deleted file mode 100644
index b170b74..0000000
--- a/extractor.cpp
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "Extractor/ExtractorCallbacks.h"
-#include "Extractor/ExtractionContainers.h"
-#include "Extractor/ScriptingEnvironment.h"
-#include "Extractor/PBFParser.h"
-#include "Extractor/XMLParser.h"
-#include "Util/FingerPrint.h"
-#include "Util/GitDescription.h"
-#include "Util/MachineInfo.h"
-#include "Util/OSRMException.h"
-#include "Util/ProgramOptions.h"
-#include "Util/SimpleLogger.h"
-#include "Util/StringUtil.h"
-#include "Util/TimingUtil.h"
-#include "typedefs.h"
-
-#include <cstdlib>
-
-#include <thread>
-#include <chrono>
-#include <iostream>
-#include <fstream>
-#include <string>
-#include <unordered_map>
-
-#include <tbb/task_scheduler_init.h>
-
-ExtractorCallbacks *extractor_callbacks;
-FingerPrint fingerprint;
-
-int main(int argc, char *argv[])
-{
-    try
-    {
-        LogPolicy::GetInstance().Unmute();
-
-        TIMER_START(extracting);
-
-        boost::filesystem::path config_file_path, input_path, profile_path;
-        unsigned requested_num_threads;
-
-        // declare a group of options that will be allowed only on command line
-        boost::program_options::options_description generic_options("Options");
-        generic_options.add_options()("version,v", "Show version")("help,h",
-                                                                   "Show this help message")(
-            "config,c",
-            boost::program_options::value<boost::filesystem::path>(&config_file_path)
-                ->default_value("extractor.ini"),
-            "Path to a configuration file.");
-
-        // declare a group of options that will be allowed both on command line and in config file
-        boost::program_options::options_description config_options("Configuration");
-        config_options.add_options()("profile,p",
-                                     boost::program_options::value<boost::filesystem::path>(
-                                         &profile_path)->default_value("profile.lua"),
-                                     "Path to LUA routing profile")(
-            "threads,t",
-            boost::program_options::value<unsigned int>(&requested_num_threads)->default_value(tbb::task_scheduler_init::default_num_threads()),
-            "Number of threads to use");
-
-        // hidden options, will be allowed both on command line and in config file, but will not be
-        // shown to the user
-        boost::program_options::options_description hidden_options("Hidden options");
-        hidden_options.add_options()(
-            "input,i",
-            boost::program_options::value<boost::filesystem::path>(&input_path),
-            "Input file in .osm, .osm.bz2 or .osm.pbf format");
-
-        // positional option
-        boost::program_options::positional_options_description positional_options;
-        positional_options.add("input", 1);
-
-        // combine above options for parsing
-        boost::program_options::options_description cmdline_options;
-        cmdline_options.add(generic_options).add(config_options).add(hidden_options);
-
-        boost::program_options::options_description config_file_options;
-        config_file_options.add(config_options).add(hidden_options);
-
-        boost::program_options::options_description visible_options(
-            boost::filesystem::basename(argv[0]) + " <input.osm/.osm.bz2/.osm.pbf> [options]");
-        visible_options.add(generic_options).add(config_options);
-
-        // parse command line options
-        boost::program_options::variables_map option_variables;
-        boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
-                                          .options(cmdline_options)
-                                          .positional(positional_options)
-                                          .run(),
-                                      option_variables);
-
-        if (option_variables.count("version"))
-        {
-            SimpleLogger().Write() << g_GIT_DESCRIPTION;
-            return 0;
-        }
-
-        if (option_variables.count("help"))
-        {
-            SimpleLogger().Write() << visible_options;
-            return 0;
-        }
-
-        boost::program_options::notify(option_variables);
-
-        // parse config file
-        if (boost::filesystem::is_regular_file(config_file_path))
-        {
-            SimpleLogger().Write() << "Reading options from: " << config_file_path.string();
-            std::string ini_file_contents = ReadIniFileAndLowerContents(config_file_path);
-            std::stringstream config_stream(ini_file_contents);
-            boost::program_options::store(parse_config_file(config_stream, config_file_options),
-                                          option_variables);
-            boost::program_options::notify(option_variables);
-        }
-
-        if (!option_variables.count("input"))
-        {
-            SimpleLogger().Write() << visible_options;
-            return 0;
-        }
-
-        if (1 > requested_num_threads)
-        {
-            SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
-            return 1;
-        }
-
-        if (!boost::filesystem::is_regular_file(input_path))
-        {
-            SimpleLogger().Write(logWARNING) << "Input file " << input_path.string()
-                                             << " not found!";
-            return 1;
-        }
-
-        if (!boost::filesystem::is_regular_file(profile_path))
-        {
-            SimpleLogger().Write(logWARNING) << "Profile " << profile_path.string()
-                                             << " not found!";
-            return 1;
-        }
-
-        const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
-
-        SimpleLogger().Write() << "Input file: " << input_path.filename().string();
-        SimpleLogger().Write() << "Profile: " << profile_path.filename().string();
-        SimpleLogger().Write() << "Threads: " << requested_num_threads;
-        if (recommended_num_threads != requested_num_threads)
-        {
-            SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
-                                             << recommended_num_threads
-                                             << "! This setting may have performance side-effects.";
-        }
-
-        tbb::task_scheduler_init init(requested_num_threads);
-
-        /*** Setup Scripting Environment ***/
-        ScriptingEnvironment scripting_environment(profile_path.string().c_str());
-
-        bool file_has_pbf_format(false);
-        std::string output_file_name = input_path.string();
-        std::string restriction_fileName = input_path.string();
-        std::string::size_type pos = output_file_name.find(".osm.bz2");
-        if (pos == std::string::npos)
-        {
-            pos = output_file_name.find(".osm.pbf");
-            if (pos != std::string::npos)
-            {
-                file_has_pbf_format = true;
-            } else {
-                pos = output_file_name.find(".osm.xml");
-            }
-        }
-        if (pos == std::string::npos)
-        {
-            pos = output_file_name.find(".pbf");
-            if (pos != std::string::npos)
-            {
-                file_has_pbf_format = true;
-            }
-        }
-        if (pos == std::string::npos)
-        {
-            pos = output_file_name.find(".osm");
-            if (pos == std::string::npos)
-            {
-                output_file_name.append(".osrm");
-                restriction_fileName.append(".osrm.restrictions");
-            }
-            else
-            {
-                output_file_name.replace(pos, 5, ".osrm");
-                restriction_fileName.replace(pos, 5, ".osrm.restrictions");
-            }
-        }
-        else
-        {
-            output_file_name.replace(pos, 8, ".osrm");
-            restriction_fileName.replace(pos, 8, ".osrm.restrictions");
-        }
-
-        std::unordered_map<std::string, NodeID> string_map;
-        ExtractionContainers extraction_containers;
-
-        string_map[""] = 0;
-        extractor_callbacks = new ExtractorCallbacks(extraction_containers, string_map);
-        BaseParser *parser;
-        if (file_has_pbf_format)
-        {
-            parser = new PBFParser(input_path.string().c_str(),
-                                   extractor_callbacks,
-                                   scripting_environment,
-                                   requested_num_threads);
-        }
-        else
-        {
-            parser = new XMLParser(input_path.string().c_str(), extractor_callbacks, scripting_environment);
-        }
-
-        if (!parser->ReadHeader())
-        {
-            throw OSRMException("Parser not initialized!");
-        }
-        SimpleLogger().Write() << "Parsing in progress..";
-        TIMER_START(parsing);
-
-        parser->Parse();
-        delete parser;
-        delete extractor_callbacks;
-
-        TIMER_STOP(parsing);
-        SimpleLogger().Write() << "Parsing finished after " << TIMER_SEC(parsing)
-                               << " seconds";
-
-        if (extraction_containers.all_edges_list.empty())
-        {
-            SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
-            return 1;
-        }
-
-        extraction_containers.PrepareData(output_file_name, restriction_fileName);
-
-        TIMER_STOP(extracting);
-        SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting)
-                               << "s";
-        SimpleLogger().Write() << "To prepare the data for routing, run: "
-                               << "./osrm-prepare " << output_file_name << std::endl;
-    }
-    catch (boost::program_options::too_many_positional_options_error &)
-    {
-        SimpleLogger().Write(logWARNING) << "Only one input file can be specified";
-        return 1;
-    }
-    catch (std::exception &e)
-    {
-        SimpleLogger().Write(logWARNING) << e.what();
-        return 1;
-    }
-    return 0;
-}
diff --git a/Extractor/ExtractionContainers.cpp b/extractor/extraction_containers.cpp
similarity index 82%
rename from Extractor/ExtractionContainers.cpp
rename to extractor/extraction_containers.cpp
index 91981d6..604f863 100644
--- a/Extractor/ExtractionContainers.cpp
+++ b/extractor/extraction_containers.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,12 +25,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "ExtractionContainers.h"
-#include "ExtractionWay.h"
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/TimingUtil.h"
-#include "../DataStructures/RangeTable.h"
+#include "extraction_containers.hpp"
+#include "extraction_way.hpp"
+
+#include "../data_structures/node_id.hpp"
+#include "../data_structures/range_table.hpp"
+
+#include "../Util/osrm_exception.hpp"
+#include "../Util/simple_logger.hpp"
+#include "../Util/timing_util.hpp"
 
 #include <boost/assert.hpp>
 #include <boost/filesystem.hpp>
@@ -82,19 +85,24 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
 
         std::cout << "[extractor] Sorting all nodes         ... " << std::flush;
         TIMER_START(sorting_nodes);
-        stxxl::sort(all_nodes_list.begin(), all_nodes_list.end(), CmpNodeByID(), stxxl_memory);
+        stxxl::sort(all_nodes_list.begin(),
+                    all_nodes_list.end(),
+                    ExternalMemoryNodeSTXXLCompare(),
+                    stxxl_memory);
         TIMER_STOP(sorting_nodes);
         std::cout << "ok, after " << TIMER_SEC(sorting_nodes) << "s" << std::endl;
 
 
         std::cout << "[extractor] Sorting used ways         ... " << std::flush;
         TIMER_START(sort_ways);
-        stxxl::sort(
-            way_start_end_id_list.begin(), way_start_end_id_list.end(), CmpWayByID(), stxxl_memory);
+        stxxl::sort(way_start_end_id_list.begin(),
+                    way_start_end_id_list.end(),
+                    FirstAndLastSegmentOfWayStxxlCompare(),
+                    stxxl_memory);
         TIMER_STOP(sort_ways);
         std::cout << "ok, after " << TIMER_SEC(sort_ways) << "s" << std::endl;
 
-        std::cout << "[extractor] Sorting restrictions. by from... " << std::flush;
+        std::cout << "[extractor] Sorting " << restrictions_list.size() << " restrictions. by from... " << std::flush;
         TIMER_START(sort_restrictions);
         stxxl::sort(restrictions_list.begin(),
                     restrictions_list.end(),
@@ -111,39 +119,39 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
         while (way_start_and_end_iterator != way_start_end_id_list.end() &&
                restrictions_iterator != restrictions_list.end())
         {
-            if (way_start_and_end_iterator->wayID < restrictions_iterator->fromWay)
+            if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.from.way)
             {
                 ++way_start_and_end_iterator;
                 continue;
             }
 
-            if (way_start_and_end_iterator->wayID > restrictions_iterator->fromWay)
+            if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.from.way)
             {
                 ++restrictions_iterator;
                 continue;
             }
 
-            BOOST_ASSERT(way_start_and_end_iterator->wayID == restrictions_iterator->fromWay);
-            const NodeID via_node_id = restrictions_iterator->restriction.viaNode;
+            BOOST_ASSERT(way_start_and_end_iterator->way_id == restrictions_iterator->restriction.from.way);
+            const NodeID via_node_id = restrictions_iterator->restriction.via.node;
 
-            if (way_start_and_end_iterator->firstStart == via_node_id)
+            if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
             {
-                restrictions_iterator->restriction.fromNode =
-                    way_start_and_end_iterator->firstTarget;
+                restrictions_iterator->restriction.from.node =
+                    way_start_and_end_iterator->first_segment_source_id;
             }
-            else if (way_start_and_end_iterator->firstTarget == via_node_id)
+            else if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
             {
-                restrictions_iterator->restriction.fromNode =
-                    way_start_and_end_iterator->firstStart;
+                restrictions_iterator->restriction.from.node =
+                    way_start_and_end_iterator->first_segment_source_id;
             }
-            else if (way_start_and_end_iterator->lastStart == via_node_id)
+            else if (way_start_and_end_iterator->last_segment_source_id == via_node_id)
             {
-                restrictions_iterator->restriction.fromNode =
-                    way_start_and_end_iterator->lastTarget;
+                restrictions_iterator->restriction.from.node =
+                    way_start_and_end_iterator->last_segment_target_id;
             }
-            else if (way_start_and_end_iterator->lastTarget == via_node_id)
+            else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
             {
-                restrictions_iterator->restriction.fromNode = way_start_and_end_iterator->lastStart;
+                restrictions_iterator->restriction.from.node = way_start_and_end_iterator->last_segment_source_id;
             }
             ++restrictions_iterator;
         }
@@ -168,36 +176,36 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
         while (way_start_and_end_iterator != way_start_end_id_list.end() &&
                restrictions_iterator != restrictions_list.end())
         {
-            if (way_start_and_end_iterator->wayID < restrictions_iterator->toWay)
+            if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.to.way)
             {
                 ++way_start_and_end_iterator;
                 continue;
             }
-            if (way_start_and_end_iterator->wayID > restrictions_iterator->toWay)
+            if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.to.way)
             {
                 ++restrictions_iterator;
                 continue;
             }
-            NodeID via_node_id = restrictions_iterator->restriction.viaNode;
-            if (way_start_and_end_iterator->lastStart == via_node_id)
+            NodeID via_node_id = restrictions_iterator->restriction.via.node;
+            if (way_start_and_end_iterator->last_segment_source_id == via_node_id)
             {
-                restrictions_iterator->restriction.toNode = way_start_and_end_iterator->lastTarget;
+                restrictions_iterator->restriction.to.node = way_start_and_end_iterator->last_segment_target_id;
             }
-            else if (way_start_and_end_iterator->lastTarget == via_node_id)
+            else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
             {
-                restrictions_iterator->restriction.toNode = way_start_and_end_iterator->lastStart;
+                restrictions_iterator->restriction.to.node = way_start_and_end_iterator->last_segment_source_id;
             }
-            else if (way_start_and_end_iterator->firstStart == via_node_id)
+            else if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
             {
-                restrictions_iterator->restriction.toNode = way_start_and_end_iterator->firstTarget;
+                restrictions_iterator->restriction.to.node = way_start_and_end_iterator->first_segment_target_id;
             }
-            else if (way_start_and_end_iterator->firstTarget == via_node_id)
+            else if (way_start_and_end_iterator->first_segment_target_id == via_node_id)
             {
-                restrictions_iterator->restriction.toNode = way_start_and_end_iterator->firstStart;
+                restrictions_iterator->restriction.to.node = way_start_and_end_iterator->first_segment_source_id;
             }
 
-            if (std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.fromNode &&
-                std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.toNode)
+            if (std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.from.node &&
+                std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.to.node)
             {
                 ++number_of_useable_restrictions;
             }
@@ -215,8 +223,8 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
 
         for(const auto & restriction_container : restrictions_list)
         {
-            if (std::numeric_limits<unsigned>::max() != restriction_container.restriction.fromNode &&
-                std::numeric_limits<unsigned>::max() != restriction_container.restriction.toNode)
+            if (std::numeric_limits<unsigned>::max() != restriction_container.restriction.from.node &&
+                std::numeric_limits<unsigned>::max() != restriction_container.restriction.to.node)
             {
                 restrictions_out_stream.write((char *)&(restriction_container.restriction),
                                               sizeof(TurnRestriction));
@@ -330,7 +338,6 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
                 edge_iterator->source_coordinate.lon != std::numeric_limits<int>::min())
             {
                 BOOST_ASSERT(edge_iterator->speed != -1);
-                BOOST_ASSERT(edge_iterator->type >= 0);
                 edge_iterator->target_coordinate.lat = node_iterator->lat;
                 edge_iterator->target_coordinate.lon = node_iterator->lon;
 
@@ -367,16 +374,19 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
                     file_out_stream.write((char *)&one, sizeof(short));
                     break;
                 default:
-                    throw OSRMException("edge has broken direction");
+                    throw osrm::exception("edge has broken direction");
                 }
 
                 file_out_stream.write((char *)&integer_weight, sizeof(int));
-                file_out_stream.write((char *)&edge_iterator->type, sizeof(short));
                 file_out_stream.write((char *)&edge_iterator->name_id, sizeof(unsigned));
                 file_out_stream.write((char *)&edge_iterator->is_roundabout, sizeof(bool));
                 file_out_stream.write((char *)&edge_iterator->is_in_tiny_cc, sizeof(bool));
                 file_out_stream.write((char *)&edge_iterator->is_access_restricted, sizeof(bool));
-                file_out_stream.write((char *)&edge_iterator->is_contra_flow, sizeof(bool));
+
+                // cannot take adress of bit field, so use local
+                const TravelMode  travel_mode = edge_iterator->travel_mode;
+                file_out_stream.write((char *)&travel_mode, sizeof(TravelMode));
+
                 file_out_stream.write((char *)&edge_iterator->is_split, sizeof(bool));
                 ++number_of_used_edges;
             }
diff --git a/Extractor/ExtractionContainers.h b/extractor/extraction_containers.hpp
similarity index 72%
rename from Extractor/ExtractionContainers.h
rename to extractor/extraction_containers.hpp
index a272387..8a1df8c 100644
--- a/Extractor/ExtractionContainers.h
+++ b/extractor/extraction_containers.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,12 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef EXTRACTIONCONTAINERS_H_
-#define EXTRACTIONCONTAINERS_H_
+#ifndef EXTRACTION_CONTAINERS_HPP
+#define EXTRACTION_CONTAINERS_HPP
 
-#include "InternalExtractorEdge.h"
-#include "ExtractorStructs.h"
-#include "../DataStructures/Restriction.h"
+#include "internal_extractor_edge.hpp"
+#include "first_and_last_segment_of_way.hpp"
+#include "../data_structures/external_memory_node.hpp"
+#include "../data_structures/restriction.hpp"
 #include "../Util/FingerPrint.h"
 
 #include <stxxl/vector>
@@ -43,12 +44,12 @@ class ExtractionContainers
     const static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? INT_MAX : UINT_MAX);
 #endif
   public:
-    typedef stxxl::vector<NodeID> STXXLNodeIDVector;
-    typedef stxxl::vector<ExternalMemoryNode> STXXLNodeVector;
-    typedef stxxl::vector<InternalExtractorEdge> STXXLEdgeVector;
-    typedef stxxl::vector<std::string> STXXLStringVector;
-    typedef stxxl::vector<InputRestrictionContainer> STXXLRestrictionsVector;
-    typedef stxxl::vector<WayIDStartAndEndEdge> STXXLWayIDStartEndVector;
+    using  STXXLNodeIDVector = stxxl::vector<NodeID>;
+    using  STXXLNodeVector = stxxl::vector<ExternalMemoryNode>;
+    using  STXXLEdgeVector = stxxl::vector<InternalExtractorEdge>;
+    using  STXXLStringVector = stxxl::vector<std::string>;
+    using  STXXLRestrictionsVector = stxxl::vector<InputRestrictionContainer>;
+    using  STXXLWayIDStartEndVector = stxxl::vector<FirstAndLastSegmentOfWay>;
 
     STXXLNodeIDVector used_node_id_list;
     STXXLNodeVector all_nodes_list;
@@ -60,10 +61,10 @@ class ExtractionContainers
 
     ExtractionContainers();
 
-    virtual ~ExtractionContainers();
+    ~ExtractionContainers();
 
     void PrepareData(const std::string &output_file_name,
                      const std::string &restrictions_file_name);
 };
 
-#endif /* EXTRACTIONCONTAINERS_H_ */
+#endif /* EXTRACTION_CONTAINERS_HPP */
diff --git a/Extractor/ExtractionHelperFunctions.h b/extractor/extraction_helper_functions.hpp
similarity index 81%
rename from Extractor/ExtractionHelperFunctions.h
rename to extractor/extraction_helper_functions.hpp
index a918744..d2a73c9 100644
--- a/Extractor/ExtractionHelperFunctions.h
+++ b/extractor/extraction_helper_functions.hpp
@@ -25,13 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef EXTRACTION_HELPER_FUNCTIONS_H
-#define EXTRACTION_HELPER_FUNCTIONS_H
+#ifndef EXTRACTION_HELPER_FUNCTIONS_HPP
+#define EXTRACTION_HELPER_FUNCTIONS_HPP
 
-#include "../Util/StringUtil.h"
+#include "../Util/cast.hpp"
 
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string_regex.hpp>
+#include <boost/spirit/include/qi.hpp>
 #include <boost/regex.hpp>
 
 #include <limits>
@@ -40,7 +41,7 @@ namespace qi = boost::spirit::qi;
 
 // TODO: Move into LUA
 
-inline bool durationIsValid(const std::string &s)
+bool durationIsValid(const std::string &s)
 {
     boost::regex e(
         "((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",
@@ -52,7 +53,7 @@ inline bool durationIsValid(const std::string &s)
     return matched;
 }
 
-inline unsigned parseDuration(const std::string &s)
+unsigned parseDuration(const std::string &s)
 {
     unsigned hours = 0;
     unsigned minutes = 0;
@@ -68,22 +69,22 @@ inline unsigned parseDuration(const std::string &s)
     {
         if (1 == result.size())
         {
-            minutes = StringToUint(result[0]);
+            minutes = cast::string_to_int(result[0]);
         }
         if (2 == result.size())
         {
-            minutes = StringToUint(result[1]);
-            hours = StringToUint(result[0]);
+            minutes = cast::string_to_int(result[1]);
+            hours = cast::string_to_int(result[0]);
         }
         if (3 == result.size())
         {
-            seconds = StringToUint(result[2]);
-            minutes = StringToUint(result[1]);
-            hours = StringToUint(result[0]);
+            seconds = cast::string_to_int(result[2]);
+            minutes = cast::string_to_int(result[1]);
+            hours = cast::string_to_int(result[0]);
         }
         return 10 * (3600 * hours + 60 * minutes + seconds);
     }
     return std::numeric_limits<unsigned>::max();
 }
 
-#endif // EXTRACTION_HELPER_FUNCTIONS_H_
+#endif // EXTRACTION_HELPER_FUNCTIONS_HPP
diff --git a/Server/Http/CompressionType.h b/extractor/extraction_node.hpp
similarity index 78%
copy from Server/Http/CompressionType.h
copy to extractor/extraction_node.hpp
index 74d0b62..defd333 100644
--- a/Server/Http/CompressionType.h
+++ b/extractor/extraction_node.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,17 +25,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef COMPRESSION_TYPE_H
-#define COMPRESSION_TYPE_H
+#ifndef EXTRACTION_NODE_HPP
+#define EXTRACTION_NODE_HPP
 
-namespace http
+struct ExtractionNode
 {
-
-enum CompressionType
-{ noCompression,
-  gzipRFC1952,
-  deflateRFC1951 };
-
-} // namespace http
-
-#endif // COMPRESSION_TYPE_H
+    ExtractionNode() : traffic_lights(false), barrier(false) { }
+    void clear()
+    {
+        traffic_lights = barrier = false;
+    }
+    bool traffic_lights;
+    bool barrier;
+};
+#endif // EXTRACTION_NODE_HPP
diff --git a/extractor/extraction_way.hpp b/extractor/extraction_way.hpp
new file mode 100644
index 0000000..b414487
--- /dev/null
+++ b/extractor/extraction_way.hpp
@@ -0,0 +1,120 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef EXTRACTION_WAY_HPP
+#define EXTRACTION_WAY_HPP
+
+#include "../data_structures/travel_mode.hpp"
+#include "../typedefs.h"
+
+#include <string>
+#include <vector>
+
+struct ExtractionWay
+{
+    ExtractionWay() { clear(); }
+
+    void clear()
+    {
+        forward_speed = -1;
+        backward_speed = -1;
+        duration = -1;
+        roundabout = false;
+        is_access_restricted = false;
+        ignore_in_grid = false;
+        name.clear();
+        forward_travel_mode = TRAVEL_MODE_DEFAULT;
+        backward_travel_mode = TRAVEL_MODE_DEFAULT;
+    }
+
+    enum Directions
+    { notSure = 0,
+      oneway,
+      bidirectional,
+      opposite };
+
+    // These accessor methods exists to support the depreciated "way.direction" access
+    // in LUA. Since the direction attribute was removed from ExtractionWay, the
+    // accessors translate to/from the mode attributes.
+    void set_direction(const Directions m)
+    {
+        if (Directions::oneway == m)
+        {
+            forward_travel_mode = TRAVEL_MODE_DEFAULT;
+            backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
+        }
+        else if (Directions::opposite == m)
+        {
+          forward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
+          backward_travel_mode = TRAVEL_MODE_DEFAULT;
+        }
+        else if (Directions::bidirectional == m)
+        {
+          forward_travel_mode = TRAVEL_MODE_DEFAULT;
+          backward_travel_mode = TRAVEL_MODE_DEFAULT;
+        }
+    }
+
+    Directions get_direction() const
+    {
+        if (TRAVEL_MODE_INACCESSIBLE != forward_travel_mode && TRAVEL_MODE_INACCESSIBLE != backward_travel_mode)
+        {
+            return Directions::bidirectional;
+        }
+        else if (TRAVEL_MODE_INACCESSIBLE != forward_travel_mode)
+        {
+            return Directions::oneway;
+        }
+        else if (TRAVEL_MODE_INACCESSIBLE != backward_travel_mode)
+        {
+            return Directions::opposite;
+        }
+        else
+        {
+            return Directions::notSure;
+        }
+    }
+
+    // These accessors exists because it's not possible to take the address of a bitfield,
+    // and LUA therefore cannot read/write the mode attributes directly.
+    void set_forward_mode(const TravelMode m) { forward_travel_mode = m; }
+    TravelMode get_forward_mode() const { return forward_travel_mode; }
+    void set_backward_mode(const TravelMode m) { backward_travel_mode = m; }
+    TravelMode get_backward_mode() const { return backward_travel_mode; }
+
+    double forward_speed;
+    double backward_speed;
+    double duration;
+    std::string name;
+    bool roundabout;
+    bool is_access_restricted;
+    bool ignore_in_grid;
+    TravelMode forward_travel_mode : 4;
+    TravelMode backward_travel_mode : 4;
+};
+
+#endif // EXTRACTION_WAY_HPP
diff --git a/extractor/extractor.cpp b/extractor/extractor.cpp
new file mode 100644
index 0000000..880e9e4
--- /dev/null
+++ b/extractor/extractor.cpp
@@ -0,0 +1,268 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "extractor.hpp"
+
+#include "extraction_containers.hpp"
+#include "extraction_node.hpp"
+#include "extraction_way.hpp"
+#include "extractor_callbacks.hpp"
+#include "extractor_options.hpp"
+#include "restriction_parser.hpp"
+#include "scripting_environment.hpp"
+
+#include "../Util/git_sha.hpp"
+#include "../Util/IniFileUtil.h"
+#include "../Util/simple_logger.hpp"
+#include "../Util/timing_util.hpp"
+#include "../Util/make_unique.hpp"
+
+#include "../typedefs.h"
+
+#include <luabind/luabind.hpp>
+
+#include <osmium/io/any_input.hpp>
+
+#include <tbb/parallel_for.h>
+#include <tbb/task_scheduler_init.h>
+
+#include <variant/optional.hpp>
+
+#include <cstdlib>
+
+#include <algorithm>
+#include <atomic>
+#include <chrono>
+#include <fstream>
+#include <iostream>
+#include <thread>
+#include <unordered_map>
+#include <vector>
+
+int Extractor::Run(int argc, char *argv[])
+{
+    ExtractorConfig extractor_config;
+
+    try
+    {
+        LogPolicy::GetInstance().Unmute();
+        TIMER_START(extracting);
+
+        if (!ExtractorOptions::ParseArguments(argc, argv, extractor_config))
+        {
+            return 0;
+        }
+        ExtractorOptions::GenerateOutputFilesNames(extractor_config);
+
+        if (1 > extractor_config.requested_num_threads)
+        {
+            SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
+            return 1;
+        }
+
+        if (!boost::filesystem::is_regular_file(extractor_config.input_path))
+        {
+            SimpleLogger().Write(logWARNING)
+                << "Input file " << extractor_config.input_path.string() << " not found!";
+            return 1;
+        }
+
+        if (!boost::filesystem::is_regular_file(extractor_config.profile_path))
+        {
+            SimpleLogger().Write(logWARNING) << "Profile " << extractor_config.profile_path.string()
+                                             << " not found!";
+            return 1;
+        }
+
+        const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
+        const auto number_of_threads = std::min(recommended_num_threads, extractor_config.requested_num_threads);
+        tbb::task_scheduler_init init(number_of_threads);
+
+        SimpleLogger().Write() << "Input file: " << extractor_config.input_path.filename().string();
+        SimpleLogger().Write() << "Profile: " << extractor_config.profile_path.filename().string();
+        SimpleLogger().Write() << "Threads: " << number_of_threads;
+
+        // setup scripting environment
+        ScriptingEnvironment scripting_environment(extractor_config.profile_path.string().c_str());
+
+        std::unordered_map<std::string, NodeID> string_map;
+        string_map[""] = 0;
+
+        ExtractionContainers extraction_containers;
+        auto extractor_callbacks =
+            osrm::make_unique<ExtractorCallbacks>(extraction_containers, string_map);
+
+        const osmium::io::File input_file(extractor_config.input_path.string());
+        osmium::io::Reader reader(input_file);
+        const osmium::io::Header header = reader.header();
+
+        std::atomic<unsigned> number_of_nodes {0};
+        std::atomic<unsigned> number_of_ways {0};
+        std::atomic<unsigned> number_of_relations {0};
+        std::atomic<unsigned> number_of_others {0};
+
+        SimpleLogger().Write() << "Parsing in progress..";
+        TIMER_START(parsing);
+
+        std::string generator = header.get("generator");
+        if (generator.empty())
+        {
+            generator = "unknown tool";
+        }
+        SimpleLogger().Write() << "input file generated by " << generator;
+
+        // write .timestamp data file
+        std::string timestamp = header.get("osmosis_replication_timestamp");
+        if (timestamp.empty())
+        {
+            timestamp = "n/a";
+        }
+        SimpleLogger().Write() << "timestamp: " << timestamp;
+
+        boost::filesystem::ofstream timestamp_out(extractor_config.timestamp_file_name);
+        timestamp_out.write(timestamp.c_str(), timestamp.length());
+        timestamp_out.close();
+
+        // initialize vectors holding parsed objects
+        tbb::concurrent_vector<std::pair<std::size_t, ExtractionNode>> resulting_nodes;
+        tbb::concurrent_vector<std::pair<std::size_t, ExtractionWay>> resulting_ways;
+        tbb::concurrent_vector<mapbox::util::optional<InputRestrictionContainer>>
+            resulting_restrictions;
+
+        // setup restriction parser
+        const RestrictionParser restriction_parser(scripting_environment.get_lua_state());
+
+        while (const osmium::memory::Buffer buffer = reader.read())
+        {
+            // create a vector of iterators into the buffer
+            std::vector<osmium::memory::Buffer::const_iterator> osm_elements;
+            for (auto iter = std::begin(buffer); iter != std::end(buffer); ++iter) {
+                osm_elements.push_back(iter);
+            }
+
+            // clear resulting vectors
+            resulting_nodes.clear();
+            resulting_ways.clear();
+            resulting_restrictions.clear();
+
+            // parse OSM entities in parallel, store in resulting vectors
+            tbb::parallel_for(tbb::blocked_range<std::size_t>(0, osm_elements.size()),
+                              [&](const tbb::blocked_range<std::size_t> &range)
+                              {
+                for (auto x = range.begin(); x != range.end(); ++x)
+                {
+                    const auto entity = osm_elements[x];
+
+                    ExtractionNode result_node;
+                    ExtractionWay result_way;
+
+                    lua_State * local_state = scripting_environment.get_lua_state();
+
+                    switch (entity->type())
+                    {
+                    case osmium::item_type::node:
+                        ++number_of_nodes;
+                        luabind::call_function<void>(
+                            local_state,
+                            "node_function",
+                            boost::cref(static_cast<const osmium::Node &>(*entity)),
+                            boost::ref(result_node));
+                        resulting_nodes.push_back(std::make_pair(x, result_node));
+                        break;
+                    case osmium::item_type::way:
+                        ++number_of_ways;
+                        luabind::call_function<void>(
+                            local_state,
+                            "way_function",
+                            boost::cref(static_cast<const osmium::Way &>(*entity)),
+                            boost::ref(result_way));
+                        resulting_ways.push_back(std::make_pair(x, result_way));
+                        break;
+                    case osmium::item_type::relation:
+                        ++number_of_relations;
+                        resulting_restrictions.push_back(
+                            restriction_parser.TryParse(static_cast<const osmium::Relation &>(*entity)));
+                        break;
+                    default:
+                        ++number_of_others;
+                        break;
+                    }
+                }
+            });
+
+            // put parsed objects thru extractor callbacks
+            for (const auto &result : resulting_nodes)
+            {
+                extractor_callbacks->ProcessNode(
+                    static_cast<const osmium::Node &>(*(osm_elements[result.first])), result.second);
+            }
+            for (const auto &result : resulting_ways)
+            {
+                extractor_callbacks->ProcessWay(
+                    static_cast<const osmium::Way &>(*(osm_elements[result.first])), result.second);
+            }
+            for (const auto &result : resulting_restrictions)
+            {
+                extractor_callbacks->ProcessRestriction(result);
+            }
+        }
+        TIMER_STOP(parsing);
+        SimpleLogger().Write() << "Parsing finished after " << TIMER_SEC(parsing) << " seconds";
+
+        unsigned nn = number_of_nodes;
+        unsigned nw = number_of_ways;
+        unsigned nr = number_of_relations;
+        unsigned no = number_of_others;
+        SimpleLogger().Write() << "Raw input contains "
+                               << nn << " nodes, "
+                               << nw << " ways, and "
+                               << nr << " relations, and "
+                               << no << " unknown entities";
+
+        extractor_callbacks.reset();
+
+        if (extraction_containers.all_edges_list.empty())
+        {
+            SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
+            return 1;
+        }
+
+        extraction_containers.PrepareData(extractor_config.output_file_name,
+                                          extractor_config.restriction_file_name);
+        TIMER_STOP(extracting);
+        SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting) << "s";
+        SimpleLogger().Write() << "To prepare the data for routing, run: "
+                               << "./osrm-prepare " << extractor_config.output_file_name
+                               << std::endl;
+    }
+    catch (std::exception &e)
+    {
+        SimpleLogger().Write(logWARNING) << e.what();
+        return 1;
+    }
+    return 0;
+}
diff --git a/extractor/extractor.hpp b/extractor/extractor.hpp
new file mode 100644
index 0000000..e9edbea
--- /dev/null
+++ b/extractor/extractor.hpp
@@ -0,0 +1,13 @@
+#ifndef EXTRACTOR_HPP
+#define EXTRACTOR_HPP
+
+#include <string>
+
+#include <boost/filesystem.hpp>
+
+/** \brief Class of 'extract' utility. */
+struct Extractor
+{
+    int Run(int argc, char *argv[]);
+};
+#endif /* EXTRACTOR_HPP */
diff --git a/extractor/extractor_callbacks.cpp b/extractor/extractor_callbacks.cpp
new file mode 100644
index 0000000..87e4f4f
--- /dev/null
+++ b/extractor/extractor_callbacks.cpp
@@ -0,0 +1,223 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "extractor_callbacks.hpp"
+#include "extraction_containers.hpp"
+#include "extraction_node.hpp"
+#include "extraction_way.hpp"
+
+#include "../data_structures/external_memory_node.hpp"
+#include "../data_structures/restriction.hpp"
+#include "../Util/container.hpp"
+#include "../Util/simple_logger.hpp"
+
+#include <osrm/Coordinate.h>
+
+#include <limits>
+#include <string>
+#include <vector>
+
+ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containers,
+                                       std::unordered_map<std::string, NodeID> &string_map)
+    : string_map(string_map), external_memory(extraction_containers)
+{
+}
+
+/** warning: caller needs to take care of synchronization! */
+void ExtractorCallbacks::ProcessNode(const osmium::Node &input_node,
+                                     const ExtractionNode &result_node)
+{
+    external_memory.all_nodes_list.push_back({
+        static_cast<int>(input_node.location().lat() * COORDINATE_PRECISION),
+        static_cast<int>(input_node.location().lon() * COORDINATE_PRECISION),
+        static_cast<NodeID>(input_node.id()),
+        result_node.barrier,
+        result_node.traffic_lights
+    });
+}
+
+void ExtractorCallbacks::ProcessRestriction(
+    const mapbox::util::optional<InputRestrictionContainer> &restriction)
+{
+    if (restriction)
+    {
+        external_memory.restrictions_list.push_back(restriction.get());
+        // SimpleLogger().Write() << "from: " << restriction.get().restriction.from.node <<
+        //                           ",via: " << restriction.get().restriction.via.node <<
+        //                           ", to: " << restriction.get().restriction.to.node <<
+        //                           ", only: " << (restriction.get().restriction.flags.is_only ? "y" : "n");
+    }
+}
+/** warning: caller needs to take care of synchronization! */
+void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const ExtractionWay &parsed_way)
+{
+    if (((0 >= parsed_way.forward_speed) ||
+         (TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode)) &&
+        ((0 >= parsed_way.backward_speed) ||
+         (TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode)) &&
+        (0 >= parsed_way.duration))
+    { // Only true if the way is specified by the speed profile
+        return;
+    }
+
+    if (input_way.nodes().size() <= 1)
+    { // safe-guard against broken data
+        return;
+    }
+
+    if (std::numeric_limits<decltype(input_way.id())>::max() == input_way.id())
+    {
+        SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << input_way.id()
+                                       << " of size " << input_way.nodes().size();
+        return;
+    }
+    if (0 < parsed_way.duration)
+    {
+        // TODO: iterate all way segments and set duration corresponding to the length of each
+        // segment
+        const_cast<ExtractionWay&>(parsed_way).forward_speed = parsed_way.duration / (input_way.nodes().size() - 1);
+        const_cast<ExtractionWay&>(parsed_way).backward_speed = parsed_way.duration / (input_way.nodes().size() - 1);
+    }
+
+    if (std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.forward_speed))
+    {
+        SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << input_way.id();
+        return;
+    }
+
+    // Get the unique identifier for the street name
+    const auto &string_map_iterator = string_map.find(parsed_way.name);
+    unsigned name_id = external_memory.name_list.size();
+    if (string_map.end() == string_map_iterator)
+    {
+        external_memory.name_list.push_back(parsed_way.name);
+        string_map.insert(std::make_pair(parsed_way.name, name_id));
+    }
+    else
+    {
+        name_id = string_map_iterator->second;
+    }
+
+    const bool split_edge = (parsed_way.forward_speed > 0) &&
+                            (TRAVEL_MODE_INACCESSIBLE != parsed_way.forward_travel_mode) &&
+                            (parsed_way.backward_speed > 0) &&
+                            (TRAVEL_MODE_INACCESSIBLE != parsed_way.backward_travel_mode) &&
+                            ((parsed_way.forward_speed != parsed_way.backward_speed) ||
+                             (parsed_way.forward_travel_mode != parsed_way.backward_travel_mode));
+
+    auto pair_wise_segment_split = [&](const osmium::NodeRef &first_node,
+                                       const osmium::NodeRef &last_node)
+    {
+        // SimpleLogger().Write() << "adding edge (" << first_node.ref() << "," <<
+        // last_node.ref() << "), fwd speed: " << parsed_way.forward_speed;
+        external_memory.all_edges_list.push_back(InternalExtractorEdge(
+            first_node.ref(),
+            last_node.ref(),
+            ((split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode)
+                 ? ExtractionWay::oneway
+                 : ExtractionWay::bidirectional),
+            parsed_way.forward_speed,
+            name_id,
+            parsed_way.roundabout,
+            parsed_way.ignore_in_grid,
+            (0 < parsed_way.duration),
+            parsed_way.is_access_restricted,
+            parsed_way.forward_travel_mode,
+            split_edge));
+        external_memory.used_node_id_list.push_back(first_node.ref());
+    };
+
+    const bool is_opposite_way = TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode;
+    if (is_opposite_way)
+    {
+        const_cast<ExtractionWay&>(parsed_way).forward_travel_mode = parsed_way.backward_travel_mode;
+        const_cast<ExtractionWay&>(parsed_way).backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
+        osrm::for_each_pair(
+            input_way.nodes().crbegin(), input_way.nodes().crend(), pair_wise_segment_split);
+        external_memory.used_node_id_list.push_back(input_way.nodes().front().ref());
+    }
+    else
+    {
+        osrm::for_each_pair(
+            input_way.nodes().cbegin(), input_way.nodes().cend(), pair_wise_segment_split);
+        external_memory.used_node_id_list.push_back(input_way.nodes().back().ref());
+    }
+
+    // The following information is needed to identify start and end segments of restrictions
+    external_memory.way_start_end_id_list.push_back(
+        {(EdgeID)input_way.id(),
+         (NodeID)input_way.nodes()[0].ref(),
+         (NodeID)input_way.nodes()[1].ref(),
+         (NodeID)input_way.nodes()[input_way.nodes().size() - 2].ref(),
+         (NodeID)input_way.nodes().back().ref()});
+
+    if (split_edge)
+    { // Only true if the way should be split
+        BOOST_ASSERT(parsed_way.backward_travel_mode>0);
+        auto pair_wise_segment_split_2 = [&](const osmium::NodeRef &first_node,
+                                             const osmium::NodeRef &last_node)
+        {
+            // SimpleLogger().Write() << "adding edge (" << last_node.ref() << "," <<
+            // first_node.ref() << "), bwd speed: " << parsed_way.backward_speed;
+            external_memory.all_edges_list.push_back(
+                InternalExtractorEdge(last_node.ref(),
+                                      first_node.ref(),
+                                      ExtractionWay::oneway,
+                                      parsed_way.backward_speed,
+                                      name_id,
+                                      parsed_way.roundabout,
+                                      parsed_way.ignore_in_grid,
+                                      (0 < parsed_way.duration),
+                                      parsed_way.is_access_restricted,
+                                      parsed_way.backward_travel_mode,
+                                      split_edge));
+        };
+
+        if (is_opposite_way)
+        {
+            // SimpleLogger().Write() << "opposite2";
+            osrm::for_each_pair(input_way.nodes().crbegin(),
+                          input_way.nodes().crend(),
+                          pair_wise_segment_split_2);
+            external_memory.used_node_id_list.push_back(input_way.nodes().front().ref());
+        }
+        else
+        {
+            osrm::for_each_pair(input_way.nodes().cbegin(),
+                          input_way.nodes().cend(),
+                          pair_wise_segment_split_2);
+            external_memory.used_node_id_list.push_back(input_way.nodes().back().ref());
+        }
+
+        external_memory.way_start_end_id_list.push_back(
+            {(EdgeID)input_way.id(),
+             (NodeID)input_way.nodes()[1].ref(),
+             (NodeID)input_way.nodes()[0].ref(),
+             (NodeID)input_way.nodes().back().ref(),
+             (NodeID)input_way.nodes()[input_way.nodes().size() - 2].ref()});
+    }
+}
diff --git a/Extractor/ExtractorCallbacks.h b/extractor/extractor_callbacks.hpp
similarity index 78%
rename from Extractor/ExtractorCallbacks.h
rename to extractor/extractor_callbacks.hpp
index fcdb272..0bb3010 100644
--- a/Extractor/ExtractorCallbacks.h
+++ b/extractor/extractor_callbacks.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,18 +25,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef EXTRACTOR_CALLBACKS_H
-#define EXTRACTOR_CALLBACKS_H
+#ifndef EXTRACTOR_CALLBACKS_HPP
+#define EXTRACTOR_CALLBACKS_HPP
 
+#include "extraction_way.hpp"
 #include "../typedefs.h"
 
-#include <unordered_map>
+#include <osmium/osm.hpp>
+
+#include <variant/optional.hpp>
+
 #include <string>
+#include <unordered_map>
 
 struct ExternalMemoryNode;
 class ExtractionContainers;
-struct ExtractionWay;
 struct InputRestrictionContainer;
+struct ExtractionNode;
 
 class ExtractorCallbacks
 {
@@ -51,13 +56,13 @@ class ExtractorCallbacks
                                 std::unordered_map<std::string, NodeID> &string_map);
 
     // warning: caller needs to take care of synchronization!
-    void ProcessNode(const ExternalMemoryNode &node);
+    void ProcessNode(const osmium::Node &current_node, const ExtractionNode &result_node);
 
     // warning: caller needs to take care of synchronization!
-    bool ProcessRestriction(const InputRestrictionContainer &restriction);
+    void ProcessRestriction(const mapbox::util::optional<InputRestrictionContainer> &restriction);
 
     // warning: caller needs to take care of synchronization!
-    void ProcessWay(ExtractionWay &way);
+    void ProcessWay(const osmium::Way &current_way, const ExtractionWay &result_way);
 };
 
-#endif /* EXTRACTOR_CALLBACKS_H */
+#endif /* EXTRACTOR_CALLBACKS_HPP */
diff --git a/extractor/extractor_options.cpp b/extractor/extractor_options.cpp
new file mode 100644
index 0000000..d14d8d9
--- /dev/null
+++ b/extractor/extractor_options.cpp
@@ -0,0 +1,167 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "extractor_options.hpp"
+
+#include "../Util/git_sha.hpp"
+#include "../Util/IniFileUtil.h"
+#include "../Util/simple_logger.hpp"
+
+#include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
+
+#include <tbb/task_scheduler_init.h>
+
+bool ExtractorOptions::ParseArguments(int argc, char *argv[], ExtractorConfig &extractor_config)
+{
+    // declare a group of options that will be allowed only on command line
+    boost::program_options::options_description generic_options("Options");
+    generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
+        "config,c",
+        boost::program_options::value<boost::filesystem::path>(&extractor_config.config_file_path)
+            ->default_value("extractor.ini"),
+        "Path to a configuration file.");
+
+    // declare a group of options that will be allowed both on command line and in config file
+    boost::program_options::options_description config_options("Configuration");
+    config_options.add_options()("profile,p",
+                                 boost::program_options::value<boost::filesystem::path>(
+                                     &extractor_config.profile_path)->default_value("profile.lua"),
+                                 "Path to LUA routing profile")(
+        "threads,t",
+        boost::program_options::value<unsigned int>(&extractor_config.requested_num_threads)
+            ->default_value(tbb::task_scheduler_init::default_num_threads()),
+        "Number of threads to use");
+
+    // hidden options, will be allowed both on command line and in config file, but will not be
+    // shown to the user
+    boost::program_options::options_description hidden_options("Hidden options");
+    hidden_options.add_options()(
+        "input,i",
+        boost::program_options::value<boost::filesystem::path>(&extractor_config.input_path),
+        "Input file in .osm, .osm.bz2 or .osm.pbf format");
+
+    // positional option
+    boost::program_options::positional_options_description positional_options;
+    positional_options.add("input", 1);
+
+    // combine above options for parsing
+    boost::program_options::options_description cmdline_options;
+    cmdline_options.add(generic_options).add(config_options).add(hidden_options);
+
+    boost::program_options::options_description config_file_options;
+    config_file_options.add(config_options).add(hidden_options);
+
+    boost::program_options::options_description visible_options(
+        boost::filesystem::basename(argv[0]) + " <input.osm/.osm.bz2/.osm.pbf> [options]");
+    visible_options.add(generic_options).add(config_options);
+
+    // parse command line options
+    boost::program_options::variables_map option_variables;
+    boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
+                                      .options(cmdline_options)
+                                      .positional(positional_options)
+                                      .run(),
+                                  option_variables);
+
+    if (option_variables.count("version"))
+    {
+        SimpleLogger().Write() << g_GIT_DESCRIPTION;
+        return false;
+    }
+
+    if (option_variables.count("help"))
+    {
+        SimpleLogger().Write() << visible_options;
+        return false;
+    }
+
+    boost::program_options::notify(option_variables);
+
+    // parse config file
+    if (boost::filesystem::is_regular_file(extractor_config.config_file_path))
+    {
+        SimpleLogger().Write() << "Reading options from: "
+                               << extractor_config.config_file_path.string();
+        std::string ini_file_contents =
+            ReadIniFileAndLowerContents(extractor_config.config_file_path);
+        std::stringstream config_stream(ini_file_contents);
+        boost::program_options::store(parse_config_file(config_stream, config_file_options),
+                                      option_variables);
+        boost::program_options::notify(option_variables);
+    }
+
+    if (!option_variables.count("input"))
+    {
+        SimpleLogger().Write() << visible_options;
+        return false;
+    }
+    return true;
+}
+
+void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_config)
+{
+    boost::filesystem::path &input_path = extractor_config.input_path;
+    extractor_config.output_file_name = input_path.string();
+    extractor_config.restriction_file_name = input_path.string();
+    extractor_config.timestamp_file_name = input_path.string();
+    std::string::size_type pos = extractor_config.output_file_name.find(".osm.bz2");
+    if (pos == std::string::npos)
+    {
+        pos = extractor_config.output_file_name.find(".osm.pbf");
+        if (pos == std::string::npos)
+        {
+            pos = extractor_config.output_file_name.find(".osm.xml");
+        }
+    }
+    if (pos == std::string::npos)
+    {
+        pos = extractor_config.output_file_name.find(".pbf");
+    }
+    if (pos == std::string::npos)
+    {
+        pos = extractor_config.output_file_name.find(".osm");
+        if (pos == std::string::npos)
+        {
+            extractor_config.output_file_name.append(".osrm");
+            extractor_config.restriction_file_name.append(".osrm.restrictions");
+            extractor_config.timestamp_file_name.append(".osrm.timestamp");
+        }
+        else
+        {
+            extractor_config.output_file_name.replace(pos, 5, ".osrm");
+            extractor_config.restriction_file_name.replace(pos, 5, ".osrm.restrictions");
+            extractor_config.timestamp_file_name.replace(pos, 5, ".osrm.timestamp");
+        }
+    }
+    else
+    {
+        extractor_config.output_file_name.replace(pos, 8, ".osrm");
+        extractor_config.restriction_file_name.replace(pos, 8, ".osrm.restrictions");
+        extractor_config.timestamp_file_name.replace(pos, 8, ".osrm.timestamp");
+    }
+}
diff --git a/DataStructures/ImportNode.h b/extractor/extractor_options.hpp
similarity index 63%
rename from DataStructures/ImportNode.h
rename to extractor/extractor_options.hpp
index b8a9451..118da78 100644
--- a/DataStructures/ImportNode.h
+++ b/extractor/extractor_options.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,33 +25,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef IMPORTNODE_H_
-#define IMPORTNODE_H_
+#ifndef EXTRACTOR_OPTIONS_HPP
+#define EXTRACTOR_OPTIONS_HPP
 
-#include "QueryNode.h"
-#include "../DataStructures/HashTable.h"
+#include "extractor.hpp"
 
-#include <string>
-
-struct ExternalMemoryNode : NodeInfo
+struct ExtractorConfig
 {
-    ExternalMemoryNode(int lat, int lon, unsigned int id, bool bollard, bool traffic_light);
-
-    ExternalMemoryNode();
-
-    static ExternalMemoryNode min_value();
-
-    static ExternalMemoryNode max_value();
-
-    bool bollard;
-    bool trafficLight;
+    ExtractorConfig() noexcept : requested_num_threads(0) {}
+    unsigned requested_num_threads;
+    boost::filesystem::path config_file_path;
+    boost::filesystem::path input_path;
+    boost::filesystem::path profile_path;
+
+    std::string output_file_name;
+    std::string restriction_file_name;
+    std::string timestamp_file_name;
 };
 
-struct ImportNode : public ExternalMemoryNode
+struct ExtractorOptions
 {
-    HashTable<std::string, std::string> keyVals;
+    static bool ParseArguments(int argc, char *argv[], ExtractorConfig &extractor_config);
 
-    inline void Clear();
+    static void GenerateOutputFilesNames(ExtractorConfig &extractor_config);
 };
 
-#endif /* IMPORTNODE_H_ */
+#endif // EXTRACTOR_OPTIONS_HPP
diff --git a/extractor/first_and_last_segment_of_way.hpp b/extractor/first_and_last_segment_of_way.hpp
new file mode 100644
index 0000000..8e8ad72
--- /dev/null
+++ b/extractor/first_and_last_segment_of_way.hpp
@@ -0,0 +1,88 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
+#define FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
+
+#include "../data_structures/external_memory_node.hpp"
+#include "../typedefs.h"
+
+#include <limits>
+#include <string>
+
+struct FirstAndLastSegmentOfWay
+{
+    EdgeID way_id;
+    NodeID first_segment_source_id;
+    NodeID first_segment_target_id;
+    NodeID last_segment_source_id;
+    NodeID last_segment_target_id;
+    FirstAndLastSegmentOfWay()
+        : way_id(std::numeric_limits<EdgeID>::max()),
+          first_segment_source_id(std::numeric_limits<NodeID>::max()),
+          first_segment_target_id(std::numeric_limits<NodeID>::max()),
+          last_segment_source_id(std::numeric_limits<NodeID>::max()),
+          last_segment_target_id(std::numeric_limits<NodeID>::max())
+    {
+    }
+
+    FirstAndLastSegmentOfWay(EdgeID w, NodeID fs, NodeID ft, NodeID ls, NodeID lt)
+        : way_id(w), first_segment_source_id(fs), first_segment_target_id(ft),
+          last_segment_source_id(ls), last_segment_target_id(lt)
+    {
+    }
+
+    static FirstAndLastSegmentOfWay min_value()
+    {
+        return {std::numeric_limits<EdgeID>::min(),
+                std::numeric_limits<NodeID>::min(),
+                std::numeric_limits<NodeID>::min(),
+                std::numeric_limits<NodeID>::min(),
+                std::numeric_limits<NodeID>::min()};
+    }
+    static FirstAndLastSegmentOfWay max_value()
+    {
+        return {std::numeric_limits<EdgeID>::max(),
+                std::numeric_limits<NodeID>::max(),
+                std::numeric_limits<NodeID>::max(),
+                std::numeric_limits<NodeID>::max(),
+                std::numeric_limits<NodeID>::max()};
+    }
+};
+
+struct FirstAndLastSegmentOfWayStxxlCompare
+{
+    using value_type = FirstAndLastSegmentOfWay;
+    bool operator()(const FirstAndLastSegmentOfWay &a, const FirstAndLastSegmentOfWay &b) const
+    {
+        return a.way_id < b.way_id;
+    }
+    value_type max_value() { return FirstAndLastSegmentOfWay::max_value(); }
+    value_type min_value() { return FirstAndLastSegmentOfWay::min_value(); }
+};
+
+#endif /* FIRST_AND_LAST_SEGMENT_OF_WAY_HPP */
diff --git a/Extractor/InternalExtractorEdge.h b/extractor/internal_extractor_edge.hpp
similarity index 78%
rename from Extractor/InternalExtractorEdge.h
rename to extractor/internal_extractor_edge.hpp
index 02903e8..ffd2d4a 100644
--- a/Extractor/InternalExtractorEdge.h
+++ b/extractor/internal_extractor_edge.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,10 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef INTERNAL_EXTRACTOR_EDGE_H
-#define INTERNAL_EXTRACTOR_EDGE_H
+#ifndef INTERNAL_EXTRACTOR_EDGE_HPP
+#define INTERNAL_EXTRACTOR_EDGE_HPP
 
 #include "../typedefs.h"
+#include "../data_structures/travel_mode.hpp"
 #include <osrm/Coordinate.h>
 
 #include <boost/assert.hpp>
@@ -36,15 +37,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 struct InternalExtractorEdge
 {
     InternalExtractorEdge()
-        : start(0), target(0), type(0), direction(0), speed(0), name_id(0), is_roundabout(false),
+        : start(0), target(0), direction(0), speed(0), name_id(0), is_roundabout(false),
           is_in_tiny_cc(false), is_duration_set(false), is_access_restricted(false),
-          is_contra_flow(false), is_split(false)
+          travel_mode(TRAVEL_MODE_INACCESSIBLE), is_split(false)
     {
     }
 
     explicit InternalExtractorEdge(NodeID start,
                                    NodeID target,
-                                   short type,
                                    short direction,
                                    double speed,
                                    unsigned name_id,
@@ -52,30 +52,28 @@ struct InternalExtractorEdge
                                    bool is_in_tiny_cc,
                                    bool is_duration_set,
                                    bool is_access_restricted,
-                                   bool is_contra_flow,
+                                   TravelMode travel_mode,
                                    bool is_split)
-        : start(start), target(target), type(type), direction(direction), speed(speed),
+        : start(start), target(target), direction(direction), speed(speed),
           name_id(name_id), is_roundabout(is_roundabout), is_in_tiny_cc(is_in_tiny_cc),
           is_duration_set(is_duration_set), is_access_restricted(is_access_restricted),
-          is_contra_flow(is_contra_flow), is_split(is_split)
+          travel_mode(travel_mode), is_split(is_split)
     {
-        BOOST_ASSERT(0 <= type);
     }
 
     // necessary static util functions for stxxl's sorting
     static InternalExtractorEdge min_value()
     {
-        return InternalExtractorEdge(0, 0, 0, 0, 0, 0, false, false, false, false, false, false);
+        return InternalExtractorEdge(0, 0, 0, 0, 0, false, false, false, false, TRAVEL_MODE_INACCESSIBLE, false);
     }
     static InternalExtractorEdge max_value()
     {
         return InternalExtractorEdge(
-            SPECIAL_NODEID, SPECIAL_NODEID, 0, 0, 0, 0, false, false, false, false, false, false);
+            SPECIAL_NODEID, SPECIAL_NODEID, 0, 0, 0, false, false, false, false, TRAVEL_MODE_INACCESSIBLE, false);
     }
 
     NodeID start;
     NodeID target;
-    short type;
     short direction;
     double speed;
     unsigned name_id;
@@ -83,7 +81,7 @@ struct InternalExtractorEdge
     bool is_in_tiny_cc;
     bool is_duration_set;
     bool is_access_restricted;
-    bool is_contra_flow;
+    TravelMode travel_mode : 4;
     bool is_split;
 
     FixedPointCoordinate source_coordinate;
@@ -92,7 +90,7 @@ struct InternalExtractorEdge
 
 struct CmpEdgeByStartID
 {
-    typedef InternalExtractorEdge value_type;
+    using value_type = InternalExtractorEdge;
     bool operator()(const InternalExtractorEdge &a, const InternalExtractorEdge &b) const
     {
         return a.start < b.start;
@@ -105,7 +103,7 @@ struct CmpEdgeByStartID
 
 struct CmpEdgeByTargetID
 {
-    typedef InternalExtractorEdge value_type;
+    using value_type = InternalExtractorEdge;
 
     bool operator()(const InternalExtractorEdge &a, const InternalExtractorEdge &b) const
     {
@@ -117,4 +115,4 @@ struct CmpEdgeByTargetID
     value_type min_value() { return InternalExtractorEdge::min_value(); }
 };
 
-#endif // INTERNAL_EXTRACTOR_EDGE_H
+#endif // INTERNAL_EXTRACTOR_EDGE_HPP
diff --git a/extractor/restriction_parser.cpp b/extractor/restriction_parser.cpp
new file mode 100644
index 0000000..2f53d33
--- /dev/null
+++ b/extractor/restriction_parser.cpp
@@ -0,0 +1,241 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "restriction_parser.hpp"
+#include "extraction_way.hpp"
+#include "scripting_environment.hpp"
+
+#include "../data_structures/external_memory_node.hpp"
+#include "../Util/lua_util.hpp"
+#include "../Util/osrm_exception.hpp"
+#include "../Util/simple_logger.hpp"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/regex.hpp>
+#include <boost/ref.hpp>
+#include <boost/regex.hpp>
+
+namespace
+{
+int lua_error_callback(lua_State *lua_state)
+{
+    luabind::object error_msg(luabind::from_stack(lua_state, -1));
+    std::ostringstream error_stream;
+    error_stream << error_msg;
+    throw osrm::exception("ERROR occured in profile script:\n" + error_stream.str());
+}
+}
+
+RestrictionParser::RestrictionParser(lua_State *lua_state)
+    : /*lua_state(scripting_environment.getLuaState()),*/ use_turn_restrictions(true)
+{
+    ReadUseRestrictionsSetting(lua_state);
+
+    if (use_turn_restrictions)
+    {
+        ReadRestrictionExceptions(lua_state);
+    }
+}
+
+void RestrictionParser::ReadUseRestrictionsSetting(lua_State *lua_state)
+{
+    if (0 == luaL_dostring(lua_state, "return use_turn_restrictions\n") &&
+        lua_isboolean(lua_state, -1))
+    {
+        use_turn_restrictions = lua_toboolean(lua_state, -1);
+    }
+
+    if (use_turn_restrictions)
+    {
+        SimpleLogger().Write() << "Using turn restrictions";
+    }
+    else
+    {
+        SimpleLogger().Write() << "Ignoring turn restrictions";
+    }
+}
+
+void RestrictionParser::ReadRestrictionExceptions(lua_State *lua_state)
+{
+    if (lua_function_exists(lua_state, "get_exceptions"))
+    {
+        luabind::set_pcall_callback(&lua_error_callback);
+        // get list of turn restriction exceptions
+        luabind::call_function<void>(
+            lua_state, "get_exceptions", boost::ref(restriction_exceptions));
+        const unsigned exception_count = restriction_exceptions.size();
+        SimpleLogger().Write() << "Found " << exception_count
+                               << " exceptions to turn restrictions:";
+        for (const std::string &str : restriction_exceptions)
+        {
+            SimpleLogger().Write() << "  " << str;
+        }
+    }
+    else
+    {
+        SimpleLogger().Write() << "Found no exceptions to turn restrictions";
+    }
+}
+
+mapbox::util::optional<InputRestrictionContainer>
+RestrictionParser::TryParse(const osmium::Relation &relation) const
+{
+    // return if turn restrictions should be ignored
+    if (!use_turn_restrictions)
+    {
+        return mapbox::util::optional<InputRestrictionContainer>();
+    }
+
+    osmium::tags::KeyPrefixFilter filter(false);
+    filter.add(true, "restriction");
+
+    const osmium::TagList &tag_list = relation.tags();
+
+    osmium::tags::KeyPrefixFilter::iterator fi_begin(filter, tag_list.begin(), tag_list.end());
+    osmium::tags::KeyPrefixFilter::iterator fi_end(filter, tag_list.end(), tag_list.end());
+
+    // if it's a restriction, continue;
+    if (std::distance(fi_begin, fi_end) == 0)
+    {
+        return mapbox::util::optional<InputRestrictionContainer>();
+    }
+
+    // check if the restriction should be ignored
+    const char *except = relation.get_value_by_key("except");
+    if (except != nullptr && ShouldIgnoreRestriction(except))
+    {
+        return mapbox::util::optional<InputRestrictionContainer>();
+    }
+
+    bool is_only_restriction = false;
+
+    for (auto iter = fi_begin; iter != fi_end; ++iter)
+    {
+        if (std::string("restriction") == iter->key() ||
+            std::string("restriction::hgv") == iter->key())
+        {
+            const std::string restriction_value(iter->value());
+
+            if (restriction_value.find("only_") == 0)
+            {
+                is_only_restriction = true;
+            }
+        }
+    }
+
+    InputRestrictionContainer restriction_container(is_only_restriction);
+
+    for (const auto &member : relation.members())
+    {
+        const char *role = member.role();
+        if (strcmp("from", role) != 0 && strcmp("to", role) != 0 && strcmp("via", role) != 0)
+        {
+            continue;
+        }
+
+        switch (member.type())
+        {
+        case osmium::item_type::node:
+            // Make sure nodes appear only in the role if a via node
+            if (0 == strcmp("from", role) || 0 == strcmp("to", role))
+            {
+                continue;
+            }
+            BOOST_ASSERT(0 == strcmp("via", role));
+            // set the via node id
+            // SimpleLogger().Write() << "via: " << member.ref();
+
+            restriction_container.restriction.via.node = member.ref();
+            break;
+
+        case osmium::item_type::way:
+            BOOST_ASSERT(0 == strcmp("from", role) || 0 == strcmp("to", role) ||
+                         0 == strcmp("via", role));
+            if (0 == strcmp("from", role))
+            {
+                // SimpleLogger().Write() << "from: " << member.ref();
+                restriction_container.restriction.from.way = member.ref();
+            }
+            else if (0 == strcmp("to", role))
+            {
+                // SimpleLogger().Write() << "to: " << member.ref();
+                restriction_container.restriction.to.way = member.ref();
+            }
+            else if (0 == strcmp("via", role))
+            {
+                // not yet suppported
+                // restriction_container.restriction.via.way = member.ref();
+            }
+            break;
+        case osmium::item_type::relation:
+            // not yet supported, but who knows what the future holds...
+            continue;
+            break;
+        default:
+            BOOST_ASSERT(false);
+            break;
+        }
+    }
+
+    // SimpleLogger().Write() << (restriction_container.restriction.flags.is_only ? "only" : "no")
+    //                        << "-restriction "
+    //                        << "<" << restriction_container.restriction.from.node << "->"
+    //                        << restriction_container.restriction.via.node << "->" <<
+    //                        restriction_container.restriction.to.node
+    //                        << ">";
+
+    return mapbox::util::optional<InputRestrictionContainer>(restriction_container);
+}
+
+bool RestrictionParser::ShouldIgnoreRestriction(const std::string &except_tag_string) const
+{
+    // should this restriction be ignored? yes if there's an overlap between:
+    // a) the list of modes in the except tag of the restriction
+    //    (except_tag_string), eg: except=bus;bicycle
+    // b) the lua profile defines a hierachy of modes,
+    //    eg: [access, vehicle, bicycle]
+
+    if (except_tag_string.empty())
+    {
+        return false;
+    }
+
+    // Be warned, this is quadratic work here, but we assume that
+    // only a few exceptions are actually defined.
+    std::vector<std::string> exceptions;
+    boost::algorithm::split_regex(exceptions, except_tag_string, boost::regex("[;][ ]*"));
+    for (std::string &current_string : exceptions)
+    {
+        const auto string_iterator =
+            std::find(restriction_exceptions.begin(), restriction_exceptions.end(), current_string);
+        if (restriction_exceptions.end() != string_iterator)
+        {
+            return true;
+        }
+    }
+    return false;
+}
diff --git a/Algorithms/PolylineCompressor.h b/extractor/restriction_parser.hpp
similarity index 59%
rename from Algorithms/PolylineCompressor.h
rename to extractor/restriction_parser.hpp
index 5472bd8..d5adb43 100644
--- a/Algorithms/PolylineCompressor.h
+++ b/extractor/restriction_parser.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,27 +25,37 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef POLYLINECOMPRESSOR_H_
-#define POLYLINECOMPRESSOR_H_
+#ifndef RESTRICTION_PARSER_HPP
+#define RESTRICTION_PARSER_HPP
 
-struct SegmentInformation;
+#include "../data_structures/restriction.hpp"
 
-#include "../DataStructures/JSONContainer.h"
+#include <osmium/osm.hpp>
+#include <osmium/tags/regex_filter.hpp>
+
+#include <variant/optional.hpp>
 
 #include <string>
 #include <vector>
 
-class PolylineCompressor
-{
-  private:
-    void encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output) const;
-
-    void encodeNumber(int number_to_encode, std::string &output) const;
+struct lua_State;
+class ScriptingEnvironment;
 
+class RestrictionParser
+{
   public:
-    JSON::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
+    // RestrictionParser(ScriptingEnvironment &scripting_environment);
+    RestrictionParser(lua_State *lua_state);
+    mapbox::util::optional<InputRestrictionContainer> TryParse(const osmium::Relation &relation) const;
+
+  private:
+    void ReadUseRestrictionsSetting(lua_State *lua_state);
+    void ReadRestrictionExceptions(lua_State *lua_state);
+    bool ShouldIgnoreRestriction(const std::string &except_tag_string) const;
 
-    JSON::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
+    // lua_State *lua_state;
+    std::vector<std::string> restriction_exceptions;
+    bool use_turn_restrictions;
 };
 
-#endif /* POLYLINECOMPRESSOR_H_ */
+#endif /* RESTRICTION_PARSER_HPP */
diff --git a/extractor/scripting_environment.cpp b/extractor/scripting_environment.cpp
new file mode 100644
index 0000000..c51651e
--- /dev/null
+++ b/extractor/scripting_environment.cpp
@@ -0,0 +1,146 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "scripting_environment.hpp"
+
+#include "extraction_helper_functions.hpp"
+#include "extraction_node.hpp"
+#include "extraction_way.hpp"
+#include "../data_structures/external_memory_node.hpp"
+#include "../Util/lua_util.hpp"
+#include "../Util/osrm_exception.hpp"
+#include "../Util/simple_logger.hpp"
+#include "../typedefs.h"
+
+#include <luabind/tag_function.hpp>
+
+#include <osmium/osm.hpp>
+
+#include <sstream>
+namespace {
+// wrapper method as luabind doesn't automatically overload funcs w/ default parameters
+template<class T>
+auto get_value_by_key(T const& object, const char *key) -> decltype(object.get_value_by_key(key))
+{
+    return object.get_value_by_key(key, "");
+}
+
+int lua_error_callback(lua_State *L) // This is so I can use my own function as an
+// exception handler, pcall_log()
+{
+    luabind::object error_msg(luabind::from_stack(L, -1));
+    std::ostringstream error_stream;
+    error_stream << error_msg;
+    throw osrm::exception("ERROR occured in profile script:\n" + error_stream.str());
+}
+}
+
+
+ScriptingEnvironment::ScriptingEnvironment(const std::string &file_name)
+: file_name(file_name)
+{
+    SimpleLogger().Write() << "Using script " << file_name;
+}
+
+void ScriptingEnvironment::init_lua_state(lua_State* lua_state)
+{
+    typedef double (osmium::Location::* location_member_ptr_type)() const;
+
+    luabind::open(lua_state);
+    // open utility libraries string library;
+    luaL_openlibs(lua_state);
+
+    luaAddScriptFolderToLoadPath(lua_state, file_name.c_str());
+
+    // Add our function to the state's global scope
+    luabind::module(lua_state)[
+        luabind::def("print", LUA_print<std::string>),
+        luabind::def("durationIsValid", durationIsValid),
+        luabind::def("parseDuration", parseDuration),
+
+        luabind::class_<std::vector<std::string>>("vector")
+        .def("Add", static_cast<void (std::vector<std::string>::*)(const std::string &)>(&std::vector<std::string>::push_back)),
+
+        luabind::class_<osmium::Location>("Location")
+        .def<location_member_ptr_type>("lat", &osmium::Location::lat)
+        .def<location_member_ptr_type>("lon", &osmium::Location::lon),
+
+        luabind::class_<osmium::Node>("Node")
+        // .def<node_member_ptr_type>("tags", &osmium::Node::tags)
+        .def("get_value_by_key", &osmium::Node::get_value_by_key)
+        .def("get_value_by_key", &get_value_by_key<osmium::Node>),
+
+        luabind::class_<ExtractionNode>("ResultNode")
+        .def_readwrite("traffic_lights", &ExtractionNode::traffic_lights)
+        .def_readwrite("barrier", &ExtractionNode::barrier),
+
+        luabind::class_<ExtractionWay>("ResultWay")
+        // .def(luabind::constructor<>())
+        .def_readwrite("forward_speed", &ExtractionWay::forward_speed)
+        .def_readwrite("backward_speed", &ExtractionWay::backward_speed)
+        .def_readwrite("name", &ExtractionWay::name)
+        .def_readwrite("roundabout", &ExtractionWay::roundabout)
+        .def_readwrite("is_access_restricted", &ExtractionWay::is_access_restricted)
+        .def_readwrite("ignore_in_index", &ExtractionWay::ignore_in_grid)
+        .def_readwrite("duration", &ExtractionWay::duration)
+        .property("forward_mode", &ExtractionWay::get_forward_mode, &ExtractionWay::set_forward_mode)
+        .property("backward_mode", &ExtractionWay::get_backward_mode, &ExtractionWay::set_backward_mode)
+        .enum_("constants")[
+            luabind::value("notSure", 0),
+            luabind::value("oneway", 1),
+            luabind::value("bidirectional", 2),
+            luabind::value("opposite", 3)
+        ],
+        luabind::class_<osmium::Way>("Way")
+        .def("get_value_by_key", &osmium::Way::get_value_by_key)
+        .def("get_value_by_key", &get_value_by_key<osmium::Way>)
+    ];
+
+    if (0 != luaL_dofile(lua_state, file_name.c_str()))
+    {
+        luabind::object error_msg(luabind::from_stack(lua_state, -1));
+        std::ostringstream error_stream;
+        error_stream << error_msg;
+        throw osrm::exception("ERROR occured in profile script:\n" + error_stream.str());
+    }
+}
+
+lua_State *ScriptingEnvironment::get_lua_state()
+{
+    std::lock_guard<std::mutex> lock(init_mutex);
+    bool initialized = false;
+    auto& ref = script_contexts.local(initialized);
+    if (!initialized)
+    {
+        std::shared_ptr<lua_State> state(luaL_newstate(), lua_close);
+        ref = state;
+        init_lua_state(ref.get());
+    }
+    luabind::set_pcall_callback(&lua_error_callback);
+
+    return ref.get();
+}
diff --git a/Extractor/ScriptingEnvironment.h b/extractor/scripting_environment.hpp
similarity index 79%
rename from Extractor/ScriptingEnvironment.h
rename to extractor/scripting_environment.hpp
index 2b1fffe..6e0b079 100644
--- a/Extractor/ScriptingEnvironment.h
+++ b/extractor/scripting_environment.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,11 +25,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef SCRIPTINGENVIRONMENT_H_
-#define SCRIPTINGENVIRONMENT_H_
+#ifndef SCRIPTING_ENVIRONMENT_HPP
+#define SCRIPTING_ENVIRONMENT_HPP
 
 #include <string>
 #include <memory>
+#include <mutex>
 #include <tbb/enumerable_thread_specific.h>
 
 struct lua_State;
@@ -37,16 +38,16 @@ struct lua_State;
 class ScriptingEnvironment
 {
   public:
-    ScriptingEnvironment();
-    explicit ScriptingEnvironment(const char *file_name);
+    ScriptingEnvironment() = delete;
+    explicit ScriptingEnvironment(const std::string &file_name);
 
-    lua_State *getLuaState();
+    lua_State *get_lua_state();
 
   private:
-    void initLuaState(lua_State* lua_state);
-
+    void init_lua_state(lua_State* lua_state);
+    std::mutex init_mutex; 
     std::string file_name;
     tbb::enumerable_thread_specific<std::shared_ptr<lua_State>> script_contexts;
 };
 
-#endif /* SCRIPTINGENVIRONMENT_H_ */
+#endif /* SCRIPTING_ENVIRONMENT_HPP */
diff --git a/features/bicycle/mode.feature b/features/bicycle/mode.feature
index eac0430..2bfa4de 100644
--- a/features/bicycle/mode.feature
+++ b/features/bicycle/mode.feature
@@ -1,89 +1,177 @@
 @routing @bicycle @mode
 Feature: Bike - Mode flag
 
-    Background:
-        Given the profile "bicycle"
+# bicycle modes:
+# 1 bike
+# 2 pushing
+# 3 ferry
+# 4 train
 
-    @todo
+	Background:
+		Given the profile "bicycle"
+    
     Scenario: Bike - Mode when using a ferry
-        Given the node map
-            | a | b |   |
-            |   | c | d |
+    	Given the node map
+    	 | a | b |   |
+    	 |   | c | d |
 
-        And the ways
-            | nodes | highway | route | duration |
-            | ab    | primary |       |          |
-            | bc    |         | ferry | 0:01     |
-            | cd    | primary |       |          |
+    	And the ways
+    	 | nodes | highway | route | duration |
+    	 | ab    | primary |       |          |
+    	 | bc    |         | ferry | 0:01     |
+    	 | cd    | primary |       |          |
 
-        When I route I should get
-            | from | to | route    | turns                        | modes           |
-            | a    | d  | ab,bc,cd | head,right,left, destination | bike,ferry,bike |
-            | d    | a  | cd,bc,ab | head,right,left, destination | bike,ferry,bike |
-            | c    | a  | bc,ab    | head,left,destination        | ferry,bike      |
-            | d    | b  | cd,bc    | head,right,destination       | bike,ferry      |
-            | a    | c  | ab,bc    | head,right,destination       | bike,ferry      |
-            | b    | d  | bc,cd    | head,left,destination        | ferry,bike      |
-
-    @todo
-    Scenario: Bike - Mode when pushing bike against oneways
-        Given the node map
-            | a | b |   |
-            |   | c | d |
+    	When I route I should get
+    	 | from | to | route    | turns                       | modes |
+    	 | a    | d  | ab,bc,cd | head,right,left,destination | 1,3,1 |
+    	 | d    | a  | cd,bc,ab | head,right,left,destination | 1,3,1 |
+    	 | c    | a  | bc,ab    | head,left,destination       | 3,1   |
+    	 | d    | b  | cd,bc    | head,right,destination      | 1,3   |
+    	 | a    | c  | ab,bc    | head,right,destination      | 1,3   |
+    	 | b    | d  | bc,cd    | head,left,destination       | 3,1   |
 
-        And the ways
-            | nodes | highway | oneway |
-            | ab    | primary |        |
-            | bc    | primary | yes    |
-            | cd    | primary |        |
+     Scenario: Bike - Mode when using a train
+     	Given the node map
+     	 | a | b |   |
+     	 |   | c | d |
 
-        When I route I should get
-            | from | to | route    | turns                       | modes          |
-            | a    | d  | ab,bc,cd | head,right,left,destination | bike,push,bike |
-            | d    | a  | cd,bc,ab | head,right,left,destination | bike,push,bike |
-            | c    | a  | bc,ab    | head,left,destination       | push,bike      |
-            | d    | b  | cd,bc    | head,right,destination      | bike,push      |
-            | a    | c  | ab,bc    | head,right,destination      | bike,push      |
-            | b    | d  | bc,cd    | head,left,destination       | push,bike      |
-
-    @todo
-    Scenario: Bike - Mode when pushing on pedestrain streets
+     	And the ways
+     	 | nodes | highway | railway | bicycle |
+     	 | ab    | primary |         |         |
+     	 | bc    |         | train   | yes     |
+     	 | cd    | primary |         |         |
+
+     	When I route I should get
+     	 | from | to | route    | turns                       | modes |
+     	 | a    | d  | ab,bc,cd | head,right,left,destination | 1,4,1 |
+     	 | d    | a  | cd,bc,ab | head,right,left,destination | 1,4,1 |
+     	 | c    | a  | bc,ab    | head,left,destination       | 4,1   |
+     	 | d    | b  | cd,bc    | head,right,destination      | 1,4   |
+     	 | a    | c  | ab,bc    | head,right,destination      | 1,4   |
+     	 | b    | d  | bc,cd    | head,left,destination       | 4,1   |
+
+     Scenario: Bike - Mode when pushing bike against oneways
+     	Given the node map
+     	 | a | b |   |
+     	 |   | c | d |
+
+     	And the ways
+     	 | nodes | highway | oneway |
+     	 | ab    | primary |        |
+     	 | bc    | primary | yes    |
+     	 | cd    | primary |        |
+
+     	When I route I should get
+     	 | from | to | route    | turns                       | modes |
+     	 | a    | d  | ab,bc,cd | head,right,left,destination | 1,1,1 |
+     	 | d    | a  | cd,bc,ab | head,right,left,destination | 1,2,1 |
+     	 | c    | a  | bc,ab    | head,left,destination       | 2,1   |
+     	 | d    | b  | cd,bc    | head,right,destination      | 1,2   |
+     	 | a    | c  | ab,bc    | head,right,destination      | 1,1   |
+     	 | b    | d  | bc,cd    | head,left,destination       | 1,1   |
+
+     Scenario: Bike - Mode when pushing on pedestrain streets
+     	Given the node map
+     	 | a | b |   |
+     	 |   | c | d |
+
+     	And the ways
+     	 | nodes | highway    |
+     	 | ab    | primary    |
+     	 | bc    | pedestrian |
+     	 | cd    | primary    |
+
+     	When I route I should get
+     	 | from | to | route    | turns                       | modes |
+     	 | a    | d  | ab,bc,cd | head,right,left,destination | 1,2,1 |
+     	 | d    | a  | cd,bc,ab | head,right,left,destination | 1,2,1 |
+     	 | c    | a  | bc,ab    | head,left,destination       | 2,1   |
+     	 | d    | b  | cd,bc    | head,right,destination      | 1,2   |
+     	 | a    | c  | ab,bc    | head,right,destination      | 1,2   |
+     	 | b    | d  | bc,cd    | head,left,destination       | 2,1   |
+
+     Scenario: Bike - Mode when pushing on pedestrain areas
+     	Given the node map
+     	 | a | b |   |   |
+     	 |   | c | d | f |
+
+     	And the ways
+     	 | nodes | highway    | area |
+     	 | ab    | primary    |      |
+     	 | bcd   | pedestrian | yes  |
+     	 | df    | primary    |      |
+
+     	When I route I should get
+     	 | from | to | route     | modes |
+     	 | a    | f  | ab,bcd,df | 1,2,1 |
+     	 | f    | a  | df,bcd,ab | 1,2,1 |
+     	 | d    | a  | bcd,ab    | 2,1   |
+     	 | f    | b  | df,bcd    | 1,2   |
+     	 | a    | d  | ab,bcd    | 1,2   |
+     	 | b    | f  | bcd,df    | 2,1   |
+
+     Scenario: Bike - Mode when pushing on steps
+     	Given the node map
+     	 | a | b |   |   |
+     	 |   | c | d | f |
+
+     	And the ways
+    	 | nodes | highway |
+    	 | ab    | primary |
+    	 | bc    | steps   |
+    	 | cd    | primary |
+
+     	When I route I should get
+    	 | from | to | route    | turns                       | modes |
+    	 | a    | d  | ab,bc,cd | head,right,left,destination | 1,2,1 |
+    	 | d    | a  | cd,bc,ab | head,right,left,destination | 1,2,1 |
+    	 | c    | a  | bc,ab    | head,left,destination       | 2,1   |
+    	 | d    | b  | cd,bc    | head,right,destination      | 1,2   |
+    	 | a    | c  | ab,bc    | head,right,destination      | 1,2   |
+    	 | b    | d  | bc,cd    | head,left,destination       | 2,1   |
+
+     Scenario: Bike - Mode when bicycle=dismount
+     	Given the node map
+     	 | a | b |   |   |
+     	 |   | c | d | f |
+
+     	And the ways
+    	 | nodes | highway | bicycle  |
+    	 | ab    | primary |          |
+    	 | bc    | primary | dismount |
+    	 | cd    | primary |          |
+
+     	When I route I should get
+    	 | from | to | route    | turns                       | modes |
+    	 | a    | d  | ab,bc,cd | head,right,left,destination | 1,2,1 |
+    	 | d    | a  | cd,bc,ab | head,right,left,destination | 1,2,1 |
+    	 | c    | a  | bc,ab    | head,left,destination       | 2,1   |
+    	 | d    | b  | cd,bc    | head,right,destination      | 1,2   |
+    	 | a    | c  | ab,bc    | head,right,destination      | 1,2   |
+         | b    | d  | bc,cd    | head,left,destination       | 2,1   |
+
+    Scenario: Bicycle - Modes when starting on forward oneway
         Given the node map
-            | a | b |   |
-            |   | c | d |
+         | a | b |
 
         And the ways
-            | nodes | highway    |
-            | ab    | primary    |
-            | bc    | pedestrian |
-            | cd    | primary    |
+         | nodes | oneway |
+         | ab    | yes    |
 
         When I route I should get
-            | from | to | route    | turns                       | modes          |
-            | a    | d  | ab,bc,cd | head,right,left,destination | bike,push,bike |
-            | d    | a  | cd,bc,ab | head,right,left,destination | bike,push,bike |
-            | c    | a  | bc,ab    | head,left,destination       | push,bike      |
-            | d    | b  | cd,bc    | head,right,destination      | bike,push      |
-            | a    | c  | ab,bc    | head,right,destination      | bike,push      |
-            | b    | d  | bc,cd    | head,left,destination       | push,bike      |
-
-    @todo
-    Scenario: Bike - Mode when pushing on pedestrain areas
+         | from | to | route | modes |
+         | a    | b  | ab    | 1     |
+         | b    | a  | ab    | 2     |
+
+    Scenario: Bicycle - Modes when starting on reverse oneway
         Given the node map
-            | a | b |   |   |
-            |   | c | d | f |
+         | a | b |
 
         And the ways
-            | nodes | highway    | area |
-            | ab    | primary    |      |
-            | bcd   | pedestrian | yes  |
-            | df    | primary    |      |
+         | nodes | oneway |
+         | ab    | -1     |
 
         When I route I should get
-            | from | to | route     | modes          |
-            | a    | f  | ab,bcd,df | bike,push,bike |
-            | f    | a  | df,bcd,ab | bike,push,bike |
-            | d    | a  | bcd,ab    | push,bike      |
-            | f    | b  | df,bcd    | bike,push      |
-            | a    | d  | ab,bcd    | bike,push      |
-            | b    | f  | bcd,df    | push,bike      |
+         | from | to | route | modes |
+         | a    | b  | ab    | 2     |
+         | b    | a  | ab    | 1     |
diff --git a/features/bicycle/pushing.feature b/features/bicycle/pushing.feature
index 2b23829..5741fb1 100644
--- a/features/bicycle/pushing.feature
+++ b/features/bicycle/pushing.feature
@@ -4,9 +4,9 @@ Feature: Bike - Accessability of different way types
     Background:
         Given the profile "bicycle"
         Given the shortcuts
-            | key  | value     |
-            | bike | 49s ~20%  |
-            | foot | 121s ~20% |
+            | key  | value        |
+            | bike | 15 km/h ~20% |
+            | foot | 5 km/h ~20%  |
 
     Scenario: Bike - Pushing bikes on pedestrian-only ways
         Then routability should be
@@ -98,11 +98,11 @@ Feature: Bike - Accessability of different way types
             | cd    | primary |        |
 
         When I route I should get
-            | from | to | route    | turns                                              |
-            | a    | d  | ab,bc,cd | head,right,left,destination                        |
-            | d    | a  | cd,bc,ab | head,enter_contraflow,leave_contraflow,destination |
-            | c    | a  | bc,ab    | head,leave_contraflow,destination                  |
-            | d    | b  | cd,bc    | head,enter_contraflow,destination                  |
+            | from | to | route    | turns                       |
+            | a    | d  | ab,bc,cd | head,right,left,destination |
+            | d    | a  | cd,bc,ab | head,right,left,destination |
+            | c    | a  | bc,ab    | head,left,destination       |
+            | d    | b  | cd,bc    | head,right,destination      |
 
     @todo
     Scenario: Bike - Instructions when pushing bike on footway/pedestrian, etc.
@@ -117,8 +117,8 @@ Feature: Bike - Accessability of different way types
             | cd    | primary |
 
         When I route I should get
-            | from | to | route    | turns                                              |
-            | a    | d  | ab,bc,cd | head,right,left,destination                        |
-            | d    | a  | cd,bc,ab | head,enter_contraflow,leave_contraflow,destination |
-            | c    | a  | bc,ab    | head,leave_contraflow,destination                  |
-            | d    | b  | cd,bc    | head,enter_contraflow,destination                  |
+            | from | to | route    | turns                       |
+            | a    | d  | ab,bc,cd | head,right,left,destination |
+            | d    | a  | cd,bc,ab | head,right,left,destination |
+            | c    | a  | bc,ab    | head,left,destination       |
+            | d    | b  | cd,bc    | head,right,destination      |
diff --git a/features/car/ferry.feature b/features/car/ferry.feature
index 3e90cf0..abbe5ed 100644
--- a/features/car/ferry.feature
+++ b/features/car/ferry.feature
@@ -17,12 +17,31 @@ Feature: Car - Handle ferry routes
             | efg   | primary |       |         |
 
         When I route I should get
-            | from | to | route       |
-            | a    | g  | abc,cde,efg |
-            | b    | f  | abc,cde,efg |
-            | e    | c  | cde         |
-            | e    | b  | cde,abc     |
-            | e    | a  | cde,abc     |
-            | c    | e  | cde         |
-            | c    | f  | cde,efg     |
-            | c    | g  | cde,efg     |
+            | from | to | route       | modes |
+            | a    | g  | abc,cde,efg | 1,2,1 |
+            | b    | f  | abc,cde,efg | 1,2,1 |
+            | e    | c  | cde         | 2     |
+            | e    | b  | cde,abc     | 2,1   |
+            | e    | a  | cde,abc     | 2,1   |
+            | c    | e  | cde         | 2     |
+            | c    | f  | cde,efg     | 2,1   |
+            | c    | g  | cde,efg     | 2,1   |
+
+    Scenario: Car - Properly handle durations
+        Given the node map
+            | a | b | c |   |   |
+            |   |   | d |   |   |
+            |   |   | e | f | g |
+
+        And the ways
+            | nodes | highway | route | duration |
+            | abc   | primary |       |          |
+            | cde   |         | ferry | 00:01:00 |
+            | efg   | primary |       |          |
+
+        When I route I should get
+            | from | to | route       | modes | speed   |
+            | a    | g  | abc,cde,efg | 1,2,1 | 26 km/h |
+            | b    | f  | abc,cde,efg | 1,2,1 | 20 km/h |
+            | c    | e  | cde         | 2     | 12 km/h |
+            | e    | c  | cde         | 2     | 12 km/h |
diff --git a/features/car/link.feature b/features/car/link.feature
new file mode 100644
index 0000000..f4628e4
--- /dev/null
+++ b/features/car/link.feature
@@ -0,0 +1,111 @@
+ at routing @link @car
+Feature: Car - Speed on links
+# Check that there's a reasonable ratio between the
+# speed of a way and it's corresponding link type.
+
+    Background: Use specific speeds
+        Given the profile "car"
+        Given a grid size of 1000 meters
+
+    Scenario: Car - Use motorway_link when reasonable
+        Given the node map
+            |   |   | e |   |   |   | f |   |   |
+            | x | a | b |   |   |   | c | d | y |
+
+        And the ways
+            | nodes | highway       |
+            | xa    | unclassified  |
+            | ab    | motorway_link |
+            | bc    | motorway_link |
+            | cd    | motorway_link |
+            | ae    | motorway      |
+            | ef    | motorway      |
+            | fd    | motorway      |
+            | dy    | unclassified  |
+
+        When I route I should get
+            | from | to | route          |
+            | x    | y  | xa,ae,ef,fd,dy |
+            | b    | c  | bc             |
+
+    Scenario: Car - Use trunk_link when reasonable
+        Given the node map
+            |   |   | e |   |   |   | f |   |   |
+            | x | a | b |   |   |   | c | d | y |
+
+        And the ways
+            | nodes | highway      |
+            | xa    | unclassified |
+            | ab    | trunk_link   |
+            | bc    | trunk_link   |
+            | cd    | trunk_link   |
+            | ae    | trunk        |
+            | ef    | trunk        |
+            | fd    | trunk        |
+            | dy    | unclassified |
+        When I route I should get
+            | from | to | route          |
+            | x    | y  | xa,ae,ef,fd,dy |
+            | b    | c  | bc             |
+
+    Scenario: Car - Use primary_link when reasonable
+        Given the node map
+            |   |   | e |   |   |   | f |   |   |
+            | x | a | b |   |   |   | c | d | y |
+
+        And the ways
+            | nodes | highway        |
+            | xa    | unclassified   |
+            | ab    | primary_link   |
+            | bc    | primary_link   |
+            | cd    | primary_link   |
+            | ae    | primary        |
+            | ef    | primary        |
+            | fd    | primary        |
+            | dy    | unclassified |
+        When I route I should get
+            | from | to | route          |
+            | x    | y  | xa,ae,ef,fd,dy |
+            | b    | c  | bc             |
+
+    Scenario: Car - Use secondary_link when reasonable
+        Given the node map
+            |   |   | e |   |   |   | f |   |   |
+            | x | a | b |   |   |   | c | d | y |
+
+        And the ways
+            | nodes | highway          |
+            | xa    | unclassified     |
+            | ab    | secondary_link   |
+            | bc    | secondary_link   |
+            | cd    | secondary_link   |
+            | ae    | secondary        |
+            | ef    | secondary        |
+            | fd    | secondary        |
+            | dy    | unclassified     |
+
+        When I route I should get
+            | from | to | route          |
+            | x    | y  | xa,ae,ef,fd,dy |
+            | b    | c  | bc             |
+
+    Scenario: Car - Use tertiary_link when reasonable
+        Given the node map
+            |   |   | e |   |   |   | f |   |   |
+            | x | a | b |   |   |   | c | d | y |
+
+        And the ways
+            | nodes | highway         |
+            | xa    | unclassified    |
+            | ab    | tertiary_link   |
+            | bc    | tertiary_link   |
+            | cd    | tertiary_link   |
+            | ae    | tertiary        |
+            | ef    | tertiary        |
+            | fd    | tertiary        |
+            | dy    | unclassified    |
+
+        When I route I should get
+            | from | to | route          |
+            | x    | y  | xa,ae,ef,fd,dy |
+            | b    | c  | bc             |
diff --git a/features/car/maxspeed.feature b/features/car/maxspeed.feature
index 9e77cde..8f85d3a 100644
--- a/features/car/maxspeed.feature
+++ b/features/car/maxspeed.feature
@@ -8,44 +8,54 @@ OSRM will use 4/5 of the projected free-flow speed.
 
     Scenario: Car - Respect maxspeeds when lower that way type speed
         Given the node map
-            | a | b | c |
+            | a | b | c | d | e | f | g |
 
         And the ways
-            | nodes | highway | maxspeed |
-            | ab    | trunk   |          |
-            | bc    | trunk   | 60       |
+            | nodes | highway | maxspeed    |
+            | ab    | trunk   |             |
+            | bc    | trunk   | 60          |
+            | cd    | trunk   | FR:urban    |
+            | de    | trunk   | CH:rural    |
+            | ef    | trunk   | CH:trunk    |
+            | fg    | trunk   | CH:motorway |
 
         When I route I should get
-            | from | to | route | speed        |
-            | a    | b  | ab    | 67 km/h      |
-            | b    | c  | bc    | 48 km/h +- 1 |
+            | from | to | route | speed         |
+            | a    | b  | ab    |  78 km/h      |
+            | b    | c  | bc    |  59 km/h +- 1 |
+            | c    | d  | cd    |  50 km/h      |
+            | d    | e  | de    |  75 km/h      |
+            | e    | f  | ef    |  90 km/h      |
+            | f    | g  | fg    | 105 km/h      |
 
     Scenario: Car - Do not ignore maxspeed when higher than way speed
         Given the node map
-            | a | b | c |
+            | a | b | c | d |
 
         And the ways
-            | nodes | highway     | maxspeed |
-            | ab    | residential |          |
-            | bc    | residential | 90       |
+            | nodes | highway       | maxspeed |
+            | ab    | residential   |          |
+            | bc    | residential   | 90       |
+            | cd    | living_street | FR:urban |
 
         When I route I should get
             | from | to | route | speed        |
-            | a    | b  | ab    | 20 km/h      |
-            | b    | c  | bc    | 72 km/h +- 1 |
+            | a    | b  | ab    | 31 km/h      |
+            | b    | c  | bc    | 83 km/h +- 1 |
+            | c    | d  | cd    | 50 km/h      |
 
     Scenario: Car - Forward/backward maxspeed
         Given a grid size of 100 meters
 
         Then routability should be
-            | highway | maxspeed | maxspeed:forward | maxspeed:backward | forw        | backw        |
-            | primary |          |                  |                   | 51 km/h     | 51 km/h      |
-            | primary | 60       |                  |                   | 48 km/h     | 48 km/h      |
-            | primary |          | 60               |                   | 48 km/h     | 65 km/h      |
-            | primary |          |                  | 60                | 51 km/h     | 48 km/h      |
-            | primary | 15       | 60               |                   | 48 km/h     | 15 km/h +- 1 |
-            | primary | 15       |                  | 60                | 12 km/h +- 1| 48 km/h      |
-            | primary | 15       | 30               | 60                | 24 km/h     | 48 km/h      |
+            | highway | maxspeed | maxspeed:forward | maxspeed:backward | forw    | backw   |
+            | primary |          |                  |                   | 65 km/h | 65 km/h |
+            | primary | 60       |                  |                   | 60 km/h | 60 km/h |
+            | primary |          | 60               |                   | 60 km/h | 65 km/h |
+            | primary |          |                  | 60                | 65 km/h | 60 km/h |
+            | primary | 15       | 60               |                   | 60 km/h | 23 km/h |
+            | primary | 15       |                  | 60                | 23 km/h | 60 km/h |
+            | primary | 15       | 30               | 60                | 34 km/h | 60 km/h |
 
     Scenario: Car - Maxspeed should not allow routing on unroutable ways
         Then routability should be
diff --git a/features/car/restrictions.feature b/features/car/restrictions.feature
index b4ccdbe..f381f2f 100644
--- a/features/car/restrictions.feature
+++ b/features/car/restrictions.feature
@@ -312,3 +312,72 @@ Feature: Car - Turn restrictions
             | e    | f  | ae,xa,bx,fb                      |
             | c    | f  | dc,da,ae,ge,hg,hg,ge,ae,xa,bx,fb |
             | d    | f  | da,ae,ge,hg,hg,ge,ae,xa,bx,fb    |
+
+    @except
+    Scenario: Car - two only_ restrictions share same to-way
+        Given the node map
+            |   |   | e |   |   |   | f |   |   |
+            |   |   |   |   | a |   |   |   |   |
+            |   |   |   |   |   |   |   |   |   |
+            |   |   | c |   | x |   | d |   |   |
+            |   |   |   |   | y |   |   |   |   |
+            |   |   |   |   |   |   |   |   |   |
+            |   |   |   |   | b |   |   |   |   |
+
+        And the ways
+            | nodes | oneway |
+            | ef    | no     |
+            | ce    | no     |
+            | fd    | no     |
+            | ca    | no     |
+            | ad    | no     |
+            | ax    | no     |
+            | xy    | no     |
+            | yb    | no     |
+            | cb    | no     |
+            | db    | no     |
+
+        And the relations
+            | type        | way:from | way:to | node:via | restriction      |
+            | restriction | ax       | xy     | x        | only_straight_on |
+            | restriction | by       | xy     | y        | only_straight_on |
+
+        When I route I should get
+            | from | to | route    |
+            | a    | b  | ax,xy,yb |
+            | b    | a  | yb,xy,ax |
+
+    @except
+    Scenario: Car - two only_ restrictions share same from-way
+        Given the node map
+            |   |   | e |   |   |   | f |   |   |
+            |   |   |   |   | a |   |   |   |   |
+            |   |   |   |   |   |   |   |   |   |
+            |   |   | c |   | x |   | d |   |   |
+            |   |   |   |   | y |   |   |   |   |
+            |   |   |   |   |   |   |   |   |   |
+            |   |   |   |   | b |   |   |   |   |
+
+        And the ways
+            | nodes | oneway |
+            | ef    | no     |
+            | ce    | no     |
+            | fd    | no     |
+            | ca    | no     |
+            | ad    | no     |
+            | ax    | no     |
+            | xy    | no     |
+            | yb    | no     |
+            | cb    | no     |
+            | db    | no     |
+
+        And the relations
+            | type        | way:from | way:to | node:via | restriction      |
+            | restriction | xy       | xa     | x        | only_straight_on |
+            | restriction | xy       | yb     | y        | only_straight_on |
+
+        When I route I should get
+            | from | to | route    |
+            | a    | b  | ax,xy,yb |
+            | b    | a  | yb,xy,ax |
+
diff --git a/features/car/speed.feature b/features/car/speed.feature
index 4f54a33..a81baeb 100644
--- a/features/car/speed.feature
+++ b/features/car/speed.feature
@@ -8,17 +8,17 @@ Feature: Car - speeds
     Scenario: Car - speed of various way types
         Then routability should be
             | highway        | oneway | bothw        |
-            | motorway       | no     | 72 km/h      |
-            | motorway_link  | no     | 60 km/h      |
-            | trunk          | no     | 67 km/h +- 1 |
-            | trunk_link     | no     | 55 km/h +- 1 |
-            | primary        | no     | 52 km/h +- 1 |
-            | primary_link   | no     | 48 km/h      |
-            | secondary      | no     | 43 km/h +- 1 |
-            | secondary_link | no     | 40 km/h      |
-            | tertiary       | no     | 32 km/h      |
-            | tertiary_link  | no     | 24 km/h      |
-            | unclassified   | no     | 20 km/h      |
-            | residential    | no     | 20 km/h      |
-            | living_street  | no     |  8 km/h      |
-            | service        | no     | 12 km/h      |
+            | motorway       | no     | 82 km/h      |
+            | motorway_link  | no     | 47 km/h      |
+            | trunk          | no     | 79 km/h +- 1 |
+            | trunk_link     | no     | 43 km/h +- 1 |
+            | primary        | no     | 63 km/h +- 1 |
+            | primary_link   | no     | 34 km/h      |
+            | secondary      | no     | 54 km/h +- 1 |
+            | secondary_link | no     | 31 km/h      |
+            | tertiary       | no     | 43 km/h      |
+            | tertiary_link  | no     | 26 km/h      |
+            | unclassified   | no     | 31 km/h      |
+            | residential    | no     | 31 km/h      |
+            | living_street  | no     | 18 km/h      |
+            | service        | no     | 23 km/h      |
diff --git a/features/car/surface.feature b/features/car/surface.feature
new file mode 100644
index 0000000..5dd4ed6
--- /dev/null
+++ b/features/car/surface.feature
@@ -0,0 +1,141 @@
+ at routing @car @surface
+Feature: Car - Surfaces
+
+    Background:
+        Given the profile "car"
+
+    Scenario: Car - Routeability of tracktype tags
+        Then routability should be
+            | highway | tracktype | bothw |
+            | trunk   | grade1    | x     |
+            | trunk   | grade2    | x     |
+            | trunk   | grade3    | x     |
+            | trunk   | grade4    | x     |
+            | trunk   | grade5    | x     |
+            | trunk   | nonsense  | x     |
+
+    Scenario: Car - Routability of smoothness tags
+        Then routability should be
+            | highway | smoothness    | bothw |
+            | trunk   | excellent     | x     |
+            | trunk   | good          | x     |
+            | trunk   | intermediate  | x     |
+            | trunk   | bad           | x     |
+            | trunk   | very_bad      | x     |
+            | trunk   | horrible      | x     |
+            | trunk   | very_horrible | x     |
+            | trunk   | impassable    |       |
+            | trunk   | nonsense      | x     |
+ 
+    Scenario: Car - Routabiliy of surface tags
+        Then routability should be
+            | highway | surface  | bothw |
+            | trunk   | asphalt  | x     |
+            | trunk   | sett     | x     |
+            | trunk   | gravel   | x     |
+            | trunk   | nonsense | x     |
+
+    Scenario: Car - Good surfaces should not grant access
+        Then routability should be
+            | highway  | access       | tracktype | smoothness | surface | forw | backw |
+            | motorway |              |           |            |         | x    |       |
+            | motorway | no           | grade1    | excellent  | asphalt |      |       |
+            | motorway | private      | grade1    | excellent  | asphalt |      |       |
+            | motorway | agricultural | grade1    | excellent  | asphalt |      |       |
+            | motorway | forestry     | grade1    | excellent  | asphalt |      |       |
+            | motorway | emergency    | grade1    | excellent  | asphalt |      |       |
+            | primary  |              |           |            |         | x    | x     |
+            | primary  | no           | grade1    | excellent  | asphalt |      |       |
+            | primary  | private      | grade1    | excellent  | asphalt |      |       |
+            | primary  | agricultural | grade1    | excellent  | asphalt |      |       |
+            | primary  | forestry     | grade1    | excellent  | asphalt |      |       |
+            | primary  | emergency    | grade1    | excellent  | asphalt |      |       |
+
+    Scenario: Car - Impassable surfaces should deny access
+        Then routability should be
+            | highway  | access | smoothness | forw | backw |
+            | motorway |        | impassable |      |       |
+            | motorway | yes    |            | x    |       |
+            | motorway | yes    | impassable |      |       |
+            | primary  |        | impassable |      |       |
+            | primary  | yes    |            | x    | x     |
+            | primary  | yes    | impassable |      |       |
+
+    Scenario: Car - Surface should reduce speed
+        Then routability should be
+            | highway  | oneway | surface         | forw        | backw       |
+            | motorway | no     |                 | 80 km/h +-1 | 80 km/h +-1 |
+            | motorway | no     | asphalt         | 80 km/h +-1 | 80 km/h +-1 |
+            | motorway | no     | concrete        | 80 km/h +-1 | 80 km/h +-1 |
+            | motorway | no     | concrete:plates | 80 km/h +-1 | 80 km/h +-1 |
+            | motorway | no     | concrete:lanes  | 80 km/h +-1 | 80 km/h +-1 |
+            | motorway | no     | paved           | 80 km/h +-1 | 80 km/h +-1 |
+            | motorway | no     | cement          | 72 km/h +-1 | 72 km/h +-1 |
+            | motorway | no     | compacted       | 72 km/h +-1 | 72 km/h +-1 |
+            | motorway | no     | fine_gravel     | 72 km/h +-1 | 72 km/h +-1 |
+            | motorway | no     | paving_stones   | 60 km/h +-1 | 60 km/h +-1 |
+            | motorway | no     | metal           | 60 km/h +-1 | 60 km/h +-1 |
+            | motorway | no     | bricks          | 60 km/h +-1 | 60 km/h +-1 |
+            | motorway | no     | grass           | 42 km/h +-1 | 42 km/h +-1 |
+            | motorway | no     | wood            | 42 km/h +-1 | 42 km/h +-1 |
+            | motorway | no     | sett            | 42 km/h +-1 | 42 km/h +-1 |
+            | motorway | no     | grass_paver     | 42 km/h +-1 | 42 km/h +-1 |
+            | motorway | no     | gravel          | 42 km/h +-1 | 42 km/h +-1 |
+            | motorway | no     | unpaved         | 42 km/h +-1 | 42 km/h +-1 |
+            | motorway | no     | ground          | 42 km/h +-1 | 42 km/h +-1 |
+            | motorway | no     | dirt            | 42 km/h +-1 | 42 km/h +-1 |
+            | motorway | no     | pebblestone     | 42 km/h +-1 | 42 km/h +-1 |
+            | motorway | no     | tartan          | 42 km/h +-1 | 42 km/h +-1 |
+            | motorway | no     | cobblestone     | 34 km/h +-1 | 34 km/h +-1 |
+            | motorway | no     | clay            | 34 km/h +-1 | 34 km/h +-1 |
+            | motorway | no     | earth           | 26 km/h +-1 | 26 km/h +-1 |
+            | motorway | no     | stone           | 26 km/h +-1 | 26 km/h +-1 |
+            | motorway | no     | rocky           | 26 km/h +-1 | 26 km/h +-1 |
+            | motorway | no     | sand            | 26 km/h +-1 | 26 km/h +-1 |
+
+    Scenario: Car - Tracktypes should reduce speed
+        Then routability should be
+            | highway  | oneway | tracktype | forw        | backw       |
+            | motorway | no     |           | 80 km/h +-1 | 80 km/h +-1 |
+            | motorway | no     | grade1    | 60 km/h +-1 | 60 km/h +-1 |
+            | motorway | no     | grade2    | 42 km/h +-1 | 42 km/h +-1 |
+            | motorway | no     | grade3    | 34 km/h +-1 | 34 km/h +-1 |
+            | motorway | no     | grade4    | 31 km/h +-1 | 31 km/h +-1 |
+            | motorway | no     | grade5    | 26 km/h +-1 | 26 km/h +-1 |
+
+    Scenario: Car - Smoothness should reduce speed
+        Then routability should be
+            | highway  | oneway | smoothness    | forw        | backw       |
+            | motorway | no     |               | 80 km/h +-1 | 80 km/h +-1 |
+            | motorway | no     | intermediate  | 72 km/h +-1 | 72 km/h +-1 |
+            | motorway | no     | bad           | 42 km/h +-1 | 42 km/h +-1 |
+            | motorway | no     | very_bad      | 26 km/h +-1 | 26 km/h +-1 |
+            | motorway | no     | horrible      | 18 km/h +-1 | 18 km/h +-1 |
+            | motorway | no     | very_horrible | 15 km/h +-1 | 15 km/h +-1 |
+
+    Scenario: Car - Combination of surface tags should use lowest speed
+        Then routability should be
+            | highway  | oneway | tracktype | surface | smoothness    | backw   | forw    |
+            | motorway | no     |           |         |               | 80 km/h | 80 km/h |
+            | service  | no     | grade1    | asphalt | excellent     | 23 km/h | 23 km/h |
+            | motorway | no     | grade5    | asphalt | excellent     | 26 km/h | 26 km/h |
+            | motorway | no     | grade1    | mud     | excellent     | 18 km/h | 18 km/h |
+            | motorway | no     | grade1    | asphalt | very_horrible | 15 km/h | 15 km/h |
+            | service  | no     | grade5    | mud     | very_horrible | 15 km/h | 15 km/h |
+
+    Scenario: Car - Surfaces should not affect oneway direction
+        Then routability should be
+            | highway | oneway | tracktype | smoothness | surface  | forw | backw |
+            | primary |        | grade1    | excellent  | asphalt  | x    | x     |
+            | primary |        | grade5    | very_bad   | mud      | x    | x     |
+            | primary |        | nonsense  | nonsense   | nonsense | x    | x     |
+            | primary | no     | grade1    | excellent  | asphalt  | x    | x     |
+            | primary | no     | grade5    | very_bad   | mud      | x    | x     |
+            | primary | no     | nonsense  | nonsense   | nonsense | x    | x     |
+            | primary | yes    | grade1    | excellent  | asphalt  | x    |       |
+            | primary | yes    | grade5    | very_bad   | mud      | x    |       |
+            | primary | yes    | nonsense  | nonsense   | nonsense | x    |       |
+            | primary | -1     | grade1    | excellent  | asphalt  |      | x     |
+            | primary | -1     | grade5    | very_bad   | mud      |      | x     |
+            | primary | -1     | nonsense  | nonsense   | nonsense |      | x     |
+    
diff --git a/features/foot/ferry.feature b/features/foot/ferry.feature
index 4308756..866644d 100644
--- a/features/foot/ferry.feature
+++ b/features/foot/ferry.feature
@@ -17,15 +17,15 @@ Feature: Foot - Handle ferry routes
             | efg   | primary |       |      |
 
         When I route I should get
-            | from | to | route       |
-            | a    | g  | abc,cde,efg |
-            | b    | f  | abc,cde,efg |
-            | e    | c  | cde         |
-            | e    | b  | cde,abc     |
-            | e    | a  | cde,abc     |
-            | c    | e  | cde         |
-            | c    | f  | cde,efg     |
-            | c    | g  | cde,efg     |
+            | from | to | route       | modes |
+            | a    | g  | abc,cde,efg | 1,2,1 |
+            | b    | f  | abc,cde,efg | 1,2,1 |
+            | e    | c  | cde         | 2     |
+            | e    | b  | cde,abc     | 2,1   |
+            | e    | a  | cde,abc     | 2,1   |
+            | c    | e  | cde         | 2     |
+            | c    | f  | cde,efg     | 2,1   |
+            | c    | g  | cde,efg     | 2,1   |
 
     Scenario: Foot - Ferry duration, single node
         Given the node map
diff --git a/features/options/extract/files.feature b/features/options/extract/files.feature
index 3061263..aceab19 100644
--- a/features/options/extract/files.feature
+++ b/features/options/extract/files.feature
@@ -1,7 +1,7 @@
 @extract @options @files
 Feature: osrm-extract command line options: files
 # expansions:
-# {base} => path to current input file
+# {osm_base} => path to current input file
 # {profile} => path to current profile script
 
     Background:
@@ -14,12 +14,12 @@ Feature: osrm-extract command line options: files
         And the data has been saved to disk
 
     Scenario: osrm-extract - Passing base file
-        When I run "osrm-extract {base}.osm --profile {profile}"
+        When I run "osrm-extract {osm_base}.osm --profile {profile}"
         Then stderr should be empty
         And it should exit with code 0
 
     Scenario: osrm-extract - Order of options should not matter
-        When I run "osrm-extract --profile {profile} {base}.osm"
+        When I run "osrm-extract --profile {profile} {osm_base}.osm"
         Then stderr should be empty
         And it should exit with code 0
 
diff --git a/features/options/prepare/files.feature b/features/options/prepare/files.feature
index de356a8..6e82a6b 100644
--- a/features/options/prepare/files.feature
+++ b/features/options/prepare/files.feature
@@ -1,7 +1,7 @@
 @prepare @options @files
 Feature: osrm-prepare command line options: files
 # expansions:
-# {base} => path to current input file
+# {extracted_base} => path to current extracted input file
 # {profile} => path to current profile script
 
     Background:
@@ -14,12 +14,12 @@ Feature: osrm-prepare command line options: files
         And the data has been extracted
 
     Scenario: osrm-prepare - Passing base file
-        When I run "osrm-prepare {base}.osrm --profile {profile}"
+        When I run "osrm-prepare {extracted_base}.osrm --profile {profile}"
         Then stderr should be empty
         And it should exit with code 0
 
     Scenario: osrm-prepare - Order of options should not matter
-        When I run "osrm-prepare --profile {profile} {base}.osrm"
+        When I run "osrm-prepare --profile {profile} {extracted_base}.osrm"
         Then stderr should be empty
         And it should exit with code 0
 
diff --git a/features/options/routed/files.feature b/features/options/routed/files.feature
index 716b2a4..15ce679 100644
--- a/features/options/routed/files.feature
+++ b/features/options/routed/files.feature
@@ -1,11 +1,16 @@
- at routed @options @files
+ at routed @options @files @todo
 Feature: osrm-routed command line options: files
 # Normally when launching osrm-routed, it will keep running as a server until it's shut down.
 # For testing program options, the --trial option is used, which causes osrm-routed to quit
 # immediately after initialization. This makes testing easier and faster.
 # 
-# The {base} part of the options to osrm-routed will be expanded to the actual base path of
-# the preprocessed file.
+# The {prepared_base} part of the options to osrm-routed will be expanded to the actual base path of
+# the prepared input file.
+
+# TODO
+# Since we're not using osmr-datastore for all testing, osrm-routed is kept running.
+# This means this test fails because osrm-routed is already running.
+# It probably needs to be rewritten to first quit osrm-routed.
 
     Background:
         Given the profile "testbot"
@@ -17,7 +22,7 @@ Feature: osrm-routed command line options: files
         And the data has been prepared
 
     Scenario: osrm-routed - Passing base file
-        When I run "osrm-routed {base}.osrm --trial"
+        When I run "osrm-routed {prepared_base}.osrm --trial"
         Then stdout should contain /^\[info\] starting up engines/
         And stdout should contain /\d{1,2}\.\d{1,2}\.\d{1,2}/
         And stdout should contain /compiled at/
diff --git a/features/step_definitions/data.rb b/features/step_definitions/data.rb
index e0985a4..f1e58ba 100644
--- a/features/step_definitions/data.rb
+++ b/features/step_definitions/data.rb
@@ -158,3 +158,19 @@ Given /^the data has been prepared$/ do
     @process_error = e
   end
 end
+
+Given /^osrm\-routed is stopped$/ do
+  begin
+    OSRMLoader.shutdown
+  rescue OSRMError => e
+    @process_error = e
+  end
+end
+
+Given /^data is loaded directly/ do
+  @load_method = 'directly'
+end
+
+Given /^data is loaded with datastore$/ do
+  @load_method = 'datastore'
+end
diff --git a/features/step_definitions/distance_matrix.rb b/features/step_definitions/distance_matrix.rb
new file mode 100644
index 0000000..f85bdcc
--- /dev/null
+++ b/features/step_definitions/distance_matrix.rb
@@ -0,0 +1,56 @@
+When /^I request a travel time matrix I should get$/ do |table|
+  
+  no_route = 2147483647   # MAX_INT
+  
+  raise "*** Top-left cell of matrix table must be empty" unless table.headers[0]==""
+  
+  nodes = []
+  column_headers = table.headers[1..-1]
+  row_headers = table.rows.map { |h| h.first }
+  unless column_headers==row_headers
+    raise "*** Column and row headers must match in matrix table, got #{column_headers.inspect} and #{row_headers.inspect}"
+  end
+  column_headers.each do |node_name|
+    node = find_node_by_name(node_name)
+    raise "*** unknown node '#{node_name}" unless node
+    nodes << node
+  end
+  
+  reprocess
+  actual = []
+  actual << table.headers
+  OSRMLoader.load(self,"#{prepared_file}.osrm") do
+    
+    # compute matrix
+    params = @query_params
+    response = request_table nodes, params
+    if response.body.empty? == false
+      json = JSON.parse response.body
+      result = json['distance_table']
+    end
+    
+    # compare actual and expected result, one row at a time
+    table.rows.each_with_index do |row,ri|
+      
+      # fuzzy match
+      ok = true
+      0.upto(nodes.size-1) do |i|
+        if FuzzyMatch.match result[ri][i], row[i+1]
+          result[ri][i] = row[i+1]
+        elsif row[i+1]=="" and result[ri][i]==no_route
+          result[ri][i] = ""
+        else
+          result[ri][i] = result[ri][i].to_s
+          ok = false
+        end
+      end
+      
+      # add row header
+      r = [row[0],result[ri]].flatten
+      
+      # store row for comparison
+      actual << r
+    end
+  end
+  table.routing_diff! actual
+end
diff --git a/features/step_definitions/locate.rb b/features/step_definitions/locate.rb
index 9d3d74f..3e67be3 100644
--- a/features/step_definitions/locate.rb
+++ b/features/step_definitions/locate.rb
@@ -1,7 +1,7 @@
 When /^I request locate I should get$/ do |table|
   reprocess
   actual = []
-  OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
+  OSRMLoader.load(self,"#{prepared_file}.osrm") do
     table.hashes.each_with_index do |row,ri|
       in_node = find_node_by_name row['in']
       raise "*** unknown in-node '#{row['in']}" unless in_node
diff --git a/features/step_definitions/nearest.rb b/features/step_definitions/nearest.rb
index ae5a79c..532c1f0 100644
--- a/features/step_definitions/nearest.rb
+++ b/features/step_definitions/nearest.rb
@@ -1,7 +1,7 @@
 When /^I request nearest I should get$/ do |table|
   reprocess
   actual = []
-  OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
+  OSRMLoader.load(self,"#{prepared_file}.osrm") do
     table.hashes.each_with_index do |row,ri|
       in_node = find_node_by_name row['in']
       raise "*** unknown in-node '#{row['in']}" unless in_node
diff --git a/features/step_definitions/options.rb b/features/step_definitions/options.rb
index ac3bc99..e2e5066 100644
--- a/features/step_definitions/options.rb
+++ b/features/step_definitions/options.rb
@@ -1,6 +1,6 @@
 When(/^I run "osrm\-routed\s?(.*?)"$/) do |options|
   begin
-    Timeout.timeout(1) { run_bin 'osrm-routed', options }
+    Timeout.timeout(SHUTDOWN_TIMEOUT) { run_bin 'osrm-routed', options }
   rescue Timeout::Error
     raise "*** osrm-routed didn't quit. Maybe the --trial option wasn't used?"
   end
@@ -14,36 +14,44 @@ When(/^I run "osrm\-prepare\s?(.*?)"$/) do |options|
   run_bin 'osrm-prepare', options
 end
 
+When(/^I run "osrm\-datastore\s?(.*?)"$/) do |options|
+  run_bin 'osrm-datastore', options
+end
+
 Then /^it should exit with code (\d+)$/ do |code|
-  @exit_code.should == code.to_i
+  expect(@exit_code).to eq( code.to_i )
 end
 
 Then /^stdout should contain "(.*?)"$/ do |str|
-  @stdout.should include(str)
+  expect(@stdout).to include(str)
 end
 
 Then /^stderr should contain "(.*?)"$/ do |str|
-  @stderr.should include(str)
+  expect(@stderr).to include(str)
 end
 
 Then(/^stdout should contain \/(.*)\/$/) do |regex_str|
   regex = Regexp.new regex_str
-  @stdout.should =~ regex
+  expect(@stdout).to match( regex )
 end
 
 Then(/^stderr should contain \/(.*)\/$/) do |regex_str|
   regex = Regexp.new regex_str
-  @stderr.should =~ regex
+  expect(@stderr).to match( regex )
 end
 
 Then /^stdout should be empty$/ do
-  @stdout.should == ""
+  expect(@stdout).to eq("")
 end
 
 Then /^stderr should be empty$/ do
-  @stderr.should == ""
+  expect(@stderr).to eq("")
 end
 
 Then /^stdout should contain (\d+) lines?$/ do |lines|
-  @stdout.lines.count.should == lines.to_i
+  expect(@stdout.lines.count).to eq( lines.to_i )
+end
+
+Given (/^the query options$/) do |table|
+  @query_params = table.rows_hash
 end
diff --git a/features/step_definitions/requests.rb b/features/step_definitions/requests.rb
index 519a739..41257e5 100644
--- a/features/step_definitions/requests.rb
+++ b/features/step_definitions/requests.rb
@@ -1,14 +1,14 @@
 When /^I request \/(.*)$/ do |path|
   reprocess
-  OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
+  OSRMLoader.load(self,"#{prepared_file}.osrm") do
     @response = request_path path
   end
 end
 
 Then /^I should get a response/ do
-  @response.code.should == "200"
-  @response.body.should_not == nil
-  @response.body.should_not == ''
+  expect(@response.code).to eq("200")
+  expect(@response.body).not_to eq(nil)
+  expect(@response.body).not_to eq('')
 end
 
 Then /^response should be valid JSON$/ do
@@ -16,31 +16,31 @@ Then /^response should be valid JSON$/ do
 end
 
 Then /^response should be well-formed$/ do
-  @json['status'].class.should == Fixnum
+  expect(@json['status'].class).to eq(Fixnum)
 end
 
 Then /^status code should be (\d+)$/ do |code|
   @json = JSON.parse @response.body
-  @json['status'].should == code.to_i
+  expect(@json['status']).to eq(code.to_i)
 end
 
 Then /^status message should be "(.*?)"$/ do |message|
   @json = JSON.parse @response.body
-  @json['status_message'].should == message
+  expect(@json['status_message']).to eq(message)
 end
 
 Then /^response should be a well-formed route$/ do
   step "response should be well-formed"
-  @json['status_message'].class.should == String
-  @json['route_summary'].class.should == Hash
-  @json['route_geometry'].class.should == String
-  @json['route_instructions'].class.should == Array
-  @json['via_points'].class.should == Array
-  @json['via_indices'].class.should == Array
+  expect(@json['status_message'].class).to eq(String)
+  expect(@json['route_summary'].class).to eq(Hash)
+  expect(@json['route_geometry'].class).to eq(String)
+  expect(@json['route_instructions'].class).to eq(Array)
+  expect(@json['via_points'].class).to eq(Array)
+  expect(@json['via_indices'].class).to eq(Array)
 end
 
 Then /^"([^"]*)" should return code (\d+)$/ do |binary, code|
-  @process_error.is_a?(OSRMError).should == true
-  @process_error.process.should == binary
-  @process_error.code.to_i.should == code.to_i
-end
\ No newline at end of file
+  expect(@process_error.is_a?(OSRMError)).to eq(true)
+  expect(@process_error.process).to eq(binary)
+  expect(@process_error.code.to_i).to eq(code.to_i)
+end
diff --git a/features/step_definitions/routability.rb b/features/step_definitions/routability.rb
index 161171f..dcbde5a 100644
--- a/features/step_definitions/routability.rb
+++ b/features/step_definitions/routability.rb
@@ -4,7 +4,7 @@ def test_routability_row i
     a = Location.new @origin[0]+(1+WAY_SPACING*i)*@zoom, @origin[1]
     b = Location.new @origin[0]+(3+WAY_SPACING*i)*@zoom, @origin[1]
     r = {}
-    r[:response] = request_route direction=='forw' ? [a,b] : [b,a]
+    r[:response] = request_route (direction=='forw' ? [a,b] : [b,a]), @query_params
     r[:query] = @query
     r[:json] = JSON.parse(r[:response].body)
 
@@ -44,7 +44,7 @@ Then /^routability should be$/ do |table|
   if table.headers&["forw","backw","bothw"] == []
     raise "*** routability tabel must contain either 'forw', 'backw' or 'bothw' column"
   end
-  OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
+  OSRMLoader.load(self,"#{prepared_file}.osrm") do
     table.hashes.each_with_index do |row,i|
       output_row = row.dup
       attempts = []
@@ -54,11 +54,11 @@ Then /^routability should be$/ do |table|
         want = shortcuts_hash[row[direction]] || row[direction]     #expand shortcuts
         case want
         when '', 'x'
-          output_row[direction] = result[direction][:status].to_s
+          output_row[direction] = result[direction][:status] ? result[direction][:status].to_s : ''
         when /^\d+s/
-          output_row[direction] = "#{result[direction][:time]}s"
+          output_row[direction] = result[direction][:time] ? "#{result[direction][:time]}s" : ''
         when /^\d+ km\/h/
-          output_row[direction] = "#{result[direction][:speed]} km/h"
+          output_row[direction] = result[direction][:speed] ? "#{result[direction][:speed]} km/h" : ''
         else
           raise "*** Unknown expectation format: #{want}"
         end
diff --git a/features/step_definitions/routing.rb b/features/step_definitions/routing.rb
index 92b69ea..c25f5b7 100644
--- a/features/step_definitions/routing.rb
+++ b/features/step_definitions/routing.rb
@@ -1,13 +1,13 @@
 When /^I route I should get$/ do |table|
   reprocess
   actual = []
-  OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
+  OSRMLoader.load(self,"#{prepared_file}.osrm") do
     table.hashes.each_with_index do |row,ri|
       if row['request']
         got = {'request' => row['request'] }
         response = request_url row['request']
       else
-        params = {}
+        params = @query_params
         waypoints = []
         if row['from'] and row['to']
           node = find_node_by_name(row['from'])
@@ -104,22 +104,22 @@ When /^I route I should get$/ do |table|
             end
           end
           if table.headers.include? 'bearing'
-            got['bearing'] = bearings
+            got['bearing'] = instructions ? bearings : ''
           end
           if table.headers.include? 'compass'
-            got['compass'] = compasses
+            got['compass'] = instructions ? compasses : ''
           end
           if table.headers.include? 'turns'
-            got['turns'] = turns
+            got['turns'] = instructions ? turns : ''
           end
           if table.headers.include? 'modes'
-            got['modes'] = modes
+            got['modes'] = instructions ? modes : ''
           end
           if table.headers.include? 'times'
-            got['times'] = times
+            got['times'] = instructions ? times : ''
           end
           if table.headers.include? 'distances'
-            got['distances'] = distances
+            got['distances'] = instructions ? distances : ''
           end
         end
       end
diff --git a/features/step_definitions/timestamp.rb b/features/step_definitions/timestamp.rb
index 53d4083..df45615 100644
--- a/features/step_definitions/timestamp.rb
+++ b/features/step_definitions/timestamp.rb
@@ -2,6 +2,6 @@ Then /^I should get a valid timestamp/ do
   step "I should get a response"
   step "response should be valid JSON"
   step "response should be well-formed"
-  @json['timestamp'].class.should == String
-  @json['timestamp'].should == OSM_TIMESTAMP
+  expect(@json['timestamp'].class).to eq(String)
+  expect(@json['timestamp']).to eq("2000-01-01T00:00:00Z")
 end
diff --git a/features/support/data.rb b/features/support/data.rb
index 7c1ba88..1ff1861 100644
--- a/features/support/data.rb
+++ b/features/support/data.rb
@@ -1,6 +1,7 @@
 require 'OSM/objects'       #osmlib gem
 require 'OSM/Database'
 require 'builder'
+require 'fileutils'
 
 class Location
   attr_accessor :lon,:lat
@@ -11,6 +12,7 @@ class Location
   end
 end
 
+
 def set_input_format format
   raise '*** Input format must be eiter "osm" or "pbf"' unless ['pbf','osm'].include? format.to_s
   @input_format = format.to_s
@@ -21,7 +23,7 @@ def input_format
 end
 
 def sanitized_scenario_title
-  @sanitized_scenario_title ||= @scenario_title.gsub /[^0-9A-Za-z.\-]/, '_'
+  @sanitized_scenario_title ||= @scenario_title.to_s.gsub /[^0-9A-Za-z.\-]/, '_'
 end
 
 def set_grid_size meters
@@ -154,7 +156,10 @@ def reset_data
   end
   reset_profile
   reset_osm
-  @fingerprint = nil
+  @fingerprint_osm = nil
+  @fingerprint_extract = nil
+  @fingerprint_prepare = nil
+  @fingerprint_route = nil
 end
 
 def make_osm_id
@@ -204,20 +209,30 @@ def osm_str
   @osm_str
 end
 
+def osm_file
+  @osm_file ||= "#{DATA_FOLDER}/#{fingerprint_osm}"
+end
+
+def extracted_file
+  @extracted_file ||= "#{osm_file}_#{fingerprint_extract}"
+end
+
+def prepared_file
+  @prepared_file ||= "#{osm_file}_#{fingerprint_extract}_#{fingerprint_prepare}"
+end
+
 def write_osm
-  #write .oms file if needed
   Dir.mkdir DATA_FOLDER unless File.exist? DATA_FOLDER
-  @osm_file = "#{DATA_FOLDER}/#{sanitized_scenario_title}_#{fingerprint}"
-  unless File.exist?("#{@osm_file}.osm")
-    File.open( "#{@osm_file}.osm", 'w') {|f| f.write(osm_str) }
+  unless File.exist?("#{osm_file}.osm")
+    File.open( "#{osm_file}.osm", 'w') {|f| f.write(osm_str) }
   end
 end
 
 def convert_osm_to_pbf
-  unless File.exist?("#{@osm_file}.osm.pbf")
+  unless File.exist?("#{osm_file}.osm.pbf")
     log_preprocess_info
-    log "== Converting #{@osm_file}.osm to protobuffer format...", :preprocess
-    unless system "osmosis --read-xml #{@osm_file}.osm --write-pbf #{@osm_file}.osm.pbf omitmetadata=true >>#{PREPROCESS_LOG_FILE} 2>&1"
+    log "== Converting #{osm_file}.osm to protobuffer format...", :preprocess
+    unless system "osmosis --read-xml #{osm_file}.osm --write-pbf #{osm_file}.osm.pbf omitmetadata=true >>#{PREPROCESS_LOG_FILE} 2>&1"
       raise OsmosisError.new $?, "osmosis exited with code #{$?.exitstatus}"
     end
     log '', :preprocess
@@ -225,22 +240,27 @@ def convert_osm_to_pbf
 end
 
 def extracted?
-  File.exist?("#{@osm_file}.osrm") &&
-  File.exist?("#{@osm_file}.osrm.names") &&
-  File.exist?("#{@osm_file}.osrm.restrictions")
+  Dir.chdir TEST_FOLDER do
+    File.exist?("#{extracted_file}.osrm") &&
+    File.exist?("#{extracted_file}.osrm.names") &&
+    File.exist?("#{extracted_file}.osrm.restrictions")
+  end
 end
 
 def prepared?
-  File.exist?("#{@osm_file}.osrm.hsgr")
+  Dir.chdir TEST_FOLDER do
+    File.exist?("#{prepared_file}.osrm.hsgr")
+  end
 end
 
 def write_timestamp
-  File.open( "#{@osm_file}.osrm.timestamp", 'w') {|f| f.write(OSM_TIMESTAMP) }
+  File.open( "#{prepared_file}.osrm.timestamp", 'w') {|f| f.write(OSM_TIMESTAMP) }
 end
 
 def pbf?
   input_format=='pbf'
 end
+
 def write_input_data
   Dir.chdir TEST_FOLDER do
     write_osm
@@ -252,23 +272,43 @@ end
 def extract_data
   Dir.chdir TEST_FOLDER do
     log_preprocess_info
-    log "== Extracting #{@osm_file}.osm...", :preprocess
-    unless system "#{BIN_PATH}/osrm-extract #{@osm_file}.osm#{'.pbf' if pbf?} --profile #{PROFILES_PATH}/#{@profile}.lua >>#{PREPROCESS_LOG_FILE} 2>&1"
+    log "== Extracting #{osm_file}.osm...", :preprocess
+    unless system "#{BIN_PATH}/osrm-extract #{osm_file}.osm#{'.pbf' if pbf?} --profile #{PROFILES_PATH}/#{@profile}.lua >>#{PREPROCESS_LOG_FILE} 2>&1"
       log "*** Exited with code #{$?.exitstatus}.", :preprocess
       raise ExtractError.new $?.exitstatus, "osrm-extract exited with code #{$?.exitstatus}."
     end
-    log '', :preprocess
+    begin
+      ["osrm","osrm.names","osrm.restrictions"].each do |file|
+        File.rename "#{osm_file}.#{file}", "#{extracted_file}.#{file}"
+      end
+    rescue Exception => e
+      raise FileError.new nil, "failed to rename data file after extracting."
+    end
   end
 end
 
 def prepare_data
   Dir.chdir TEST_FOLDER do
     log_preprocess_info
-    log "== Preparing #{@osm_file}.osm...", :preprocess
-    unless system "#{BIN_PATH}/osrm-prepare #{@osm_file}.osrm  --profile #{PROFILES_PATH}/#{@profile}.lua >>#{PREPROCESS_LOG_FILE} 2>&1"
+    log "== Preparing #{extracted_file}.osm...", :preprocess
+    unless system "#{BIN_PATH}/osrm-prepare #{extracted_file}.osrm  --profile #{PROFILES_PATH}/#{@profile}.lua >>#{PREPROCESS_LOG_FILE} 2>&1"
       log "*** Exited with code #{$?.exitstatus}.", :preprocess
       raise PrepareError.new $?.exitstatus, "osrm-prepare exited with code #{$?.exitstatus}."
     end
+    begin
+      ["osrm.hsgr","osrm.fileIndex","osrm.geometry","osrm.nodes","osrm.ramIndex"].each do |file|
+        File.rename "#{extracted_file}.#{file}", "#{prepared_file}.#{file}"
+      end
+    rescue Exception => e
+      raise FileError.new nil, "failed to rename data file after preparing."
+    end
+    begin
+      ["osrm.names","osrm.edges","osrm.restrictions"].each do |file|
+        FileUtils.cp "#{extracted_file}.#{file}", "#{prepared_file}.#{file}"
+      end
+    rescue Exception => e
+      raise FileError.new nil, "failed to copy data file after preparing."
+    end
     log '', :preprocess
   end
 end
diff --git a/features/support/env.rb b/features/support/env.rb
index a6a9ca0..a01341d 100644
--- a/features/support/env.rb
+++ b/features/support/env.rb
@@ -1,15 +1,15 @@
 require 'rspec/expectations'
 
+
 DEFAULT_PORT = 5000
 DEFAULT_TIMEOUT = 2
-
 ROOT_FOLDER = Dir.pwd
 OSM_USER = 'osrm'
 OSM_GENERATOR = 'osrm-test'
 OSM_UID = 1
 TEST_FOLDER = File.join ROOT_FOLDER, 'test'
 DATA_FOLDER = 'cache'
-OSM_TIMESTAMP = '2000-00-00T00:00:00Z'
+OSM_TIMESTAMP = '2000-01-01T00:00:00Z'
 DEFAULT_SPEEDPROFILE = 'bicycle'
 WAY_SPACING = 100
 DEFAULT_GRID_SIZE = 100   #meters
@@ -17,6 +17,26 @@ PROFILES_PATH = File.join ROOT_FOLDER, 'profiles'
 BIN_PATH = File.join ROOT_FOLDER, 'build'
 DEFAULT_INPUT_FORMAT = 'osm'
 DEFAULT_ORIGIN = [1,1]
+LAUNCH_TIMEOUT = 1
+SHUTDOWN_TIMEOUT = 10
+DEFAULT_LOAD_METHOD = 'datastore'
+OSRM_ROUTED_LOG_FILE = 'osrm-routed.log'
+
+if ENV['OS']==/Windows.*/ then
+  TERMSIGNAL='TERM'
+else
+  TERMSIGNAL=9
+end
+
+
+def log_time_and_run cmd
+  log_time cmd
+  `#{cmd}`
+end
+
+def log_time cmd
+  puts "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S:%L')}] #{cmd}"
+end
 
 
 puts "Ruby version #{RUBY_VERSION}"
@@ -44,6 +64,7 @@ unless File.exists? TEST_FOLDER
   raise "*** Test folder #{TEST_FOLDER} doesn't exist."
 end
 
+
 if ENV['OS']=~/Windows.*/ then
    EXE='.exe'
    QQ='"'
@@ -53,5 +74,12 @@ else
 end
 
 AfterConfiguration do |config|
+  if OSRMLoader::OSRMBaseLoader.new.osrm_up?
+    raise "*** osrm-routed is already running."
+  end
   clear_log_files
-end
\ No newline at end of file
+end
+
+at_exit do
+  OSRMLoader::OSRMBaseLoader.new.shutdown
+end
diff --git a/features/support/exceptions.rb b/features/support/exceptions.rb
index 2901bfe..02f59d3 100644
--- a/features/support/exceptions.rb
+++ b/features/support/exceptions.rb
@@ -31,6 +31,12 @@ class OSRMError < StandardError
   end
 end
 
+class FileError < OSRMError
+  def initialize code, msg
+    super 'fileutil', code, msg, PREPROCESS_LOG_FILE, 5
+  end
+end
+
 class OsmosisError < OSRMError
   def initialize code, msg
     super 'osmosis', code, msg, PREPROCESS_LOG_FILE, 40
diff --git a/features/support/hash.rb b/features/support/hash.rb
index 197cd42..6980b66 100644
--- a/features/support/hash.rb
+++ b/features/support/hash.rb
@@ -32,18 +32,32 @@ def lua_lib_hash
 end
 
 def bin_extract_hash
-  bin_extract_hash ||= hash_of_files "#{BIN_PATH}/osrm-extract#{EXE}"
+  @bin_extract_hash ||= hash_of_files "#{BIN_PATH}/osrm-extract#{EXE}"
+  @bin_extract_hash
 end
 
 def bin_prepare_hash
-  bin_prepare_hash ||= hash_of_files "#{BIN_PATH}/osrm-prepare#{EXE}"
+  @bin_prepare_hash ||= hash_of_files "#{BIN_PATH}/osrm-prepare#{EXE}"
 end
 
 def bin_routed_hash
-  bin_routed_hash ||= hash_of_files "#{BIN_PATH}/osrm-routed#{EXE}"
+  @bin_routed_hash ||= hash_of_files "#{BIN_PATH}/osrm-routed#{EXE}"
 end
 
-#combine state of data, profile and binaries into a hash that identifies the exact test scenario
-def fingerprint
-  @fingerprint ||= Digest::SHA1.hexdigest "#{bin_extract_hash}-#{bin_prepare_hash}-#{bin_routed_hash}-#{profile_hash}-#{lua_lib_hash}-#{osm_hash}"
+# combine state of data, profile and binaries into a hashes that identifies
+# the exact test situation at different stages, so we can later skip steps when possible.
+def fingerprint_osm
+  @fingerprint_osm ||= Digest::SHA1.hexdigest "#{osm_hash}"
 end
+
+def fingerprint_extract
+  @fingerprint_extract ||= Digest::SHA1.hexdigest "#{profile_hash}-#{lua_lib_hash}-#{bin_extract_hash}"
+end
+
+def fingerprint_prepare
+  @fingerprint_prepare ||= Digest::SHA1.hexdigest "#{bin_prepare_hash}"
+end
+
+def fingerprint_route
+  @fingerprint_route ||= Digest::SHA1.hexdigest "#{bin_routed_hash}"
+end
\ No newline at end of file
diff --git a/features/support/hooks.rb b/features/support/hooks.rb
index 4c58a17..3370142 100644
--- a/features/support/hooks.rb
+++ b/features/support/hooks.rb
@@ -1,7 +1,9 @@
 
 STRESS_TIMEOUT = 300
 
+
 Before do |scenario|
+
   # feature name
   case scenario
     when Cucumber::Ast::Scenario
@@ -18,13 +20,15 @@ Before do |scenario|
       @scenario_title = scenario.scenario_outline.name
   end
 
-
+  @load_method  = DEFAULT_LOAD_METHOD
+  @query_params = {}
   @scenario_time = Time.now.strftime("%Y-%m-%dT%H:%m:%SZ")
   reset_data
   @has_logged_preprocess_info = false
   @has_logged_scenario_info = false
   set_grid_size DEFAULT_GRID_SIZE
   set_origin DEFAULT_ORIGIN
+
 end
 
 Around('@stress') do |scenario, block|
diff --git a/features/support/launch.rb b/features/support/launch.rb
index e55867a..0f983c1 100644
--- a/features/support/launch.rb
+++ b/features/support/launch.rb
@@ -1,95 +1,137 @@
 require 'socket'
 require 'open3'
+require 'json'
 
-if ENV['OS']==/Windows.*/ then
-  TERMSIGNAL='TERM'
-else
-  TERMSIGNAL=9
-end
+# Only one isntance of osrm-routed is ever launched, to avoid collisions.
+# The default is to keep osrm-routed running and load data with datastore.
+# however, osrm-routed it shut down and relaunched for each scenario thats 
+# loads data directly.
+class OSRMLoader
 
-OSRM_ROUTED_LOG_FILE = 'osrm-routed.log'
+  class OSRMBaseLoader
+    @@pid = nil
 
-class OSRMBackgroundLauncher
-  def initialize input_file, &block
-    @input_file = input_file
-    Dir.chdir TEST_FOLDER do
-      begin
-        launch
-        yield
-      ensure
-        shutdown
+    def launch
+      Timeout.timeout(LAUNCH_TIMEOUT) do
+        osrm_up
+        wait_for_connection
       end
+    rescue Timeout::Error
+      raise RoutedError.new "Launching osrm-routed timed out."
     end
-  end
 
-  private
+    def shutdown
+      Timeout.timeout(SHUTDOWN_TIMEOUT) do
+        osrm_down
+      end
+    rescue Timeout::Error
+      kill
+      raise RoutedError.new "Shutting down osrm-routed timed out."
+    end
 
-  def launch
-    Timeout.timeout(OSRM_TIMEOUT) do
-      osrm_up
-      wait_for_connection
+    def osrm_up?
+      if @@pid
+        begin
+          if Process.waitpid(@@pid, Process::WNOHANG) then
+             false
+          else
+             true
+          end
+        rescue Errno::ESRCH, Errno::ECHILD
+          false
+        end
+      end
     end
-  rescue Timeout::Error
-    raise RoutedError.new "Launching osrm-routed timed out."
-  end
 
-  def shutdown
-    Timeout.timeout(OSRM_TIMEOUT) do
-      osrm_down
+    def osrm_down
+      if @@pid
+        Process.kill TERMSIGNAL, @@pid
+        wait_for_shutdown
+        @@pid = nil
+      end
     end
-  rescue Timeout::Error
-    kill
-    raise RoutedError.new "Shutting down osrm-routed timed out."
-  end
 
+    def kill
+      if @@pid
+        Process.kill 'KILL', @@pid
+      end
+    end
 
-  def osrm_up?
-    if @pid
-      begin
-        if Process.waitpid(@pid, Process::WNOHANG) then
-           false
-        else
-           true
+    def wait_for_connection
+      while true
+        begin
+          socket = TCPSocket.new('127.0.0.1', OSRM_PORT)
+          return
+        rescue Errno::ECONNREFUSED
+          sleep 0.1
         end
-      rescue Errno::ESRCH, Errno::ECHILD
-        false
       end
     end
-  end
 
-  def osrm_up
-    return if osrm_up?
-    @pid = Process.spawn("#{BIN_PATH}/osrm-routed #{@input_file} --port #{OSRM_PORT}",:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE)
-    Process.detach(@pid)    # avoid zombie processes
+    def wait_for_shutdown
+      while osrm_up?
+        sleep 0.01
+      end
+    end
   end
 
-  def osrm_down
-    if @pid
-      Process.kill TERMSIGNAL, @pid
-      wait_for_shutdown
+  # looading data directly when lauching osrm-routed:
+  # under this scheme, osmr-routed is launched and shutdown for each scenario,
+  # and osrm-datastore is not used
+  class OSRMDirectLoader < OSRMBaseLoader
+    def load world, input_file, &block
+      @world = world
+      @input_file = input_file
+      Dir.chdir TEST_FOLDER do
+        shutdown
+        launch
+        yield
+        shutdown
+      end
     end
-  end
 
-  def kill
-    if @pid
-      Process.kill 'KILL', @pid
+    def osrm_up
+      return if @@pid
+      @@pid = Process.spawn("#{BIN_PATH}/osrm-routed #{@input_file} --port #{OSRM_PORT}",:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE)
+      Process.detach(@@pid)    # avoid zombie processes
     end
+
   end
 
-  def wait_for_connection
-    while true
-      begin
-        socket = TCPSocket.new('127.0.0.1', OSRM_PORT)
-        return
-      rescue Errno::ECONNREFUSED
-        sleep 0.1
+  # looading data with osrm-datastore:
+  # under this scheme, osmr-routed is launched once and kept running for all scenarios,
+  # and osrm-datastore is used to load data for each scenario
+  class OSRMDatastoreLoader < OSRMBaseLoader
+    def load world, input_file, &block
+      @world = world
+      @input_file = input_file
+      Dir.chdir TEST_FOLDER do
+        load_data
+        launch unless @@pid
+        yield
       end
     end
+
+    def load_data
+      run_bin "osrm-datastore", @input_file
+    end
+
+    def osrm_up
+      return if osrm_up?
+      @@pid = Process.spawn("#{BIN_PATH}/osrm-routed --sharedmemory=1 --port #{OSRM_PORT}",:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE)
+      Process.detach(@@pid)    # avoid zombie processes
+    end
   end
 
-  def wait_for_shutdown
-    while osrm_up?
-      sleep 0.1
+  def self.load world, input_file, &block
+    method = world.instance_variable_get "@load_method"
+    if method == 'datastore'
+      OSRMDatastoreLoader.new.load world, input_file, &block
+    elsif method == 'directly'
+      OSRMDirectLoader.new.load world, input_file, &block
+    else
+      raise "*** Unknown load method '#{method}'"
     end
   end
+
 end
diff --git a/features/support/log.rb b/features/support/log.rb
index e5d34cc..8e6f9c1 100644
--- a/features/support/log.rb
+++ b/features/support/log.rb
@@ -29,7 +29,10 @@ def log_scenario_fail_info
   log "========================================="
   log "Failed scenario: #{@scenario_title}"
   log "Time: #{@scenario_time}"
-  log "Fingerprint: #{@fingerprint}"
+  log "Fingerprint osm stage: #{@fingerprint_osm}"
+  log "Fingerprint extract stage: #{@fingerprint_extract}"
+  log "Fingerprint prepare stage: #{@fingerprint_prepare}"
+  log "Fingerprint route stage: #{@fingerprint_route}"
   log "Profile: #{@profile}"
   log
   log '```xml' #so output can be posted directly to github comment fields
@@ -41,6 +44,7 @@ def log_scenario_fail_info
 end
 
 def log_fail expected,got,attempts
+  return
   log_scenario_fail_info
   log "== "
   log "Expected: #{expected}"
diff --git a/features/support/route.rb b/features/support/route.rb
index 745edc0..a8c7822 100644
--- a/features/support/route.rb
+++ b/features/support/route.rb
@@ -43,6 +43,11 @@ def request_route waypoints, params={}
   request_path "viaroute", waypoints, defaults.merge(params)
 end
 
+def request_table waypoints, params={}
+  defaults = { 'output' => 'json' }
+  request_path "table", waypoints, defaults.merge(params)
+end
+
 def got_route? response
   if response.code == "200" && !response.body.empty?
     json = JSON.parse response.body
diff --git a/features/support/run.rb b/features/support/run.rb
index 794050a..42dc597 100644
--- a/features/support/run.rb
+++ b/features/support/run.rb
@@ -1,17 +1,27 @@
 def run_bin bin, options
   Dir.chdir TEST_FOLDER do
     opt = options.dup
-    
-    if opt.include? '{base}'
-      raise "*** {base} is missing" unless @osm_file
-      opt.gsub! "{base}", "#{@osm_file}" 
+
+    if opt.include? '{osm_base}'
+      raise "*** {osm_base} is missing" unless osm_file
+      opt.gsub! "{osm_base}", "#{osm_file}" 
+    end
+
+    if opt.include? '{extracted_base}'
+      raise "*** {extracted_base} is missing" unless extracted_file
+      opt.gsub! "{extracted_base}", "#{extracted_file}" 
     end
 
+    if opt.include? '{prepared_base}'
+      raise "*** {prepared_base} is missing" unless prepared_file
+      opt.gsub! "{prepared_base}", "#{prepared_file}" 
+    end
     if opt.include? '{profile}'
       opt.gsub! "{profile}", "#{PROFILES_PATH}/#{@profile}.lua" 
     end
 
-    @stdout = `#{QQ}#{BIN_PATH}/#{bin}#{EXE}#{QQ} #{opt} 2>error.log`
+    cmd = "#{QQ}#{BIN_PATH}/#{bin}#{EXE}#{QQ} #{opt} 2>error.log"
+    @stdout = `#{cmd}`
     @stderr = File.read 'error.log'
     @exit_code = $?.exitstatus
   end
diff --git a/features/testbot/bad.feature b/features/testbot/bad.feature
index f0f3cfa..d7e3c95 100644
--- a/features/testbot/bad.feature
+++ b/features/testbot/bad.feature
@@ -1,4 +1,4 @@
- at routing @bad
+ at routing @bad @testbot
 Feature: Handle bad data in a graceful manner
 
     Background:
diff --git a/features/testbot/basic.feature b/features/testbot/basic.feature
index 4164319..599b062 100644
--- a/features/testbot/basic.feature
+++ b/features/testbot/basic.feature
@@ -1,4 +1,4 @@
- at routing @basic
+ at routing @basic @testbot
 Feature: Basic Routing
 
     Background:
diff --git a/features/testbot/bearing.feature b/features/testbot/bearing.feature
index c306af9..9b3dc4e 100644
--- a/features/testbot/bearing.feature
+++ b/features/testbot/bearing.feature
@@ -1,4 +1,4 @@
- at routing @bearing
+ at routing @bearing @testbot
 Feature: Compass bearing
 
     Background:
diff --git a/features/testbot/bearing_param.feature b/features/testbot/bearing_param.feature
index e9db873..810f690 100644
--- a/features/testbot/bearing_param.feature
+++ b/features/testbot/bearing_param.feature
@@ -1,4 +1,4 @@
- at routing @bearing_param @todo
+ at routing @bearing_param @todo @testbot
 Feature: Bearing parameter
 
     Background:
diff --git a/features/testbot/compression.feature b/features/testbot/compression.feature
new file mode 100644
index 0000000..146ad63
--- /dev/null
+++ b/features/testbot/compression.feature
@@ -0,0 +1,22 @@
+ at routing @graph @testbot
+Feature: Geometry Compression
+
+    Background:
+        Given the profile "testbot"
+
+    Scenario: Compressed segments have correct order
+        Given the node map
+            | a |   | d |   |   |   | h |
+            | b |   |   |   | e |   | f |
+            |   | c |   |   |   |   | g |
+
+        And the ways
+            | nodes  |
+            | abcdef |
+            | fh     |
+            | fg     |
+
+        When I route I should get
+            | from | to | route   | distance | speed   |
+            | b    | e  | abcdef  | 589m     | 35 km/h |
+            | e    | b  | abcdef  | 589m     | 35 km/h |
diff --git a/features/testbot/datastore.feature b/features/testbot/datastore.feature
new file mode 100644
index 0000000..568ae7a
--- /dev/null
+++ b/features/testbot/datastore.feature
@@ -0,0 +1,31 @@
+ at routing @datastore @testbot
+Feature: Temporary tests related to osrm-datastore
+
+    Background:
+        Given the profile "testbot"
+
+    Scenario: Scenario ab
+        Given the node map
+            | a | b |
+
+        And the ways
+            | nodes |
+            | ab    |
+
+        When I route I should get
+            | from | to | route |
+            | a    | b  | ab    |
+            | b    | a  | ab    |
+
+    Scenario: Scenaria xy
+        Given the node map
+            | x | y |
+
+        And the ways
+            | nodes |
+            | xy    |
+
+        When I route I should get
+            | from | to | route |
+            | x    | y  | xy    |
+            | y    | x  | xy    |
diff --git a/features/testbot/distance.feature b/features/testbot/distance.feature
index f9f166b..55b5f64 100644
--- a/features/testbot/distance.feature
+++ b/features/testbot/distance.feature
@@ -1,4 +1,4 @@
- at routing @distance
+ at routing @distance @testbot
 Feature: Distance calculation
 
     Background:
@@ -145,7 +145,7 @@ Feature: Distance calculation
             | a    | h  | abcdefgh | 70m +-14 |
 
     Scenario: Geometric distances
-        Given a grid size of 1000 meters
+        Given a grid size of 100 meters
         Given the node map
             | v | w | y | a | b | c | d |
             | u |   |   |   |   |   | e |
@@ -184,30 +184,30 @@ Feature: Distance calculation
 
         When I route I should get
             | from | to | route | distance  |
-            | x    | a  | xa    | 3000m +-2 |
-            | x    | b  | xb    | 3162m +-2 |
-            | x    | c  | xc    | 3606m +-2 |
-            | x    | d  | xd    | 4243m +-2 |
-            | x    | e  | xe    | 3606m +-2 |
-            | x    | f  | xf    | 3162m +-2 |
-            | x    | g  | xg    | 3000m +-2 |
-            | x    | h  | xh    | 3162m +-2 |
-            | x    | i  | xi    | 3606m +-2 |
-            | x    | j  | xj    | 4243m +-2 |
-            | x    | k  | xk    | 3606m +-2 |
-            | x    | l  | xl    | 3162m +-2 |
-            | x    | m  | xm    | 3000m +-2 |
-            | x    | n  | xn    | 3162m +-2 |
-            | x    | o  | xo    | 3606m +-2 |
-            | x    | p  | xp    | 4243m +-2 |
-            | x    | q  | xq    | 3606m +-2 |
-            | x    | r  | xr    | 3162m +-2 |
-            | x    | s  | xs    | 3000m +-2 |
-            | x    | t  | xt    | 3162m +-2 |
-            | x    | u  | xu    | 3606m +-2 |
-            | x    | v  | xv    | 4243m +-2 |
-            | x    | w  | xw    | 3606m +-2 |
-            | x    | y  | xy    | 3162m +-2 |
+            | x    | a  | xa    | 300m +-2 |
+            | x    | b  | xb    | 316m +-2 |
+            | x    | c  | xc    | 360m +-2 |
+            | x    | d  | xd    | 424m +-2 |
+            | x    | e  | xe    | 360m +-2 |
+            | x    | f  | xf    | 316m +-2 |
+            | x    | g  | xg    | 300m +-2 |
+            | x    | h  | xh    | 316m +-2 |
+            | x    | i  | xi    | 360m +-2 |
+            | x    | j  | xj    | 424m +-2 |
+            | x    | k  | xk    | 360m +-2 |
+            | x    | l  | xl    | 316m +-2 |
+            | x    | m  | xm    | 300m +-2 |
+            | x    | n  | xn    | 316m +-2 |
+            | x    | o  | xo    | 360m +-2 |
+            | x    | p  | xp    | 424m +-2 |
+            | x    | q  | xq    | 360m +-2 |
+            | x    | r  | xr    | 316m +-2 |
+            | x    | s  | xs    | 300m +-2 |
+            | x    | t  | xt    | 316m +-2 |
+            | x    | u  | xu    | 360m +-2 |
+            | x    | v  | xv    | 424m +-2 |
+            | x    | w  | xw    | 360m +-2 |
+            | x    | y  | xy    | 316m +-2 |
 
     @maze
     Scenario: Distance of a maze of short segments
diff --git a/features/testbot/distance_matrix.feature b/features/testbot/distance_matrix.feature
new file mode 100644
index 0000000..390ae98
--- /dev/null
+++ b/features/testbot/distance_matrix.feature
@@ -0,0 +1,102 @@
+ at matrix @testbot
+Feature: Basic Distance Matrix
+# note that results are travel time, specified in 1/10th of seconds
+# since testbot uses a default speed of 100m/10s, the result matches
+# the number of meters as long as the way type is the default 'primary'
+
+    Background:
+        Given the profile "testbot"
+
+    Scenario: Testbot - Travel time matrix of minimal network
+        Given the node map
+            | a | b |
+
+        And the ways
+            | nodes |
+            | ab    |
+
+        When I request a travel time matrix I should get
+            |   | a   | b   |
+            | a | 0   | 100 |
+            | b | 100 | 0   |
+
+    Scenario: Testbot - Travel time matrix with different way speeds
+        Given the node map
+            | a | b | c | d |
+
+        And the ways
+            | nodes | highway   |
+            | ab    | primary   |
+            | bc    | secondary |
+            | cd    | tertiary  |
+            
+        When I request a travel time matrix I should get
+            |   | a   | b   | c   | d   |
+            | a | 0   | 100 | 300 | 600 |
+            | b | 100 | 0   | 200 | 500 |
+            | c | 300 | 200 | 0   | 300 |
+            | d | 600 | 500 | 300 | 0   |
+
+    Scenario: Testbot - Travel time matrix with fuzzy match
+        Given the node map
+            | a | b |
+
+        And the ways
+            | nodes |
+            | ab    |
+
+        When I request a travel time matrix I should get
+            |   | a       | b        |
+            | a | 0       | 95 +- 10 |
+            | b | 95 ~10% | 0        |
+    
+    Scenario: Testbot - Travel time matrix of small grid
+        Given the node map
+            | a | b | c |
+            | d | e | f |
+
+        And the ways
+            | nodes |
+            | abc   |
+            | def   |
+            | ad    |
+            | be    |
+            | cf    |
+
+        When I request a travel time matrix I should get
+            |   | a   | b   | e   | f   |
+            | a | 0   | 100 | 200 | 300 |
+            | b | 100 | 0   | 100 | 200 |
+            | e | 200 | 100 | 0   | 100 |
+            | f | 300 | 200 | 100 | 0   |
+
+    Scenario: Testbot - Travel time matrix of network with unroutable parts
+        Given the node map
+            | a | b |
+
+        And the ways
+            | nodes | oneway |
+            | ab    | yes    |
+
+        When I request a travel time matrix I should get
+            |   | a  | b   |
+            | a | 0  | 100 |
+            | b |    | 0   |
+    
+    Scenario: Testbot - Travel time matrix of network with oneways
+        Given the node map
+            | x | a | b | y |
+            |   | d | e |   |
+
+        And the ways
+            | nodes | oneway |
+            | abeda | yes    |
+            | xa    |        |
+            | by    |        |
+
+        When I request a travel time matrix I should get
+            |   | x   | y   | d   | e   |
+            | x | 0   | 300 | 400 | 300 |
+            | y | 500 | 0   | 300 | 200 |
+            | d | 200 | 300 | 0   | 300 |
+            | e | 300 | 400 | 100 | 0   |
diff --git a/features/testbot/fastest.feature b/features/testbot/fastest.feature
index 9a5cf24..8c24a53 100644
--- a/features/testbot/fastest.feature
+++ b/features/testbot/fastest.feature
@@ -1,4 +1,4 @@
- at routing @fastest
+ at routing @fastest @testbot
 Feature: Choosing fastest route
 
     Background:
diff --git a/features/testbot/geometry.feature b/features/testbot/geometry.feature
index 553af93..8b38c06 100644
--- a/features/testbot/geometry.feature
+++ b/features/testbot/geometry.feature
@@ -1,4 +1,4 @@
- at routing
+ at routing @testbot
 Feature: Retrieve geometry
 
     Background: Use some profile
diff --git a/features/testbot/graph.feature b/features/testbot/graph.feature
index a870106..adff998 100644
--- a/features/testbot/graph.feature
+++ b/features/testbot/graph.feature
@@ -1,4 +1,4 @@
- at routing @graph
+ at routing @graph @testbot
 Feature: Basic Routing
 #Test the input data descibed on https://github.com/DennisOSRM/Project-OSRM/wiki/Graph-representation
 
@@ -19,3 +19,22 @@ Feature: Basic Routing
         When I route I should get
             | from | to | route   |
             | a    | e  | abc,dce |
+
+    Scenario: Turn instructions on compressed road network geometry
+        Given the node map
+            | x | a |   |   |
+            |   | b |   |   |
+            | f |   |   | e |
+            |   |   |   |   |
+            |   |   |   |   |
+            | y | c |   | d |
+
+        And the ways
+            | nodes  | name  |
+            | xa     | first |
+            | abcdef | compr |
+            | fy     | last  |
+
+        When I route I should get
+            | from | to | route            | turns                       |
+            | x    | y  | first,compr,last | head,right,left,destination |
diff --git a/features/testbot/load.feature b/features/testbot/load.feature
new file mode 100644
index 0000000..cf5e470
--- /dev/null
+++ b/features/testbot/load.feature
@@ -0,0 +1,63 @@
+ at routing @load @testbot
+Feature: Ways of loading data
+# Several scenarios that change between direct/datastore makes
+# it easier to check that the test framework behaves as expected.
+
+    Background:
+        Given the profile "testbot"
+
+    Scenario: Load data with datastore - ab
+        Given data is loaded with datastore
+        Given the node map
+            | a | b |
+
+        And the ways
+            | nodes |
+            | ab    |
+
+        When I route I should get
+            | from | to | route |
+            | a    | b  | ab    |
+            | b    | a  | ab    |
+
+    Scenario: Load data directly - st
+        Given data is loaded directly
+        Given the node map
+            | s | t |
+
+        And the ways
+            | nodes |
+            | st    |
+
+        When I route I should get
+            | from | to | route |
+            | s    | t  | st    |
+            | t    | s  | st    |
+
+    Scenario: Load data datstore - xy
+        Given data is loaded with datastore
+        Given the node map
+            | x | y |
+
+        And the ways
+            | nodes |
+            | xy    |
+
+        When I route I should get
+            | from | to | route |
+            | x    | y  | xy    |
+            | y    | x  | xy    |
+
+    Scenario: Load data directly - cd
+        Given data is loaded directly
+        Given the node map
+            | c | d |
+
+        And the ways
+            | nodes |
+            | cd    |
+
+        When I route I should get
+            | from | to | route |
+            | c    | d  | cd    |
+            | d    | c  | cd    |
diff --git a/features/testbot/loop.feature b/features/testbot/loop.feature
index eb5b45e..fe898ec 100644
--- a/features/testbot/loop.feature
+++ b/features/testbot/loop.feature
@@ -1,4 +1,4 @@
- at routing @726
+ at routing @726 @testbot
 Feature: Avoid weird loops caused by rounding errors
 
     Background:
@@ -73,6 +73,6 @@ Feature: Avoid weird loops caused by rounding errors
             | cf    | secondary |
 
         When I route I should get
-            | waypoints | route          | turns                                  |
-            | a,2,d     | ab,be,ef,cf,cd | head,left,right,right,left,destination |
-            | a,1,d     | ab,be,ef,cf,cd | head,left,right,right,left,destination |
+            | waypoints | route             | turns                                      |
+            | a,2,d     | ab,be,ef,ef,cf,cd | head,left,right,via,right,left,destination |
+            | a,1,d     | ab,be,ef,ef,cf,cd | head,left,right,via,right,left,destination |
diff --git a/features/testbot/mode.feature b/features/testbot/mode.feature
index bcc087e..11fe83a 100644
--- a/features/testbot/mode.feature
+++ b/features/testbot/mode.feature
@@ -1,26 +1,227 @@
 @routing @testbot @mode
-Feature: Testbot - Mode flag
+Feature: Testbot - Travel mode
+
+# testbot modes:
+# 1 normal
+# 2 route
+# 3 river downstream
+# 4 river upstream
+# 5 steps down
+# 6 steps up
 
     Background:
-        Given the profile "testbot"
+       Given the profile "testbot"
+        
+    Scenario: Testbot - Modes in each direction, different forward/backward speeds
+        Given the node map
+            |   | 0 | 1 |   |
+            | a |   |   | b |
+
+        And the ways
+            | nodes | highway | oneway |
+            | ab    | river   |        |
+
+        When I route I should get
+            | from | to | route | modes |
+            | a    | 0  | ab    | 3     |
+            | a    | b  | ab    | 3     |
+            | 0    | 1  | ab    | 3     |
+            | 0    | b  | ab    | 3     |
+            | b    | 1  | ab    | 4     |
+            | b    | a  | ab    | 4     |
+            | 1    | 0  | ab    | 4     |
+            | 1    | a  | ab    | 4     |
+
+    Scenario: Testbot - Modes in each direction, same forward/backward speeds
+        Given the node map
+            |   | 0 | 1 |   |
+            | a |   |   | b |
+
+        And the ways
+            | nodes | highway |
+            | ab    | steps   |
+
+        When I route I should get
+            | from | to | route | modes | time    |
+            | 0    | 1  | ab    | 5     | 60s +-1 |
+            | 1    | 0  | ab    | 6     | 60s +-1 |
+
+    @oneway
+    Scenario: Testbot - Modes for oneway, different forward/backward speeds
+        Given the node map
+            | a | b |
 
-    @todo
-    Scenario: Bike - Mode
+        And the ways
+            | nodes | highway | oneway |
+            | ab    | river   | yes    |
+
+        When I route I should get
+            | from | to | route | modes |
+            | a    | b  | ab    | 3     |
+            | b    | a  |       |       |
+
+    @oneway
+    Scenario: Testbot - Modes for oneway, same forward/backward speeds
+        Given the node map
+            | a | b |
+
+        And the ways
+            | nodes | highway | oneway |
+            | ab    | steps   | yes    |
+
+        When I route I should get
+            | from | to | route | modes |
+            | a    | b  | ab    | 5     |
+            | b    | a  |       |       |
+
+    @oneway
+    Scenario: Testbot - Modes for reverse oneway, different forward/backward speeds
         Given the node map
-            | a | b |   |
-            |   | c | d |
+            | a | b |
 
         And the ways
+            | nodes | highway | oneway |
+            | ab    | river   | -1     |
+
+        When I route I should get
+            | from | to | route | modes |
+            | a    | b  |       |       |
+            | b    | a  | ab    | 4     |
+
+    @oneway
+    Scenario: Testbot - Modes for reverse oneway, same forward/backward speeds
+        Given the node map
+            | a | b |
+
+        And the ways
+            | nodes | highway | oneway |
+            | ab    | steps   | -1     |
+
+        When I route I should get
+            | from | to | route | modes |
+            | a    | b  |       |       |
+            | b    | a  | ab    | 6     |
+
+    @via
+    Scenario: Testbot - Mode should be set at via points
+        Given the node map
+            | a | 1 | b |
+
+        And the ways
+            | nodes | highway |
+            | ab    | river   |
+
+        When I route I should get
+            | waypoints | route | modes | turns                |
+            | a,1,b     | ab,ab | 3,3   | head,via,destination |
+            | b,1,a     | ab,ab | 4,4   | head,via,destination |
+
+    Scenario: Testbot - Starting at a tricky node
+       Given the node map
+            |  | a |  |   |   |
+            |  |   |  | b | c |
+
+       And the ways
+            | nodes | highway |
+            | ab    | river   |
+            | bc    | primary |
+
+       When I route I should get
+            | from | to | route | modes |
+            | b    | a  | ab    | 4     |
+
+    Scenario: Testbot - Mode changes on straight way without name change
+       Given the node map
+            | a | 1 | b | 2 | c |
+
+       And the ways
+            | nodes | highway | name   |
+            | ab    | primary | Avenue |
+            | bc    | river   | Avenue |
+
+       When I route I should get
+            | from | to | route         | modes | turns                     |
+            | a    | c  | Avenue,Avenue | 1,3   | head,straight,destination |
+            | c    | a  | Avenue,Avenue | 4,1   | head,straight,destination |
+            | 1    | 2  | Avenue,Avenue | 1,3   | head,straight,destination |
+            | 2    | 1  | Avenue,Avenue | 4,1   | head,straight,destination |
+
+    Scenario: Testbot - Mode for routes
+       Given the node map
+            | a | b |   |   |   |
+            |   | c | d | e | f |
+
+       And the ways
             | nodes | highway | route | duration |
             | ab    | primary |       |          |
             | bc    |         | ferry | 0:01     |
             | cd    | primary |       |          |
+            | de    | primary |       |          |
+            | ef    | primary |       |          |
+
+       When I route I should get
+            | from | to | route          | turns                                         | modes     |
+            | a    | d  | ab,bc,cd       | head,right,left,destination                   | 1,2,1     |
+            | d    | a  | cd,bc,ab       | head,right,left,destination                   | 1,2,1     |
+            | c    | a  | bc,ab          | head,left,destination                         | 2,1       |
+            | d    | b  | cd,bc          | head,right,destination                        | 1,2       |
+            | a    | c  | ab,bc          | head,right,destination                        | 1,2       |
+            | b    | d  | bc,cd          | head,left,destination                         | 2,1       |
+            | a    | f  | ab,bc,cd,de,ef | head,right,left,straight,straight,destination | 1,2,1,1,1 |
+
+    Scenario: Testbot - Modes, triangle map
+        Given the node map
+            |   |   |   |   |   |   | d |
+            |   |   |   |   |   | 2 |   |
+            |   |   |   |   | 6 |   | 5 |
+            | a | 0 | b | c |   |   |   |
+            |   |   |   |   | 4 |   | 1 |
+            |   |   |   |   |   | 3 |   |
+            |   |   |   |   |   |   | e |
+
+       And the ways
+            | nodes | highway | oneway |
+            | abc   | primary |        |
+            | cd    | primary | yes    |
+            | ce    | river   |        |
+            | de    | primary |        |
+
+       When I route I should get
+            | from | to | route        | modes   |
+            | 0    | 1  | abc,ce,de    | 1,3,1   |
+            | 1    | 0  | de,ce,abc    | 1,4,1   |
+            | 0    | 2  | abc,cd       | 1,1     |
+            | 2    | 0  | cd,de,ce,abc | 1,1,4,1 |
+            | 0    | 3  | abc,ce       | 1,3     |
+            | 3    | 0  | ce,abc       | 4,1     |
+            | 4    | 3  | ce           | 3       |
+            | 3    | 4  | ce           | 4       |
+            | 3    | 1  | ce,de        | 3,1     |
+            | 1    | 3  | de,ce        | 1,4     |
+            | a    | e  | abc,ce       | 1,3     |
+            | e    | a  | ce,abc       | 4,1     |
+            | a    | d  | abc,cd       | 1,1     |
+            | d    | a  | de,ce,abc    | 1,4,1   |
+
+    Scenario: Testbot - River in the middle
+        Given the node map
+            | a | b | c |   |   |
+            |   |   | d |   |   |
+            |   |   | e | f | g |
+
+        And the ways
+            | nodes | highway |
+            | abc   | primary |
+            | cde   | river   |
+            | efg   | primary |
 
         When I route I should get
-            | from | to | route    | turns                       | modes         |
-            | a    | d  | ab,bc,cd | head,right,left,destination | bot,ferry,bot |
-            | d    | a  | cd,bc,ab | head,right left,destination | bot,ferry,bot |
-            | c    | a  | bc,ab    | head,left,destination       | ferry,bot     |
-            | d    | b  | cd,bc    | head,right,destination      | bot,ferry     |
-            | a    | c  | ab,bc    | head,right,destination      | bot,ferry     |
-            | b    | d  | bc,cd    | head,left,destination       | ferry,bot     |
+            | from | to | route       | modes |
+            | a    | g  | abc,cde,efg | 1,3,1 |
+            | b    | f  | abc,cde,efg | 1,3,1 |
+            | e    | c  | cde         | 4     |
+            | e    | b  | cde,abc     | 4,1   |
+            | e    | a  | cde,abc     | 4,1   |
+            | c    | e  | cde         | 3     |
+            | c    | f  | cde,efg     | 3,1   |
+            | c    | g  | cde,efg     | 3,1   |
diff --git a/features/testbot/oneway.feature b/features/testbot/oneway.feature
index c21d8b1..766bf8b 100644
--- a/features/testbot/oneway.feature
+++ b/features/testbot/oneway.feature
@@ -6,11 +6,12 @@ Feature: Testbot - oneways
 
     Scenario: Routing on a oneway roundabout
         Given the node map
-        | x |   |   | v |   |   |
-        |   |   | d | c |   |   |
+        |   |   |   |   | v |   |
+        | x |   | d | c |   |   |
         |   | e |   |   | b |   |
         |   | f |   |   | a |   |
-        |   |   | g | h |   |   |
+        |   |   | g | h |   | y |
+        |   | z |   |   |   |   |
 
         And the ways
             | nodes | oneway |
@@ -23,6 +24,9 @@ Feature: Testbot - oneways
             | gh    | yes    |
             | ha    | yes    |
             | vx    | yes    |
+            | vy    | yes    |
+            | yz    | yes    |
+            | xe    | yes    |
 
         When I route I should get
             | from | to | route                |
@@ -42,3 +46,57 @@ Feature: Testbot - oneways
             | g    | f  | gh,ha,ab,bc,cd,de,ef |
             | h    | g  | ha,ab,bc,cd,de,ef,fg |
             | a    | h  | ab,bc,cd,de,ef,fg,gh |
+
+    Scenario: Testbot - Simple oneway
+        Then routability should be
+            | highway | foot | oneway | forw | backw |
+            | primary | no   | yes    | x    |       |
+
+    Scenario: Simple reverse oneway
+        Then routability should be
+            | highway | foot | oneway | forw | backw |
+            | primary | no   | -1     |      | x     |
+
+    Scenario: Testbot - Around the Block
+        Given the node map
+            | a | b |
+            | d | c |
+
+        And the ways
+            | nodes | oneway | foot |
+            | ab    | yes    | no   |
+            | bc    |        | no   |
+            | cd    |        | no   |
+            | da    |        | no   |
+
+        When I route I should get
+            | from | to | route    |
+            | a    | b  | ab       |
+            | b    | a  | bc,cd,da |
+
+    Scenario: Testbot - Handle various oneway tag values
+        Then routability should be
+            | foot | oneway   | forw | backw |
+            | no   |          | x    | x     |
+            | no   | nonsense | x    | x     |
+            | no   | no       | x    | x     |
+            | no   | false    | x    | x     |
+            | no   | 0        | x    | x     |
+            | no   | yes      | x    |       |
+            | no   | true     | x    |       |
+            | no   | 1        | x    |       |
+            | no   | -1       |      | x     |
+
+    Scenario: Testbot - Two consecutive oneways
+        Given the node map
+            | a | b | c |
+
+        And the ways
+            | nodes | oneway |
+            | ab    | yes    |
+            | bc    | yes    |
+
+
+        When I route I should get
+            | from | to | route |
+            | a    | c  | ab,bc |
diff --git a/features/testbot/origin.feature b/features/testbot/origin.feature
index c43e04e..b5b1945 100644
--- a/features/testbot/origin.feature
+++ b/features/testbot/origin.feature
@@ -1,4 +1,4 @@
- at routing @origin
+ at routing @origin @testbot
 Feature: Routing close to the [0,0] origin
 
     Background:
diff --git a/features/testbot/penalty.feature b/features/testbot/penalty.feature
index 85f43c7..e4f3cb6 100644
--- a/features/testbot/penalty.feature
+++ b/features/testbot/penalty.feature
@@ -1,4 +1,4 @@
- at routing @penalty @signal
+ at routing @penalty @signal @testbot
 Feature: Penalties
 # Testbot uses a signal penalty of 7s.
 
diff --git a/features/testbot/planetary.feature b/features/testbot/planetary.feature
index f2ba21e..19925fe 100644
--- a/features/testbot/planetary.feature
+++ b/features/testbot/planetary.feature
@@ -1,4 +1,4 @@
- at routing @planetary
+ at routing @planetary @testbot
 Feature: Distance calculation
 
     Scenario: Approximated Longitudinal distances at equator
diff --git a/features/testbot/projection.feature b/features/testbot/projection.feature
index ed2f2fc..d7a0b89 100644
--- a/features/testbot/projection.feature
+++ b/features/testbot/projection.feature
@@ -1,4 +1,4 @@
- at routing @projection
+ at routing @projection @testbot
 Feature: Projection to nearest point on road
 # Waypoints are projected perpendiculary onto the closest road
 
diff --git a/features/testbot/protobuffer.feature b/features/testbot/protobuffer.feature
index a77ff34..e32de26 100644
--- a/features/testbot/protobuffer.feature
+++ b/features/testbot/protobuffer.feature
@@ -1,4 +1,4 @@
- at routing @pbf
+ at routing @pbf @testbot
 Feature: Importing protobuffer (.pbf) format
 # Test normally read .osm, which is faster than .pbf files,
 # since we don't need to use osmosis to first convert to .pbf
diff --git a/features/testbot/snap.feature b/features/testbot/snap.feature
index c8a04bf..bee75bc 100644
--- a/features/testbot/snap.feature
+++ b/features/testbot/snap.feature
@@ -1,4 +1,4 @@
- at routing @snap
+ at routing @snap @testbot
 Feature: Snap start/end point to the nearest way
 
     Background:
diff --git a/features/testbot/status.feature b/features/testbot/status.feature
index 4fa15eb..1b12b33 100644
--- a/features/testbot/status.feature
+++ b/features/testbot/status.feature
@@ -1,4 +1,4 @@
- at routing @status
+ at routing @status @testbot
 Feature: Status messages
 
     Background:
diff --git a/features/testbot/time.feature b/features/testbot/time.feature
index e0ccc37..c838796 100644
--- a/features/testbot/time.feature
+++ b/features/testbot/time.feature
@@ -1,4 +1,4 @@
- at routing @time
+ at routing @time @testbot
 Feature: Estimation of travel time
 # Testbot speeds:
 # Primary road:    36km/h = 36000m/3600s = 100m/10s
diff --git a/features/testbot/turns.feature b/features/testbot/turns.feature
index 87bf21f..6eba4f9 100644
--- a/features/testbot/turns.feature
+++ b/features/testbot/turns.feature
@@ -1,4 +1,4 @@
- at routing @turns
+ at routing @turns @testbot
 Feature: Turn directions/codes
 
     Background:
diff --git a/features/testbot/utf.feature b/features/testbot/utf.feature
index e9d324c..d979e9f 100644
--- a/features/testbot/utf.feature
+++ b/features/testbot/utf.feature
@@ -1,4 +1,4 @@
- at routing @utf
+ at routing @utf @testbot
 Feature: Handling of UTF characters
 
     Background:
diff --git a/features/testbot/uturn.feature b/features/testbot/uturn.feature
new file mode 100644
index 0000000..943796e
--- /dev/null
+++ b/features/testbot/uturn.feature
@@ -0,0 +1,69 @@
+ at routing @uturn @via @testbot
+Feature: U-turns at via points
+
+    Background:
+        Given the profile "testbot"
+
+    Scenario: U-turns at via points disabled by default
+        Given the node map
+            | a | b | c | d |
+            |   | e | f | g |
+
+        And the ways
+            | nodes |
+            | ab    |
+            | bc    |
+            | cd    |
+            | be    |
+            | dg    |
+            | ef    |
+            | fg    |
+
+        When I route I should get
+            | waypoints | route             | turns                                          |
+            | a,e,c     | ab,be,be,ef,fg,dg,cd | head,right,via,left,straight,left,left,destination |
+
+    Scenario: Query param to allow U-turns at all via points
+        Given the node map
+            | a | b | c | d |
+            |   | e | f | g |
+
+        And the query options
+            | uturns | true |
+
+        And the ways
+            | nodes |
+            | ab    |
+            | bc    |
+            | cd    |
+            | be    |
+            | dg    |
+            | ef    |
+            | fg    |
+
+        When I route I should get
+            | waypoints | route       |
+            | a,e,c     | ab,be,be,bc |
+
+    @todo
+    Scenario: Instructions at via points at u-turns
+        Given the node map
+            | a | b | c | d |
+            |   | e | f | g |
+
+        And the query options
+            | uturns | true |
+
+        And the ways
+            | nodes |
+            | ab    |
+            | bc    |
+            | cd    |
+            | be    |
+            | dg    |
+            | ef    |
+            | fg    |
+
+        When I route I should get
+            | waypoints | route       | turns                              |
+            | a,e,c     | ab,be,be,bc | head,right,uturn,right,destination |
diff --git a/features/testbot/via.feature b/features/testbot/via.feature
index 79fe540..9eb8f55 100644
--- a/features/testbot/via.feature
+++ b/features/testbot/via.feature
@@ -13,9 +13,9 @@ Feature: Via points
             | abc   |
 
         When I route I should get
-            | waypoints | route |
-            | a,b,c     | abc   |
-            | c,b,a     | abc   |
+            | waypoints | route   |
+            | a,b,c     | abc,abc |
+            | c,b,a     | abc,abc |
 
     Scenario: Via point at a dead end
         Given the node map
@@ -28,9 +28,9 @@ Feature: Via points
             | bd    |
 
         When I route I should get
-            | waypoints | route         |
-            | a,d,c     | abc,bd,bd,abc |
-            | c,d,a     | abc,bd,bd,abc |
+            | waypoints | route            |
+            | a,d,c     | abc,bd,bd,bd,abc |
+            | c,d,a     | abc,bd,bd,bd,abc |
 
     Scenario: Multiple via points
         Given the node map
@@ -48,9 +48,9 @@ Feature: Via points
             | dh    |
 
         When I route I should get
-            | waypoints | route            |
-            | a,c,f     | ab,bcd,de,efg    |
-            | a,c,f,h   | ab,bcd,de,efg,gh |
+            | waypoints | route                    |
+            | a,c,f     | ab,bcd,bcd,de,efg        |
+            | a,c,f,h   | ab,bcd,bcd,de,efg,efg,gh |
 
     Scenario: Via points on ring of oneways
     # xa it to avoid only having a single ring, which cna trigger edge cases
@@ -73,9 +73,9 @@ Feature: Via points
             | waypoints | route                      | distance  | turns                                                               |
             | 1,3       | ab,bc,cd                   |  400m +-1 | head,straight,straight,destination                                  |
             | 3,1       | cd,de,ef,fa,ab             | 1000m +-1 | head,right,right,right,right,destination                            |
-            | 1,2,3     | ab,bc,cd                   |  400m +-1 | head,straight,straight,destination                                  |
-            | 1,3,2     | ab,bc,cd,de,ef,fa,ab,bc    | 1600m +-1 | head,straight,straight,right,right,right,right,straight,destination |
-            | 3,2,1     | cd,de,ef,fa,ab,bc,cd,de,ef,fa,ab | 2400m +-1 | head,right,right,right,right,straight,straight,right,right,right,right,destination |
+            | 1,2,3     | ab,bc,bc,cd                |  400m +-1 | head,straight,via,straight,destination                              |
+            | 1,3,2     | ab,bc,cd,cd,de,ef,fa,ab,bc | 1600m +-1 | head,straight,straight,via,right,right,right,right,straight,destination |
+            | 3,2,1     | cd,de,ef,fa,ab,bc,bc,cd,de,ef,fa,ab | 2400m +-1 | head,right,right,right,right,straight,via,straight,right,right,right,right,destination |
 
     @bug
     Scenario: Via points on ring on the same oneway
diff --git a/Plugins/DistanceTablePlugin.h b/plugins/distance_table.hpp
similarity index 62%
rename from Plugins/DistanceTablePlugin.h
rename to plugins/distance_table.hpp
index d3e307b..6ef90a5 100644
--- a/Plugins/DistanceTablePlugin.h
+++ b/plugins/distance_table.hpp
@@ -28,16 +28,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef DISTANCE_TABLE_PLUGIN_H
 #define DISTANCE_TABLE_PLUGIN_H
 
-#include "BasePlugin.h"
-
-#include "../Algorithms/ObjectToBase64.h"
-#include "../DataStructures/JSONContainer.h"
-#include "../DataStructures/QueryEdge.h"
-#include "../DataStructures/SearchEngine.h"
-#include "../Descriptors/BaseDescriptor.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/StringUtil.h"
-#include "../Util/TimingUtil.h"
+#include "plugin_base.hpp"
+
+#include "../algorithms/object_encoder.hpp"
+#include "../data_structures/json_container.hpp"
+#include "../data_structures/query_edge.hpp"
+#include "../data_structures/search_engine.hpp"
+#include "../descriptors/descriptor_base.hpp"
+#include "../Util/json_renderer.hpp"
+#include "../Util/make_unique.hpp"
+#include "../Util/string_util.hpp"
+#include "../Util/timing_util.hpp"
 
 #include <cstdlib>
 
@@ -47,70 +48,51 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <string>
 #include <vector>
 
-template <class DataFacadeT> class DistanceTablePlugin : public BasePlugin
+template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
 {
   private:
-    std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
+    std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
 
   public:
     explicit DistanceTablePlugin(DataFacadeT *facade) : descriptor_string("table"), facade(facade)
     {
-        search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
+        search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
     }
 
     virtual ~DistanceTablePlugin() {}
 
-    const std::string GetDescriptor() const { return descriptor_string; }
+    const std::string GetDescriptor() const final { return descriptor_string; }
 
-    void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
+    void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
     {
-        // check number of parameters
-        if (2 > route_parameters.coordinates.size())
+        if (!check_all_coordinates(route_parameters.coordinates))
         {
             reply = http::Reply::StockReply(http::Reply::badRequest);
             return;
         }
 
-        RawRouteData raw_route;
-        raw_route.check_sum = facade->GetCheckSum();
-
-        if (std::any_of(begin(route_parameters.coordinates),
-                        end(route_parameters.coordinates),
-                        [&](FixedPointCoordinate coordinate)
-                        { return !coordinate.isValid(); }))
-        {
-            reply = http::Reply::StockReply(http::Reply::badRequest);
-            return;
-        }
-
-        for (const FixedPointCoordinate &coordinate : route_parameters.coordinates)
-        {
-            raw_route.raw_via_node_coordinates.emplace_back(std::move(coordinate));
-        }
-
-        const bool checksum_OK = (route_parameters.check_sum == raw_route.check_sum);
+        const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
         unsigned max_locations =
-            std::min(100u, static_cast<unsigned>(raw_route.raw_via_node_coordinates.size()));
+            std::min(100u, static_cast<unsigned>(route_parameters.coordinates.size()));
         PhantomNodeArray phantom_node_vector(max_locations);
-        for (unsigned i = 0; i < max_locations; ++i)
+        for (const auto i : osrm::irange(0u, max_locations))
         {
             if (checksum_OK && i < route_parameters.hints.size() &&
                 !route_parameters.hints[i].empty())
             {
                 PhantomNode current_phantom_node;
-                DecodeObjectFromBase64(route_parameters.hints[i], current_phantom_node);
-                if (current_phantom_node.isValid(facade->GetNumberOfNodes()))
+                ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
+                if (current_phantom_node.is_valid(facade->GetNumberOfNodes()))
                 {
                     phantom_node_vector[i].emplace_back(std::move(current_phantom_node));
                     continue;
                 }
             }
-            facade->IncrementalFindPhantomNodeForCoordinate(raw_route.raw_via_node_coordinates[i],
+            facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i],
                                                             phantom_node_vector[i],
-                                                            route_parameters.zoom_level,
                                                             1);
 
-            BOOST_ASSERT(phantom_node_vector[i].front().isValid(facade->GetNumberOfNodes()));
+            BOOST_ASSERT(phantom_node_vector[i].front().is_valid(facade->GetNumberOfNodes()));
         }
 
         // TIMER_START(distance_table);
@@ -123,10 +105,11 @@ template <class DataFacadeT> class DistanceTablePlugin : public BasePlugin
             reply = http::Reply::StockReply(http::Reply::badRequest);
             return;
         }
+
         JSON::Object json_object;
         JSON::Array json_array;
-        const unsigned number_of_locations = static_cast<unsigned>(phantom_node_vector.size());
-        for (unsigned row = 0; row < number_of_locations; ++row)
+        const auto number_of_locations = phantom_node_vector.size();
+        for (const auto row : osrm::irange<std::size_t>(0, number_of_locations))
         {
             JSON::Array json_row;
             auto row_begin_iterator = result_table->begin() + (row * number_of_locations);
diff --git a/Plugins/HelloWorldPlugin.h b/plugins/hello_world.hpp
similarity index 73%
rename from Plugins/HelloWorldPlugin.h
rename to plugins/hello_world.hpp
index 2d99a10..c8b07b0 100644
--- a/Plugins/HelloWorldPlugin.h
+++ b/plugins/hello_world.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -28,13 +28,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef HELLO_WORLD_PLUGIN_H
 #define HELLO_WORLD_PLUGIN_H
 
-#include "BasePlugin.h"
-#include "../DataStructures/JSONContainer.h"
-#include "../Util/StringUtil.h"
+#include "plugin_base.hpp"
+
+#include "../data_structures/json_container.hpp"
+#include "../Util/cast.hpp"
+#include "../Util/json_renderer.hpp"
 
 #include <string>
 
-class HelloWorldPlugin : public BasePlugin
+class HelloWorldPlugin final : public BasePlugin
 {
   private:
     std::string temp_string;
@@ -42,9 +44,9 @@ class HelloWorldPlugin : public BasePlugin
   public:
     HelloWorldPlugin() : descriptor_string("hello") {}
     virtual ~HelloWorldPlugin() {}
-    const std::string GetDescriptor() const { return descriptor_string; }
+    const std::string GetDescriptor() const final { return descriptor_string; }
 
-    void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply)
+    void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply) final
     {
         reply.status = http::Reply::ok;
 
@@ -52,20 +54,22 @@ class HelloWorldPlugin : public BasePlugin
         std::string temp_string;
         json_result.values["title"] = "Hello World";
 
-        temp_string = IntToString(routeParameters.zoom_level);
+        temp_string = cast::integral_to_string(routeParameters.zoom_level);
         json_result.values["zoom_level"] = temp_string;
 
-        temp_string = UintToString(routeParameters.check_sum);
+        temp_string = cast::integral_to_string(routeParameters.check_sum);
         json_result.values["check_sum"] = temp_string;
         json_result.values["instructions"] = (routeParameters.print_instructions ? "yes" : "no");
         json_result.values["geometry"] = (routeParameters.geometry ? "yes" : "no");
         json_result.values["compression"] = (routeParameters.compression ? "yes" : "no");
-        json_result.values["output_format"] = (!routeParameters.output_format.empty() ? "yes" : "no");
+        json_result.values["output_format"] =
+            (!routeParameters.output_format.empty() ? "yes" : "no");
 
-        json_result.values["jsonp_parameter"] = (!routeParameters.jsonp_parameter.empty() ? "yes" : "no");
+        json_result.values["jsonp_parameter"] =
+            (!routeParameters.jsonp_parameter.empty() ? "yes" : "no");
         json_result.values["language"] = (!routeParameters.language.empty() ? "yes" : "no");
 
-        temp_string = UintToString(static_cast<unsigned>(routeParameters.coordinates.size()));
+        temp_string = cast::integral_to_string(routeParameters.coordinates.size());
         json_result.values["location_count"] = temp_string;
 
         JSON::Array json_locations;
@@ -75,9 +79,9 @@ class HelloWorldPlugin : public BasePlugin
             JSON::Object json_location;
             JSON::Array json_coordinates;
 
-            json_coordinates.values.push_back(coordinate.lat / COORDINATE_PRECISION);
-            json_coordinates.values.push_back(coordinate.lon / COORDINATE_PRECISION);
-            json_location.values[UintToString(counter)] = json_coordinates;
+            json_coordinates.values.push_back(static_cast<double>(coordinate.lat / COORDINATE_PRECISION));
+            json_coordinates.values.push_back(static_cast<double>(coordinate.lon / COORDINATE_PRECISION));
+            json_location.values[cast::integral_to_string(counter)] = json_coordinates;
             json_locations.values.push_back(json_location);
             ++counter;
         }
diff --git a/Plugins/LocatePlugin.h b/plugins/locate.hpp
similarity index 78%
rename from Plugins/LocatePlugin.h
rename to plugins/locate.hpp
index 518259d..6171395 100644
--- a/Plugins/LocatePlugin.h
+++ b/plugins/locate.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -28,24 +28,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef LOCATE_PLUGIN_H
 #define LOCATE_PLUGIN_H
 
-#include "BasePlugin.h"
-#include "../DataStructures/JSONContainer.h"
-#include "../Util/StringUtil.h"
+#include "plugin_base.hpp"
+
+#include "../data_structures/json_container.hpp"
+#include "../Util/json_renderer.hpp"
+#include "../Util/string_util.hpp"
 
 #include <string>
 
 // locates the nearest node in the road network for a given coordinate.
-template <class DataFacadeT> class LocatePlugin : public BasePlugin
+template <class DataFacadeT> class LocatePlugin final : public BasePlugin
 {
   public:
     explicit LocatePlugin(DataFacadeT *facade) : descriptor_string("locate"), facade(facade) {}
-    const std::string GetDescriptor() const { return descriptor_string; }
+    const std::string GetDescriptor() const final { return descriptor_string; }
 
-    void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
+    void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
     {
         // check number of parameters
-        if (route_parameters.coordinates.empty() ||
-            !route_parameters.coordinates.front().isValid())
+        if (route_parameters.coordinates.empty() || !route_parameters.coordinates.front().is_valid())
         {
             reply = http::Reply::StockReply(http::Reply::badRequest);
             return;
@@ -63,8 +64,8 @@ template <class DataFacadeT> class LocatePlugin : public BasePlugin
             reply.status = http::Reply::ok;
             json_result.values["status"] = 0;
             JSON::Array json_coordinate;
-            json_coordinate.values.push_back(result.lat/COORDINATE_PRECISION);
-            json_coordinate.values.push_back(result.lon/COORDINATE_PRECISION);
+            json_coordinate.values.push_back(result.lat / COORDINATE_PRECISION);
+            json_coordinate.values.push_back(result.lon / COORDINATE_PRECISION);
             json_result.values["mapped_coordinate"] = json_coordinate;
         }
 
diff --git a/Plugins/NearestPlugin.h b/plugins/nearest.hpp
similarity index 50%
rename from Plugins/NearestPlugin.h
rename to plugins/nearest.hpp
index 27bd016..ac1079b 100644
--- a/Plugins/NearestPlugin.h
+++ b/plugins/nearest.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -28,9 +28,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef NEAREST_PLUGIN_H
 #define NEAREST_PLUGIN_H
 
-#include "BasePlugin.h"
-#include "../DataStructures/JSONContainer.h"
-#include "../DataStructures/PhantomNodes.h"
+#include "plugin_base.hpp"
+
+#include "../data_structures/json_container.hpp"
+#include "../data_structures/phantom_node.hpp"
+#include "../Util/integer_range.hpp"
+#include "../Util/json_renderer.hpp"
 
 #include <string>
 
@@ -38,30 +41,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * This Plugin locates the nearest point on a street in the road network for a given coordinate.
  */
 
-template <class DataFacadeT> class NearestPlugin : public BasePlugin
+template <class DataFacadeT> class NearestPlugin final : public BasePlugin
 {
   public:
     explicit NearestPlugin(DataFacadeT *facade) : facade(facade), descriptor_string("nearest") {}
 
-    const std::string GetDescriptor() const { return descriptor_string; }
+    const std::string GetDescriptor() const final { return descriptor_string; }
 
-    void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
+    void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
     {
         // check number of parameters
-        if (route_parameters.coordinates.empty() || !route_parameters.coordinates.front().isValid())
+        if (route_parameters.coordinates.empty() || !route_parameters.coordinates.front().is_valid())
         {
             reply = http::Reply::StockReply(http::Reply::badRequest);
             return;
         }
-
+        auto number_of_results = static_cast<std::size_t>(route_parameters.num_results);
         std::vector<PhantomNode> phantom_node_vector;
         facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates.front(),
                                                         phantom_node_vector,
-                                                        route_parameters.zoom_level,
-                                                        1);
+                                                        static_cast<int>(number_of_results));
 
         JSON::Object json_result;
-        if (phantom_node_vector.empty() || !phantom_node_vector.front().isValid())
+        if (phantom_node_vector.empty() || !phantom_node_vector.front().is_valid())
         {
             json_result.values["status"] = 207;
         }
@@ -69,17 +71,41 @@ template <class DataFacadeT> class NearestPlugin : public BasePlugin
         {
             reply.status = http::Reply::ok;
             json_result.values["status"] = 0;
-            JSON::Array json_coordinate;
-            json_coordinate.values.push_back(phantom_node_vector.front().location.lat /
-                                             COORDINATE_PRECISION);
-            json_coordinate.values.push_back(phantom_node_vector.front().location.lon /
-                                             COORDINATE_PRECISION);
-            json_result.values["mapped_coordinate"] = json_coordinate;
-            std::string temp_string;
-            facade->GetName(phantom_node_vector.front().name_id, temp_string);
-            json_result.values["name"] = temp_string;
-        }
 
+            if (number_of_results > 1)
+            {
+                JSON::Array results;
+
+                auto vector_length = phantom_node_vector.size();
+                for (const auto i : osrm::irange<std::size_t>(0, std::min(number_of_results, vector_length)))
+                {
+                    JSON::Array json_coordinate;
+                    JSON::Object result;
+                    json_coordinate.values.push_back(phantom_node_vector.at(i).location.lat /
+                                                     COORDINATE_PRECISION);
+                    json_coordinate.values.push_back(phantom_node_vector.at(i).location.lon /
+                                                     COORDINATE_PRECISION);
+                    result.values["mapped coordinate"] = json_coordinate;
+                    std::string temp_string;
+                    facade->GetName(phantom_node_vector.at(i).name_id, temp_string);
+                    result.values["name"] = temp_string;
+                    results.values.push_back(result);
+                }
+                json_result.values["results"] = results;
+            }
+            else
+            {
+                JSON::Array json_coordinate;
+                json_coordinate.values.push_back(phantom_node_vector.front().location.lat /
+                                                 COORDINATE_PRECISION);
+                json_coordinate.values.push_back(phantom_node_vector.front().location.lon /
+                                                 COORDINATE_PRECISION);
+                json_result.values["mapped_coordinate"] = json_coordinate;
+                std::string temp_string;
+                facade->GetName(phantom_node_vector.front().name_id, temp_string);
+                json_result.values["name"] = temp_string;
+            }
+        }
         JSON::render(reply.content, json_result);
     }
 
diff --git a/Plugins/BasePlugin.h b/plugins/plugin_base.hpp
similarity index 79%
rename from Plugins/BasePlugin.h
rename to plugins/plugin_base.hpp
index 11c6940..bb23a4d 100644
--- a/Plugins/BasePlugin.h
+++ b/plugins/plugin_base.hpp
@@ -28,8 +28,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef BASEPLUGIN_H_
 #define BASEPLUGIN_H_
 
-#include "../Util/StringUtil.h"
-
 #include <osrm/Coordinate.h>
 #include <osrm/Reply.h>
 #include <osrm/RouteParameters.h>
@@ -45,6 +43,20 @@ class BasePlugin
     virtual ~BasePlugin() {}
     virtual const std::string GetDescriptor() const = 0;
     virtual void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply) = 0;
+    virtual bool check_all_coordinates(const std::vector<FixedPointCoordinate> coordinates) const final
+    {
+        if (2 > coordinates.size() ||
+            std::any_of(std::begin(coordinates),
+                        std::end(coordinates),
+                        [](const FixedPointCoordinate &coordinate)
+                        {
+                return !coordinate.is_valid();
+            }))
+        {
+            return false;
+        }
+        return true;
+    }
 };
 
 #endif /* BASEPLUGIN_H_ */
diff --git a/Plugins/TimestampPlugin.h b/plugins/timestamp.hpp
similarity index 84%
rename from Plugins/TimestampPlugin.h
rename to plugins/timestamp.hpp
index 63f63b2..acdf32e 100644
--- a/Plugins/TimestampPlugin.h
+++ b/plugins/timestamp.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -28,20 +28,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef TIMESTAMP_PLUGIN_H
 #define TIMESTAMP_PLUGIN_H
 
-#include "../DataStructures/JSONContainer.h"
-#include "BasePlugin.h"
+#include "plugin_base.hpp"
+
+#include "../data_structures/json_container.hpp"
+#include "../Util/json_renderer.hpp"
 
 #include <string>
 
-template <class DataFacadeT> class TimestampPlugin : public BasePlugin
+template <class DataFacadeT> class TimestampPlugin final : public BasePlugin
 {
   public:
     explicit TimestampPlugin(const DataFacadeT *facade)
         : facade(facade), descriptor_string("timestamp")
     {
     }
-    const std::string GetDescriptor() const { return descriptor_string; }
-    void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
+    const std::string GetDescriptor() const final { return descriptor_string; }
+    void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
     {
         reply.status = http::Reply::ok;
         JSON::Object json_result;
diff --git a/plugins/viaroute.hpp b/plugins/viaroute.hpp
new file mode 100644
index 0000000..236ee39
--- /dev/null
+++ b/plugins/viaroute.hpp
@@ -0,0 +1,190 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef VIA_ROUTE_HPP
+#define VIA_ROUTE_HPP
+
+#include "plugin_base.hpp"
+
+#include "../algorithms/object_encoder.hpp"
+#include "../data_structures/search_engine.hpp"
+#include "../descriptors/descriptor_base.hpp"
+#include "../descriptors/gpx_descriptor.hpp"
+#include "../descriptors/json_descriptor.hpp"
+#include "../Util/integer_range.hpp"
+#include "../Util/json_renderer.hpp"
+#include "../Util/make_unique.hpp"
+#include "../Util/simple_logger.hpp"
+
+#include <cstdlib>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
+{
+  private:
+    DescriptorTable descriptor_table;
+    std::string descriptor_string;
+    std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
+    DataFacadeT *facade;
+
+  public:
+    explicit ViaRoutePlugin(DataFacadeT *facade) : descriptor_string("viaroute"), facade(facade)
+    {
+        search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
+
+        descriptor_table.emplace("json", 0);
+        descriptor_table.emplace("gpx", 1);
+        // descriptor_table.emplace("geojson", 2);
+    }
+
+    virtual ~ViaRoutePlugin() {}
+
+    const std::string GetDescriptor() const final { return descriptor_string; }
+
+    void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
+    {
+        if (!check_all_coordinates(route_parameters.coordinates))
+        {
+            reply = http::Reply::StockReply(http::Reply::badRequest);
+            return;
+        }
+        reply.status = http::Reply::ok;
+
+        std::vector<phantom_node_pair> phantom_node_pair_list(route_parameters.coordinates.size());
+        const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
+
+        for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
+        {
+            if (checksum_OK && i < route_parameters.hints.size() &&
+                !route_parameters.hints[i].empty())
+            {
+                ObjectEncoder::DecodeFromBase64(route_parameters.hints[i],
+                                                phantom_node_pair_list[i]);
+                if (phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()))
+                {
+                    continue;
+                }
+            }
+            std::vector<PhantomNode> phantom_node_vector;
+            if (facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i],
+                                                                phantom_node_vector, 1))
+            {
+                BOOST_ASSERT(!phantom_node_vector.empty());
+                phantom_node_pair_list[i].first = phantom_node_vector.front();
+                if (phantom_node_vector.size() > 1)
+                {
+                    phantom_node_pair_list[i].second = phantom_node_vector.back();
+                }
+            }
+        }
+
+        auto check_component_id_is_tiny = [](const phantom_node_pair &phantom_pair)
+        {
+            return phantom_pair.first.component_id != 0;
+        };
+
+        const bool every_phantom_is_in_tiny_cc =
+            std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
+                        check_component_id_is_tiny);
+
+        // are all phantoms from a tiny cc?
+        const auto component_id = phantom_node_pair_list.front().first.component_id;
+
+        auto check_component_id_is_equal = [component_id](const phantom_node_pair &phantom_pair)
+        {
+            return component_id == phantom_pair.first.component_id;
+        };
+
+        const bool every_phantom_has_equal_id =
+            std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
+                        check_component_id_is_equal);
+
+        auto swap_phantom_from_big_cc_into_front = [](phantom_node_pair &phantom_pair)
+        {
+            if (0 != phantom_pair.first.component_id)
+            {
+                using namespace std;
+                swap(phantom_pair.first, phantom_pair.second);
+            }
+        };
+
+        // this case is true if we take phantoms from the big CC
+        if (!every_phantom_is_in_tiny_cc || !every_phantom_has_equal_id)
+        {
+            std::for_each(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
+                          swap_phantom_from_big_cc_into_front);
+        }
+
+        RawRouteData raw_route;
+        auto build_phantom_pairs =
+            [&raw_route](const phantom_node_pair &first_pair, const phantom_node_pair &second_pair)
+        {
+            raw_route.segment_end_coordinates.emplace_back(
+                PhantomNodes{first_pair.first, second_pair.first});
+        };
+        osrm::for_each_pair(phantom_node_pair_list, build_phantom_pairs);
+
+        if (route_parameters.alternate_route && 1 == raw_route.segment_end_coordinates.size())
+        {
+            search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
+                                                raw_route);
+        }
+        else
+        {
+            search_engine_ptr->shortest_path(raw_route.segment_end_coordinates,
+                                             route_parameters.uturns, raw_route);
+        }
+
+        if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
+        {
+            SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
+        }
+
+        std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor;
+        switch (descriptor_table.get_id(route_parameters.output_format))
+        {
+        case 1:
+            descriptor = osrm::make_unique<GPXDescriptor<DataFacadeT>>(facade);
+            break;
+        // case 2:
+        //      descriptor = osrm::make_unique<GEOJSONDescriptor<DataFacadeT>>();
+        //      break;
+        default:
+            descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
+            break;
+        }
+
+        descriptor->SetConfig(route_parameters);
+        descriptor->Run(raw_route, reply);
+    }
+};
+
+#endif // VIA_ROUTE_HPP
diff --git a/prepare.cpp b/prepare.cpp
index bb0dab4..e50f134 100644
--- a/prepare.cpp
+++ b/prepare.cpp
@@ -25,484 +25,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "Algorithms/IteratorBasedCRC32.h"
-#include "Contractor/Contractor.h"
-#include "Contractor/EdgeBasedGraphFactory.h"
-#include "DataStructures/BinaryHeap.h"
-#include "DataStructures/DeallocatingVector.h"
-#include "DataStructures/QueryEdge.h"
-#include "DataStructures/StaticGraph.h"
-#include "DataStructures/StaticRTree.h"
-#include "DataStructures/RestrictionMap.h"
-#include "Util/GitDescription.h"
-#include "Util/GraphLoader.h"
-#include "Util/LuaUtil.h"
-#include "Util/OSRMException.h"
+#include "contractor/processing_chain.hpp"
 
-#include "Util/SimpleLogger.h"
-#include "Util/StringUtil.h"
-#include "Util/TimingUtil.h"
-#include "typedefs.h"
-
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
-
-#include <luabind/luabind.hpp>
-
-#include <thread>
-#include <chrono>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <tbb/task_scheduler_init.h>
-#include <tbb/parallel_sort.h>
-
-typedef QueryEdge::EdgeData EdgeData;
-typedef DynamicGraph<EdgeData>::InputEdge InputEdge;
-typedef StaticGraph<EdgeData>::InputEdge StaticEdge;
-
-std::vector<NodeInfo> internal_to_external_node_map;
-std::vector<TurnRestriction> restriction_list;
-std::vector<NodeID> barrier_node_list;
-std::vector<NodeID> traffic_light_list;
-std::vector<ImportEdge> edge_list;
+#include <boost/program_options.hpp>
 
 int main(int argc, char *argv[])
 {
     try
     {
-        LogPolicy::GetInstance().Unmute();
-        TIMER_START(preparing);
-        TIMER_START(expansion);
-
-        boost::filesystem::path config_file_path, input_path, restrictions_path, profile_path;
-        unsigned int requested_num_threads;
-
-        // declare a group of options that will be allowed only on command line
-        boost::program_options::options_description generic_options("Options");
-        generic_options.add_options()("version,v", "Show version")("help,h",
-                                                                   "Show this help message")(
-            "config,c",
-            boost::program_options::value<boost::filesystem::path>(&config_file_path)
-                ->default_value("contractor.ini"),
-            "Path to a configuration file.");
-
-        // declare a group of options that will be allowed both on command line and in config file
-        boost::program_options::options_description config_options("Configuration");
-        config_options.add_options()(
-            "restrictions,r",
-            boost::program_options::value<boost::filesystem::path>(&restrictions_path),
-            "Restrictions file in .osrm.restrictions format")(
-            "profile,p",
-            boost::program_options::value<boost::filesystem::path>(&profile_path)
-                ->default_value("profile.lua"),
-            "Path to LUA routing profile")(
-            "threads,t",
-            boost::program_options::value<unsigned int>(&requested_num_threads)->default_value(tbb::task_scheduler_init::default_num_threads()),
-            "Number of threads to use");
-
-        // hidden options, will be allowed both on command line and in config file, but will not be
-        // shown to the user
-        boost::program_options::options_description hidden_options("Hidden options");
-        hidden_options.add_options()(
-            "input,i",
-            boost::program_options::value<boost::filesystem::path>(&input_path),
-            "Input file in .osm, .osm.bz2 or .osm.pbf format");
-
-        // positional option
-        boost::program_options::positional_options_description positional_options;
-        positional_options.add("input", 1);
-
-        // combine above options for parsing
-        boost::program_options::options_description cmdline_options;
-        cmdline_options.add(generic_options).add(config_options).add(hidden_options);
-
-        boost::program_options::options_description config_file_options;
-        config_file_options.add(config_options).add(hidden_options);
-
-        boost::program_options::options_description visible_options(
-            "Usage: " + boost::filesystem::basename(argv[0]) + " <input.osrm> [options]");
-        visible_options.add(generic_options).add(config_options);
-
-        // parse command line options
-        boost::program_options::variables_map option_variables;
-        boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
-                                          .options(cmdline_options)
-                                          .positional(positional_options)
-                                          .run(),
-                                      option_variables);
-
-        if (option_variables.count("version"))
-        {
-            SimpleLogger().Write() << g_GIT_DESCRIPTION;
-            return 0;
-        }
-
-        if (option_variables.count("help"))
-        {
-            SimpleLogger().Write() << "\n" << visible_options;
-            return 0;
-        }
-
-        boost::program_options::notify(option_variables);
-
-        if (!option_variables.count("restrictions"))
-        {
-            restrictions_path = std::string(input_path.string() + ".restrictions");
-        }
-
-        if (!option_variables.count("input"))
-        {
-            SimpleLogger().Write() << "\n" << visible_options;
-            return 0;
-        }
-
-        if (!boost::filesystem::is_regular_file(input_path))
-        {
-            SimpleLogger().Write(logWARNING) << "Input file " << input_path.string()
-                                             << " not found!";
-            return 1;
-        }
-
-        if (!boost::filesystem::is_regular_file(profile_path))
-        {
-            SimpleLogger().Write(logWARNING) << "Profile " << profile_path.string()
-                                             << " not found!";
-            return 1;
-        }
-
-        if (1 > requested_num_threads)
-        {
-            SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
-            return 1;
-        }
-
-        const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
-
-        SimpleLogger().Write() << "Input file: " << input_path.filename().string();
-        SimpleLogger().Write() << "Restrictions file: " << restrictions_path.filename().string();
-        SimpleLogger().Write() << "Profile: " << profile_path.filename().string();
-        SimpleLogger().Write() << "Threads: " << requested_num_threads;
-        if (recommended_num_threads != requested_num_threads)
-        {
-            SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
-                                             << recommended_num_threads
-                                             << "! This setting may have performance side-effects.";
-        }
-
-        tbb::task_scheduler_init init(requested_num_threads);
-
-        LogPolicy::GetInstance().Unmute();
-        boost::filesystem::ifstream restriction_stream(restrictions_path, std::ios::binary);
-        TurnRestriction restriction;
-        FingerPrint fingerprint_loaded, fingerprint_orig;
-        unsigned number_of_usable_restrictions = 0;
-        restriction_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
-        if (!fingerprint_loaded.TestPrepare(fingerprint_orig))
-        {
-            SimpleLogger().Write(logWARNING) << ".restrictions was prepared with different build.\n"
-                                                "Reprocess to get rid of this warning.";
-        }
-
-        restriction_stream.read((char *)&number_of_usable_restrictions, sizeof(unsigned));
-        restriction_list.resize(number_of_usable_restrictions);
-        if (number_of_usable_restrictions > 0)
-        {
-            restriction_stream.read((char *)&(restriction_list[0]),
-                                number_of_usable_restrictions * sizeof(TurnRestriction));
-        }
-        restriction_stream.close();
-
-        boost::filesystem::ifstream in;
-        in.open(input_path, std::ios::in | std::ios::binary);
-
-        const std::string node_filename = input_path.string() + ".nodes";
-        const std::string edge_out = input_path.string() + ".edges";
-        const std::string geometry_filename = input_path.string() + ".geometry";
-        const std::string graphOut = input_path.string() + ".hsgr";
-        const std::string rtree_nodes_path = input_path.string() + ".ramIndex";
-        const std::string rtree_leafs_path = input_path.string() + ".fileIndex";
-
-        /*** Setup Scripting Environment ***/
-
-        // Create a new lua state
-        lua_State *lua_state = luaL_newstate();
-
-        // Connect LuaBind to this lua state
-        luabind::open(lua_state);
-
-        // open utility libraries string library;
-        luaL_openlibs(lua_state);
-
-        // adjust lua load path
-        luaAddScriptFolderToLoadPath(lua_state, profile_path.string().c_str());
-
-        // Now call our function in a lua script
-        if (0 != luaL_dofile(lua_state, profile_path.string().c_str()))
-        {
-            std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
-            return 1;
-        }
-
-        EdgeBasedGraphFactory::SpeedProfileProperties speed_profile;
-
-        if (0 != luaL_dostring(lua_state, "return traffic_signal_penalty\n"))
-        {
-            std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
-            return 1;
-        }
-        speed_profile.trafficSignalPenalty = 10 * lua_tointeger(lua_state, -1);
-        SimpleLogger().Write(logDEBUG)
-            << "traffic_signal_penalty: " << speed_profile.trafficSignalPenalty;
-
-        if (0 != luaL_dostring(lua_state, "return u_turn_penalty\n"))
-        {
-            std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
-            return 1;
-        }
-        speed_profile.uTurnPenalty = 10 * lua_tointeger(lua_state, -1);
-
-        speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function");
-
-        #ifdef WIN32
-        #pragma message ("Memory consumption on Windows can be higher due to memory alignment")
-        #else
-        static_assert(sizeof(ImportEdge) == 20,
-                      "changing ImportEdge type has influence on memory consumption!");
-        #endif
-        std::vector<ImportEdge> edge_list;
-        NodeID number_of_node_based_nodes =
-            readBinaryOSRMGraphFromStream(in,
-                                          edge_list,
-                                          barrier_node_list,
-                                          traffic_light_list,
-                                          &internal_to_external_node_map,
-                                          restriction_list);
-        in.close();
-
-        if (edge_list.empty())
-        {
-            SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
-            return 1;
-        }
-
-        SimpleLogger().Write() << restriction_list.size() << " restrictions, "
-                               << barrier_node_list.size() << " bollard nodes, "
-                               << traffic_light_list.size() << " traffic lights";
-
-        /***
-         * Building an edge-expanded graph from node-based input and turn restrictions
-         */
-
-        SimpleLogger().Write() << "Generating edge-expanded graph representation";
-        std::shared_ptr<NodeBasedDynamicGraph> node_based_graph =
-            NodeBasedDynamicGraphFromImportEdges(number_of_node_based_nodes, edge_list);
-        std::unique_ptr<RestrictionMap> restriction_map =
-            std::unique_ptr<RestrictionMap>(new RestrictionMap(node_based_graph, restriction_list));
-        EdgeBasedGraphFactory *edge_based_graph_factor =
-            new EdgeBasedGraphFactory(node_based_graph,
-                                      std::move(restriction_map),
-                                      barrier_node_list,
-                                      traffic_light_list,
-                                      internal_to_external_node_map,
-                                      speed_profile);
-        edge_list.clear();
-        edge_list.shrink_to_fit();
-
-        edge_based_graph_factor->Run(edge_out, geometry_filename, lua_state);
-
-        restriction_list.clear();
-        restriction_list.shrink_to_fit();
-        barrier_node_list.clear();
-        barrier_node_list.shrink_to_fit();
-        traffic_light_list.clear();
-        traffic_light_list.shrink_to_fit();
-
-        unsigned number_of_edge_based_nodes = edge_based_graph_factor->GetNumberOfEdgeBasedNodes();
-        BOOST_ASSERT(number_of_edge_based_nodes != std::numeric_limits<unsigned>::max());
-        DeallocatingVector<EdgeBasedEdge> edgeBasedEdgeList;
-        #ifndef WIN32
-        static_assert(sizeof(EdgeBasedEdge) == 16,
-                      "changing ImportEdge type has influence on memory consumption!");
-        #endif
-
-        edge_based_graph_factor->GetEdgeBasedEdges(edgeBasedEdgeList);
-        std::vector<EdgeBasedNode> node_based_edge_list;
-        edge_based_graph_factor->GetEdgeBasedNodes(node_based_edge_list);
-        delete edge_based_graph_factor;
-
-        // TODO actually use scoping: Split this up in subfunctions
-        node_based_graph.reset();
-
-        TIMER_STOP(expansion);
-
-        // Building grid-like nearest-neighbor data structure
-        SimpleLogger().Write() << "building r-tree ...";
-        StaticRTree<EdgeBasedNode> *rtree =
-            new StaticRTree<EdgeBasedNode>(node_based_edge_list,
-                                           rtree_nodes_path.c_str(),
-                                           rtree_leafs_path.c_str(),
-                                           internal_to_external_node_map);
-        delete rtree;
-        IteratorbasedCRC32<std::vector<EdgeBasedNode>> crc32;
-        unsigned node_based_edge_list_CRC32 =
-            crc32(node_based_edge_list.begin(), node_based_edge_list.end());
-        node_based_edge_list.clear();
-        node_based_edge_list.shrink_to_fit();
-        SimpleLogger().Write() << "CRC32: " << node_based_edge_list_CRC32;
-
-        /***
-         * Writing info on original (node-based) nodes
-         */
-
-        SimpleLogger().Write() << "writing node map ...";
-        boost::filesystem::ofstream node_stream(node_filename, std::ios::binary);
-        const unsigned size_of_mapping = internal_to_external_node_map.size();
-        node_stream.write((char *)&size_of_mapping, sizeof(unsigned));
-        if (size_of_mapping > 0)
-        {
-            node_stream.write((char *)&(internal_to_external_node_map[0]),
-                          size_of_mapping * sizeof(NodeInfo));
-        }
-        node_stream.close();
-        internal_to_external_node_map.clear();
-        internal_to_external_node_map.shrink_to_fit();
-
-        /***
-         * Contracting the edge-expanded graph
-         */
-
-        SimpleLogger().Write() << "initializing contractor";
-        Contractor *contractor = new Contractor(number_of_edge_based_nodes, edgeBasedEdgeList);
-
-        TIMER_START(contraction);
-        contractor->Run();
-        TIMER_STOP(contraction);
-
-        SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
-
-        DeallocatingVector<QueryEdge> contracted_edge_list;
-        contractor->GetEdges(contracted_edge_list);
-        delete contractor;
-
-        /***
-         * Sorting contracted edges in a way that the static query graph can read some in in-place.
-         */
-
-        std::sort(contracted_edge_list.begin(), contracted_edge_list.end());
-        unsigned max_used_node_id = 0;
-        unsigned contracted_edge_count = contracted_edge_list.size();
-        SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count
-                               << " edges";
-
-        boost::filesystem::ofstream hsgr_output_stream(graphOut, std::ios::binary);
-        hsgr_output_stream.write((char *)&fingerprint_orig, sizeof(FingerPrint));
-        for (const QueryEdge &edge : contracted_edge_list)
-        {
-            BOOST_ASSERT(UINT_MAX != edge.source);
-            BOOST_ASSERT(UINT_MAX != edge.target);
-
-            max_used_node_id = std::max(max_used_node_id, edge.source);
-            max_used_node_id = std::max(max_used_node_id, edge.target);
-        }
-        SimpleLogger().Write(logDEBUG) << "input graph has " << number_of_edge_based_nodes
-                                       << " nodes";
-        SimpleLogger().Write(logDEBUG) << "contracted graph has " << max_used_node_id << " nodes";
-        max_used_node_id += 1;
-
-        std::vector<StaticGraph<EdgeData>::NodeArrayEntry> node_array;
-        node_array.resize(number_of_edge_based_nodes + 1);
-
-        SimpleLogger().Write() << "Building node array";
-        StaticGraph<EdgeData>::EdgeIterator edge = 0;
-        StaticGraph<EdgeData>::EdgeIterator position = 0;
-        StaticGraph<EdgeData>::EdgeIterator last_edge = edge;
-
-        for (StaticGraph<EdgeData>::NodeIterator node = 0; node < max_used_node_id; ++node)
-        {
-            last_edge = edge;
-            while ((edge < contracted_edge_count) && (contracted_edge_list[edge].source == node))
-            {
-                ++edge;
-            }
-            node_array[node].first_edge = position; //=edge
-            position += edge - last_edge;           // remove
-        }
-
-        for (unsigned sentinel_counter = max_used_node_id; sentinel_counter != node_array.size();
-             ++sentinel_counter)
-        {
-            // sentinel element, guarded against underflow
-            node_array[sentinel_counter].first_edge = contracted_edge_count;
-        }
-
-        unsigned node_array_size = node_array.size();
-        // serialize crc32, aka checksum
-        hsgr_output_stream.write((char *)&node_based_edge_list_CRC32, sizeof(unsigned));
-        // serialize number of nodes
-        hsgr_output_stream.write((char *)&node_array_size, sizeof(unsigned));
-        // serialize number of edges
-        hsgr_output_stream.write((char *)&contracted_edge_count, sizeof(unsigned));
-        // serialize all nodes
-        if (node_array_size > 0)
-        {
-            hsgr_output_stream.write((char *)&node_array[0],
-                                 sizeof(StaticGraph<EdgeData>::NodeArrayEntry) * node_array_size);
-        }
-        // serialize all edges
-
-        SimpleLogger().Write() << "Building edge array";
-        edge = 0;
-        int number_of_used_edges = 0;
-
-        StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
-        for (unsigned edge = 0; edge < contracted_edge_list.size(); ++edge)
-        {
-            // no eigen loops
-            BOOST_ASSERT(contracted_edge_list[edge].source != contracted_edge_list[edge].target);
-            current_edge.target = contracted_edge_list[edge].target;
-            current_edge.data = contracted_edge_list[edge].data;
-
-            // every target needs to be valid
-            BOOST_ASSERT(current_edge.target < max_used_node_id);
-#ifndef NDEBUG
-            if (current_edge.data.distance <= 0)
-            {
-                SimpleLogger().Write(logWARNING)
-                    << "Edge: " << edge << ",source: " << contracted_edge_list[edge].source
-                    << ", target: " << contracted_edge_list[edge].target
-                    << ", dist: " << current_edge.data.distance;
-
-                SimpleLogger().Write(logWARNING) << "Failed at adjacency list of node "
-                                                 << contracted_edge_list[edge].source << "/"
-                                                 << node_array.size() - 1;
-                return 1;
-            }
-#endif
-            hsgr_output_stream.write((char *)&current_edge,
-                                     sizeof(StaticGraph<EdgeData>::EdgeArrayEntry));
-            ++number_of_used_edges;
-        }
-        hsgr_output_stream.close();
-
-        TIMER_STOP(preparing);
-
-        SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
-        SimpleLogger().Write() << "Expansion  : "
-                               << (number_of_node_based_nodes / TIMER_SEC(expansion))
-                               << " nodes/sec and "
-                               << (number_of_edge_based_nodes / TIMER_SEC(expansion))
-                               << " edges/sec";
-
-        SimpleLogger().Write() << "Contraction: "
-                               << (number_of_edge_based_nodes / TIMER_SEC(contraction))
-                               << " nodes/sec and "
-                               << number_of_used_edges / TIMER_SEC(contraction)
-                               << " edges/sec";
-
-        node_array.clear();
-        SimpleLogger().Write() << "finished preprocessing";
+        return Prepare().Process(argc, argv);
     }
     catch (boost::program_options::too_many_positional_options_error &)
     {
@@ -519,5 +50,4 @@ int main(int argc, char *argv[])
         SimpleLogger().Write(logWARNING) << "Exception occured: " << e.what() << std::endl;
         return 1;
     }
-    return 0;
 }
diff --git a/profiles/bicycle.lua b/profiles/bicycle.lua
index 3efa3d0..713c6b7 100644
--- a/profiles/bicycle.lua
+++ b/profiles/bicycle.lua
@@ -1,4 +1,5 @@
 require("lib/access")
+require("lib/maxspeed")
 
 -- Begin of globals
 barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true }
@@ -94,7 +95,13 @@ u_turn_penalty      = 20
 use_turn_restrictions   = false
 turn_penalty      = 60
 turn_bias         = 1.4
--- End of globals
+
+
+--modes
+mode_normal = 1
+mode_pushing = 2
+mode_ferry = 3
+mode_train = 4
 
 
 local function parse_maxspeed(source)
@@ -118,42 +125,40 @@ function get_exceptions(vector)
   end
 end
 
-function node_function (node)
-  local barrier = node.tags:Find ("barrier")
+function node_function (node, result)
+  local barrier = node:get_value_by_key("barrier")
   local access = Access.find_access_tag(node, access_tags_hierachy)
-  local traffic_signal = node.tags:Find("highway")
+  local traffic_signal = node:get_value_by_key("highway")
 
 	-- flag node if it carries a traffic light
-	if traffic_signal == "traffic_signals" then
-		node.traffic_light = true
+	if traffic_signal and traffic_signal == "traffic_signals" then
+		result.traffic_lights = true
 	end
 
 	-- parse access and barrier tags
 	if access and access ~= "" then
 		if access_tag_blacklist[access] then
-			node.bollard = true
+			result.barrier = true
 		else
-			node.bollard = false
+			result.barrier = false
 		end
 	elseif barrier and barrier ~= "" then
 		if barrier_whitelist[barrier] then
-			node.bollard = false
+			result.barrier = false
 		else
-			node.bollard = true
+			result.barrier = true
 		end
 	end
-
-	-- return 1
 end
 
-function way_function (way)
+function way_function (way, result)
   -- initial routability check, filters out buildings, boundaries, etc
-  local highway = way.tags:Find("highway")
-  local route = way.tags:Find("route")
-  local man_made = way.tags:Find("man_made")
-  local railway = way.tags:Find("railway")
-  local amenity = way.tags:Find("amenity")
-  local public_transport = way.tags:Find("public_transport")
+  local highway = way:get_value_by_key("highway")
+  local route = way:get_value_by_key("route")
+  local man_made = way:get_value_by_key("man_made")
+  local railway = way:get_value_by_key("railway")
+  local amenity = way:get_value_by_key("amenity")
+  local public_transport = way:get_value_by_key("public_transport")
   if (not highway or highway == '') and
   (not route or route == '') and
   (not railway or railway=='') and
@@ -161,208 +166,216 @@ function way_function (way)
   (not man_made or man_made=='') and
   (not public_transport or public_transport=='')
   then
-    return 0
+    return
   end
 
   -- don't route on ways or railways that are still under construction
   if highway=='construction' or railway=='construction' then
-    return 0
+    return
   end
 
   -- access
   local access = Access.find_access_tag(way, access_tags_hierachy)
-  if access_tag_blacklist[access] then
-    return 0
+  if access and access_tag_blacklist[access] then
+    return
   end
 
   -- other tags
-  local name = way.tags:Find("name")
-  local ref = way.tags:Find("ref")
-  local junction = way.tags:Find("junction")
-  local maxspeed = parse_maxspeed(way.tags:Find ( "maxspeed") )
-  local maxspeed_forward = parse_maxspeed(way.tags:Find( "maxspeed:forward"))
-  local maxspeed_backward = parse_maxspeed(way.tags:Find( "maxspeed:backward"))
-  local barrier = way.tags:Find("barrier")
-  local oneway = way.tags:Find("oneway")
-  local onewayClass = way.tags:Find("oneway:bicycle")
-  local cycleway = way.tags:Find("cycleway")
-  local cycleway_left = way.tags:Find("cycleway:left")
-  local cycleway_right = way.tags:Find("cycleway:right")
-  local duration = way.tags:Find("duration")
-  local service = way.tags:Find("service")
-  local area = way.tags:Find("area")
-  local foot = way.tags:Find("foot")
-  local surface = way.tags:Find("surface")
+  local name = way:get_value_by_key("name")
+  local ref = way:get_value_by_key("ref")
+  local junction = way:get_value_by_key("junction")
+  local maxspeed = parse_maxspeed(way:get_value_by_key ( "maxspeed") )
+  local maxspeed_forward = parse_maxspeed(way:get_value_by_key( "maxspeed:forward"))
+  local maxspeed_backward = parse_maxspeed(way:get_value_by_key( "maxspeed:backward"))
+  local barrier = way:get_value_by_key("barrier")
+  local oneway = way:get_value_by_key("oneway")
+  local onewayClass = way:get_value_by_key("oneway:bicycle")
+  local cycleway = way:get_value_by_key("cycleway")
+  local cycleway_left = way:get_value_by_key("cycleway:left")
+  local cycleway_right = way:get_value_by_key("cycleway:right")
+  local duration = way:get_value_by_key("duration")
+  local service = way:get_value_by_key("service")
+  local area = way:get_value_by_key("area")
+  local foot = way:get_value_by_key("foot")
+  local surface = way:get_value_by_key("surface")
+  local bicycle = way:get_value_by_key("bicycle")
 
   -- name
-  if "" ~= ref and "" ~= name then
-    way.name = name .. ' / ' .. ref
-  elseif "" ~= ref then
-    way.name = ref
-  elseif "" ~= name then
-    way.name = name
-  else
+  if ref and "" ~= ref and name and "" ~= name then
+    result.name = name .. ' / ' .. ref
+  elseif ref and "" ~= ref then
+    result.name = ref
+  elseif name and "" ~= name then
+    result.name = name
+  elseif highway then
     -- if no name exists, use way type
     -- this encoding scheme is excepted to be a temporary solution
-    way.name = "{highway:"..highway.."}"
+    result.name = "{highway:"..highway.."}"
   end
 
   -- roundabout handling
-  if "roundabout" == junction then
-    way.roundabout = true;
+  if junction and "roundabout" == junction then
+    result.roundabout = true;
   end
 
   -- speed
   if route_speeds[route] then
     -- ferries (doesn't cover routes tagged using relations)
-    way.direction = Way.bidirectional
-    way.ignore_in_grid = true
-    if durationIsValid(duration) then
-      way.duration = math.max( 1, parseDuration(duration) )
+    result.forward_mode = mode_ferry
+    result.backward_mode = mode_ferry
+    result.ignore_in_grid = true
+    if duration and durationIsValid(duration) then
+      result.duration = math.max( 1, parseDuration(duration) )
     else
-       way.speed = route_speeds[route]
+       result.forward_speed = route_speeds[route]
+       result.backward_speed = route_speeds[route]
     end
   elseif railway and platform_speeds[railway] then
     -- railway platforms (old tagging scheme)
-    way.speed = platform_speeds[railway]
+    result.forward_speed = platform_speeds[railway]
+    result.backward_speed = platform_speeds[railway]
   elseif platform_speeds[public_transport] then
     -- public_transport platforms (new tagging platform)
-    way.speed = platform_speeds[public_transport]
+    result.forward_speed = platform_speeds[public_transport]
+    result.backward_speed = platform_speeds[public_transport]
     elseif railway and railway_speeds[railway] then
+      result.forward_mode = mode_train
+      result.backward_mode = mode_train
      -- railways
     if access and access_tag_whitelist[access] then
-      way.speed = railway_speeds[railway]
-      way.direction = Way.bidirectional
+      result.forward_speed = railway_speeds[railway]
+      result.backward_speed = railway_speeds[railway]
     end
   elseif amenity and amenity_speeds[amenity] then
     -- parking areas
-    way.speed = amenity_speeds[amenity]
+    result.forward_speed = amenity_speeds[amenity]
+    result.backward_speed = amenity_speeds[amenity]
   elseif bicycle_speeds[highway] then
     -- regular ways
-    way.speed = bicycle_speeds[highway]
+    result.forward_speed = bicycle_speeds[highway]
+    result.backward_speed = bicycle_speeds[highway]
   elseif access and access_tag_whitelist[access] then
     -- unknown way, but valid access tag
-    way.speed = default_speed
+    result.forward_speed = default_speed
+    result.backward_speed = default_speed
   else
     -- biking not allowed, maybe we can push our bike?
     -- essentially requires pedestrian profiling, for example foot=no mean we can't push a bike
-    -- TODO: if we can push, the way should be marked as pedestrion mode, but there's no way to do it yet from lua..
-    if foot ~= 'no' then
+    if foot ~= 'no' and junction ~= "roundabout" then
       if pedestrian_speeds[highway] then
         -- pedestrian-only ways and areas
-        way.speed = pedestrian_speeds[highway]
+        result.forward_speed = pedestrian_speeds[highway]
+        result.backward_speed = pedestrian_speeds[highway]
+        result.forward_mode = mode_pushing
+        result.backward_mode = mode_pushing
       elseif man_made and man_made_speeds[man_made] then
         -- man made structures
-        way.speed = man_made_speeds[man_made]
+        result.forward_speed = man_made_speeds[man_made]
+        result.backward_speed = man_made_speeds[man_made]
+        result.forward_mode = mode_pushing
+        result.backward_mode = mode_pushing
       elseif foot == 'yes' then
-        way.speed = walking_speed
+        result.forward_speed = walking_speed
+        result.backward_speed = walking_speed
+        result.forward_mode = mode_pushing
+        result.backward_mode = mode_pushing
+      elseif foot_forward == 'yes' then
+        result.forward_speed = walking_speed
+        result.forward_mode = mode_pushing
+        result.backward_mode = 0
+      elseif foot_backward == 'yes' then
+        result.forward_speed = walking_speed
+        result.forward_mode = 0
+        result.backward_mode = mode_pushing
       end
     end
   end
 
   -- direction
-  way.direction = Way.bidirectional
   local impliedOneway = false
   if junction == "roundabout" or highway == "motorway_link" or highway == "motorway" then
-    way.direction = Way.oneway
     impliedOneway = true
   end
 
   if onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then
-    way.direction = Way.oneway
+    result.backward_mode = 0
   elseif onewayClass == "no" or onewayClass == "0" or onewayClass == "false" then
-    way.direction = Way.bidirectional
+    -- prevent implied oneway
   elseif onewayClass == "-1" then
-    way.direction = Way.opposite
+    result.forward_mode = 0
   elseif oneway == "no" or oneway == "0" or oneway == "false" then
-    way.direction = Way.bidirectional
+    -- prevent implied oneway
   elseif cycleway and string.find(cycleway, "opposite") == 1 then
     if impliedOneway then
-      way.direction = Way.opposite
-    else
-      way.direction = Way.bidirectional
+      result.forward_mode = 0
+      result.backward_mode = mode_normal
+      result.backward_speed = bicycle_speeds["cycleway"]
     end
   elseif cycleway_left and cycleway_tags[cycleway_left] and cycleway_right and cycleway_tags[cycleway_right] then
-    way.direction = Way.bidirectional
+    -- prevent implied
   elseif cycleway_left and cycleway_tags[cycleway_left] then
     if impliedOneway then
-      way.direction = Way.opposite
-    else
-      way.direction = Way.bidirectional
+      result.forward_mode = 0
+      result.backward_mode = mode_normal
+      result.backward_speed = bicycle_speeds["cycleway"]
     end
   elseif cycleway_right and cycleway_tags[cycleway_right] then
     if impliedOneway then
-      way.direction = Way.oneway
-    else
-      way.direction = Way.bidirectional
+      result.forward_mode = mode_normal
+      result.backward_speed = bicycle_speeds["cycleway"]
+      result.backward_mode = 0
     end
   elseif oneway == "-1" then
-    way.direction = Way.opposite
-  elseif oneway == "yes" or oneway == "1" or oneway == "true" then
-    way.direction = Way.oneway
+    result.forward_mode = 0
+  elseif oneway == "yes" or oneway == "1" or oneway == "true" or impliedOneway then
+    result.backward_mode = 0
   end
 
   -- pushing bikes
   if bicycle_speeds[highway] or pedestrian_speeds[highway] then
-    if foot ~= 'no' then
-      if junction ~= "roundabout" then
-        if way.direction == Way.oneway then
-          way.backward_speed = walking_speed
-        elseif way.direction == Way.opposite then
-          way.backward_speed = walking_speed
-          way.speed = way.speed
-        end
+    if foot ~= "no" and junction ~= "roundabout" then
+      if result.backward_mode == 0 then
+        result.backward_speed = walking_speed
+        result.backward_mode = mode_pushing
+      elseif result.forward_mode == 0 then
+        result.forward_speed = walking_speed
+        result.forward_mode = mode_pushing
       end
     end
-    if way.backward_speed == way.speed then
-      -- TODO: no way yet to mark a way as pedestrian mode if forward/backward speeds are equal
-      way.direction = Way.bidirectional
-    end
   end
 
   -- cycleways
   if cycleway and cycleway_tags[cycleway] then
-    way.speed = bicycle_speeds["cycleway"]
+    result.forward_speed = bicycle_speeds["cycleway"]
   elseif cycleway_left and cycleway_tags[cycleway_left] then
-    way.speed = bicycle_speeds["cycleway"]
+    result.forward_speed = bicycle_speeds["cycleway"]
   elseif cycleway_right and cycleway_tags[cycleway_right] then
-    way.speed = bicycle_speeds["cycleway"]
+    result.forward_speed = bicycle_speeds["cycleway"]
+  end
+
+  -- dismount
+  if bicycle == "dismount" then
+    result.forward_mode = mode_pushing
+    result.backward_mode = mode_pushing
+    result.forward_speed = walking_speed
+    result.backward_speed = walking_speed
   end
 
   -- surfaces
   if surface then
     surface_speed = surface_speeds[surface]
     if surface_speed then
-      if way.speed > 0 then
-        way.speed = surface_speed
+      if result.forward_speed > 0 then
+        result.forward_speed = surface_speed
       end
-      if way.backward_speed > 0 then
-        way.backward_speed  = surface_speed
+      if result.backward_speed > 0 then
+        result.backward_speed  = surface_speed
       end
     end
   end
 
   -- maxspeed
-  -- TODO: maxspeed of backward direction
-  if take_minimum_of_speeds then
-    if maxspeed and maxspeed>0 then
-      way.speed = math.min(way.speed, maxspeed)
-    end
-  end
-
-  -- Override speed settings if explicit forward/backward maxspeeds are given
-  if way.speed > 0 and maxspeed_forward ~= nil and maxspeed_forward > 0 then
-    if Way.bidirectional == way.direction then
-      way.backward_speed = way.speed
-    end
-    way.speed = maxspeed_forward
-  end
-  if maxspeed_backward ~= nil and maxspeed_backward > 0 then
-    way.backward_speed = maxspeed_backward
-  end
-
-  way.type = 1
-  return 1
+  MaxSpeed.limit( result, maxspeed, maxspeed_forward, maxspeed_backward )
 end
 
 function turn_function (angle)
diff --git a/profiles/car.lua b/profiles/car.lua
index 9c65852..cd1f06b 100644
--- a/profiles/car.lua
+++ b/profiles/car.lua
@@ -1,7 +1,7 @@
 -- Begin of globals
 --require("lib/access") --function temporarily inlined
 
-barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true, ["entrance"] = true }
+barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = true, ["checkpoint"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true, ["entrance"] = true }
 access_tag_whitelist = { ["yes"] = true, ["motorcar"] = true, ["motor_vehicle"] = true, ["vehicle"] = true, ["permissive"] = true, ["designated"] = true }
 access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["emergency"] = true }
 access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
@@ -13,15 +13,15 @@ restriction_exception_tags = { "motorcar", "motor_vehicle", "vehicle" }
 
 speed_profile = {
   ["motorway"] = 90,
-  ["motorway_link"] = 75,
+  ["motorway_link"] = 45,
   ["trunk"] = 85,
-  ["trunk_link"] = 70,
+  ["trunk_link"] = 40,
   ["primary"] = 65,
-  ["primary_link"] = 60,
+  ["primary_link"] = 30,
   ["secondary"] = 55,
-  ["secondary_link"] = 50,
+  ["secondary_link"] = 25,
   ["tertiary"] = 40,
-  ["tertiary_link"] = 30,
+  ["tertiary_link"] = 20,
   ["unclassified"] = 25,
   ["residential"] = 25,
   ["living_street"] = 10,
@@ -32,13 +32,106 @@ speed_profile = {
   ["default"] = 10
 }
 
+
+-- surface/trackype/smoothness
+-- values were estimated from looking at the photos at the relevant wiki pages
+
+-- max speed for surfaces
+surface_speeds = {
+  ["asphalt"] = nil,    -- nil mean no limit. removing the line has the same effect
+  ["concrete"] = nil,
+  ["concrete:plates"] = nil,
+  ["concrete:lanes"] = nil,
+  ["paved"] = nil,
+
+  ["cement"] = 80,
+  ["compacted"] = 80,
+  ["fine_gravel"] = 80,
+
+  ["paving_stones"] = 60,
+  ["metal"] = 60,
+  ["bricks"] = 60,
+
+  ["grass"] = 40,
+  ["wood"] = 40,
+  ["sett"] = 40,
+  ["grass_paver"] = 40,
+  ["gravel"] = 40,
+  ["unpaved"] = 40,
+  ["ground"] = 40,
+  ["dirt"] = 40,
+  ["pebblestone"] = 40,
+  ["tartan"] = 40,
+
+  ["cobblestone"] = 30,
+  ["clay"] = 30,
+
+  ["earth"] = 20,
+  ["stone"] = 20,
+  ["rocky"] = 20,
+  ["sand"] = 20,
+
+  ["mud"] = 10
+}
+
+-- max speed for tracktypes
+tracktype_speeds = {
+  ["grade1"] =  60,
+  ["grade2"] =  40,
+  ["grade3"] =  30,
+  ["grade4"] =  25,
+  ["grade5"] =  20
+}
+
+-- max speed for smoothnesses
+smoothness_speeds = {
+  ["intermediate"]    =  80,
+  ["bad"]             =  40,
+  ["very_bad"]        =  20,
+  ["horrible"]        =  10,
+  ["very_horrible"]   =  5,
+  ["impassable"]      =  0
+}
+
+-- http://wiki.openstreetmap.org/wiki/Speed_limits
+maxspeed_table_default = {
+  ["urban"] = 50,
+  ["rural"] = 90,
+  ["trunk"] = 110,
+  ["motorway"] = 130
+}
+
+-- List only exceptions
+maxspeed_table = {
+  ["ch:rural"] = 80,
+  ["ch:trunk"] = 100,
+  ["ch:motorway"] = 120,
+  ["de:living_street"] = 7,
+  ["ru:living_street"] = 20,
+  ["ru:urban"] = 60,
+  ["ua:urban"] = 60,
+  ["at:rural"] = 100,
+  ["de:rural"] = 100,
+  ["at:trunk"] = 100,
+  ["cz:trunk"] = 0,
+  ["ro:trunk"] = 100,
+  ["cz:motorway"] = 0,
+  ["de:motorway"] = 0,
+  ["ru:motorway"] = 110,
+  ["gb:nsl_single"] = (60*1609)/1000,
+  ["gb:nsl_dual"] = (70*1609)/1000,
+  ["gb:motorway"] = (70*1609)/1000,
+  ["uk:nsl_single"] = (60*1609)/1000,
+  ["uk:nsl_dual"] = (70*1609)/1000,
+  ["uk:motorway"] = (70*1609)/1000
+}
+
 traffic_signal_penalty          = 2
+use_turn_restrictions           = true
 
--- End of globals
 local take_minimum_of_speeds    = false
 local obey_oneway               = true
 local obey_bollards             = true
-local use_turn_restrictions     = true
 local ignore_areas              = true     -- future feature
 local u_turn_penalty            = 20
 
@@ -48,14 +141,18 @@ local max = math.max
 
 local speed_reduction = 0.8
 
-local function find_access_tag(source,access_tags_hierachy)
+--modes
+local mode_normal = 1
+local mode_ferry = 2
+
+local function find_access_tag(source, access_tags_hierachy)
   for i,v in ipairs(access_tags_hierachy) do
-    local has_tag = source.tags:Holds(v)
-    if has_tag then
-      return source.tags:Find(v)
+    local access_tag = source:get_value_by_key(v)
+    if access_tag and "" ~= access_tag then
+      return access_tag
     end
   end
-  return nil
+  return ""
 end
 
 function get_exceptions(vector)
@@ -69,11 +166,21 @@ local function parse_maxspeed(source)
     return 0
   end
   local n = tonumber(source:match("%d*"))
-  if not n then
-    n = 0
-  end
-  if string.match(source, "mph") or string.match(source, "mp/h") then
-    n = (n*1609)/1000;
+  if n then
+    if string.match(source, "mph") or string.match(source, "mp/h") then
+      n = (n*1609)/1000;
+    end
+  else
+    -- parse maxspeed like FR:urban
+    source = string.lower(source)
+    n = maxspeed_table[source]
+    if not n then
+      local highway_type = string.match(source, "%a%a:(%a+)")
+      n = maxspeed_table_default[highway_type]
+      if not n then
+        n = 0
+      end
+    end
   end
   return n
 end
@@ -86,61 +193,59 @@ end
 --   return penalty
 -- end
 
-function node_function (node)
-  local access = find_access_tag(node, access_tags_hierachy)
-
-  --flag node if it carries a traffic light
-  if node.tags:Holds("highway") then
-    if node.tags:Find("highway") == "traffic_signals" then
-      node.traffic_light = true;
-    end
-  end
-
+function node_function (node, result)
   -- parse access and barrier tags
-  if access and access ~= "" then
+  local access = find_access_tag(node, access_tags_hierachy)
+  if access ~= "" then
     if access_tag_blacklist[access] then
-      node.bollard = true
+      result.barrier = true
     end
-  elseif node.tags:Holds("barrier") then
-    local barrier = node.tags:Find("barrier")
-    if barrier_whitelist[barrier] then
-      return
-    else
-      node.bollard = true
+  else
+    local barrier = node:get_value_by_key("barrier")
+    if barrier and "" ~= barrier then
+      if barrier_whitelist[barrier] then
+        return
+      else
+        result.barrier = true
+      end
     end
   end
+
+  -- check if node is a traffic light
+  local tag = node:get_value_by_key("highway")
+  if tag and "traffic_signals" == tag then
+    result.traffic_lights = true;
+  end
 end
 
-function way_function (way)
+function way_function (way, result)
+  local highway = way:get_value_by_key("highway")
+  local route = way:get_value_by_key("route")
+
+  if not ((highway and highway ~= "") or (route and route ~= "")) then
+    return
+  end
+
   -- we dont route over areas
-  local is_area = way.tags:Holds("area")
-  if ignore_areas and is_area then
-    local area = way.tags:Find("area")
-    if "yes" == area then
-      return
-    end
+  local area = way:get_value_by_key("area")
+  if ignore_areas and area and "yes" == area then
+    return
   end
 
   -- check if oneway tag is unsupported
-  local oneway = way.tags:Find("oneway")
-  if "reversible" == oneway then
+  local oneway = way:get_value_by_key("oneway")
+  if oneway and "reversible" == oneway then
     return
   end
 
-  local is_impassable = way.tags:Holds("impassable")
-  if is_impassable then
-    local impassable = way.tags:Find("impassable")
-    if "yes" == impassable then
-      return
-    end
+  local impassable = way:get_value_by_key("impassable")
+  if impassable and "yes" == impassable then
+    return
   end
 
-  local is_status = way.tags:Holds("status")
-  if is_status then
-    local status = way.tags:Find("status")
-    if "impassable" == status then
-      return
-    end
+  local status = way:get_value_by_key("status")
+  if status and "impassable" == status then
+    return
   end
 
   -- Check if we are allowed to access the way
@@ -149,20 +254,18 @@ function way_function (way)
     return
   end
 
-  -- Second, parse the way according to these properties
-  local highway = way.tags:Find("highway")
-  local route = way.tags:Find("route")
-
   -- Handling ferries and piers
   local route_speed = speed_profile[route]
   if(route_speed and route_speed > 0) then
     highway = route;
-    local duration  = way.tags:Find("duration")
-    if durationIsValid(duration) then
-      way.duration = max( parseDuration(duration), 1 );
+    local duration  = way:get_value_by_key("duration")
+    if duration and durationIsValid(duration) then
+      result.duration = max( parseDuration(duration), 1 );
     end
-    way.direction = Way.bidirectional
-    way.speed = route_speed
+    result.forward_mode = mode_ferry
+    result.backward_mode = mode_ferry
+    result.forward_speed = route_speed
+    result.backward_speed = route_speed
   end
 
   -- leave early of this way is not accessible
@@ -170,104 +273,125 @@ function way_function (way)
     return
   end
 
-  if way.speed == -1 then
+  if result.forward_speed == -1 then
     local highway_speed = speed_profile[highway]
-    local max_speed = parse_maxspeed( way.tags:Find("maxspeed") )
+    local max_speed = parse_maxspeed( way:get_value_by_key("maxspeed") )
     -- Set the avg speed on the way if it is accessible by road class
     if highway_speed then
-      if max_speed > highway_speed then
-        way.speed = max_speed
+      if max_speed and max_speed > highway_speed then
+        result.forward_speed = max_speed
+        result.backward_speed = max_speed
         -- max_speed = math.huge
       else
-        way.speed = highway_speed
+        result.forward_speed = highway_speed
+        result.backward_speed = highway_speed
       end
     else
       -- Set the avg speed on ways that are marked accessible
       if access_tag_whitelist[access] then
-        way.speed = speed_profile["default"]
+        result.forward_speed = speed_profile["default"]
+        result.backward_speed = speed_profile["default"]
       end
     end
     if 0 == max_speed then
       max_speed = math.huge
     end
-    way.speed = min(way.speed, max_speed)
+    result.forward_speed = min(result.forward_speed, max_speed)
+    result.backward_speed = min(result.backward_speed, max_speed)
   end
 
-  if -1 == way.speed then
+  if -1 == result.forward_speed and -1 == result.backward_speed then
     return
   end
 
+  -- reduce speed on bad surfaces
+  local surface = way:get_value_by_key("surface")
+  local tracktype = way:get_value_by_key("tracktype")
+  local smoothness = way:get_value_by_key("smoothness")
+
+  if surface and surface_speeds[surface] then
+    result.forward_speed = math.min(surface_speeds[surface], result.forward_speed)
+    result.backward_speed = math.min(surface_speeds[surface], result.backward_speed)
+  end
+  if tracktype and tracktype_speeds[tracktype] then
+    result.forward_speed = math.min(tracktype_speeds[tracktype], result.forward_speed)
+    result.backward_speed = math.min(tracktype_speeds[tracktype], result.backward_speed)
+  end
+  if smoothness and smoothness_speeds[smoothness] then
+    result.forward_speed = math.min(smoothness_speeds[smoothness], result.forward_speed)
+    result.backward_speed = math.min(smoothness_speeds[smoothness], result.backward_speed)
+  end
+
   -- parse the remaining tags
-  local name = way.tags:Find("name")
-  local ref = way.tags:Find("ref")
-  local junction = way.tags:Find("junction")
-  -- local barrier = way.tags:Find("barrier")
-  -- local cycleway = way.tags:Find("cycleway")
-  local service  = way.tags:Find("service")
+  local name = way:get_value_by_key("name")
+  local ref = way:get_value_by_key("ref")
+  local junction = way:get_value_by_key("junction")
+  -- local barrier = way:get_value_by_key("barrier", "")
+  -- local cycleway = way:get_value_by_key("cycleway", "")
+  local service = way:get_value_by_key("service")
 
   -- Set the name that will be used for instructions
-  if "" ~= ref then
-    way.name = ref
-  elseif "" ~= name then
-    way.name = name
+  if ref and "" ~= ref then
+    result.name = ref
+  elseif name and "" ~= name then
+    result.name = name
 --  else
-      --    way.name = highway  -- if no name exists, use way type
+      --    result.name = highway  -- if no name exists, use way type
   end
 
-  if "roundabout" == junction then
-    way.roundabout = true;
+  if junction and "roundabout" == junction then
+    result.roundabout = true;
   end
 
   -- Set access restriction flag if access is allowed under certain restrictions only
   if access ~= "" and access_tag_restricted[access] then
-    way.is_access_restricted = true
+    result.is_access_restricted = true
   end
 
   -- Set access restriction flag if service is allowed under certain restrictions only
-  if service ~= "" and service_tag_restricted[service] then
-    way.is_access_restricted = true
+  if service and service ~= "" and service_tag_restricted[service] then
+    result.is_access_restricted = true
   end
 
   -- Set direction according to tags on way
-  way.direction = Way.bidirectional
-  if obey_oneway  then
+  if obey_oneway then
     if oneway == "-1" then
-      way.direction = Way.opposite
+      result.forward_mode = 0
     elseif oneway == "yes" or
     oneway == "1" or
     oneway == "true" or
     junction == "roundabout" or
     (highway == "motorway_link" and oneway ~="no") or
     (highway == "motorway" and oneway ~= "no") then
-      way.direction = Way.oneway
+      result.backward_mode = 0
     end
   end
 
   -- Override speed settings if explicit forward/backward maxspeeds are given
-  local maxspeed_forward = parse_maxspeed(way.tags:Find( "maxspeed:forward"))
-  local maxspeed_backward = parse_maxspeed(way.tags:Find( "maxspeed:backward"))
-  if maxspeed_forward > 0 then
-    if Way.bidirectional == way.direction then
-      way.backward_speed = way.speed
+  local maxspeed_forward = parse_maxspeed(way:get_value_by_key( "maxspeed:forward"))
+  local maxspeed_backward = parse_maxspeed(way:get_value_by_key( "maxspeed:backward"))
+  if maxspeed_forward and maxspeed_forward > 0 then
+    if 0 ~= result.forward_mode and 0 ~= result.backward_mode then
+      result.backward_speed = result.forward_speed
     end
-    way.speed = maxspeed_forward
+    result.forward_speed = maxspeed_forward
   end
-  if maxspeed_backward > 0 then
-    way.backward_speed = maxspeed_backward
+  if maxspeed_backward and maxspeed_backward > 0 then
+    result.backward_speed = maxspeed_backward
   end
 
   -- Override general direction settings of there is a specific one for our mode of travel
   if ignore_in_grid[highway] then
-    way.ignore_in_grid = true
+    result.ignore_in_grid = true
   end
-  way.type = 1
 
   -- scale speeds to get better avg driving times
-  way.speed = way.speed * speed_reduction
-  if maxspeed_backward > 0 then
-    way.backward_speed = way.backward_speed*speed_reduction
+  if result.forward_speed > 0 then
+    result.forward_speed = result.forward_speed*speed_reduction + 11;
+  end
+  if result.backward_speed > 0 then
+    result.backward_speed = result.backward_speed*speed_reduction + 11;
   end
-  return
 end
 
 -- These are wrappers to parse vectors of nodes and ways and thus to speed up any tracing JIT
diff --git a/profiles/examples/postgis.lua b/profiles/examples/postgis.lua
index b101a27..6e32e4c 100644
--- a/profiles/examples/postgis.lua
+++ b/profiles/examples/postgis.lua
@@ -65,11 +65,11 @@ function way_function (way)
 
   local cursor = assert( sql_con:execute(sql_query) )   -- execute querty
   local row = cursor:fetch( {}, "a" )                   -- fetch first (and only) row
-  way.speed = 20.0                                      -- default speed
+  way.forward_speed = 20.0                                      -- default speed
   if row then
     local val = tonumber(row.val)                       -- read 'val' from row 
     if val > 10 then
-      way.speed = way.speed / math.log10( val )         -- reduce speed by amount of industry close by 
+      way.forward_speed = way.forward_speed / math.log10( val )         -- reduce speed by amount of industry close by 
     end
   end
   cursor:close()                                        -- done with this query
diff --git a/profiles/foot.lua b/profiles/foot.lua
index ae0dd60..5a37097 100644
--- a/profiles/foot.lua
+++ b/profiles/foot.lua
@@ -63,143 +63,149 @@ traffic_signal_penalty 	= 2
 u_turn_penalty 			= 2
 use_turn_restrictions   = false
 
+--modes
+local mode_normal = 1
+local mode_ferry = 2
+
 function get_exceptions(vector)
 	for i,v in ipairs(restriction_exception_tags) do
 		vector:Add(v)
 	end
 end
 
-function node_function (node)
-	local barrier = node.tags:Find ("barrier")
+function node_function (node, result)
+	local barrier = node:get_value_by_key("barrier")
 	local access = Access.find_access_tag(node, access_tags_hierachy)
-	local traffic_signal = node.tags:Find("highway")
+	local traffic_signal = node:get_value_by_key("highway")
 
 	-- flag node if it carries a traffic light
-	if traffic_signal == "traffic_signals" then
-		node.traffic_light = true
+	if traffic_signal and traffic_signal == "traffic_signals" then
+		result.traffic_light = true
 	end
 
 	-- parse access and barrier tags
 	if access and access ~= "" then
 		if access_tag_blacklist[access] then
-			node.bollard = true
+			result.barrier = true
 		else
-			node.bollard = false
+			result.barrier = false
 		end
 	elseif barrier and barrier ~= "" then
 		if barrier_whitelist[barrier] then
-			node.bollard = false
+			result.barrier = false
 		else
-			node.bollard = true
+			result.barrier = true
 		end
 	end
 
 	return 1
 end
 
-function way_function (way)
- 	-- initial routability check, filters out buildings, boundaries, etc
-	local highway = way.tags:Find("highway")
-	local route = way.tags:Find("route")
-	local man_made = way.tags:Find("man_made")
-	local railway = way.tags:Find("railway")
-	local amenity = way.tags:Find("amenity")
-	local public_transport = way.tags:Find("public_transport")
-    if (not highway or highway == '') and
+function way_function (way, result)
+	-- initial routability check, filters out buildings, boundaries, etc
+	local highway = way:get_value_by_key("highway")
+	local route = way:get_value_by_key("route")
+	local man_made = way:get_value_by_key("man_made")
+	local railway = way:get_value_by_key("railway")
+	local amenity = way:get_value_by_key("amenity")
+	local public_transport = way:get_value_by_key("public_transport")
+	if (not highway or highway == '') and
 		(not route or route == '') and
 		(not railway or railway=='') and
 		(not amenity or amenity=='') and
 		(not man_made or man_made=='') and
-    	(not public_transport or public_transport=='')
-    	then
-    	return 0
+		(not public_transport or public_transport=='')
+		then
+		return
     end
 
     -- don't route on ways that are still under construction
     if highway=='construction' then
-        return 0
+        return
     end
 
 	-- access
     local access = Access.find_access_tag(way, access_tags_hierachy)
     if access_tag_blacklist[access] then
-		return 0
+		return
     end
 
-	local name = way.tags:Find("name")
-	local ref = way.tags:Find("ref")
-	local junction = way.tags:Find("junction")
-	local onewayClass = way.tags:Find("oneway:foot")
-	local duration	= way.tags:Find("duration")
-	local service	= way.tags:Find("service")
-	local area = way.tags:Find("area")
-	local foot = way.tags:Find("foot")
-	local surface = way.tags:Find("surface")
+	local name = way:get_value_by_key("name")
+	local ref = way:get_value_by_key("ref")
+	local junction = way:get_value_by_key("junction")
+	local onewayClass = way:get_value_by_key("oneway:foot")
+	local duration	= way:get_value_by_key("duration")
+	local service	= way:get_value_by_key("service")
+	local area = way:get_value_by_key("area")
+	local foot = way:get_value_by_key("foot")
+	local surface = way:get_value_by_key("surface")
 
  	-- name
-	if "" ~= ref and "" ~= name then
-		way.name = name .. ' / ' .. ref
-    elseif "" ~= ref then
-    	way.name = ref
-	elseif "" ~= name then
-		way.name = name
-	else
-		way.name = "{highway:"..highway.."}"	-- if no name exists, use way type
+	if ref and "" ~= ref and name and "" ~= name then
+		result.name = name .. ' / ' .. ref
+    elseif ref and "" ~= ref then
+    	result.name = ref
+	elseif name and "" ~= name then
+		result.name = name
+	elseif highway then
+		result.name = "{highway:"..highway.."}"	-- if no name exists, use way type
 		                                        -- this encoding scheme is excepted to be a temporary solution
 	end
 
     -- roundabouts
 	if "roundabout" == junction then
-	  way.roundabout = true;
+	  result.roundabout = true;
 	end
 
     -- speed
     if route_speeds[route] then
 		-- ferries (doesn't cover routes tagged using relations)
-		way.direction = Way.bidirectional
-		way.ignore_in_grid = true
-		if durationIsValid(duration) then
-			way.duration = math.max( 1, parseDuration(duration) )
+		result.ignore_in_grid = true
+		if duration and durationIsValid(duration) then
+			result.duration = math.max( 1, parseDuration(duration) )
 		else
-		 	way.speed = route_speeds[route]
+			result.forward_speed = route_speeds[route]
+			result.backward_speed = route_speeds[route]
 		end
+		result.forward_mode = mode_ferry
+		result.backward_mode = mode_ferry
 	elseif railway and platform_speeds[railway] then
 		-- railway platforms (old tagging scheme)
-		way.speed = platform_speeds[railway]
+		result.forward_speed = platform_speeds[railway]
+		result.backward_speed = platform_speeds[railway]
 	elseif platform_speeds[public_transport] then
 		-- public_transport platforms (new tagging platform)
-		way.speed = platform_speeds[public_transport]
+		result.forward_speed = platform_speeds[public_transport]
+		result.backward_speed = platform_speeds[public_transport]
 	elseif amenity and amenity_speeds[amenity] then
 		-- parking areas
-		way.speed = amenity_speeds[amenity]
+		result.forward_speed = amenity_speeds[amenity]
+		result.backward_speed = amenity_speeds[amenity]
 	elseif speeds[highway] then
 		-- regular ways
-      	way.speed = speeds[highway]
+		result.forward_speed = speeds[highway]
+		result.backward_speed = speeds[highway]
 	elseif access and access_tag_whitelist[access] then
 	    -- unknown way, but valid access tag
-		way.speed = walking_speed
+		result.forward_speed = walking_speed
+		result.backward_speed = walking_speed
     end
 
 	-- oneway
 	if onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then
-		way.direction = Way.oneway
+		result.backward_mode = 0
 	elseif onewayClass == "no" or onewayClass == "0" or onewayClass == "false" then
-		way.direction = Way.bidirectional
+		-- nothing to do
 	elseif onewayClass == "-1" then
-		way.direction = Way.opposite
-	else
-      way.direction = Way.bidirectional
+		result.forward_mode = 0
     end
 
     -- surfaces
     if surface then
         surface_speed = surface_speeds[surface]
         if surface_speed then
-            way.speed = math.min(way.speed, surface_speed)
-            way.backward_speed  = math.min(way.backward_speed, surface_speed)
+            result.forward_speed = math.min(result.forward_speed, surface_speed)
+            result.backward_speed  = math.min(result.backward_speed, surface_speed)
         end
     end
-
-  	way.type = 1
-    return 1
 end
diff --git a/profiles/lib/access.lua b/profiles/lib/access.lua
index 094db62..76d2e2c 100644
--- a/profiles/lib/access.lua
+++ b/profiles/lib/access.lua
@@ -4,10 +4,10 @@ module "Access"
 
 function find_access_tag(source,access_tags_hierachy)
     for i,v in ipairs(access_tags_hierachy) do
-        local tag = source.tags:Find(v)
-        if tag ~= '' then
+        local tag = source:get_value_by_key(v)
+        if tag and tag ~= '' then
             return tag
         end
     end
     return nil
-end
\ No newline at end of file
+end
diff --git a/profiles/lib/maxspeed.lua b/profiles/lib/maxspeed.lua
new file mode 100644
index 0000000..aca344a
--- /dev/null
+++ b/profiles/lib/maxspeed.lua
@@ -0,0 +1,17 @@
+local math = math
+
+module "MaxSpeed"
+
+function limit(way,max,maxf,maxb)
+  if maxf and maxf>0 then
+    way.forward_speed = math.min(way.forward_speed, maxf)
+  elseif max and max>0 then
+    way.forward_speed = math.min(way.forward_speed, max)
+  end
+
+  if maxb and maxb>0 then
+    way.backward_speed = math.min(way.backward_speed, maxb)
+  elseif max and max>0 then
+    way.backward_speed = math.min(way.backward_speed, max)
+  end
+end
diff --git a/profiles/testbot.lua b/profiles/testbot.lua
index 66d6599..7bd1416 100644
--- a/profiles/testbot.lua
+++ b/profiles/testbot.lua
@@ -6,10 +6,19 @@
 -- Secondary road:  18km/h = 18000m/3600s = 100m/20s
 -- Tertiary road:  12km/h = 12000m/3600s = 100m/30s
 
+-- modes:
+-- 1: normal
+-- 2: route
+-- 3: river downstream
+-- 4: river upstream
+-- 5: steps down
+-- 6: steps up
+
 speed_profile = {
   ["primary"] = 36,
   ["secondary"] = 18,
   ["tertiary"] = 12,
+  ["steps"] = 6,
   ["default"] = 24
 }
 
@@ -36,39 +45,47 @@ function limit_speed(speed, limits)
   return speed
 end
 
-function node_function (node)
-  local traffic_signal = node.tags:Find("highway")
+function node_function (node, result)
+  local traffic_signal = node:get_value_by_key("highway")
 
-  if traffic_signal == "traffic_signals" then
-    node.traffic_light = true;
+  if traffic_signal and traffic_signal == "traffic_signals" then
+    result.traffic_lights = true;
     -- TODO: a way to set the penalty value
   end
-  return 1
 end
 
-function way_function (way)
-  local highway = way.tags:Find("highway")
-  local name = way.tags:Find("name")
-  local oneway = way.tags:Find("oneway")
-  local route = way.tags:Find("route")
-  local duration = way.tags:Find("duration")
-  local maxspeed = tonumber(way.tags:Find ( "maxspeed"))
-  local maxspeed_forward = tonumber(way.tags:Find( "maxspeed:forward"))
-  local maxspeed_backward = tonumber(way.tags:Find( "maxspeed:backward"))
-  local junction = way.tags:Find("junction")
-
-  way.name = name
-
-  if route ~= nil and durationIsValid(duration) then
-    way.duration = math.max( 1, parseDuration(duration) )
+function way_function (way, result)
+  local highway = way:get_value_by_key("highway")
+  local name = way:get_value_by_key("name")
+  local oneway = way:get_value_by_key("oneway")
+  local route = way:get_value_by_key("route")
+  local duration = way:get_value_by_key("duration")
+  local maxspeed = tonumber(way:get_value_by_key ( "maxspeed"))
+  local maxspeed_forward = tonumber(way:get_value_by_key( "maxspeed:forward"))
+  local maxspeed_backward = tonumber(way:get_value_by_key( "maxspeed:backward"))
+  local junction = way:get_value_by_key("junction")
+
+  if name then
+    result.name = name
+  end
+
+  if duration and durationIsValid(duration) then
+    result.duration = math.max( 1, parseDuration(duration) )
+    result.forward_mode = 2
+    result.backward_mode = 2
   else
     local speed_forw = speed_profile[highway] or speed_profile['default']
     local speed_back = speed_forw
 
     if highway == "river" then
       local temp_speed = speed_forw;
+      result.forward_mode = 3
+      result.backward_mode = 4
       speed_forw = temp_speed*1.5
       speed_back = temp_speed/1.5
+    elseif highway == "steps" then
+      result.forward_mode = 5
+      result.backward_mode = 6
     end
 
     if maxspeed_forward ~= nil and maxspeed_forward > 0 then
@@ -87,26 +104,19 @@ function way_function (way)
       end
     end
 
-    way.speed = speed_forw
-    if speed_back ~= way_forw then
-      way.backward_speed = speed_back
-    end
+    result.forward_speed = speed_forw
+    result.backward_speed = speed_back
   end
 
   if oneway == "no" or oneway == "0" or oneway == "false" then
-    way.direction = Way.bidirectional
+    -- nothing to do
   elseif oneway == "-1" then
-    way.direction = Way.opposite
+    result.forward_mode = 0
   elseif oneway == "yes" or oneway == "1" or oneway == "true" or junction == "roundabout" then
-    way.direction = Way.oneway
-  else
-    way.direction = Way.bidirectional
+    result.backward_mode = 0
   end
 
   if junction == 'roundabout' then
-    way.roundabout = true
+    result.roundabout = true
   end
-
-  way.type = 1
-  return 1
 end
diff --git a/routed.cpp b/routed.cpp
index adf2e2d..1be6dd8 100644
--- a/routed.cpp
+++ b/routed.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -26,11 +26,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "Library/OSRM.h"
-#include "Server/ServerFactory.h"
-#include "Util/GitDescription.h"
+#include "Server/Server.h"
+#include "Util/git_sha.hpp"
 #include "Util/ProgramOptions.h"
-#include "Util/SimpleLogger.h"
-#include "Util/FingerPrint.h"
+#include "Util/simple_logger.hpp"
 
 #ifdef __linux__
 #include <sys/mman.h>
@@ -41,7 +40,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <signal.h>
 
 #include <chrono>
-#include <functional>
 #include <future>
 #include <iostream>
 #include <thread>
@@ -101,27 +99,16 @@ int main(int argc, const char *argv[])
             SimpleLogger().Write(logWARNING) << argv[0] << " could not be locked to RAM";
         }
 #endif
-        SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION << ", "
-                               << "compiled at " << __DATE__ << ", " __TIME__;
+        SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION;
 
         if (use_shared_memory)
         {
             SimpleLogger().Write(logDEBUG) << "Loading from shared memory";
         }
-        else
-        {
-            SimpleLogger().Write() << "HSGR file:\t" << server_paths["hsgrdata"];
-            SimpleLogger().Write(logDEBUG) << "Nodes file:\t" << server_paths["nodesdata"];
-            SimpleLogger().Write(logDEBUG) << "Edges file:\t" << server_paths["edgesdata"];
-            SimpleLogger().Write(logDEBUG) << "Geometry file:\t" << server_paths["geometries"];
-            SimpleLogger().Write(logDEBUG) << "RAM file:\t" << server_paths["ramindex"];
-            SimpleLogger().Write(logDEBUG) << "Index file:\t" << server_paths["fileindex"];
-            SimpleLogger().Write(logDEBUG) << "Names file:\t" << server_paths["namesdata"];
-            SimpleLogger().Write(logDEBUG) << "Timestamp file:\t" << server_paths["timestamp"];
-            SimpleLogger().Write(logDEBUG) << "Threads:\t" << requested_thread_num;
-            SimpleLogger().Write(logDEBUG) << "IP address:\t" << ip_address;
-            SimpleLogger().Write(logDEBUG) << "IP port:\t" << ip_port;
-        }
+
+        SimpleLogger().Write(logDEBUG) << "Threads:\t" << requested_thread_num;
+        SimpleLogger().Write(logDEBUG) << "IP address:\t" << ip_address;
+        SimpleLogger().Write(logDEBUG) << "IP port:\t" << ip_port;
 #ifndef _WIN32
         int sig = 0;
         sigset_t new_mask;
@@ -131,8 +118,8 @@ int main(int argc, const char *argv[])
 #endif
 
         OSRM osrm_lib(server_paths, use_shared_memory);
-        Server *routing_server =
-            ServerFactory::CreateServer(ip_address, ip_port, requested_thread_num);
+        auto routing_server =
+            Server::CreateServer(ip_address, ip_port, requested_thread_num);
 
         routing_server->GetRequestHandlerPtr().RegisterRoutingMachine(&osrm_lib);
 
@@ -169,19 +156,19 @@ int main(int argc, const char *argv[])
 
             auto status = future.wait_for(std::chrono::seconds(2));
 
-            if (status != std::future_status::ready)
+            if (status == std::future_status::ready)
             {
-                SimpleLogger().Write(logWARNING) << "Didn't exit within 2 seconds. Hard abort!";
-                server_task.reset(); // just kill it
+               server_thread.join();
             }
             else
             {
-                server_thread.join();
+                SimpleLogger().Write(logWARNING) << "Didn't exit within 2 seconds. Hard abort!";
+                server_task.reset(); // just kill it
             }
         }
 
         SimpleLogger().Write() << "freeing objects";
-        delete routing_server;
+        routing_server.reset();
         SimpleLogger().Write() << "shutdown completed";
     }
     catch (const std::exception &e)
diff --git a/RoutingAlgorithms/AlternativePathRouting.h b/routing_algorithms/alternative_path.hpp
similarity index 82%
rename from RoutingAlgorithms/AlternativePathRouting.h
rename to routing_algorithms/alternative_path.hpp
index 3506f93..84b5856 100644
--- a/RoutingAlgorithms/AlternativePathRouting.h
+++ b/routing_algorithms/alternative_path.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,27 +25,31 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef ALTERNATIVE_PATH_ROUTING_H
-#define ALTERNATIVE_PATH_ROUTING_H
+#ifndef ALTERNATIVE_PATH_ROUTING_HPP
+#define ALTERNATIVE_PATH_ROUTING_HPP
 
-#include "BasicRoutingInterface.h"
-#include "../DataStructures/SearchEngineData.h"
+#include "routing_base.hpp"
+#include "../data_structures/search_engine_data.hpp"
+#include "../Util/integer_range.hpp"
+#include "../Util/container.hpp"
 
 #include <boost/assert.hpp>
 
 #include <unordered_map>
+#include <unordered_set>
+
 #include <vector>
 
 const double VIAPATH_ALPHA = 0.10;
 const double VIAPATH_EPSILON = 0.15; // alternative at most 15% longer
 const double VIAPATH_GAMMA = 0.75;   // alternative shares at most 75% with the shortest.
 
-template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInterface<DataFacadeT>
+template <class DataFacadeT> class AlternativeRouting final : private BasicRoutingInterface<DataFacadeT>
 {
-    typedef BasicRoutingInterface<DataFacadeT> super;
-    typedef typename DataFacadeT::EdgeData EdgeData;
-    typedef SearchEngineData::QueryHeap QueryHeap;
-    typedef std::pair<NodeID, NodeID> SearchSpaceEdge;
+    using super = BasicRoutingInterface<DataFacadeT>;
+    using EdgeData = typename DataFacadeT::EdgeData;
+    using QueryHeap = SearchEngineData::QueryHeap;
+    using SearchSpaceEdge = std::pair<NodeID, NodeID>;
 
     struct RankedCandidateNode
     {
@@ -96,6 +100,11 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
 
         int upper_bound_to_shortest_path_distance = INVALID_EDGE_WEIGHT;
         NodeID middle_node = SPECIAL_NODEID;
+        EdgeWeight min_edge_offset =
+            std::min(0, -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset());
+        min_edge_offset = std::min(min_edge_offset,
+                                   -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
+
         if (phantom_node_pair.source_phantom.forward_node_id != SPECIAL_NODEID)
         {
             // SimpleLogger().Write(logDEBUG) << "fwd-a insert: " <<
@@ -107,8 +116,8 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
         }
         if (phantom_node_pair.source_phantom.reverse_node_id != SPECIAL_NODEID)
         {
-            // SimpleLogger().Write(logDEBUG) << "fwd-b insert: " <<
-            // phantom_node_pair.source_phantom.reverse_node_id << ", w: " <<
+            //     SimpleLogger().Write(logDEBUG) << "fwd-b insert: " <<
+            //     phantom_node_pair.source_phantom.reverse_node_id << ", w: " <<
             // -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset();
             forward_heap1.Insert(phantom_node_pair.source_phantom.reverse_node_id,
                                  -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
@@ -144,7 +153,8 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
                                              &middle_node,
                                              &upper_bound_to_shortest_path_distance,
                                              via_node_candidate_list,
-                                             forward_search_space);
+                                             forward_search_space,
+                                             min_edge_offset);
             }
             if (0 < reverse_heap1.Size())
             {
@@ -153,7 +163,8 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
                                               &middle_node,
                                               &upper_bound_to_shortest_path_distance,
                                               via_node_candidate_list,
-                                              reverse_search_space);
+                                              reverse_search_space,
+                                              min_edge_offset);
             }
         }
 
@@ -162,7 +173,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
             return;
         }
 
-        sort_unique_resize(via_node_candidate_list);
+        osrm::sort_unique_resize(via_node_candidate_list);
 
         std::vector<NodeID> packed_forward_path;
         std::vector<NodeID> packed_reverse_path;
@@ -170,49 +181,58 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
         super::RetrievePackedPathFromSingleHeap(forward_heap1, middle_node, packed_forward_path);
         super::RetrievePackedPathFromSingleHeap(reverse_heap1, middle_node, packed_reverse_path);
 
+        // this set is is used as an indicator if a node is on the shortest path
+        std::unordered_set<NodeID> nodes_in_path(packed_forward_path.size() +
+                                                 packed_reverse_path.size());
+        nodes_in_path.insert(packed_forward_path.begin(), packed_forward_path.end());
+        nodes_in_path.insert(middle_node);
+        nodes_in_path.insert(packed_reverse_path.begin(), packed_reverse_path.end());
+
         std::unordered_map<NodeID, int> approximated_forward_sharing;
         std::unordered_map<NodeID, int> approximated_reverse_sharing;
 
-        unsigned index_into_forward_path = 0;
         // sweep over search space, compute forward sharing for each current edge (u,v)
         for (const SearchSpaceEdge &current_edge : forward_search_space)
         {
             const NodeID u = current_edge.first;
             const NodeID v = current_edge.second;
-            if ((packed_forward_path.size() < index_into_forward_path) &&
-                (current_edge == forward_search_space[index_into_forward_path]))
+
+            if (nodes_in_path.find(v) != nodes_in_path.end())
             {
-                // current_edge is on shortest path => sharing(u):=queue.GetKey(u);
-                ++index_into_forward_path;
-                approximated_forward_sharing[v] = forward_heap1.GetKey(u);
+                // current_edge is on shortest path => sharing(v):=queue.GetKey(v);
+                approximated_forward_sharing.emplace(v, forward_heap1.GetKey(v));
             }
             else
             {
-                // sharing (s) = sharing (t)
-                approximated_forward_sharing[v] = approximated_forward_sharing[u];
+                // current edge is not on shortest path. Check if we know a value for the other
+                // endpoint
+                const auto sharing_of_u_iterator = approximated_forward_sharing.find(u);
+                if (sharing_of_u_iterator != approximated_forward_sharing.end())
+                {
+                    approximated_forward_sharing.emplace(v, sharing_of_u_iterator->second);
+                }
             }
         }
 
-        unsigned index_into_reverse_path = 0;
         // sweep over search space, compute backward sharing
         for (const SearchSpaceEdge &current_edge : reverse_search_space)
         {
             const NodeID u = current_edge.first;
             const NodeID v = current_edge.second;
-            if ((packed_reverse_path.size() < index_into_reverse_path) &&
-                (current_edge == reverse_search_space[index_into_reverse_path]))
+            if (nodes_in_path.find(v) != nodes_in_path.end())
             {
                 // current_edge is on shortest path => sharing(u):=queue.GetKey(u);
-                ++index_into_reverse_path;
-                approximated_reverse_sharing[v] = reverse_heap1.GetKey(u);
+                approximated_reverse_sharing.emplace(v, reverse_heap1.GetKey(v));
             }
             else
             {
-                // sharing (s) = sharing (t)
-                const auto rev_iterator = approximated_reverse_sharing.find(u);
-                const int rev_sharing =
-                    (rev_iterator != approximated_reverse_sharing.end()) ? rev_iterator->second : 0;
-                approximated_reverse_sharing[v] = rev_sharing;
+                // current edge is not on shortest path. Check if we know a value for the other
+                // endpoint
+                const auto sharing_of_u_iterator = approximated_reverse_sharing.find(u);
+                if (sharing_of_u_iterator != approximated_reverse_sharing.end())
+                {
+                    approximated_reverse_sharing.emplace(v, sharing_of_u_iterator->second);
+                }
             }
         }
 
@@ -251,8 +271,6 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
             }
         }
 
-        // SimpleLogger().Write() << preselected_node_list.size() << " passed preselection";
-
         std::vector<NodeID> &packed_shortest_path = packed_forward_path;
         std::reverse(packed_shortest_path.begin(), packed_shortest_path.end());
         packed_shortest_path.emplace_back(middle_node);
@@ -264,10 +282,13 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
         for (const NodeID node : preselected_node_list)
         {
             int length_of_via_path = 0, sharing_of_via_path = 0;
-            ComputeLengthAndSharingOfViaPath(
-                node, &length_of_via_path, &sharing_of_via_path, packed_shortest_path);
-            const int maximum_allowed_sharing = static_cast<int>(
-                upper_bound_to_shortest_path_distance * VIAPATH_GAMMA);
+            ComputeLengthAndSharingOfViaPath(node,
+                                             &length_of_via_path,
+                                             &sharing_of_via_path,
+                                             packed_shortest_path,
+                                             min_edge_offset);
+            const int maximum_allowed_sharing =
+                static_cast<int>(upper_bound_to_shortest_path_distance * VIAPATH_GAMMA);
             if (sharing_of_via_path <= maximum_allowed_sharing &&
                 length_of_via_path <= upper_bound_to_shortest_path_distance * (1 + VIAPATH_EPSILON))
             {
@@ -289,7 +310,8 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
                                             upper_bound_to_shortest_path_distance,
                                             &length_of_via_path,
                                             &s_v_middle,
-                                            &v_t_middle))
+                                            &v_t_middle,
+                                            min_edge_offset))
             {
                 // select first admissable
                 selected_via_node = candidate.node;
@@ -329,8 +351,8 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
                                         v_t_middle,
                                         packed_alternate_path);
 
-            raw_route_data.alt_source_traversed_in_reverse.push_back(
-                (packed_alternate_path.front() != phantom_node_pair.source_phantom.forward_node_id));
+            raw_route_data.alt_source_traversed_in_reverse.push_back((
+                packed_alternate_path.front() != phantom_node_pair.source_phantom.forward_node_id));
             raw_route_data.alt_target_traversed_in_reverse.push_back(
                 (packed_alternate_path.back() != phantom_node_pair.target_phantom.forward_node_id));
 
@@ -339,7 +361,9 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
                 packed_alternate_path, phantom_node_pair, raw_route_data.unpacked_alternative);
 
             raw_route_data.alternative_path_length = length_of_via_path;
-        } else {
+        }
+        else
+        {
             BOOST_ASSERT(raw_route_data.alternative_path_length == INVALID_EDGE_WEIGHT);
         }
     }
@@ -373,7 +397,8 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
     inline void ComputeLengthAndSharingOfViaPath(const NodeID via_node,
                                                  int *real_length_of_via_path,
                                                  int *sharing_of_via_path,
-                                                 const std::vector<NodeID> &packed_shortest_path)
+                                                 const std::vector<NodeID> &packed_shortest_path,
+                                                 const EdgeWeight min_edge_offset)
     {
         engine_working_data.InitializeOrClearSecondThreadLocalStorage(
             super::facade->GetNumberOfNodes());
@@ -399,6 +424,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
                                existing_forward_heap,
                                &s_v_middle,
                                &upper_bound_s_v_path_length,
+                               min_edge_offset,
                                false);
         }
         // compute path <v,..,t> by reusing backward search from node t
@@ -411,6 +437,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
                                existing_reverse_heap,
                                &v_t_middle,
                                &upper_bound_of_v_t_path_length,
+                               min_edge_offset,
                                true);
         }
         *real_length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;
@@ -428,48 +455,52 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
 
         // partial unpacking, compute sharing
         // First partially unpack s-->v until paths deviate, note length of common path.
-        const unsigned s_v_min_path_size =
+        const int64_t s_v_min_path_size =
             std::min(packed_s_v_path.size(), packed_shortest_path.size()) - 1;
-        for (unsigned i = 0; i < s_v_min_path_size; ++i)
+        for (const int64_t current_node : osrm::irange<int64_t>(0, s_v_min_path_size))
         {
-            if (packed_s_v_path[i] == packed_shortest_path[i] &&
-                packed_s_v_path[i + 1] == packed_shortest_path[i + 1])
+            if (packed_s_v_path[current_node] == packed_shortest_path[current_node] &&
+                packed_s_v_path[current_node + 1] == packed_shortest_path[current_node + 1])
             {
-                EdgeID edgeID =
-                    facade->FindEdgeInEitherDirection(packed_s_v_path[i], packed_s_v_path[i + 1]);
+                EdgeID edgeID = facade->FindEdgeInEitherDirection(
+                    packed_s_v_path[current_node], packed_s_v_path[current_node + 1]);
                 *sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
             }
             else
             {
-                if (packed_s_v_path[i] == packed_shortest_path[i])
+                if (packed_s_v_path[current_node] == packed_shortest_path[current_node])
                 {
-                    super::UnpackEdge(
-                        packed_s_v_path[i], packed_s_v_path[i + 1], partially_unpacked_via_path);
-                    super::UnpackEdge(packed_shortest_path[i],
-                                      packed_shortest_path[i + 1],
+                    super::UnpackEdge(packed_s_v_path[current_node],
+                                      packed_s_v_path[current_node + 1],
+                                      partially_unpacked_via_path);
+                    super::UnpackEdge(packed_shortest_path[current_node],
+                                      packed_shortest_path[current_node + 1],
                                       partially_unpacked_shortest_path);
                     break;
                 }
             }
         }
         // traverse partially unpacked edge and note common prefix
-        for (int i = 0,
-                 packed_path_length = std::min(partially_unpacked_via_path.size(),
-                                               partially_unpacked_shortest_path.size()) -
-                                      1;
-             (i < packed_path_length) &&
-                 (partially_unpacked_via_path[i] == partially_unpacked_shortest_path[i] &&
-                  partially_unpacked_via_path[i + 1] == partially_unpacked_shortest_path[i + 1]);
-             ++i)
-        {
-            EdgeID edgeID = facade->FindEdgeInEitherDirection(partially_unpacked_via_path[i],
-                                                              partially_unpacked_via_path[i + 1]);
-            *sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
+        const int64_t packed_path_length =
+            std::min(partially_unpacked_via_path.size(), partially_unpacked_shortest_path.size()) -
+            1;
+        for (int64_t current_node = 0;
+             (current_node < packed_path_length) &&
+                 (partially_unpacked_via_path[current_node] ==
+                      partially_unpacked_shortest_path[current_node] &&
+                  partially_unpacked_via_path[current_node + 1] ==
+                      partially_unpacked_shortest_path[current_node + 1]);
+             ++current_node)
+        {
+            EdgeID selected_edge =
+                facade->FindEdgeInEitherDirection(partially_unpacked_via_path[current_node],
+                                                  partially_unpacked_via_path[current_node + 1]);
+            *sharing_of_via_path += facade->GetEdgeData(selected_edge).distance;
         }
 
         // Second, partially unpack v-->t in reverse order until paths deviate and note lengths
-        int via_path_index = packed_v_t_path.size() - 1;
-        int shortest_path_index = packed_shortest_path.size() - 1;
+        int64_t via_path_index = packed_v_t_path.size() - 1;
+        int64_t shortest_path_index = packed_shortest_path.size() - 1;
         for (; via_path_index > 0 && shortest_path_index > 0;
              --via_path_index, --shortest_path_index)
         {
@@ -572,11 +603,17 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
                                        NodeID *middle_node,
                                        int *upper_bound_to_shortest_path_distance,
                                        std::vector<NodeID> &search_space_intersection,
-                                       std::vector<SearchSpaceEdge> &search_space) const
+                                       std::vector<SearchSpaceEdge> &search_space,
+                                       const EdgeWeight min_edge_offset) const
     {
         const NodeID node = forward_heap.DeleteMin();
         const int distance = forward_heap.GetKey(node);
-        const int scaled_distance = static_cast<int>(distance / (1. + VIAPATH_EPSILON));
+        // const NodeID parentnode = forward_heap.GetData(node).parent;
+        // SimpleLogger().Write() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled edge ("
+        // << parentnode << "," << node << "), dist: " << distance;
+
+        const int scaled_distance =
+            static_cast<int>((distance + min_edge_offset) / (1. + VIAPATH_EPSILON));
         if ((INVALID_EDGE_WEIGHT != *upper_bound_to_shortest_path_distance) &&
             (scaled_distance > *upper_bound_to_shortest_path_distance))
         {
@@ -589,7 +626,6 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
         if (reverse_heap.WasInserted(node))
         {
             search_space_intersection.emplace_back(node);
-
             const int new_distance = reverse_heap.GetKey(node) + distance;
             if (new_distance < *upper_bound_to_shortest_path_distance)
             {
@@ -597,6 +633,11 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
                 {
                     *middle_node = node;
                     *upper_bound_to_shortest_path_distance = new_distance;
+                    //     SimpleLogger().Write() << "accepted middle_node " << *middle_node << " at
+                    //     distance " << new_distance;
+                    // } else {
+                    //     SimpleLogger().Write() << "discarded middle_node " << *middle_node << "
+                    //     at distance " << new_distance;
                 }
             }
         }
@@ -641,7 +682,8 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
                                             const int length_of_shortest_path,
                                             int *length_of_via_path,
                                             NodeID *s_v_middle,
-                                            NodeID *v_t_middle) const
+                                            NodeID *v_t_middle,
+                                            const EdgeWeight min_edge_offset) const
     {
         new_forward_heap.Clear();
         new_reverse_heap.Clear();
@@ -658,6 +700,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
                                existing_forward_heap,
                                s_v_middle,
                                &upper_bound_s_v_path_length,
+                               min_edge_offset,
                                false);
         }
 
@@ -676,6 +719,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
                                existing_reverse_heap,
                                v_t_middle,
                                &upper_bound_of_v_t_path_length,
+                               min_edge_offset,
                                true);
         }
 
@@ -844,15 +888,17 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
         {
             if (!forward_heap3.Empty())
             {
-                super::RoutingStep(forward_heap3, reverse_heap3, &middle, &upper_bound, true);
+                super::RoutingStep(
+                    forward_heap3, reverse_heap3, &middle, &upper_bound, min_edge_offset, true);
             }
             if (!reverse_heap3.Empty())
             {
-                super::RoutingStep(reverse_heap3, forward_heap3, &middle, &upper_bound, false);
+                super::RoutingStep(
+                    reverse_heap3, forward_heap3, &middle, &upper_bound, min_edge_offset, false);
             }
         }
         return (upper_bound <= t_test_path_length);
     }
 };
 
-#endif /* ALTERNATIVE_PATH_ROUTING_H */
+#endif /* ALTERNATIVE_PATH_ROUTING_HPP */
diff --git a/RoutingAlgorithms/ManyToManyRouting.h b/routing_algorithms/many_to_many.hpp
similarity index 95%
rename from RoutingAlgorithms/ManyToManyRouting.h
rename to routing_algorithms/many_to_many.hpp
index 7819c67..f1e9960 100644
--- a/RoutingAlgorithms/ManyToManyRouting.h
+++ b/routing_algorithms/many_to_many.hpp
@@ -25,11 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef MANY_TO_MANY_ROUTING_H
-#define MANY_TO_MANY_ROUTING_H
+#ifndef MANY_TO_MANY_ROUTING_HPP
+#define MANY_TO_MANY_ROUTING_HPP
 
-#include "BasicRoutingInterface.h"
-#include "../DataStructures/SearchEngineData.h"
+#include "routing_base.hpp"
+#include "../data_structures/search_engine_data.hpp"
 #include "../typedefs.h"
 
 #include <boost/assert.hpp>
@@ -39,10 +39,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <unordered_map>
 #include <vector>
 
-template <class DataFacadeT> class ManyToManyRouting : public BasicRoutingInterface<DataFacadeT>
+template <class DataFacadeT> class ManyToManyRouting final : public BasicRoutingInterface<DataFacadeT>
 {
-    typedef BasicRoutingInterface<DataFacadeT> super;
-    typedef SearchEngineData::QueryHeap QueryHeap;
+    using super = BasicRoutingInterface<DataFacadeT>;
+    using QueryHeap = SearchEngineData::QueryHeap;
     SearchEngineData &engine_working_data;
 
     struct NodeBucket
@@ -54,7 +54,7 @@ template <class DataFacadeT> class ManyToManyRouting : public BasicRoutingInterf
         {
         }
     };
-    typedef std::unordered_map<NodeID, std::vector<NodeBucket>> SearchSpaceWithBuckets;
+    using SearchSpaceWithBuckets = std::unordered_map<NodeID, std::vector<NodeBucket>>;
 
   public:
     ManyToManyRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
@@ -67,7 +67,7 @@ template <class DataFacadeT> class ManyToManyRouting : public BasicRoutingInterf
     std::shared_ptr<std::vector<EdgeWeight>> operator()(const PhantomNodeArray &phantom_nodes_array)
         const
     {
-        const unsigned number_of_locations = static_cast<unsigned>(phantom_nodes_array.size());
+        const auto number_of_locations = phantom_nodes_array.size();
         std::shared_ptr<std::vector<EdgeWeight>> result_table =
             std::make_shared<std::vector<EdgeWeight>>(number_of_locations * number_of_locations,
                                                       std::numeric_limits<EdgeWeight>::max());
diff --git a/RoutingAlgorithms/BasicRoutingInterface.h b/routing_algorithms/routing_base.hpp
similarity index 81%
rename from RoutingAlgorithms/BasicRoutingInterface.h
rename to routing_algorithms/routing_base.hpp
index 464c088..20610ea 100644
--- a/RoutingAlgorithms/BasicRoutingInterface.h
+++ b/routing_algorithms/routing_base.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,14 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef BASIC_ROUTING_INTERFACE_H
-#define BASIC_ROUTING_INTERFACE_H
+#ifndef ROUTING_BASE_HPP
+#define ROUTING_BASE_HPP
 
-#include "../DataStructures/RawRouteData.h"
-#include "../DataStructures/SearchEngineData.h"
-#include "../DataStructures/TurnInstructions.h"
-#include "../Util/ContainerUtils.h"
-#include "../Util/SimpleLogger.h"
+#include "../data_structures/raw_route_data.hpp"
+#include "../data_structures/search_engine_data.hpp"
+#include "../data_structures/turn_instructions.hpp"
+// #include "../Util/simple_logger.hpp.h"
 
 #include <boost/assert.hpp>
 
@@ -63,10 +62,15 @@ template <class DataFacadeT> class BasicRoutingInterface
                             SearchEngineData::QueryHeap &reverse_heap,
                             NodeID *middle_node_id,
                             int *upper_bound,
+                            const int min_edge_offset,
                             const bool forward_direction) const
     {
         const NodeID node = forward_heap.DeleteMin();
         const int distance = forward_heap.GetKey(node);
+
+        // const NodeID parentnode = forward_heap.GetData(node).parent;
+        // SimpleLogger().Write() << (forward_direction ? "[fwd] " : "[rev] ") << "settled edge (" << parentnode << "," << node << "), dist: " << distance;
+
         if (reverse_heap.WasInserted(node))
         {
             const int new_distance = reverse_heap.GetKey(node) + distance;
@@ -76,18 +80,22 @@ template <class DataFacadeT> class BasicRoutingInterface
                 {
                     *middle_node_id = node;
                     *upper_bound = new_distance;
+                //     SimpleLogger().Write() << "accepted middle node " << node << " at distance " << new_distance;
+                // } else {
+                //     SimpleLogger().Write() << "discared middle node " << node << " at distance " << new_distance;
                 }
             }
         }
 
-        if (distance > *upper_bound)
+        if (distance + min_edge_offset > *upper_bound)
         {
+            // SimpleLogger().Write() << "min_edge_offset: " << min_edge_offset;
             forward_heap.DeleteAll();
             return;
         }
 
         // Stalling
-        for (auto edge : facade->GetAdjacentEdgeRange(node))
+        for (const auto edge : facade->GetAdjacentEdgeRange(node))
         {
             const EdgeData &data = facade->GetEdgeData(edge);
             const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
@@ -108,7 +116,7 @@ template <class DataFacadeT> class BasicRoutingInterface
             }
         }
 
-        for (auto edge : facade->GetAdjacentEdgeRange(node))
+        for (const auto edge : facade->GetAdjacentEdgeRange(node))
         {
             const EdgeData &data = facade->GetEdgeData(edge);
             bool forward_directionFlag = (forward_direction ? data.forward : data.backward);
@@ -171,8 +179,8 @@ template <class DataFacadeT> class BasicRoutingInterface
             // facade->FindEdge does not suffice here in case of shortcuts.
             // The above explanation unclear? Think!
             EdgeID smaller_edge_id = SPECIAL_EDGEID;
-            int edge_weight = INT_MAX;
-            for (auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
+            int edge_weight = std::numeric_limits<EdgeWeight>::max();
+            for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
             {
                 const int weight = facade->GetEdgeData(edge_id).distance;
                 if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
@@ -192,7 +200,7 @@ template <class DataFacadeT> class BasicRoutingInterface
             */
             if (SPECIAL_EDGEID == smaller_edge_id)
             {
-                for (auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
+                for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
                 {
                     const int weight = facade->GetEdgeData(edge_id).distance;
                     if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
@@ -218,6 +226,8 @@ template <class DataFacadeT> class BasicRoutingInterface
                 BOOST_ASSERT_MSG(!ed.shortcut, "original edge flagged as shortcut");
                 unsigned name_index = facade->GetNameIndexFromEdgeID(ed.id);
                 const TurnInstruction turn_instruction = facade->GetTurnInstructionForEdgeID(ed.id);
+                const TravelMode travel_mode = facade->GetTravelModeForEdgeID(ed.id);
+
 
                 if (!facade->EdgeIsCompressed(ed.id))
                 {
@@ -225,7 +235,8 @@ template <class DataFacadeT> class BasicRoutingInterface
                     unpacked_path.emplace_back(facade->GetGeometryIndexForEdgeID(ed.id),
                                                name_index,
                                                turn_instruction,
-                                               ed.distance);
+                                               ed.distance,
+                                               travel_mode);
                 }
                 else
                 {
@@ -233,20 +244,20 @@ template <class DataFacadeT> class BasicRoutingInterface
                     facade->GetUncompressedGeometry(facade->GetGeometryIndexForEdgeID(ed.id),
                                                     id_vector);
 
-                    const int start_index =
+                    const std::size_t start_index =
                         (unpacked_path.empty()
                              ? ((start_traversed_in_reverse)
                                     ? id_vector.size() -
                                           phantom_node_pair.source_phantom.fwd_segment_position - 1
                                     : phantom_node_pair.source_phantom.fwd_segment_position)
                              : 0);
-                    const int end_index = id_vector.size();
+                    const std::size_t end_index = id_vector.size();
 
                     BOOST_ASSERT(start_index >= 0);
                     BOOST_ASSERT(start_index <= end_index);
-                    for (int i = start_index; i < end_index; ++i)
+                    for (std::size_t i = start_index; i < end_index; ++i)
                     {
-                        unpacked_path.emplace_back(id_vector[i], name_index, TurnInstruction::NoTurn, 0);
+                        unpacked_path.emplace_back(id_vector[i], name_index, TurnInstruction::NoTurn, 0, travel_mode);
                     }
                     unpacked_path.back().turn_instruction = turn_instruction;
                     unpacked_path.back().segment_duration = ed.distance;
@@ -258,42 +269,43 @@ template <class DataFacadeT> class BasicRoutingInterface
             std::vector<unsigned> id_vector;
             facade->GetUncompressedGeometry(phantom_node_pair.target_phantom.packed_geometry_id,
                                             id_vector);
-            if (target_traversed_in_reverse)
-            {
-                std::reverse(id_vector.begin(), id_vector.end());
-            }
             const bool is_local_path = (phantom_node_pair.source_phantom.packed_geometry_id ==
                                         phantom_node_pair.target_phantom.packed_geometry_id) &&
                                        unpacked_path.empty();
 
-            int start_index = 0;
-            int end_index = phantom_node_pair.target_phantom.fwd_segment_position;
-            if (target_traversed_in_reverse)
-            {
-                end_index =
-                    id_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position;
-            }
+            std::size_t start_index = 0;
             if (is_local_path)
             {
                 start_index = phantom_node_pair.source_phantom.fwd_segment_position;
-                end_index = phantom_node_pair.target_phantom.fwd_segment_position;
                 if (target_traversed_in_reverse)
                 {
                     start_index =
                         id_vector.size() - phantom_node_pair.source_phantom.fwd_segment_position;
-                    end_index =
-                        id_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position;
                 }
             }
 
-            BOOST_ASSERT(start_index >= 0);
-            for (int i = start_index; i != end_index; (start_index < end_index ? ++i : --i))
+            std::size_t end_index = phantom_node_pair.target_phantom.fwd_segment_position;
+            if (target_traversed_in_reverse)
             {
-                BOOST_ASSERT(i >= -1);
+                std::reverse(id_vector.begin(), id_vector.end());
+                end_index =
+                    id_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position;
+            }
+
+            if (start_index > end_index)
+            {
+                start_index = std::min(start_index, id_vector.size()-1);
+            }
+
+            for (std::size_t i = start_index; i != end_index; (start_index < end_index ? ++i : --i))
+            {
+                BOOST_ASSERT(i < id_vector.size());
+                BOOST_ASSERT(phantom_node_pair.target_phantom.forward_travel_mode>0 );
                 unpacked_path.emplace_back(PathData{id_vector[i],
-                                           phantom_node_pair.target_phantom.name_id,
-                                           TurnInstruction::NoTurn,
-                                           0});
+                                                    phantom_node_pair.target_phantom.name_id,
+                                                    TurnInstruction::NoTurn,
+                                                    0,
+                                                    phantom_node_pair.target_phantom.forward_travel_mode});
             }
         }
 
@@ -304,8 +316,8 @@ template <class DataFacadeT> class BasicRoutingInterface
         // the last node.
         if (unpacked_path.size() > 1)
         {
-            const unsigned last_index = unpacked_path.size() - 1;
-            const unsigned second_to_last_index = last_index - 1;
+            const std::size_t last_index = unpacked_path.size() - 1;
+            const std::size_t second_to_last_index = last_index - 1;
 
             // looks like a trivially true check but tests for underflow
             BOOST_ASSERT(last_index > second_to_last_index);
@@ -330,8 +342,8 @@ template <class DataFacadeT> class BasicRoutingInterface
             recursion_stack.pop();
 
             EdgeID smaller_edge_id = SPECIAL_EDGEID;
-            int edge_weight = INT_MAX;
-            for (auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
+            int edge_weight = std::numeric_limits<EdgeWeight>::max();
+            for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
             {
                 const int weight = facade->GetEdgeData(edge_id).distance;
                 if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
@@ -344,7 +356,7 @@ template <class DataFacadeT> class BasicRoutingInterface
 
             if (SPECIAL_EDGEID == smaller_edge_id)
             {
-                for (auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
+                for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
                 {
                     const int weight = facade->GetEdgeData(edge_id).distance;
                     if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
@@ -355,7 +367,7 @@ template <class DataFacadeT> class BasicRoutingInterface
                     }
                 }
             }
-            BOOST_ASSERT_MSG(edge_weight != INT_MAX, "edge weight invalid");
+            BOOST_ASSERT_MSG(edge_weight != std::numeric_limits<EdgeWeight>::max(), "edge weight invalid");
 
             const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
             if (ed.shortcut)
@@ -379,20 +391,10 @@ template <class DataFacadeT> class BasicRoutingInterface
                                            const NodeID middle_node_id,
                                            std::vector<NodeID> &packed_path) const
     {
-        NodeID current_node_id = middle_node_id;
-        while (current_node_id != forward_heap.GetData(current_node_id).parent)
-        {
-            current_node_id = forward_heap.GetData(current_node_id).parent;
-            packed_path.emplace_back(current_node_id);
-        }
+        RetrievePackedPathFromSingleHeap(forward_heap, middle_node_id, packed_path);
         std::reverse(packed_path.begin(), packed_path.end());
         packed_path.emplace_back(middle_node_id);
-        current_node_id = middle_node_id;
-        while (current_node_id != reverse_heap.GetData(current_node_id).parent)
-        {
-            current_node_id = reverse_heap.GetData(current_node_id).parent;
-            packed_path.emplace_back(current_node_id);
-        }
+        RetrievePackedPathFromSingleHeap(reverse_heap, middle_node_id, packed_path);
     }
 
     inline void RetrievePackedPathFromSingleHeap(const SearchEngineData::QueryHeap &search_heap,
@@ -408,4 +410,4 @@ template <class DataFacadeT> class BasicRoutingInterface
     }
 };
 
-#endif // BASIC_ROUTING_INTERFACE_H
+#endif // ROUTING_BASE_HPP
diff --git a/RoutingAlgorithms/ShortestPathRouting.h b/routing_algorithms/shortest_path.hpp
similarity index 69%
rename from RoutingAlgorithms/ShortestPathRouting.h
rename to routing_algorithms/shortest_path.hpp
index cc5afe5..cab09ab 100644
--- a/RoutingAlgorithms/ShortestPathRouting.h
+++ b/routing_algorithms/shortest_path.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,19 +25,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef SHORTEST_PATH_ROUTING_H
-#define SHORTEST_PATH_ROUTING_H
+#ifndef SHORTEST_PATH_HPP
+#define SHORTEST_PATH_HPP
 
 #include <boost/assert.hpp>
 
-#include "BasicRoutingInterface.h"
-#include "../DataStructures/SearchEngineData.h"
+#include "routing_base.hpp"
+#include "../data_structures/search_engine_data.hpp"
+#include "../Util/integer_range.hpp"
 #include "../typedefs.h"
 
-template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInterface<DataFacadeT>
+template <class DataFacadeT> class ShortestPathRouting final : public BasicRoutingInterface<DataFacadeT>
 {
-    typedef BasicRoutingInterface<DataFacadeT> super;
-    typedef SearchEngineData::QueryHeap QueryHeap;
+    using super = BasicRoutingInterface<DataFacadeT>;
+    using QueryHeap = SearchEngineData::QueryHeap;
     SearchEngineData &engine_working_data;
 
   public:
@@ -49,14 +50,15 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
     ~ShortestPathRouting() {}
 
     void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
+                    const std::vector<bool> &uturn_indicators,
                     RawRouteData &raw_route_data) const
     {
         int distance1 = 0;
         int distance2 = 0;
         bool search_from_1st_node = true;
         bool search_from_2nd_node = true;
-        NodeID middle1 = UINT_MAX;
-        NodeID middle2 = UINT_MAX;
+        NodeID middle1 = SPECIAL_NODEID;
+        NodeID middle2 = SPECIAL_NODEID;
         std::vector<std::vector<NodeID>> packed_legs1(phantom_nodes_vector.size());
         std::vector<std::vector<NodeID>> packed_legs2(phantom_nodes_vector.size());
 
@@ -72,7 +74,7 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
         QueryHeap &forward_heap2 = *(engine_working_data.forwardHeap2);
         QueryHeap &reverse_heap2 = *(engine_working_data.backwardHeap2);
 
-        int current_leg = 0;
+        std::size_t current_leg = 0;
         // Get distance to next pair of target nodes.
         for (const PhantomNodes &phantom_node_pair : phantom_nodes_vector)
         {
@@ -80,36 +82,50 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
             forward_heap2.Clear();
             reverse_heap1.Clear();
             reverse_heap2.Clear();
-            int local_upper_bound1 = INT_MAX;
-            int local_upper_bound2 = INT_MAX;
+            int local_upper_bound1 = INVALID_EDGE_WEIGHT;
+            int local_upper_bound2 = INVALID_EDGE_WEIGHT;
 
-            middle1 = UINT_MAX;
-            middle2 = UINT_MAX;
+            middle1 = SPECIAL_NODEID;
+            middle2 = SPECIAL_NODEID;
+
+            const bool allow_u_turn = current_leg > 0 && uturn_indicators.size() > current_leg && uturn_indicators[current_leg-1];
+            EdgeWeight min_edge_offset = 0;
 
             // insert new starting nodes into forward heap, adjusted by previous distances.
-            if (search_from_1st_node &&
+            if ((allow_u_turn || search_from_1st_node) &&
                 phantom_node_pair.source_phantom.forward_node_id != SPECIAL_NODEID)
             {
                 forward_heap1.Insert(
                     phantom_node_pair.source_phantom.forward_node_id,
-                    distance1 - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
+                    (allow_u_turn ? 0 : distance1) - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
                     phantom_node_pair.source_phantom.forward_node_id);
+                min_edge_offset = std::min(min_edge_offset, (allow_u_turn ? 0 : distance1) - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset());
+                // SimpleLogger().Write(logDEBUG) << "fwd-a2 insert: " << phantom_node_pair.source_phantom.forward_node_id << ", w: " << (allow_u_turn ? 0 : distance1) - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset();
                 forward_heap2.Insert(
                     phantom_node_pair.source_phantom.forward_node_id,
-                    distance1 - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
+                    (allow_u_turn ? 0 : distance1) - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
                     phantom_node_pair.source_phantom.forward_node_id);
+                min_edge_offset = std::min(min_edge_offset, (allow_u_turn ? 0 : distance1) - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset());
+                // SimpleLogger().Write(logDEBUG) << "fwd-b2 insert: " << phantom_node_pair.source_phantom.forward_node_id << ", w: " << (allow_u_turn ? 0 : distance1) - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset();
+
             }
-            if (search_from_2nd_node &&
+            if ((allow_u_turn || search_from_2nd_node) &&
                 phantom_node_pair.source_phantom.reverse_node_id != SPECIAL_NODEID)
             {
                 forward_heap1.Insert(
                     phantom_node_pair.source_phantom.reverse_node_id,
-                    distance2 - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
+                    (allow_u_turn ? 0 : distance2) - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
                     phantom_node_pair.source_phantom.reverse_node_id);
+                min_edge_offset = std::min(min_edge_offset, (allow_u_turn ? 0 : distance2) - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
+                // SimpleLogger().Write(logDEBUG) << "fwd-a2 insert: " << phantom_node_pair.source_phantom.reverse_node_id <<
+                //                     ", w: " << (allow_u_turn ? 0 : distance2) - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset();
                 forward_heap2.Insert(
                     phantom_node_pair.source_phantom.reverse_node_id,
-                    distance2 - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
+                    (allow_u_turn ? 0 : distance2) - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
                     phantom_node_pair.source_phantom.reverse_node_id);
+                min_edge_offset = std::min(min_edge_offset, (allow_u_turn ? 0 : distance2) - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
+                // SimpleLogger().Write(logDEBUG) << "fwd-b2 insert: " << phantom_node_pair.source_phantom.reverse_node_id <<
+                //                     ", w: " << (allow_u_turn ? 0 : distance2) - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset();
             }
 
             // insert new backward nodes into backward heap, unadjusted.
@@ -118,27 +134,31 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
                 reverse_heap1.Insert(phantom_node_pair.target_phantom.forward_node_id,
                                      phantom_node_pair.target_phantom.GetForwardWeightPlusOffset(),
                                      phantom_node_pair.target_phantom.forward_node_id);
-            }
+                // SimpleLogger().Write(logDEBUG) << "rev-a insert: " << phantom_node_pair.target_phantom.forward_node_id <<
+                //                     ", w: " << phantom_node_pair.target_phantom.GetForwardWeightPlusOffset();
+           }
 
             if (phantom_node_pair.target_phantom.reverse_node_id != SPECIAL_NODEID)
             {
                 reverse_heap2.Insert(phantom_node_pair.target_phantom.reverse_node_id,
                                      phantom_node_pair.target_phantom.GetReverseWeightPlusOffset(),
                                      phantom_node_pair.target_phantom.reverse_node_id);
+                // SimpleLogger().Write(logDEBUG) << "rev-a insert: " << phantom_node_pair.target_phantom.reverse_node_id <<
+                //                     ", w: " << phantom_node_pair.target_phantom.GetReverseWeightPlusOffset();
             }
 
             // run two-Target Dijkstra routing step.
             while (0 < (forward_heap1.Size() + reverse_heap1.Size()))
             {
-                if (0 < forward_heap1.Size())
+                if (!forward_heap1.Empty())
                 {
                     super::RoutingStep(
-                        forward_heap1, reverse_heap1, &middle1, &local_upper_bound1, true);
+                        forward_heap1, reverse_heap1, &middle1, &local_upper_bound1, min_edge_offset, true);
                 }
-                if (0 < reverse_heap1.Size())
+                if (!reverse_heap1.Empty())
                 {
                     super::RoutingStep(
-                        reverse_heap1, forward_heap1, &middle1, &local_upper_bound1, false);
+                        reverse_heap1, forward_heap1, &middle1, &local_upper_bound1, min_edge_offset, false);
                 }
             }
 
@@ -146,15 +166,15 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
             {
                 while (0 < (forward_heap2.Size() + reverse_heap2.Size()))
                 {
-                    if (0 < forward_heap2.Size())
+                    if (!forward_heap2.Empty())
                     {
                         super::RoutingStep(
-                            forward_heap2, reverse_heap2, &middle2, &local_upper_bound2, true);
+                            forward_heap2, reverse_heap2, &middle2, &local_upper_bound2, min_edge_offset, true);
                     }
-                    if (0 < reverse_heap2.Size())
+                    if (!reverse_heap2.Empty())
                     {
                         super::RoutingStep(
-                            reverse_heap2, forward_heap2, &middle2, &local_upper_bound2, false);
+                            reverse_heap2, forward_heap2, &middle2, &local_upper_bound2, min_edge_offset, false);
                     }
                 }
             }
@@ -180,7 +200,7 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
             }
 
             // Was at most one of the two paths not found?
-            BOOST_ASSERT_MSG((INT_MAX != distance1 || INT_MAX != distance2), "no path found");
+            BOOST_ASSERT_MSG((INVALID_EDGE_WEIGHT != distance1 || INVALID_EDGE_WEIGHT != distance2), "no path found");
 
             // Unpack paths if they exist
             std::vector<NodeID> temporary_packed_leg1;
@@ -202,15 +222,17 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
             }
 
             // if one of the paths was not found, replace it with the other one.
-            if (temporary_packed_leg1.empty())
+            if ((allow_u_turn && local_upper_bound1 > local_upper_bound2) || temporary_packed_leg1.empty())
             {
+                temporary_packed_leg1.clear();
                 temporary_packed_leg1.insert(temporary_packed_leg1.end(),
                                              temporary_packed_leg2.begin(),
                                              temporary_packed_leg2.end());
                 local_upper_bound1 = local_upper_bound2;
             }
-            if (temporary_packed_leg2.empty())
+            if ((allow_u_turn && local_upper_bound2 > local_upper_bound1) || temporary_packed_leg2.empty())
             {
+                temporary_packed_leg2.clear();
                 temporary_packed_leg2.insert(temporary_packed_leg2.end(),
                                              temporary_packed_leg1.begin(),
                                              temporary_packed_leg1.end());
@@ -223,7 +245,7 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
             BOOST_ASSERT((0 == current_leg) || !packed_legs1[current_leg - 1].empty());
             BOOST_ASSERT((0 == current_leg) || !packed_legs2[current_leg - 1].empty());
 
-            if (0 < current_leg)
+            if (!allow_u_turn && 0 < current_leg)
             {
                 const NodeID end_id_of_segment1 = packed_legs1[current_leg - 1].back();
                 const NodeID end_id_of_segment2 = packed_legs2[current_leg - 1].back();
@@ -236,13 +258,8 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
                     std::swap(temporary_packed_leg1, temporary_packed_leg2);
                     std::swap(local_upper_bound1, local_upper_bound2);
                 }
-            }
 
-            // remove the shorter path if both legs end at the same segment
-            if (0 < current_leg)
-            {
-                const NodeID start_id_of_leg1 = temporary_packed_leg1.front();
-                const NodeID start_id_of_leg2 = temporary_packed_leg2.front();
+                // remove the shorter path if both legs end at the same segment
                 if (start_id_of_leg1 == start_id_of_leg2)
                 {
                     const NodeID last_id_of_packed_legs1 = packed_legs1[current_leg - 1].back();
@@ -270,8 +287,8 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
                                              temporary_packed_leg2.end());
             BOOST_ASSERT(packed_legs2[current_leg].size() == temporary_packed_leg2.size());
 
-            if ((packed_legs1[current_leg].back() == packed_legs2[current_leg].back()) &&
-                phantom_node_pair.target_phantom.isBidirected())
+            if (!allow_u_turn && (packed_legs1[current_leg].back() == packed_legs2[current_leg].back()) &&
+                phantom_node_pair.target_phantom.is_bidirected())
             {
                 const NodeID last_node_id = packed_legs2[current_leg].back();
                 search_from_1st_node &=
@@ -292,27 +309,27 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
         }
         raw_route_data.unpacked_path_segments.resize(packed_legs1.size());
 
-        for (unsigned i = 0; i < packed_legs1.size(); ++i)
+        for (const std::size_t index : osrm::irange<std::size_t>(0, packed_legs1.size()))
         {
             BOOST_ASSERT(!phantom_nodes_vector.empty());
             BOOST_ASSERT(packed_legs1.size() == raw_route_data.unpacked_path_segments.size());
 
-            PhantomNodes unpack_phantom_node_pair = phantom_nodes_vector[i];
+            PhantomNodes unpack_phantom_node_pair = phantom_nodes_vector[index];
             super::UnpackPath(
                 // -- packed input
-                packed_legs1[i],
+                packed_legs1[index],
                 // -- start and end of (sub-)route
                 unpack_phantom_node_pair,
                 // -- unpacked output
-                raw_route_data.unpacked_path_segments[i]);
+                raw_route_data.unpacked_path_segments[index]);
 
             raw_route_data.source_traversed_in_reverse.push_back(
-            (packed_legs1[i].front() != phantom_nodes_vector[i].source_phantom.forward_node_id));
+            (packed_legs1[index].front() != phantom_nodes_vector[index].source_phantom.forward_node_id));
             raw_route_data.target_traversed_in_reverse.push_back(
-            (packed_legs1[i].back() != phantom_nodes_vector[i].target_phantom.forward_node_id));
+            (packed_legs1[index].back() != phantom_nodes_vector[index].target_phantom.forward_node_id));
         }
         raw_route_data.shortest_path_length = std::min(distance1, distance2);
     }
 };
 
-#endif /* SHORTEST_PATH_ROUTING_H */
+#endif /* SHORTEST_PATH_HPP */
diff --git a/taginfo.json b/taginfo.json
new file mode 100644
index 0000000..17a4f8f
--- /dev/null
+++ b/taginfo.json
@@ -0,0 +1,84 @@
+{
+    "data_format": 1,
+    "data_url": "https://raw.githubusercontent.com/Project-OSRM/osrm-backend/develop/taginfo.json",
+    "project": {
+        "name": "Open Source Routing Machine (car profile)",
+        "description": "High-performance routing engine for shortest paths in road networks.",
+        "project_url": "http://project-osrm.org",
+        "icon_url": "http://project-osrm.org/images/osrm_icon.png",
+        "contact_name": "Dennis Luxen",
+        "contact_email": "info at project-osrm.org"
+    },
+    "tags": [
+        {
+            "key": "highway",
+            "description": "Type of road.",
+            "object_types": [ "way" ]
+        },
+        {
+            "key": "service",
+            "value": "parking_aisle",
+            "object_types": [ "way" ]
+        },
+        {
+            "key": "oneway",
+            "object_types": [ "way" ]
+        },
+        {
+            "key": "area",
+            "value": "yes",
+            "object_types": [ "way" ],
+            "description": "Roads with area=yes are ignored by default."
+        },
+        {
+            "key": "impassable",
+            "description": "This is used by HOT."
+        },
+        {
+            "key": "status",
+            "description": "This is used by HOT."
+        },
+        {
+            "key": "access",
+            "object_types": [ "way" ]
+        },
+        {
+            "key": "barrier"
+        },
+        {
+            "key": "maxspeed",
+            "object_types": [ "way" ]
+        },
+        {
+            "key": "maxspeed:forward",
+            "object_types": [ "way" ]
+        },
+        {
+            "key": "maxspeed:backward",
+            "object_types": [ "way" ]
+        },
+        {
+            "key": "duration"
+        },
+        {
+            "key": "name",
+            "object_types": [ "way" ],
+            "description": "Name of road for navigation instructions."
+        },
+        {
+            "key": "ref",
+            "object_types": [ "way" ],
+            "description": "Ref of road for navigation instructions, overrides name."
+        },
+        {
+            "key": "junction",
+            "object_types": [ "way" ],
+            "value": "roundabout"
+        },
+        {
+            "key": "type",
+            "value": "restriction",
+            "object_types": [ "relation" ]
+        }
+    ]
+}
diff --git a/third_party/osmium/area/assembler.hpp b/third_party/osmium/area/assembler.hpp
new file mode 100644
index 0000000..155fa24
--- /dev/null
+++ b/third_party/osmium/area/assembler.hpp
@@ -0,0 +1,783 @@
+#ifndef OSMIUM_AREA_ASSEMBLER_HPP
+#define OSMIUM_AREA_ASSEMBLER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <list>
+#include <map>
+#include <vector>
+
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/area.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/tags/filter.hpp>
+
+#include <osmium/area/detail/proto_ring.hpp>
+#include <osmium/area/detail/node_ref_segment.hpp>
+#include <osmium/area/detail/segment_list.hpp>
+#include <osmium/area/problem_reporter.hpp>
+
+namespace osmium {
+
+    namespace area {
+
+        using osmium::area::detail::ProtoRing;
+
+        struct AssemblerConfig {
+
+            osmium::area::ProblemReporter* problem_reporter;
+
+            // Enables debug output to stderr
+            bool debug;
+
+            explicit AssemblerConfig(osmium::area::ProblemReporter* pr = nullptr, bool d=false) :
+                problem_reporter(pr),
+                debug(d) {
+            }
+
+            /**
+             * Enable or disable debug output to stderr. This is for Osmium
+             * developers only.
+             */
+            void enable_debug_output(bool d=true) {
+                debug = d;
+            }
+
+        }; // struct AssemblerConfig
+
+        /**
+         * Assembles area objects from multipolygon relations and their
+         * members. This is called by the MultipolygonCollector object
+         * after all members have been collected.
+         */
+        class Assembler {
+
+            const AssemblerConfig m_config;
+
+            // The way segments
+            osmium::area::detail::SegmentList m_segment_list;
+
+            // The rings we are building from the way segments
+            std::list<ProtoRing> m_rings;
+
+            std::vector<ProtoRing*> m_outer_rings;
+            std::vector<ProtoRing*> m_inner_rings;
+
+            int m_inner_outer_mismatches { 0 };
+
+            bool debug() const {
+                return m_config.debug;
+            }
+
+            /**
+             * Checks whether the given NodeRefs have the same location.
+             * Uses the actual location for the test, not the id. If both
+             * have the same location, but not the same id, a problem
+             * point will be added to the list of problem points.
+             */
+            bool has_same_location(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) {
+                if (nr1.location() != nr2.location()) {
+                    return false;
+                }
+                if (nr1.ref() != nr2.ref()) {
+                    if (m_config.problem_reporter) {
+                        m_config.problem_reporter->report_duplicate_node(nr1.ref(), nr2.ref(), nr1.location());
+                    }
+                }
+                return true;
+            }
+
+            void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Way& way) const {
+                osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
+                for (const osmium::Tag& tag : way.tags()) {
+                    tl_builder.add_tag(tag.key(), tag.value());
+                }
+            }
+
+            void add_common_tags(osmium::builder::TagListBuilder& tl_builder, std::set<const osmium::Way*>& ways) const {
+                std::map<std::string, size_t> counter;
+                for (const osmium::Way* way : ways) {
+                    for (const auto& tag : way->tags()) {
+                        std::string kv {tag.key()};
+                        kv.append(1, '\0');
+                        kv.append(tag.value());
+                        ++counter[kv];
+                    }
+                }
+
+                size_t num_ways = ways.size();
+                for (const auto& t_c : counter) {
+                    if (debug()) {
+                        std::cerr << "        tag " << t_c.first << " is used " << t_c.second << " times in " << num_ways << " ways\n";
+                    }
+                    if (t_c.second == num_ways) {
+                        size_t len = std::strlen(t_c.first.c_str());
+                        tl_builder.add_tag(t_c.first.c_str(), t_c.first.c_str() + len + 1);
+                    }
+                }
+            }
+
+            struct MPFilter : public osmium::tags::KeyFilter {
+
+                MPFilter() : osmium::tags::KeyFilter(true) {
+                    add(false, "type");
+                    add(false, "created_by");
+                    add(false, "source");
+                    add(false, "note");
+                    add(false, "test:id");
+                    add(false, "test:section");
+                }
+
+            }; // struct MPFilter
+
+            static MPFilter& filter() {
+                static MPFilter filter;
+                return filter;
+            }
+
+            void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Relation& relation) const {
+                auto count = std::count_if(relation.tags().begin(), relation.tags().end(), filter());
+
+                if (debug()) {
+                    std::cerr << "  found " << count << " tags on relation (without ignored ones)\n";
+                }
+
+                if (count > 0) {
+                    if (debug()) {
+                        std::cerr << "    use tags from relation\n";
+                    }
+
+                    // write out all tags except type=*
+                    osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
+                    for (const osmium::Tag& tag : relation.tags()) {
+                        if (strcmp(tag.key(), "type")) {
+                            tl_builder.add_tag(tag.key(), tag.value());
+                        }
+                    }
+                } else {
+                    if (debug()) {
+                        std::cerr << "    use tags from outer ways\n";
+                    }
+                    std::set<const osmium::Way*> ways;
+                    for (const auto& ring : m_outer_rings) {
+                        ring->get_ways(ways);
+                    }
+                    if (ways.size() == 1) {
+                        if (debug()) {
+                            std::cerr << "      only one outer way\n";
+                        }
+                        osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
+                        for (const osmium::Tag& tag : (*ways.begin())->tags()) {
+                            tl_builder.add_tag(tag.key(), tag.value());
+                        }
+                    } else {
+                        if (debug()) {
+                            std::cerr << "      multiple outer ways, get common tags\n";
+                        }
+                        osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
+                        add_common_tags(tl_builder, ways);
+                    }
+                }
+            }
+
+            /**
+             * Go through all the rings and find rings that are not closed.
+             * Problems are reported through the problem reporter.
+             *
+             * @returns true if any rings were not closed, false otherwise
+             */
+            bool check_for_open_rings() {
+                bool open_rings = false;
+
+                for (const auto& ring : m_rings) {
+                    if (!ring.closed()) {
+                        open_rings = true;
+                        if (m_config.problem_reporter) {
+                            m_config.problem_reporter->report_ring_not_closed(ring.get_segment_front().first().location(), ring.get_segment_back().second().location());
+                        }
+                    }
+                }
+
+                return open_rings;
+            }
+
+            /**
+             * Check whether there are any rings that can be combined with the
+             * given ring to one larger ring by appending the other ring to
+             * the end of this ring.
+             * If the rings can be combined they are and the function returns
+             * true.
+             */
+            bool possibly_combine_rings_back(ProtoRing& ring) {
+                const osmium::NodeRef& nr = ring.get_segment_back().second();
+
+                if (debug()) {
+                    std::cerr << "      possibly_combine_rings_back()\n";
+                }
+                for (auto it = m_rings.begin(); it != m_rings.end(); ++it) {
+                    if (&*it != &ring && !it->closed()) {
+                        if (has_same_location(nr, it->get_segment_front().first())) {
+                            if (debug()) {
+                                std::cerr << "      ring.last=it->first\n";
+                            }
+                            ring.merge_ring(*it, debug());
+                            m_rings.erase(it);
+                            return true;
+                        }
+                        if (has_same_location(nr, it->get_segment_back().second())) {
+                            if (debug()) {
+                                std::cerr << "      ring.last=it->last\n";
+                            }
+                            ring.merge_ring_reverse(*it, debug());
+                            m_rings.erase(it);
+                            return true;
+                        }
+                    }
+                }
+                return false;
+            }
+
+            /**
+             * Check whether there are any rings that can be combined with the
+             * given ring to one larger ring by prepending the other ring to
+             * the start of this ring.
+             * If the rings can be combined they are and the function returns
+             * true.
+             */
+            bool possibly_combine_rings_front(ProtoRing& ring) {
+                const osmium::NodeRef& nr = ring.get_segment_front().first();
+
+                if (debug()) {
+                    std::cerr << "      possibly_combine_rings_front()\n";
+                }
+                for (auto it = m_rings.begin(); it != m_rings.end(); ++it) {
+                    if (&*it != &ring && !it->closed()) {
+                        if (has_same_location(nr, it->get_segment_back().second())) {
+                            if (debug()) {
+                                std::cerr << "      ring.first=it->last\n";
+                            }
+                            ring.swap_segments(*it);
+                            ring.merge_ring(*it, debug());
+                            m_rings.erase(it);
+                            return true;
+                        }
+                        if (has_same_location(nr, it->get_segment_front().first())) {
+                            if (debug()) {
+                                std::cerr << "      ring.first=it->first\n";
+                            }
+                            ring.reverse();
+                            ring.merge_ring(*it, debug());
+                            m_rings.erase(it);
+                            return true;
+                        }
+                    }
+                }
+                return false;
+            }
+
+            void split_off_subring(osmium::area::detail::ProtoRing& ring, osmium::area::detail::ProtoRing::segments_type::iterator it, osmium::area::detail::ProtoRing::segments_type::iterator it_begin, osmium::area::detail::ProtoRing::segments_type::iterator it_end) {
+                if (debug()) {
+                    std::cerr << "        subring found at: " << *it << "\n";
+                }
+                ProtoRing new_ring(it_begin, it_end);
+                ring.remove_segments(it_begin, it_end);
+                if (debug()) {
+                    std::cerr << "        split into two rings:\n";
+                    std::cerr << "          " << new_ring << "\n";
+                    std::cerr << "          " << ring << "\n";
+                }
+                m_rings.push_back(std::move(new_ring));
+            }
+
+            bool has_closed_subring_back(ProtoRing& ring, const NodeRef& nr) {
+                if (ring.segments().size() < 3) {
+                    return false;
+                }
+                if (debug()) {
+                    std::cerr << "      has_closed_subring_back()\n";
+                }
+                auto end = ring.segments().end();
+                for (auto it = ring.segments().begin() + 1; it != end - 1; ++it) {
+                    if (has_same_location(nr, it->first())) {
+                        split_off_subring(ring, it, it, end);
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            bool has_closed_subring_front(ProtoRing& ring, const NodeRef& nr) {
+                if (ring.segments().size() < 3) {
+                    return false;
+                }
+                if (debug()) {
+                    std::cerr << "      has_closed_subring_front()\n";
+                }
+                auto end = ring.segments().end();
+                for (auto it = ring.segments().begin() + 1; it != end - 1; ++it) {
+                    if (has_same_location(nr, it->second())) {
+                        split_off_subring(ring, it, ring.segments().begin(), it+1);
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            bool check_for_closed_subring(ProtoRing& ring) {
+                if (debug()) {
+                    std::cerr << "      check_for_closed_subring()\n";
+                }
+
+                osmium::area::detail::ProtoRing::segments_type segments(ring.segments().size());
+                std::copy(ring.segments().begin(), ring.segments().end(), segments.begin());
+                std::sort(segments.begin(), segments.end());
+                auto it = std::adjacent_find(segments.begin(), segments.end(), [this](const osmium::area::detail::NodeRefSegment& s1, const osmium::area::detail::NodeRefSegment& s2) {
+                    return has_same_location(s1.first(), s2.first());
+                });
+                if (it == segments.end()) {
+                    return false;
+                }
+                auto r1 = std::find_first_of(ring.segments().begin(), ring.segments().end(), it, it+1);
+                assert(r1 != ring.segments().end());
+                auto r2 = std::find_first_of(ring.segments().begin(), ring.segments().end(), it+1, it+2);
+                assert(r2 != ring.segments().end());
+
+                if (debug()) {
+                    std::cerr << "      found subring in ring " << ring << " at " << it->first() << "\n";
+                }
+
+                auto m = std::minmax(r1, r2);
+
+                ProtoRing new_ring(m.first, m.second);
+                ring.remove_segments(m.first, m.second);
+
+                if (debug()) {
+                    std::cerr << "        split ring1=" << new_ring << "\n";
+                    std::cerr << "        split ring2=" << ring << "\n";
+                }
+
+                m_rings.emplace_back(new_ring);
+
+                return true;
+            }
+
+            void combine_rings_front(const osmium::area::detail::NodeRefSegment& segment, ProtoRing& ring) {
+                if (debug()) {
+                    std::cerr << " => match at front of ring\n";
+                }
+                ring.add_segment_front(segment);
+                has_closed_subring_front(ring, segment.first());
+                if (possibly_combine_rings_front(ring)) {
+                    check_for_closed_subring(ring);
+                }
+            }
+
+            void combine_rings_back(const osmium::area::detail::NodeRefSegment& segment, ProtoRing& ring) {
+                if (debug()) {
+                    std::cerr << " => match at back of ring\n";
+                }
+                ring.add_segment_back(segment);
+                has_closed_subring_back(ring, segment.second());
+                if (possibly_combine_rings_back(ring)) {
+                    check_for_closed_subring(ring);
+                }
+            }
+
+            /**
+             * Append each outer ring together with its inner rings to the
+             * area in the buffer.
+             */
+            void add_rings_to_area(osmium::builder::AreaBuilder& builder) const {
+                for (const ProtoRing* ring : m_outer_rings) {
+                    if (debug()) {
+                        std::cerr << "    ring " << *ring << " is outer\n";
+                    }
+                    {
+                        osmium::builder::OuterRingBuilder ring_builder(builder.buffer(), &builder);
+                        ring_builder.add_node_ref(ring->get_segment_front().first());
+                        for (const auto& segment : ring->segments()) {
+                            ring_builder.add_node_ref(segment.second());
+                        }
+                    }
+                    for (ProtoRing* inner : ring->inner_rings()) {
+                        osmium::builder::InnerRingBuilder ring_builder(builder.buffer(), &builder);
+                        ring_builder.add_node_ref(inner->get_segment_front().first());
+                        for (const auto& segment : inner->segments()) {
+                            ring_builder.add_node_ref(segment.second());
+                        }
+                    }
+                }
+            }
+
+            bool add_to_existing_ring(osmium::area::detail::NodeRefSegment segment) {
+                int n=0;
+                for (auto& ring : m_rings) {
+                    if (debug()) {
+                        std::cerr << "    check against ring " << n << " " << ring;
+                    }
+                    if (ring.closed()) {
+                        if (debug()) {
+                            std::cerr << " => ring CLOSED\n";
+                        }
+                    } else {
+                        if (has_same_location(ring.get_segment_back().second(), segment.first())) {
+                            combine_rings_back(segment, ring);
+                            return true;
+                        }
+                        if (has_same_location(ring.get_segment_back().second(), segment.second())) {
+                            segment.swap_locations();
+                            combine_rings_back(segment, ring);
+                            return true;
+                        }
+                        if (has_same_location(ring.get_segment_front().first(), segment.first())) {
+                            segment.swap_locations();
+                            combine_rings_front(segment, ring);
+                            return true;
+                        }
+                        if (has_same_location(ring.get_segment_front().first(), segment.second())) {
+                            combine_rings_front(segment, ring);
+                            return true;
+                        }
+                        if (debug()) {
+                            std::cerr << " => no match\n";
+                        }
+                    }
+
+                    ++n;
+                }
+                return false;
+            }
+
+            void check_inner_outer(ProtoRing& ring) {
+                const osmium::NodeRef& min_node = ring.min_node();
+                if (debug()) {
+                    std::cerr << "    check_inner_outer min_node=" << min_node << "\n";
+                }
+
+                int count = 0;
+                int above = 0;
+
+                for (auto it = m_segment_list.begin(); it != m_segment_list.end() && it->first().location().x() <= min_node.location().x(); ++it) {
+                    if (!ring.contains(*it)) {
+                        if (debug()) {
+                            std::cerr << "      segments for count: " << *it;
+                        }
+                        if (it->to_left_of(min_node.location())) {
+                            ++count;
+                            if (debug()) {
+                                std::cerr << " counted\n";
+                            }
+                        } else {
+                            if (debug()) {
+                                std::cerr << " not counted\n";
+                            }
+                        }
+                        if (it->first().location() == min_node.location()) {
+                            if (it->second().location().y() > min_node.location().y()) {
+                                ++above;
+                            }
+                        }
+                        if (it->second().location() == min_node.location()) {
+                            if (it->first().location().y() > min_node.location().y()) {
+                                ++above;
+                            }
+                        }
+                    }
+                }
+
+                if (debug()) {
+                    std::cerr << "      count=" << count << " above=" << above << "\n";
+                }
+
+                count += above % 2;
+
+                if (count % 2) {
+                    ring.set_inner();
+                }
+            }
+
+            void check_inner_outer_roles() {
+                if (debug()) {
+                    std::cerr << "    check_inner_outer_roles\n";
+                }
+
+                for (const auto ringptr : m_outer_rings) {
+                    for (const auto segment : ringptr->segments()) {
+                        if (!segment.role_outer()) {
+                            ++m_inner_outer_mismatches;
+                            if (debug()) {
+                                std::cerr << "      segment " << segment << " from way " << segment.way()->id() << " should have role 'outer'\n";
+                            }
+                            if (m_config.problem_reporter) {
+                                m_config.problem_reporter->report_role_should_be_outer(segment.way()->id(), segment.first().location(), segment.second().location());
+                            }
+                        }
+                    }
+                }
+                for (const auto ringptr : m_inner_rings) {
+                    for (const auto segment : ringptr->segments()) {
+                        if (!segment.role_inner()) {
+                            ++m_inner_outer_mismatches;
+                            if (debug()) {
+                                std::cerr << "      segment " << segment << " from way " << segment.way()->id() << " should have role 'inner'\n";
+                            }
+                            if (m_config.problem_reporter) {
+                                m_config.problem_reporter->report_role_should_be_inner(segment.way()->id(), segment.first().location(), segment.second().location());
+                            }
+                        }
+                    }
+                }
+            }
+
+            /**
+             * Create rings from segments.
+             */
+            bool create_rings() {
+                m_segment_list.sort();
+                m_segment_list.erase_duplicate_segments();
+
+                // Now we look for segments crossing each other. If there are
+                // any, the multipolygon is invalid.
+                // In the future this could be improved by trying to fix those
+                // cases.
+                if (m_segment_list.find_intersections(m_config.problem_reporter)) {
+                    return false;
+                }
+
+                // Now iterator over all segments and add them to rings. Each segment
+                // is tacked on to either end of an existing ring if possible, or a
+                // new ring is started with it.
+                for (const auto& segment : m_segment_list) {
+                    if (debug()) {
+                        std::cerr << "  checking segment " << segment << "\n";
+                    }
+                    if (!add_to_existing_ring(segment)) {
+                        if (debug()) {
+                            std::cerr << "    new ring for segment " << segment << "\n";
+                        }
+                        m_rings.emplace_back(segment);
+                    }
+                }
+
+                if (debug()) {
+                    std::cerr << "  Rings:\n";
+                    for (const auto& ring : m_rings) {
+                        std::cerr << "    " << ring;
+                        if (ring.closed()) {
+                            std::cerr << " (closed)";
+                        }
+                        std::cerr << "\n";
+                    }
+                }
+
+                if (check_for_open_rings()) {
+                    if (debug()) {
+                        std::cerr << "  not all rings are closed\n";
+                    }
+                    return false;
+                }
+
+                if (debug()) {
+                    std::cerr << "  Find inner/outer...\n";
+                }
+
+                if (m_rings.size() == 1) {
+                    m_outer_rings.push_back(&m_rings.front());
+                } else {
+                    for (auto& ring : m_rings) {
+                        check_inner_outer(ring);
+                        if (ring.outer()) {
+                            if (!ring.is_cw()) {
+                                ring.reverse();
+                            }
+                            m_outer_rings.push_back(&ring);
+                        } else {
+                            if (ring.is_cw()) {
+                                ring.reverse();
+                            }
+                            m_inner_rings.push_back(&ring);
+                        }
+                    }
+
+                    if (m_outer_rings.size() == 1) {
+                        for (auto inner : m_inner_rings) {
+                            m_outer_rings.front()->add_inner_ring(inner);
+                        }
+                    } else {
+                        // sort outer rings by size, smallest first
+                        std::sort(m_outer_rings.begin(), m_outer_rings.end(), [](ProtoRing* a, ProtoRing* b) {
+                            return a->area() < b->area();
+                        });
+                        for (auto inner : m_inner_rings) {
+                            for (auto outer : m_outer_rings) {
+                                if (inner->is_in(outer)) {
+                                    outer->add_inner_ring(inner);
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+
+                check_inner_outer_roles();
+
+                return true;
+            }
+
+        public:
+
+            typedef osmium::area::AssemblerConfig config_type;
+
+            explicit Assembler(const config_type& config) :
+                m_config(config),
+                m_segment_list(config.debug) {
+            }
+
+            ~Assembler() = default;
+
+            /**
+             * Assemble an area from the given way.
+             * The resulting area is put into the out_buffer.
+             */
+            void operator()(const osmium::Way& way, osmium::memory::Buffer& out_buffer) {
+                if (m_config.problem_reporter) {
+                    m_config.problem_reporter->set_object(osmium::item_type::way, way.id());
+                }
+
+                if (!way.ends_have_same_id()) {
+                    if (m_config.problem_reporter) {
+                        m_config.problem_reporter->report_duplicate_node(way.nodes().front().ref(), way.nodes().back().ref(), way.nodes().front().location());
+                    }
+                }
+
+                m_segment_list.extract_segments_from_way(way, "outer");
+
+                if (debug()) {
+                    std::cerr << "\nBuild way id()=" << way.id() << " segments.size()=" << m_segment_list.size() << "\n";
+                }
+
+                // Now create the Area object and add the attributes and tags
+                // from the relation.
+                {
+                    osmium::builder::AreaBuilder builder(out_buffer);
+                    builder.initialize_from_object(way);
+
+                    if (create_rings()) {
+                        add_tags_to_area(builder, way);
+                        add_rings_to_area(builder);
+                    }
+                }
+                out_buffer.commit();
+            }
+
+            /**
+             * Assemble an area from the given relation and its members.
+             * All members are to be found in the in_buffer at the offsets
+             * given by the members parameter.
+             * The resulting area is put into the out_buffer.
+             */
+            void operator()(const osmium::Relation& relation, const std::vector<size_t>& members, const osmium::memory::Buffer& in_buffer, osmium::memory::Buffer& out_buffer) {
+                if (m_config.problem_reporter) {
+                    m_config.problem_reporter->set_object(osmium::item_type::relation, relation.id());
+                }
+
+                m_segment_list.extract_segments_from_ways(relation, members, in_buffer);
+
+                if (debug()) {
+                    std::cerr << "\nBuild relation id()=" << relation.id() << " members.size()=" << members.size() << " segments.size()=" << m_segment_list.size() << "\n";
+                }
+
+                size_t area_offset = out_buffer.committed();
+
+                // Now create the Area object and add the attributes and tags
+                // from the relation.
+                {
+                    osmium::builder::AreaBuilder builder(out_buffer);
+                    builder.initialize_from_object(relation);
+
+                    if (create_rings()) {
+                        add_tags_to_area(builder, relation);
+                        add_rings_to_area(builder);
+                    }
+                }
+                out_buffer.commit();
+
+                const osmium::TagList& area_tags = out_buffer.get<osmium::Area>(area_offset).tags(); // tags of the area we just built
+
+                // Find all closed ways that are inner rings and check their
+                // tags. If they are not the same as the tags of the area we
+                // just built, add them to a list and later build areas for
+                // them, too.
+                std::vector<const osmium::Way*> ways_that_should_be_areas;
+                if (m_inner_outer_mismatches == 0) {
+                    auto memit = relation.members().begin();
+                    for (size_t offset : members) {
+                        if (!std::strcmp(memit->role(), "inner")) {
+                            const osmium::Way& way = in_buffer.get<const osmium::Way>(offset);
+                            if (way.is_closed() && way.tags().size() > 0) {
+                                auto d = std::count_if(way.tags().begin(), way.tags().end(), filter());
+                                if (d > 0) {
+                                    osmium::tags::KeyFilter::iterator way_fi_begin(filter(), way.tags().begin(), way.tags().end());
+                                    osmium::tags::KeyFilter::iterator way_fi_end(filter(), way.tags().end(), way.tags().end());
+                                    osmium::tags::KeyFilter::iterator area_fi_begin(filter(), area_tags.begin(), area_tags.end());
+                                    osmium::tags::KeyFilter::iterator area_fi_end(filter(), area_tags.end(), area_tags.end());
+
+                                    if (!std::equal(way_fi_begin, way_fi_end, area_fi_begin) || d != std::distance(area_fi_begin, area_fi_end)) {
+                                        ways_that_should_be_areas.push_back(&way);
+                                    }
+                                }
+                            }
+                        }
+                        ++memit;
+                    }
+                }
+
+                // Now build areas for all ways found in the last step.
+                for (const osmium::Way* way : ways_that_should_be_areas) {
+                    Assembler assembler(m_config);
+                    assembler(*way, out_buffer);
+                }
+            }
+
+        }; // class Assembler
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_ASSEMBLER_HPP
diff --git a/third_party/osmium/area/detail/node_ref_segment.hpp b/third_party/osmium/area/detail/node_ref_segment.hpp
new file mode 100644
index 0000000..5b251bb
--- /dev/null
+++ b/third_party/osmium/area/detail/node_ref_segment.hpp
@@ -0,0 +1,262 @@
+#ifndef OSMIUM_AREA_DETAIL_NODE_REF_SEGMENT_HPP
+#define OSMIUM_AREA_DETAIL_NODE_REF_SEGMENT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstdint>
+#include <cstring>
+#include <iosfwd>
+#include <utility>
+
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node_ref.hpp>
+
+namespace osmium {
+
+    class Way;
+
+    namespace area {
+
+        /**
+         * @brief Namespace for Osmium internal use
+         */
+        namespace detail {
+
+            /**
+             * This helper class for the Assembler class models a segment.
+             * Segments are the connection between
+             * two nodes and they all have their smaller coordinate at the
+             * beginning of the segment. Smaller, in this case, means smaller x
+             * coordinate, and if they are the same smaller y coordinate.
+             */
+            class NodeRefSegment {
+
+                osmium::NodeRef m_first;
+                osmium::NodeRef m_second;
+
+                /// Role of the member this segment was from.
+                const char* m_role;
+
+                /// Way this segment was from.
+                const osmium::Way* m_way;
+
+            public:
+
+                void swap_locations() {
+                    using std::swap;
+                    swap(m_first, m_second);
+                }
+
+                explicit NodeRefSegment() noexcept :
+                    m_first(),
+                    m_second(),
+                    m_role(nullptr),
+                    m_way(nullptr) {
+                }
+
+                explicit NodeRefSegment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2, const char* role, const osmium::Way* way) :
+                    m_first(nr1),
+                    m_second(nr2),
+                    m_role(role),
+                    m_way(way) {
+                    if (nr2.location() < nr1.location()) {
+                        swap_locations();
+                    }
+                }
+
+                NodeRefSegment(const NodeRefSegment&) = default;
+                NodeRefSegment(NodeRefSegment&&) = default;
+
+                NodeRefSegment& operator=(const NodeRefSegment&) = default;
+                NodeRefSegment& operator=(NodeRefSegment&&) = default;
+
+                ~NodeRefSegment() = default;
+
+                /// Return first NodeRef of Segment according to sorting order (bottom left to top right).
+                const osmium::NodeRef& first() const noexcept {
+                    return m_first;
+                }
+
+                /// Return second NodeRef of Segment according to sorting order (bottom left to top right).
+                const osmium::NodeRef& second() const noexcept {
+                    return m_second;
+                }
+
+                bool to_left_of(const osmium::Location location) const {
+    //                std::cerr << "segment " << first() << "--" << second() << " to_left_of(" << location << "\n";
+
+                    if (first().location() == location || second().location() == location) {
+                        return false;
+                    }
+
+                    const std::pair<osmium::Location, osmium::Location> mm = std::minmax(first().location(), second().location(), [](const osmium::Location a, const osmium::Location b) {
+                        return a.y() < b.y();
+                    });
+
+                    if (mm.first.y() >= location.y() || mm.second.y() < location.y() || first().location().x() > location.x()) {
+    //                    std::cerr << "  false\n";
+                        return false;
+                    }
+
+                    int64_t ax = mm.first.x();
+                    int64_t bx = mm.second.x();
+                    int64_t lx = location.x();
+                    int64_t ay = mm.first.y();
+                    int64_t by = mm.second.y();
+                    int64_t ly = location.y();
+                    return ((bx - ax)*(ly - ay) - (by - ay)*(lx - ax)) <= 0;
+                }
+
+                bool role_outer() const noexcept {
+                    return !strcmp(m_role, "outer");
+                }
+
+                bool role_inner() const noexcept {
+                    return !strcmp(m_role, "inner");
+                }
+
+                const osmium::Way* way() const noexcept {
+                    return m_way;
+                }
+
+            }; // class NodeRefSegment
+
+            /// NodeRefSegments are equal if both their locations are equal
+            inline bool operator==(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+                return lhs.first().location() == rhs.first().location() && lhs.second().location() == rhs.second().location();
+            }
+
+            inline bool operator!=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+                return ! (lhs == rhs);
+            }
+
+            /**
+             * NodeRefSegments are "smaller" if they are to the left and down of another
+             * segment. The first() location is checked first() and only if they have the
+             * same first() location the second() location is taken into account.
+             */
+            inline bool operator<(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+                return (lhs.first().location() == rhs.first().location() && lhs.second().location() < rhs.second().location()) || lhs.first().location() < rhs.first().location();
+            }
+
+            inline bool operator>(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+                return rhs < lhs;
+            }
+
+            inline bool operator<=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+                return ! (rhs < lhs);
+            }
+
+            inline bool operator>=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+                return ! (lhs < rhs);
+            }
+
+            template <typename TChar, typename TTraits>
+            inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const NodeRefSegment& segment) {
+                return out << segment.first() << "--" << segment.second();
+            }
+
+            inline bool outside_x_range(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
+                if (s1.first().location().x() > s2.second().location().x()) {
+                    return true;
+                }
+                return false;
+            }
+
+            inline bool y_range_overlap(const NodeRefSegment& s1, const NodeRefSegment& s2) {
+                auto m1 = std::minmax(s1.first().location().y(), s1.second().location().y());
+                auto m2 = std::minmax(s2.first().location().y(), s2.second().location().y());
+                if (m1.first > m2.second || m2.first > m1.second) {
+                    return false;
+                }
+                return true;
+            }
+
+            /**
+             * Calculate the intersection between to NodeRefSegments. The result is returned
+             * as a Location. Note that because the Location uses integers with limited
+             * precision internally, the result might be slightly different than the
+             * numerically correct location.
+             *
+             * If the segments touch in one of their endpoints, it doesn't count as an
+             * intersection.
+             *
+             * If the segments intersect not in a single point but in multiple points, ie
+             * if they overlap, this is NOT detected.
+             *
+             * @returns Undefined osmium::Location if there is no intersection or a defined
+             *          Location if the segments intersect.
+             */
+            inline osmium::Location calculate_intersection(const NodeRefSegment& s1, const NodeRefSegment& s2) {
+                if (s1.first().location()  == s2.first().location()  ||
+                    s1.first().location()  == s2.second().location() ||
+                    s1.second().location() == s2.first().location()  ||
+                    s1.second().location() == s2.second().location()) {
+                    return osmium::Location();
+                }
+
+                auto d = (static_cast<int64_t>(s2.second().y()) - static_cast<int64_t>(s2.first().y())) *
+                         (static_cast<int64_t>(s1.second().x()) - static_cast<int64_t>(s1.first().x())) -
+                         (static_cast<int64_t>(s2.second().x()) - static_cast<int64_t>(s2.first().x())) *
+                         (static_cast<int64_t>(s1.second().y()) - static_cast<int64_t>(s1.first().y()));
+
+                if (d != 0) {
+                    double denom  = ((s2.second().lat() - s2.first().lat())*(s1.second().lon() - s1.first().lon())) -
+                                    ((s2.second().lon() - s2.first().lon())*(s1.second().lat() - s1.first().lat()));
+
+                    double nume_a = ((s2.second().lon() - s2.first().lon())*(s1.first().lat() - s2.first().lat())) -
+                                    ((s2.second().lat() - s2.first().lat())*(s1.first().lon() - s2.first().lon()));
+
+                    double nume_b = ((s1.second().lon() - s1.first().lon())*(s1.first().lat() - s2.first().lat())) -
+                                    ((s1.second().lat() - s1.first().lat())*(s1.first().lon() - s2.first().lon()));
+
+                    if ((denom > 0 && nume_a >= 0 && nume_a <= denom && nume_b >= 0 && nume_b <= denom) ||
+                        (denom < 0 && nume_a <= 0 && nume_a >= denom && nume_b <= 0 && nume_b >= denom)) {
+                        double ua = nume_a / denom;
+                        double ix = s1.first().lon() + ua*(s1.second().lon() - s1.first().lon());
+                        double iy = s1.first().lat() + ua*(s1.second().lat() - s1.first().lat());
+                        return osmium::Location(ix, iy);
+                    }
+                }
+
+                return osmium::Location();
+            }
+
+        } // namespace detail
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_DETAIL_NODE_REF_SEGMENT_HPP
diff --git a/third_party/osmium/area/detail/proto_ring.hpp b/third_party/osmium/area/detail/proto_ring.hpp
new file mode 100644
index 0000000..63fec5b
--- /dev/null
+++ b/third_party/osmium/area/detail/proto_ring.hpp
@@ -0,0 +1,274 @@
+#ifndef OSMIUM_AREA_DETAIL_PROTO_RING_HPP
+#define OSMIUM_AREA_DETAIL_PROTO_RING_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <iostream>
+#include <list>
+#include <set>
+#include <vector>
+
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/area/detail/node_ref_segment.hpp>
+
+namespace osmium {
+
+    namespace area {
+
+        namespace detail {
+
+            /**
+             * A ring in the process of being built by the Assembler object.
+             */
+            class ProtoRing {
+
+            public:
+
+                typedef std::vector<NodeRefSegment> segments_type;
+
+            private:
+
+                // segments in this ring
+                segments_type m_segments;
+
+                bool m_outer {true};
+
+                // if this is an outer ring, these point to it's inner rings (if any)
+                std::vector<ProtoRing*> m_inner;
+
+            public:
+
+                explicit ProtoRing(const NodeRefSegment& segment) noexcept :
+                    m_segments() {
+                    add_segment_back(segment);
+                }
+
+                explicit ProtoRing(segments_type::const_iterator sbegin, segments_type::const_iterator send) :
+                    m_segments(static_cast<size_t>(std::distance(sbegin, send))) {
+                    std::copy(sbegin, send, m_segments.begin());
+                }
+
+                bool outer() const noexcept {
+                    return m_outer;
+                }
+
+                void set_inner() noexcept {
+                    m_outer = false;
+                }
+
+                segments_type& segments() noexcept {
+                    return m_segments;
+                }
+
+                const segments_type& segments() const noexcept {
+                    return m_segments;
+                }
+
+                void remove_segments(segments_type::iterator sbegin, segments_type::iterator send) {
+                    m_segments.erase(sbegin, send);
+                }
+
+                void add_segment_front(const NodeRefSegment& segment) {
+                    m_segments.insert(m_segments.begin(), segment);
+                }
+
+                void add_segment_back(const NodeRefSegment& segment) {
+                    m_segments.push_back(segment);
+                }
+
+                const NodeRefSegment& get_segment_front() const {
+                    return m_segments.front();
+                }
+
+                NodeRefSegment& get_segment_front() {
+                    return m_segments.front();
+                }
+
+                const NodeRefSegment& get_segment_back() const {
+                    return m_segments.back();
+                }
+
+                NodeRefSegment& get_segment_back() {
+                    return m_segments.back();
+                }
+
+                bool closed() const {
+                    return m_segments.front().first().location() == m_segments.back().second().location();
+                }
+
+                int64_t sum() const {
+                    int64_t sum = 0;
+
+                    for (const auto& segment : m_segments) {
+                        sum += static_cast<int64_t>(segment.first().location().x()) * static_cast<int64_t>(segment.second().location().y()) -
+                               static_cast<int64_t>(segment.second().location().x()) * static_cast<int64_t>(segment.first().location().y());
+                    }
+
+                    return sum;
+                }
+
+                bool is_cw() const {
+                    return sum() <= 0;
+                }
+
+                int64_t area() const {
+                    return std::abs(sum()) / 2;
+                }
+
+                void swap_segments(ProtoRing& other) {
+                    std::swap(m_segments, other.m_segments);
+                }
+
+                void add_inner_ring(ProtoRing* ring) {
+                    m_inner.push_back(ring);
+                }
+
+                const std::vector<ProtoRing*> inner_rings() const {
+                    return m_inner;
+                }
+
+                void print(std::ostream& out) const {
+                    out << "[";
+                    bool first = true;
+                    for (const auto& segment : m_segments) {
+                        if (first) {
+                            out << segment.first().ref();
+                        }
+                        out << ',' << segment.second().ref();
+                        first = false;
+                    }
+                    out << "]";
+                }
+
+                void reverse() {
+                    std::for_each(m_segments.begin(), m_segments.end(), [](NodeRefSegment& segment) {
+                        segment.swap_locations();
+                    });
+                    std::reverse(m_segments.begin(), m_segments.end());
+                }
+
+                /**
+                 * Merge other ring to end of this ring.
+                 */
+                void merge_ring(const ProtoRing& other, bool debug) {
+                    if (debug) {
+                        std::cerr << "        MERGE rings ";
+                        print(std::cerr);
+                        std::cerr << " to ";
+                        other.print(std::cerr);
+                        std::cerr << "\n";
+                    }
+                    m_segments.insert(m_segments.end(), other.m_segments.begin(), other.m_segments.end());
+                    if (debug) {
+                        std::cerr << "          result ring: ";
+                        print(std::cerr);
+                        std::cerr << "\n";
+                    }
+                }
+
+                void merge_ring_reverse(const ProtoRing& other, bool debug) {
+                    if (debug) {
+                        std::cerr << "        MERGE rings (reverse) ";
+                        print(std::cerr);
+                        std::cerr << " to ";
+                        other.print(std::cerr);
+                        std::cerr << "\n";
+                    }
+                    size_t n = m_segments.size();
+                    m_segments.resize(n + other.m_segments.size());
+                    std::transform(other.m_segments.rbegin(), other.m_segments.rend(), m_segments.begin() + static_cast<segments_type::difference_type>(n), [](NodeRefSegment segment) {
+                        segment.swap_locations();
+                        return segment;
+                    });
+                    if (debug) {
+                        std::cerr << "          result ring: ";
+                        print(std::cerr);
+                        std::cerr << "\n";
+                    }
+                }
+
+                const NodeRef& min_node() const {
+                    auto it = std::min_element(m_segments.begin(), m_segments.end());
+                    if (location_less()(it->first(), it->second())) {
+                        return it->first();
+                    } else {
+                        return it->second();
+                    }
+                }
+
+                bool is_in(ProtoRing* outer) {
+                    osmium::Location testpoint = segments().front().first().location();
+                    bool is_in = false;
+
+                    for (size_t i = 0, j = outer->segments().size()-1; i < outer->segments().size(); j = i++) {
+                        if (((outer->segments()[i].first().location().y() > testpoint.y()) != (outer->segments()[j].first().location().y() > testpoint.y())) &&
+                            (testpoint.x() < (outer->segments()[j].first().location().x() - outer->segments()[i].first().location().x()) * (testpoint.y() - outer->segments()[i].first().location().y()) / (outer->segments()[j].first().location().y() - outer->segments()[i].first().location().y()) + outer->segments()[i].first().location().x()) ) {
+                            is_in = !is_in;
+                        }
+                    }
+
+                    return is_in;
+                }
+
+                void get_ways(std::set<const osmium::Way*>& ways) {
+                    for (const auto& segment : m_segments) {
+                        ways.insert(segment.way());
+                    }
+                }
+
+                bool contains(const NodeRefSegment& segment) const {
+                    for (const auto& s : m_segments) {
+                        if (s == segment || (s.first() == segment.second() && s.second() == segment.first())) {
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+
+            }; // class ProtoRing
+
+            template <typename TChar, typename TTraits>
+            inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const ProtoRing& ring) {
+                ring.print(out);
+                return out;
+            }
+
+        } // namespace detail
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_DETAIL_PROTO_RING_HPP
diff --git a/third_party/osmium/area/detail/segment_list.hpp b/third_party/osmium/area/detail/segment_list.hpp
new file mode 100644
index 0000000..a14f792
--- /dev/null
+++ b/third_party/osmium/area/detail/segment_list.hpp
@@ -0,0 +1,216 @@
+#ifndef OSMIUM_AREA_DETAIL_SEGMENT_LIST_HPP
+#define OSMIUM_AREA_DETAIL_SEGMENT_LIST_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <iostream>
+#include <vector>
+
+#include <osmium/area/problem_reporter.hpp>
+#include <osmium/area/detail/node_ref_segment.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/way.hpp>
+
+namespace osmium {
+
+    namespace area {
+
+        namespace detail {
+
+            /**
+             * This is a helper class for the area assembler. It models
+             * a list of segments.
+             */
+            class SegmentList {
+
+                typedef std::vector<NodeRefSegment> slist_type;
+
+                slist_type m_segments;
+
+                bool m_debug;
+
+            public:
+
+                explicit SegmentList(bool debug) noexcept :
+                    m_debug(debug) {
+                }
+
+                ~SegmentList() = default;
+
+                SegmentList(const SegmentList&) = delete;
+                SegmentList(SegmentList&&) = delete;
+
+                SegmentList& operator=(const SegmentList&) = delete;
+                SegmentList& operator=(SegmentList&&) = delete;
+
+                /// The number of segments in the list.
+                size_t size() const noexcept {
+                    return m_segments.size();
+                }
+
+                bool empty() const noexcept {
+                    return m_segments.empty();
+                }
+
+                typedef slist_type::const_iterator const_iterator;
+
+                const_iterator begin() const noexcept {
+                    return m_segments.begin();
+                }
+
+                const_iterator end() const noexcept {
+                    return m_segments.end();
+                }
+
+                /**
+                 * Enable or disable debug output to stderr. This is for Osmium
+                 * developers only.
+                 */
+                void enable_debug_output(bool debug=true) noexcept {
+                    m_debug = debug;
+                }
+
+                /// Clear the list of segments. All segments are removed.
+                void clear() {
+                    m_segments.clear();
+                }
+
+                /// Sort the list of segments.
+                void sort() {
+                    std::sort(m_segments.begin(), m_segments.end());
+                }
+
+                /**
+                 * Extract segments from given way and add them to the list.
+                 *
+                 * Segments connecting two nodes with the same location (ie same
+                 * node or different node with same location) are removed.
+                 *
+                 * XXX should two nodes with same location be reported?
+                 */
+                void extract_segments_from_way(const osmium::Way& way, const char* role) {
+                    osmium::NodeRef last_nr;
+                    for (const osmium::NodeRef& nr : way.nodes()) {
+                        if (last_nr.location() && last_nr.location() != nr.location()) {
+                            m_segments.emplace_back(last_nr, nr, role, &way);
+                        }
+                        last_nr = nr;
+                    }
+                }
+
+                /**
+                 * Extract all segments from all ways that make up this
+                 * multipolygon relation and add them to the list.
+                 */
+                void extract_segments_from_ways(const osmium::Relation& relation, const std::vector<size_t>& members, const osmium::memory::Buffer& in_buffer) {
+                    auto member_it = relation.members().begin();
+                    for (size_t offset : members) {
+                        const osmium::Way& way = in_buffer.get<const osmium::Way>(offset);
+                        extract_segments_from_way(way, member_it->role());
+                        ++member_it;
+                    }
+                }
+
+                /**
+                 * Find duplicate segments (ie same start and end point) in the
+                 * list and remove them. This will always remove pairs of the same
+                 * segment. So if there are three, for instance, two will be
+                 * removed and one will be left.
+                 */
+                void erase_duplicate_segments() {
+                    while (true) {
+                        auto it = std::adjacent_find(m_segments.begin(), m_segments.end());
+                        if (it == m_segments.end()) {
+                            return;
+                        }
+                        if (m_debug) {
+                            std::cerr << "  erase duplicate segment: " << *it << "\n";
+                        }
+                        m_segments.erase(it, it+2);
+                    }
+                }
+
+                /**
+                 * Find intersection between segments.
+                 *
+                 * @param problem_reporter Any intersections found are reported to this object.
+                 * @returns true if there are intersections.
+                 */
+                bool find_intersections(osmium::area::ProblemReporter* problem_reporter) const {
+                    if (m_segments.empty()) {
+                        return false;
+                    }
+
+                    bool found_intersections = false;
+
+                    for (auto it1 = m_segments.begin(); it1 != m_segments.end()-1; ++it1) {
+                        const NodeRefSegment& s1 = *it1;
+                        for (auto it2 = it1+1; it2 != m_segments.end(); ++it2) {
+                            const NodeRefSegment& s2 = *it2;
+
+                            assert(s1 != s2); // erase_duplicate_segments() should have made sure of that
+
+                            if (outside_x_range(s2, s1)) {
+                                break;
+                            }
+
+                            if (y_range_overlap(s1, s2)) {
+                                osmium::Location intersection = calculate_intersection(s1, s2);
+                                if (intersection) {
+                                    found_intersections = true;
+                                    if (m_debug) {
+                                        std::cerr << "  segments " << s1 << " and " << s2 << " intersecting at " << intersection << "\n";
+                                    }
+                                    if (problem_reporter) {
+                                        problem_reporter->report_intersection(s1.way()->id(), s1.first().location(), s1.second().location(), s2.way()->id(), s2.first().location(), s2.second().location(), intersection);
+                                    }
+                                }
+                            }
+                        }
+                    }
+
+                    return found_intersections;
+                }
+
+            }; // class SegmentList
+
+        } // namespace detail
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_DETAIL_SEGMENT_LIST_HPP
diff --git a/third_party/osmium/area/multipolygon_collector.hpp b/third_party/osmium/area/multipolygon_collector.hpp
new file mode 100644
index 0000000..af48176
--- /dev/null
+++ b/third_party/osmium/area/multipolygon_collector.hpp
@@ -0,0 +1,212 @@
+#ifndef OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
+#define OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <vector>
+
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/relations/collector.hpp>
+#include <osmium/relations/detail/member_meta.hpp>
+
+namespace osmium {
+
+    struct invalid_location;
+
+    namespace relations {
+        class RelationMeta;
+    }
+
+    /**
+     * @brief Code related to the building of areas (multipolygons) from relations.
+     */
+    namespace area {
+
+        /**
+         * This class collects all data needed for creating areas from
+         * relations tagged with type=multipolygon or type=boundary.
+         * Most of its functionality is derived from the parent class
+         * osmium::relations::Collector.
+         *
+         * The actual assembling of the areas is done by the assembler
+         * class given as template argument.
+         *
+         * @tparam TAssembler Multipolygon Assembler class.
+         */
+        template <class TAssembler>
+        class MultipolygonCollector : public osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> {
+
+            typedef typename osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> collector_type;
+
+            typedef typename TAssembler::config_type assembler_config_type;
+            const assembler_config_type m_assembler_config;
+
+            osmium::memory::Buffer m_output_buffer;
+
+            static constexpr size_t initial_output_buffer_size = 1024 * 1024;
+            static constexpr size_t max_buffer_size_for_flush = 100 * 1024;
+
+            void flush_output_buffer() {
+                if (this->callback()) {
+                    osmium::memory::Buffer buffer(initial_output_buffer_size);
+                    std::swap(buffer, m_output_buffer);
+                    this->callback()(std::move(buffer));
+                }
+            }
+
+            void possibly_flush_output_buffer() {
+                if (m_output_buffer.committed() > max_buffer_size_for_flush) {
+                    flush_output_buffer();
+                }
+            }
+
+        public:
+
+            explicit MultipolygonCollector(const assembler_config_type& assembler_config) :
+                collector_type(),
+                m_assembler_config(assembler_config),
+                m_output_buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes) {
+            }
+
+            /**
+             * We are interested in all relations tagged with type=multipolygon or
+             * type=boundary.
+             *
+             * Overwritten from the base class.
+             */
+            bool keep_relation(const osmium::Relation& relation) const {
+                const char* type = relation.tags().get_value_by_key("type");
+
+                // ignore relations without "type" tag
+                if (!type) {
+                    return false;
+                }
+
+                if ((!strcmp(type, "multipolygon")) || (!strcmp(type, "boundary"))) {
+                    return true;
+                }
+
+                return false;
+            }
+
+            /**
+             * Overwritten from the base class.
+             */
+            bool keep_member(const osmium::relations::RelationMeta& /*relation_meta*/, const osmium::RelationMember& member) const {
+                // We are only interested in members of type way.
+                return member.type() == osmium::item_type::way;
+            }
+
+            /**
+             * This is called when a way is not in any multipolygon
+             * relation.
+             *
+             * Overwritten from the base class.
+             */
+            void way_not_in_any_relation(const osmium::Way& way) {
+                if (way.ends_have_same_location() && way.nodes().size() > 3) {
+                    // way is closed and has enough nodes, build simple multipolygon
+                    try {
+                        TAssembler assembler(m_assembler_config);
+                        assembler(way, m_output_buffer);
+                        possibly_flush_output_buffer();
+                    } catch (osmium::invalid_location&) {
+                        // XXX ignore
+                    }
+                }
+            }
+
+            void complete_relation(osmium::relations::RelationMeta& relation_meta) {
+                const osmium::Relation& relation = this->get_relation(relation_meta);
+                std::vector<size_t> offsets;
+                for (const auto& member : relation.members()) {
+                    if (member.ref() != 0) {
+                        offsets.push_back(this->get_offset(member.type(), member.ref()));
+                    }
+                }
+                try {
+                    TAssembler assembler(m_assembler_config);
+                    assembler(relation, offsets, this->members_buffer(), m_output_buffer);
+                    possibly_flush_output_buffer();
+                } catch (osmium::invalid_location&) {
+                    // XXX ignore
+                }
+
+                // clear member metas
+                for (const auto& member : relation.members()) {
+                    if (member.ref() != 0) {
+                        auto& mmv = this->member_meta(member.type());
+                        auto range = std::equal_range(mmv.begin(), mmv.end(), osmium::relations::MemberMeta(member.ref()));
+                        assert(range.first != range.second);
+
+                        // if this is the last time this object was needed
+                        // then mark it as removed
+                        if (osmium::relations::count_not_removed(range.first, range.second) == 1) {
+                            this->get_member(range.first->buffer_offset()).set_removed(true);
+                        }
+
+                        for (auto it = range.first; it != range.second; ++it) {
+                            if (!it->removed() && relation.id() == this->get_relation(it->relation_pos()).id()) {
+                                it->remove();
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+
+            void flush() {
+                flush_output_buffer();
+            }
+
+            osmium::memory::Buffer read() {
+                osmium::memory::Buffer buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes);
+                std::swap(buffer, m_output_buffer);
+                return buffer;
+            }
+
+        }; // class MultipolygonCollector
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
diff --git a/third_party/osmium/area/problem_reporter.hpp b/third_party/osmium/area/problem_reporter.hpp
new file mode 100644
index 0000000..5e255db
--- /dev/null
+++ b/third_party/osmium/area/problem_reporter.hpp
@@ -0,0 +1,149 @@
+#ifndef OSMIUM_AREA_PROBLEM_REPORTER_HPP
+#define OSMIUM_AREA_PROBLEM_REPORTER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    namespace area {
+
+        /**
+         * When assembling a multipolygon/area from a multipolygon relation
+         * or a closed way several problems can be detected. This includes
+         * intersections between lines, wrong role attributes on relation
+         * members etc. These problems are reported by the area::Assembler
+         * class to the ProblemReporter class or one of its child classes.
+         *
+         * This is the parent class which does nothing with the reports.
+         * Child classes are expected to implement different ways of
+         * reporting the problems.
+         */
+        class ProblemReporter {
+
+        protected:
+
+            // Type of object we are currently working on
+            osmium::item_type m_object_type;
+
+            // ID of the relation/way we are currently working on
+            osmium::object_id_type m_object_id;
+
+        public:
+
+            ProblemReporter() = default;
+
+            virtual ~ProblemReporter() = default;
+
+            /**
+             * Set the object the next problem reports will be on.
+             *
+             * @param object_type The type of the object.
+             * @param object_id The ID of the object.
+             */
+            void set_object(osmium::item_type object_type, osmium::object_id_type object_id) noexcept {
+                m_object_type = object_type;
+                m_object_id = object_id;
+            }
+
+// Disable "unused-parameter" warning, so that the compiler will not complain.
+// We can't remove the parameter names, because then doxygen will complain.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
+            /**
+             * Report a duplicate node, ie. two nodes with the same location.
+             *
+             * @param node_id1       ID of the first node.
+             * @param node_id2       ID of the second node.
+             * @param location       Location of both nodes.
+             */
+            virtual void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) {
+            }
+
+            /**
+             * Report an intersection between two segments.
+             *
+             * @param way1_id        ID of the first involved way.
+             * @param way1_seg_start Location where the segment of the first way with the intersection starts
+             * @param way1_seg_end   Location where the segment of the first way with the intersection ends
+             * @param way2_id        ID of the second involved way.
+             * @param way2_seg_start Location where the segment of the second way with the intersection starts
+             * @param way2_seg_end   Location where the segment of the second way with the intersection ends
+             * @param intersection   Location of the intersection. This might be slightly off the correct location due to rounding.
+             */
+            virtual void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
+                                             osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) {
+            }
+
+            /**
+             * Report an open ring.
+             *
+             * @param end1           Location of the first open end.
+             * @param end2           Location of the second open end.
+             */
+            virtual void report_ring_not_closed(osmium::Location end1, osmium::Location end2) {
+            }
+
+            /**
+             * Report a segment that should have role "outer", but has a different role.
+             *
+             * @param way_id         ID of the way this segment is in.
+             * @param seg_start      Start of the segment with the wrong role.
+             * @param seg_end        End of the segment with the wrong role.
+             */
+            virtual void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) {
+            }
+
+            /**
+             * Report a segment that should have role "inner", but has a different role.
+             *
+             * @param way_id         ID of the way this segment is in.
+             * @param seg_start      Start of the segment with the wrong role.
+             * @param seg_end        End of the segment with the wrong role.
+             */
+            virtual void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) {
+            }
+
+#pragma GCC diagnostic pop
+
+        }; // class ProblemReporter
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_PROBLEM_REPORTER_HPP
diff --git a/third_party/osmium/area/problem_reporter_exception.hpp b/third_party/osmium/area/problem_reporter_exception.hpp
new file mode 100644
index 0000000..29c7ad4
--- /dev/null
+++ b/third_party/osmium/area/problem_reporter_exception.hpp
@@ -0,0 +1,96 @@
+#ifndef OSMIUM_AREA_PROBLEM_REPORTER_EXCEPTION_HPP
+#define OSMIUM_AREA_PROBLEM_REPORTER_EXCEPTION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <sstream>
+#include <stdexcept>
+
+#include <osmium/area/problem_reporter_stream.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    namespace area {
+
+        class ProblemReporterException : public ProblemReporterStream {
+
+            std::stringstream m_sstream;
+
+        public:
+
+            ProblemReporterException() :
+                ProblemReporterStream(m_sstream) {
+            }
+
+            virtual ~ProblemReporterException() = default;
+
+            void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
+                m_sstream.str();
+                ProblemReporterStream::report_duplicate_node(node_id1, node_id2, location);
+                throw std::runtime_error(m_sstream.str());
+            }
+
+            void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
+                                     osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
+                m_sstream.str();
+                ProblemReporterStream::report_intersection(way1_id, way1_seg_start, way1_seg_end, way2_id, way2_seg_start, way2_seg_end, intersection);
+                throw std::runtime_error(m_sstream.str());
+            }
+
+            void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
+                m_sstream.str();
+                ProblemReporterStream::report_ring_not_closed(end1, end2);
+                throw std::runtime_error(m_sstream.str());
+            }
+
+            void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+                m_sstream.str();
+                ProblemReporterStream::report_role_should_be_outer(way_id, seg_start, seg_end);
+                throw std::runtime_error(m_sstream.str());
+            }
+
+            void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+                m_sstream.str();
+                ProblemReporterStream::report_role_should_be_inner(way_id, seg_start, seg_end);
+                throw std::runtime_error(m_sstream.str());
+            }
+
+        }; // class ProblemReporterException
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_PROBLEM_REPORTER_EXCEPTION_HPP
diff --git a/third_party/osmium/area/problem_reporter_ogr.hpp b/third_party/osmium/area/problem_reporter_ogr.hpp
new file mode 100644
index 0000000..a9eb135
--- /dev/null
+++ b/third_party/osmium/area/problem_reporter_ogr.hpp
@@ -0,0 +1,206 @@
+#ifndef OSMIUM_AREA_PROBLEM_REPORTER_OGR_HPP
+#define OSMIUM_AREA_PROBLEM_REPORTER_OGR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#define OSMIUM_COMPILE_WITH_CFLAGS_OGR `gdal-config --cflags`
+#define OSMIUM_LINK_WITH_LIBS_OGR `gdal-config --libs`
+
+#pragma GCC diagnostic push
+#ifdef __clang__
+# pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
+#endif
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#pragma GCC diagnostic ignored "-Wpadded"
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#pragma GCC diagnostic ignored "-Wshadow"
+# include <ogr_api.h>
+# include <ogrsf_frmts.h>
+#pragma GCC diagnostic pop
+
+#include <memory>
+#include <stdexcept>
+
+#include <osmium/area/problem_reporter.hpp>
+#include <osmium/geom/ogr.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    namespace area {
+
+        /**
+         * Report problems when assembling areas by adding them to
+         * layers in an OGR datasource.
+         */
+        class ProblemReporterOGR : public ProblemReporter {
+
+            osmium::geom::OGRFactory<> m_ogr_factory;
+
+            OGRDataSource* m_data_source;
+
+            OGRLayer* m_layer_perror;
+            OGRLayer* m_layer_lerror;
+
+            void write_point(const char* problem_type, osmium::object_id_type id1, osmium::object_id_type id2, osmium::Location location) {
+                OGRFeature* feature = OGRFeature::CreateFeature(m_layer_perror->GetLayerDefn());
+                std::unique_ptr<OGRPoint> ogr_point = m_ogr_factory.create_point(location);
+                feature->SetGeometry(ogr_point.get());
+                feature->SetField("id1", static_cast<double>(id1));
+                feature->SetField("id2", static_cast<double>(id2));
+                feature->SetField("problem_type", problem_type);
+
+                if (m_layer_perror->CreateFeature(feature) != OGRERR_NONE) {
+                    std::runtime_error("Failed to create feature on layer 'perrors'");
+                }
+
+                OGRFeature::DestroyFeature(feature);
+            }
+
+            void write_line(const char* problem_type, osmium::object_id_type id1, osmium::object_id_type id2, osmium::Location loc1, osmium::Location loc2) {
+                std::unique_ptr<OGRPoint> ogr_point1 = m_ogr_factory.create_point(loc1);
+                std::unique_ptr<OGRPoint> ogr_point2 = m_ogr_factory.create_point(loc2);
+                std::unique_ptr<OGRLineString> ogr_linestring = std::unique_ptr<OGRLineString>(new OGRLineString());
+                ogr_linestring->addPoint(ogr_point1.get());
+                ogr_linestring->addPoint(ogr_point2.get());
+                OGRFeature* feature = OGRFeature::CreateFeature(m_layer_lerror->GetLayerDefn());
+                feature->SetGeometry(ogr_linestring.get());
+                feature->SetField("id1", static_cast<double>(id1));
+                feature->SetField("id2", static_cast<double>(id2));
+                feature->SetField("problem_type", problem_type);
+
+                if (m_layer_lerror->CreateFeature(feature) != OGRERR_NONE) {
+                    std::runtime_error("Failed to create feature on layer 'lerrors'");
+                }
+
+                OGRFeature::DestroyFeature(feature);
+            }
+
+        public:
+
+            explicit ProblemReporterOGR(OGRDataSource* data_source) :
+                m_data_source(data_source) {
+
+                OGRSpatialReference sparef;
+                sparef.SetWellKnownGeogCS("WGS84");
+
+                m_layer_perror = m_data_source->CreateLayer("perrors", &sparef, wkbPoint, nullptr);
+                if (!m_layer_perror) {
+                    std::runtime_error("Layer creation failed for layer 'perrors'");
+                }
+
+                OGRFieldDefn layer_perror_field_id1("id1", OFTReal);
+                layer_perror_field_id1.SetWidth(10);
+
+                if (m_layer_perror->CreateField(&layer_perror_field_id1) != OGRERR_NONE) {
+                    std::runtime_error("Creating field 'id1' failed for layer 'perrors'");
+                }
+
+                OGRFieldDefn layer_perror_field_id2("id2", OFTReal);
+                layer_perror_field_id2.SetWidth(10);
+
+                if (m_layer_perror->CreateField(&layer_perror_field_id2) != OGRERR_NONE) {
+                    std::runtime_error("Creating field 'id2' failed for layer 'perrors'");
+                }
+
+                OGRFieldDefn layer_perror_field_problem_type("problem_type", OFTString);
+                layer_perror_field_problem_type.SetWidth(30);
+
+                if (m_layer_perror->CreateField(&layer_perror_field_problem_type) != OGRERR_NONE) {
+                    std::runtime_error("Creating field 'problem_type' failed for layer 'perrors'");
+                }
+
+                /**************/
+
+                m_layer_lerror = m_data_source->CreateLayer("lerrors", &sparef, wkbLineString, nullptr);
+                if (!m_layer_lerror) {
+                    std::runtime_error("Layer creation failed for layer 'lerrors'");
+                }
+
+                OGRFieldDefn layer_lerror_field_id1("id1", OFTReal);
+                layer_lerror_field_id1.SetWidth(10);
+
+                if (m_layer_lerror->CreateField(&layer_lerror_field_id1) != OGRERR_NONE) {
+                    std::runtime_error("Creating field 'id1' failed for layer 'lerrors'");
+                }
+
+                OGRFieldDefn layer_lerror_field_id2("id2", OFTReal);
+                layer_lerror_field_id2.SetWidth(10);
+
+                if (m_layer_lerror->CreateField(&layer_lerror_field_id2) != OGRERR_NONE) {
+                    std::runtime_error("Creating field 'id2' failed for layer 'lerrors'");
+                }
+
+                OGRFieldDefn layer_lerror_field_problem_type("problem_type", OFTString);
+                layer_lerror_field_problem_type.SetWidth(30);
+
+                if (m_layer_lerror->CreateField(&layer_lerror_field_problem_type) != OGRERR_NONE) {
+                    std::runtime_error("Creating field 'problem_type' failed for layer 'lerrors'");
+                }
+            }
+
+            virtual ~ProblemReporterOGR() = default;
+
+            void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
+                write_point("duplicate_node", node_id1, node_id2, location);
+            }
+
+            void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
+                                     osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
+                write_point("intersection", m_object_id, 0, intersection);
+                write_line("intersection", m_object_id, way1_id, way1_seg_start, way1_seg_end);
+                write_line("intersection", m_object_id, way2_id, way2_seg_start, way2_seg_end);
+            }
+
+            void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
+                write_point("ring_not_closed", m_object_id, 0, end1);
+                write_point("ring_not_closed", m_object_id, 0, end2);
+            }
+
+            void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+                write_line("role_should_be_outer", m_object_id, way_id, seg_start, seg_end);
+            }
+
+            void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+                write_line("role_should_be_inner", m_object_id, way_id, seg_start, seg_end);
+            }
+
+        }; // class ProblemReporterOGR
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_PROBLEM_REPORTER_OGR_HPP
diff --git a/third_party/osmium/area/problem_reporter_stream.hpp b/third_party/osmium/area/problem_reporter_stream.hpp
new file mode 100644
index 0000000..6bee568
--- /dev/null
+++ b/third_party/osmium/area/problem_reporter_stream.hpp
@@ -0,0 +1,96 @@
+#ifndef OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP
+#define OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <ostream>
+
+#include <osmium/area/problem_reporter.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    namespace area {
+
+        class ProblemReporterStream : public ProblemReporter {
+
+            std::ostream* m_out;
+
+        public:
+
+            explicit ProblemReporterStream(std::ostream& out) :
+                m_out(&out) {
+            }
+
+            virtual ~ProblemReporterStream() = default;
+
+            void header(const char* msg) {
+                *m_out << "DATA PROBLEM: " << msg << " on " << item_type_to_char(m_object_type) << m_object_id << ": ";
+            }
+
+            void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
+                header("duplicate node");
+                *m_out << "node_id1=" << node_id1 << " node_id2=" << node_id2 << " location=" << location << "\n";
+            }
+
+            void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
+                                     osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
+                header("intersection");
+                *m_out << "way1_id=" << way1_id << " way1_seg_start=" << way1_seg_start << " way1_seg_end=" << way1_seg_end
+                       << " way2_id=" << way2_id << " way2_seg_start=" << way2_seg_start << " way2_seg_end=" << way2_seg_end << " intersection=" << intersection << "\n";
+            }
+
+            void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
+                header("ring not closed");
+                *m_out << "end1=" << end1 << " end2=" << end2 << "\n";
+            }
+
+            void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+                header("role should be outer");
+                *m_out << "way_id=" << way_id << " seg_start=" << seg_start << " seg_end=" << seg_end << "\n";
+            }
+
+            void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+                header("role should be inner");
+                *m_out << "way_id=" << way_id << " seg_start=" << seg_start << " seg_end=" << seg_end << "\n";
+            }
+
+        }; // class ProblemReporterStream
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP
diff --git a/third_party/osmium/builder/builder.hpp b/third_party/osmium/builder/builder.hpp
new file mode 100644
index 0000000..61e853e
--- /dev/null
+++ b/third_party/osmium/builder/builder.hpp
@@ -0,0 +1,220 @@
+#ifndef OSMIUM_BUILDER_BUILDER_HPP
+#define OSMIUM_BUILDER_BUILDER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <new>
+#include <type_traits>
+
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+    /**
+     * @brief Classes for building OSM objects and other items in buffers
+     */
+    namespace builder {
+
+        class Builder {
+
+            osmium::memory::Buffer& m_buffer;
+            Builder* m_parent;
+            size_t m_item_offset;
+
+            Builder(const Builder&) = delete;
+            Builder(Builder&&) = delete;
+
+            Builder& operator=(const Builder&) = delete;
+            Builder& operator=(Builder&&) = delete;
+
+        protected:
+
+            explicit Builder(osmium::memory::Buffer& buffer, Builder* parent, osmium::memory::item_size_type size) :
+                m_buffer(buffer),
+                m_parent(parent),
+                m_item_offset(buffer.written()) {
+                m_buffer.reserve_space(size);
+                assert(buffer.is_aligned());
+                if (m_parent) {
+                    m_parent->add_size(size);
+                }
+            }
+
+            ~Builder() = default;
+
+            osmium::memory::Item& item() const {
+                return *reinterpret_cast<osmium::memory::Item*>(m_buffer.data() + m_item_offset);
+            }
+
+        public:
+
+            /**
+             * Add padding to buffer (if needed) to align data properly.
+             *
+             * This calculates how many padding bytes are needed and adds
+             * as many zero bytes to the buffer. It also adds this number
+             * to the size of the current item (if the "self" param is
+             * true) and recursively to all the parent items.
+             *
+             * @param self If true add number of padding bytes to size
+             *             of current item. Size is always added to
+             *             parent item (if any).
+             *
+             */
+            void add_padding(bool self=false) {
+                auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
+                if (padding != osmium::memory::align_bytes) {
+                    std::memset(m_buffer.reserve_space(padding), 0, padding);
+                    if (self) {
+                        add_size(padding);
+                    } else if (m_parent) {
+                        m_parent->add_size(padding);
+                        assert(m_parent->size() % osmium::memory::align_bytes == 0);
+                    }
+                }
+            }
+
+            void add_size(uint32_t size) {
+                item().add_size(size);
+                if (m_parent) {
+                    m_parent->add_size(size);
+                }
+            }
+
+            uint32_t size() const noexcept {
+                return item().byte_size();
+            }
+
+            void add_item(const osmium::memory::Item* item) {
+                std::memcpy(m_buffer.reserve_space(item->padded_size()), item, item->padded_size());
+                add_size(item->padded_size());
+            }
+
+            /**
+             * Reserve space for an object of class T in buffer and return
+             * pointer to it.
+             */
+            template <class T>
+            T* reserve_space_for() {
+                assert(m_buffer.is_aligned());
+                return reinterpret_cast<T*>(m_buffer.reserve_space(sizeof(T)));
+            }
+
+            /**
+             * Append data to buffer.
+             *
+             * @param data Pointer to data.
+             * @param length Length of data in bytes. If data is a
+             *               \0-terminated string, length must contain the
+             *               \0 byte.
+             */
+            osmium::memory::item_size_type append(const char* data, const osmium::memory::item_size_type length) {
+                std::memcpy(m_buffer.reserve_space(length), data, length);
+                return length;
+            }
+
+            /**
+             * Append \0-terminated string to buffer.
+             */
+            osmium::memory::item_size_type append(const char* str) {
+                return append(str, static_cast<osmium::memory::item_size_type>(std::strlen(str) + 1));
+            }
+
+            /// Return the buffer this builder is using.
+            osmium::memory::Buffer& buffer() noexcept {
+                return m_buffer;
+            }
+
+        }; // class Builder
+
+        template <class TItem>
+        class ObjectBuilder : public Builder {
+
+            static_assert(std::is_base_of<osmium::memory::Item, TItem>::value,
+                "ObjectBuilder can only build objects derived from osmium::memory::Item");
+
+        public:
+
+            explicit ObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+                Builder(buffer, parent, sizeof(TItem)) {
+                new (&item()) TItem();
+            }
+
+            TItem& object() noexcept {
+                return static_cast<TItem&>(item());
+            }
+
+            /**
+             * Add user name to buffer.
+             *
+             * @param user Pointer to user name.
+             * @param length Length of user name including \0 byte.
+             */
+            void add_user(const char* user, const string_size_type length) {
+                object().set_user_size(length);
+                add_size(append(user, length));
+                add_padding(true);
+            }
+
+            /**
+             * Add user name to buffer.
+             *
+             * @param user Pointer to \0-terminated user name.
+             */
+            void add_user(const char* user) {
+                add_user(user, static_cast_with_assert<string_size_type>(std::strlen(user) + 1));
+            }
+
+            /**
+             * Add user name to buffer.
+             *
+             * @param user User name.
+             */
+            void add_user(const std::string& user) {
+                add_user(user.data(), static_cast_with_assert<string_size_type>(user.size() + 1));
+            }
+
+        }; // class ObjectBuilder
+
+    } // namespace builder
+
+} // namespace osmium
+
+#endif // OSMIUM_BUILDER_BUILDER_HPP
diff --git a/third_party/osmium/builder/builder_helper.hpp b/third_party/osmium/builder/builder_helper.hpp
new file mode 100644
index 0000000..3e00f81
--- /dev/null
+++ b/third_party/osmium/builder/builder_helper.hpp
@@ -0,0 +1,103 @@
+#ifndef OSMIUM_BUILDER_BUILDER_HELPER_HPP
+#define OSMIUM_BUILDER_BUILDER_HELPER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <initializer_list>
+#include <functional>
+#include <map>
+#include <utility>
+
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/memory/buffer.hpp>
+
+namespace osmium {
+
+    class NodeRef;
+    class TagList;
+    class WayNodeList;
+
+    namespace builder {
+
+        inline const osmium::WayNodeList& build_way_node_list(osmium::memory::Buffer& buffer, const std::initializer_list<osmium::NodeRef>& nodes) {
+            size_t pos = buffer.committed();
+            {
+                osmium::builder::WayNodeListBuilder wnl_builder(buffer);
+                for (const auto& node_ref : nodes) {
+                    wnl_builder.add_node_ref(node_ref);
+                }
+            }
+            buffer.commit();
+            return buffer.get<const osmium::WayNodeList>(pos);
+        }
+
+        inline const osmium::TagList& build_tag_list(osmium::memory::Buffer& buffer, const std::initializer_list<std::pair<const char*, const char*>>& tags) {
+            size_t pos = buffer.committed();
+            {
+                osmium::builder::TagListBuilder tl_builder(buffer);
+                for (const auto& p : tags) {
+                    tl_builder.add_tag(p.first, p.second);
+                }
+            }
+            buffer.commit();
+            return buffer.get<const osmium::TagList>(pos);
+        }
+
+        inline const osmium::TagList& build_tag_list_from_map(osmium::memory::Buffer& buffer, const std::map<const char*, const char*>& tags) {
+            size_t pos = buffer.committed();
+            {
+                osmium::builder::TagListBuilder tl_builder(buffer);
+                for (const auto& p : tags) {
+                    tl_builder.add_tag(p.first, p.second);
+                }
+            }
+            buffer.commit();
+            return buffer.get<const osmium::TagList>(pos);
+        }
+
+        inline const osmium::TagList& build_tag_list_from_func(osmium::memory::Buffer& buffer, std::function<void(osmium::builder::TagListBuilder&)> func) {
+            size_t pos = buffer.committed();
+            {
+                osmium::builder::TagListBuilder tl_builder(buffer);
+                func(tl_builder);
+            }
+            buffer.commit();
+            return buffer.get<const osmium::TagList>(pos);
+        }
+
+    } // namespace builder
+
+} // namespace osmium
+
+#endif // OSMIUM_BUILDER_BUILDER_HELPER_HPP
diff --git a/third_party/osmium/builder/osm_object_builder.hpp b/third_party/osmium/builder/osm_object_builder.hpp
new file mode 100644
index 0000000..851eb85
--- /dev/null
+++ b/third_party/osmium/builder/osm_object_builder.hpp
@@ -0,0 +1,283 @@
+#ifndef OSMIUM_BUILDER_OSM_OBJECT_BUILDER_HPP
+#define OSMIUM_BUILDER_OSM_OBJECT_BUILDER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstring>
+#include <initializer_list>
+#include <new>
+#include <utility>
+
+#include <osmium/builder/builder.hpp>
+#include <osmium/osm.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+    namespace memory {
+        class Buffer;
+    }
+
+    namespace builder {
+
+        class TagListBuilder : public ObjectBuilder<TagList> {
+
+        public:
+
+            explicit TagListBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+                ObjectBuilder<TagList>(buffer, parent) {
+            }
+
+            ~TagListBuilder() {
+                add_padding();
+            }
+
+            /**
+             * Add tag to buffer.
+             *
+             * @param key Tag key.
+             * @param value Tag value.
+             */
+            void add_tag(const char* key, const char* value) {
+                add_size(append(key) + append(value));
+            }
+
+            /**
+             * Add tag to buffer.
+             *
+             * @param key Tag key.
+             * @param value Tag value.
+             */
+            void add_tag(const std::string& key, const std::string& value) {
+                add_size(append(key.data(),   static_cast_with_assert<string_size_type>(key.size()   + 1)) +
+                         append(value.data(), static_cast_with_assert<string_size_type>(value.size() + 1)));
+            }
+
+        }; // class TagListBuilder
+
+        template <class T>
+        class NodeRefListBuilder : public ObjectBuilder<T> {
+
+        public:
+
+            explicit NodeRefListBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+                ObjectBuilder<T>(buffer, parent) {
+            }
+
+            ~NodeRefListBuilder() {
+                static_cast<Builder*>(this)->add_padding();
+            }
+
+            void add_node_ref(const NodeRef& node_ref) {
+                new (static_cast<Builder*>(this)->reserve_space_for<osmium::NodeRef>()) osmium::NodeRef(node_ref);
+                static_cast<Builder*>(this)->add_size(sizeof(osmium::NodeRef));
+            }
+
+            void add_node_ref(const object_id_type ref, const osmium::Location location=Location()) {
+                add_node_ref(NodeRef(ref, location));
+            }
+
+        }; // class NodeRefListBuilder
+
+        typedef NodeRefListBuilder<WayNodeList> WayNodeListBuilder;
+        typedef NodeRefListBuilder<OuterRing> OuterRingBuilder;
+        typedef NodeRefListBuilder<InnerRing> InnerRingBuilder;
+
+        class RelationMemberListBuilder : public ObjectBuilder<RelationMemberList> {
+
+            /**
+             * Add role to buffer.
+             *
+             * @param member Relation member object where the length of the role
+             *               will be set.
+             * @param role The role.
+             * @param length Length of role string including \0 termination.
+             */
+            void add_role(osmium::RelationMember& member, const char* role, const string_size_type length) {
+                member.set_role_size(length);
+                add_size(append(role, length));
+                add_padding(true);
+            }
+
+            /**
+             * Add role to buffer.
+             *
+             * @param member Relation member object where the length of the role
+             *               will be set.
+             * @param role \0-terminated role.
+             */
+            void add_role(osmium::RelationMember& member, const char* role) {
+                add_role(member, role, static_cast_with_assert<string_size_type>(std::strlen(role) + 1));
+            }
+
+            /**
+             * Add role to buffer.
+             *
+             * @param member Relation member object where the length of the role
+             *               will be set.
+             * @param role Role.
+             */
+            void add_role(osmium::RelationMember& member, const std::string& role) {
+                add_role(member, role.data(), static_cast_with_assert<string_size_type>(role.size() + 1));
+            }
+
+        public:
+
+            explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+                ObjectBuilder<RelationMemberList>(buffer, parent) {
+            }
+
+            ~RelationMemberListBuilder() {
+                add_padding();
+            }
+
+            /**
+             * Add a member to the relation.
+             *
+             * @param type The type (node, way, or relation).
+             * @param ref The ID of the member.
+             * @param role The role of the member.
+             * @param full_member Optional pointer to the member object. If it
+             *                    is available a copy will be added to the
+             *                    relation.
+             */
+            void add_member(osmium::item_type type, object_id_type ref, const char* role, const osmium::OSMObject* full_member = nullptr) {
+                osmium::RelationMember* member = reserve_space_for<osmium::RelationMember>();
+                new (member) osmium::RelationMember(ref, type, full_member != nullptr);
+                add_size(sizeof(RelationMember));
+                add_role(*member, role);
+                if (full_member) {
+                    add_item(full_member);
+                }
+            }
+
+            /**
+             * Add a member to the relation.
+             *
+             * @param type The type (node, way, or relation).
+             * @param ref The ID of the member.
+             * @param role The role of the member.
+             * @param full_member Optional pointer to the member object. If it
+             *                    is available a copy will be added to the
+             *                    relation.
+             */
+            void add_member(osmium::item_type type, object_id_type ref, const std::string& role, const osmium::OSMObject* full_member = nullptr) {
+                osmium::RelationMember* member = reserve_space_for<osmium::RelationMember>();
+                new (member) osmium::RelationMember(ref, type, full_member != nullptr);
+                add_size(sizeof(RelationMember));
+                add_role(*member, role);
+                if (full_member) {
+                    add_item(full_member);
+                }
+            }
+
+        }; // class RelationMemberListBuilder
+
+        template <class T>
+        class OSMObjectBuilder : public ObjectBuilder<T> {
+
+        public:
+
+            explicit OSMObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+                ObjectBuilder<T>(buffer, parent) {
+                static_cast<Builder*>(this)->reserve_space_for<string_size_type>();
+                static_cast<Builder*>(this)->add_size(sizeof(string_size_type));
+            }
+
+            void add_tags(const std::initializer_list<std::pair<const char*, const char*>>& tags) {
+                osmium::builder::TagListBuilder tl_builder(static_cast<Builder*>(this)->buffer(), this);
+                for (const auto& p : tags) {
+                    tl_builder.add_tag(p.first, p.second);
+                }
+            }
+
+        }; // class OSMObjectBuilder
+
+        typedef OSMObjectBuilder<osmium::Node> NodeBuilder;
+        typedef OSMObjectBuilder<osmium::Relation> RelationBuilder;
+
+        class WayBuilder : public OSMObjectBuilder<osmium::Way> {
+
+        public:
+
+            explicit WayBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+                OSMObjectBuilder<osmium::Way>(buffer, parent) {
+            }
+
+            void add_node_refs(const std::initializer_list<osmium::NodeRef>& nodes) {
+                osmium::builder::WayNodeListBuilder builder(buffer(), this);
+                for (const auto& node_ref : nodes) {
+                    builder.add_node_ref(node_ref);
+                }
+            }
+
+        }; // class WayBuilder
+
+        class AreaBuilder : public OSMObjectBuilder<osmium::Area> {
+
+        public:
+
+            explicit AreaBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+                OSMObjectBuilder<osmium::Area>(buffer, parent) {
+            }
+
+            /**
+             * Initialize area attributes from the attributes of the given object.
+             */
+            void initialize_from_object(const osmium::OSMObject& source) {
+                osmium::Area& area = object();
+                area.set_id(osmium::object_id_to_area_id(source.id(), source.type()));
+                area.set_version(source.version());
+                area.set_changeset(source.changeset());
+                area.set_timestamp(source.timestamp());
+                area.set_visible(source.visible());
+                area.set_uid(source.uid());
+
+                add_user(source.user());
+            }
+
+        }; // class AreaBuilder
+
+        typedef ObjectBuilder<osmium::Changeset> ChangesetBuilder;
+
+    } // namespace builder
+
+} // namespace osmium
+
+#endif // OSMIUM_BUILDER_OSM_OBJECT_BUILDER_HPP
diff --git a/third_party/osmium/config/constexpr.hpp b/third_party/osmium/config/constexpr.hpp
new file mode 100644
index 0000000..3eddc84
--- /dev/null
+++ b/third_party/osmium/config/constexpr.hpp
@@ -0,0 +1,43 @@
+#ifndef OSMIUM_CONFIG_CONSTEXPR_HPP
+#define OSMIUM_CONFIG_CONSTEXPR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+// Workaround for MSVC which doesn't support constexpr in all cases yet
+#ifdef _MSC_VER
+# define OSMIUM_CONSTEXPR
+#else
+# define OSMIUM_CONSTEXPR constexpr
+#endif
+
+#endif // OSMIUM_CONFIG_CONSTEXPR_HPP
diff --git a/third_party/osmium/diff_handler.hpp b/third_party/osmium/diff_handler.hpp
new file mode 100644
index 0000000..9864df5
--- /dev/null
+++ b/third_party/osmium/diff_handler.hpp
@@ -0,0 +1,67 @@
+#ifndef OSMIUM_DIFF_HANDLER_HPP
+#define OSMIUM_DIFF_HANDLER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/osm/diff_object.hpp>
+
+namespace osmium {
+
+    /**
+     * @brief Osmium diff handlers provide access to differences between OSM object versions
+     */
+    namespace diff_handler {
+
+        class DiffHandler {
+
+        public:
+
+            DiffHandler() {
+            }
+
+            void node(const osmium::DiffNode&) const {
+            }
+
+            void way(const osmium::DiffWay&) const {
+            }
+
+            void relation(const osmium::DiffRelation&) const {
+            }
+
+        }; // class DiffHandler
+
+    } // namespace diff_handler
+
+} // namespace osmium
+
+#endif // OSMIUM_DIFF_HANDLER_HPP
diff --git a/third_party/osmium/diff_iterator.hpp b/third_party/osmium/diff_iterator.hpp
new file mode 100644
index 0000000..576834c
--- /dev/null
+++ b/third_party/osmium/diff_iterator.hpp
@@ -0,0 +1,129 @@
+#ifndef OSMIUM_DIFF_ITERATOR_HPP
+#define OSMIUM_DIFF_ITERATOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <iterator>
+#include <type_traits>
+
+#include <osmium/osm/diff_object.hpp>
+
+namespace osmium {
+
+    class OSMObject;
+
+    template <class TBasicIterator>
+    class DiffIterator : public std::iterator<std::input_iterator_tag, const osmium::DiffObject> {
+
+        static_assert(std::is_base_of<osmium::OSMObject, typename TBasicIterator::value_type>::value, "TBasicIterator::value_type must derive from osmium::OSMObject");
+
+        TBasicIterator m_prev;
+        TBasicIterator m_curr;
+        TBasicIterator m_next;
+
+        const TBasicIterator m_end;
+
+        mutable osmium::DiffObject m_diff;
+
+        void set_diff() const {
+            assert(m_curr != m_end);
+
+            TBasicIterator prev = m_prev;
+            if (prev->type() != m_curr->type() || prev->id() != m_curr->id()) {
+                prev = m_curr;
+            }
+
+            TBasicIterator next = m_next;
+            if (next == m_end || next->type() != m_curr->type() || next->id() != m_curr->id()) {
+                next = m_curr;
+            }
+
+            m_diff = osmium::DiffObject(*prev, *m_curr, *next);
+        }
+
+    public:
+
+        explicit DiffIterator(TBasicIterator begin, TBasicIterator end) :
+            m_prev(begin),
+            m_curr(begin),
+            m_next(begin == end ? begin : ++begin),
+            m_end(end) {
+        }
+
+        DiffIterator(const DiffIterator&) = default;
+        DiffIterator& operator=(const DiffIterator&) = default;
+
+        DiffIterator(DiffIterator&&) = default;
+        DiffIterator& operator=(DiffIterator&&) = default;
+
+        DiffIterator& operator++() {
+            m_prev = std::move(m_curr);
+            m_curr = m_next;
+
+            if (m_next != m_end) {
+                ++m_next;
+            }
+
+            return *this;
+        }
+
+        DiffIterator operator++(int) {
+            DiffIterator tmp(*this);
+            operator++();
+            return tmp;
+        }
+
+        bool operator==(const DiffIterator& rhs) const {
+            return m_curr == rhs.m_curr && m_end == rhs.m_end;
+        }
+
+        bool operator!=(const DiffIterator& rhs) const {
+            return !(*this == rhs);
+        }
+
+        reference operator*() const {
+            set_diff();
+            return m_diff;
+        }
+
+        pointer operator->() const {
+            set_diff();
+            return &m_diff;
+        }
+
+    }; // class DiffIterator
+
+} // namespace osmium
+
+#endif // OSMIUM_DIFF_ITERATOR_HPP
diff --git a/third_party/osmium/diff_visitor.hpp b/third_party/osmium/diff_visitor.hpp
new file mode 100644
index 0000000..b8db697
--- /dev/null
+++ b/third_party/osmium/diff_visitor.hpp
@@ -0,0 +1,104 @@
+#ifndef OSMIUM_DIFF_VISITOR_HPP
+#define OSMIUM_DIFF_VISITOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/diff_iterator.hpp>
+#include <osmium/io/input_iterator.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/diff_object.hpp>
+#include <osmium/osm/item_type.hpp>
+
+namespace osmium {
+
+    namespace detail {
+
+        template <class THandler>
+        inline void apply_diff_iterator_recurse(const osmium::DiffObject& diff, THandler& handler) {
+            switch (diff.type()) {
+                case osmium::item_type::node:
+                    handler.node(static_cast<const osmium::DiffNode&>(diff));
+                    break;
+                case osmium::item_type::way:
+                    handler.way(static_cast<const osmium::DiffWay&>(diff));
+                    break;
+                case osmium::item_type::relation:
+                    handler.relation(static_cast<const osmium::DiffRelation&>(diff));
+                    break;
+                default:
+                    throw osmium::unknown_type();
+            }
+        }
+
+        template <class THandler, class ...TRest>
+        inline void apply_diff_iterator_recurse(const osmium::DiffObject& diff, THandler& handler, TRest&... more) {
+            apply_diff_iterator_recurse(diff, handler);
+            apply_diff_iterator_recurse(diff, more...);
+        }
+
+    } // namespace detail
+
+    template <class TIterator, class ...THandlers>
+    inline void apply_diff(TIterator it, TIterator end, THandlers&... handlers) {
+        typedef osmium::DiffIterator<TIterator> diff_iterator;
+
+        diff_iterator dit(it, end);
+        diff_iterator dend(end, end);
+
+        for (; dit != dend; ++dit) {
+            detail::apply_diff_iterator_recurse(*dit, handlers...);
+        }
+    }
+
+    class OSMObject;
+
+    template <class TSource, class ...THandlers>
+    inline void apply_diff(TSource& source, THandlers&... handlers) {
+        apply_diff(osmium::io::InputIterator<TSource, osmium::OSMObject> {source},
+                   osmium::io::InputIterator<TSource, osmium::OSMObject> {},
+                   handlers...);
+    }
+
+    template <class ...THandlers>
+    inline void apply_diff(osmium::memory::Buffer& buffer, THandlers&... handlers) {
+        apply_diff(buffer.begin(), buffer.end(), handlers...);
+    }
+
+    template <class ...THandlers>
+    inline void apply_diff(const osmium::memory::Buffer& buffer, THandlers&... handlers) {
+        apply_diff(buffer.cbegin(), buffer.cend(), handlers...);
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_DIFF_VISITOR_HPP
diff --git a/third_party/osmium/dynamic_handler.hpp b/third_party/osmium/dynamic_handler.hpp
new file mode 100644
index 0000000..bc59313
--- /dev/null
+++ b/third_party/osmium/dynamic_handler.hpp
@@ -0,0 +1,195 @@
+#ifndef OSMIUM_DYNAMIC_HANDLER_HPP
+#define OSMIUM_DYNAMIC_HANDLER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <memory>
+#include <utility>
+
+#include <osmium/handler.hpp>
+
+namespace osmium {
+
+    class Node;
+    class Way;
+    class Relation;
+    class Area;
+    class Changeset;
+
+    namespace handler {
+
+        namespace detail {
+
+            class HandlerWrapperBase {
+
+            public:
+
+                virtual ~HandlerWrapperBase() {
+                }
+
+                virtual void node(const osmium::Node&) {
+                }
+
+                virtual void way(const osmium::Way&) {
+                }
+
+                virtual void relation(const osmium::Relation&) {
+                }
+
+                virtual void area(const osmium::Area&) {
+                }
+
+                virtual void changeset(const osmium::Changeset&) {
+                }
+
+                virtual void flush() {
+                }
+
+            }; // class HandlerWrapperBase
+
+
+            // The following uses trick from
+            // http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence
+            // to either call handler style functions or visitor style operator().
+
+#define OSMIUM_DYNAMIC_HANDLER_DISPATCH(_name_, _type_) \
+template <class THandler> \
+auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, int) -> decltype(handler._name_(object), void()) { \
+    handler._name_(object); \
+} \
+template <class THandler> \
+auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) -> decltype(handler(object), void()) { \
+    handler(object); \
+}
+
+            OSMIUM_DYNAMIC_HANDLER_DISPATCH(node, Node)
+            OSMIUM_DYNAMIC_HANDLER_DISPATCH(way, Way)
+            OSMIUM_DYNAMIC_HANDLER_DISPATCH(relation, Relation)
+            OSMIUM_DYNAMIC_HANDLER_DISPATCH(changeset, Changeset)
+            OSMIUM_DYNAMIC_HANDLER_DISPATCH(area, Area)
+
+            template <class THandler>
+            auto flush_dispatch(THandler& handler, int) -> decltype(handler.flush(), void()) {
+                handler.flush();
+            }
+
+            template <class THandler>
+            void flush_dispatch(THandler&, long) {}
+
+            template <class THandler>
+            class HandlerWrapper : public HandlerWrapperBase {
+
+                THandler m_handler;
+
+            public:
+
+                template <class... TArgs>
+                HandlerWrapper(TArgs&&... args) :
+                    m_handler(std::forward<TArgs>(args)...) {
+                }
+
+                void node(const osmium::Node& node) override final {
+                    node_dispatch(m_handler, node, 0);
+                }
+
+                void way(const osmium::Way& way) override final {
+                    way_dispatch(m_handler, way, 0);
+                }
+
+                void relation(const osmium::Relation& relation) override final {
+                    relation_dispatch(m_handler, relation, 0);
+                }
+
+                void area(const osmium::Area& area) override final {
+                    area_dispatch(m_handler, area, 0);
+                }
+
+                void changeset(const osmium::Changeset& changeset) override final {
+                    changeset_dispatch(m_handler, changeset, 0);
+                }
+
+                void flush() override final {
+                    flush_dispatch(m_handler, 0);
+                }
+
+            }; // class HandlerWrapper
+
+        } // namespace detail
+
+        class DynamicHandler : public osmium::handler::Handler {
+
+            typedef std::unique_ptr<osmium::handler::detail::HandlerWrapperBase> impl_ptr;
+            impl_ptr m_impl;
+
+        public:
+
+            DynamicHandler() :
+                m_impl(impl_ptr(new osmium::handler::detail::HandlerWrapperBase)) {
+            }
+
+            template <class THandler, class... TArgs>
+            void set(TArgs&&... args) {
+                m_impl = impl_ptr(new osmium::handler::detail::HandlerWrapper<THandler>(std::forward<TArgs>(args)...));
+            }
+
+            void node(const osmium::Node& node) {
+                m_impl->node(node);
+            }
+
+            void way(const osmium::Way& way) {
+                m_impl->way(way);
+            }
+
+            void relation(const osmium::Relation& relation) {
+                m_impl->relation(relation);
+            }
+
+            void area(const osmium::Area& area) {
+                m_impl->area(area);
+            }
+
+            void changeset(const osmium::Changeset& changeset) {
+                m_impl->changeset(changeset);
+            }
+
+            void flush() {
+                m_impl->flush();
+            }
+
+        }; // class DynamicHandler
+
+    } // namspace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_DYNAMIC_HANDLER_HPP
diff --git a/third_party/osmium/experimental/flex_reader.hpp b/third_party/osmium/experimental/flex_reader.hpp
new file mode 100644
index 0000000..8dca152
--- /dev/null
+++ b/third_party/osmium/experimental/flex_reader.hpp
@@ -0,0 +1,131 @@
+#ifndef OSMIUM_EXPERIMENTAL_FLEX_READER_HPP
+#define OSMIUM_EXPERIMENTAL_FLEX_READER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/handler/node_locations_for_ways.hpp>
+#include <osmium/visitor.hpp>
+#include <osmium/area/multipolygon_collector.hpp>
+#include <osmium/area/assembler.hpp>
+
+namespace osmium {
+
+    /**
+     * Experimental code that is not "officially" supported.
+     */
+    namespace experimental {
+
+        template <class TLocationHandler>
+        class FlexReader {
+
+            bool m_with_areas;
+            osmium::osm_entity_bits::type m_entities;
+
+            typename TLocationHandler::index_pos_type m_index_pos;
+            typename TLocationHandler::index_neg_type m_index_neg;
+            TLocationHandler m_location_handler;
+
+            osmium::io::Reader m_reader;
+            osmium::area::Assembler::config_type m_assembler_config;
+            osmium::area::MultipolygonCollector<osmium::area::Assembler> m_collector;
+
+        public:
+
+            explicit FlexReader(const osmium::io::File& file, osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::nwr) :
+                m_with_areas(entities & osmium::osm_entity_bits::area),
+                m_entities((entities & ~osmium::osm_entity_bits::area) | (m_with_areas ? osmium::osm_entity_bits::node | osmium::osm_entity_bits::way : osmium::osm_entity_bits::nothing)),
+                m_index_pos(),
+                m_index_neg(),
+                m_location_handler(m_index_pos, m_index_neg),
+                m_reader(file, m_entities),
+                m_assembler_config(),
+                m_collector(m_assembler_config)
+            {
+                m_location_handler.ignore_errors();
+                if (m_with_areas) {
+                    osmium::io::Reader reader(file, osmium::osm_entity_bits::relation);
+                    m_collector.read_relations(reader);
+                    reader.close();
+                }
+            }
+
+            explicit FlexReader(const std::string& filename, osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::nwr) :
+                FlexReader(osmium::io::File(filename), entities) {
+            }
+
+            explicit FlexReader(const char* filename, osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::nwr) :
+                FlexReader(osmium::io::File(filename), entities) {
+            }
+
+            std::vector<osmium::memory::Buffer> read() {
+                std::vector<osmium::memory::Buffer> buffers;
+
+                osmium::memory::Buffer buffer = m_reader.read();
+
+                if (buffer) {
+                    buffers.push_back(std::move(buffer));
+                    if (m_with_areas) {
+                        osmium::apply(buffers[0], m_location_handler, m_collector.handler([&buffers](osmium::memory::Buffer&& area_buffer) {
+                            buffers.push_back(std::move(area_buffer));
+                        }));
+                    } else if (m_entities & (osmium::osm_entity_bits::node | osmium::osm_entity_bits::way)) {
+                        osmium::apply(buffers[0], m_location_handler);
+                    }
+                }
+
+                return buffers;
+            }
+
+            osmium::io::Header header() const {
+                return m_reader.header();
+            }
+
+            void close() {
+                return m_reader.close();
+            }
+
+            bool eof() const {
+                return m_reader.eof();
+            }
+
+            const osmium::area::MultipolygonCollector<osmium::area::Assembler>& collector() const {
+                return m_collector;
+            }
+
+        }; // class FlexReader
+
+    } // namespace experimental
+
+} // namespace osmium
+
+#endif // OSMIUM_EXPERIMENTAL_FLEX_READER_HPP
diff --git a/third_party/osmium/geom/coordinates.hpp b/third_party/osmium/geom/coordinates.hpp
new file mode 100644
index 0000000..1ff27fe
--- /dev/null
+++ b/third_party/osmium/geom/coordinates.hpp
@@ -0,0 +1,97 @@
+#ifndef OSMIUM_GEOM_COORDINATES_HPP
+#define OSMIUM_GEOM_COORDINATES_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <iosfwd>
+#include <string>
+
+#include <osmium/osm/location.hpp>
+#include <osmium/util/double.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        struct Coordinates {
+
+            double x;
+            double y;
+
+            explicit Coordinates(double cx, double cy) noexcept : x(cx), y(cy) {
+            }
+
+            Coordinates(const osmium::Location& location) : x(location.lon()), y(location.lat()) {
+            }
+
+            void append_to_string(std::string& s, const char infix, int precision) const {
+                osmium::util::double2string(s, x, precision);
+                s += infix;
+                osmium::util::double2string(s, y, precision);
+            }
+
+            void append_to_string(std::string& s, const char prefix, const char infix, const char suffix, int precision) const {
+                s += prefix;
+                append_to_string(s, infix, precision);
+                s += suffix;
+            }
+
+        }; // struct coordinates
+
+        /**
+         * Compare whether two Coordinates are identical. Might not give the
+         * right result if the coordinates have been the result of some
+         * calculation that introduced rounding errors.
+         */
+        inline bool operator==(const Coordinates& lhs, const Coordinates& rhs) noexcept {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+            return lhs.x == rhs.x && lhs.y == rhs.y;
+#pragma GCC diagnostic pop
+        }
+
+        inline bool operator!=(const Coordinates& lhs, const Coordinates& rhs) noexcept {
+            return ! operator==(lhs, rhs);
+        }
+
+        template <typename TChar, typename TTraits>
+        inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const Coordinates& c) {
+            return out << '(' << c.x << ',' << c.y << ')';
+        }
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_COORDINATES_HPP
diff --git a/third_party/osmium/geom/factory.hpp b/third_party/osmium/geom/factory.hpp
new file mode 100644
index 0000000..4097b5d
--- /dev/null
+++ b/third_party/osmium/geom/factory.hpp
@@ -0,0 +1,328 @@
+#ifndef OSMIUM_GEOM_FACTORY_HPP
+#define OSMIUM_GEOM_FACTORY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/area.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/way.hpp>
+
+namespace osmium {
+
+    /**
+     * Exception thrown when an invalid geometry is encountered. An example
+     * would be a linestring with less than two points.
+     */
+    struct geometry_error : public std::runtime_error {
+
+        geometry_error(const std::string& what) :
+            std::runtime_error(what) {
+        }
+
+        geometry_error(const char* what) :
+            std::runtime_error(what) {
+        }
+
+    }; // struct geometry_error
+
+    /**
+     * @brief Everything related to geometry handling.
+     */
+    namespace geom {
+
+        /**
+         * Which nodes of a way to use for a linestring.
+         */
+        enum class use_nodes : bool {
+            unique = true, ///< Remove consecutive nodes with same location.
+            all    = false ///< Use all nodes.
+        }; // enum class use_nodes
+
+        /**
+         * Which direction the linestring created from a way
+         * should have.
+         */
+        enum class direction : bool {
+            backward = true, ///< Linestring has reverse direction.
+            forward  = false ///< Linestring has same direction as way.
+        }; // enum class direction
+
+        /**
+         * This pseudo projection just returns its WGS84 input unchanged.
+         * Used as a template parameter if a real projection is not needed.
+         */
+        class IdentityProjection {
+
+        public:
+
+            Coordinates operator()(osmium::Location location) const {
+                return Coordinates{location.lon(), location.lat()};
+            }
+
+            int epsg() const noexcept {
+                return 4326;
+            }
+
+            std::string proj_string() const {
+                return "+proj=longlat +datum=WGS84 +no_defs";
+            }
+
+        }; // class IdentityProjection
+
+        /**
+         * Geometry factory.
+         */
+        template <class TGeomImpl, class TProjection = IdentityProjection>
+        class GeometryFactory {
+
+            /**
+             * Add all points of an outer or inner ring to a multipolygon.
+             */
+            void add_points(const osmium::OuterRing& nodes) {
+                osmium::Location last_location;
+                for (const osmium::NodeRef& node_ref : nodes) {
+                    if (last_location != node_ref.location()) {
+                        last_location = node_ref.location();
+                        m_impl.multipolygon_add_location(m_projection(last_location));
+                    }
+                }
+            }
+
+            TProjection m_projection;
+            TGeomImpl m_impl;
+
+        public:
+
+            /**
+             * Constructor for default initialized projection.
+             */
+            template <class... TArgs>
+            GeometryFactory<TGeomImpl, TProjection>(TArgs&&... args) :
+                m_projection(),
+                m_impl(std::forward<TArgs>(args)...) {
+            }
+
+            /**
+             * Constructor for explicitly initialized projection. Note that the
+             * projection is moved into the GeometryFactory.
+             */
+            template <class... TArgs>
+            GeometryFactory<TGeomImpl, TProjection>(TProjection&& projection, TArgs&&... args) :
+                m_projection(std::move(projection)),
+                m_impl(std::forward<TArgs>(args)...) {
+            }
+
+            typedef typename TGeomImpl::point_type        point_type;
+            typedef typename TGeomImpl::linestring_type   linestring_type;
+            typedef typename TGeomImpl::polygon_type      polygon_type;
+            typedef typename TGeomImpl::multipolygon_type multipolygon_type;
+            typedef typename TGeomImpl::ring_type         ring_type;
+
+            int epsg() const {
+                return m_projection.epsg();
+            }
+
+            std::string proj_string() const {
+                return m_projection.proj_string();
+            }
+
+            /* Point */
+
+            point_type create_point(const osmium::Location location) const {
+                return m_impl.make_point(m_projection(location));
+            }
+
+            point_type create_point(const osmium::Node& node) {
+                return create_point(node.location());
+            }
+
+            point_type create_point(const osmium::NodeRef& node_ref) {
+                return create_point(node_ref.location());
+            }
+
+            /* LineString */
+
+            void linestring_start() {
+                m_impl.linestring_start();
+            }
+
+            template <class TIter>
+            size_t fill_linestring(TIter it, TIter end) {
+                size_t num_points = 0;
+                for (; it != end; ++it, ++num_points) {
+                    m_impl.linestring_add_location(m_projection(it->location()));
+                }
+                return num_points;
+            }
+
+            template <class TIter>
+            size_t fill_linestring_unique(TIter it, TIter end) {
+                size_t num_points = 0;
+                osmium::Location last_location;
+                for (; it != end; ++it) {
+                    if (last_location != it->location()) {
+                        last_location = it->location();
+                        m_impl.linestring_add_location(m_projection(last_location));
+                        ++num_points;
+                    }
+                }
+                return num_points;
+            }
+
+            linestring_type linestring_finish(size_t num_points) {
+                return m_impl.linestring_finish(num_points);
+            }
+
+            linestring_type create_linestring(const osmium::WayNodeList& wnl, use_nodes un=use_nodes::unique, direction dir=direction::forward) {
+                linestring_start();
+                size_t num_points = 0;
+
+                if (un == use_nodes::unique) {
+                    osmium::Location last_location;
+                    switch (dir) {
+                        case direction::forward:
+                            num_points = fill_linestring_unique(wnl.cbegin(), wnl.cend());
+                            break;
+                        case direction::backward:
+                            num_points = fill_linestring_unique(wnl.crbegin(), wnl.crend());
+                            break;
+                    }
+                } else {
+                    switch (dir) {
+                        case direction::forward:
+                            num_points = fill_linestring(wnl.cbegin(), wnl.cend());
+                            break;
+                        case direction::backward:
+                            num_points = fill_linestring(wnl.crbegin(), wnl.crend());
+                            break;
+                    }
+                }
+
+                if (num_points < 2) {
+                    throw osmium::geometry_error("not enough points for linestring");
+                }
+
+                return linestring_finish(num_points);
+            }
+
+            linestring_type create_linestring(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir=direction::forward) {
+                return create_linestring(way.nodes(), un, dir);
+            }
+
+            /* Polygon */
+
+            void polygon_start() {
+                m_impl.polygon_start();
+            }
+
+            template <class TIter>
+            size_t fill_polygon(TIter it, TIter end) {
+                size_t num_points = 0;
+                for (; it != end; ++it, ++num_points) {
+                    m_impl.polygon_add_location(m_projection(it->location()));
+                }
+                return num_points;
+            }
+
+            template <class TIter>
+            size_t fill_polygon_unique(TIter it, TIter end) {
+                size_t num_points = 0;
+                osmium::Location last_location;
+                for (; it != end; ++it) {
+                    if (last_location != it->location()) {
+                        last_location = it->location();
+                        m_impl.polygon_add_location(m_projection(last_location));
+                        ++num_points;
+                    }
+                }
+                return num_points;
+            }
+
+            polygon_type polygon_finish(size_t num_points) {
+                return m_impl.polygon_finish(num_points);
+            }
+
+            /* MultiPolygon */
+
+            multipolygon_type create_multipolygon(const osmium::Area& area) {
+                size_t num_polygons = 0;
+                size_t num_rings = 0;
+                m_impl.multipolygon_start();
+
+                for (auto it = area.cbegin(); it != area.cend(); ++it) {
+                    const osmium::OuterRing& ring = static_cast<const osmium::OuterRing&>(*it);
+                    if (it->type() == osmium::item_type::outer_ring) {
+                        if (num_polygons > 0) {
+                            m_impl.multipolygon_polygon_finish();
+                        }
+                        m_impl.multipolygon_polygon_start();
+                        m_impl.multipolygon_outer_ring_start();
+                        add_points(ring);
+                        m_impl.multipolygon_outer_ring_finish();
+                        ++num_rings;
+                        ++num_polygons;
+                    } else if (it->type() == osmium::item_type::inner_ring) {
+                        m_impl.multipolygon_inner_ring_start();
+                        add_points(ring);
+                        m_impl.multipolygon_inner_ring_finish();
+                        ++num_rings;
+                    }
+                }
+
+                // if there are no rings, this area is invalid
+                if (num_rings == 0) {
+                    throw osmium::geometry_error("invalid area");
+                }
+
+                m_impl.multipolygon_polygon_finish();
+                return m_impl.multipolygon_finish();
+            }
+
+        }; // class GeometryFactory
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_FACTORY_HPP
diff --git a/third_party/osmium/geom/geojson.hpp b/third_party/osmium/geom/geojson.hpp
new file mode 100644
index 0000000..f6d7ee6
--- /dev/null
+++ b/third_party/osmium/geom/geojson.hpp
@@ -0,0 +1,152 @@
+#ifndef OSMIUM_GEOM_GEOJSON_HPP
+#define OSMIUM_GEOM_GEOJSON_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <string>
+#include <utility>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/factory.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        namespace detail {
+
+            class GeoJSONFactoryImpl {
+
+                std::string m_str;
+                int m_precision;
+
+            public:
+
+                typedef std::string point_type;
+                typedef std::string linestring_type;
+                typedef std::string polygon_type;
+                typedef std::string multipolygon_type;
+                typedef std::string ring_type;
+
+                GeoJSONFactoryImpl(int precision = 7) :
+                    m_precision(precision) {
+                }
+
+                /* Point */
+
+                // { "type": "Point", "coordinates": [100.0, 0.0] }
+                point_type make_point(const osmium::geom::Coordinates& xy) const {
+                    std::string str {"{\"type\":\"Point\",\"coordinates\":"};
+                    xy.append_to_string(str, '[', ',', ']', m_precision);
+                    str += "}";
+                    return str;
+                }
+
+                /* LineString */
+
+                // { "type": "LineString", "coordinates": [ [100.0, 0.0], [101.0, 1.0] ] }
+                void linestring_start() {
+                    m_str = "{\"type\":\"LineString\",\"coordinates\":[";
+                }
+
+                void linestring_add_location(const osmium::geom::Coordinates& xy) {
+                    xy.append_to_string(m_str, '[', ',', ']', m_precision);
+                    m_str += ',';
+                }
+
+                linestring_type linestring_finish(size_t /* num_points */) {
+                    assert(!m_str.empty());
+                    std::string str;
+                    std::swap(str, m_str);
+                    str.back() = ']';
+                    str += "}";
+                    return str;
+                }
+
+                /* MultiPolygon */
+
+                void multipolygon_start() {
+                    m_str = "{\"type\":\"MultiPolygon\",\"coordinates\":[";
+                }
+
+                void multipolygon_polygon_start() {
+                    m_str += '[';
+                }
+
+                void multipolygon_polygon_finish() {
+                    m_str += "],";
+                }
+
+                void multipolygon_outer_ring_start() {
+                    m_str += '[';
+                }
+
+                void multipolygon_outer_ring_finish() {
+                    assert(!m_str.empty());
+                    m_str.back() = ']';
+                }
+
+                void multipolygon_inner_ring_start() {
+                    m_str += ",[";
+                }
+
+                void multipolygon_inner_ring_finish() {
+                    assert(!m_str.empty());
+                    m_str.back() = ']';
+                }
+
+                void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
+                    xy.append_to_string(m_str, '[', ',', ']', m_precision);
+                    m_str += ',';
+                }
+
+                multipolygon_type multipolygon_finish() {
+                    assert(!m_str.empty());
+                    m_str.back() = ']';
+                    m_str += "}";
+                    return std::move(m_str);
+                }
+
+            }; // class GeoJSONFactoryImpl
+
+        } // namespace detail
+
+        template <class TProjection = IdentityProjection>
+        using GeoJSONFactory = GeometryFactory<osmium::geom::detail::GeoJSONFactoryImpl, TProjection>;
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_GEOJSON_HPP
diff --git a/third_party/osmium/geom/geos.hpp b/third_party/osmium/geom/geos.hpp
new file mode 100644
index 0000000..877520b
--- /dev/null
+++ b/third_party/osmium/geom/geos.hpp
@@ -0,0 +1,224 @@
+#ifndef OSMIUM_GEOM_GEOS_HPP
+#define OSMIUM_GEOM_GEOS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#define OSMIUM_COMPILE_WITH_CFLAGS_GEOS `geos-config --cflags`
+#define OSMIUM_LINK_WITH_LIBS_GEOS `geos-config --libs`
+
+#include <utility>
+
+#include <geos/geom/Coordinate.h>
+#include <geos/geom/CoordinateSequence.h>
+#include <geos/geom/CoordinateSequenceFactory.h>
+#include <geos/geom/GeometryFactory.h>
+#include <geos/geom/LinearRing.h>
+#include <geos/geom/MultiPolygon.h>
+#include <geos/geom/Point.h>
+#include <geos/geom/Polygon.h>
+#include <geos/geom/PrecisionModel.h>
+#include <geos/util/GEOSException.h>
+
+#include <osmium/geom/factory.hpp>
+#include <osmium/geom/coordinates.hpp>
+
+// MSVC doesn't support throw_with_nested yet
+#ifdef _MSC_VER
+# define THROW throw
+#else
+# define THROW std::throw_with_nested
+#endif
+
+namespace osmium {
+
+    struct geos_geometry_error : public geometry_error {
+
+        geos_geometry_error() :
+            geometry_error("geometry creation failed in GEOS library, see nested exception for details") {
+        }
+
+    }; // struct geos_geometry_error
+
+    namespace geom {
+
+        namespace detail {
+
+            class GEOSFactoryImpl {
+
+                geos::geom::PrecisionModel m_precision_model;
+                geos::geom::GeometryFactory m_geos_factory;
+
+                std::unique_ptr<geos::geom::CoordinateSequence> m_coordinate_sequence;
+                std::vector<std::unique_ptr<geos::geom::LinearRing>> m_rings;
+                std::vector<std::unique_ptr<geos::geom::Polygon>> m_polygons;
+
+            public:
+
+                typedef std::unique_ptr<geos::geom::Point>        point_type;
+                typedef std::unique_ptr<geos::geom::LineString>   linestring_type;
+                typedef std::unique_ptr<geos::geom::Polygon>      polygon_type;
+                typedef std::unique_ptr<geos::geom::MultiPolygon> multipolygon_type;
+                typedef std::unique_ptr<geos::geom::LinearRing>   ring_type;
+
+                explicit GEOSFactoryImpl(int srid = -1) :
+                    m_precision_model(),
+                    m_geos_factory(&m_precision_model, srid) {
+                }
+
+                /* Point */
+
+                point_type make_point(const osmium::geom::Coordinates& xy) const {
+                    try {
+                        return point_type(m_geos_factory.createPoint(geos::geom::Coordinate(xy.x, xy.y)));
+                    } catch (geos::util::GEOSException&) {
+                        THROW(osmium::geos_geometry_error());
+                    }
+                }
+
+                /* LineString */
+
+                void linestring_start() {
+                    try {
+                        m_coordinate_sequence.reset(m_geos_factory.getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
+                    } catch (geos::util::GEOSException&) {
+                        THROW(osmium::geos_geometry_error());
+                    }
+                }
+
+                void linestring_add_location(const osmium::geom::Coordinates& xy) {
+                    try {
+                        m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y));
+                    } catch (geos::util::GEOSException&) {
+                        THROW(osmium::geos_geometry_error());
+                    }
+                }
+
+                linestring_type linestring_finish(size_t /* num_points */) {
+                    try {
+                        return linestring_type(m_geos_factory.createLineString(m_coordinate_sequence.release()));
+                    } catch (geos::util::GEOSException&) {
+                        THROW(osmium::geos_geometry_error());
+                    }
+                }
+
+                /* MultiPolygon */
+
+                void multipolygon_start() {
+                    m_polygons.clear();
+                }
+
+                void multipolygon_polygon_start() {
+                    m_rings.clear();
+                }
+
+                void multipolygon_polygon_finish() {
+                    try {
+                        assert(!m_rings.empty());
+                        auto inner_rings = new std::vector<geos::geom::Geometry*>;
+                        std::transform(std::next(m_rings.begin(), 1), m_rings.end(), std::back_inserter(*inner_rings), [](std::unique_ptr<geos::geom::LinearRing>& r) {
+                            return r.release();
+                        });
+                        m_polygons.emplace_back(m_geos_factory.createPolygon(m_rings[0].release(), inner_rings));
+                        m_rings.clear();
+                    } catch (geos::util::GEOSException&) {
+                        THROW(osmium::geos_geometry_error());
+                    }
+                }
+
+                void multipolygon_outer_ring_start() {
+                    try {
+                        m_coordinate_sequence.reset(m_geos_factory.getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
+                    } catch (geos::util::GEOSException&) {
+                        THROW(osmium::geos_geometry_error());
+                    }
+                }
+
+                void multipolygon_outer_ring_finish() {
+                    try {
+                        m_rings.emplace_back(m_geos_factory.createLinearRing(m_coordinate_sequence.release()));
+                    } catch (geos::util::GEOSException&) {
+                        THROW(osmium::geos_geometry_error());
+                    }
+                }
+
+                void multipolygon_inner_ring_start() {
+                    try {
+                        m_coordinate_sequence.reset(m_geos_factory.getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
+                    } catch (geos::util::GEOSException&) {
+                        THROW(osmium::geos_geometry_error());
+                    }
+                }
+
+                void multipolygon_inner_ring_finish() {
+                    try {
+                        m_rings.emplace_back(m_geos_factory.createLinearRing(m_coordinate_sequence.release()));
+                    } catch (geos::util::GEOSException&) {
+                        THROW(osmium::geos_geometry_error());
+                    }
+                }
+
+                void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
+                    try {
+                        m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y));
+                    } catch (geos::util::GEOSException&) {
+                        THROW(osmium::geos_geometry_error());
+                    }
+                }
+
+                multipolygon_type multipolygon_finish() {
+                    try {
+                        auto polygons = new std::vector<geos::geom::Geometry*>;
+                        std::transform(m_polygons.begin(), m_polygons.end(), std::back_inserter(*polygons), [](std::unique_ptr<geos::geom::Polygon>& p) {
+                            return p.release();
+                        });
+                        m_polygons.clear();
+                        return multipolygon_type(m_geos_factory.createMultiPolygon(polygons));
+                    } catch (geos::util::GEOSException&) {
+                        THROW(osmium::geos_geometry_error());
+                    }
+                }
+
+            }; // class GEOSFactoryImpl
+
+        } // namespace detail
+
+        template <class TProjection = IdentityProjection>
+        using GEOSFactory = GeometryFactory<osmium::geom::detail::GEOSFactoryImpl, TProjection>;
+
+    } // namespace geom
+
+} // namespace osmium
+
+#undef THROW
+
+#endif // OSMIUM_GEOM_GEOS_HPP
diff --git a/third_party/osmium/geom/haversine.hpp b/third_party/osmium/geom/haversine.hpp
new file mode 100644
index 0000000..b8d0134
--- /dev/null
+++ b/third_party/osmium/geom/haversine.hpp
@@ -0,0 +1,94 @@
+#ifndef OSMIUM_GEOM_HAVERSINE_HPP
+#define OSMIUM_GEOM_HAVERSINE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cmath>
+#include <iterator>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/util.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/way.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        /**
+         * @brief Functions to calculate arc distance on Earth using the haversine formula.
+         *
+         * See http://en.wikipedia.org/wiki/Haversine_formula
+         *
+         * Implementation derived from
+         * http://blog.julien.cayzac.name/2008/10/arc-and-distance-between-two-points-on.html
+         */
+        namespace haversine {
+
+            /// @brief Earth's quadratic mean radius for WGS84
+            constexpr double EARTH_RADIUS_IN_METERS = 6372797.560856;
+
+            /**
+             * Calculate distance in meters between two sets of coordinates.
+             */
+            inline double distance(const osmium::geom::Coordinates& c1, const osmium::geom::Coordinates& c2) {
+                double lonh = sin(deg_to_rad(c1.x - c2.x) * 0.5);
+                lonh *= lonh;
+                double lath = sin(deg_to_rad(c1.y - c2.y) * 0.5);
+                lath *= lath;
+                const double tmp = cos(deg_to_rad(c1.y)) * cos(deg_to_rad(c2.y));
+                return 2.0 * EARTH_RADIUS_IN_METERS * asin(sqrt(lath + tmp*lonh));
+            }
+
+            /**
+             * Calculate length of way.
+             */
+            inline double distance(const osmium::WayNodeList& wnl) {
+                double sum_length=0;
+
+                for (auto it = wnl.begin(); it != wnl.end(); ++it) {
+                    if (std::next(it) != wnl.end()) {
+                        sum_length += distance(it->location(), std::next(it)->location());
+                    }
+                }
+
+                return sum_length;
+            }
+
+        } // namespace haversine
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_HAVERSINE_HPP
diff --git a/third_party/osmium/geom/mercator_projection.hpp b/third_party/osmium/geom/mercator_projection.hpp
new file mode 100644
index 0000000..d170017
--- /dev/null
+++ b/third_party/osmium/geom/mercator_projection.hpp
@@ -0,0 +1,109 @@
+#ifndef OSMIUM_GEOM_MERCATOR_PROJECTION_HPP
+#define OSMIUM_GEOM_MERCATOR_PROJECTION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cmath>
+#include <string>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/util.hpp>
+#include <osmium/osm/location.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        namespace detail {
+
+            constexpr double earth_radius_for_epsg3857 = 6378137.0;
+
+            constexpr inline double lon_to_x(double lon) {
+                return earth_radius_for_epsg3857 * deg_to_rad(lon);
+            }
+
+            inline double lat_to_y(double lat) { // not constexpr because math functions aren't
+                return earth_radius_for_epsg3857 * std::log(std::tan(osmium::geom::PI/4 + deg_to_rad(lat)/2));
+            }
+
+            constexpr inline double x_to_lon(double x) {
+                return rad_to_deg(x) / earth_radius_for_epsg3857;
+            }
+
+            inline double y_to_lat(double y) { // not constexpr because math functions aren't
+                return rad_to_deg(2 * std::atan(std::exp(y / earth_radius_for_epsg3857)) - osmium::geom::PI/2);
+            }
+
+        } // namespace detail
+
+        /**
+         * The maximum latitude that can be projected with the Web Mercator
+         * (EPSG:3857) projection.
+         */
+        constexpr double MERCATOR_MAX_LAT = 85.0511288;
+
+        inline Coordinates lonlat_to_mercator(const Coordinates& c) {
+            return Coordinates(detail::lon_to_x(c.x), detail::lat_to_y(c.y));
+        }
+
+        inline Coordinates mercator_to_lonlat(const Coordinates& c) {
+            return Coordinates(detail::x_to_lon(c.x), detail::y_to_lat(c.y));
+        }
+
+        /**
+         * Functor that does projection from WGS84 (EPSG:4326) to "Web
+         * Mercator" (EPSG:3857)
+         */
+        class MercatorProjection {
+
+        public:
+
+            Coordinates operator()(osmium::Location location) const {
+                return Coordinates {detail::lon_to_x(location.lon()), detail::lat_to_y(location.lat())};
+            }
+
+            int epsg() const noexcept {
+                return 3857;
+            }
+
+            std::string proj_string() const {
+                return "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs";
+            }
+
+        }; // class MercatorProjection
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_MERCATOR_PROJECTION_HPP
diff --git a/third_party/osmium/geom/ogr.hpp b/third_party/osmium/geom/ogr.hpp
new file mode 100644
index 0000000..2727f2f
--- /dev/null
+++ b/third_party/osmium/geom/ogr.hpp
@@ -0,0 +1,179 @@
+#ifndef OSMIUM_GEOM_OGR_HPP
+#define OSMIUM_GEOM_OGR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#define OSMIUM_COMPILE_WITH_CFLAGS_OGR `gdal-config --cflags`
+#define OSMIUM_LINK_WITH_LIBS_OGR `gdal-config --libs`
+
+#include <cassert>
+#include <cstddef>
+#include <memory>
+#include <utility>
+
+#pragma GCC diagnostic push
+#ifdef __clang__
+# pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
+#endif
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#pragma GCC diagnostic ignored "-Wpadded"
+# include <ogr_geometry.h>
+#pragma GCC diagnostic pop
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/factory.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        namespace detail {
+
+            class OGRFactoryImpl {
+
+            public:
+
+                typedef std::unique_ptr<OGRPoint>        point_type;
+                typedef std::unique_ptr<OGRLineString>   linestring_type;
+                typedef std::unique_ptr<OGRPolygon>      polygon_type;
+                typedef std::unique_ptr<OGRMultiPolygon> multipolygon_type;
+                typedef std::unique_ptr<OGRLinearRing>   ring_type;
+
+            private:
+
+                linestring_type   m_linestring;
+                multipolygon_type m_multipolygon;
+                polygon_type      m_polygon;
+                ring_type         m_ring;
+
+            public:
+
+                OGRFactoryImpl() = default;
+
+                /* Point */
+
+                point_type make_point(const osmium::geom::Coordinates& xy) const {
+                    return point_type(new OGRPoint(xy.x, xy.y));
+                }
+
+                /* LineString */
+
+                void linestring_start() {
+                    m_linestring = std::unique_ptr<OGRLineString>(new OGRLineString());
+                }
+
+                void linestring_add_location(const osmium::geom::Coordinates& xy) {
+                    assert(!!m_linestring);
+                    m_linestring->addPoint(xy.x, xy.y);
+                }
+
+                linestring_type linestring_finish(size_t /* num_points */) {
+                    return std::move(m_linestring);
+                }
+
+                /* Polygon */
+
+                void polygon_start() {
+                    m_ring = std::unique_ptr<OGRLinearRing>(new OGRLinearRing());
+                }
+
+                void polygon_add_location(const osmium::geom::Coordinates& xy) {
+                    assert(!!m_ring);
+                    m_ring->addPoint(xy.x, xy.y);
+                }
+
+                polygon_type polygon_finish(size_t /* num_points */) {
+                    std::unique_ptr<OGRPolygon> polygon = std::unique_ptr<OGRPolygon>(new OGRPolygon());
+                    polygon->addRingDirectly(m_ring.release());
+                    return polygon;
+                }
+
+                /* MultiPolygon */
+
+                void multipolygon_start() {
+                    m_multipolygon.reset(new OGRMultiPolygon());
+                }
+
+                void multipolygon_polygon_start() {
+                    m_polygon.reset(new OGRPolygon());
+                }
+
+                void multipolygon_polygon_finish() {
+                    assert(!!m_multipolygon);
+                    assert(!!m_polygon);
+                    m_multipolygon->addGeometryDirectly(m_polygon.release());
+                }
+
+                void multipolygon_outer_ring_start() {
+                    m_ring.reset(new OGRLinearRing());
+                }
+
+                void multipolygon_outer_ring_finish() {
+                    assert(!!m_polygon);
+                    assert(!!m_ring);
+                    m_polygon->addRingDirectly(m_ring.release());
+                }
+
+                void multipolygon_inner_ring_start() {
+                    m_ring.reset(new OGRLinearRing());
+                }
+
+                void multipolygon_inner_ring_finish() {
+                    assert(!!m_polygon);
+                    assert(!!m_ring);
+                    m_polygon->addRingDirectly(m_ring.release());
+                }
+
+                void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
+                    assert(!!m_polygon);
+                    assert(!!m_ring);
+                    m_ring->addPoint(xy.x, xy.y);
+                }
+
+                multipolygon_type multipolygon_finish() {
+                    assert(!!m_multipolygon);
+                    return std::move(m_multipolygon);
+                }
+
+            }; // class OGRFactoryImpl
+
+        } // namespace detail
+
+        template <class TProjection = IdentityProjection>
+        using OGRFactory = GeometryFactory<osmium::geom::detail::OGRFactoryImpl, TProjection>;
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_OGR_HPP
diff --git a/third_party/osmium/geom/projection.hpp b/third_party/osmium/geom/projection.hpp
new file mode 100644
index 0000000..72ff945
--- /dev/null
+++ b/third_party/osmium/geom/projection.hpp
@@ -0,0 +1,159 @@
+#ifndef OSMIUM_GEOM_PROJECTION_HPP
+#define OSMIUM_GEOM_PROJECTION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#define OSMIUM_LINK_WITH_LIBS_PROJ -lproj
+
+#include <memory>
+#include <string>
+
+#include <proj_api.h>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/util.hpp>
+#include <osmium/osm/location.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        /**
+         * C++ wrapper for a Coordinate Reference System of the proj library.
+         */
+        class CRS {
+
+            struct ProjCRSDeleter {
+                void operator()(void* crs) {
+                    pj_free(crs);
+                }
+            }; // struct ProjCRSDeleter
+
+            std::unique_ptr<void, ProjCRSDeleter> m_crs;
+
+            projPJ get() const {
+                return m_crs.get();
+            }
+
+        public:
+
+            CRS(const std::string& crs) :
+                m_crs(pj_init_plus(crs.c_str()), ProjCRSDeleter()) {
+                if (!m_crs) {
+                    throw osmium::projection_error(std::string("creation of CRS failed: ") + pj_strerrno(*pj_get_errno_ref()));
+                }
+            }
+
+            CRS(int epsg) :
+                CRS(std::string("+init=epsg:") + std::to_string(epsg)) {
+            }
+
+            bool is_latlong() const {
+                return pj_is_latlong(m_crs.get());
+            }
+
+            bool is_geocent() const {
+                return pj_is_geocent(m_crs.get());
+            }
+
+            /**
+             * Transform coordinates from one CRS into another. Wraps the same function
+             * of the proj library.
+             *
+             * Coordinates have to be in radians and are produced in radians.
+             *
+             * @throws osmmium::projection_error if the projection fails
+             */
+            friend Coordinates transform(const CRS& src, const CRS& dest, Coordinates c) {
+                int result = pj_transform(src.get(), dest.get(), 1, 1, &c.x, &c.y, nullptr);
+                if (result != 0) {
+                    throw osmium::projection_error(std::string("projection failed: ") + pj_strerrno(result));
+                }
+                return c;
+            }
+
+        }; // class CRS
+
+        /**
+         * Functor that does projection from WGS84 (EPSG:4326) in to the given
+         * CRS.
+         */
+        class Projection {
+
+            int m_epsg;
+            std::string m_proj_string;
+            CRS m_crs_wgs84 {4326};
+            CRS m_crs_user;
+
+        public:
+
+            Projection(const std::string& proj_string) :
+                m_epsg(-1),
+                m_proj_string(proj_string),
+                m_crs_user(proj_string) {
+            }
+
+            Projection(int epsg) :
+                m_epsg(epsg),
+                m_proj_string(std::string("+init=epsg:") + std::to_string(epsg)),
+                m_crs_user(epsg) {
+            }
+
+            Coordinates operator()(osmium::Location location) const {
+                if (m_epsg == 4326) {
+                    return Coordinates(location.lon(), location.lat());
+                } else {
+                    Coordinates c = transform(m_crs_wgs84, m_crs_user, Coordinates(deg_to_rad(location.lon()), deg_to_rad(location.lat())));
+                    if (m_crs_user.is_latlong()) {
+                        c.x = rad_to_deg(c.x);
+                        c.y = rad_to_deg(c.y);
+                    }
+                    return c;
+                }
+            }
+
+            int epsg() const noexcept {
+                return m_epsg;
+            }
+
+            std::string proj_string() const {
+                return m_proj_string;
+            }
+
+        }; // class Projection
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_PROJECTION_HPP
diff --git a/third_party/osmium/geom/relations.hpp b/third_party/osmium/geom/relations.hpp
new file mode 100644
index 0000000..e57e2f4
--- /dev/null
+++ b/third_party/osmium/geom/relations.hpp
@@ -0,0 +1,57 @@
+#ifndef OSMIUM_GEOM_RELATIONS_HPP
+#define OSMIUM_GEOM_RELATIONS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/location.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        /**
+         * Check whether one geometry contains another.
+         */
+        inline bool contains(const osmium::Box& a, const osmium::Box& b) {
+            return ((a.bottom_left().x() >= b.bottom_left().x()) &&
+                    (a.top_right().x()   <= b.top_right().x())   &&
+                    (a.bottom_left().y() >= b.bottom_left().y()) &&
+                    (a.top_right().y()   <= b.top_right().y()));
+        }
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_RELATIONS_HPP
diff --git a/third_party/osmium/geom/util.hpp b/third_party/osmium/geom/util.hpp
new file mode 100644
index 0000000..1f1a50d
--- /dev/null
+++ b/third_party/osmium/geom/util.hpp
@@ -0,0 +1,75 @@
+#ifndef OSMIUM_GEOM_UTIL_HPP
+#define OSMIUM_GEOM_UTIL_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <stdexcept>
+#include <string>
+
+namespace osmium {
+
+    /**
+     * Exception thrown when a projection object can not be initialized or the
+     * projection of some coordinates can not be calculated.
+     */
+    struct projection_error : public std::runtime_error {
+
+        projection_error(const std::string& what) :
+            std::runtime_error(what) {
+        }
+
+        projection_error(const char* what) :
+            std::runtime_error(what) {
+        }
+
+    }; // struct projection_error
+
+    namespace geom {
+
+        constexpr double PI = 3.14159265358979323846;
+
+        /// Convert angle from degrees to radians.
+        inline constexpr double deg_to_rad(double degree) noexcept {
+            return degree * (PI / 180.0);
+        }
+
+        /// Convert angle from radians to degrees.
+        inline constexpr double rad_to_deg(double radians) noexcept {
+            return radians * (180.0 / PI);
+        }
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_UTIL_HPP
diff --git a/third_party/osmium/geom/wkb.hpp b/third_party/osmium/geom/wkb.hpp
new file mode 100644
index 0000000..0748ede
--- /dev/null
+++ b/third_party/osmium/geom/wkb.hpp
@@ -0,0 +1,279 @@
+#ifndef OSMIUM_GEOM_WKB_HPP
+#define OSMIUM_GEOM_WKB_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <string>
+
+// Windows is only available for little endian architectures
+// http://stackoverflow.com/questions/6449468/can-i-safely-assume-that-windows-installations-will-always-be-little-endian
+#if !defined(_WIN32) && !defined(__APPLE__)
+# include <endian.h>
+#else
+# define __LITTLE_ENDIAN 1234
+# define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/factory.hpp>
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        enum class wkb_type : bool {
+            wkb  = false,
+            ewkb = true
+        }; // enum class wkb_type
+
+        enum class out_type : bool {
+            binary = false,
+            hex    = true
+        }; // enum class out_type
+
+        namespace detail {
+
+            template <typename T>
+            inline void str_push(std::string& str, T data) {
+                size_t size = str.size();
+                str.resize(size + sizeof(T));
+                std::memcpy(const_cast<char *>(&str[size]), reinterpret_cast<char*>(&data), sizeof(T));
+            }
+
+            inline std::string convert_to_hex(std::string& str) {
+                static const char* lookup_hex = "0123456789ABCDEF";
+                std::string out;
+
+                for (char c : str) {
+                    out += lookup_hex[(c >> 4) & 0xf];
+                    out += lookup_hex[c & 0xf];
+                }
+
+                return out;
+            }
+
+            class WKBFactoryImpl {
+
+                /// OSM data always uses SRID 4326 (WGS84).
+                static constexpr uint32_t srid = 4326;
+
+                /**
+                * Type of WKB geometry.
+                * These definitions are from
+                * 99-049_OpenGIS_Simple_Features_Specification_For_SQL_Rev_1.1.pdf (for WKB)
+                * and http://trac.osgeo.org/postgis/browser/trunk/doc/ZMSgeoms.txt (for EWKB).
+                * They are used to encode geometries into the WKB format.
+                */
+                enum wkbGeometryType : uint32_t {
+                    wkbPoint               = 1,
+                    wkbLineString          = 2,
+                    wkbPolygon             = 3,
+                    wkbMultiPoint          = 4,
+                    wkbMultiLineString     = 5,
+                    wkbMultiPolygon        = 6,
+                    wkbGeometryCollection  = 7,
+
+                    // SRID-presence flag (EWKB)
+                    wkbSRID                = 0x20000000
+                }; // enum wkbGeometryType
+
+                /**
+                * Byte order marker in WKB geometry.
+                */
+                enum class wkb_byte_order_type : uint8_t {
+                    XDR = 0,         // Big Endian
+                    NDR = 1          // Little Endian
+                }; // enum class wkb_byte_order_type
+
+                std::string m_data;
+                uint32_t m_points {0};
+                wkb_type m_wkb_type;
+                out_type m_out_type;
+
+                size_t m_linestring_size_offset = 0;
+                size_t m_polygons = 0;
+                size_t m_rings = 0;
+                size_t m_multipolygon_size_offset = 0;
+                size_t m_polygon_size_offset = 0;
+                size_t m_ring_size_offset = 0;
+
+                size_t header(std::string& str, wkbGeometryType type, bool add_length) const {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+                    str_push(str, wkb_byte_order_type::NDR);
+#else
+                    str_push(str, wkb_byte_order_type::XDR);
+#endif
+                    if (m_wkb_type == wkb_type::ewkb) {
+                        str_push(str, type | wkbSRID);
+                        str_push(str, srid);
+                    } else {
+                        str_push(str, type);
+                    }
+                    size_t offset = str.size();
+                    if (add_length) {
+                        str_push(str, static_cast<uint32_t>(0));
+                    }
+                    return offset;
+                }
+
+                void set_size(const size_t offset, const size_t size) {
+                    const uint32_t s = static_cast_with_assert<uint32_t>(size);
+                    memcpy(&m_data[offset], &s, sizeof(uint32_t));
+                }
+
+            public:
+
+                typedef std::string point_type;
+                typedef std::string linestring_type;
+                typedef std::string polygon_type;
+                typedef std::string multipolygon_type;
+                typedef std::string ring_type;
+
+                explicit WKBFactoryImpl(wkb_type wtype=wkb_type::wkb, out_type otype=out_type::binary) :
+                    m_wkb_type(wtype),
+                    m_out_type(otype) {
+                }
+
+                /* Point */
+
+                point_type make_point(const osmium::geom::Coordinates& xy) const {
+                    std::string data;
+                    header(data, wkbPoint, false);
+                    str_push(data, xy.x);
+                    str_push(data, xy.y);
+
+                    if (m_out_type == out_type::hex) {
+                        return convert_to_hex(data);
+                    } else {
+                        return data;
+                    }
+                }
+
+                /* LineString */
+
+                void linestring_start() {
+                    m_data.clear();
+                    m_linestring_size_offset = header(m_data, wkbLineString, true);
+                }
+
+                void linestring_add_location(const osmium::geom::Coordinates& xy) {
+                    str_push(m_data, xy.x);
+                    str_push(m_data, xy.y);
+                }
+
+                linestring_type linestring_finish(size_t num_points) {
+                    set_size(m_linestring_size_offset, num_points);
+                    std::string data;
+                    std::swap(data, m_data);
+
+                    if (m_out_type == out_type::hex) {
+                        return convert_to_hex(data);
+                    } else {
+                        return data;
+                    }
+                }
+
+                /* MultiPolygon */
+
+                void multipolygon_start() {
+                    m_data.clear();
+                    m_polygons = 0;
+                    m_multipolygon_size_offset = header(m_data, wkbMultiPolygon, true);
+                }
+
+                void multipolygon_polygon_start() {
+                    ++m_polygons;
+                    m_rings = 0;
+                    m_polygon_size_offset = header(m_data, wkbPolygon, true);
+                }
+
+                void multipolygon_polygon_finish() {
+                    set_size(m_polygon_size_offset, m_rings);
+                }
+
+                void multipolygon_outer_ring_start() {
+                    ++m_rings;
+                    m_points = 0;
+                    m_ring_size_offset = m_data.size();
+                    str_push(m_data, static_cast<uint32_t>(0));
+                }
+
+                void multipolygon_outer_ring_finish() {
+                    set_size(m_ring_size_offset, m_points);
+                }
+
+                void multipolygon_inner_ring_start() {
+                    ++m_rings;
+                    m_points = 0;
+                    m_ring_size_offset = m_data.size();
+                    str_push(m_data, static_cast<uint32_t>(0));
+                }
+
+                void multipolygon_inner_ring_finish() {
+                    set_size(m_ring_size_offset, m_points);
+                }
+
+                void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
+                    str_push(m_data, xy.x);
+                    str_push(m_data, xy.y);
+                    ++m_points;
+                }
+
+                multipolygon_type multipolygon_finish() {
+                    set_size(m_multipolygon_size_offset, m_polygons);
+                    std::string data;
+                    std::swap(data, m_data);
+
+                    if (m_out_type == out_type::hex) {
+                        return convert_to_hex(data);
+                    } else {
+                        return data;
+                    }
+                }
+
+            }; // class WKBFactoryImpl
+
+        } // namespace detail
+
+        template <class TProjection = IdentityProjection>
+        using WKBFactory = GeometryFactory<osmium::geom::detail::WKBFactoryImpl, TProjection>;
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_WKB_HPP
diff --git a/third_party/osmium/geom/wkt.hpp b/third_party/osmium/geom/wkt.hpp
new file mode 100644
index 0000000..0ef304a
--- /dev/null
+++ b/third_party/osmium/geom/wkt.hpp
@@ -0,0 +1,148 @@
+#ifndef OSMIUM_GEOM_WKT_HPP
+#define OSMIUM_GEOM_WKT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstddef>
+#include <string>
+#include <utility>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/factory.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        namespace detail {
+
+            class WKTFactoryImpl {
+
+                std::string m_str;
+                int m_precision;
+
+            public:
+
+                typedef std::string point_type;
+                typedef std::string linestring_type;
+                typedef std::string polygon_type;
+                typedef std::string multipolygon_type;
+                typedef std::string ring_type;
+
+                WKTFactoryImpl(int precision = 7) :
+                    m_precision(precision) {
+                }
+
+                /* Point */
+
+                point_type make_point(const osmium::geom::Coordinates& xy) const {
+                    std::string str {"POINT"};
+                    xy.append_to_string(str, '(', ' ', ')', m_precision);
+                    return str;
+                }
+
+                /* LineString */
+
+                void linestring_start() {
+                    m_str = "LINESTRING(";
+                }
+
+                void linestring_add_location(const osmium::geom::Coordinates& xy) {
+                    xy.append_to_string(m_str, ' ', m_precision);
+                    m_str += ',';
+                }
+
+                linestring_type linestring_finish(size_t /* num_points */) {
+                    assert(!m_str.empty());
+                    std::string str;
+                    std::swap(str, m_str);
+                    str.back() = ')';
+                    return str;
+                }
+
+                /* MultiPolygon */
+
+                void multipolygon_start() {
+                    m_str = "MULTIPOLYGON(";
+                }
+
+                void multipolygon_polygon_start() {
+                    m_str += '(';
+                }
+
+                void multipolygon_polygon_finish() {
+                    m_str += "),";
+                }
+
+                void multipolygon_outer_ring_start() {
+                    m_str += '(';
+                }
+
+                void multipolygon_outer_ring_finish() {
+                    assert(!m_str.empty());
+                    m_str.back() = ')';
+                }
+
+                void multipolygon_inner_ring_start() {
+                    m_str += ",(";
+                }
+
+                void multipolygon_inner_ring_finish() {
+                    assert(!m_str.empty());
+                    m_str.back() = ')';
+                }
+
+                void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
+                    xy.append_to_string(m_str, ' ', m_precision);
+                    m_str += ',';
+                }
+
+                multipolygon_type multipolygon_finish() {
+                    assert(!m_str.empty());
+                    m_str.back() = ')';
+                    return std::move(m_str);
+                }
+
+            }; // class WKTFactoryImpl
+
+        } // namespace detail
+
+        template <class TProjection = IdentityProjection>
+        using WKTFactory = GeometryFactory<osmium::geom::detail::WKTFactoryImpl, TProjection>;
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_WKT_HPP
diff --git a/third_party/osmium/handler.hpp b/third_party/osmium/handler.hpp
new file mode 100644
index 0000000..62e59f8
--- /dev/null
+++ b/third_party/osmium/handler.hpp
@@ -0,0 +1,101 @@
+#ifndef OSMIUM_HANDLER_HPP
+#define OSMIUM_HANDLER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+namespace osmium {
+
+    class OSMObject;
+    class Node;
+    class Way;
+    class Relation;
+    class Area;
+    class Changeset;
+    class TagList;
+    class WayNodeList;
+    class RelationMemberList;
+    class OuterRing;
+    class InnerRing;
+
+    /**
+     * @brief Osmium handlers provide callbacks for OSM objects
+     */
+    namespace handler {
+
+        class Handler {
+
+        public:
+
+            void osm_object(const osmium::OSMObject&) const {
+            }
+
+            void node(const osmium::Node&) const {
+            }
+
+            void way(const osmium::Way&) const {
+            }
+
+            void relation(const osmium::Relation&) const {
+            }
+
+            void area(const osmium::Area&) const {
+            }
+
+            void changeset(const osmium::Changeset&) const {
+            }
+
+            void tag_list(const osmium::TagList&) const {
+            }
+
+            void way_node_list(const osmium::WayNodeList&) const {
+            }
+
+            void relation_member_list(const osmium::RelationMemberList&) const {
+            }
+
+            void outer_ring(const osmium::OuterRing&) const {
+            }
+
+            void inner_ring(const osmium::InnerRing&) const {
+            }
+
+            void flush() const {
+            }
+
+        }; // class Handler
+
+    } // namspace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_HPP
diff --git a/third_party/osmium/handler/chain.hpp b/third_party/osmium/handler/chain.hpp
new file mode 100644
index 0000000..868632d
--- /dev/null
+++ b/third_party/osmium/handler/chain.hpp
@@ -0,0 +1,128 @@
+#ifndef OSMIUM_HANDLER_CHAIN_HPP
+#define OSMIUM_HANDLER_CHAIN_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <tuple>
+
+#include <osmium/handler.hpp>
+
+#define OSMIUM_CHAIN_HANDLER_CALL(_func_, _type_) \
+    template <int N, int SIZE, class THandlers> \
+    struct call_ ## _func_ { \
+        void operator()(THandlers& handlers, osmium::_type_& object) { \
+            std::get<N>(handlers)._func_(object); \
+            call_ ## _func_<N+1, SIZE, THandlers>()(handlers, object); \
+        } \
+    }; \
+    template <int SIZE, class THandlers> \
+    struct call_ ## _func_<SIZE, SIZE, THandlers> { \
+        void operator()(THandlers&, osmium::_type_&) {} \
+    };
+
+namespace osmium {
+
+    class Node;
+    class Way;
+    class Relation;
+    class Area;
+    class Changeset;
+
+    namespace handler {
+
+        /**
+         * This handler allows chaining of any number of handlers into a single
+         * handler.
+         */
+        template <class ...THandler>
+        class ChainHandler : public osmium::handler::Handler {
+
+            typedef std::tuple<THandler&...> handlers_type;
+            handlers_type m_handlers;
+
+            template <int N, int SIZE, class THandlers>
+            struct call_flush {
+                void operator()(THandlers& handlers) {
+                    std::get<N>(handlers).flush();
+                    call_flush<N+1, SIZE, THandlers>()(handlers);
+                }
+            }; // struct call_flush
+
+            template <int SIZE, class THandlers>
+            struct call_flush<SIZE, SIZE, THandlers> {
+                void operator()(THandlers&) {}
+            }; // struct call_flush
+
+            OSMIUM_CHAIN_HANDLER_CALL(node, Node)
+            OSMIUM_CHAIN_HANDLER_CALL(way, Way)
+            OSMIUM_CHAIN_HANDLER_CALL(relation, Relation)
+            OSMIUM_CHAIN_HANDLER_CALL(changeset, Changeset)
+            OSMIUM_CHAIN_HANDLER_CALL(area, Area)
+
+        public:
+
+            explicit ChainHandler(THandler&... handlers) :
+                m_handlers(handlers...) {
+            }
+
+            void node(osmium::Node& node) {
+                call_node<0, sizeof...(THandler), handlers_type>()(m_handlers, node);
+            }
+
+            void way(osmium::Way& way) {
+                call_way<0, sizeof...(THandler), handlers_type>()(m_handlers, way);
+            }
+
+            void relation(osmium::Relation& relation) {
+                call_relation<0, sizeof...(THandler), handlers_type>()(m_handlers, relation);
+            }
+
+            void changeset( osmium::Changeset& changeset) {
+                call_changeset<0, sizeof...(THandler), handlers_type>()(m_handlers, changeset);
+            }
+
+            void area(osmium::Area& area) {
+                call_area<0, sizeof...(THandler), handlers_type>()(m_handlers, area);
+            }
+
+            void flush() {
+                call_flush<0, sizeof...(THandler), handlers_type>()(m_handlers);
+            }
+
+        }; // class ChainHandler
+
+    } // namespace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_CHAIN_HPP
diff --git a/third_party/osmium/handler/disk_store.hpp b/third_party/osmium/handler/disk_store.hpp
new file mode 100644
index 0000000..2b7ffcf
--- /dev/null
+++ b/third_party/osmium/handler/disk_store.hpp
@@ -0,0 +1,111 @@
+#ifndef OSMIUM_HANDLER_DISK_STORE_HPP
+#define OSMIUM_HANDLER_DISK_STORE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+
+#include <osmium/handler.hpp>
+#include <osmium/index/map.hpp>
+#include <osmium/io/detail/read_write.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/item_iterator.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+    namespace handler {
+
+        /**
+         *
+         * Note: This handler will only work if either all object IDs are
+         *       positive or all object IDs are negative.
+         */
+        class DiskStore : public osmium::handler::Handler {
+
+            typedef osmium::index::map::Map<unsigned_object_id_type, size_t> offset_index_type;
+
+            size_t m_offset = 0;
+            int m_data_fd;
+
+            offset_index_type& m_node_index;
+            offset_index_type& m_way_index;
+            offset_index_type& m_relation_index;
+
+        public:
+
+            explicit DiskStore(int data_fd, offset_index_type& node_index, offset_index_type& way_index, offset_index_type& relation_index) :
+                m_data_fd(data_fd),
+                m_node_index(node_index),
+                m_way_index(way_index),
+                m_relation_index(relation_index) {
+            }
+
+            DiskStore(const DiskStore&) = delete;
+            DiskStore& operator=(const DiskStore&) = delete;
+
+            ~DiskStore() noexcept = default;
+
+            void node(const osmium::Node& node) {
+                m_node_index.set(node.positive_id(), m_offset);
+                m_offset += node.byte_size();
+            }
+
+            void way(const osmium::Way& way) {
+                m_way_index.set(way.positive_id(), m_offset);
+                m_offset += way.byte_size();
+            }
+
+            void relation(const osmium::Relation& relation) {
+                m_relation_index.set(relation.positive_id(), m_offset);
+                m_offset += relation.byte_size();
+            }
+
+            // XXX
+            void operator()(const osmium::memory::Buffer& buffer) {
+                osmium::io::detail::reliable_write(m_data_fd, buffer.data(), buffer.committed());
+
+                osmium::apply(buffer.begin(), buffer.end(), *this);
+            }
+
+        }; // class DiskStore
+
+    } // namespace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_DISK_STORE_HPP
diff --git a/third_party/osmium/handler/dump.hpp b/third_party/osmium/handler/dump.hpp
new file mode 100644
index 0000000..e62c4b0
--- /dev/null
+++ b/third_party/osmium/handler/dump.hpp
@@ -0,0 +1,294 @@
+#ifndef OSMIUM_HANDLER_DUMP_HPP
+#define OSMIUM_HANDLER_DUMP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <iomanip>
+#include <iostream>
+#include <string>
+
+#include <osmium/handler.hpp>
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/area.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/changeset.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+    namespace handler {
+
+        class Dump : public osmium::handler::Handler {
+
+            std::ostream* m_out;
+            bool m_with_size;
+            std::string m_prefix;
+
+            void print_title(const char* title, const osmium::memory::Item& item) {
+                *m_out << m_prefix
+                       << title
+                       << ":";
+
+                if (m_with_size) {
+                    *m_out << " ["
+                           << item.byte_size()
+                           << "]";
+                }
+
+                *m_out << "\n";
+            }
+
+            void print_meta(const osmium::OSMObject& object) {
+                *m_out << m_prefix
+                       << "  id="
+                       << object.id()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  version="
+                       << object.version()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  uid="
+                       << object.uid()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  user=|"
+                       << object.user()
+                       << "|\n";
+                *m_out << m_prefix
+                       << "  changeset="
+                       << object.changeset()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  timestamp="
+                       << object.timestamp().to_iso()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  visible="
+                       << (object.visible() ? "yes" : "no")
+                       << "\n";
+
+                Dump dump(*m_out, m_with_size, m_prefix + "  ");
+                osmium::apply(object.cbegin(), object.cend(), dump);
+            }
+
+            void print_location(const osmium::Node& node) {
+                const osmium::Location& location = node.location();
+
+                if (location) {
+                    *m_out << m_prefix
+                           << "  lon="
+                           << std::fixed
+                           << std::setprecision(7)
+                           << location.lon_without_check()
+                           << "\n";
+                    *m_out << m_prefix
+                           << "  lat="
+                           << location.lat_without_check()
+                           << "\n";
+                } else {
+                    *m_out << m_prefix
+                           << "  lon=\n"
+                           << m_prefix
+                           << "  lat=\n";
+                }
+            }
+
+        public:
+
+            explicit Dump(std::ostream& out, bool with_size=true, const std::string& prefix="") :
+                m_out(&out),
+                m_with_size(with_size),
+                m_prefix(prefix) {
+            }
+
+            void tag_list(const osmium::TagList& tags) {
+                print_title("TAGS", tags);
+                for (const auto& tag : tags) {
+                    *m_out << m_prefix
+                           << "  k=|"
+                           << tag.key()
+                           << "| v=|"
+                           << tag.value()
+                           << "|"
+                           << "\n";
+                }
+            }
+
+            void way_node_list(const osmium::WayNodeList& wnl) {
+                print_title("NODES", wnl);
+                for (const auto& node_ref : wnl) {
+                    *m_out << m_prefix
+                           << "  ref="
+                           << node_ref.ref();
+                    if (node_ref.location()) {
+                        *m_out << " pos="
+                               << node_ref.location();
+                    }
+                    *m_out << "\n";
+                }
+            }
+
+            void relation_member_list(const osmium::RelationMemberList& rml) {
+                print_title("MEMBERS", rml);
+                for (const auto& member : rml) {
+                    *m_out << m_prefix
+                           << "  type="
+                           << item_type_to_name(member.type())
+                           << " ref="
+                           << member.ref()
+                           << " role=|"
+                           << member.role()
+                           << "|\n";
+                    if (member.full_member()) {
+                        Dump dump(*m_out, m_with_size, m_prefix + "  | ");
+                        osmium::apply_item(member.get_object(), dump);
+                    }
+                }
+            }
+
+            void outer_ring(const osmium::OuterRing& ring) {
+                print_title("OUTER RING", ring);
+                for (const auto& node_ref : ring) {
+                    *m_out << m_prefix
+                           << "  ref="
+                           << node_ref.ref();
+                    if (node_ref.location()) {
+                        *m_out << " pos="
+                               << node_ref.location();
+                    }
+                    *m_out << "\n";
+                }
+            }
+
+            void inner_ring(const osmium::InnerRing& ring) {
+                print_title("INNER RING", ring);
+                for (const auto& node_ref : ring) {
+                    *m_out << m_prefix
+                           << "  ref="
+                           << node_ref.ref();
+                    if (node_ref.location()) {
+                        *m_out << " pos="
+                               << node_ref.location();
+                    }
+                    *m_out << "\n";
+                }
+            }
+
+            void node(const osmium::Node& node) {
+                print_title("NODE", node);
+                print_meta(node);
+                print_location(node);
+            }
+
+            void way(const osmium::Way& way) {
+                print_title("WAY", way);
+                print_meta(way);
+            }
+
+            void relation(const osmium::Relation& relation) {
+                print_title("RELATION", relation);
+                print_meta(relation);
+            }
+
+            void area(const osmium::Area& area) {
+                print_title("AREA", area);
+                print_meta(area);
+            }
+
+            void changeset(const osmium::Changeset& changeset) {
+                print_title("CHANGESET", changeset);
+                *m_out << m_prefix
+                       << "  id="
+                       << changeset.id()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  num_changes="
+                       << changeset.num_changes()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  uid="
+                       << changeset.uid()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  user=|"
+                       << changeset.user()
+                       << "|\n";
+                *m_out << m_prefix
+                       << "  created_at="
+                       << changeset.created_at().to_iso()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  closed_at="
+                       << changeset.closed_at().to_iso()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  bounds=";
+
+                if (changeset.bounds()) {
+                    *m_out << '('
+                           << changeset.bounds().bottom_left().lon_without_check()
+                           << ','
+                           << changeset.bounds().bottom_left().lat_without_check()
+                           << ','
+                           << changeset.bounds().top_right().lon_without_check()
+                           << ','
+                           << changeset.bounds().top_right().lat_without_check()
+                           << ')';
+                } else {
+                    *m_out << "(undefined)";
+                }
+
+                *m_out << "\n";
+
+                Dump dump(*m_out, m_with_size, m_prefix + "  ");
+                osmium::apply(changeset.cbegin(), changeset.cend(), dump);
+            }
+
+        }; // class Dump
+
+    } // namespace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_DUMP_HPP
diff --git a/third_party/osmium/handler/node_locations_for_ways.hpp b/third_party/osmium/handler/node_locations_for_ways.hpp
new file mode 100644
index 0000000..a273082
--- /dev/null
+++ b/third_party/osmium/handler/node_locations_for_ways.hpp
@@ -0,0 +1,177 @@
+#ifndef OSMIUM_HANDLER_NODE_LOCATIONS_FOR_WAYS_HPP
+#define OSMIUM_HANDLER_NODE_LOCATIONS_FOR_WAYS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <type_traits>
+
+#include <osmium/handler.hpp>
+#include <osmium/index/index.hpp>
+#include <osmium/index/map/dummy.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/way.hpp>
+
+namespace osmium {
+
+    namespace handler {
+
+        typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> dummy_type;
+
+        /**
+         * Handler to retrieve locations from nodes and add them to ways.
+         *
+         * @tparam TStoragePosIDs Class that handles the actual storage of the node locations
+         *                        (for positive IDs). It must support the set(id, value) and
+         *                        get(id) methods.
+         * @tparam TStorageNegIDs Same but for negative IDs.
+         */
+        template <class TStoragePosIDs, class TStorageNegIDs = dummy_type>
+        class NodeLocationsForWays : public osmium::handler::Handler {
+
+            static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStoragePosIDs>::value,
+                "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
+
+            static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStorageNegIDs>::value,
+                "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
+
+        public:
+
+            typedef TStoragePosIDs index_pos_type;
+            typedef TStorageNegIDs index_neg_type;
+
+        private:
+
+            /// Object that handles the actual storage of the node locations (with positive IDs).
+            TStoragePosIDs& m_storage_pos;
+
+            /// Object that handles the actual storage of the node locations (with negative IDs).
+            TStorageNegIDs& m_storage_neg;
+
+            bool m_ignore_errors {false};
+
+            bool m_must_sort {false};
+
+            // It is okay to have this static dummy instance, even when using several threads,
+            // because it is read-only.
+            static dummy_type& get_dummy() {
+                static dummy_type instance;
+                return instance;
+            }
+
+        public:
+
+            explicit NodeLocationsForWays(TStoragePosIDs& storage_pos,
+                                          TStorageNegIDs& storage_neg = get_dummy()) :
+                m_storage_pos(storage_pos),
+                m_storage_neg(storage_neg) {
+            }
+
+            NodeLocationsForWays(const NodeLocationsForWays&) = delete;
+            NodeLocationsForWays& operator=(const NodeLocationsForWays&) = delete;
+
+            ~NodeLocationsForWays() noexcept = default;
+
+            void ignore_errors() {
+                m_ignore_errors = true;
+            }
+
+            /**
+             * Store the location of the node in the storage.
+             */
+            void node(const osmium::Node& node) {
+                m_must_sort = true;
+                const osmium::object_id_type id = node.id();
+                if (id >= 0) {
+                    m_storage_pos.set(static_cast<osmium::unsigned_object_id_type>( id), node.location());
+                } else {
+                    m_storage_neg.set(static_cast<osmium::unsigned_object_id_type>(-id), node.location());
+                }
+            }
+
+            /**
+             * Get location of node with given id.
+             */
+            osmium::Location get_node_location(const osmium::object_id_type id) const {
+                if (id >= 0) {
+                    return m_storage_pos.get(static_cast<osmium::unsigned_object_id_type>( id));
+                } else {
+                    return m_storage_neg.get(static_cast<osmium::unsigned_object_id_type>(-id));
+                }
+            }
+
+            /**
+             * Retrieve locations of all nodes in the way from storage and add
+             * them to the way object.
+             */
+            void way(osmium::Way& way) {
+                if (m_must_sort) {
+                    m_storage_pos.sort();
+                    m_storage_neg.sort();
+                    m_must_sort = false;
+                }
+                bool error = false;
+                for (auto& node_ref : way.nodes()) {
+                    try {
+                        node_ref.set_location(get_node_location(node_ref.ref()));
+                        if (!node_ref.location()) {
+                            error = true;
+                        }
+                    } catch (osmium::not_found&) {
+                        error = true;
+                    }
+                }
+                if (error && !m_ignore_errors) {
+                    throw osmium::not_found("location for one or more nodes not found in node location index");
+                }
+            }
+
+            /**
+             * Call clear on the location indexes. Makes the
+             * NodeLocationsForWays handler unusable. Used to explicitly free
+             * memory if thats needed.
+             */
+            void clear() {
+                m_storage_pos.clear();
+                m_storage_neg.clear();
+            }
+
+        }; // class NodeLocationsForWays
+
+    } // namespace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_NODE_LOCATIONS_FOR_WAYS_HPP
diff --git a/third_party/osmium/handler/object_relations.hpp b/third_party/osmium/handler/object_relations.hpp
new file mode 100644
index 0000000..e73ce87
--- /dev/null
+++ b/third_party/osmium/handler/object_relations.hpp
@@ -0,0 +1,106 @@
+#ifndef OSMIUM_HANDLER_OBJECT_RELATIONS_HPP
+#define OSMIUM_HANDLER_OBJECT_RELATIONS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/handler.hpp>
+#include <osmium/index/multimap.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/way.hpp>
+
+namespace osmium {
+
+    namespace handler {
+
+        /**
+         *
+         * Note: This handler will only work if either all object IDs are
+         *       positive or all object IDs are negative.
+         */
+        class ObjectRelations : public osmium::handler::Handler {
+
+            typedef osmium::index::multimap::Multimap<unsigned_object_id_type, unsigned_object_id_type> index_type;
+
+            index_type& m_index_n2w;
+            index_type& m_index_n2r;
+            index_type& m_index_w2r;
+            index_type& m_index_r2r;
+
+        public:
+
+            explicit ObjectRelations(index_type& n2w, index_type& n2r, index_type& w2r, index_type& r2r) :
+                m_index_n2w(n2w),
+                m_index_n2r(n2r),
+                m_index_w2r(w2r),
+                m_index_r2r(r2r) {
+            }
+
+            ObjectRelations(const ObjectRelations&) = delete;
+            ObjectRelations& operator=(const ObjectRelations&) = delete;
+
+            ~ObjectRelations() noexcept = default;
+
+            void way(const osmium::Way& way) {
+                for (const auto& node_ref : way.nodes()) {
+                    m_index_n2w.set(node_ref.positive_ref(), way.positive_id());
+                }
+            }
+
+            void relation(const osmium::Relation& relation) {
+                for (const auto& member : relation.members()) {
+                    switch (member.type()) {
+                        case osmium::item_type::node:
+                            m_index_n2r.set(member.positive_ref(), relation.positive_id());
+                            break;
+                        case osmium::item_type::way:
+                            m_index_w2r.set(member.positive_ref(), relation.positive_id());
+                            break;
+                        case osmium::item_type::relation:
+                            m_index_r2r.set(member.positive_ref(), relation.positive_id());
+                            break;
+                        default:
+                            break;
+                    }
+                }
+            }
+
+        }; // class ObjectRelations
+
+    } // namespace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_OBJECT_RELATIONS_HPP
diff --git a/third_party/osmium/index/detail/mmap_vector_anon.hpp b/third_party/osmium/index/detail/mmap_vector_anon.hpp
new file mode 100644
index 0000000..f066961
--- /dev/null
+++ b/third_party/osmium/index/detail/mmap_vector_anon.hpp
@@ -0,0 +1,78 @@
+#ifndef OSMIUM_DETAIL_MMAP_VECTOR_ANON_HPP
+#define OSMIUM_DETAIL_MMAP_VECTOR_ANON_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#ifdef __linux__
+
+#include <cstddef>
+
+#include <osmium/index/detail/typed_mmap.hpp>
+#include <osmium/index/detail/mmap_vector_base.hpp>
+
+namespace osmium {
+
+    namespace detail {
+
+        /**
+        * This class looks and behaves like STL vector, but uses mmap internally.
+        */
+        template <typename T>
+        class mmap_vector_anon : public mmap_vector_base<T, mmap_vector_anon> {
+
+        public:
+
+            mmap_vector_anon() :
+                mmap_vector_base<T, osmium::detail::mmap_vector_anon>(
+                    -1,
+                    osmium::detail::mmap_vector_size_increment,
+                    0,
+                    osmium::detail::typed_mmap<T>::map(osmium::detail::mmap_vector_size_increment)) {
+            }
+
+            void reserve(size_t new_capacity) {
+                if (new_capacity > this->capacity()) {
+                    this->data(osmium::detail::typed_mmap<T>::remap(this->data(), this->capacity(), new_capacity));
+                    this->m_capacity = new_capacity;
+                }
+            }
+
+        }; // class mmap_vector_anon
+
+    } // namespace detail
+
+} // namespace osmium
+
+#endif // __linux__
+
+#endif // OSMIUM_DETAIL_MMAP_VECTOR_ANON_HPP
diff --git a/third_party/osmium/index/detail/mmap_vector_base.hpp b/third_party/osmium/index/detail/mmap_vector_base.hpp
new file mode 100644
index 0000000..fc96b27
--- /dev/null
+++ b/third_party/osmium/index/detail/mmap_vector_base.hpp
@@ -0,0 +1,183 @@
+#ifndef OSMIUM_DETAIL_MMAP_VECTOR_BASE_HPP
+#define OSMIUM_DETAIL_MMAP_VECTOR_BASE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <new>
+#include <stdexcept>
+
+#include <osmium/index/detail/typed_mmap.hpp>
+
+namespace osmium {
+
+    namespace detail {
+
+        constexpr size_t mmap_vector_size_increment = 1024 * 1024;
+
+        /**
+         * This is a base class for implementing classes that look like
+         * STL vector but use mmap internally. This class can not be used
+         * on it's own. Use the derived classes mmap_vector_anon or
+         * mmap_vector_file.
+         */
+        template <typename T, template <typename> class TDerived>
+        class mmap_vector_base {
+
+        protected:
+
+            int m_fd;
+            size_t m_capacity;
+            size_t m_size;
+            T* m_data;
+
+            explicit mmap_vector_base(int fd, size_t capacity, size_t size, T* data) noexcept :
+                m_fd(fd),
+                m_capacity(capacity),
+                m_size(size),
+                m_data(data) {
+            }
+
+            explicit mmap_vector_base(int fd, size_t capacity, size_t size) :
+                m_fd(fd),
+                m_capacity(capacity),
+                m_size(size),
+                m_data(osmium::detail::typed_mmap<T>::grow_and_map(capacity, m_fd)) {
+            }
+
+            void data(T* data) {
+                m_data = data;
+            }
+
+        public:
+
+            typedef T value_type;
+            typedef T& reference;
+            typedef const T& const_reference;
+            typedef T* pointer;
+            typedef const T* const_pointer;
+            typedef T* iterator;
+            typedef const T* const_iterator;
+
+            ~mmap_vector_base() {
+                osmium::detail::typed_mmap<T>::unmap(m_data, m_capacity);
+            }
+
+            size_t capacity() const noexcept {
+                return m_capacity;
+            }
+
+            size_t size() const noexcept {
+                return m_size;
+            }
+
+            bool empty() const noexcept {
+                return m_size == 0;
+            }
+
+            const T* data() const noexcept {
+                return m_data;
+            }
+
+            T* data() noexcept {
+                return m_data;
+            }
+
+            T& operator[](size_t n) {
+                return m_data[n];
+            }
+
+            T at(size_t n) const {
+                if (n >= m_size) {
+                    throw std::out_of_range("out of range");
+                }
+                return m_data[n];
+            }
+
+            void clear() noexcept {
+                m_size = 0;
+            }
+
+            void shrink_to_fit() {
+                // XXX do something here
+            }
+
+            void push_back(const T& value) {
+                if (m_size >= m_capacity) {
+                    resize(m_size+1);
+                }
+                m_data[m_size] = value;
+                ++m_size;
+            }
+
+            void resize(size_t new_size) {
+                if (new_size > capacity()) {
+                    static_cast<TDerived<T>*>(this)->reserve(new_size + osmium::detail::mmap_vector_size_increment);
+                }
+                if (new_size > size()) {
+                    new (data() + size()) T[new_size - size()];
+                }
+                m_size = new_size;
+            }
+
+            iterator begin() noexcept {
+                return m_data;
+            }
+
+            iterator end() noexcept {
+                return m_data + m_size;
+            }
+
+            const_iterator begin() const noexcept {
+                return m_data;
+            }
+
+            const_iterator end() const noexcept {
+                return m_data + m_size;
+            }
+
+            const_iterator cbegin() noexcept {
+                return m_data;
+            }
+
+            const_iterator cend() noexcept {
+                return m_data + m_size;
+            }
+
+        }; // class mmap_vector_base
+
+    } // namespace detail
+
+} // namespace osmium
+
+#endif // OSMIUM_DETAIL_MMAP_VECTOR_BASE_HPP
diff --git a/third_party/osmium/index/detail/mmap_vector_file.hpp b/third_party/osmium/index/detail/mmap_vector_file.hpp
new file mode 100644
index 0000000..ca8f0eb
--- /dev/null
+++ b/third_party/osmium/index/detail/mmap_vector_file.hpp
@@ -0,0 +1,82 @@
+#ifndef OSMIUM_DETAIL_MMAP_VECTOR_FILE_HPP
+#define OSMIUM_DETAIL_MMAP_VECTOR_FILE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+
+#include <osmium/index/detail/typed_mmap.hpp>
+#include <osmium/index/detail/mmap_vector_base.hpp>
+#include <osmium/index/detail/tmpfile.hpp>
+
+namespace osmium {
+
+    namespace detail {
+
+        /**
+        * This class looks and behaves like STL vector, but mmap's a file internally.
+        */
+        template <typename T>
+        class mmap_vector_file : public mmap_vector_base<T, mmap_vector_file> {
+
+        public:
+
+            explicit mmap_vector_file() :
+                mmap_vector_base<T, osmium::detail::mmap_vector_file>(
+                    osmium::detail::create_tmp_file(),
+                    osmium::detail::mmap_vector_size_increment,
+                    0) {
+            }
+
+            explicit mmap_vector_file(int fd) :
+                mmap_vector_base<T, osmium::detail::mmap_vector_file>(
+                    fd,
+                    osmium::detail::typed_mmap<T>::file_size(fd) == 0 ? osmium::detail::mmap_vector_size_increment : osmium::detail::typed_mmap<T>::file_size(fd),
+                    osmium::detail::typed_mmap<T>::file_size(fd)) {
+            }
+
+            void reserve(size_t new_capacity) {
+                if (new_capacity > this->capacity()) {
+                    osmium::detail::typed_mmap<T>::unmap(this->data(), this->capacity());
+                    this->data(osmium::detail::typed_mmap<T>::grow_and_map(new_capacity, this->m_fd));
+                    this->m_capacity = new_capacity;
+                }
+            }
+
+        }; // class mmap_vector_file
+
+    } // namespace detail
+
+} // namespace osmium
+
+#endif // OSMIUM_DETAIL_MMAP_VECTOR_FILE_HPP
diff --git a/third_party/osmium/index/detail/tmpfile.hpp b/third_party/osmium/index/detail/tmpfile.hpp
new file mode 100644
index 0000000..3d00c50
--- /dev/null
+++ b/third_party/osmium/index/detail/tmpfile.hpp
@@ -0,0 +1,62 @@
+#ifndef OSMIUM_DETAIL_TMPFILE_HPP
+#define OSMIUM_DETAIL_TMPFILE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cerrno>
+#include <cstdio>
+#include <system_error>
+
+namespace osmium {
+
+    namespace detail {
+
+        /**
+         * Create and open a temporary file. It is removed after opening.
+         *
+         * @returns File descriptor of temporary file.
+         * @throws std::system_error if something went wrong.
+         */
+        inline int create_tmp_file() {
+            FILE* file = ::tmpfile();
+            if (!file) {
+                throw std::system_error(errno, std::system_category(), "tempfile failed");
+            }
+            return fileno(file);
+        }
+
+    } // namespace detail
+
+} // namespace osmium
+
+#endif // OSMIUM_DETAIL_TMPFILE
diff --git a/third_party/osmium/index/detail/typed_mmap.hpp b/third_party/osmium/index/detail/typed_mmap.hpp
new file mode 100644
index 0000000..8a952a4
--- /dev/null
+++ b/third_party/osmium/index/detail/typed_mmap.hpp
@@ -0,0 +1,229 @@
+#ifndef OSMIUM_DETAIL_TYPED_MMAP_HPP
+#define OSMIUM_DETAIL_TYPED_MMAP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cerrno>
+#include <cstddef>
+#include <stdexcept>
+#include <system_error>
+
+#include <sys/stat.h>
+
+#ifndef _WIN32
+# include <sys/mman.h>
+#else
+# include <mmap_for_windows.hpp>
+#endif
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#else
+# define ftruncate _chsize
+#endif
+
+// for bsd systems
+#ifndef MAP_ANONYMOUS
+# define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+    /**
+     * @brief Namespace for Osmium internal use
+     */
+    namespace detail {
+
+        /**
+         * This is a helper class for working with memory mapped files and
+         * anonymous shared memory. It wraps the necessary system calls
+         * adding:
+         * - error checking: all functions throw exceptions where needed
+         * - internal casts and size calculations allow use with user defined
+         *   type T instead of void*
+         *
+         * This class only contains static functions. It should never be
+         * instantiated.
+         *
+         * @tparam T Type of objects we want to store.
+         */
+        template <typename T>
+        class typed_mmap {
+
+        public:
+
+            /**
+             * Create anonymous private memory mapping with enough space for size
+             * objects of type T.
+             *
+             * Note that no constructor is called for any of the objects in this memory!
+             *
+             * @param size Number of objects of type T that should fit into this memory
+             * @returns Pointer to mapped memory
+             * @throws std::system_error If mmap(2) failed
+             */
+            static T* map(size_t size) {
+                void* addr = ::mmap(nullptr, sizeof(T) * size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+                if (addr == MAP_FAILED) {
+                    throw std::system_error(errno, std::system_category(), "mmap failed");
+                }
+#pragma GCC diagnostic pop
+                return reinterpret_cast<T*>(addr);
+            }
+
+            /**
+             * Create shared memory mapping of a file with enough space for size
+             * objects of type T. The file must already have at least the
+             * required size.
+             *
+             * Note that no constructor is called for any of the objects in this memory!
+             *
+             * @param size Number of objects of type T that should fit into this memory
+             * @param fd File descriptor
+             * @param write True if data should be writable
+             * @returns Pointer to mapped memory
+             * @throws std::system_error If mmap(2) failed
+             */
+            static T* map(size_t size, int fd, bool write = false) {
+                int prot = PROT_READ;
+                if (write) {
+                    prot |= PROT_WRITE;
+                }
+                void* addr = ::mmap(nullptr, sizeof(T) * size, prot, MAP_SHARED, fd, 0);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+                if (addr == MAP_FAILED) {
+                    throw std::system_error(errno, std::system_category(), "mmap failed");
+                }
+#pragma GCC diagnostic pop
+                return reinterpret_cast<T*>(addr);
+            }
+
+// mremap(2) is only available on linux systems
+#ifdef __linux__
+            /**
+             * Grow memory mapping created with map().
+             *
+             * Note that no constructor is called for any of the objects in this memory!
+             *
+             * @param data Pointer to current mapping (as returned by typed_mmap())
+             * @param old_size Number of objects currently stored in this memory
+             * @param new_size Number of objects we want to have space for
+             * @throws std::system_error If mremap(2) call failed
+             */
+            static T* remap(T* data, size_t old_size, size_t new_size) {
+                void* addr = ::mremap(reinterpret_cast<void*>(data), sizeof(T) * old_size, sizeof(T) * new_size, MREMAP_MAYMOVE);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+                if (addr == MAP_FAILED) {
+                    throw std::system_error(errno, std::system_category(), "mremap failed");
+                }
+#pragma GCC diagnostic pop
+                return reinterpret_cast<T*>(addr);
+            }
+#endif
+
+            /**
+             * Release memory from map() call.
+             *
+             * Note that no destructor is called for the objects in this memory!
+             *
+             * @param data Pointer to the data
+             * @param size Number of objects of type T stored
+             * @throws std::system_error If munmap(2) call failed
+             */
+            static void unmap(T* data, size_t size) {
+                if (::munmap(reinterpret_cast<void*>(data), sizeof(T) * size) != 0) {
+                    throw std::system_error(errno, std::system_category(), "munmap failed");
+                }
+            }
+
+            /**
+             * Get number of objects of type T that would fit into a file.
+             *
+             * @param fd File descriptor
+             * @returns Number of objects of type T in this file
+             * @throws std::system_error If fstat(2) call failed
+             * @throws std::length_error If size of the file isn't a multiple of sizeof(T)
+             */
+            static size_t file_size(int fd) {
+                struct stat s;
+                if (fstat(fd, &s) < 0) {
+                    throw std::system_error(errno, std::system_category(), "fstat failed");
+                }
+                if (static_cast<size_t>(s.st_size) % sizeof(T) != 0) {
+                    throw std::length_error("file size has to be multiple of object size");
+                }
+                return static_cast<size_t>(s.st_size) / sizeof(T);
+            }
+
+            /**
+             * Grow file so there is enough space for at least new_size objects
+             * of type T. If the file is large enough already, nothing is done.
+             * The file is never shrunk.
+             *
+             * @param new_size Number of objects of type T that should fit into this file
+             * @param fd File descriptor
+             * @throws std::system_error If ftruncate(2) call failed
+             */
+            static void grow_file(size_t new_size, int fd) {
+                if (file_size(fd) < new_size) {
+                    if (::ftruncate(fd, static_cast_with_assert<off_t>(sizeof(T) * new_size)) < 0) {
+                        throw std::system_error(errno, std::system_category(), "ftruncate failed");
+                    }
+                }
+            }
+
+            /**
+             * Grow file to given size (if it is smaller) and mmap it.
+             *
+             * @param size Number of objects of type T that should fit into this file
+             * @param fd File descriptor
+             * @throws Errors thrown by grow_file() or map()
+             */
+            static T* grow_and_map(size_t size, int fd) {
+                grow_file(size, fd);
+                return map(size, fd, true);
+            }
+
+        }; // class typed_mmap
+
+    } // namespace detail
+
+} // namespace osmium
+
+#endif // OSMIUM_DETAIL_TYPED_MMAP_HPP
diff --git a/third_party/osmium/index/index.hpp b/third_party/osmium/index/index.hpp
new file mode 100644
index 0000000..ece8ec4
--- /dev/null
+++ b/third_party/osmium/index/index.hpp
@@ -0,0 +1,100 @@
+#ifndef OSMIUM_INDEX_INDEX_HPP
+#define OSMIUM_INDEX_INDEX_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <limits>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+    /**
+     * Exception signaling that an element could not be
+     * found in an index.
+     */
+    struct not_found : public std::runtime_error {
+
+        not_found(const std::string& what) :
+            std::runtime_error(what) {
+        }
+
+        not_found(const char* what) :
+            std::runtime_error(what) {
+        }
+
+    }; // struct not_found
+
+    /**
+     * @brief Indexing of OSM data, Locations, etc.
+     */
+    namespace index {
+
+        template <typename TKey>
+        OSMIUM_NORETURN void not_found_error(TKey key) {
+            std::stringstream s;
+            s << "id " << key << " no found";
+            throw not_found(s.str());
+        }
+
+        /**
+         * Some of the index classes need an "empty" value that can
+         * never appear in real data. This function must return this
+         * empty value for any class used as a value in an index.
+         * The default implementation returns a default constructed
+         * object, but it can be specialized.
+         */
+        template <typename T>
+        inline constexpr T empty_value() {
+            return T{};
+        }
+
+        /**
+         * The size_t value in indexes is usually used for offsets
+         * into a buffer or file. It is unlikely that we ever need
+         * the full range, so the max value is a good "empty" value.
+         */
+        template <>
+        inline OSMIUM_CONSTEXPR size_t empty_value<size_t>() {
+            return std::numeric_limits<size_t>::max();
+        }
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_INDEX_HPP
diff --git a/third_party/osmium/index/map.hpp b/third_party/osmium/index/map.hpp
new file mode 100644
index 0000000..92b880f
--- /dev/null
+++ b/third_party/osmium/index/map.hpp
@@ -0,0 +1,155 @@
+#ifndef OSMIUM_INDEX_MAP_HPP
+#define OSMIUM_INDEX_MAP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <type_traits>
+
+#include <osmium/index/index.hpp> // IWYU pragma: export
+
+namespace osmium {
+
+    namespace index {
+
+        /**
+         * @brief Key-value containers with unique integer values for a key
+         */
+        namespace map {
+
+            /**
+             * This abstract class defines an interface to storage classes
+             * intended for storing small pieces of data (such as coordinates)
+             * indexed by a positive integer (such as an object ID). The
+             * storage must be very space efficient and able to scale to billions
+             * of objects.
+             *
+             * Subclasses have different implementations that store the
+             * data in different ways in memory and/or on disk. Some storage
+             * classes are better suited when working with the whole planet,
+             * some are better for data extracts.
+             *
+             * Note that these classes are not required to track "empty" fields.
+             * When reading data you have to be sure you have put something in
+             * there before.
+             *
+             * A typical use for this and derived classes is storage of node
+             * locations indexed by node ID. These indexes will only work
+             * on 64 bit systems if used in this case. 32 bit systems just
+             * can't address that much memory!
+             *
+             * @tparam TId Id type, usually osmium::unsigned_object_id_type,
+             *             must be an unsigned integral type.
+             * @tparam TValue Value type, usually osmium::Location or size_t.
+             *                Copied by value, so should be "small" type.
+             */
+            template <typename TId, typename TValue>
+            class Map {
+
+                static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value,
+                              "TId template parameter for class Map must be unsigned integral type");
+
+                Map(const Map&) = delete;
+                Map& operator=(const Map&) = delete;
+
+            protected:
+
+                Map(Map&&) = default;
+                Map& operator=(Map&&) = default;
+
+            public:
+
+                /// The "key" type, usually osmium::unsigned_object_id_type.
+                typedef TId key_type;
+
+                /// The "value" type, usually a Location or size_t.
+                typedef TValue value_type;
+
+                Map() = default;
+
+                virtual ~Map() = default;
+
+                virtual void reserve(const size_t) {
+                    // default implementation is empty
+                }
+
+                /// Set the field with id to value.
+                virtual void set(const TId id, const TValue value) = 0;
+
+                /// Retrieve value by id. Does not check for overflow or empty fields.
+                virtual const TValue get(const TId id) const = 0;
+
+                /**
+                 * Get the approximate number of items in the storage. The storage
+                 * might allocate memory in blocks, so this size might not be
+                 * accurate. You can not use this to find out how much memory the
+                 * storage uses. Use used_memory() for that.
+                 */
+                virtual size_t size() const = 0;
+
+                /**
+                 * Get the memory used for this storage in bytes. Note that this
+                 * is not necessarily entirely accurate but an approximation.
+                 * For storage classes that store the data in memory, this is
+                 * the main memory used, for storage classes storing data on disk
+                 * this is the memory used on disk.
+                 */
+                virtual size_t used_memory() const = 0;
+
+                /**
+                 * Clear memory used for this storage. After this you can not
+                 * use the storage container any more.
+                 */
+                virtual void clear() = 0;
+
+                /**
+                 * Sort data in map. Call this after writing all data and
+                 * before reading. Not all implementations need this.
+                 */
+                virtual void sort() {
+                    // default implementation is empty
+                }
+
+                virtual void dump_as_list(int /*fd*/) const {
+                    std::runtime_error("can't dump as list");
+                }
+
+            }; // class Map
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_HPP
diff --git a/third_party/osmium/index/map/dummy.hpp b/third_party/osmium/index/map/dummy.hpp
new file mode 100644
index 0000000..bafb810
--- /dev/null
+++ b/third_party/osmium/index/map/dummy.hpp
@@ -0,0 +1,87 @@
+#ifndef OSMIUM_INDEX_MAP_DUMMY_HPP
+#define OSMIUM_INDEX_MAP_DUMMY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+
+#include <osmium/index/map.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            /**
+             * Pseudo map.
+             * Use this class if you don't need a map, but you
+             * need an object that behaves like one.
+             */
+            template <typename TId, typename TValue>
+            class Dummy : public osmium::index::map::Map<TId, TValue> {
+
+            public:
+
+                Dummy() = default;
+
+                ~Dummy() override final = default;
+
+                void set(const TId, const TValue) override final {
+                    // intentionally left blank
+                }
+
+                const TValue get(const TId id) const override final {
+                    not_found_error(id);
+                }
+
+                size_t size() const override final {
+                    return 0;
+                }
+
+                size_t used_memory() const override final {
+                    return 0;
+                }
+
+                void clear() override final {
+                }
+
+            }; // class Dummy
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_DUMMY_HPP
diff --git a/third_party/osmium/index/map/mmap_vector_anon.hpp b/third_party/osmium/index/map/mmap_vector_anon.hpp
new file mode 100644
index 0000000..a62e99a
--- /dev/null
+++ b/third_party/osmium/index/map/mmap_vector_anon.hpp
@@ -0,0 +1,61 @@
+#ifndef OSMIUM_INDEX_MAP_MMAP_VECTOR_ANON_HPP
+#define OSMIUM_INDEX_MAP_MMAP_VECTOR_ANON_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#ifdef __linux__
+
+#include <osmium/index/map/vector.hpp>
+#include <osmium/index/detail/mmap_vector_anon.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            template <typename TId, typename TValue>
+            using DenseMapMmap = VectorBasedDenseMap<osmium::detail::mmap_vector_anon<TValue>, TId, TValue>;
+
+            template <typename TId, typename TValue>
+            using SparseMapMmap = VectorBasedSparseMap<TId, TValue, osmium::detail::mmap_vector_anon>;
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // __linux__
+
+#endif // OSMIUM_INDEX_MAP_MMAP_VECTOR_ANON_HPP
diff --git a/third_party/osmium/index/map/mmap_vector_file.hpp b/third_party/osmium/index/map/mmap_vector_file.hpp
new file mode 100644
index 0000000..7ea76fa
--- /dev/null
+++ b/third_party/osmium/index/map/mmap_vector_file.hpp
@@ -0,0 +1,57 @@
+#ifndef OSMIUM_INDEX_MAP_MMAP_VECTOR_FILE_HPP
+#define OSMIUM_INDEX_MAP_MMAP_VECTOR_FILE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/index/map/vector.hpp>
+#include <osmium/index/detail/mmap_vector_file.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            template <typename TId, typename TValue>
+            using DenseMapFile = VectorBasedDenseMap<osmium::detail::mmap_vector_file<TValue>, TId, TValue>;
+
+            template <typename TId, typename TValue>
+            using SparseMapFile = VectorBasedSparseMap<TId, TValue, osmium::detail::mmap_vector_file>;
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_MMAP_VECTOR_FILE_HPP
diff --git a/third_party/osmium/index/map/sparse_table.hpp b/third_party/osmium/index/map/sparse_table.hpp
new file mode 100644
index 0000000..704e33e
--- /dev/null
+++ b/third_party/osmium/index/map/sparse_table.hpp
@@ -0,0 +1,140 @@
+#ifndef OSMIUM_INDEX_MAP_SPARSE_TABLE_HPP
+#define OSMIUM_INDEX_MAP_SPARSE_TABLE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <stdexcept>
+#include <utility>
+#include <vector>
+
+#include <google/sparsetable>
+
+#include <osmium/index/map.hpp>
+#include <osmium/io/detail/read_write.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            /**
+            * The SparseTable index stores elements in a Google sparsetable,
+            * a data structure that can hold sparsly filled tables in a
+            * very space efficient way. It will resize automatically.
+            *
+            * Use this index if the ID space is only sparsly
+            * populated, such as when working with smaller OSM files (like
+            * country extracts).
+            *
+            * This will only work on 64 bit machines.
+            */
+            template <typename TId, typename TValue>
+            class SparseTable : public osmium::index::map::Map<TId, TValue> {
+
+                TId m_grow_size;
+
+                google::sparsetable<TValue> m_elements;
+
+                static_assert(sizeof(typename google::sparsetable<TValue>::size_type) >= 8, "google::sparsetable needs 64bit machine");
+
+            public:
+
+                /**
+                * Constructor.
+                *
+                * @param grow_size The initial size of the index (ie number of
+                *                  elements that fit into the index).
+                *                  The storage will grow by at least this size
+                *                  every time it runs out of space.
+                */
+                explicit SparseTable(const TId grow_size=10000) :
+                    m_grow_size(grow_size),
+                    m_elements(grow_size) {
+                }
+
+                ~SparseTable() override final = default;
+
+                void set(const TId id, const TValue value) override final {
+                    if (id >= m_elements.size()) {
+                        m_elements.resize(id + m_grow_size);
+                    }
+                    m_elements[id] = value;
+                }
+
+                const TValue get(const TId id) const override final {
+                    if (id >= m_elements.size()) {
+                        not_found_error(id);
+                    }
+                    if (m_elements[id] == osmium::index::empty_value<TValue>()) {
+                        not_found_error(id);
+                    }
+                    return m_elements[id];
+                }
+
+                size_t size() const override final {
+                    return m_elements.size();
+                }
+
+                size_t used_memory() const override final {
+                    // unused elements use 1 bit, used elements sizeof(TValue) bytes
+                    // http://google-sparsehash.googlecode.com/svn/trunk/doc/sparsetable.html
+                    return (m_elements.size() / 8) + (m_elements.num_nonempty() * sizeof(TValue));
+                }
+
+                void clear() override final {
+                    m_elements.clear();
+                }
+
+                void dump_as_list(const int fd) const override final {
+                    std::vector<std::pair<TId, TValue>> v;
+                    int n=0;
+                    for (const TValue value : m_elements) {
+                        if (value != osmium::index::empty_value<TValue>()) {
+                            v.emplace_back(n, value);
+                        }
+                        ++n;
+                    }
+                    osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(std::pair<TId, TValue>) * v.size());
+                }
+
+            }; // class SparseTable
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_BYID_SPARSE_TABLE_HPP
diff --git a/third_party/osmium/index/map/stl_map.hpp b/third_party/osmium/index/map/stl_map.hpp
new file mode 100644
index 0000000..d2781a7
--- /dev/null
+++ b/third_party/osmium/index/map/stl_map.hpp
@@ -0,0 +1,112 @@
+#ifndef OSMIUM_INDEX_MAP_STL_MAP_HPP
+#define OSMIUM_INDEX_MAP_STL_MAP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstddef>
+#include <iterator>
+#include <map>
+#include <stdexcept>
+#include <vector>
+
+#include <osmium/index/map.hpp>
+#include <osmium/io/detail/read_write.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            /**
+             * This implementation uses std::map internally. It uses rather a
+             * lot of memory, but might make sense for small maps.
+             */
+            template <typename TId, typename TValue>
+            class StlMap : public osmium::index::map::Map<TId, TValue> {
+
+                // This is a rough estimate for the memory needed for each
+                // element in the map (id + value + pointers to left, right,
+                // and parent plus some overhead for color of red-black-tree
+                // or similar).
+                static constexpr size_t element_size = sizeof(TId) + sizeof(TValue) + sizeof(void*) * 4;
+
+                std::map<TId, TValue> m_elements;
+
+            public:
+
+                StlMap() = default;
+
+                ~StlMap() override final = default;
+
+                void set(const TId id, const TValue value) override final {
+                    m_elements[id] = value;
+                }
+
+                const TValue get(const TId id) const override final {
+                    try {
+                        return m_elements.at(id);
+                    } catch (std::out_of_range&) {
+                        not_found_error(id);
+                    }
+                }
+
+                size_t size() const override final {
+                    return m_elements.size();
+                }
+
+                size_t used_memory() const override final {
+                    return element_size * m_elements.size();
+                }
+
+                void clear() override final {
+                    m_elements.clear();
+                }
+
+                void dump_as_list(const int fd) const override final {
+                    typedef typename std::map<TId, TValue>::value_type t;
+                    std::vector<t> v;
+                    std::copy(m_elements.begin(), m_elements.end(), std::back_inserter(v));
+                    osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(t) * v.size());
+                }
+
+            }; // class StlMap
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_STL_MAP_HPP
diff --git a/third_party/osmium/index/map/stl_vector.hpp b/third_party/osmium/index/map/stl_vector.hpp
new file mode 100644
index 0000000..238e9af
--- /dev/null
+++ b/third_party/osmium/index/map/stl_vector.hpp
@@ -0,0 +1,61 @@
+#ifndef OSMIUM_INDEX_MAP_STL_VECTOR_HPP
+#define OSMIUM_INDEX_MAP_STL_VECTOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <vector>
+
+#include <osmium/index/map/vector.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            template <typename TId, typename TValue>
+            using DenseMapMem = VectorBasedDenseMap<std::vector<TValue>, TId, TValue>;
+
+            template <typename T>
+            using StdVectorWrap = std::vector<T>;
+
+            template <typename TId, typename TValue>
+            using SparseMapMem = VectorBasedSparseMap<TId, TValue, StdVectorWrap>;
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_STL_VECTOR_HPP
diff --git a/third_party/osmium/index/map/vector.hpp b/third_party/osmium/index/map/vector.hpp
new file mode 100644
index 0000000..7e47ccf
--- /dev/null
+++ b/third_party/osmium/index/map/vector.hpp
@@ -0,0 +1,208 @@
+#ifndef OSMIUM_INDEX_MAP_VECTOR_HPP
+#define OSMIUM_INDEX_MAP_VECTOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstddef>
+#include <stdexcept>
+#include <utility>
+
+#include <osmium/index/map.hpp>
+#include <osmium/io/detail/read_write.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            template <class TVector, typename TId, typename TValue>
+            class VectorBasedDenseMap : public Map<TId, TValue> {
+
+                TVector m_vector;
+
+            public:
+
+                VectorBasedDenseMap() :
+                    m_vector() {
+                }
+
+                explicit VectorBasedDenseMap(int fd) :
+                    m_vector(fd) {
+                }
+
+                ~VectorBasedDenseMap() {}
+
+                void reserve(const size_t size) override final {
+                    m_vector.reserve(size);
+                }
+
+                void set(const TId id, const TValue value) override final {
+                    if (size() <= id) {
+                        m_vector.resize(id+1);
+                    }
+                    m_vector[id] = value;
+                }
+
+                const TValue get(const TId id) const override final {
+                    try {
+                        const TValue& value = m_vector.at(id);
+                        if (value == osmium::index::empty_value<TValue>()) {
+                            not_found_error(id);
+                        }
+                        return value;
+                    } catch (std::out_of_range&) {
+                        not_found_error(id);
+                    }
+                }
+
+                size_t size() const override final {
+                    return m_vector.size();
+                }
+
+                size_t used_memory() const override final {
+                    return sizeof(TValue) * size();
+                }
+
+                void clear() override final {
+                    m_vector.clear();
+                    m_vector.shrink_to_fit();
+                }
+
+            }; // class VectorBasedDenseMap
+
+
+            template <typename TId, typename TValue, template<typename...> class TVector>
+            class VectorBasedSparseMap : public Map<TId, TValue> {
+
+            public:
+
+                typedef typename std::pair<TId, TValue> element_type;
+                typedef TVector<element_type> vector_type;
+                typedef typename vector_type::iterator iterator;
+                typedef typename vector_type::const_iterator const_iterator;
+
+            private:
+
+                vector_type m_vector;
+
+            public:
+
+                VectorBasedSparseMap() :
+                    m_vector() {
+                }
+
+                VectorBasedSparseMap(int fd) :
+                    m_vector(fd) {
+                }
+
+                ~VectorBasedSparseMap() override final = default;
+
+                void set(const TId id, const TValue value) override final {
+                    m_vector.push_back(element_type(id, value));
+                }
+
+                const TValue get(const TId id) const override final {
+                    const element_type element {
+                        id,
+                        osmium::index::empty_value<TValue>()
+                    };
+                    const auto result = std::lower_bound(m_vector.begin(), m_vector.end(), element, [](const element_type& a, const element_type& b) {
+                        return a.first < b.first;
+                    });
+                    if (result == m_vector.end() || result->first != id) {
+                        not_found_error(id);
+                    } else {
+                        return result->second;
+                    }
+                }
+
+                size_t size() const override final {
+                    return m_vector.size();
+                }
+
+                size_t byte_size() const {
+                    return m_vector.size() * sizeof(element_type);
+                }
+
+                size_t used_memory() const override final {
+                    return sizeof(element_type) * size();
+                }
+
+                void clear() override final {
+                    m_vector.clear();
+                    m_vector.shrink_to_fit();
+                }
+
+                void sort() override final {
+                    std::sort(m_vector.begin(), m_vector.end());
+                }
+
+                void dump_as_list(int fd) const override final {
+                    osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size());
+                }
+
+                iterator begin() {
+                    return m_vector.begin();
+                }
+
+                iterator end() {
+                    return m_vector.end();
+                }
+
+                const_iterator cbegin() const {
+                    return m_vector.cbegin();
+                }
+
+                const_iterator cend() const {
+                    return m_vector.cend();
+                }
+
+                const_iterator begin() const {
+                    return m_vector.cbegin();
+                }
+
+                const_iterator end() const {
+                    return m_vector.cend();
+                }
+
+            }; // class VectorBasedSparseMap
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_VECTOR_HPP
diff --git a/third_party/osmium/index/multimap.hpp b/third_party/osmium/index/multimap.hpp
new file mode 100644
index 0000000..f76c65d
--- /dev/null
+++ b/third_party/osmium/index/multimap.hpp
@@ -0,0 +1,129 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_HPP
+#define OSMIUM_INDEX_MULTIMAP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <type_traits>
+#include <utility>
+
+#include <osmium/index/index.hpp> // IWYU pragma: export
+
+namespace osmium {
+
+    namespace index {
+
+        /**
+         * @brief Key-value containers with multiple values for an integer key
+         */
+        namespace multimap {
+
+            template <typename TId, typename TValue>
+            class Multimap {
+
+                static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value,
+                              "TId template parameter for class Multimap must be unsigned integral type");
+
+                typedef typename std::pair<TId, TValue> element_type;
+
+                Multimap(const Multimap&) = delete;
+                Multimap& operator=(const Multimap&) = delete;
+
+            protected:
+
+                Multimap(Multimap&&) = default;
+                Multimap& operator=(Multimap&&) = default;
+
+            public:
+
+                /// The "key" type, usually osmium::unsigned_object_id_type.
+                typedef TId key_type;
+
+                /// The "value" type, usually a Location or size_t.
+                typedef TValue value_type;
+
+                Multimap() = default;
+
+                virtual ~Multimap() noexcept = default;
+
+                /// Set the field with id to value.
+                virtual void set(const TId id, const TValue value) = 0;
+
+                typedef element_type* iterator;
+
+//                virtual std::pair<iterator, iterator> get_all(const TId id) const = 0;
+
+                /**
+                 * Get the approximate number of items in the storage. The storage
+                 * might allocate memory in blocks, so this size might not be
+                 * accurate. You can not use this to find out how much memory the
+                 * storage uses. Use used_memory() for that.
+                 */
+                virtual size_t size() const = 0;
+
+                /**
+                 * Get the memory used for this storage in bytes. Note that this
+                 * is not necessarily entirely accurate but an approximation.
+                 * For storage classes that store the data in memory, this is
+                 * the main memory used, for storage classes storing data on disk
+                 * this is the memory used on disk.
+                 */
+                virtual size_t used_memory() const = 0;
+
+                /**
+                 * Clear memory used for this storage. After this you can not
+                 * use the storage container any more.
+                 */
+                virtual void clear() = 0;
+
+                /**
+                 * Sort data in map. Call this after writing all data and
+                 * before reading. Not all implementations need this.
+                 */
+                virtual void sort() {
+                    // default implementation is empty
+                }
+
+                virtual void dump_as_list(int /*fd*/) const {
+                    std::runtime_error("can't dump as list");
+                }
+
+            }; // class Multimap
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_HPP
diff --git a/third_party/osmium/index/multimap/hybrid.hpp b/third_party/osmium/index/multimap/hybrid.hpp
new file mode 100644
index 0000000..abaf31e
--- /dev/null
+++ b/third_party/osmium/index/multimap/hybrid.hpp
@@ -0,0 +1,199 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_HYBRID_HPP
+#define OSMIUM_INDEX_MULTIMAP_HYBRID_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <utility>
+
+#include <osmium/index/multimap.hpp>
+#include <osmium/index/multimap/stl_vector.hpp>
+#include <osmium/index/multimap/stl_multimap.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace multimap {
+
+            template <typename TId, typename TValue>
+            class HybridIterator {
+
+                typedef SparseMultimapMem<TId, TValue> main_map_type;
+                typedef StlMultimap<TId, TValue> extra_map_type;
+
+                typedef typename std::pair<TId, TValue> element_type;
+
+                typename main_map_type::iterator m_begin_main;
+                typename main_map_type::iterator m_end_main;
+                typename extra_map_type::iterator m_begin_extra;
+                typename extra_map_type::iterator m_end_extra;
+
+            public:
+
+                explicit HybridIterator(typename main_map_type::iterator begin_main,
+                               typename main_map_type::iterator end_main,
+                               typename extra_map_type::iterator begin_extra,
+                               typename extra_map_type::iterator end_extra) :
+                    m_begin_main(begin_main),
+                    m_end_main(end_main),
+                    m_begin_extra(begin_extra),
+                    m_end_extra(end_extra) {
+                }
+
+                HybridIterator& operator++() {
+                    if (m_begin_main == m_end_main) {
+                        ++m_begin_extra;
+                    } else {
+                        ++m_begin_main;
+                        while (m_begin_main != m_end_main && m_begin_main->second == osmium::index::empty_value<TValue>()) { // ignore removed elements
+                            ++m_begin_main;
+                        }
+                    }
+                    return *this;
+                }
+
+                HybridIterator<TId, TValue> operator++(int) {
+                    auto tmp(*this);
+                    operator++();
+                    return tmp;
+                }
+
+                bool operator==(const HybridIterator& rhs) const {
+                    return m_begin_main == rhs.m_begin_main &&
+                           m_end_main   == rhs.m_end_main &&
+                           m_begin_extra == rhs.m_begin_extra &&
+                           m_end_extra   == rhs.m_end_extra;
+                }
+
+                bool operator!=(const HybridIterator& rhs) const {
+                    return ! operator==(rhs);
+                }
+
+                const element_type& operator*() {
+                    if (m_begin_main == m_end_main) {
+                        return *m_begin_extra;
+                    } else {
+                        return *m_begin_main;
+                    }
+                }
+
+                const element_type* operator->() {
+                    return &operator*();
+                }
+
+            }; // class HybridIterator
+
+            template <typename TId, typename TValue>
+            class Hybrid : public Multimap<TId, TValue> {
+
+                typedef SparseMultimapMem<TId, TValue> main_map_type;
+                typedef StlMultimap<TId, TValue> extra_map_type;
+
+                main_map_type m_main;
+                extra_map_type m_extra;
+
+            public:
+
+                typedef HybridIterator<TId, TValue> iterator;
+                typedef const HybridIterator<TId, TValue> const_iterator;
+
+                Hybrid() :
+                    m_main(),
+                    m_extra() {
+                }
+
+                size_t size() const override final {
+                    return m_main.size() + m_extra.size();
+                }
+
+                size_t used_memory() const override final {
+                    return m_main.used_memory() + m_extra.used_memory();
+                }
+
+                void reserve(const size_t size) {
+                    m_main.reserve(size);
+                }
+
+                void unsorted_set(const TId id, const TValue value) {
+                    m_main.set(id, value);
+                }
+
+                void set(const TId id, const TValue value) override final {
+                    m_extra.set(id, value);
+                }
+
+                std::pair<iterator, iterator> get_all(const TId id) {
+                    auto result_main = m_main.get_all(id);
+                    auto result_extra = m_extra.get_all(id);
+                    return std::make_pair(iterator(result_main.first, result_main.second, result_extra.first, result_extra.second),
+                                          iterator(result_main.second, result_main.second, result_extra.second, result_extra.second));
+                }
+
+                void remove(const TId id, const TValue value) {
+                    m_main.remove(id, value);
+                    m_extra.remove(id, value);
+                }
+
+                void consolidate() {
+                    m_main.erase_removed();
+                    for (const auto& element : m_extra) {
+                        m_main.set(element.first, element.second);
+                    }
+                    m_extra.clear();
+                    m_main.sort();
+                }
+
+                void dump_as_list(int fd) override final {
+                    consolidate();
+                    m_main.dump_as_list(fd);
+                }
+
+                void clear() override final {
+                    m_main.clear();
+                    m_extra.clear();
+                }
+
+                void sort() override final {
+                    m_main.sort();
+                }
+
+            }; // class Hybrid
+
+        } // namespace multimap
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_HYBRID_HPP
diff --git a/third_party/osmium/index/multimap/mmap_vector_anon.hpp b/third_party/osmium/index/multimap/mmap_vector_anon.hpp
new file mode 100644
index 0000000..b9de34a
--- /dev/null
+++ b/third_party/osmium/index/multimap/mmap_vector_anon.hpp
@@ -0,0 +1,58 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_MMAP_VECTOR_ANON_HPP
+#define OSMIUM_INDEX_MULTIMAP_MMAP_VECTOR_ANON_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#ifdef __linux__
+
+#include <osmium/index/multimap/vector.hpp>
+#include <osmium/index/detail/mmap_vector_anon.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace multimap {
+
+            template <typename TId, typename TValue>
+            using SparseMultimapMmap = VectorBasedSparseMultimap<TId, TValue, osmium::detail::mmap_vector_anon>;
+
+        } // namespace multimap
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // __linux__
+
+#endif // OSMIUM_INDEX_MULTIMAP_MMAP_VECTOR_ANON_HPP
diff --git a/third_party/osmium/index/multimap/mmap_vector_file.hpp b/third_party/osmium/index/multimap/mmap_vector_file.hpp
new file mode 100644
index 0000000..0a925b4
--- /dev/null
+++ b/third_party/osmium/index/multimap/mmap_vector_file.hpp
@@ -0,0 +1,54 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_MMAP_VECTOR_FILE_HPP
+#define OSMIUM_INDEX_MULTIMAP_MMAP_VECTOR_FILE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/index/multimap/vector.hpp>
+#include <osmium/index/detail/mmap_vector_file.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace multimap {
+
+            template <typename TId, typename TValue>
+            using SparseMultimapFile = VectorBasedSparseMultimap<TId, TValue, osmium::detail::mmap_vector_file>;
+
+        } // namespace multimap
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_MMAP_VECTOR_FILE_HPP
diff --git a/third_party/osmium/index/multimap/stl_multimap.hpp b/third_party/osmium/index/multimap/stl_multimap.hpp
new file mode 100644
index 0000000..3df07ab
--- /dev/null
+++ b/third_party/osmium/index/multimap/stl_multimap.hpp
@@ -0,0 +1,151 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_STL_MULTIMAP_HPP
+#define OSMIUM_INDEX_MULTIMAP_STL_MULTIMAP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstddef>
+#include <map>
+#include <utility>
+#include <vector>
+
+#include <osmium/index/multimap.hpp>
+#include <osmium/io/detail/read_write.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace multimap {
+
+            /**
+             * This implementation uses std::multimap internally. It uses rather a
+             * lot of memory, but might make sense for small maps.
+             */
+            template <typename TId, typename TValue>
+            class StlMultimap : public osmium::index::multimap::Multimap<TId, TValue> {
+
+                // This is a rough estimate for the memory needed for each
+                // element in the map (id + value + pointers to left, right,
+                // and parent plus some overhead for color of red-black-tree
+                // or similar).
+                static constexpr size_t element_size = sizeof(TId) + sizeof(TValue) + sizeof(void*) * 4;
+
+            public:
+
+                typedef typename std::multimap<const TId, TValue> collection_type;
+                typedef typename collection_type::iterator iterator;
+                typedef typename collection_type::const_iterator const_iterator;
+                typedef typename collection_type::value_type value_type;
+
+                typedef typename std::pair<TId, TValue> element_type;
+
+            private:
+
+                collection_type m_elements;
+
+            public:
+
+                StlMultimap() = default;
+
+                ~StlMultimap() noexcept override final = default;
+
+                void unsorted_set(const TId id, const TValue value) {
+                    m_elements.emplace(id, value);
+                }
+
+                void set(const TId id, const TValue value) override final {
+                    m_elements.emplace(id, value);
+                }
+
+                std::pair<iterator, iterator> get_all(const TId id) {
+                    return m_elements.equal_range(id);
+                }
+
+                std::pair<const_iterator, const_iterator> get_all(const TId id) const {
+                    return m_elements.equal_range(id);
+                }
+
+                void remove(const TId id, const TValue value) {
+                    std::pair<iterator, iterator> r = get_all(id);
+                    for (iterator it = r.first; it != r.second; ++it) {
+                        if (it->second == value) {
+                            m_elements.erase(it);
+                            return;
+                        }
+                    }
+                }
+
+                iterator begin() {
+                    return m_elements.begin();
+                }
+
+                iterator end() {
+                    return m_elements.end();
+                }
+
+                size_t size() const override final {
+                    return m_elements.size();
+                }
+
+                size_t used_memory() const override final {
+                    return element_size * m_elements.size();
+                }
+
+                void clear() override final {
+                    m_elements.clear();
+                }
+
+                void consolidate() {
+                    // intentionally left blank
+                }
+
+                void dump_as_list(const int fd) const override final {
+                    std::vector<element_type> v;
+                    for (const auto& element : m_elements) {
+                        v.emplace_back(element.first, element.second);
+                    }
+//                    std::copy(m_elements.cbegin(), m_elements.cend(), std::back_inserter(v));
+                    std::sort(v.begin(), v.end());
+                    osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(element_type) * v.size());
+                }
+
+            }; // class StlMultimap
+
+        } // namespace multimap
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_STL_MULTIMAP_HPP
diff --git a/third_party/osmium/index/multimap/stl_vector.hpp b/third_party/osmium/index/multimap/stl_vector.hpp
new file mode 100644
index 0000000..2102824
--- /dev/null
+++ b/third_party/osmium/index/multimap/stl_vector.hpp
@@ -0,0 +1,58 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_STL_VECTOR_HPP
+#define OSMIUM_INDEX_MULTIMAP_STL_VECTOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <vector>
+
+#include <osmium/index/multimap/vector.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace multimap {
+
+            template <typename T>
+            using StdVectorWrap = std::vector<T>;
+
+            template <typename TId, typename TValue>
+            using SparseMultimapMem = VectorBasedSparseMultimap<TId, TValue, StdVectorWrap>;
+
+        } // namespace multimap
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_STL_VECTOR_HPP
diff --git a/third_party/osmium/index/multimap/vector.hpp b/third_party/osmium/index/multimap/vector.hpp
new file mode 100644
index 0000000..b9dae43
--- /dev/null
+++ b/third_party/osmium/index/multimap/vector.hpp
@@ -0,0 +1,151 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_VECTOR_HPP
+#define OSMIUM_INDEX_MULTIMAP_VECTOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstddef>
+#include <utility>
+
+#include <osmium/index/multimap.hpp>
+#include <osmium/io/detail/read_write.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace multimap {
+
+            template <typename TId, typename TValue, template<typename...> class TVector>
+            class VectorBasedSparseMultimap : public Multimap<TId, TValue> {
+
+            public:
+
+                typedef typename std::pair<TId, TValue> element_type;
+                typedef TVector<element_type> vector_type;
+                typedef typename vector_type::iterator iterator;
+                typedef typename vector_type::const_iterator const_iterator;
+
+            private:
+
+                vector_type m_vector;
+
+                static bool is_removed(element_type& element) {
+                    return element.second == osmium::index::empty_value<TValue>();
+                }
+
+            public:
+
+                void set(const TId id, const TValue value) override final {
+                    m_vector.push_back(element_type(id, value));
+                }
+
+                void unsorted_set(const TId id, const TValue value) {
+                    m_vector.push_back(element_type(id, value));
+                }
+
+                std::pair<iterator, iterator> get_all(const TId id) {
+                    const element_type element {
+                        id,
+                        osmium::index::empty_value<TValue>()
+                    };
+                    return std::equal_range(m_vector.begin(), m_vector.end(), element, [](const element_type& a, const element_type& b) {
+                        return a.first < b.first;
+                    });
+                }
+
+                std::pair<const_iterator, const_iterator> get_all(const TId id) const {
+                    const element_type element {
+                        id,
+                        osmium::index::empty_value<TValue>()
+                    };
+                    return std::equal_range(m_vector.cbegin(), m_vector.cend(), element, [](const element_type& a, const element_type& b) {
+                        return a.first < b.first;
+                    });
+                }
+
+                size_t size() const override final {
+                    return m_vector.size();
+                }
+
+                size_t byte_size() const {
+                    return m_vector.size() * sizeof(element_type);
+                }
+
+                size_t used_memory() const override final {
+                    return sizeof(element_type) * size();
+                }
+
+                void clear() override final {
+                    m_vector.clear();
+                    m_vector.shrink_to_fit();
+                }
+
+                void sort() override final {
+                    std::sort(m_vector.begin(), m_vector.end());
+                }
+
+                void remove(const TId id, const TValue value) {
+                    auto r = get_all(id);
+                    for (auto it = r.first; it != r.second; ++it) {
+                        if (it->second == value) {
+                            it->second = 0;
+                            return;
+                        }
+                    }
+                }
+
+                void consolidate() {
+                    std::sort(m_vector.begin(), m_vector.end());
+                }
+
+                void erase_removed() {
+                    m_vector.erase(
+                        std::remove_if(m_vector.begin(), m_vector.end(), is_removed),
+                        m_vector.end()
+                    );
+                }
+
+                void dump_as_list(int fd) const override final {
+                    osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size());
+                }
+
+            }; // class VectorBasedSparseMultimap
+
+        } // namespace multimap
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_VECTOR_HPP
diff --git a/third_party/osmium/io/any_compression.hpp b/third_party/osmium/io/any_compression.hpp
new file mode 100644
index 0000000..03ad5ce
--- /dev/null
+++ b/third_party/osmium/io/any_compression.hpp
@@ -0,0 +1,39 @@
+#ifndef OSMIUM_IO_ANY_COMPRESSION_HPP
+#define OSMIUM_IO_ANY_COMPRESSION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/io/bzip2_compression.hpp> // IWYU pragma: export
+#include <osmium/io/gzip_compression.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_ANY_COMPRESSION_HPP
diff --git a/third_party/osmium/io/any_input.hpp b/third_party/osmium/io/any_input.hpp
new file mode 100644
index 0000000..f60ff14
--- /dev/null
+++ b/third_party/osmium/io/any_input.hpp
@@ -0,0 +1,41 @@
+#ifndef OSMIUM_IO_ANY_INPUT_HPP
+#define OSMIUM_IO_ANY_INPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/io/any_compression.hpp> // IWYU pragma: export
+
+#include <osmium/io/pbf_input.hpp> // IWYU pragma: export
+#include <osmium/io/xml_input.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_ANY_INPUT_HPP
diff --git a/third_party/osmium/io/any_output.hpp b/third_party/osmium/io/any_output.hpp
new file mode 100644
index 0000000..9d97d7d
--- /dev/null
+++ b/third_party/osmium/io/any_output.hpp
@@ -0,0 +1,42 @@
+#ifndef OSMIUM_IO_ANY_OUTPUT_HPP
+#define OSMIUM_IO_ANY_OUTPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/io/any_compression.hpp> // IWYU pragma: export
+
+#include <osmium/io/opl_output.hpp> // IWYU pragma: export
+#include <osmium/io/pbf_output.hpp> // IWYU pragma: export
+#include <osmium/io/xml_output.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_ANY_OUTPUT_HPP
diff --git a/third_party/osmium/io/bzip2_compression.hpp b/third_party/osmium/io/bzip2_compression.hpp
new file mode 100644
index 0000000..cbfaf9a
--- /dev/null
+++ b/third_party/osmium/io/bzip2_compression.hpp
@@ -0,0 +1,277 @@
+#ifndef OSMIUM_IO_BZIP2_COMPRESSION_HPP
+#define OSMIUM_IO_BZIP2_COMPRESSION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#define OSMIUM_LINK_WITH_LIBS_BZ2LIB -lbz2
+
+#include <cstdio>
+#include <stdexcept>
+#include <string>
+
+#include <bzlib.h>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#endif
+
+#include <osmium/io/compression.hpp>
+#include <osmium/io/file_compression.hpp>
+#include <osmium/util/cast.hpp>
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+    /**
+     * Exception thrown when there are problems compressing or
+     * decompressing bzip2 files.
+     */
+    struct bzip2_error : public std::runtime_error {
+
+        int bzip2_error_code;
+        int system_errno;
+
+        bzip2_error(const std::string& what, int error_code) :
+            std::runtime_error(what),
+            bzip2_error_code(error_code),
+            system_errno(error_code == BZ_IO_ERROR ? errno : 0) {
+        }
+
+    }; // struct bzip2_error
+
+    namespace io {
+
+        namespace detail {
+
+            OSMIUM_NORETURN inline void throw_bzip2_error(BZFILE* bzfile, const char* msg, int bzlib_error=0) {
+                std::string error("bzip2 error: ");
+                error += msg;
+                error += ": ";
+                int errnum = bzlib_error;
+                if (bzlib_error) {
+                    error += std::to_string(bzlib_error);
+                } else {
+                    error += ::BZ2_bzerror(bzfile, &errnum);
+                }
+                throw osmium::bzip2_error(error, errnum);
+            }
+
+        } // namespace detail
+
+        class Bzip2Compressor : public Compressor {
+
+            FILE* m_file;
+            int m_bzerror;
+            BZFILE* m_bzfile;
+
+        public:
+
+            explicit Bzip2Compressor(int fd) :
+                Compressor(),
+                m_file(fdopen(dup(fd), "wb")),
+                m_bzerror(BZ_OK),
+                m_bzfile(::BZ2_bzWriteOpen(&m_bzerror, m_file, 6, 0, 0)) {
+                if (!m_bzfile) {
+                    detail::throw_bzip2_error(m_bzfile, "write open failed", m_bzerror);
+                }
+            }
+
+            ~Bzip2Compressor() override final {
+                close();
+            }
+
+            void write(const std::string& data) override final {
+                int error;
+                ::BZ2_bzWrite(&error, m_bzfile, const_cast<char*>(data.data()), static_cast_with_assert<int>(data.size()));
+                if (error != BZ_OK && error != BZ_STREAM_END) {
+                    detail::throw_bzip2_error(m_bzfile, "write failed", error);
+                }
+            }
+
+            void close() override final {
+                if (m_bzfile) {
+                    int error;
+                    ::BZ2_bzWriteClose(&error, m_bzfile, 0, nullptr, nullptr);
+                    m_bzfile = nullptr;
+                    if (m_file) {
+                        fclose(m_file);
+                    }
+                    if (error != BZ_OK) {
+                        detail::throw_bzip2_error(m_bzfile, "write close failed", error);
+                    }
+                }
+            }
+
+        }; // class Bzip2Compressor
+
+        class Bzip2Decompressor : public Decompressor {
+
+            FILE* m_file;
+            int m_bzerror;
+            BZFILE* m_bzfile;
+            bool m_stream_end {false};
+
+        public:
+
+            Bzip2Decompressor(int fd) :
+                Decompressor(),
+                m_file(fdopen(dup(fd), "rb")),
+                m_bzerror(BZ_OK),
+                m_bzfile(::BZ2_bzReadOpen(&m_bzerror, m_file, 0, 0, nullptr, 0)) {
+                if (!m_bzfile) {
+                    detail::throw_bzip2_error(m_bzfile, "read open failed", m_bzerror);
+                }
+            }
+
+            ~Bzip2Decompressor() override final {
+                close();
+            }
+
+            std::string read() override final {
+                if (m_stream_end) {
+                    return std::string();
+                }
+                std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0');
+                int error;
+                int nread = ::BZ2_bzRead(&error, m_bzfile, const_cast<char*>(buffer.data()), static_cast_with_assert<int>(buffer.size()));
+                if (error != BZ_OK && error != BZ_STREAM_END) {
+                    detail::throw_bzip2_error(m_bzfile, "read failed", error);
+                }
+                if (error == BZ_STREAM_END) {
+                    void* unused;
+                    int nunused;
+                    if (! feof(m_file)) {
+                        ::BZ2_bzReadGetUnused(&error, m_bzfile, &unused, &nunused);
+                        if (error != BZ_OK) {
+                            detail::throw_bzip2_error(m_bzfile, "get unused failed", error);
+                        }
+                        std::string unused_data(static_cast<const char*>(unused), static_cast<std::string::size_type>(nunused));
+                        ::BZ2_bzReadClose(&error, m_bzfile);
+                        if (error != BZ_OK) {
+                            detail::throw_bzip2_error(m_bzfile, "read close failed", error);
+                        }
+                        m_bzfile = ::BZ2_bzReadOpen(&error, m_file, 0, 0, const_cast<void*>(static_cast<const void*>(unused_data.data())), static_cast_with_assert<int>(unused_data.size()));
+                        if (error != BZ_OK) {
+                            detail::throw_bzip2_error(m_bzfile, "read open failed", error);
+                        }
+                    } else {
+                        m_stream_end = true;
+                    }
+                }
+                buffer.resize(static_cast<std::string::size_type>(nread));
+                return buffer;
+            }
+
+            void close() override final {
+                if (m_bzfile) {
+                    int error;
+                    ::BZ2_bzReadClose(&error, m_bzfile);
+                    m_bzfile = nullptr;
+                    if (m_file) {
+                        fclose(m_file);
+                    }
+                    if (error != BZ_OK) {
+                        detail::throw_bzip2_error(m_bzfile, "read close failed", error);
+                    }
+                }
+            }
+
+        }; // class Bzip2Decompressor
+
+        class Bzip2BufferDecompressor : public Decompressor {
+
+            const char* m_buffer;
+            size_t m_buffer_size;
+            bz_stream m_bzstream;
+
+        public:
+
+            Bzip2BufferDecompressor(const char* buffer, size_t size) :
+                m_buffer(buffer),
+                m_buffer_size(size),
+                m_bzstream() {
+                m_bzstream.next_in = const_cast<char*>(buffer);
+                m_bzstream.avail_in = static_cast_with_assert<unsigned int>(size);
+                int result = BZ2_bzDecompressInit(&m_bzstream, 0, 0);
+                if (result != BZ_OK) {
+                    std::string message("bzip2 error: decompression init failed: ");
+                    throw bzip2_error(message, result);
+                }
+            }
+
+            ~Bzip2BufferDecompressor() override final {
+                BZ2_bzDecompressEnd(&m_bzstream);
+            }
+
+            std::string read() override final {
+                if (!m_buffer) {
+                    return std::string();
+                }
+
+                const size_t buffer_size = 10240;
+                std::string output(buffer_size, '\0');
+                m_bzstream.next_out = const_cast<char*>(output.data());
+                m_bzstream.avail_out = buffer_size;
+                int result = BZ2_bzDecompress(&m_bzstream);
+
+                if (result != BZ_OK) {
+                    m_buffer = nullptr;
+                    m_buffer_size = 0;
+                }
+
+                if (result != BZ_OK && result != BZ_STREAM_END) {
+                    std::string message("bzip2 error: decompress failed: ");
+                    throw bzip2_error(message, result);
+                }
+
+                output.resize(static_cast<unsigned long>(m_bzstream.next_out - output.data()));
+                return output;
+            }
+
+        }; // class Bzip2BufferDecompressor
+
+        namespace {
+
+            const bool registered_bzip2_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::bzip2,
+                [](int fd) { return new osmium::io::Bzip2Compressor(fd); },
+                [](int fd) { return new osmium::io::Bzip2Decompressor(fd); },
+                [](const char* buffer, size_t size) { return new osmium::io::Bzip2BufferDecompressor(buffer, size); }
+            );
+
+        } // anonymous namespace
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_BZIP2_COMPRESSION_HPP
diff --git a/third_party/osmium/io/compression.hpp b/third_party/osmium/io/compression.hpp
new file mode 100644
index 0000000..5977640
--- /dev/null
+++ b/third_party/osmium/io/compression.hpp
@@ -0,0 +1,279 @@
+#ifndef OSMIUM_IO_COMPRESSION_HPP
+#define OSMIUM_IO_COMPRESSION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cerrno>
+#include <functional>
+#include <map>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <system_error>
+#include <utility>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#else
+# include <io.h>
+#endif
+
+#include <osmium/io/detail/read_write.hpp>
+#include <osmium/io/file_compression.hpp>
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        class Compressor {
+
+        public:
+
+            Compressor() = default;
+
+            virtual ~Compressor() {
+            }
+
+            virtual void write(const std::string& data) = 0;
+
+            virtual void close() = 0;
+
+        }; // class Compressor
+
+        class Decompressor {
+
+        public:
+
+            static constexpr size_t input_buffer_size = 256 * 1024;
+
+            Decompressor() = default;
+
+            Decompressor(const Decompressor&) = delete;
+            Decompressor& operator=(const Decompressor&) = delete;
+
+            Decompressor(Decompressor&&) = delete;
+            Decompressor& operator=(Decompressor&&) = delete;
+
+            virtual ~Decompressor() {
+            }
+
+            virtual std::string read() = 0;
+
+            virtual void close() {
+            }
+
+        }; // class Decompressor
+
+        /**
+         * This singleton factory class is used to register compression
+         * algorithms used for reading and writing OSM files.
+         *
+         * For each algorithm we store two functions that construct
+         * a compressor and decompressor object, respectively.
+         */
+        class CompressionFactory {
+
+        public:
+
+            typedef std::function<osmium::io::Compressor*(int)> create_compressor_type;
+            typedef std::function<osmium::io::Decompressor*(int)> create_decompressor_type_fd;
+            typedef std::function<osmium::io::Decompressor*(const char*, size_t)> create_decompressor_type_buffer;
+
+        private:
+
+            typedef std::map<const osmium::io::file_compression, std::tuple<create_compressor_type, create_decompressor_type_fd, create_decompressor_type_buffer>> compression_map_type;
+
+            compression_map_type m_callbacks;
+
+            CompressionFactory() = default;
+
+            CompressionFactory(const CompressionFactory&) = delete;
+            CompressionFactory& operator=(const CompressionFactory&) = delete;
+
+            CompressionFactory(CompressionFactory&&) = delete;
+            CompressionFactory& operator=(CompressionFactory&&) = delete;
+
+            OSMIUM_NORETURN void error(osmium::io::file_compression compression) {
+                std::string error_message {"Support for compression '"};
+                error_message += as_string(compression);
+                error_message += "' not compiled into this binary.";
+                throw std::runtime_error(error_message);
+            }
+
+        public:
+
+            static CompressionFactory& instance() {
+                static CompressionFactory factory;
+                return factory;
+            }
+
+            bool register_compression(
+                osmium::io::file_compression compression,
+                create_compressor_type create_compressor,
+                create_decompressor_type_fd create_decompressor_fd,
+                create_decompressor_type_buffer create_decompressor_buffer) {
+
+                compression_map_type::value_type cc(compression, std::make_tuple(create_compressor, create_decompressor_fd, create_decompressor_buffer));
+                return m_callbacks.insert(cc).second;
+            }
+
+            std::unique_ptr<osmium::io::Compressor> create_compressor(osmium::io::file_compression compression, int fd) {
+                auto it = m_callbacks.find(compression);
+
+                if (it != m_callbacks.end()) {
+                    return std::unique_ptr<osmium::io::Compressor>(std::get<0>(it->second)(fd));
+                }
+
+                error(compression);
+            }
+
+            std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, int fd) {
+                auto it = m_callbacks.find(compression);
+
+                if (it != m_callbacks.end()) {
+                    return std::unique_ptr<osmium::io::Decompressor>(std::get<1>(it->second)(fd));
+                }
+
+                error(compression);
+            }
+
+            std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, const char* buffer, size_t size) {
+                auto it = m_callbacks.find(compression);
+
+                if (it != m_callbacks.end()) {
+                    return std::unique_ptr<osmium::io::Decompressor>(std::get<2>(it->second)(buffer, size));
+                }
+
+                error(compression);
+            }
+
+        }; // class CompressionFactory
+
+        class NoCompressor : public Compressor {
+
+            int m_fd;
+
+        public:
+
+            NoCompressor(int fd) :
+                Compressor(),
+                m_fd(fd) {
+            }
+
+            ~NoCompressor() override final {
+                close();
+            }
+
+            void write(const std::string& data) override final {
+                osmium::io::detail::reliable_write(m_fd, data.data(), data.size());
+            }
+
+            void close() override final {
+                if (m_fd >= 0) {
+                    ::close(m_fd);
+                    m_fd = -1;
+                }
+            }
+
+        }; // class NoCompressor
+
+        class NoDecompressor : public Decompressor {
+
+            int m_fd;
+            const char *m_buffer;
+            size_t m_buffer_size;
+
+        public:
+
+            NoDecompressor(int fd) :
+                Decompressor(),
+                m_fd(fd),
+                m_buffer(nullptr),
+                m_buffer_size(0) {
+            }
+
+            NoDecompressor(const char* buffer, size_t size) :
+                Decompressor(),
+                m_fd(-1),
+                m_buffer(buffer),
+                m_buffer_size(size) {
+            }
+
+            ~NoDecompressor() override final {
+                close();
+            }
+
+            std::string read() override final {
+                if (m_buffer) {
+                    if (m_buffer_size == 0) {
+                        return std::string();
+                    }
+                    size_t size = m_buffer_size;
+                    m_buffer_size = 0;
+                    return std::string(m_buffer, size);
+                } else {
+                    std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0');
+                    ssize_t nread = ::read(m_fd, const_cast<char*>(buffer.data()), buffer.size());
+                    if (nread < 0) {
+                        throw std::system_error(errno, std::system_category(), "Read failed");
+                    }
+                    buffer.resize(static_cast<size_t>(nread));
+                    return buffer;
+                }
+            }
+
+            void close() override final {
+                if (m_fd >= 0) {
+                    ::close(m_fd);
+                    m_fd = -1;
+                }
+            }
+
+        }; // class NoDecompressor
+
+        namespace {
+
+            const bool registered_no_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::none,
+                [](int fd) { return new osmium::io::NoCompressor(fd); },
+                [](int fd) { return new osmium::io::NoDecompressor(fd); },
+                [](const char* buffer, size_t size) { return new osmium::io::NoDecompressor(buffer, size); }
+            );
+
+        } // anonymous namespace
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_COMPRESSION_HPP
diff --git a/third_party/osmium/io/detail/input_format.hpp b/third_party/osmium/io/detail/input_format.hpp
new file mode 100644
index 0000000..f88561b
--- /dev/null
+++ b/third_party/osmium/io/detail/input_format.hpp
@@ -0,0 +1,160 @@
+#ifndef OSMIUM_IO_DETAIL_INPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_INPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+#include <osmium/io/file.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/entity_bits.hpp>
+
+namespace osmium {
+
+    namespace thread {
+        template <typename T> class Queue;
+    } // namespace thread
+
+    namespace io {
+
+        namespace detail {
+
+            /**
+             * Virtual base class for all classes reading OSM files in different
+             * formats.
+             *
+             * Do not use this class or derived classes directly. Use the
+             * osmium::io::Reader class instead.
+             */
+            class InputFormat {
+
+            protected:
+
+                osmium::io::File m_file;
+                osmium::osm_entity_bits::type m_read_which_entities;
+                osmium::thread::Queue<std::string>& m_input_queue;
+                osmium::io::Header m_header;
+
+                explicit InputFormat(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) :
+                    m_file(file),
+                    m_read_which_entities(read_which_entities),
+                    m_input_queue(input_queue) {
+                    m_header.set_has_multiple_object_versions(m_file.has_multiple_object_versions());
+                }
+
+                InputFormat(const InputFormat&) = delete;
+                InputFormat(InputFormat&&) = delete;
+
+                InputFormat& operator=(const InputFormat&) = delete;
+                InputFormat& operator=(InputFormat&&) = delete;
+
+            public:
+
+                virtual ~InputFormat() {
+                }
+
+                virtual osmium::memory::Buffer read() = 0;
+
+                virtual void close() {
+                }
+
+                virtual osmium::io::Header header() {
+                    return m_header;
+                }
+
+            }; // class InputFormat
+
+            /**
+             * This factory class is used to create objects that read OSM data
+             * written in a specified format.
+             *
+             * Do not use this class directly. Instead use the osmium::io::Reader
+             * class.
+             */
+            class InputFormatFactory {
+
+            public:
+
+                typedef std::function<osmium::io::detail::InputFormat*(const osmium::io::File&, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>&)> create_input_type;
+
+            private:
+
+                typedef std::map<osmium::io::file_format, create_input_type> map_type;
+
+                map_type m_callbacks;
+
+                InputFormatFactory() :
+                    m_callbacks() {
+                }
+
+            public:
+
+                static InputFormatFactory& instance() {
+                    static InputFormatFactory factory;
+                    return factory;
+                }
+
+                bool register_input_format(osmium::io::file_format format, create_input_type create_function) {
+                    if (! m_callbacks.insert(map_type::value_type(format, create_function)).second) {
+                        return false;
+                    }
+                    return true;
+                }
+
+                std::unique_ptr<osmium::io::detail::InputFormat> create_input(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) {
+                    file.check();
+
+                    auto it = m_callbacks.find(file.format());
+                    if (it != m_callbacks.end()) {
+                        return std::unique_ptr<osmium::io::detail::InputFormat>((it->second)(file, read_which_entities, input_queue));
+                    }
+
+                    throw std::runtime_error(std::string("Support for input format '") + as_string(file.format()) + "' not compiled into this binary.");
+                }
+
+            }; // class InputFormatFactory
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_INPUT_FORMAT_HPP
diff --git a/third_party/osmium/io/detail/opl_output_format.hpp b/third_party/osmium/io/detail/opl_output_format.hpp
new file mode 100644
index 0000000..b21d118
--- /dev/null
+++ b/third_party/osmium/io/detail/opl_output_format.hpp
@@ -0,0 +1,315 @@
+#ifndef OSMIUM_IO_DETAIL_OPL_OUTPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_OPL_OUTPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <chrono>
+#include <cinttypes>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <future>
+#include <iterator>
+#include <memory>
+#include <ratio>
+#include <string>
+#include <thread>
+#include <utility>
+
+#include <boost/version.hpp>
+
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wmissing-noreturn"
+# pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#if BOOST_VERSION >= 104800
+# include <boost/regex/pending/unicode_iterator.hpp>
+#else
+# include <boost_unicode_iterator.hpp>
+#endif
+
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif
+
+#include <osmium/handler.hpp>
+#include <osmium/io/detail/output_format.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/collection.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/changeset.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/thread/pool.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        class File;
+
+        namespace detail {
+
+            /**
+             * Writes out one buffer with OSM data in OPL format.
+             */
+            class OPLOutputBlock : public osmium::handler::Handler {
+
+                static constexpr size_t tmp_buffer_size = 100;
+
+                osmium::memory::Buffer m_input_buffer;
+
+                std::string m_out;
+
+                char m_tmp_buffer[tmp_buffer_size+1];
+
+                template <typename... TArgs>
+                void output_formatted(const char* format, TArgs&&... args) {
+#ifndef NDEBUG
+                    int len =
+#endif
+#ifndef _MSC_VER
+                    snprintf(m_tmp_buffer, tmp_buffer_size, format, std::forward<TArgs>(args)...);
+#else
+                    _snprintf(m_tmp_buffer, tmp_buffer_size, format, std::forward<TArgs>(args)...);
+#endif
+                    assert(len > 0 && static_cast<size_t>(len) < tmp_buffer_size);
+                    m_out += m_tmp_buffer;
+                }
+
+                void append_encoded_string(const std::string& data) {
+                    boost::u8_to_u32_iterator<std::string::const_iterator> it(data.cbegin(), data.cbegin(), data.cend());
+                    boost::u8_to_u32_iterator<std::string::const_iterator> end(data.cend(), data.cend(), data.cend());
+                    boost::utf8_output_iterator<std::back_insert_iterator<std::string>> oit(std::back_inserter(m_out));
+
+                    for (; it != end; ++it) {
+                        uint32_t c = *it;
+
+                        // This is a list of Unicode code points that we let
+                        // through instead of escaping them. It is incomplete
+                        // and can be extended later.
+                        // Generally we don't want to let through any character
+                        // that has special meaning in the OPL format such as
+                        // space, comma, @, etc. and any non-printing characters.
+                        if ((0x0021 <= c && c <= 0x0024) ||
+                            (0x0026 <= c && c <= 0x002b) ||
+                            (0x002d <= c && c <= 0x003c) ||
+                            (0x003e <= c && c <= 0x003f) ||
+                            (0x0041 <= c && c <= 0x007e) ||
+                            (0x00a1 <= c && c <= 0x00ac) ||
+                            (0x00ae <= c && c <= 0x05ff)) {
+                            *oit = c;
+                        } else {
+                            m_out += '%';
+                            output_formatted("%04x", c);
+                        }
+                    }
+                }
+
+                void write_meta(const osmium::OSMObject& object) {
+                    output_formatted("%" PRId64 " v%d d", object.id(), object.version());
+                    m_out += (object.visible() ? 'V' : 'D');
+                    output_formatted(" c%d t", object.changeset());
+                    m_out += object.timestamp().to_iso();
+                    output_formatted(" i%d u", object.uid());
+                    append_encoded_string(object.user());
+                    m_out += " T";
+                    bool first = true;
+                    for (const auto& tag : object.tags()) {
+                        if (first) {
+                            first = false;
+                        } else {
+                            m_out += ',';
+                        }
+                        append_encoded_string(tag.key());
+                        m_out += '=';
+                        append_encoded_string(tag.value());
+                    }
+                }
+
+                void write_location(const osmium::Location location, const char x, const char y) {
+                    if (location) {
+                        output_formatted(" %c%.7f %c%.7f", x, location.lon_without_check(), y, location.lat_without_check());
+                    } else {
+                        m_out += ' ';
+                        m_out += x;
+                        m_out += ' ';
+                        m_out += y;
+                    }
+                }
+
+            public:
+
+                explicit OPLOutputBlock(osmium::memory::Buffer&& buffer) :
+                    m_input_buffer(std::move(buffer)),
+                    m_out(),
+                    m_tmp_buffer() {
+                }
+
+                OPLOutputBlock(const OPLOutputBlock&) = delete;
+                OPLOutputBlock& operator=(const OPLOutputBlock&) = delete;
+
+                OPLOutputBlock(OPLOutputBlock&&) = default;
+                OPLOutputBlock& operator=(OPLOutputBlock&&) = default;
+
+                std::string operator()() {
+                    osmium::apply(m_input_buffer.cbegin(), m_input_buffer.cend(), *this);
+
+                    std::string out;
+                    std::swap(out, m_out);
+                    return out;
+                }
+
+                void node(const osmium::Node& node) {
+                    m_out += 'n';
+                    write_meta(node);
+                    write_location(node.location(), 'x', 'y');
+                    m_out += '\n';
+                }
+
+                void way(const osmium::Way& way) {
+                    m_out += 'w';
+                    write_meta(way);
+
+                    m_out += " N";
+                    bool first = true;
+                    for (const auto& node_ref : way.nodes()) {
+                        if (first) {
+                            first = false;
+                        } else {
+                            m_out += ',';
+                        }
+                        output_formatted("n%" PRId64, node_ref.ref());
+                    }
+                    m_out += '\n';
+                }
+
+                void relation(const osmium::Relation& relation) {
+                    m_out += 'r';
+                    write_meta(relation);
+
+                    m_out += " M";
+                    bool first = true;
+                    for (const auto& member : relation.members()) {
+                        if (first) {
+                            first = false;
+                        } else {
+                            m_out += ',';
+                        }
+                        m_out += item_type_to_char(member.type());
+                        output_formatted("%" PRId64 "@", member.ref());
+                        m_out += member.role();
+                    }
+                    m_out += '\n';
+                }
+
+                void changeset(const osmium::Changeset& changeset) {
+                    output_formatted("c%d k%d s", changeset.id(), changeset.num_changes());
+                    m_out += changeset.created_at().to_iso();
+                    m_out += " e";
+                    m_out += changeset.closed_at().to_iso();
+                    output_formatted(" i%d u", changeset.uid());
+                    append_encoded_string(changeset.user());
+                    write_location(changeset.bounds().bottom_left(), 'x', 'y');
+                    write_location(changeset.bounds().top_right(), 'X', 'Y');
+                    m_out += " T";
+                    bool first = true;
+                    for (const auto& tag : changeset.tags()) {
+                        if (first) {
+                            first = false;
+                        } else {
+                            m_out += ',';
+                        }
+                        append_encoded_string(tag.key());
+                        m_out += '=';
+                        append_encoded_string(tag.value());
+                    }
+
+                    m_out += '\n';
+                }
+
+            }; // OPLOutputBlock
+
+            class OPLOutputFormat : public osmium::io::detail::OutputFormat {
+
+                OPLOutputFormat(const OPLOutputFormat&) = delete;
+                OPLOutputFormat& operator=(const OPLOutputFormat&) = delete;
+
+            public:
+
+                OPLOutputFormat(const osmium::io::File& file, data_queue_type& output_queue) :
+                    OutputFormat(file, output_queue) {
+                }
+
+                void write_buffer(osmium::memory::Buffer&& buffer) override final {
+                    m_output_queue.push(osmium::thread::Pool::instance().submit(OPLOutputBlock{std::move(buffer)}));
+                }
+
+                void close() override final {
+                    std::string out;
+                    std::promise<std::string> promise;
+                    m_output_queue.push(promise.get_future());
+                    promise.set_value(out);
+                }
+
+            }; // class OPLOutputFormat
+
+            namespace {
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-variable"
+                const bool registered_opl_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::opl,
+                    [](const osmium::io::File& file, data_queue_type& output_queue) {
+                        return new osmium::io::detail::OPLOutputFormat(file, output_queue);
+                });
+#pragma GCC diagnostic pop
+
+            } // anonymous namespace
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_OPL_OUTPUT_FORMAT_HPP
diff --git a/third_party/osmium/io/detail/output_format.hpp b/third_party/osmium/io/detail/output_format.hpp
new file mode 100644
index 0000000..ad9e702
--- /dev/null
+++ b/third_party/osmium/io/detail/output_format.hpp
@@ -0,0 +1,156 @@
+#ifndef OSMIUM_IO_DETAIL_OUTPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_OUTPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <functional>
+#include <future>
+#include <map>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+#include <osmium/io/file.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/thread/queue.hpp>
+
+namespace osmium {
+
+    namespace memory {
+        class Buffer;
+    }
+
+    namespace io {
+
+        namespace detail {
+
+            typedef osmium::thread::Queue<std::future<std::string>> data_queue_type;
+
+            /**
+             * Virtual base class for all classes writing OSM files in different
+             * formats.
+             *
+             * Do not use this class or derived classes directly. Use the
+             * osmium::io::Writer class instead.
+             */
+            class OutputFormat {
+
+            protected:
+
+                osmium::io::File m_file;
+                data_queue_type& m_output_queue;
+
+            public:
+
+                explicit OutputFormat(const osmium::io::File& file, data_queue_type& output_queue) :
+                    m_file(file),
+                    m_output_queue(output_queue) {
+                }
+
+                OutputFormat(const OutputFormat&) = delete;
+                OutputFormat(OutputFormat&&) = delete;
+
+                OutputFormat& operator=(const OutputFormat&) = delete;
+                OutputFormat& operator=(OutputFormat&&) = delete;
+
+                virtual ~OutputFormat() {
+                }
+
+                virtual void write_header(const osmium::io::Header&) {
+                }
+
+                virtual void write_buffer(osmium::memory::Buffer&&) = 0;
+
+                virtual void close() = 0;
+
+            }; // class OutputFormat
+
+            /**
+             * This factory class is used to create objects that write OSM data
+             * into a specified output format.
+             *
+             * Do not use this class directly. Instead use the osmium::io::Writer
+             * class.
+             */
+            class OutputFormatFactory {
+
+            public:
+
+                typedef std::function<osmium::io::detail::OutputFormat*(const osmium::io::File&, data_queue_type&)> create_output_type;
+
+            private:
+
+                typedef std::map<osmium::io::file_format, create_output_type> map_type;
+
+                map_type m_callbacks;
+
+                OutputFormatFactory() :
+                    m_callbacks() {
+                }
+
+            public:
+
+                static OutputFormatFactory& instance() {
+                    static OutputFormatFactory factory;
+                    return factory;
+                }
+
+                bool register_output_format(osmium::io::file_format format, create_output_type create_function) {
+                    if (! m_callbacks.insert(map_type::value_type(format, create_function)).second) {
+                        return false;
+                    }
+                    return true;
+                }
+
+                std::unique_ptr<osmium::io::detail::OutputFormat> create_output(const osmium::io::File& file, data_queue_type& output_queue) {
+                    file.check();
+
+                    auto it = m_callbacks.find(file.format());
+                    if (it != m_callbacks.end()) {
+                        return std::unique_ptr<osmium::io::detail::OutputFormat>((it->second)(file, output_queue));
+                    }
+
+                    throw std::runtime_error(std::string("Support for output format '") + as_string(file.format()) + "' not compiled into this binary.");
+                }
+
+            }; // class OutputFormatFactory
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_OUTPUT_FORMAT_HPP
diff --git a/third_party/osmium/io/detail/pbf.hpp b/third_party/osmium/io/detail/pbf.hpp
new file mode 100644
index 0000000..9814bd4
--- /dev/null
+++ b/third_party/osmium/io/detail/pbf.hpp
@@ -0,0 +1,100 @@
+#ifndef OSMIUM_IO_DETAIL_PBF_HPP
+#define OSMIUM_IO_DETAIL_PBF_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#define OSMIUM_LINK_WITH_LIBS_PBF -pthread -lz -lprotobuf-lite -losmpbf
+
+#include <stdexcept>
+
+#include <osmpbf/osmpbf.h>
+
+// needed for htonl and ntohl
+#ifndef _WIN32
+# include <netinet/in.h>
+#else
+# include <winsock2.h>
+#endif
+
+#include <osmium/io/error.hpp>
+#include <osmium/osm/item_type.hpp>
+
+namespace osmium {
+
+// avoid g++ false positive
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wreturn-type"
+    inline item_type osmpbf_membertype_to_item_type(const OSMPBF::Relation::MemberType mt) {
+        switch (mt) {
+            case OSMPBF::Relation::NODE:
+                return item_type::node;
+            case OSMPBF::Relation::WAY:
+                return item_type::way;
+            case OSMPBF::Relation::RELATION:
+                return item_type::relation;
+        }
+    }
+#pragma GCC diagnostic pop
+
+    inline OSMPBF::Relation::MemberType item_type_to_osmpbf_membertype(const item_type type) {
+        switch (type) {
+            case item_type::node:
+                return OSMPBF::Relation::NODE;
+            case item_type::way:
+                return OSMPBF::Relation::WAY;
+            case item_type::relation:
+                return OSMPBF::Relation::RELATION;
+            default:
+                throw std::runtime_error("Unknown relation member type");
+        }
+    }
+
+    /**
+     * Exception thrown when there was a problem with parsing the PBF format of
+     * a file.
+     */
+    struct pbf_error : public io_error {
+
+        pbf_error(const std::string& what) :
+            io_error(std::string("PBF error: ") + what) {
+        }
+
+        pbf_error(const char* what) :
+            io_error(std::string("PBF error: ") + what) {
+        }
+
+    }; // struct pbf_error
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_PBF_HPP
diff --git a/third_party/osmium/io/detail/pbf_input_format.hpp b/third_party/osmium/io/detail/pbf_input_format.hpp
new file mode 100644
index 0000000..3491bed
--- /dev/null
+++ b/third_party/osmium/io/detail/pbf_input_format.hpp
@@ -0,0 +1,240 @@
+#ifndef OSMIUM_IO_DETAIL_PBF_INPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_PBF_INPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <atomic>
+#include <cassert>
+#include <chrono>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <future>
+#include <memory>
+#include <ratio>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <thread>
+#include <type_traits>
+
+#include <osmium/io/detail/input_format.hpp>
+#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
+#include <osmium/io/detail/pbf_parser.hpp>
+#include <osmium/io/error.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/thread/pool.hpp>
+#include <osmium/thread/queue.hpp>
+#include <osmium/thread/util.hpp>
+#include <osmium/util/cast.hpp>
+#include <osmium/util/config.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        class File;
+
+        namespace detail {
+
+            typedef osmium::thread::Queue<std::future<osmium::memory::Buffer>> queue_type;
+
+            /**
+             * Class for parsing PBF files.
+             */
+            class PBFInputFormat : public osmium::io::detail::InputFormat {
+
+                bool m_use_thread_pool;
+                queue_type m_queue;
+                std::atomic<bool> m_done;
+                std::thread m_reader;
+                osmium::thread::Queue<std::string>& m_input_queue;
+                std::string m_input_buffer;
+
+                /**
+                 * Read the given number of bytes from the input queue.
+                 *
+                 * @param size Number of bytes to read
+                 * @returns String with the data
+                 * @throws osmium::pbf_error If size bytes can't be read
+                 */
+                std::string read_from_input_queue(size_t size) {
+                    while (m_input_buffer.size() < size) {
+                        std::string new_data;
+                        m_input_queue.wait_and_pop(new_data);
+                        if (new_data.empty()) {
+                            throw osmium::pbf_error("truncated data (EOF encountered)");
+                        }
+                        m_input_buffer += new_data;
+                    }
+
+                    std::string output { m_input_buffer.substr(size) };
+                    m_input_buffer.resize(size);
+                    std::swap(output, m_input_buffer);
+                    return output;
+                }
+
+                /**
+                 * Read BlobHeader by first reading the size and then the
+                 * BlobHeader. The BlobHeader contains a type field (which is
+                 * checked against the expected type) and a size field.
+                 *
+                 * @param expected_type Expected type of data ("OSMHeader" or
+                 *                      "OSMData").
+                 * @returns Size of the data read from BlobHeader (0 on EOF).
+                 */
+                size_t read_blob_header(const char* expected_type) {
+                    uint32_t size_in_network_byte_order;
+
+                    try {
+                        std::string input_data = read_from_input_queue(sizeof(size_in_network_byte_order));
+                        size_in_network_byte_order = *reinterpret_cast<const uint32_t*>(input_data.data());
+                    } catch (osmium::pbf_error&) {
+                        return 0; // EOF
+                    }
+
+                    uint32_t size = ntohl(size_in_network_byte_order);
+                    if (size > static_cast<uint32_t>(OSMPBF::max_blob_header_size)) {
+                        throw osmium::pbf_error("invalid BlobHeader size (> max_blob_header_size)");
+                    }
+
+                    OSMPBF::BlobHeader blob_header;
+                    if (!blob_header.ParseFromString(read_from_input_queue(size))) {
+                        throw osmium::pbf_error("failed to parse BlobHeader");
+                    }
+
+                    if (blob_header.type() != expected_type) {
+                        throw osmium::pbf_error("blob does not have expected type (OSMHeader in first blob, OSMData in following blobs)");
+                    }
+
+                    return static_cast<size_t>(blob_header.datasize());
+                }
+
+                void parse_osm_data(osmium::osm_entity_bits::type read_types) {
+                    osmium::thread::set_thread_name("_osmium_pbf_in");
+                    int n=0;
+                    while (auto size = read_blob_header("OSMData")) {
+
+                        if (m_use_thread_pool) {
+                            m_queue.push(osmium::thread::Pool::instance().submit(DataBlobParser{read_from_input_queue(size), read_types}));
+                        } else {
+                            std::promise<osmium::memory::Buffer> promise;
+                            m_queue.push(promise.get_future());
+                            DataBlobParser data_blob_parser{read_from_input_queue(size), read_types};
+                            promise.set_value(data_blob_parser());
+                        }
+                        ++n;
+
+                        if (m_done) {
+                            return;
+                        }
+                    }
+                    m_done = true;
+                }
+
+            public:
+
+                /**
+                 * Instantiate PBF Parser
+                 *
+                 * @param file osmium::io::File instance describing file to be read from.
+                 * @param read_which_entities Which types of OSM entities (nodes, ways, relations, changesets) should be parsed?
+                 * @param input_queue String queue where data is read from.
+                 */
+                PBFInputFormat(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) :
+                    osmium::io::detail::InputFormat(file, read_which_entities, input_queue),
+                    m_use_thread_pool(osmium::config::use_pool_threads_for_pbf_parsing()),
+                    m_queue(20, "pbf_parser_results"), // XXX
+                    m_done(false),
+                    m_input_queue(input_queue),
+                    m_input_buffer() {
+                    GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+                    // handle OSMHeader
+                    auto size = read_blob_header("OSMHeader");
+                    m_header = parse_header_blob(read_from_input_queue(size));
+
+                    if (m_read_which_entities != osmium::osm_entity_bits::nothing) {
+                        m_reader = std::thread(&PBFInputFormat::parse_osm_data, this, m_read_which_entities);
+                    }
+                }
+
+                ~PBFInputFormat() {
+                    m_done = true;
+                    if (m_reader.joinable()) {
+                        m_reader.join();
+                    }
+                }
+
+                /**
+                 * Returns the next buffer with OSM data read from the PBF file.
+                 * Blocks if data is not available yet.
+                 * Returns an empty buffer at end of input.
+                 */
+                osmium::memory::Buffer read() override {
+                    if (!m_done || !m_queue.empty()) {
+                        std::future<osmium::memory::Buffer> buffer_future;
+                        m_queue.wait_and_pop(buffer_future);
+                        return std::move(buffer_future.get());
+                    }
+
+                    return osmium::memory::Buffer();
+                }
+
+            }; // class PBFInputFormat
+
+            namespace {
+
+                const bool registered_pbf_input = osmium::io::detail::InputFormatFactory::instance().register_input_format(osmium::io::file_format::pbf,
+                    [](const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) {
+                        return new osmium::io::detail::PBFInputFormat(file, read_which_entities, input_queue);
+                });
+
+            } // anonymous namespace
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_PBF_INPUT_FORMAT_HPP
diff --git a/third_party/osmium/io/detail/pbf_output_format.hpp b/third_party/osmium/io/detail/pbf_output_format.hpp
new file mode 100644
index 0000000..44f8ffb
--- /dev/null
+++ b/third_party/osmium/io/detail/pbf_output_format.hpp
@@ -0,0 +1,944 @@
+#ifndef OSMIUM_IO_DETAIL_PBF_OUTPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_PBF_OUTPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+/*
+
+About the .osm.pbf file format
+This is an excerpt of <http://wiki.openstreetmap.org/wiki/PBF_Format>
+
+The .osm.pbf format and it's derived formats (.osh.pbf and .osc.pbf) are encoded
+using googles protobuf library for the low-level storage. They are constructed
+by nesting data on two levels:
+
+On the lower level the file is constructed using BlobHeaders and Blobs. A .osm.pbf
+file contains multiple sequences of
+ 1. a 4-byte header size, stored in network-byte-order
+ 2. a BlobHeader of exactly this size
+ 3. a Blob
+
+The BlobHeader tells the reader about the type and size of the following Blob. The
+Blob can contain data in raw or zlib-compressed form. After uncompressing the blob
+it is treated differently depending on the type specified in the BlobHeader.
+
+The contents of the Blob belongs to the higher level. It contains either an HeaderBlock
+(type="OSMHeader") or an PrimitiveBlock (type="OSMData"). The file needs to have
+at least one HeaderBlock before the first PrimitiveBlock.
+
+The HeaderBlock contains meta-information like the writing program or a bbox. It may
+also contain multiple "required features" that describe what kinds of input a
+reading program needs to handle in order to fully understand the files' contents.
+
+The PrimitiveBlock can store multiple types of objects (i.e. 5 nodes, 2 ways and
+1 relation). It contains one or more PrimitiveGroup which in turn contain multiple
+nodes, ways or relations. A PrimitiveGroup should only contain one kind of object.
+
+There's a special kind of "object type" called dense-nodes. It is used to store nodes
+in a very dense format, avoiding message overheads and using delta-encoding for nearly
+all ids.
+
+All Strings are stored as indexes to rows in a StringTable. The StringTable contains
+one row for each used string, so strings that are used multiple times need to be
+stored only once. The StringTable is sorted by usage-count, so the most often used
+string is stored at index 1.
+
+A simple outline of a .osm.pbf file could look like this:
+
+  4-bytes header size
+  BlobHeader
+  Blob
+    HeaderBlock
+  4-bytes header size
+  BlobHeader
+  Blob
+    PrimitiveBlock
+      StringTable
+      PrimitiveGroup
+        5 nodes
+      PrimitiveGroup
+        2 ways
+      PrimitiveGroup
+        1 relation
+
+More complete outlines of real .osm.pbf files can be created using the osmpbf-outline tool:
+ <https://github.com/MaZderMind/OSM-binary/tree/osmpbf-outline>
+*/
+
+#include <algorithm>
+#include <chrono>
+#include <cmath>
+#include <cstdint>
+#include <cstdlib>
+#include <future>
+#include <iostream>
+#include <memory>
+#include <ratio>
+#include <string>
+#include <thread>
+#include <time.h>
+#include <utility>
+
+#include <osmium/handler.hpp>
+#include <osmium/io/detail/output_format.hpp>
+#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
+#include <osmium/io/detail/pbf_stringtable.hpp>
+#include <osmium/io/detail/zlib.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/collection.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/util/cast.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            namespace {
+
+                /**
+                 * Serialize a protobuf message into a Blob, optionally apply compression
+                 * and return it together with a BlobHeader ready to be written to a file.
+                 *
+                 * @param type Type-string used in the BlobHeader.
+                 * @param msg Protobuf-message.
+                 * @param use_compression Should the output be compressed using zlib?
+                 */
+                std::string serialize_blob(const std::string& type, const google::protobuf::MessageLite& msg, bool use_compression) {
+                    OSMPBF::Blob pbf_blob;
+
+                    {
+                        std::string content;
+                        msg.SerializeToString(&content);
+
+                        pbf_blob.set_raw_size(static_cast_with_assert<::google::protobuf::int32>(content.size()));
+
+                        if (use_compression) {
+                            pbf_blob.set_zlib_data(osmium::io::detail::zlib_compress(content));
+                        } else {
+                            pbf_blob.set_raw(content);
+                        }
+                    }
+
+                    std::string blob_data;
+                    pbf_blob.SerializeToString(&blob_data);
+
+                    OSMPBF::BlobHeader pbf_blob_header;
+                    pbf_blob_header.set_type(type);
+                    pbf_blob_header.set_datasize(static_cast_with_assert<::google::protobuf::int32>(blob_data.size()));
+
+                    std::string blob_header_data;
+                    pbf_blob_header.SerializeToString(&blob_header_data);
+
+                    uint32_t sz = htonl(static_cast_with_assert<uint32_t>(blob_header_data.size()));
+
+                    // write to output: the 4-byte BlobHeader-Size followed by the BlobHeader followed by the Blob
+                    std::string output;
+                    output.reserve(sizeof(sz) + blob_header_data.size() + blob_data.size());
+                    output.append(reinterpret_cast<const char*>(&sz), sizeof(sz));
+                    output.append(blob_header_data);
+                    output.append(blob_data);
+
+                    return output;
+                }
+
+            } // anonymous namespace
+
+            class PBFOutputFormat : public osmium::io::detail::OutputFormat, public osmium::handler::Handler {
+
+                /**
+                 * This class models a variable that keeps track of the value
+                 * it was last set to and returns the delta between old and
+                 * new value from the update() call.
+                 */
+                template <typename T>
+                class Delta {
+
+                    T m_value;
+
+                public:
+
+                    Delta() :
+                        m_value(0) {
+                    }
+
+                    void clear() {
+                        m_value = 0;
+                    }
+
+                    T update(T new_value) {
+                        using std::swap;
+                        swap(m_value, new_value);
+                        return m_value - new_value;
+                    }
+
+                }; // class Delta
+
+                /**
+                 * Maximum number of items in a primitive block.
+                 *
+                 * The uncompressed length of a Blob *should* be less
+                 * than 16 megabytes and *must* be less than 32 megabytes.
+                 *
+                 * A block may contain any number of entities, as long as
+                 * the size limits for the surrounding blob are obeyed.
+                 * However, for simplicity, the current Osmosis (0.38)
+                 * as well as Osmium implementation always
+                 * uses at most 8k entities in a block.
+                 */
+                static constexpr uint32_t max_block_contents = 8000;
+
+                /**
+                 * The output buffer (block) will be filled to about
+                 * 95% and then written to disk. This leaves more than
+                 * enough space for the string table (which typically
+                 * needs about 0.1 to 0.3% of the block size).
+                 */
+                static constexpr int64_t buffer_fill_percent = 95;
+
+                /**
+                 * protobuf-struct of a HeaderBlock
+                 */
+                OSMPBF::HeaderBlock pbf_header_block;
+
+                /**
+                 * protobuf-struct of a PrimitiveBlock
+                 */
+                OSMPBF::PrimitiveBlock pbf_primitive_block;
+
+                /**
+                 * pointer to PrimitiveGroups inside the current PrimitiveBlock,
+                 * used for writing nodes, ways or relations
+                 */
+                OSMPBF::PrimitiveGroup* pbf_nodes;
+                OSMPBF::PrimitiveGroup* pbf_ways;
+                OSMPBF::PrimitiveGroup* pbf_relations;
+
+                /**
+                 * To flexibly handle multiple resolutions, the granularity, or
+                 * resolution used for representing locations is adjustable in
+                 * multiples of 1 nanodegree. The default scaling factor is 100
+                 * nanodegrees, corresponding to about ~1cm at the equator.
+                 * This is the current resolution of the OSM database.
+                 */
+                int m_location_granularity;
+
+                /**
+                 * The granularity used for representing timestamps is also adjustable in
+                 * multiples of 1 millisecond. The default scaling factor is 1000
+                 * milliseconds, which is the current resolution of the OSM database.
+                 */
+                int m_date_granularity;
+
+                /**
+                 * should nodes be serialized into the dense format?
+                 *
+                 * nodes can be encoded one of two ways, as a Node
+                 * (m_use_dense_nodes = false) and a special dense format.
+                 * In the dense format, all information is stored 'column wise',
+                 * as an array of ID's, array of latitudes, and array of
+                 * longitudes. Each column is delta-encoded. This reduces
+                 * header overheads and allows delta-coding to work very effectively.
+                 */
+                bool m_use_dense_nodes {true};
+
+                /**
+                 * should the PBF blobs contain zlib compressed data?
+                 *
+                 * the zlib compression is optional, it's possible to store the
+                 * blobs in raw format. Disabling the compression can improve the
+                 * writing speed a little but the output will be 2x to 3x bigger.
+                 */
+                bool m_use_compression {true};
+
+                /**
+                 * While the .osm.pbf-format is able to carry all meta information, it is
+                 * also able to omit this information to reduce size.
+                 */
+                bool m_should_add_metadata {true};
+
+                /**
+                 * Should the visible flag be added on objects?
+                 */
+                bool m_add_visible;
+
+                /**
+                 * counter used to quickly check the number of objects stored inside
+                 * the current PrimitiveBlock. When the counter reaches max_block_contents
+                 * the PrimitiveBlock is serialized into a Blob and flushed to the file.
+                 *
+                 * this check is performed in check_block_contents_counter() which is
+                 * called once for each object.
+                 */
+                uint16_t primitive_block_contents;
+                int primitive_block_size;
+
+                // StringTable management
+                StringTable string_table;
+
+                /**
+                 * These variables are used to calculate the
+                 * delta-encoding while storing dense-nodes. It holds the last seen values
+                 * from which the difference is stored into the protobuf.
+                 */
+                Delta<int64_t> m_delta_id;
+                Delta<int64_t> m_delta_lat;
+                Delta<int64_t> m_delta_lon;
+                Delta<int64_t> m_delta_timestamp;
+                Delta<int64_t> m_delta_changeset;
+                Delta<int64_t> m_delta_uid;
+                Delta<::google::protobuf::int32> m_delta_user_sid;
+
+                bool debug;
+
+                bool has_debug_level(int) {
+                    return false;
+                }
+
+                ///// Blob writing /////
+
+                /**
+                 * Before a PrimitiveBlock gets serialized, all interim StringTable-ids needs to be
+                 * mapped to the associated real StringTable ids. This is done in this function.
+                 *
+                 * This function needs to know about the concrete structure of all item types to find
+                 * all occurrences of string-ids.
+                 */
+                void map_string_ids() {
+                    // test, if the node-block has been allocated
+                    if (pbf_nodes) {
+                        // iterate over all nodes, passing them to the map_common_string_ids function
+                        for (int i=0, l=pbf_nodes->nodes_size(); i<l; ++i) {
+                            map_common_string_ids(pbf_nodes->mutable_nodes(i));
+                        }
+
+                        // test, if the node-block has a densenodes structure
+                        if (pbf_nodes->has_dense()) {
+                            // get a pointer to the densenodes structure
+                            OSMPBF::DenseNodes* dense = pbf_nodes->mutable_dense();
+
+                            // in the densenodes structure keys and vals are encoded in an intermixed
+                            // array, individual nodes are seperated by a value of 0 (0 in the StringTable
+                            // is always unused). String-ids of 0 are thus kept alone.
+                            for (int i=0, l=dense->keys_vals_size(); i<l; ++i) {
+                                // map interim string-ids > 0 to real string ids
+                                auto sid = dense->keys_vals(i);
+                                if (sid > 0) {
+                                    dense->set_keys_vals(i, string_table.map_string_id(sid));
+                                }
+                            }
+
+                            // test if the densenodes block has meta infos
+                            if (dense->has_denseinfo()) {
+                                // get a pointer to the denseinfo structure
+                                OSMPBF::DenseInfo* denseinfo = dense->mutable_denseinfo();
+
+                                // iterate over all username string-ids
+                                for (int i=0, l=denseinfo->user_sid_size(); i<l; ++i) {
+                                    // map interim string-ids > 0 to real string ids
+                                    auto user_sid = string_table.map_string_id(denseinfo->user_sid(i));
+
+                                    // delta encode the string-id
+                                    denseinfo->set_user_sid(i, m_delta_user_sid.update(user_sid));
+                                }
+                            }
+                        }
+                    }
+
+                    // test, if the ways-block has been allocated
+                    if (pbf_ways) {
+                        // iterate over all ways, passing them to the map_common_string_ids function
+                        for (int i=0, l=pbf_ways->ways_size(); i<l; ++i) {
+                            map_common_string_ids(pbf_ways->mutable_ways(i));
+                        }
+                    }
+
+                    // test, if the relations-block has been allocated
+                    if (pbf_relations) {
+                        // iterate over all relations
+                        for (int i=0, l=pbf_relations->relations_size(); i<l; ++i) {
+                            // get a pointer to the relation
+                            OSMPBF::Relation* relation = pbf_relations->mutable_relations(i);
+
+                            // pass them to the map_common_string_ids function
+                            map_common_string_ids(relation);
+
+                            // iterate over all relation members, mapping the interim string-ids
+                            // of the role to real string ids
+                            for (int mi=0; mi < relation->roles_sid_size(); ++mi) {
+                                relation->set_roles_sid(mi, string_table.map_string_id(relation->roles_sid(mi)));
+                            }
+                        }
+                    }
+                }
+
+                /**
+                * a helper function used in map_string_ids to map common interim string-ids of the
+                * user name and all tags to real string ids.
+                *
+                * TPBFObject is either OSMPBF::Node, OSMPBF::Way or OSMPBF::Relation.
+                */
+                template <class TPBFObject>
+                void map_common_string_ids(TPBFObject* in) {
+                    // if the object has meta-info attached
+                    if (in->has_info()) {
+                        // map the interim-id of the user name to a real id
+                        OSMPBF::Info* info = in->mutable_info();
+                        info->set_user_sid(string_table.map_string_id(info->user_sid()));
+                    }
+
+                    // iterate over all tags and map the interim-ids of the key and the value to real ids
+                    for (int i=0, l=in->keys_size(); i<l; ++i) {
+                        in->set_keys(i, string_table.map_string_id(in->keys(i)));
+                        in->set_vals(i, string_table.map_string_id(in->vals(i)));
+                    }
+                }
+
+
+                ///// MetaData helper /////
+
+                /**
+                 * convert a double lat or lon value to an int, respecting the current blocks granularity
+                 */
+                int64_t lonlat2int(double lonlat) {
+                    return static_cast<int64_t>(std::round(lonlat * OSMPBF::lonlat_resolution / location_granularity()));
+                }
+
+                /**
+                 * convert a timestamp to an int, respecting the current blocks granularity
+                 */
+                int64_t timestamp2int(time_t timestamp) {
+                    return static_cast<int64_t>(std::round(timestamp * (1000.0 / date_granularity())));
+                }
+
+                /**
+                 * helper function used in the write()-calls to apply common information from an osmium-object
+                 * onto a pbf-object.
+                 *
+                 * TPBFObject is either OSMPBF::Node, OSMPBF::Way or OSMPBF::Relation.
+                 */
+                template <class TPBFObject>
+                void apply_common_info(const osmium::OSMObject& in, TPBFObject* out) {
+                    // set the object-id
+                    out->set_id(in.id());
+
+                    // iterate over all tags and set the keys and vals, recording the strings in the
+                    // interim StringTable and storing the interim ids
+                    for (const auto& tag : in.tags()) {
+                        out->add_keys(string_table.record_string(tag.key()));
+                        out->add_vals(string_table.record_string(tag.value()));
+                    }
+
+                    if (m_should_add_metadata) {
+                        // add an info-section to the pbf object and set the meta-info on it
+                        OSMPBF::Info* out_info = out->mutable_info();
+                        if (m_add_visible) {
+                            out_info->set_visible(in.visible());
+                        }
+                        out_info->set_version(static_cast<::google::protobuf::int32>(in.version()));
+                        out_info->set_timestamp(timestamp2int(in.timestamp()));
+                        out_info->set_changeset(in.changeset());
+                        out_info->set_uid(static_cast<::google::protobuf::int32>(in.uid()));
+                        out_info->set_user_sid(string_table.record_string(in.user()));
+                    }
+                }
+
+
+                ///// High-Level Block writing /////
+
+                /**
+                 * store the current pbf_header_block into a Blob and clear this struct afterwards.
+                 */
+                void store_header_block() {
+                    if (debug && has_debug_level(1)) {
+                        std::cerr << "storing header block" << std::endl;
+                    }
+
+                    std::promise<std::string> promise;
+                    m_output_queue.push(promise.get_future());
+                    promise.set_value(serialize_blob("OSMHeader", pbf_header_block, m_use_compression));
+
+                    pbf_header_block.Clear();
+                }
+
+                /**
+                 * store the interim StringTable to the current pbf_primitive_block, map all interim string ids
+                 * to real StringTable ids and then store the current pbf_primitive_block into a Blob and clear
+                 * this struct and all related pointers and maps afterwards.
+                 */
+                void store_primitive_block() {
+                    if (debug && has_debug_level(1)) {
+                        std::cerr << "storing primitive block with " << primitive_block_contents << " items" << std::endl;
+                    }
+
+                    // set the granularity
+                    pbf_primitive_block.set_granularity(location_granularity());
+                    pbf_primitive_block.set_date_granularity(date_granularity());
+
+                    // store the interim StringTable into the protobuf object
+                    string_table.store_stringtable(pbf_primitive_block.mutable_stringtable());
+
+                    // map all interim string ids to real ids
+                    map_string_ids();
+
+                    std::promise<std::string> promise;
+                    m_output_queue.push(promise.get_future());
+                    promise.set_value(serialize_blob("OSMData", pbf_primitive_block, m_use_compression));
+
+                    // clear the PrimitiveBlock struct
+                    pbf_primitive_block.Clear();
+
+                    // clear the interim StringTable and its id map
+                    string_table.clear();
+
+                    // reset the delta variables
+                    m_delta_id.clear();
+                    m_delta_lat.clear();
+                    m_delta_lon.clear();
+                    m_delta_timestamp.clear();
+                    m_delta_changeset.clear();
+                    m_delta_uid.clear();
+                    m_delta_user_sid.clear();
+
+                    // reset the contents-counter to zero
+                    primitive_block_contents = 0;
+                    primitive_block_size = 0;
+
+                    // reset the node/way/relation pointers to nullptr
+                    pbf_nodes = nullptr;
+                    pbf_ways = nullptr;
+                    pbf_relations = nullptr;
+                }
+
+                /**
+                 * this little function checks primitive_block_contents counter against its maximum and calls
+                 * store_primitive_block to flush the block to the disk when it's reached. It's also responsible
+                 * for increasing this counter.
+                 *
+                 * this function also checks the estimated size of the current block and calls store_primitive_block
+                 * when the estimated size reaches buffer_fill_percent of the maximum uncompressed blob size.
+                 */
+                void check_block_contents_counter() {
+                    if (primitive_block_contents >= max_block_contents) {
+                        store_primitive_block();
+                    } else if (primitive_block_size > OSMPBF::max_uncompressed_blob_size * buffer_fill_percent / 100) {
+                        if (debug && has_debug_level(1)) {
+                            std::cerr << "storing primitive_block with only " << primitive_block_contents << " items, because its ByteSize (" << primitive_block_size << ") reached " <<
+                                      (static_cast<float>(primitive_block_size) / static_cast<float>(OSMPBF::max_uncompressed_blob_size) * 100.0) << "% of the maximum blob-size" << std::endl;
+                        }
+
+                        store_primitive_block();
+                    }
+
+                    ++primitive_block_contents;
+                }
+
+
+                ///// Block content writing /////
+
+                /**
+                 * Add a node to the block.
+                 *
+                 * @param node The node to add.
+                 */
+                void write_node(const osmium::Node& node) {
+                    // add a way to the group
+                    OSMPBF::Node* pbf_node = pbf_nodes->add_nodes();
+
+                    // copy the common meta-info from the osmium-object to the pbf-object
+                    apply_common_info(node, pbf_node);
+
+                    // modify lat & lon to integers, respecting the block's granularity and copy
+                    // the ints to the pbf-object
+                    pbf_node->set_lon(lonlat2int(node.location().lon_without_check()));
+                    pbf_node->set_lat(lonlat2int(node.location().lat_without_check()));
+                }
+
+                /**
+                 * Add a node to the block using DenseNodes.
+                 *
+                 * @param node The node to add.
+                 */
+                void write_dense_node(const osmium::Node& node) {
+                    // add a DenseNodes-Section to the PrimitiveGroup
+                    OSMPBF::DenseNodes* dense = pbf_nodes->mutable_dense();
+
+                    // copy the id, delta encoded
+                    dense->add_id(m_delta_id.update(node.id()));
+
+                    // copy the longitude, delta encoded
+                    dense->add_lon(m_delta_lon.update(lonlat2int(node.location().lon_without_check())));
+
+                    // copy the latitude, delta encoded
+                    dense->add_lat(m_delta_lat.update(lonlat2int(node.location().lat_without_check())));
+
+                    // in the densenodes structure keys and vals are encoded in an intermixed
+                    // array, individual nodes are seperated by a value of 0 (0 in the StringTable
+                    // is always unused)
+                    // so for three nodes the keys_vals array may look like this: 3 5 2 1 0 0 8 5
+                    // the first node has two tags (3=>5 and 2=>1), the second node does not
+                    // have any tags and the third node has a single tag (8=>5)
+                    for (const auto& tag : node.tags()) {
+                        dense->add_keys_vals(string_table.record_string(tag.key()));
+                        dense->add_keys_vals(string_table.record_string(tag.value()));
+                    }
+                    dense->add_keys_vals(0);
+
+                    if (m_should_add_metadata) {
+                        // add a DenseInfo-Section to the PrimitiveGroup
+                        OSMPBF::DenseInfo* denseinfo = dense->mutable_denseinfo();
+
+                        denseinfo->add_version(static_cast<::google::protobuf::int32>(node.version()));
+
+                        if (m_add_visible) {
+                            denseinfo->add_visible(node.visible());
+                        }
+
+                        // copy the timestamp, delta encoded
+                        denseinfo->add_timestamp(m_delta_timestamp.update(timestamp2int(node.timestamp())));
+
+                        // copy the changeset, delta encoded
+                        denseinfo->add_changeset(m_delta_changeset.update(node.changeset()));
+
+                        // copy the user id, delta encoded
+                        denseinfo->add_uid(static_cast<::google::protobuf::int32>(m_delta_uid.update(node.uid())));
+
+                        // record the user-name to the interim stringtable and copy the
+                        // interim string-id to the pbf-object
+                        denseinfo->add_user_sid(string_table.record_string(node.user()));
+                    }
+                }
+
+                /**
+                 * Add a way to the block.
+                 *
+                 * @param way The way to add.
+                 */
+                void write_way(const osmium::Way& way) {
+                    // add a way to the group
+                    OSMPBF::Way* pbf_way = pbf_ways->add_ways();
+
+                    // copy the common meta-info from the osmium-object to the pbf-object
+                    apply_common_info(way, pbf_way);
+
+                    // last way-node-id used for delta-encoding
+                    Delta<int64_t> delta_id;
+
+                    for (const auto& node_ref : way.nodes()) {
+                        // copy the way-node-id, delta encoded
+                        pbf_way->add_refs(delta_id.update(node_ref.ref()));
+                    }
+
+                    // count up blob size by the size of the Way
+                    primitive_block_size += pbf_way->ByteSize();
+                }
+
+                /**
+                 * Add a relation to the block.
+                 *
+                 * @param relation The relation to add.
+                 */
+                void write_relation(const osmium::Relation& relation) {
+                    // add a relation to the group
+                    OSMPBF::Relation* pbf_relation = pbf_relations->add_relations();
+
+                    // copy the common meta-info from the osmium-object to the pbf-object
+                    apply_common_info(relation, pbf_relation);
+
+                    Delta<int64_t> delta_id;
+
+                    for (const auto& member : relation.members()) {
+                        // record the relation-member role to the interim stringtable and copy the
+                        // interim string-id to the pbf-object
+                        pbf_relation->add_roles_sid(string_table.record_string(member.role()));
+
+                        // copy the relation-member-id, delta encoded
+                        pbf_relation->add_memids(delta_id.update(member.ref()));
+
+                        // copy the relation-member-type, mapped to the OSMPBF enum
+                        pbf_relation->add_types(item_type_to_osmpbf_membertype(member.type()));
+                    }
+
+                    // count up blob size by the size of the Relation
+                    primitive_block_size += pbf_relation->ByteSize();
+                }
+
+                // objects of this class can't be copied
+                PBFOutputFormat(const PBFOutputFormat&) = delete;
+                PBFOutputFormat& operator=(const PBFOutputFormat&) = delete;
+
+            public:
+
+                /**
+                 * Create PBFOutputFormat object from File.
+                 */
+                explicit PBFOutputFormat(const osmium::io::File& file, data_queue_type& output_queue) :
+                    OutputFormat(file, output_queue),
+                    pbf_header_block(),
+                    pbf_primitive_block(),
+                    pbf_nodes(nullptr),
+                    pbf_ways(nullptr),
+                    pbf_relations(nullptr),
+                    m_location_granularity(pbf_primitive_block.granularity()),
+                    m_date_granularity(pbf_primitive_block.date_granularity()),
+                    m_add_visible(file.has_multiple_object_versions()),
+                    primitive_block_contents(0),
+                    primitive_block_size(0),
+                    string_table(),
+                    m_delta_id(),
+                    m_delta_lat(),
+                    m_delta_lon(),
+                    m_delta_timestamp(),
+                    m_delta_changeset(),
+                    m_delta_uid(),
+                    m_delta_user_sid(),
+                    debug(true) {
+                    GOOGLE_PROTOBUF_VERIFY_VERSION;
+                    if (file.get("pbf_dense_nodes") == "false") {
+                        m_use_dense_nodes = false;
+                    }
+                    if (file.get("pbf_compression") == "none" || file.get("pbf_compression") == "false") {
+                        m_use_compression = false;
+                    }
+                    if (file.get("pbf_add_metadata") == "false") {
+                        m_should_add_metadata = false;
+                    }
+                }
+
+                void write_buffer(osmium::memory::Buffer&& buffer) override final {
+                    osmium::apply(buffer.cbegin(), buffer.cend(), *this);
+                }
+
+
+                /**
+                 * getter to access the granularity
+                 */
+                int location_granularity() const {
+                    return m_location_granularity;
+                }
+
+                /**
+                 * setter to set the granularity
+                 */
+                PBFOutputFormat& location_granularity(int g) {
+                    m_location_granularity = g;
+                    return *this;
+                }
+
+
+                /**
+                 * getter to access the date_granularity
+                 */
+                int date_granularity() const {
+                    return m_date_granularity;
+                }
+
+                /**
+                 * Set date granularity.
+                 */
+                PBFOutputFormat& date_granularity(int g) {
+                    m_date_granularity = g;
+                    return *this;
+                }
+
+
+                /**
+                 * Initialize the writing process.
+                 *
+                 * This initializes the header-block, sets the required-features and
+                 * the writing-program and adds the obligatory StringTable-Index 0.
+                 */
+                void write_header(const osmium::io::Header& header) override final {
+                    // add the schema version as required feature to the HeaderBlock
+                    pbf_header_block.add_required_features("OsmSchema-V0.6");
+
+                    // when the densenodes-feature is used, add DenseNodes as required feature
+                    if (m_use_dense_nodes) {
+                        pbf_header_block.add_required_features("DenseNodes");
+                    }
+
+                    // when the resulting file will carry history information, add
+                    // HistoricalInformation as required feature
+                    if (m_file.has_multiple_object_versions()) {
+                        pbf_header_block.add_required_features("HistoricalInformation");
+                    }
+
+                    // set the writing program
+                    pbf_header_block.set_writingprogram(header.get("generator"));
+
+                    if (!header.boxes().empty()) {
+                        OSMPBF::HeaderBBox* pbf_bbox = pbf_header_block.mutable_bbox();
+                        osmium::Box box = header.joined_boxes();
+                        pbf_bbox->set_left(static_cast<::google::protobuf::int64>(box.bottom_left().lon() * OSMPBF::lonlat_resolution));
+                        pbf_bbox->set_bottom(static_cast<::google::protobuf::int64>(box.bottom_left().lat() * OSMPBF::lonlat_resolution));
+                        pbf_bbox->set_right(static_cast<::google::protobuf::int64>(box.top_right().lon() * OSMPBF::lonlat_resolution));
+                        pbf_bbox->set_top(static_cast<::google::protobuf::int64>(box.top_right().lat() * OSMPBF::lonlat_resolution));
+                    }
+
+                    std::string osmosis_replication_timestamp = header.get("osmosis_replication_timestamp");
+                    if (!osmosis_replication_timestamp.empty()) {
+                        osmium::Timestamp ts(osmosis_replication_timestamp.c_str());
+                        pbf_header_block.set_osmosis_replication_timestamp(ts);
+                    }
+
+                    std::string osmosis_replication_sequence_number = header.get("osmosis_replication_sequence_number");
+                    if (!osmosis_replication_sequence_number.empty()) {
+                        pbf_header_block.set_osmosis_replication_sequence_number(std::atoll(osmosis_replication_sequence_number.c_str()));
+                    }
+
+                    std::string osmosis_replication_base_url = header.get("osmosis_replication_base_url");
+                    if (!osmosis_replication_base_url.empty()) {
+                        pbf_header_block.set_osmosis_replication_base_url(osmosis_replication_base_url);
+                    }
+
+                    store_header_block();
+                }
+
+                /**
+                 * Add a node to the pbf.
+                 *
+                 * A call to this method won't write the node to the file directly but
+                 * cache it for later bulk-writing. Calling final() ensures that everything
+                 * gets written and every file pointer is closed.
+                 */
+                void node(const osmium::Node& node) {
+                    // first of we check the contents-counter which may flush the cached nodes to
+                    // disk if the limit is reached. This call also increases the contents-counter
+                    check_block_contents_counter();
+
+                    if (debug && has_debug_level(2)) {
+                        std::cerr << "node " << node.id() << " v" << node.version() << std::endl;
+                    }
+
+                    // if no PrimitiveGroup for nodes has been added, add one and save the pointer
+                    if (!pbf_nodes) {
+                        pbf_nodes = pbf_primitive_block.add_primitivegroup();
+                    }
+
+                    if (m_use_dense_nodes) {
+                        write_dense_node(node);
+                    } else {
+                        write_node(node);
+                    }
+                }
+
+                /**
+                 * Add a way to the pbf.
+                 *
+                 * A call to this method won't write the way to the file directly but
+                 * cache it for later bulk-writing. Calling final() ensures that everything
+                 * gets written and every file pointer is closed.
+                 */
+                void way(const osmium::Way& way) {
+                    // first of we check the contents-counter which may flush the cached ways to
+                    // disk if the limit is reached. This call also increases the contents-counter
+                    check_block_contents_counter();
+
+                    // if no PrimitiveGroup for nodes has been added, add one and save the pointer
+                    if (!pbf_ways) {
+                        pbf_ways = pbf_primitive_block.add_primitivegroup();
+                    }
+
+                    write_way(way);
+                }
+
+                /**
+                 * Add a relation to the pbf.
+                 *
+                 * A call to this method won't write the way to the file directly but
+                 * cache it for later bulk-writing. Calling final() ensures that everything
+                 * gets written and every file pointer is closed.
+                 */
+                void relation(const osmium::Relation& relation) {
+                    // first of we check the contents-counter which may flush the cached relations to
+                    // disk if the limit is reached. This call also increases the contents-counter
+                    check_block_contents_counter();
+
+                    // if no PrimitiveGroup for relations has been added, add one and save the pointer
+                    if (!pbf_relations) {
+                        pbf_relations = pbf_primitive_block.add_primitivegroup();
+                    }
+
+                    write_relation(relation);
+                }
+
+                /**
+                 * Finalize the writing process, flush any open primitive blocks to the file and
+                 * close the file.
+                 */
+                void close() override final {
+                    if (debug && has_debug_level(1)) {
+                        std::cerr << "finishing" << std::endl;
+                    }
+
+                    // if the current block contains any elements, flush it to the protobuf
+                    if (primitive_block_contents > 0) {
+                        store_primitive_block();
+                    }
+
+                    std::promise<std::string> promise;
+                    m_output_queue.push(promise.get_future());
+                    promise.set_value(std::string());
+                }
+
+            }; // class PBFOutputFormat
+
+            namespace {
+
+                const bool registered_pbf_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::pbf,
+                    [](const osmium::io::File& file, data_queue_type& output_queue) {
+                        return new osmium::io::detail::PBFOutputFormat(file, output_queue);
+                });
+
+            } // anonymous namespace
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_PBF_OUTPUT_FORMAT_HPP
diff --git a/third_party/osmium/io/detail/pbf_parser.hpp b/third_party/osmium/io/detail/pbf_parser.hpp
new file mode 100644
index 0000000..201c57c
--- /dev/null
+++ b/third_party/osmium/io/detail/pbf_parser.hpp
@@ -0,0 +1,449 @@
+#ifndef OSMIUM_IO_DETAIL_PBF_PRIMITIVE_BLOCK_PARSER_HPP
+#define OSMIUM_IO_DETAIL_PBF_PRIMITIVE_BLOCK_PARSER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <algorithm>
+
+#include <osmpbf/osmpbf.h>
+
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
+#include <osmium/io/detail/zlib.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            class PBFPrimitiveBlockParser {
+
+                static constexpr size_t initial_buffer_size = 2 * 1024 * 1024;
+
+                const std::string& m_data;
+
+                const OSMPBF::StringTable* m_stringtable;
+                int64_t m_lon_offset;
+                int64_t m_lat_offset;
+                int64_t m_date_factor;
+                int32_t m_granularity;
+
+                osmium::osm_entity_bits::type m_read_types;
+
+                osmium::memory::Buffer m_buffer;
+
+                PBFPrimitiveBlockParser(const PBFPrimitiveBlockParser&) = delete;
+                PBFPrimitiveBlockParser(PBFPrimitiveBlockParser&&) = delete;
+
+                PBFPrimitiveBlockParser& operator=(const PBFPrimitiveBlockParser&) = delete;
+                PBFPrimitiveBlockParser& operator=(PBFPrimitiveBlockParser&&) = delete;
+
+            public:
+
+                explicit PBFPrimitiveBlockParser(const std::string& data, osmium::osm_entity_bits::type read_types) :
+                    m_data(data),
+                    m_stringtable(nullptr),
+                    m_lon_offset(0),
+                    m_lat_offset(0),
+                    m_date_factor(1000),
+                    m_granularity(100),
+                    m_read_types(read_types),
+                    m_buffer(initial_buffer_size) {
+                }
+
+                ~PBFPrimitiveBlockParser() = default;
+
+                osmium::memory::Buffer operator()() {
+                    OSMPBF::PrimitiveBlock pbf_primitive_block;
+                    if (!pbf_primitive_block.ParseFromString(m_data)) {
+                        throw osmium::pbf_error("failed to parse PrimitiveBlock");
+                    }
+
+                    m_stringtable = &pbf_primitive_block.stringtable();
+                    m_lon_offset  = pbf_primitive_block.lon_offset();
+                    m_lat_offset  = pbf_primitive_block.lat_offset();
+                    m_date_factor = pbf_primitive_block.date_granularity() / 1000;
+                    m_granularity = pbf_primitive_block.granularity();
+
+                    for (int i=0; i < pbf_primitive_block.primitivegroup_size(); ++i) {
+                        const OSMPBF::PrimitiveGroup& group = pbf_primitive_block.primitivegroup(i);
+
+                        if (group.has_dense())  {
+                            if (m_read_types & osmium::osm_entity_bits::node) parse_dense_node_group(group);
+                        } else if (group.ways_size() != 0) {
+                            if (m_read_types & osmium::osm_entity_bits::way) parse_way_group(group);
+                        } else if (group.relations_size() != 0) {
+                            if (m_read_types & osmium::osm_entity_bits::relation) parse_relation_group(group);
+                        } else if (group.nodes_size() != 0) {
+                            if (m_read_types & osmium::osm_entity_bits::node) parse_node_group(group);
+                        } else {
+                            throw osmium::pbf_error("group of unknown type");
+                        }
+                    }
+
+                    return std::move(m_buffer);
+                }
+
+            private:
+
+                template <class TBuilder, class TPBFObject>
+                void parse_attributes(TBuilder& builder, const TPBFObject& pbf_object) {
+                    auto& object = builder.object();
+
+                    object.set_id(pbf_object.id());
+
+                    if (pbf_object.has_info()) {
+                        object.set_version(static_cast_with_assert<object_version_type>(pbf_object.info().version()))
+                            .set_changeset(static_cast_with_assert<changeset_id_type>(pbf_object.info().changeset()))
+                            .set_timestamp(pbf_object.info().timestamp() * m_date_factor)
+                            .set_uid_from_signed(pbf_object.info().uid());
+                        if (pbf_object.info().has_visible()) {
+                            object.set_visible(pbf_object.info().visible());
+                        }
+                        builder.add_user(m_stringtable->s(static_cast_with_assert<int>(pbf_object.info().user_sid())));
+                    } else {
+                        builder.add_user("", 1);
+                    }
+                }
+
+                void parse_node_group(const OSMPBF::PrimitiveGroup& group) {
+                    for (int i=0; i < group.nodes_size(); ++i) {
+                        osmium::builder::NodeBuilder builder(m_buffer);
+                        const OSMPBF::Node& pbf_node = group.nodes(i);
+                        parse_attributes(builder, pbf_node);
+
+                        if (builder.object().visible()) {
+                            builder.object().set_location(osmium::Location(
+                                              (pbf_node.lon() * m_granularity + m_lon_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision),
+                                              (pbf_node.lat() * m_granularity + m_lat_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision)));
+                        }
+
+                        if (pbf_node.keys_size() > 0) {
+                            osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
+                            for (int tag=0; tag < pbf_node.keys_size(); ++tag) {
+                                tl_builder.add_tag(m_stringtable->s(static_cast<int>(pbf_node.keys(tag))),
+                                                   m_stringtable->s(static_cast<int>(pbf_node.vals(tag))));
+                            }
+                        }
+
+                        m_buffer.commit();
+                    }
+                }
+
+                void parse_way_group(const OSMPBF::PrimitiveGroup& group) {
+                    for (int i=0; i < group.ways_size(); ++i) {
+                        osmium::builder::WayBuilder builder(m_buffer);
+                        const OSMPBF::Way& pbf_way = group.ways(i);
+                        parse_attributes(builder, pbf_way);
+
+                        if (pbf_way.refs_size() > 0) {
+                            osmium::builder::WayNodeListBuilder wnl_builder(m_buffer, &builder);
+                            int64_t ref = 0;
+                            for (int n=0; n < pbf_way.refs_size(); ++n) {
+                                ref += pbf_way.refs(n);
+                                wnl_builder.add_node_ref(ref);
+                            }
+                        }
+
+                        if (pbf_way.keys_size() > 0) {
+                            osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
+                            for (int tag=0; tag < pbf_way.keys_size(); ++tag) {
+                                tl_builder.add_tag(m_stringtable->s(static_cast<int>(pbf_way.keys(tag))),
+                                                   m_stringtable->s(static_cast<int>(pbf_way.vals(tag))));
+                            }
+                        }
+
+                        m_buffer.commit();
+                    }
+                }
+
+                void parse_relation_group(const OSMPBF::PrimitiveGroup& group) {
+                    for (int i=0; i < group.relations_size(); ++i) {
+                        osmium::builder::RelationBuilder builder(m_buffer);
+                        const OSMPBF::Relation& pbf_relation = group.relations(i);
+                        parse_attributes(builder, pbf_relation);
+
+                        if (pbf_relation.types_size() > 0) {
+                            osmium::builder::RelationMemberListBuilder rml_builder(m_buffer, &builder);
+                            int64_t ref = 0;
+                            for (int n=0; n < pbf_relation.types_size(); ++n) {
+                                ref += pbf_relation.memids(n);
+                                rml_builder.add_member(osmpbf_membertype_to_item_type(pbf_relation.types(n)), ref, m_stringtable->s(pbf_relation.roles_sid(n)));
+                            }
+                        }
+
+                        if (pbf_relation.keys_size() > 0) {
+                            osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
+                            for (int tag=0; tag < pbf_relation.keys_size(); ++tag) {
+                                tl_builder.add_tag(m_stringtable->s(static_cast<int>(pbf_relation.keys(tag))),
+                                                   m_stringtable->s(static_cast<int>(pbf_relation.vals(tag))));
+                            }
+                        }
+
+                        m_buffer.commit();
+                    }
+                }
+
+                int add_tags(const OSMPBF::DenseNodes& dense, int n, osmium::builder::NodeBuilder* builder) {
+                    if (n >= dense.keys_vals_size()) {
+                        return n;
+                    }
+
+                    if (dense.keys_vals(n) == 0) {
+                        return n+1;
+                    }
+
+                    osmium::builder::TagListBuilder tl_builder(m_buffer, builder);
+
+                    while (n < dense.keys_vals_size()) {
+                        int tag_key_pos = dense.keys_vals(n++);
+
+                        if (tag_key_pos == 0) {
+                            break;
+                        }
+
+                        tl_builder.add_tag(m_stringtable->s(tag_key_pos),
+                                           m_stringtable->s(dense.keys_vals(n)));
+
+                        ++n;
+                    }
+
+                    return n;
+                }
+
+                void parse_dense_node_group(const OSMPBF::PrimitiveGroup& group) {
+                    int64_t last_dense_id        = 0;
+                    int64_t last_dense_latitude  = 0;
+                    int64_t last_dense_longitude = 0;
+                    int64_t last_dense_uid       = 0;
+                    int64_t last_dense_user_sid  = 0;
+                    int64_t last_dense_changeset = 0;
+                    int64_t last_dense_timestamp = 0;
+                    int     last_dense_tag       = 0;
+
+                    const OSMPBF::DenseNodes& dense = group.dense();
+
+                    for (int i=0; i < dense.id_size(); ++i) {
+                        bool visible = true;
+
+                        last_dense_id        += dense.id(i);
+                        last_dense_latitude  += dense.lat(i);
+                        last_dense_longitude += dense.lon(i);
+
+                        if (dense.has_denseinfo()) {
+                            last_dense_changeset += dense.denseinfo().changeset(i);
+                            last_dense_timestamp += dense.denseinfo().timestamp(i);
+                            last_dense_uid       += dense.denseinfo().uid(i);
+                            last_dense_user_sid  += dense.denseinfo().user_sid(i);
+                            if (dense.denseinfo().visible_size() > 0) {
+                                visible = dense.denseinfo().visible(i);
+                            }
+                            assert(last_dense_changeset >= 0);
+                            assert(last_dense_timestamp >= 0);
+                            assert(last_dense_uid >= -1);
+                            assert(last_dense_user_sid >= 0);
+                        }
+
+                        osmium::builder::NodeBuilder builder(m_buffer);
+                        osmium::Node& node = builder.object();
+
+                        node.set_id(last_dense_id);
+
+                        if (dense.has_denseinfo()) {
+                            auto v = dense.denseinfo().version(i);
+                            assert(v > 0);
+                            node.set_version(static_cast<osmium::object_version_type>(v));
+                            node.set_changeset(static_cast<osmium::changeset_id_type>(last_dense_changeset));
+                            node.set_timestamp(last_dense_timestamp * m_date_factor);
+                            node.set_uid_from_signed(static_cast<osmium::signed_user_id_type>(last_dense_uid));
+                            node.set_visible(visible);
+                            builder.add_user(m_stringtable->s(static_cast<int>(last_dense_user_sid)));
+                        } else {
+                            builder.add_user("", 1);
+                        }
+
+                        if (visible) {
+                            builder.object().set_location(osmium::Location(
+                                              (last_dense_longitude * m_granularity + m_lon_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision),
+                                              (last_dense_latitude  * m_granularity + m_lat_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision)));
+                        }
+
+                        last_dense_tag = add_tags(dense, last_dense_tag, &builder);
+                        m_buffer.commit();
+                    }
+                }
+
+            }; // class PBFPrimitiveBlockParser
+
+            /**
+             * PBF blobs can optionally be packed with the zlib algorithm.
+             * This function returns the raw data (if it was unpacked) or
+             * the unpacked data (if it was packed).
+             *
+             * @param input_data Reference to input data.
+             * @returns Unpacked data
+             * @throws osmium::pbf_error If there was a problem parsing the PBF
+             */
+            inline std::unique_ptr<const std::string> unpack_blob(const std::string& input_data) {
+                OSMPBF::Blob pbf_blob;
+                if (!pbf_blob.ParseFromString(input_data)) {
+                    throw osmium::pbf_error("failed to parse blob");
+                }
+
+                if (pbf_blob.has_raw()) {
+                    return std::unique_ptr<std::string>(pbf_blob.release_raw());
+                } else if (pbf_blob.has_zlib_data()) {
+                    auto raw_size = pbf_blob.raw_size();
+                    assert(raw_size >= 0);
+                    assert(raw_size <= OSMPBF::max_uncompressed_blob_size);
+                    return osmium::io::detail::zlib_uncompress(pbf_blob.zlib_data(), static_cast<unsigned long>(raw_size));
+                } else if (pbf_blob.has_lzma_data()) {
+                    throw osmium::pbf_error("lzma blobs not implemented");
+                } else {
+                    throw osmium::pbf_error("blob contains no data");
+                }
+            }
+
+            /**
+             * Parse blob as a HeaderBlock.
+             *
+             * @param input_buffer Blob data
+             * @returns Header object
+             * @throws osmium::pbf_error If there was a parsing error
+             */
+            inline osmium::io::Header parse_header_blob(const std::string& input_buffer) {
+                const std::unique_ptr<const std::string> data = unpack_blob(input_buffer);
+
+                OSMPBF::HeaderBlock pbf_header_block;
+                if (!pbf_header_block.ParseFromString(*data)) {
+                    throw osmium::pbf_error("failed to parse HeaderBlock");
+                }
+
+                osmium::io::Header header;
+                for (int i=0; i < pbf_header_block.required_features_size(); ++i) {
+                    const std::string& feature = pbf_header_block.required_features(i);
+
+                    if (feature == "OsmSchema-V0.6") continue;
+                    if (feature == "DenseNodes") {
+                        header.set("pbf_dense_nodes", true);
+                        continue;
+                    }
+                    if (feature == "HistoricalInformation") {
+                        header.set_has_multiple_object_versions(true);
+                        continue;
+                    }
+
+                    throw osmium::pbf_error(std::string("required feature not supported: ") + feature);
+                }
+
+                for (int i=0; i < pbf_header_block.optional_features_size(); ++i) {
+                    const std::string& feature = pbf_header_block.optional_features(i);
+                    header.set("pbf_optional_feature_" + std::to_string(i), feature);
+                }
+
+                if (pbf_header_block.has_writingprogram()) {
+                    header.set("generator", pbf_header_block.writingprogram());
+                }
+
+                if (pbf_header_block.has_bbox()) {
+                    const OSMPBF::HeaderBBox& pbf_bbox = pbf_header_block.bbox();
+                    const int64_t resolution_convert = OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision;
+                    osmium::Box box;
+                    box.extend(osmium::Location(pbf_bbox.left()  / resolution_convert, pbf_bbox.bottom() / resolution_convert));
+                    box.extend(osmium::Location(pbf_bbox.right() / resolution_convert, pbf_bbox.top()    / resolution_convert));
+                    header.add_box(box);
+                }
+
+                if (pbf_header_block.has_osmosis_replication_timestamp()) {
+                    header.set("osmosis_replication_timestamp", osmium::Timestamp(pbf_header_block.osmosis_replication_timestamp()).to_iso());
+                }
+
+                if (pbf_header_block.has_osmosis_replication_sequence_number()) {
+                    header.set("osmosis_replication_sequence_number", std::to_string(pbf_header_block.osmosis_replication_sequence_number()));
+                }
+
+                if (pbf_header_block.has_osmosis_replication_base_url()) {
+                    header.set("osmosis_replication_base_url", pbf_header_block.osmosis_replication_base_url());
+                }
+
+                return header;
+            }
+
+            class DataBlobParser {
+
+                std::string m_input_buffer;
+                osmium::osm_entity_bits::type m_read_types;
+
+            public:
+
+                DataBlobParser(std::string&& input_buffer, osmium::osm_entity_bits::type read_types) :
+                    m_input_buffer(std::move(input_buffer)),
+                    m_read_types(read_types) {
+                    if (input_buffer.size() > OSMPBF::max_uncompressed_blob_size) {
+                        throw osmium::pbf_error(std::string("invalid blob size: " + std::to_string(input_buffer.size())));
+                    }
+                }
+
+                DataBlobParser(const DataBlobParser& other) :
+                    m_input_buffer(std::move(other.m_input_buffer)),
+                    m_read_types(other.m_read_types) {
+                }
+
+                DataBlobParser& operator=(const DataBlobParser&) = delete;
+
+                osmium::memory::Buffer operator()() {
+                    const std::unique_ptr<const std::string> data = unpack_blob(m_input_buffer);
+                    PBFPrimitiveBlockParser parser(*data, m_read_types);
+                    return std::move(parser());
+                }
+
+            }; // class DataBlobParser
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_PBF_PRIMITIVE_BLOCK_PARSER_HPP
diff --git a/third_party/osmium/io/detail/pbf_stringtable.hpp b/third_party/osmium/io/detail/pbf_stringtable.hpp
new file mode 100644
index 0000000..6f6c54c
--- /dev/null
+++ b/third_party/osmium/io/detail/pbf_stringtable.hpp
@@ -0,0 +1,204 @@
+#ifndef OSMIUM_IO_DETAIL_PBF_STRINGTABLE_HPP
+#define OSMIUM_IO_DETAIL_PBF_STRINGTABLE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstdint>
+#include <iterator>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <osmpbf/osmpbf.h>
+
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            /**
+             * StringTable management for PBF writer
+             *
+             * All strings are stored as indexes to rows in a StringTable. The StringTable contains
+             * one row for each used string, so strings that are used multiple times need to be
+             * stored only once. The StringTable is sorted by usage-count, so the most often used
+             * string is stored at index 1.
+             */
+            class StringTable {
+
+            public:
+
+                /// type for string IDs (interim and final)
+                typedef uint16_t string_id_type;
+
+            private:
+
+                /**
+                 * this is the struct used to build the StringTable. It is stored as
+                 * the value-part in the strings-map.
+                 *
+                 * when a new string is added to the map, its count is set to 0 and
+                 * the interim_id is set to the current size of the map. This interim_id
+                 * is then stored into the pbf-objects.
+                 *
+                 * before the PrimitiveBlock is serialized, the map is sorted by count
+                 * and stored into the pbf-StringTable. Afterwards the interim-ids are
+                 * mapped to the "real" id in the StringTable.
+                 *
+                 * this way often used strings get lower ids in the StringTable. As the
+                 * protobuf-serializer stores numbers in variable bit-lengths, lower
+                 * IDs means less used space in the resulting file.
+                 */
+                struct string_info {
+
+                    /// number of occurrences of this string
+                    uint16_t count;
+
+                    /// an intermediate-id
+                    string_id_type interim_id;
+
+                }; // struct string_info
+
+                /**
+                 * Interim StringTable, storing all strings that should be written to
+                 * the StringTable once the block is written to disk.
+                 */
+                typedef std::map<std::string, string_info> string2string_info_type;
+                string2string_info_type m_strings;
+
+                /**
+                 * This vector is used to map the interim IDs to real StringTable IDs after
+                 * writing all strings to the StringTable.
+                 */
+                typedef std::vector<string_id_type> interim_id2id_type;
+                interim_id2id_type m_id2id_map;
+
+                size_t m_size = 0;
+
+            public:
+
+                StringTable() {
+                }
+
+                friend bool operator<(const string_info& lhs, const string_info& rhs) {
+                    return lhs.count > rhs.count;
+                }
+
+                /**
+                 * record a string in the interim StringTable if it's missing, otherwise just increase its counter,
+                 * return the interim-id assigned to the string.
+                 */
+                string_id_type record_string(const std::string& string) {
+                    string_info& info = m_strings[string];
+                    if (info.interim_id == 0) {
+                        ++m_size;
+                        info.interim_id = static_cast_with_assert<string_id_type>(m_size);
+                    } else {
+                        info.count++;
+                    }
+                    return info.interim_id;
+                }
+
+                /**
+                 * Sort the interim StringTable and store it to the real protobuf StringTable.
+                 * while storing to the real table, this function fills the id2id_map with
+                 * pairs, mapping the interim-ids to final and real StringTable ids.
+                 *
+                 * Note that the m_strings table is a std::map and as such is sorted lexicographically.
+                 * When the transformation into the sortedby multimap is done, it gets sorted by
+                 * the count. The end result (at least with the glibc standard container/algorithm
+                 * implementation) is that the string table is sorted first by reverse count (ie descending)
+                 * and then by reverse lexicographic order.
+                 */
+                void store_stringtable(OSMPBF::StringTable* st) {
+                    // add empty StringTable entry at index 0
+                    // StringTable index 0 is reserved as delimiter in the densenodes key/value list
+                    // this line also ensures that there's always a valid StringTable
+                    st->add_s("");
+
+                    std::multimap<string_info, std::string> sortedbycount;
+
+                    m_id2id_map.resize(m_size+1);
+
+                    std::transform(m_strings.begin(), m_strings.end(),
+                                std::inserter(sortedbycount, sortedbycount.begin()),
+                                [](const std::pair<std::string, string_info>& p) {
+                                        return std::pair<string_info, std::string>(p.second, p.first);
+                                });
+
+                    string_id_type n=0;
+
+                    for (const auto& mapping : sortedbycount) {
+                        // add the string of the current item to the pbf StringTable
+                        st->add_s(mapping.second);
+
+                        // store the mapping from the interim-id to the real id
+                        m_id2id_map[mapping.first.interim_id] = ++n;
+                    }
+                }
+
+                /**
+                 * Map from an interim ID to a real string ID.
+                 */
+                string_id_type map_string_id(const string_id_type interim_id) const {
+                    return m_id2id_map[interim_id];
+                }
+
+                template <typename T>
+                string_id_type map_string_id(const T interim_id) const {
+                    return map_string_id(static_cast_with_assert<string_id_type>(interim_id));
+                }
+
+                /**
+                 * Clear the stringtable, preparing for the next block.
+                 */
+                void clear() {
+                    m_strings.clear();
+                    m_id2id_map.clear();
+                    m_size = 0;
+                }
+
+            }; // class StringTable
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_PBF_STRINGTABLE_HPP
diff --git a/third_party/osmium/io/detail/read_thread.hpp b/third_party/osmium/io/detail/read_thread.hpp
new file mode 100644
index 0000000..7c37139
--- /dev/null
+++ b/third_party/osmium/io/detail/read_thread.hpp
@@ -0,0 +1,106 @@
+#ifndef OSMIUM_IO_DETAIL_READ_THREAD_HPP
+#define OSMIUM_IO_DETAIL_READ_THREAD_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <atomic>
+#include <chrono>
+#include <ratio>
+#include <string>
+#include <thread>
+#include <utility>
+
+#include <osmium/io/compression.hpp>
+#include <osmium/thread/queue.hpp>
+#include <osmium/thread/util.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            class ReadThread {
+
+                osmium::thread::Queue<std::string>& m_queue;
+                osmium::io::Decompressor* m_decompressor;
+
+                // If this is set in the main thread, we have to wrap up at the
+                // next possible moment.
+                std::atomic<bool>& m_done;
+
+            public:
+
+                explicit ReadThread(osmium::thread::Queue<std::string>& queue, osmium::io::Decompressor* decompressor, std::atomic<bool>& done) :
+                    m_queue(queue),
+                    m_decompressor(decompressor),
+                    m_done(done) {
+                }
+
+                bool operator()() {
+                    osmium::thread::set_thread_name("_osmium_input");
+
+                    try {
+                        while (!m_done) {
+                            std::string data {m_decompressor->read()};
+                            if (data.empty()) {
+                                m_queue.push(std::move(data));
+                                break;
+                            }
+                            m_queue.push(std::move(data));
+                            while (m_queue.size() > 10 && !m_done) {
+                                std::this_thread::sleep_for(std::chrono::milliseconds(10));
+                            }
+                        }
+
+                        m_decompressor->close();
+                    } catch (...) {
+                        // If there is an exception in this thread, we make sure
+                        // to push an empty string onto the queue to signal the
+                        // end-of-data to the reading thread so that it will not
+                        // hang. Then we re-throw the exception.
+                        m_queue.push(std::string());
+                        throw;
+                    }
+                    return true;
+                }
+
+            }; // class ReadThread
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_READ_THREAD_HPP
diff --git a/third_party/osmium/io/detail/read_write.hpp b/third_party/osmium/io/detail/read_write.hpp
new file mode 100644
index 0000000..a949296
--- /dev/null
+++ b/third_party/osmium/io/detail/read_write.hpp
@@ -0,0 +1,156 @@
+#ifndef OSMIUM_IO_DETAIL_READ_WRITE_HPP
+#define OSMIUM_IO_DETAIL_READ_WRITE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cerrno>
+#include <cstddef>
+#include <fcntl.h>
+#include <string>
+#include <system_error>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#else
+# include <io.h>
+typedef int ssize_t;
+#endif
+
+#include <osmium/io/overwrite.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        /**
+         * @brief Namespace for Osmium internal use
+         */
+        namespace detail {
+
+            /**
+             * Open file for writing. If the file exists, it is truncated, if
+             * not, it is created. If the file name is empty or "-", no file
+             * is opened and the stdout file descriptor (1) is returned.
+             *
+             * @param filename Name of file to be opened.
+             * @param allow_overwrite If the file exists, should it be overwritten?
+             * @returns File descriptor of open file.
+             * @throws system_error if the file can't be opened.
+             */
+            inline int open_for_writing(const std::string& filename, osmium::io::overwrite allow_overwrite = osmium::io::overwrite::no) {
+                if (filename == "" || filename == "-") {
+                    return 1; // stdout
+                } else {
+                    int flags = O_WRONLY | O_CREAT;
+                    if (allow_overwrite == osmium::io::overwrite::allow) {
+                        flags |= O_TRUNC;
+                    } else {
+                        flags |= O_EXCL;
+                    }
+#ifdef _WIN32
+                    flags |= O_BINARY;
+#endif
+                    int fd = ::open(filename.c_str(), flags, 0666);
+                    if (fd < 0) {
+                        throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
+                    }
+                    return fd;
+                }
+            }
+
+            /**
+             * Open file for reading. If the file name is empty or "-", no file
+             * is opened and the stdin file descriptor (0) is returned.
+             *
+             * @param filename Name of file to be opened.
+             * @returns File descriptor of open file.
+             * @throws system_error if the file can't be opened.
+             */
+            inline int open_for_reading(const std::string& filename) {
+                if (filename == "" || filename == "-") {
+                    return 0; // stdin
+                } else {
+                    int flags = O_RDONLY;
+#ifdef _WIN32
+                    flags |= O_BINARY;
+#endif
+                    int fd = ::open(filename.c_str(), flags);
+                    if (fd < 0) {
+                        throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
+                    }
+                    return fd;
+                }
+            }
+
+            /**
+             * Writes the given number of bytes from the output_buffer to the file descriptor.
+             * This is just a wrapper around write(2), because write(2) can write less than
+             * the given number of bytes.
+             *
+             * @param fd File descriptor.
+             * @param output_buffer Buffer with data to be written. Must be at least size bytes long.
+             * @param size Number of bytes to write.
+             * @throws std::system_error On error.
+             */
+            inline void reliable_write(const int fd, const unsigned char* output_buffer, const size_t size) {
+                size_t offset = 0;
+                do {
+                    ssize_t length = ::write(fd, output_buffer + offset, size - offset);
+                    if (length < 0) {
+                        throw std::system_error(errno, std::system_category(), "Write failed");
+                    }
+                    offset += static_cast<size_t>(length);
+                } while (offset < size);
+            }
+
+            /**
+             * Writes the given number of bytes from the output_buffer to the file descriptor.
+             * This is just a wrapper around write(2), because write(2) can write less than
+             * the given number of bytes.
+             *
+             * @param fd File descriptor.
+             * @param output_buffer Buffer with data to be written. Must be at least size bytes long.
+             * @param size Number of bytes to write.
+             * @throws std::system_error On error.
+             */
+            inline void reliable_write(const int fd, const char* output_buffer, const size_t size) {
+                reliable_write(fd, reinterpret_cast<const unsigned char*>(output_buffer), size);
+            }
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_READ_WRITE_HPP
diff --git a/third_party/osmium/io/detail/write_thread.hpp b/third_party/osmium/io/detail/write_thread.hpp
new file mode 100644
index 0000000..49b7b5d
--- /dev/null
+++ b/third_party/osmium/io/detail/write_thread.hpp
@@ -0,0 +1,86 @@
+#ifndef OSMIUM_IO_DETAIL_WRITE_THREAD_HPP
+#define OSMIUM_IO_DETAIL_WRITE_THREAD_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <future>
+#include <string>
+
+#include <osmium/io/compression.hpp>
+#include <osmium/io/detail/output_format.hpp>
+#include <osmium/thread/util.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            class WriteThread {
+
+                typedef osmium::io::detail::data_queue_type data_queue_type;
+
+                data_queue_type& m_input_queue;
+                osmium::io::Compressor* m_compressor;
+
+            public:
+
+                explicit WriteThread(data_queue_type& input_queue, osmium::io::Compressor* compressor) :
+                    m_input_queue(input_queue),
+                    m_compressor(compressor) {
+                }
+
+                bool operator()() {
+                    osmium::thread::set_thread_name("_osmium_output");
+
+                    std::future<std::string> data_future;
+                    std::string data;
+                    do {
+                        m_input_queue.wait_and_pop(data_future);
+                        data = data_future.get();
+                        m_compressor->write(data);
+                    } while (!data.empty());
+
+                    m_compressor->close();
+                    return true;
+                }
+
+            }; // class WriteThread
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_WRITE_THREAD_HPP
diff --git a/third_party/osmium/io/detail/xml_input_format.hpp b/third_party/osmium/io/detail/xml_input_format.hpp
new file mode 100644
index 0000000..1564b78
--- /dev/null
+++ b/third_party/osmium/io/detail/xml_input_format.hpp
@@ -0,0 +1,726 @@
+#ifndef OSMIUM_IO_DETAIL_XML_INPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_XML_INPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#define OSMIUM_LINK_WITH_LIBS_EXPAT -lexpat
+
+#include <atomic>
+#include <cassert>
+#include <chrono>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <exception>
+#include <future>
+#include <iostream>
+#include <memory>
+#include <ratio>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <thread>
+#include <utility>
+
+#include <expat.h>
+
+#include <osmium/builder/builder.hpp>
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/io/detail/input_format.hpp>
+#include <osmium/io/error.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/thread/queue.hpp>
+#include <osmium/thread/util.hpp>
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+    /**
+     * Exception thrown when the XML parser failed. The exception contains
+     * information about the place where the error happened and the type of
+     * error.
+     */
+    struct xml_error : public io_error {
+
+        unsigned long line;
+        unsigned long column;
+        XML_Error error_code;
+        std::string error_string;
+
+        xml_error(XML_Parser parser) :
+            io_error(std::string("XML parsing error at line ")
+                    + std::to_string(XML_GetCurrentLineNumber(parser))
+                    + ", column "
+                    + std::to_string(XML_GetCurrentColumnNumber(parser))
+                    + ": "
+                    + XML_ErrorString(XML_GetErrorCode(parser))),
+            line(XML_GetCurrentLineNumber(parser)),
+            column(XML_GetCurrentColumnNumber(parser)),
+            error_code(XML_GetErrorCode(parser)),
+            error_string(XML_ErrorString(error_code)) {
+        }
+
+    }; // struct xml_error
+
+    struct format_version_error : public io_error {
+
+        std::string version;
+
+        explicit format_version_error() :
+            io_error("Can not read file without version (missing version attribute on osm element)."),
+            version() {
+        }
+
+        explicit format_version_error(const char* v) :
+            io_error(std::string("Can not read file with version ") + v),
+            version(v) {
+        }
+
+    }; // struct format_version_error
+
+    namespace io {
+
+        class File;
+
+        namespace detail {
+
+            /**
+             * Once the header is fully parsed this exception will be thrown if
+             * the caller is not interested in anything else except the header.
+             * It will break off the parsing at this point.
+             *
+             * This exception is never seen by user code, it is caught internally.
+             */
+            class ParserIsDone : std::exception {
+            };
+
+            class XMLParser {
+
+                static constexpr int buffer_size = 10 * 1000 * 1000;
+
+                enum class context {
+                    root,
+                    top,
+                    node,
+                    way,
+                    relation,
+                    changeset,
+                    ignored_node,
+                    ignored_way,
+                    ignored_relation,
+                    ignored_changeset,
+                    in_object
+                }; // enum class context
+
+                context m_context;
+                context m_last_context;
+
+                /**
+                 * This is used only for change files which contain create, modify,
+                 * and delete sections.
+                 */
+                bool m_in_delete_section;
+
+                osmium::io::Header m_header;
+
+                osmium::memory::Buffer m_buffer;
+
+                std::unique_ptr<osmium::builder::NodeBuilder>               m_node_builder;
+                std::unique_ptr<osmium::builder::WayBuilder>                m_way_builder;
+                std::unique_ptr<osmium::builder::RelationBuilder>           m_relation_builder;
+                std::unique_ptr<osmium::builder::ChangesetBuilder>          m_changeset_builder;
+
+                std::unique_ptr<osmium::builder::TagListBuilder>            m_tl_builder;
+                std::unique_ptr<osmium::builder::WayNodeListBuilder>        m_wnl_builder;
+                std::unique_ptr<osmium::builder::RelationMemberListBuilder> m_rml_builder;
+
+                osmium::thread::Queue<std::string>& m_input_queue;
+                osmium::thread::Queue<osmium::memory::Buffer>& m_queue;
+                std::promise<osmium::io::Header>& m_header_promise;
+
+                osmium::osm_entity_bits::type m_read_types;
+
+                std::atomic<bool>& m_done;
+
+                /**
+                 * A C++ wrapper for the Expat parser that makes sure no memory is leaked.
+                 */
+                template <class T>
+                class ExpatXMLParser {
+
+                    XML_Parser m_parser;
+
+                    static void XMLCALL start_element_wrapper(void* data, const XML_Char* element, const XML_Char** attrs) {
+                        static_cast<XMLParser*>(data)->start_element(element, attrs);
+                    }
+
+                    static void XMLCALL end_element_wrapper(void* data, const XML_Char* element) {
+                        static_cast<XMLParser*>(data)->end_element(element);
+                    }
+
+                public:
+
+                    ExpatXMLParser(T* callback_object) :
+                        m_parser(XML_ParserCreate(nullptr)) {
+                        if (!m_parser) {
+                            throw osmium::io_error("Internal error: Can not create parser");
+                        }
+                        XML_SetUserData(m_parser, callback_object);
+                        XML_SetElementHandler(m_parser, start_element_wrapper, end_element_wrapper);
+                    }
+
+                    ExpatXMLParser(const ExpatXMLParser&) = delete;
+                    ExpatXMLParser(ExpatXMLParser&&) = delete;
+
+                    ExpatXMLParser& operator=(const ExpatXMLParser&) = delete;
+                    ExpatXMLParser& operator=(ExpatXMLParser&&) = delete;
+
+                    ~ExpatXMLParser() {
+                        XML_ParserFree(m_parser);
+                    }
+
+                    void operator()(const std::string& data, bool last) {
+                        if (XML_Parse(m_parser, data.data(), static_cast_with_assert<int>(data.size()), last) == XML_STATUS_ERROR) {
+                            throw osmium::xml_error(m_parser);
+                        }
+                    }
+
+                }; // class ExpatXMLParser
+
+                /**
+                 * A helper class that makes sure a promise is kept. It stores
+                 * a reference to some piece of data and to a promise and, on
+                 * destruction, sets the value of the promise from the data.
+                 */
+                template <class T>
+                class PromiseKeeper {
+
+                    T& m_data;
+                    std::promise<T>& m_promise;
+
+                public:
+
+                    PromiseKeeper(T& data, std::promise<T>& promise) :
+                        m_data(data),
+                        m_promise(promise) {
+                    }
+
+                    ~PromiseKeeper() {
+                        m_promise.set_value(m_data);
+                    }
+
+                }; // class PromiseKeeper
+
+            public:
+
+                explicit XMLParser(osmium::thread::Queue<std::string>& input_queue, osmium::thread::Queue<osmium::memory::Buffer>& queue, std::promise<osmium::io::Header>& header_promise, osmium::osm_entity_bits::type read_types, std::atomic<bool>& done) :
+                    m_context(context::root),
+                    m_last_context(context::root),
+                    m_in_delete_section(false),
+                    m_header(),
+                    m_buffer(buffer_size),
+                    m_node_builder(),
+                    m_way_builder(),
+                    m_relation_builder(),
+                    m_changeset_builder(),
+                    m_tl_builder(),
+                    m_wnl_builder(),
+                    m_rml_builder(),
+                    m_input_queue(input_queue),
+                    m_queue(queue),
+                    m_header_promise(header_promise),
+                    m_read_types(read_types),
+                    m_done(done) {
+                }
+
+                /**
+                 * The copy constructor is needed for storing XMLParser in a std::function.
+                 * The copy will look the same as if it has been initialized with the
+                 * same parameters as the original. Any state changes in the original will
+                 * not be reflected in the copy.
+                 */
+                XMLParser(const XMLParser& other) :
+                    m_context(context::root),
+                    m_last_context(context::root),
+                    m_in_delete_section(false),
+                    m_header(),
+                    m_buffer(buffer_size),
+                    m_node_builder(),
+                    m_way_builder(),
+                    m_relation_builder(),
+                    m_changeset_builder(),
+                    m_tl_builder(),
+                    m_wnl_builder(),
+                    m_rml_builder(),
+                    m_input_queue(other.m_input_queue),
+                    m_queue(other.m_queue),
+                    m_header_promise(other.m_header_promise),
+                    m_read_types(other.m_read_types),
+                    m_done(other.m_done) {
+                }
+
+                XMLParser(XMLParser&&) = default;
+
+                XMLParser& operator=(const XMLParser&) = delete;
+
+                XMLParser& operator=(XMLParser&&) = default;
+
+                ~XMLParser() = default;
+
+                bool operator()() {
+                    ExpatXMLParser<XMLParser> parser(this);
+                    PromiseKeeper<osmium::io::Header> promise_keeper(m_header, m_header_promise);
+                    bool last;
+                    do {
+                        std::string data;
+                        m_input_queue.wait_and_pop(data);
+                        last = data.empty();
+                        try {
+                            parser(data, last);
+                        } catch (ParserIsDone&) {
+                            return true;
+                        } catch (...) {
+                            m_queue.push(osmium::memory::Buffer()); // empty buffer to signify eof
+                            throw;
+                        }
+                    } while (!last && !m_done);
+                    if (m_buffer.committed() > 0) {
+                        m_queue.push(std::move(m_buffer));
+                    }
+                    m_queue.push(osmium::memory::Buffer()); // empty buffer to signify eof
+                    return true;
+                }
+
+            private:
+
+                const char* init_object(osmium::OSMObject& object, const XML_Char** attrs) {
+                    static const char* empty = "";
+                    const char* user = empty;
+
+                    if (m_in_delete_section) {
+                        object.set_visible(false);
+                    }
+
+                    osmium::Location location;
+                    for (int count = 0; attrs[count]; count += 2) {
+                        if (!strcmp(attrs[count], "lon")) {
+                            location.set_lon(std::atof(attrs[count+1])); // XXX doesn't detect garbage after the number
+                        } else if (!strcmp(attrs[count], "lat")) {
+                            location.set_lat(std::atof(attrs[count+1])); // XXX doesn't detect garbage after the number
+                        } else if (!strcmp(attrs[count], "user")) {
+                            user = attrs[count+1];
+                        } else {
+                            object.set_attribute(attrs[count], attrs[count+1]);
+                        }
+                    }
+
+                    if (location && object.type() == osmium::item_type::node) {
+                        static_cast<osmium::Node&>(object).set_location(location);
+                    }
+
+                    return user;
+                }
+
+                void init_changeset(osmium::builder::ChangesetBuilder* builder, const XML_Char** attrs) {
+                    static const char* empty = "";
+                    const char* user = empty;
+                    osmium::Changeset& new_changeset = builder->object();
+
+                    osmium::Location min;
+                    osmium::Location max;
+                    for (int count = 0; attrs[count]; count += 2) {
+                        if (!strcmp(attrs[count], "min_lon")) {
+                            min.set_lon(atof(attrs[count+1]));
+                        } else if (!strcmp(attrs[count], "min_lat")) {
+                            min.set_lat(atof(attrs[count+1]));
+                        } else if (!strcmp(attrs[count], "max_lon")) {
+                            max.set_lon(atof(attrs[count+1]));
+                        } else if (!strcmp(attrs[count], "max_lat")) {
+                            max.set_lat(atof(attrs[count+1]));
+                        } else if (!strcmp(attrs[count], "user")) {
+                            user = attrs[count+1];
+                        } else {
+                            new_changeset.set_attribute(attrs[count], attrs[count+1]);
+                        }
+                    }
+
+                    new_changeset.bounds().extend(min);
+                    new_changeset.bounds().extend(max);
+
+                    builder->add_user(user);
+                }
+
+                void check_tag(osmium::builder::Builder* builder, const XML_Char* element, const XML_Char** attrs) {
+                    if (!strcmp(element, "tag")) {
+                        m_wnl_builder.reset();
+                        m_rml_builder.reset();
+
+                        const char* key = "";
+                        const char* value = "";
+                        for (int count = 0; attrs[count]; count += 2) {
+                            if (attrs[count][0] == 'k' && attrs[count][1] == 0) {
+                                key = attrs[count+1];
+                            } else if (attrs[count][0] == 'v' && attrs[count][1] == 0) {
+                                value = attrs[count+1];
+                            }
+                        }
+                        if (!m_tl_builder) {
+                            m_tl_builder = std::unique_ptr<osmium::builder::TagListBuilder>(new osmium::builder::TagListBuilder(m_buffer, builder));
+                        }
+                        m_tl_builder->add_tag(key, value);
+                    }
+                }
+
+                void header_is_done() {
+                    if (m_read_types == osmium::osm_entity_bits::nothing) {
+                        throw ParserIsDone();
+                    }
+                }
+
+                void start_element(const XML_Char* element, const XML_Char** attrs) {
+                    switch (m_context) {
+                        case context::root:
+                            if (!strcmp(element, "osm") || !strcmp(element, "osmChange")) {
+                                if (!strcmp(element, "osmChange")) {
+                                    m_header.set_has_multiple_object_versions(true);
+                                }
+                                for (int count = 0; attrs[count]; count += 2) {
+                                    if (!strcmp(attrs[count], "version")) {
+                                        m_header.set("version", attrs[count+1]);
+                                        if (strcmp(attrs[count+1], "0.6")) {
+                                            throw osmium::format_version_error(attrs[count+1]);
+                                        }
+                                    } else if (!strcmp(attrs[count], "generator")) {
+                                        m_header.set("generator", attrs[count+1]);
+                                    }
+                                }
+                                if (m_header.get("version") == "") {
+                                    throw osmium::format_version_error();
+                                }
+                            }
+                            m_context = context::top;
+                            break;
+                        case context::top:
+                            assert(!m_tl_builder);
+                            if (!strcmp(element, "node")) {
+                                header_is_done();
+                                if (m_read_types & osmium::osm_entity_bits::node) {
+                                    m_node_builder = std::unique_ptr<osmium::builder::NodeBuilder>(new osmium::builder::NodeBuilder(m_buffer));
+                                    m_node_builder->add_user(init_object(m_node_builder->object(), attrs));
+                                    m_context = context::node;
+                                } else {
+                                    m_context = context::ignored_node;
+                                }
+                            } else if (!strcmp(element, "way")) {
+                                header_is_done();
+                                if (m_read_types & osmium::osm_entity_bits::way) {
+                                    m_way_builder = std::unique_ptr<osmium::builder::WayBuilder>(new osmium::builder::WayBuilder(m_buffer));
+                                    m_way_builder->add_user(init_object(m_way_builder->object(), attrs));
+                                    m_context = context::way;
+                                } else {
+                                    m_context = context::ignored_way;
+                                }
+                            } else if (!strcmp(element, "relation")) {
+                                header_is_done();
+                                if (m_read_types & osmium::osm_entity_bits::relation) {
+                                    m_relation_builder = std::unique_ptr<osmium::builder::RelationBuilder>(new osmium::builder::RelationBuilder(m_buffer));
+                                    m_relation_builder->add_user(init_object(m_relation_builder->object(), attrs));
+                                    m_context = context::relation;
+                                } else {
+                                    m_context = context::ignored_relation;
+                                }
+                            } else if (!strcmp(element, "changeset")) {
+                                header_is_done();
+                                if (m_read_types & osmium::osm_entity_bits::changeset) {
+                                    m_changeset_builder = std::unique_ptr<osmium::builder::ChangesetBuilder>(new osmium::builder::ChangesetBuilder(m_buffer));
+                                    init_changeset(m_changeset_builder.get(), attrs);
+                                    m_context = context::changeset;
+                                } else {
+                                    m_context = context::ignored_changeset;
+                                }
+                            } else if (!strcmp(element, "bounds")) {
+                                osmium::Location min;
+                                osmium::Location max;
+                                for (int count = 0; attrs[count]; count += 2) {
+                                    if (!strcmp(attrs[count], "minlon")) {
+                                        min.set_lon(atof(attrs[count+1]));
+                                    } else if (!strcmp(attrs[count], "minlat")) {
+                                        min.set_lat(atof(attrs[count+1]));
+                                    } else if (!strcmp(attrs[count], "maxlon")) {
+                                        max.set_lon(atof(attrs[count+1]));
+                                    } else if (!strcmp(attrs[count], "maxlat")) {
+                                        max.set_lat(atof(attrs[count+1]));
+                                    }
+                                }
+                                osmium::Box box;
+                                box.extend(min).extend(max);
+                                m_header.add_box(box);
+                            } else if (!strcmp(element, "delete")) {
+                                m_in_delete_section = true;
+                            }
+                            break;
+                        case context::node:
+                            m_last_context = context::node;
+                            m_context = context::in_object;
+                            check_tag(m_node_builder.get(), element, attrs);
+                            break;
+                        case context::way:
+                            m_last_context = context::way;
+                            m_context = context::in_object;
+                            if (!strcmp(element, "nd")) {
+                                m_tl_builder.reset();
+
+                                if (!m_wnl_builder) {
+                                    m_wnl_builder = std::unique_ptr<osmium::builder::WayNodeListBuilder>(new osmium::builder::WayNodeListBuilder(m_buffer, m_way_builder.get()));
+                                }
+
+                                for (int count = 0; attrs[count]; count += 2) {
+                                    if (!strcmp(attrs[count], "ref")) {
+                                        m_wnl_builder->add_node_ref(osmium::string_to_object_id(attrs[count+1]));
+                                    }
+                                }
+                            } else {
+                                check_tag(m_way_builder.get(), element, attrs);
+                            }
+                            break;
+                        case context::relation:
+                            m_last_context = context::relation;
+                            m_context = context::in_object;
+                            if (!strcmp(element, "member")) {
+                                m_tl_builder.reset();
+
+                                if (!m_rml_builder) {
+                                    m_rml_builder = std::unique_ptr<osmium::builder::RelationMemberListBuilder>(new osmium::builder::RelationMemberListBuilder(m_buffer, m_relation_builder.get()));
+                                }
+
+                                char type = 'x';
+                                object_id_type ref  = 0;
+                                const char* role = "";
+                                for (int count = 0; attrs[count]; count += 2) {
+                                    if (!strcmp(attrs[count], "type")) {
+                                        type = static_cast<char>(attrs[count+1][0]);
+                                    } else if (!strcmp(attrs[count], "ref")) {
+                                        ref = osmium::string_to_object_id(attrs[count+1]);
+                                    } else if (!strcmp(attrs[count], "role")) {
+                                        role = static_cast<const char*>(attrs[count+1]);
+                                    }
+                                }
+                                // XXX assert type, ref, role are set
+                                m_rml_builder->add_member(char_to_item_type(type), ref, role);
+                            } else {
+                                check_tag(m_relation_builder.get(), element, attrs);
+                            }
+                            break;
+                        case context::changeset:
+                            m_last_context = context::changeset;
+                            m_context = context::in_object;
+                            check_tag(m_changeset_builder.get(), element, attrs);
+                            break;
+                        case context::ignored_node:
+                            break;
+                        case context::ignored_way:
+                            break;
+                        case context::ignored_relation:
+                            break;
+                        case context::ignored_changeset:
+                            break;
+                        case context::in_object:
+                            assert(false); // should never be here
+                            break;
+                    }
+                }
+
+                void end_element(const XML_Char* element) {
+                    switch (m_context) {
+                        case context::root:
+                            assert(false); // should never be here
+                            break;
+                        case context::top:
+                            if (!strcmp(element, "osm") || !strcmp(element, "osmChange")) {
+                                header_is_done();
+                                m_context = context::root;
+                            } else if (!strcmp(element, "delete")) {
+                                m_in_delete_section = false;
+                            }
+                            break;
+                        case context::node:
+                            assert(!strcmp(element, "node"));
+                            m_tl_builder.reset();
+                            m_node_builder.reset();
+                            m_buffer.commit();
+                            m_context = context::top;
+                            flush_buffer();
+                            break;
+                        case context::way:
+                            assert(!strcmp(element, "way"));
+                            m_tl_builder.reset();
+                            m_wnl_builder.reset();
+                            m_way_builder.reset();
+                            m_buffer.commit();
+                            m_context = context::top;
+                            flush_buffer();
+                            break;
+                        case context::relation:
+                            assert(!strcmp(element, "relation"));
+                            m_tl_builder.reset();
+                            m_rml_builder.reset();
+                            m_relation_builder.reset();
+                            m_buffer.commit();
+                            m_context = context::top;
+                            flush_buffer();
+                            break;
+                        case context::changeset:
+                            assert(!strcmp(element, "changeset"));
+                            m_tl_builder.reset();
+                            m_changeset_builder.reset();
+                            m_buffer.commit();
+                            m_context = context::top;
+                            flush_buffer();
+                            break;
+                        case context::in_object:
+                            m_context = m_last_context;
+                            break;
+                        case context::ignored_node:
+                            if (!strcmp(element, "node")) {
+                                m_context = context::top;
+                            }
+                            break;
+                        case context::ignored_way:
+                            if (!strcmp(element, "way")) {
+                                m_context = context::top;
+                            }
+                            break;
+                        case context::ignored_relation:
+                            if (!strcmp(element, "relation")) {
+                                m_context = context::top;
+                            }
+                            break;
+                        case context::ignored_changeset:
+                            if (!strcmp(element, "changeset")) {
+                                m_context = context::top;
+                            }
+                            break;
+                    }
+                }
+
+                void flush_buffer() {
+                    if (m_buffer.capacity() - m_buffer.committed() < 1000 * 1000) {
+                        m_queue.push(std::move(m_buffer));
+                        osmium::memory::Buffer buffer(buffer_size);
+                        std::swap(m_buffer, buffer);
+                    }
+                }
+
+            }; // class XMLParser
+
+            class XMLInputFormat : public osmium::io::detail::InputFormat {
+
+                static constexpr size_t max_queue_size = 100;
+
+                osmium::thread::Queue<osmium::memory::Buffer> m_queue;
+                std::atomic<bool> m_done;
+                std::promise<osmium::io::Header> m_header_promise;
+                std::future<bool> m_parser_future;
+
+            public:
+
+                /**
+                 * Instantiate XML Parser
+                 *
+                 * @param file osmium::io::File instance describing file to be read from.
+                 * @param read_which_entities Which types of OSM entities (nodes, ways, relations, changesets) should be parsed?
+                 * @param input_queue String queue where data is read from.
+                 */
+                explicit XMLInputFormat(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) :
+                    osmium::io::detail::InputFormat(file, read_which_entities, input_queue),
+                    m_queue(max_queue_size, "xml_parser_results"),
+                    m_done(false),
+                    m_header_promise(),
+                    m_parser_future(std::async(std::launch::async, XMLParser(input_queue, m_queue, m_header_promise, read_which_entities, m_done))) {
+                }
+
+                ~XMLInputFormat() {
+                    try {
+                        close();
+                    } catch (...) {
+                        // ignore any exceptions at this point because destructor should not throw
+                    }
+                }
+
+                virtual osmium::io::Header header() override final {
+                    osmium::thread::check_for_exception(m_parser_future);
+                    return m_header_promise.get_future().get();
+                }
+
+                osmium::memory::Buffer read() override {
+                    osmium::memory::Buffer buffer;
+                    if (!m_done || !m_queue.empty()) {
+                        m_queue.wait_and_pop(buffer);
+                    }
+
+                    osmium::thread::check_for_exception(m_parser_future);
+                    return buffer;
+                }
+
+                void close() {
+                    m_done = true;
+                    osmium::thread::wait_until_done(m_parser_future);
+                }
+
+            }; // class XMLInputFormat
+
+            namespace {
+
+                const bool registered_xml_input = osmium::io::detail::InputFormatFactory::instance().register_input_format(osmium::io::file_format::xml,
+                    [](const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) {
+                        return new osmium::io::detail::XMLInputFormat(file, read_which_entities, input_queue);
+                });
+
+            } // anonymous namespace
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_XML_INPUT_FORMAT_HPP
diff --git a/third_party/osmium/io/detail/xml_output_format.hpp b/third_party/osmium/io/detail/xml_output_format.hpp
new file mode 100644
index 0000000..c8c7a38
--- /dev/null
+++ b/third_party/osmium/io/detail/xml_output_format.hpp
@@ -0,0 +1,481 @@
+#ifndef OSMIUM_IO_DETAIL_XML_OUTPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_XML_OUTPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <chrono>
+#include <cinttypes>
+#include <cstddef>
+#include <cstdio>
+#include <future>
+#include <iterator>
+#include <memory>
+#include <ratio>
+#include <string>
+#include <thread>
+#include <utility>
+
+#include <osmium/handler.hpp>
+#include <osmium/io/detail/output_format.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/collection.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/changeset.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/thread/pool.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            struct XMLWriteError {};
+
+            namespace {
+
+                void xml_string(std::string& out, const char* in) {
+                    for (; *in != '\0'; ++in) {
+                        switch(*in) {
+                            case '&':  out += "&";  break;
+                            case '\"': out += """; break;
+                            case '\'': out += "'"; break;
+                            case '<':  out += "<";   break;
+                            case '>':  out += ">";   break;
+                            default:   out += *in;      break;
+                        }
+                    }
+                }
+
+                const size_t tmp_buffer_size = 100;
+
+                template <typename T>
+                void oprintf(std::string& out, const char* format, T value) {
+                    char buffer[tmp_buffer_size+1];
+                    size_t max_size = sizeof(buffer)/sizeof(char);
+#ifndef NDEBUG
+                    int len =
+#endif
+#ifndef _MSC_VER
+                    snprintf(buffer, max_size, format, value);
+#else
+                    _snprintf(buffer, max_size, format, value);
+#endif
+                    assert(len > 0 && static_cast<size_t>(len) < max_size);
+                    out += buffer;
+                }
+
+            } // anonymous namespace
+
+            class XMLOutputBlock : public osmium::handler::Handler {
+
+                // operation (create, modify, delete) for osc files
+                enum class operation {
+                    op_none   = 0,
+                    op_create = 1,
+                    op_modify = 2,
+                    op_delete = 3
+                }; // enum class operation
+
+                osmium::memory::Buffer m_input_buffer;
+
+                std::string m_out;
+
+                operation m_last_op {operation::op_none};
+
+                const bool m_write_visible_flag;
+                const bool m_write_change_ops;
+
+                void write_spaces(int num) {
+                    for (; num!=0; --num) {
+                        m_out += ' ';
+                    }
+                }
+
+                void write_prefix() {
+                    if (m_write_change_ops) {
+                        write_spaces(4);
+                    } else {
+                        write_spaces(2);
+                    }
+                }
+
+                void write_meta(const osmium::OSMObject& object) {
+                    oprintf(m_out, " id=\"%" PRId64 "\"", object.id());
+
+                    if (object.version()) {
+                        oprintf(m_out, " version=\"%d\"", object.version());
+                    }
+
+                    if (object.timestamp()) {
+                        m_out += " timestamp=\"";
+                        m_out += object.timestamp().to_iso();
+                        m_out += "\"";
+                    }
+
+                    if (!object.user_is_anonymous()) {
+                        oprintf(m_out, " uid=\"%d\" user=\"", object.uid());
+                        xml_string(m_out, object.user());
+                        m_out += "\"";
+                    }
+
+                    if (object.changeset()) {
+                        oprintf(m_out, " changeset=\"%d\"", object.changeset());
+                    }
+
+                    if (m_write_visible_flag) {
+                        if (object.visible()) {
+                            m_out += " visible=\"true\"";
+                        } else {
+                            m_out += " visible=\"false\"";
+                        }
+                    }
+                }
+
+                void write_tags(const osmium::TagList& tags) {
+                    for (const auto& tag : tags) {
+                        write_prefix();
+                        m_out += "  <tag k=\"";
+                        xml_string(m_out, tag.key());
+                        m_out += "\" v=\"";
+                        xml_string(m_out, tag.value());
+                        m_out += "\"/>\n";
+                    }
+                }
+
+                void open_close_op_tag(const operation op = operation::op_none) {
+                    if (op == m_last_op) {
+                        return;
+                    }
+
+                    switch (m_last_op) {
+                        case operation::op_none:
+                            break;
+                        case operation::op_create:
+                            m_out += "  </create>\n";
+                            break;
+                        case operation::op_modify:
+                            m_out += "  </modify>\n";
+                            break;
+                        case operation::op_delete:
+                            m_out += "  </delete>\n";
+                            break;
+                    }
+
+                    switch (op) {
+                        case operation::op_none:
+                            break;
+                        case operation::op_create:
+                            m_out += "  <create>\n";
+                            break;
+                        case operation::op_modify:
+                            m_out += "  <modify>\n";
+                            break;
+                        case operation::op_delete:
+                            m_out += "  <delete>\n";
+                            break;
+                    }
+
+                    m_last_op = op;
+                }
+
+            public:
+
+                explicit XMLOutputBlock(osmium::memory::Buffer&& buffer, bool write_visible_flag, bool write_change_ops) :
+                    m_input_buffer(std::move(buffer)),
+                    m_write_visible_flag(write_visible_flag && !write_change_ops),
+                    m_write_change_ops(write_change_ops) {
+                }
+
+                XMLOutputBlock(const XMLOutputBlock&) = delete;
+                XMLOutputBlock& operator=(const XMLOutputBlock&) = delete;
+
+                XMLOutputBlock(XMLOutputBlock&&) = default;
+                XMLOutputBlock& operator=(XMLOutputBlock&&) = default;
+
+                std::string operator()() {
+                    osmium::apply(m_input_buffer.cbegin(), m_input_buffer.cend(), *this);
+
+                    if (m_write_change_ops) {
+                        open_close_op_tag();
+                    }
+
+                    std::string out;
+                    std::swap(out, m_out);
+                    return out;
+                }
+
+                void node(const osmium::Node& node) {
+                    if (m_write_change_ops) {
+                        open_close_op_tag(node.visible() ? (node.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete);
+                    }
+
+                    write_prefix();
+                    m_out += "<node";
+
+                    write_meta(node);
+
+                    if (node.location()) {
+                        m_out += " lat=\"";
+                        osmium::util::double2string(std::back_inserter(m_out), node.location().lat_without_check(), 7);
+                        m_out += "\" lon=\"";
+                        osmium::util::double2string(std::back_inserter(m_out), node.location().lon_without_check(), 7);
+                        m_out += "\"";
+                    }
+
+                    if (node.tags().empty()) {
+                        m_out += "/>\n";
+                        return;
+                    }
+
+                    m_out += ">\n";
+
+                    write_tags(node.tags());
+
+                    write_prefix();
+                    m_out += "</node>\n";
+                }
+
+                void way(const osmium::Way& way) {
+                    if (m_write_change_ops) {
+                        open_close_op_tag(way.visible() ? (way.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete);
+                    }
+
+                    write_prefix();
+                    m_out += "<way";
+                    write_meta(way);
+
+                    if (way.tags().empty() && way.nodes().empty()) {
+                        m_out += "/>\n";
+                        return;
+                    }
+
+                    m_out += ">\n";
+
+                    for (const auto& node_ref : way.nodes()) {
+                        write_prefix();
+                        oprintf(m_out, "  <nd ref=\"%" PRId64 "\"/>\n", node_ref.ref());
+                    }
+
+                    write_tags(way.tags());
+
+                    write_prefix();
+                    m_out += "</way>\n";
+                }
+
+                void relation(const osmium::Relation& relation) {
+                    if (m_write_change_ops) {
+                        open_close_op_tag(relation.visible() ? (relation.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete);
+                    }
+
+                    write_prefix();
+                    m_out += "<relation";
+                    write_meta(relation);
+
+                    if (relation.tags().empty() && relation.members().empty()) {
+                        m_out += "/>\n";
+                        return;
+                    }
+
+                    m_out += ">\n";
+
+                    for (const auto& member : relation.members()) {
+                        write_prefix();
+                        m_out += "  <member type=\"";
+                        m_out += item_type_to_name(member.type());
+                        oprintf(m_out, "\" ref=\"%" PRId64 "\" role=\"", member.ref());
+                        xml_string(m_out, member.role());
+                        m_out += "\"/>\n";
+                    }
+
+                    write_tags(relation.tags());
+
+                    write_prefix();
+                    m_out += "</relation>\n";
+                }
+
+                void changeset(const osmium::Changeset& changeset) {
+                    write_prefix();
+                    m_out += "<changeset";
+
+                    oprintf(m_out, " id=\"%" PRId32 "\"", changeset.id());
+
+                    if (changeset.created_at()) {
+                        m_out += " created_at=\"";
+                        m_out += changeset.created_at().to_iso();
+                        m_out += "\"";
+                    }
+
+                    oprintf(m_out, " num_changes=\"%" PRId32 "\"", changeset.num_changes());
+
+                    if (changeset.closed_at()) {
+                        m_out += " closed_at=\"";
+                        m_out += changeset.closed_at().to_iso();
+                        m_out += "\" open=\"false\"";
+                    } else {
+                        m_out += " open=\"true\"";
+                    }
+
+                    if (changeset.bounds()) {
+                        oprintf(m_out, " min_lon=\"%.7f\"", changeset.bounds().bottom_left().lon_without_check());
+                        oprintf(m_out, " min_lat=\"%.7f\"", changeset.bounds().bottom_left().lat_without_check());
+                        oprintf(m_out, " max_lon=\"%.7f\"", changeset.bounds().top_right().lon_without_check());
+                        oprintf(m_out, " max_lat=\"%.7f\"", changeset.bounds().top_right().lat_without_check());
+                    }
+
+                    if (!changeset.user_is_anonymous()) {
+                        m_out += " user=\"";
+                        xml_string(m_out, changeset.user());
+                        oprintf(m_out, "\" uid=\"%d\"", changeset.uid());
+                    }
+
+                    if (changeset.tags().empty()) {
+                        m_out += "/>\n";
+                        return;
+                    }
+
+                    m_out += ">\n";
+
+                    write_tags(changeset.tags());
+
+                    write_prefix();
+                    m_out += "</changeset>\n";
+                }
+
+            }; // class XMLOutputBlock
+
+            class XMLOutputFormat : public osmium::io::detail::OutputFormat, public osmium::handler::Handler {
+
+                bool m_write_visible_flag;
+
+            public:
+
+                XMLOutputFormat(const osmium::io::File& file, data_queue_type& output_queue) :
+                    OutputFormat(file, output_queue),
+                    m_write_visible_flag(file.has_multiple_object_versions() || m_file.is_true("force_visible_flag")) {
+                }
+
+                XMLOutputFormat(const XMLOutputFormat&) = delete;
+                XMLOutputFormat& operator=(const XMLOutputFormat&) = delete;
+
+                ~XMLOutputFormat() override final {
+                }
+
+                void write_buffer(osmium::memory::Buffer&& buffer) override final {
+                    m_output_queue.push(osmium::thread::Pool::instance().submit(XMLOutputBlock{std::move(buffer), m_write_visible_flag, m_file.is_true("xml_change_format")}));
+                }
+
+                void write_header(const osmium::io::Header& header) override final {
+                    std::string out = "<?xml version='1.0' encoding='UTF-8'?>\n";
+
+                    if (m_file.is_true("xml_change_format")) {
+                        out += "<osmChange version=\"0.6\" generator=\"";
+                        xml_string(out, header.get("generator").c_str());
+                        out += "\">\n";
+                    } else {
+                        out += "<osm version=\"0.6\"";
+
+                        std::string xml_josm_upload = header.get("xml_josm_upload");
+                        if (xml_josm_upload == "true" || xml_josm_upload == "false") {
+                            out += " upload=\"";
+                            out += xml_josm_upload;
+                            out += "\"";
+                        }
+                        out += " generator=\"";
+                        xml_string(out, header.get("generator").c_str());
+                        out += "\">\n";
+                    }
+
+                    for (const auto& box : header.boxes()) {
+                        out += "  <bounds";
+                        oprintf(out, " minlon=\"%.7f\"", box.bottom_left().lon());
+                        oprintf(out, " minlat=\"%.7f\"", box.bottom_left().lat());
+                        oprintf(out, " maxlon=\"%.7f\"", box.top_right().lon());
+                        oprintf(out, " maxlat=\"%.7f\"/>\n", box.top_right().lat());
+                    }
+
+                    std::promise<std::string> promise;
+                    m_output_queue.push(promise.get_future());
+                    promise.set_value(std::move(out));
+                }
+
+                void close() override final {
+                    {
+                        std::string out;
+                        if (m_file.is_true("xml_change_format")) {
+                            out += "</osmChange>\n";
+                        } else {
+                            out += "</osm>\n";
+                        }
+
+                        std::promise<std::string> promise;
+                        m_output_queue.push(promise.get_future());
+                        promise.set_value(std::move(out));
+                    }
+
+                    std::promise<std::string> promise;
+                    m_output_queue.push(promise.get_future());
+                    promise.set_value(std::string());
+                }
+
+            }; // class XMLOutputFormat
+
+            namespace {
+
+                const bool registered_xml_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::xml,
+                    [](const osmium::io::File& file, data_queue_type& output_queue) {
+                        return new osmium::io::detail::XMLOutputFormat(file, output_queue);
+                });
+
+            } // anonymous namespace
+
+        } // namespace detail
+
+    } // namespace output
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_XML_OUTPUT_FORMAT_HPP
diff --git a/third_party/osmium/io/detail/zlib.hpp b/third_party/osmium/io/detail/zlib.hpp
new file mode 100644
index 0000000..84ab86c
--- /dev/null
+++ b/third_party/osmium/io/detail/zlib.hpp
@@ -0,0 +1,99 @@
+#ifndef OSMIUM_IO_DETAIL_ZLIB_HPP
+#define OSMIUM_IO_DETAIL_ZLIB_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#define OSMIUM_LINK_WITH_LIBS_ZLIB -lz
+
+#include <memory>
+#include <stdexcept>
+#include <string>
+
+#include <zlib.h>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            /**
+             * Compress data using zlib.
+             *
+             * @param input Data to compress.
+             * @returns Compressed data.
+             */
+            inline std::string zlib_compress(const std::string& input) {
+                unsigned long output_size = ::compressBound(input.size());
+
+                std::string output(output_size, '\0');
+
+                if (::compress(reinterpret_cast<unsigned char*>(const_cast<char *>(output.data())),
+                               &output_size,
+                               reinterpret_cast<const unsigned char*>(input.data()),
+                               input.size()) != Z_OK) {
+                    throw std::runtime_error("failed to compress data");
+                }
+
+                output.resize(output_size);
+
+                return output;
+            }
+
+            /**
+             * Uncompress data using zlib.
+             *
+             * @param input Compressed input data.
+             * @param raw_size Size of uncompressed data.
+             * @returns Uncompressed data.
+             */
+            inline std::unique_ptr<std::string> zlib_uncompress(const std::string& input, unsigned long raw_size) {
+                auto output = std::unique_ptr<std::string>(new std::string(raw_size, '\0'));
+
+                if (::uncompress(reinterpret_cast<unsigned char*>(const_cast<char *>(output->data())),
+                                 &raw_size,
+                                 reinterpret_cast<const unsigned char*>(input.data()),
+                                 input.size()) != Z_OK) {
+                    throw std::runtime_error("failed to uncompress data");
+                }
+
+                return output;
+            }
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_ZLIB_HPP
diff --git a/third_party/osmium/io/error.hpp b/third_party/osmium/io/error.hpp
new file mode 100644
index 0000000..8fb9f05
--- /dev/null
+++ b/third_party/osmium/io/error.hpp
@@ -0,0 +1,57 @@
+#ifndef OSMIUM_IO_ERROR_HPP
+#define OSMIUM_IO_ERROR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <stdexcept>
+
+namespace osmium {
+
+    /**
+     * Exception thrown when some kind of input/output operation failed.
+     */
+    struct io_error : public std::runtime_error {
+
+        io_error(const std::string& what) :
+            std::runtime_error(what) {
+        }
+
+        io_error(const char* what) :
+            std::runtime_error(what) {
+        }
+
+    }; // struct io_error
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_ERROR_HPP
diff --git a/third_party/osmium/io/file.hpp b/third_party/osmium/io/file.hpp
new file mode 100644
index 0000000..21469b8
--- /dev/null
+++ b/third_party/osmium/io/file.hpp
@@ -0,0 +1,343 @@
+#ifndef OSMIUM_IO_FILE_HPP
+#define OSMIUM_IO_FILE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <stdexcept>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/file_compression.hpp>
+#include <osmium/util/options.hpp>
+
+namespace osmium {
+
+    /**
+     * @brief Everything related to input and output of OSM data.
+     */
+    namespace io {
+
+        namespace detail {
+
+            inline std::vector<std::string> split(const std::string& in, const char delim) {
+                std::vector<std::string> result;
+                std::stringstream ss(in);
+                std::string item;
+                while (std::getline(ss, item, delim)) {
+                    result.push_back(item);
+                }
+                return result;
+            }
+
+        } // namespace detail
+
+        /**
+         * This class describes an OSM file in one of several different formats.
+         *
+         * If the filename is empty or "-", this means stdin or stdout is used.
+         */
+        class File : public osmium::util::Options {
+
+        private:
+
+            std::string m_filename;
+
+            const char* m_buffer;
+            size_t m_buffer_size;
+
+            std::string m_format_string;
+
+            file_format m_file_format {file_format::unknown};
+
+            file_compression m_file_compression {file_compression::none};
+
+            bool m_has_multiple_object_versions {false};
+
+        public:
+
+            /**
+             * Create File using type and encoding from filename or given
+             * format specification.
+             *
+             * @param filename Filename including suffix. The type and encoding
+             *                 of the file will be taken from the suffix.
+             *                 An empty filename or "-" means stdin or stdout.
+             * @param format File format as string. See the description of the
+             *               parse_format() function for details.
+             */
+            explicit File(const std::string& filename = "", const std::string& format = "") :
+                Options(),
+                m_filename(filename),
+                m_buffer(nullptr),
+                m_buffer_size(0),
+                m_format_string(format) {
+
+                // stdin/stdout
+                if (filename == "" || filename == "-") {
+                    m_filename = "";
+                    default_settings_for_stdinout();
+                }
+
+                // filename is actually a URL
+                std::string protocol = m_filename.substr(0, m_filename.find_first_of(':'));
+                if (protocol == "http" || protocol == "https") {
+                    default_settings_for_url();
+                }
+
+                detect_format_from_suffix(m_filename);
+
+                if (format != "") {
+                    parse_format(format);
+                }
+            }
+
+            /**
+             * Create File using buffer pointer and size and type and encoding
+             * from given format specification.
+             *
+             * @param buffer Pointer to buffer with data.
+             * @param size   Size of buffer.
+             * @param format File format as string. See the description of the
+             *               parse_format() function for details.
+             */
+            explicit File(const char* buffer, size_t size, const std::string& format = "") :
+                Options(),
+                m_filename(),
+                m_buffer(buffer),
+                m_buffer_size(size),
+                m_format_string(format) {
+
+                default_settings_for_stdinout();
+
+                if (format != "") {
+                    parse_format(format);
+                }
+            }
+
+            File(const File&) = default;
+            File& operator=(const File&) = default;
+
+            File(File&&) = default;
+            File& operator=(File&&) = default;
+
+            ~File() = default;
+
+            const char* buffer() const noexcept {
+                return m_buffer;
+            }
+
+            size_t buffer_size() const noexcept {
+                return m_buffer_size;
+            }
+
+            void parse_format(const std::string& format) {
+                std::vector<std::string> options = detail::split(format, ',');
+
+                // if the first item in the format list doesn't contain
+                // an equals sign, it is a format
+                if (!options.empty() && options[0].find_first_of('=') == std::string::npos) {
+                    detect_format_from_suffix(options[0]);
+                    options.erase(options.begin());
+                }
+
+                for (auto& option : options) {
+                    size_t pos = option.find_first_of('=');
+                    if (pos == std::string::npos) {
+                        set(option, true);
+                    } else {
+                        std::string value = option.substr(pos+1);
+                        option.erase(pos);
+                        set(option, value);
+                    }
+                }
+
+                if (get("history") == "true") {
+                    m_has_multiple_object_versions = true;
+                } else if (get("history") == "false") {
+                    m_has_multiple_object_versions = false;
+                }
+            }
+
+            void detect_format_from_suffix(const std::string& name) {
+                std::vector<std::string> suffixes = detail::split(name, '.');
+
+                if (suffixes.empty()) return;
+
+                // if the last suffix is one of a known set of compressions,
+                // set that compression
+                if (suffixes.back() == "gz") {
+                    m_file_compression = file_compression::gzip;
+                    suffixes.pop_back();
+                } else if (suffixes.back() == "bz2") {
+                    m_file_compression = file_compression::bzip2;
+                    suffixes.pop_back();
+                }
+
+                if (suffixes.empty()) return;
+
+                // if the last suffix is one of a known set of formats,
+                // set that format
+                if (suffixes.back() == "pbf") {
+                    m_file_format = file_format::pbf;
+                    suffixes.pop_back();
+                } else if (suffixes.back() == "xml") {
+                    m_file_format = file_format::xml;
+                    suffixes.pop_back();
+                } else if (suffixes.back() == "opl") {
+                    m_file_format = file_format::opl;
+                    suffixes.pop_back();
+                }
+
+                if (suffixes.empty()) return;
+
+                if (suffixes.back() == "osm") {
+                    if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
+                    suffixes.pop_back();
+                } else if (suffixes.back() == "osh") {
+                    if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
+                    m_has_multiple_object_versions = true;
+                    suffixes.pop_back();
+                } else if (suffixes.back() == "osc") {
+                    if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
+                    m_has_multiple_object_versions = true;
+                    set("xml_change_format", true);
+                    suffixes.pop_back();
+                }
+            }
+
+            /**
+             * Check file format etc. for consistency and throw exception if there
+             * is a problem.
+             *
+             * @throws std::runtime_error
+             */
+            void check() const {
+                if (m_file_format == file_format::unknown) {
+                    std::string msg = "Could not detect file format";
+                    if (!m_format_string.empty())  {
+                        msg += " from format string '";
+                        msg += m_format_string;
+                        msg += "'";
+                    }
+                    if (m_filename.empty()) {
+                        msg += " for stdin/stdout";
+                    } else {
+                        msg += " for filename '";
+                        msg += m_filename;
+                        msg += "'";
+                    }
+                    msg += ".";
+                    throw std::runtime_error(msg);
+                }
+            }
+
+            /**
+             * Set default settings for type and encoding when the filename is
+             * empty or "-". If you want to have a different default setting
+             * override this in a subclass.
+             */
+            void default_settings_for_stdinout() {
+                m_file_format      = file_format::unknown;
+                m_file_compression = file_compression::none;
+            }
+
+            /**
+             * Set default settings for type and encoding when the filename is
+             * a normal file. If you want to have a different default setting
+             * override this in a subclass.
+             */
+            void default_settings_for_file() {
+                m_file_format      = file_format::unknown;
+                m_file_compression = file_compression::none;
+            }
+
+            /**
+             * Set default settings for type and encoding when the filename is a URL.
+             * If you want to have a different default setting override this in a
+             * subclass.
+             */
+            void default_settings_for_url() {
+                m_file_format      = file_format::xml;
+                m_file_compression = file_compression::none;
+            }
+
+            file_format format() const noexcept {
+                return m_file_format;
+            }
+
+            File& set_format(file_format format) noexcept {
+                m_file_format = format;
+                return *this;
+            }
+
+            file_compression compression() const noexcept {
+                return m_file_compression;
+            }
+
+            File& set_compression(file_compression compression) noexcept {
+                m_file_compression = compression;
+                return *this;
+            }
+
+            bool has_multiple_object_versions() const noexcept {
+                return m_has_multiple_object_versions;
+            }
+
+            File& set_has_multiple_object_versions(bool value) noexcept {
+                m_has_multiple_object_versions = value;
+                return *this;
+            }
+
+            File& filename(const std::string& filename) {
+                if (filename == "-") {
+                    m_filename = "";
+                } else {
+                    m_filename = filename;
+                }
+                return *this;
+            }
+
+            const std::string& filename() const noexcept {
+                return m_filename;
+            }
+
+        }; // class File
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_FILE_HPP
diff --git a/third_party/osmium/io/file_compression.hpp b/third_party/osmium/io/file_compression.hpp
new file mode 100644
index 0000000..c718715
--- /dev/null
+++ b/third_party/osmium/io/file_compression.hpp
@@ -0,0 +1,72 @@
+#ifndef OSMIUM_IO_FILE_COMPRESSION_HPP
+#define OSMIUM_IO_FILE_COMPRESSION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <iosfwd>
+
+namespace osmium {
+
+    namespace io {
+
+        enum class file_compression {
+            none  = 0,
+            gzip  = 1,
+            bzip2 = 2
+        };
+
+// avoid g++ false positive
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wreturn-type"
+        inline const char* as_string(file_compression compression) {
+            switch (compression) {
+                case file_compression::none:
+                    return "none";
+                case file_compression::gzip:
+                    return "gzip";
+                case file_compression::bzip2:
+                    return "bzip2";
+            }
+        }
+#pragma GCC diagnostic pop
+
+        template <typename TChar, typename TTraits>
+        inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const file_compression compression) {
+            return out << as_string(compression);
+        }
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_FILE_COMPRESSION_HPP
diff --git a/third_party/osmium/io/file_format.hpp b/third_party/osmium/io/file_format.hpp
new file mode 100644
index 0000000..5a4aa5c
--- /dev/null
+++ b/third_party/osmium/io/file_format.hpp
@@ -0,0 +1,78 @@
+#ifndef OSMIUM_IO_FILE_FORMAT_HPP
+#define OSMIUM_IO_FILE_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <iosfwd>
+
+namespace osmium {
+
+    namespace io {
+
+        enum class file_format {
+            unknown = 0,
+            xml     = 1,
+            pbf     = 2,
+            opl     = 3,
+            json    = 4
+        };
+
+// avoid g++ false positive
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wreturn-type"
+        inline const char* as_string(file_format format) {
+            switch (format) {
+                case file_format::unknown:
+                    return "unknown";
+                case file_format::xml:
+                    return "XML";
+                case file_format::pbf:
+                    return "PBF";
+                case file_format::opl:
+                    return "OPL";
+                case file_format::json:
+                    return "JSON";
+            }
+        }
+#pragma GCC diagnostic pop
+
+        template <typename TChar, typename TTraits>
+        inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const file_format format) {
+            return out << as_string(format);
+        }
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_FILE_FORMAT_HPP
diff --git a/third_party/osmium/io/gzip_compression.hpp b/third_party/osmium/io/gzip_compression.hpp
new file mode 100644
index 0000000..db99acb
--- /dev/null
+++ b/third_party/osmium/io/gzip_compression.hpp
@@ -0,0 +1,238 @@
+#ifndef OSMIUM_IO_GZIP_COMPRESSION_HPP
+#define OSMIUM_IO_GZIP_COMPRESSION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#define OSMIUM_LINK_WITH_LIBS_ZLIB -lz
+
+#include <stdexcept>
+#include <string>
+
+#include <errno.h>
+#include <zlib.h>
+
+#include <osmium/io/compression.hpp>
+#include <osmium/io/file_compression.hpp>
+#include <osmium/util/cast.hpp>
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+    /**
+     * Exception thrown when there are problems compressing or
+     * decompressing gzip files.
+     */
+    struct gzip_error : public std::runtime_error {
+
+        int gzip_error_code;
+        int system_errno;
+
+        gzip_error(const std::string& what, int error_code) :
+            std::runtime_error(what),
+            gzip_error_code(error_code),
+            system_errno(error_code == Z_ERRNO ? errno : 0) {
+        }
+
+    }; // struct gzip_error
+
+    namespace io {
+
+        namespace detail {
+
+            OSMIUM_NORETURN inline void throw_gzip_error(gzFile gzfile, const char* msg, int zlib_error=0) {
+                std::string error("gzip error: ");
+                error += msg;
+                error += ": ";
+                int errnum = zlib_error;
+                if (zlib_error) {
+                    error += std::to_string(zlib_error);
+                } else {
+                    error += ::gzerror(gzfile, &errnum);
+                }
+                throw osmium::gzip_error(error, errnum);
+            }
+
+        } // namespace detail
+
+        class GzipCompressor : public Compressor {
+
+            gzFile m_gzfile;
+
+        public:
+
+            explicit GzipCompressor(int fd) :
+                Compressor(),
+                m_gzfile(::gzdopen(fd, "w")) {
+                if (!m_gzfile) {
+                    detail::throw_gzip_error(m_gzfile, "write initialization failed");
+                }
+            }
+
+            ~GzipCompressor() override final {
+                close();
+            }
+
+            void write(const std::string& data) override final {
+                if (!data.empty()) {
+                    int nwrite = ::gzwrite(m_gzfile, data.data(), static_cast_with_assert<unsigned int>(data.size()));
+                    if (nwrite == 0) {
+                        detail::throw_gzip_error(m_gzfile, "write failed");
+                    }
+                }
+            }
+
+            void close() override final {
+                if (m_gzfile) {
+                    int result = ::gzclose(m_gzfile);
+                    m_gzfile = nullptr;
+                    if (result != Z_OK) {
+                        detail::throw_gzip_error(m_gzfile, "write close failed", result);
+                    }
+                }
+            }
+
+        }; // class GzipCompressor
+
+        class GzipDecompressor : public Decompressor {
+
+            gzFile m_gzfile;
+
+        public:
+
+            explicit GzipDecompressor(int fd) :
+                Decompressor(),
+                m_gzfile(::gzdopen(fd, "r")) {
+                if (!m_gzfile) {
+                    detail::throw_gzip_error(m_gzfile, "read initialization failed");
+                }
+            }
+
+            ~GzipDecompressor() override final {
+                close();
+            }
+
+            std::string read() override final {
+                std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0');
+                int nread = ::gzread(m_gzfile, const_cast<char*>(buffer.data()), static_cast_with_assert<unsigned int>(buffer.size()));
+                if (nread < 0) {
+                    detail::throw_gzip_error(m_gzfile, "read failed");
+                }
+                buffer.resize(static_cast<std::string::size_type>(nread));
+                return buffer;
+            }
+
+            void close() override final {
+                if (m_gzfile) {
+                    int result = ::gzclose(m_gzfile);
+                    m_gzfile = nullptr;
+                    if (result != Z_OK) {
+                        detail::throw_gzip_error(m_gzfile, "read close failed", result);
+                    }
+                }
+            }
+
+        }; // class GzipDecompressor
+
+        class GzipBufferDecompressor : public Decompressor {
+
+            const char* m_buffer;
+            size_t m_buffer_size;
+            z_stream m_zstream;
+
+        public:
+
+            GzipBufferDecompressor(const char* buffer, size_t size) :
+                m_buffer(buffer),
+                m_buffer_size(size),
+                m_zstream() {
+                m_zstream.next_in = reinterpret_cast<unsigned char*>(const_cast<char*>(buffer));
+                m_zstream.avail_in = static_cast_with_assert<unsigned int>(size);
+                int result = inflateInit2(&m_zstream, MAX_WBITS | 32);
+                if (result != Z_OK) {
+                    std::string message("gzip error: decompression init failed: ");
+                    if (m_zstream.msg) {
+                        message.append(m_zstream.msg);
+                    }
+                    throw osmium::gzip_error(message, result);
+                }
+            }
+
+            ~GzipBufferDecompressor() override final {
+                inflateEnd(&m_zstream);
+            }
+
+            std::string read() override final {
+                if (!m_buffer) {
+                    return std::string();
+                }
+
+                const size_t buffer_size = 10240;
+                std::string output(buffer_size, '\0');
+                m_zstream.next_out = reinterpret_cast<unsigned char*>(const_cast<char*>(output.data()));
+                m_zstream.avail_out = buffer_size;
+                int result = inflate(&m_zstream, Z_SYNC_FLUSH);
+
+                if (result != Z_OK) {
+                    m_buffer = nullptr;
+                    m_buffer_size = 0;
+                }
+
+                if (result != Z_OK && result != Z_STREAM_END) {
+                    std::string message("gzip error: inflate failed: ");
+                    if (m_zstream.msg) {
+                        message.append(m_zstream.msg);
+                    }
+                    throw osmium::gzip_error(message, result);
+                }
+
+                output.resize(static_cast<unsigned long>(m_zstream.next_out - reinterpret_cast<const unsigned char*>(output.data())));
+                return output;
+            }
+
+        }; // class GzipBufferDecompressor
+
+        namespace {
+
+            const bool registered_gzip_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::gzip,
+                [](int fd) { return new osmium::io::GzipCompressor(fd); },
+                [](int fd) { return new osmium::io::GzipDecompressor(fd); },
+                [](const char* buffer, size_t size) { return new osmium::io::GzipBufferDecompressor(buffer, size); }
+            );
+
+        } // anonymous namespace
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_GZIP_COMPRESSION_HPP
diff --git a/third_party/osmium/io/header.hpp b/third_party/osmium/io/header.hpp
new file mode 100644
index 0000000..0fdbf77
--- /dev/null
+++ b/third_party/osmium/io/header.hpp
@@ -0,0 +1,122 @@
+#ifndef OSMIUM_IO_HEADER_HPP
+#define OSMIUM_IO_HEADER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <initializer_list>
+#include <vector>
+
+#include <osmium/osm/box.hpp>
+#include <osmium/util/options.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        /**
+        * Meta information from the header of an OSM file.
+        */
+        class Header : public osmium::util::Options {
+
+            /// Bounding boxes
+            std::vector<osmium::Box> m_boxes;
+
+            /**
+            * Are there possibly multiple versions of the same object in this stream of objects?
+            * This is true for history files and for change files, but not for normal OSM files.
+            */
+            bool m_has_multiple_object_versions = false;
+
+        public:
+
+            Header() = default;
+
+            explicit Header(const std::initializer_list<osmium::util::Options::value_type>& values) :
+                Options(values) {
+            }
+
+            Header(const Header&) = default;
+            Header& operator=(const Header&) = default;
+
+            Header(Header&&) = default;
+            Header& operator=(Header&&) = default;
+
+            ~Header() = default;
+
+            std::vector<osmium::Box>& boxes() noexcept {
+                return m_boxes;
+            }
+
+            const std::vector<osmium::Box>& boxes() const noexcept {
+                return m_boxes;
+            }
+
+            Header& boxes(const std::vector<osmium::Box>& boxes) noexcept {
+                m_boxes = boxes;
+                return *this;
+            }
+
+            osmium::Box box() const {
+                return m_boxes.empty() ? osmium::Box() : m_boxes.front();
+            }
+
+            osmium::Box joined_boxes() const {
+                osmium::Box box;
+                for (const auto& b : m_boxes) {
+                    box.extend(b.bottom_left());
+                    box.extend(b.top_right());
+                }
+                return box;
+            }
+
+            Header& add_box(const osmium::Box& box) {
+                m_boxes.push_back(box);
+                return *this;
+            }
+
+            bool has_multiple_object_versions() const noexcept {
+                return m_has_multiple_object_versions;
+            }
+
+            Header& set_has_multiple_object_versions(bool value) noexcept {
+                m_has_multiple_object_versions = value;
+                return *this;
+            }
+
+        }; // class Header
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_HEADER_HPP
diff --git a/third_party/osmium/io/input_iterator.hpp b/third_party/osmium/io/input_iterator.hpp
new file mode 100644
index 0000000..a2e3b83
--- /dev/null
+++ b/third_party/osmium/io/input_iterator.hpp
@@ -0,0 +1,139 @@
+#ifndef OSMIUM_IO_INPUT_ITERATOR_HPP
+#define OSMIUM_IO_INPUT_ITERATOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/item.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        /**
+         * This iterator class allows you to iterate over all items from a
+         * source. It hides all the buffer handling and makes the contents of a
+         * source accessible as a normal STL input iterator.
+         */
+        template <class TSource, class TItem = osmium::memory::Item>
+        class InputIterator {
+
+            static_assert(std::is_base_of<osmium::memory::Item, TItem>::value, "TItem must derive from osmium::buffer::Item");
+
+            typedef typename osmium::memory::Buffer::t_iterator<TItem> item_iterator;
+
+            TSource* m_source;
+            std::shared_ptr<osmium::memory::Buffer> m_buffer;
+            item_iterator m_iter {};
+
+            void update_buffer() {
+                do {
+                    m_buffer = std::make_shared<osmium::memory::Buffer>(std::move(m_source->read()));
+                    if (!m_buffer || !*m_buffer) { // end of input
+                        m_source = nullptr;
+                        m_buffer.reset();
+                        m_iter = item_iterator();
+                        return;
+                    }
+                    m_iter = m_buffer->begin<TItem>();
+                } while (m_iter == m_buffer->end<TItem>());
+            }
+
+        public:
+
+            typedef std::input_iterator_tag iterator_category;
+            typedef TItem                   value_type;
+            typedef ptrdiff_t               difference_type;
+            typedef TItem*                  pointer;
+            typedef TItem&                  reference;
+
+            explicit InputIterator(TSource& source) :
+                m_source(&source) {
+                update_buffer();
+            }
+
+            // end iterator
+            InputIterator() noexcept :
+                m_source(nullptr) {
+            }
+
+            InputIterator& operator++() {
+                assert(m_source);
+                assert(m_buffer);
+                assert(m_iter);
+                ++m_iter;
+                if (m_iter == m_buffer->end<TItem>()) {
+                    update_buffer();
+                }
+                return *this;
+            }
+
+            InputIterator operator++(int) {
+                InputIterator tmp(*this);
+                operator++();
+                return tmp;
+            }
+
+            bool operator==(const InputIterator& rhs) const noexcept {
+                return m_source == rhs.m_source &&
+                       m_buffer == rhs.m_buffer &&
+                       m_iter == rhs.m_iter;
+            }
+
+            bool operator!=(const InputIterator& rhs) const noexcept {
+                return !(*this == rhs);
+            }
+
+            reference operator*() const {
+                assert(m_iter);
+                return static_cast<reference>(*m_iter);
+            }
+
+            pointer operator->() const {
+                assert(m_iter);
+                return &static_cast<reference>(*m_iter);
+            }
+
+        }; // class InputIterator
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_INPUT_ITERATOR_HPP
diff --git a/third_party/osmium/io/opl_output.hpp b/third_party/osmium/io/opl_output.hpp
new file mode 100644
index 0000000..46a1224
--- /dev/null
+++ b/third_party/osmium/io/opl_output.hpp
@@ -0,0 +1,39 @@
+#ifndef OSMIUM_IO_OPL_OUTPUT_HPP
+#define OSMIUM_IO_OPL_OUTPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/io/writer.hpp> // IWYU pragma: export
+#include <osmium/io/detail/opl_output_format.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_OPL_OUTPUT_HPP
diff --git a/third_party/osmium/io/output_iterator.hpp b/third_party/osmium/io/output_iterator.hpp
new file mode 100644
index 0000000..e6a9cc0
--- /dev/null
+++ b/third_party/osmium/io/output_iterator.hpp
@@ -0,0 +1,116 @@
+#ifndef OSMIUM_IO_OUTPUT_ITERATOR_HPP
+#define OSMIUM_IO_OUTPUT_ITERATOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <iterator>
+#include <memory>
+#include <utility>
+
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/diff_object.hpp>
+
+namespace osmium {
+
+    namespace memory {
+        class Item;
+    } // namespace memory
+
+    namespace io {
+
+        template <class TDest>
+        class OutputIterator : public std::iterator<std::output_iterator_tag, osmium::memory::Item> {
+
+            struct buffer_wrapper {
+
+                osmium::memory::Buffer buffer;
+
+                buffer_wrapper(size_t buffer_size) :
+                    buffer(buffer_size, osmium::memory::Buffer::auto_grow::no) {
+                }
+
+            }; // struct buffer_wrapper
+
+            static constexpr size_t default_buffer_size = 10 * 1024 * 1024;
+
+            TDest* m_destination;
+
+            std::shared_ptr<buffer_wrapper> m_buffer_wrapper;
+
+        public:
+
+            explicit OutputIterator(TDest& destination, const size_t buffer_size = default_buffer_size) :
+                m_destination(&destination),
+                m_buffer_wrapper(std::make_shared<buffer_wrapper>(buffer_size)) {
+            }
+
+            void flush() {
+                osmium::memory::Buffer buffer(m_buffer_wrapper->buffer.capacity(), osmium::memory::Buffer::auto_grow::no);
+                std::swap(m_buffer_wrapper->buffer, buffer);
+                (*m_destination)(std::move(buffer));
+            }
+
+            OutputIterator& operator=(const osmium::memory::Item& item) {
+                try {
+                    m_buffer_wrapper->buffer.push_back(item);
+                } catch (osmium::buffer_is_full&) {
+                    flush();
+                    m_buffer_wrapper->buffer.push_back(item);
+                }
+                return *this;
+            }
+
+            OutputIterator& operator=(const osmium::DiffObject& diff) {
+                return this->operator=(diff.curr());
+            }
+
+            OutputIterator& operator*() {
+                return *this;
+            }
+
+            OutputIterator& operator++() {
+                return *this;
+            }
+
+            OutputIterator& operator++(int) {
+                return *this;
+            }
+
+        }; // class OutputIterator
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_OUTPUT_ITERATOR_HPP
diff --git a/third_party/osmium/io/overwrite.hpp b/third_party/osmium/io/overwrite.hpp
new file mode 100644
index 0000000..f29a932
--- /dev/null
+++ b/third_party/osmium/io/overwrite.hpp
@@ -0,0 +1,52 @@
+#ifndef OSMIUM_IO_OVERWRITE_HPP
+#define OSMIUM_IO_OVERWRITE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+namespace osmium {
+
+    namespace io {
+
+        /**
+         * Allow overwriting of existing file.
+         */
+        enum class overwrite : bool {
+            no    = false,
+            allow = true
+        };
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_OVERWRITE_HPP
diff --git a/third_party/osmium/io/pbf_input.hpp b/third_party/osmium/io/pbf_input.hpp
new file mode 100644
index 0000000..8426f6c
--- /dev/null
+++ b/third_party/osmium/io/pbf_input.hpp
@@ -0,0 +1,39 @@
+#ifndef OSMIUM_IO_PBF_INPUT_HPP
+#define OSMIUM_IO_PBF_INPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/io/reader.hpp> // IWYU pragma: export
+#include <osmium/io/detail/pbf_input_format.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_PBF_INPUT_HPP
diff --git a/third_party/osmium/io/pbf_output.hpp b/third_party/osmium/io/pbf_output.hpp
new file mode 100644
index 0000000..9fd0396
--- /dev/null
+++ b/third_party/osmium/io/pbf_output.hpp
@@ -0,0 +1,39 @@
+#ifndef OSMIUM_IO_PBF_OUTPUT_HPP
+#define OSMIUM_IO_PBF_OUTPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/io/writer.hpp> // IWYU pragma: export
+#include <osmium/io/detail/pbf_output_format.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_PBF_OUTPUT_HPP
diff --git a/third_party/osmium/io/reader.hpp b/third_party/osmium/io/reader.hpp
new file mode 100644
index 0000000..a9b8b95
--- /dev/null
+++ b/third_party/osmium/io/reader.hpp
@@ -0,0 +1,303 @@
+#ifndef OSMIUM_IO_READER_HPP
+#define OSMIUM_IO_READER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <atomic>
+#include <cerrno>
+#include <cstdlib>
+#include <fcntl.h>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <thread>
+#include <utility>
+
+#ifndef _WIN32
+# include <sys/wait.h>
+#endif
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#endif
+
+#include <osmium/io/compression.hpp>
+#include <osmium/io/detail/input_format.hpp>
+#include <osmium/io/detail/read_thread.hpp>
+#include <osmium/io/detail/read_write.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/thread/util.hpp>
+#include <osmium/thread/queue.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        /**
+         * This is the user-facing interface for reading OSM files. Instantiate
+         * an object of this class with a file name or osmium::io::File object
+         * and then call read() on it in a loop until it returns an invalid
+         * Buffer.
+         */
+        class Reader {
+
+            osmium::io::File m_file;
+            osmium::osm_entity_bits::type m_read_which_entities;
+            std::atomic<bool> m_input_done;
+            int m_childpid;
+
+            osmium::thread::Queue<std::string> m_input_queue;
+
+            std::unique_ptr<osmium::io::Decompressor> m_decompressor;
+            std::future<bool> m_read_future;
+
+            std::unique_ptr<osmium::io::detail::InputFormat> m_input;
+
+#ifndef _WIN32
+            /**
+             * Fork and execute the given command in the child.
+             * A pipe is created between the child and the parent.
+             * The child writes to the pipe, the parent reads from it.
+             * This function never returns in the child.
+             *
+             * @param command Command to execute in the child.
+             * @param filename Filename to give to command as argument.
+             * @returns File descriptor of pipe in the parent.
+             * @throws std::system_error if a system call fails.
+             */
+            static int execute(const std::string& command, const std::string& filename, int* childpid) {
+                int pipefd[2];
+                if (pipe(pipefd) < 0) {
+                    throw std::system_error(errno, std::system_category(), "opening pipe failed");
+                }
+                pid_t pid = fork();
+                if (pid < 0) {
+                    throw std::system_error(errno, std::system_category(), "fork failed");
+                }
+                if (pid == 0) { // child
+                    // close all file descriptors except one end of the pipe
+                    for (int i=0; i < 32; ++i) {
+                        if (i != pipefd[1]) {
+                            ::close(i);
+                        }
+                    }
+                    if (dup2(pipefd[1], 1) < 0) { // put end of pipe as stdout/stdin
+                        exit(1);
+                    }
+
+                    ::open("/dev/null", O_RDONLY); // stdin
+                    ::open("/dev/null", O_WRONLY); // stderr
+                    // hack: -g switches off globbing in curl which allows [] to be used in file names
+                    // this is important for XAPI URLs
+                    // in theory this execute() function could be used for other commands, but it is
+                    // only used for curl at the moment, so this is okay.
+                    if (::execlp(command.c_str(), command.c_str(), "-g", filename.c_str(), nullptr) < 0) {
+                        exit(1);
+                    }
+                }
+                // parent
+                *childpid = pid;
+                ::close(pipefd[1]);
+                return pipefd[0];
+            }
+#endif
+
+            /**
+             * Open File for reading. Handles URLs or normal files. URLs
+             * are opened by executing the "curl" program (which must be installed)
+             * and reading from its output.
+             *
+             * @returns File descriptor of open file or pipe.
+             * @throws std::system_error if a system call fails.
+             */
+            static int open_input_file_or_url(const std::string& filename, int* childpid) {
+                std::string protocol = filename.substr(0, filename.find_first_of(':'));
+                if (protocol == "http" || protocol == "https" || protocol == "ftp" || protocol == "file") {
+#ifndef _WIN32
+                    return execute("curl", filename, childpid);
+#else
+                    throw std::runtime_error("Reading OSM files from the network currently not supported on Windows.");
+#endif
+                } else {
+                    return osmium::io::detail::open_for_reading(filename);
+                }
+            }
+
+        public:
+
+            /**
+             * Create new Reader object.
+             *
+             * @param file The file we want to open.
+             * @param read_which_entities Which OSM entities (nodes, ways, relations, and/or changesets)
+             *                            should be read from the input file. It can speed the read up
+             *                            significantly if objects that are not needed anyway are not
+             *                            parsed.
+             */
+            explicit Reader(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities = osmium::osm_entity_bits::all) :
+                m_file(file),
+                m_read_which_entities(read_which_entities),
+                m_input_done(false),
+                m_childpid(0),
+                m_input_queue(20, "raw_input"), // XXX
+                m_decompressor(m_file.buffer() ?
+                    osmium::io::CompressionFactory::instance().create_decompressor(file.compression(), m_file.buffer(), m_file.buffer_size()) :
+                    osmium::io::CompressionFactory::instance().create_decompressor(file.compression(), open_input_file_or_url(m_file.filename(), &m_childpid))),
+                m_read_future(std::async(std::launch::async, detail::ReadThread(m_input_queue, m_decompressor.get(), m_input_done))),
+                m_input(osmium::io::detail::InputFormatFactory::instance().create_input(m_file, m_read_which_entities, m_input_queue)) {
+            }
+
+            explicit Reader(const std::string& filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) :
+                Reader(osmium::io::File(filename), read_types) {
+            }
+
+            explicit Reader(const char* filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) :
+                Reader(osmium::io::File(filename), read_types) {
+            }
+
+            Reader(const Reader&) = delete;
+            Reader& operator=(const Reader&) = delete;
+
+            ~Reader() {
+                try {
+                    close();
+                }
+                catch (...) {
+                }
+            }
+
+            /**
+             * Close down the Reader. A call to this is optional, because the
+             * destructor of Reader will also call this. But if you don't call
+             * this function first, the destructor might throw an exception
+             * which is not good.
+             *
+             * @throws Some form of std::runtime_error when there is a problem.
+             */
+            void close() {
+                // Signal to input child process that it should wrap up.
+                m_input_done = true;
+
+                m_input->close();
+
+#ifndef _WIN32
+                if (m_childpid) {
+                    int status;
+                    pid_t pid = ::waitpid(m_childpid, &status, 0);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+                    if (pid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+                        throw std::system_error(errno, std::system_category(), "subprocess returned error");
+                    }
+#pragma GCC diagnostic pop
+                    m_childpid = 0;
+                }
+#endif
+
+                osmium::thread::wait_until_done(m_read_future);
+            }
+
+            /**
+             * Get the header data from the file.
+             */
+            osmium::io::Header header() const {
+                return m_input->header();
+            }
+
+            /**
+             * Reads the next buffer from the input. An invalid buffer signals
+             * end-of-file. After end-of-file all read() calls will return an
+             * invalid buffer. An invalid buffer is also always returned if
+             * osmium::osm_entity_bits::nothing was set when the Reader was
+             * constructed.
+             *
+             * @returns Buffer.
+             * @throws Some form of std::runtime_error if there is an error.
+             */
+            osmium::memory::Buffer read() {
+                // If an exception happened in the input thread, re-throw
+                // it in this (the main) thread.
+                osmium::thread::check_for_exception(m_read_future);
+
+                if (m_read_which_entities == osmium::osm_entity_bits::nothing || m_input_done) {
+                    // If the caller didn't want anything but the header, it will
+                    // always get an empty buffer here.
+                    return osmium::memory::Buffer();
+                }
+
+                osmium::memory::Buffer buffer = m_input->read();
+                if (!buffer) {
+                    m_input_done = true;
+                }
+                return buffer;
+            }
+
+            /**
+             * Has the end of file been reached? This is set after the last
+             * data has been read. It is also set by calling close().
+             */
+            bool eof() const {
+                return m_input_done;
+            }
+
+        }; // class Reader
+
+        /**
+         * Read contents of the given file into a buffer in one go. Takes
+         * the same arguments as any of the Reader constructors.
+         *
+         * The buffer can take up quite a lot of memory, so don't do this
+         * unless you are working with small OSM files and/or have lots of
+         * RAM.
+         */
+        template <class... TArgs>
+        osmium::memory::Buffer read_file(TArgs&&... args) {
+            osmium::memory::Buffer buffer(1024*1024, osmium::memory::Buffer::auto_grow::yes);
+
+            Reader reader(std::forward<TArgs>(args)...);
+            while (osmium::memory::Buffer read_buffer = reader.read()) {
+                buffer.add_buffer(read_buffer);
+                buffer.commit();
+            }
+
+            return buffer;
+        }
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_READER_HPP
diff --git a/third_party/osmium/io/reader_iterator.hpp b/third_party/osmium/io/reader_iterator.hpp
new file mode 100644
index 0000000..8d71418
--- /dev/null
+++ b/third_party/osmium/io/reader_iterator.hpp
@@ -0,0 +1,51 @@
+#ifndef OSMIUM_IO_READER_ITERATOR_HPP
+#define OSMIUM_IO_READER_ITERATOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/io/reader.hpp>
+#include <osmium/io/input_iterator.hpp>
+
+namespace std {
+
+    inline osmium::io::InputIterator<osmium::io::Reader> begin(osmium::io::Reader& reader) {
+        return osmium::io::InputIterator<osmium::io::Reader>(reader);
+    }
+
+    inline osmium::io::InputIterator<osmium::io::Reader> end(osmium::io::Reader&) {
+        return osmium::io::InputIterator<osmium::io::Reader>();
+    }
+
+} // namespace std
+
+#endif // OSMIUM_IO_READER_ITERATOR_HPP
diff --git a/third_party/osmium/io/writer.hpp b/third_party/osmium/io/writer.hpp
new file mode 100644
index 0000000..7e9bd13
--- /dev/null
+++ b/third_party/osmium/io/writer.hpp
@@ -0,0 +1,145 @@
+#ifndef OSMIUM_IO_WRITER_HPP
+#define OSMIUM_IO_WRITER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include <osmium/io/compression.hpp>
+#include <osmium/io/detail/output_format.hpp>
+#include <osmium/io/detail/read_write.hpp>
+#include <osmium/io/detail/write_thread.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/io/overwrite.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/thread/util.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        /**
+         * This is the user-facing interface for writing OSM files. Instantiate
+         * an object of this class with a file name or osmium::io::File object
+         * and optionally the data for the header and then call operator() on it
+         * to write Buffers. Call close() to finish up.
+         */
+        class Writer {
+
+            osmium::io::File m_file;
+
+            osmium::io::detail::data_queue_type m_output_queue;
+
+            std::unique_ptr<osmium::io::detail::OutputFormat> m_output;
+
+            std::unique_ptr<osmium::io::Compressor> m_compressor;
+
+            std::future<bool> m_write_future;
+
+        public:
+
+            /**
+             * The constructor of the Writer object opens a file and writes the
+             * header to it.
+             *
+             * @param file File (contains name and format info) to open.
+             * @param header Optional header data. If this is not given sensible
+             *               defaults will be used. See the default constructor
+             *               of osmium::io::Header for details.
+             * @param allow_overwrite Allow overwriting of existing file? Can be
+             *               osmium::io::overwrite::allow or osmium::io::overwrite::no+
+             *               (default).
+             *
+             * @throws std::runtime_error If the file could not be opened.
+             * @throws std::system_error If the file could not be opened.
+             */
+            explicit Writer(const osmium::io::File& file, const osmium::io::Header& header = osmium::io::Header(), overwrite allow_overwrite = overwrite::no) :
+                m_file(file),
+                m_output_queue(20, "raw_output"), // XXX
+                m_output(osmium::io::detail::OutputFormatFactory::instance().create_output(m_file, m_output_queue)),
+                m_compressor(osmium::io::CompressionFactory::instance().create_compressor(file.compression(), osmium::io::detail::open_for_writing(m_file.filename(), allow_overwrite))),
+                m_write_future(std::async(std::launch::async, detail::WriteThread(m_output_queue, m_compressor.get()))) {
+                assert(!m_file.buffer());
+                m_output->write_header(header);
+            }
+
+            explicit Writer(const std::string& filename, const osmium::io::Header& header = osmium::io::Header(), overwrite allow_overwrite = overwrite::no) :
+                Writer(osmium::io::File(filename), header, allow_overwrite) {
+            }
+
+            explicit Writer(const char* filename, const osmium::io::Header& header = osmium::io::Header(), overwrite allow_overwrite = overwrite::no) :
+                Writer(osmium::io::File(filename), header, allow_overwrite) {
+            }
+
+            Writer(const Writer&) = delete;
+            Writer& operator=(const Writer&) = delete;
+
+            ~Writer() {
+                close();
+            }
+
+            /**
+             * Write contents of a buffer to the output file.
+             *
+             * @throws Some form of std::runtime_error when there is a problem.
+             */
+            void operator()(osmium::memory::Buffer&& buffer) {
+                osmium::thread::check_for_exception(m_write_future);
+                if (buffer.committed() > 0) {
+                    m_output->write_buffer(std::move(buffer));
+                }
+            }
+
+            /**
+             * Flush writes to output file and closes it. If you do not
+             * call this, the destructor of Writer will also do the same
+             * thing. But because this call might thrown an exception,
+             * it is better to call close() explicitly.
+             *
+             * @throws Some form of std::runtime_error when there is a problem.
+             */
+            void close() {
+                m_output->close();
+                osmium::thread::wait_until_done(m_write_future);
+            }
+
+        }; // class Writer
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_WRITER_HPP
diff --git a/third_party/osmium/io/xml_input.hpp b/third_party/osmium/io/xml_input.hpp
new file mode 100644
index 0000000..f33d37e
--- /dev/null
+++ b/third_party/osmium/io/xml_input.hpp
@@ -0,0 +1,39 @@
+#ifndef OSMIUM_IO_XML_INPUT_HPP
+#define OSMIUM_IO_XML_INPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/io/reader.hpp> // IWYU pragma: export
+#include <osmium/io/detail/xml_input_format.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_XML_INPUT_HPP
diff --git a/third_party/osmium/io/xml_output.hpp b/third_party/osmium/io/xml_output.hpp
new file mode 100644
index 0000000..d5b839f
--- /dev/null
+++ b/third_party/osmium/io/xml_output.hpp
@@ -0,0 +1,39 @@
+#ifndef OSMIUM_IO_XML_OUTPUT_HPP
+#define OSMIUM_IO_XML_OUTPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/io/writer.hpp> // IWYU pragma: export
+#include <osmium/io/detail/xml_output_format.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_XML_OUTPUT_HPP
diff --git a/third_party/osmium/memory/buffer.hpp b/third_party/osmium/memory/buffer.hpp
new file mode 100644
index 0000000..fe040ca
--- /dev/null
+++ b/third_party/osmium/memory/buffer.hpp
@@ -0,0 +1,534 @@
+#ifndef OSMIUM_MEMORY_BUFFER_HPP
+#define OSMIUM_MEMORY_BUFFER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <exception>
+#include <functional>
+#include <iterator>
+#include <stdexcept>
+#include <utility>
+#include <vector>
+
+#include <osmium/memory/item.hpp>
+#include <osmium/memory/item_iterator.hpp>
+#include <osmium/osm/entity.hpp>
+
+namespace osmium {
+
+    /**
+     * Exception thrown by the osmium::memory::Buffer class when somebody tries
+     * to write data into a buffer and it doesn't fit. Buffers with internal
+     * memory management will not throw this exception, but increase their size.
+     */
+    struct buffer_is_full : public std::runtime_error {
+
+        buffer_is_full() :
+            std::runtime_error("Osmium buffer is full") {
+        }
+
+    }; // struct buffer_is_full
+
+    /**
+     * @brief Memory management of items in buffers and iterators over this data.
+     */
+    namespace memory {
+
+        /**
+         * A memory area for storing OSM objects and other items. Each item stored
+         * has a type and a length. See the Item class for details.
+         *
+         * Data can be added to a buffer piece by piece using reserve_space() and
+         * add_item(). After all data that together forms an item is added, it must
+         * be committed using the commit() call. Usually this is done through the
+         * Builder class and its derived classes.
+         *
+         * You can iterate over all items in a buffer using the iterators returned
+         * by begin(), end(), cbegin(), and cend().
+         *
+         * Buffers exist in two flavours, those with external memory management and
+         * those with internal memory management. If you already have some memory
+         * with data in it (for instance read from disk), you create a Buffer with
+         * external memory managment. It is your job then to free the memory once
+         * the buffer isn't used any more. If you don't have memory already, you can
+         * create a Buffer object and have it manage the memory internally. It will
+         * dynamically allocate memory and free it again after use.
+         *
+         * By default, if a buffer gets full it will throw a buffer_is_full exception.
+         * You can use the set_full_callback() method to set a callback functor
+         * which will be called instead of throwing an exception.
+         */
+        class Buffer {
+
+        public:
+
+            enum class auto_grow : bool {
+                yes = true,
+                no  = false
+            }; // enum class auto_grow
+
+        private:
+
+            std::vector<unsigned char> m_memory;
+            unsigned char* m_data;
+            size_t m_capacity;
+            size_t m_written;
+            size_t m_committed;
+            auto_grow m_auto_grow {auto_grow::no};
+            std::function<void(Buffer&)> m_full;
+
+        public:
+
+            typedef Item value_type;
+
+            /**
+             * The constructor without any parameters creates a non-initialized
+             * buffer, ie an empty hull of a buffer that has no actual memory
+             * associated with it. It can be used to signify end-of-input.
+             */
+            Buffer() noexcept :
+                m_memory(),
+                m_data(nullptr),
+                m_capacity(0),
+                m_written(0),
+                m_committed(0) {
+            }
+
+            /**
+             * Constructs an externally memory-managed buffer using the given
+             * memory and size.
+             *
+             * @param data A pointer to some already initialized data.
+             * @param size The size of the initialized data.
+             * @throws std::invalid_argument When the size isn't a multiple of the alignment.
+             */
+            explicit Buffer(unsigned char* data, size_t size) :
+                m_memory(),
+                m_data(data),
+                m_capacity(size),
+                m_written(size),
+                m_committed(size) {
+                if (size % align_bytes != 0) {
+                    throw std::invalid_argument("buffer size needs to be multiple of alignment");
+                }
+            }
+
+            /**
+             * Constructs an externally memory-managed buffer with the given
+             * capacity that already contains 'committed' bytes of data.
+             *
+             * @param data A pointer to some (possibly initialized) data.
+             * @param capacity The size of the memory for this buffer.
+             * @param committed The size of the initialized data. If this is 0, the buffer startes out empty.
+             * @throws std::invalid_argument When the capacity or committed isn't a multiple of the alignment.
+             */
+            explicit Buffer(unsigned char* data, size_t capacity, size_t committed) :
+                m_memory(),
+                m_data(data),
+                m_capacity(capacity),
+                m_written(committed),
+                m_committed(committed) {
+                if (capacity % align_bytes != 0) {
+                    throw std::invalid_argument("buffer capacity needs to be multiple of alignment");
+                }
+                if (committed % align_bytes != 0) {
+                    throw std::invalid_argument("buffer parameter 'committed' needs to be multiple of alignment");
+                }
+            }
+
+            /**
+             * Create an internally memory-managed buffer with the given capacity.
+             * different in that it internally gets dynamic memory of the
+             * required size. The dynamic memory will be automatically
+             * freed when the Buffer is destroyed.
+             */
+            explicit Buffer(size_t capacity, auto_grow auto_grow = auto_grow::yes) :
+                m_memory(capacity),
+                m_data(m_memory.data()),
+                m_capacity(capacity),
+                m_written(0),
+                m_committed(0),
+                m_auto_grow(auto_grow) {
+                if (capacity % align_bytes != 0) {
+                    throw std::invalid_argument("buffer capacity needs to be multiple of alignment");
+                }
+            }
+
+            // buffers can not be copied
+            Buffer(const Buffer&) = delete;
+            Buffer& operator=(const Buffer&) = delete;
+
+            // buffers can be moved
+            Buffer(Buffer&&) = default;
+            Buffer& operator=(Buffer&&) = default;
+
+            ~Buffer() = default;
+
+            /**
+             * Return a pointer to data inside the buffer.
+             */
+            unsigned char* data() const noexcept {
+                return m_data;
+            }
+
+            /**
+             * Returns the capacity of the buffer, ie how many bytes it can contain.
+             */
+            size_t capacity() const noexcept {
+                return m_capacity;
+            }
+
+            /**
+             * Returns the number of bytes already filled in this buffer.
+             */
+            size_t committed() const noexcept {
+                return m_committed;
+            }
+
+            /**
+             * Returns the number of bytes currently filled in this buffer that
+             * are not yet committed.
+             */
+            size_t written() const noexcept {
+                return m_written;
+            }
+
+            /**
+             * This tests if the current state of the buffer is aligned
+             * properly. Can be used for asserts.
+             */
+            bool is_aligned() const noexcept {
+                return (m_written % align_bytes == 0) && (m_committed % align_bytes == 0);
+            }
+
+            /**
+             * Set functor to be called whenever the buffer is full
+             * instead of throwing buffer_is_full.
+             */
+            void set_full_callback(std::function<void(Buffer&)> full) {
+                m_full = full;
+            }
+
+            /**
+             * Grow capacity of this buffer to the given size.
+             * This works only with internally memory-managed buffers.
+             * If the given size is not larger than the current capacity, nothing is done.
+             * Already written but not committed data is discarded.
+             *
+             * @param size New capacity.
+             */
+            void grow(size_t size) {
+                if (m_memory.empty()) {
+                    throw std::logic_error("Can't grow Buffer if it doesn't use internal memory management.");
+                }
+                if (m_capacity < size) {
+                    if (size % align_bytes != 0) {
+                        throw std::invalid_argument("buffer capacity needs to be multiple of alignment");
+                    }
+                    m_memory.resize(size);
+                    m_data = m_memory.data();
+                    m_capacity = size;
+                }
+            }
+
+            /**
+             * Mark currently written bytes in the buffer as committed.
+             *
+             * @returns Last number of committed bytes before this commit.
+             */
+            size_t commit() {
+                assert(is_aligned());
+
+                const size_t offset = m_committed;
+                m_committed = m_written;
+                return offset;
+            }
+
+            /**
+             * Roll back changes in buffer to last committed state.
+             */
+            void rollback() {
+                m_written = m_committed;
+            }
+
+            /**
+             * Clear the buffer.
+             *
+             * @returns Number of bytes in the buffer before it was cleared.
+             */
+            size_t clear() {
+                const size_t committed = m_committed;
+                m_written = 0;
+                m_committed = 0;
+                return committed;
+            }
+
+            /**
+             * Get the data in the buffer at the given offset.
+             *
+             * @tparam T Type we want to the data to be interpreted as.
+             * @returns Reference of given type pointing to the data in the buffer.
+             */
+            template <class T>
+            T& get(const size_t offset) const {
+                return *reinterpret_cast<T*>(&m_data[offset]);
+            }
+
+            /**
+             * Reserve space of given size in buffer and return pointer to it.
+             * This is the only way of adding data to the buffer. You reserve
+             * the space and then fill it.
+             *
+             * Note that you have to eventually call commit() to actually
+             * commit this data.
+             *
+             * If there isn't enough space in the buffer, one of three things
+             * can happen:
+             *
+             * * If you have set a callback with set_full_callback(), it is
+             *   called. After the call returns, you must have either grown
+             *   the buffer or cleared it by calling buffer.clear().
+             * * If no callback is defined and this buffer uses internal
+             *   memory management, the buffers capacity is grown, so that
+             *   the new data will fit.
+             * * Else the buffer_is_full exception is thrown.
+             *
+             * @param size Number of bytes to reserve.
+             * @returns Pointer to reserved space. Note that this pointer is
+             *         only guaranteed to be valid until the next call to
+             *         reserve_space().
+             * @throws osmium::buffer_is_full Might be thrown if the buffer is full.
+             */
+            unsigned char* reserve_space(const size_t size) {
+                if (m_written + size > m_capacity) {
+                    if (m_full) {
+                        m_full(*this);
+                    } else if (!m_memory.empty() && (m_auto_grow == auto_grow::yes)) {
+                        // double buffer size until there is enough space
+                        size_t new_capacity = m_capacity * 2;
+                        while (m_written + size > new_capacity) {
+                            new_capacity *= 2;
+                        }
+                        grow(new_capacity);
+                    } else {
+                        throw osmium::buffer_is_full();
+                    }
+                }
+                unsigned char* data = &m_data[m_written];
+                m_written += size;
+                return data;
+            }
+
+            /**
+             * Add an item to the buffer. The size of the item is stored inside
+             * the item, so we know how much memory to copy.
+             *
+             * Note that you have to eventually call commit() to actually
+             * commit this data.
+             *
+             * @tparam T Class of the item to be copied.
+             * @param item Reference to the item to be copied.
+             * @returns Reference to newly copied data in the buffer.
+             */
+            template <class T>
+            T& add_item(const T& item) {
+                unsigned char* ptr = reserve_space(item.padded_size());
+                std::memcpy(ptr, &item, item.padded_size());
+                return *reinterpret_cast<T*>(ptr);
+            }
+
+            /**
+             * Add committed contents of the given buffer to this buffer.
+             *
+             * Note that you have to eventually call commit() to actually
+             * commit this data.
+             */
+            void add_buffer(const Buffer& buffer) {
+                unsigned char* ptr = reserve_space(buffer.committed());
+                std::memcpy(ptr, buffer.data(), buffer.committed());
+            }
+
+            /**
+             * Add an item to the buffer. This function is provided so that
+             * you can use std::back_inserter.
+             */
+            void push_back(const osmium::memory::Item& item) {
+                add_item(item);
+                commit();
+            }
+
+            /**
+             * These iterators can be used to iterate over all items in
+             * a buffer.
+             */
+            template <class T>
+            using t_iterator = osmium::memory::ItemIterator<T>;
+
+            template <class T>
+            using t_const_iterator = osmium::memory::ItemIterator<const T>;
+
+            typedef t_iterator<osmium::OSMEntity> iterator;
+            typedef t_const_iterator<osmium::OSMEntity> const_iterator;
+
+            template <class T>
+            t_iterator<T> begin() {
+                return t_iterator<T>(m_data, m_data + m_committed);
+            }
+
+            iterator begin() {
+                return iterator(m_data, m_data + m_committed);
+            }
+
+            template <class T>
+            t_iterator<T> end() {
+                return t_iterator<T>(m_data + m_committed, m_data + m_committed);
+            }
+
+            iterator end() {
+                return iterator(m_data + m_committed, m_data + m_committed);
+            }
+
+            template <class T>
+            t_const_iterator<T> cbegin() const {
+                return t_const_iterator<T>(m_data, m_data + m_committed);
+            }
+
+            const_iterator cbegin() const {
+                return const_iterator(m_data, m_data + m_committed);
+            }
+
+            template <class T>
+            t_const_iterator<T> cend() const {
+                return t_const_iterator<T>(m_data + m_committed, m_data + m_committed);
+            }
+
+            const_iterator cend() const {
+                return const_iterator(m_data + m_committed, m_data + m_committed);
+            }
+
+            template <class T>
+            t_const_iterator<T> begin() const {
+                return cbegin<T>();
+            }
+
+            const_iterator begin() const {
+                return cbegin();
+            }
+
+            template <class T>
+            t_const_iterator<T> end() const {
+                return cend<T>();
+            }
+
+            const_iterator end() const {
+                return cend();
+            }
+
+            /**
+             * In a bool context any initialized buffer is true.
+             */
+            explicit operator bool() const {
+                return m_data != nullptr;
+            }
+
+            friend void swap(Buffer& lhs, Buffer& rhs) {
+                using std::swap;
+
+                swap(lhs.m_memory, rhs.m_memory);
+                swap(lhs.m_data, rhs.m_data);
+                swap(lhs.m_capacity, rhs.m_capacity);
+                swap(lhs.m_written, rhs.m_written);
+                swap(lhs.m_committed, rhs.m_committed);
+            }
+
+            /**
+             * Purge removed items from the buffer. This is done by moving all
+             * non-removed items forward in the buffer overwriting removed
+             * items and then correcting the m_written and m_committed numbers.
+             *
+             * Note that calling this function invalidates all iterators on this
+             * buffer and all offsets in this buffer.
+             *
+             * For every non-removed item that moves its position, the function
+             * 'moving_in_buffer' is called on the given callback object with
+             * the old and new offsets in the buffer where the object used to
+             * be and is now, respectively. This call can be used to update any
+             * indexes.
+             */
+            template <class TCallbackClass>
+            void purge_removed(TCallbackClass* callback) {
+                if (begin() == end()) {
+                    return;
+                }
+
+                iterator it_write = begin();
+
+                iterator next;
+                for (iterator it_read = begin(); it_read != end(); it_read = next) {
+                    next = std::next(it_read);
+                    if (!it_read->removed()) {
+                        if (it_read != it_write) {
+                            assert(it_read.data() >= data());
+                            assert(it_write.data() >= data());
+                            size_t old_offset = static_cast<size_t>(it_read.data() - data());
+                            size_t new_offset = static_cast<size_t>(it_write.data() - data());
+                            callback->moving_in_buffer(old_offset, new_offset);
+                            std::memmove(it_write.data(), it_read.data(), it_read->padded_size());
+                        }
+                        it_write.advance_once();
+                    }
+                }
+
+                assert(it_write.data() >= data());
+                m_written = static_cast<size_t>(it_write.data() - data());
+                m_committed = m_written;
+            }
+
+        }; // class Buffer
+
+        inline bool operator==(const Buffer& lhs, const Buffer& rhs) noexcept {
+            return lhs.data() == rhs.data() && lhs.capacity() == rhs.capacity() && lhs.committed() == rhs.committed();
+        }
+
+        inline bool operator!=(const Buffer& lhs, const Buffer& rhs) noexcept {
+            return ! (lhs == rhs);
+        }
+
+    } // namespace memory
+
+} // namespace osmium
+
+#endif // OSMIUM_MEMORY_BUFFER_HPP
diff --git a/third_party/osmium/memory/collection.hpp b/third_party/osmium/memory/collection.hpp
new file mode 100644
index 0000000..b25dd64
--- /dev/null
+++ b/third_party/osmium/memory/collection.hpp
@@ -0,0 +1,153 @@
+#ifndef OSMIUM_MEMORY_COLLECTION_HPP
+#define OSMIUM_MEMORY_COLLECTION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <iterator>
+#include <iosfwd>
+#include <type_traits>
+
+#include <osmium/memory/item.hpp>
+
+namespace osmium {
+
+    namespace memory {
+
+        template <class TMember>
+        class CollectionIterator : public std::iterator<std::forward_iterator_tag, TMember> {
+
+            // This data_type is either 'unsigned char*' or 'const unsigned char*' depending
+            // on whether TMember is const. This allows this class to be used as an iterator and
+            // as a const_iterator.
+            typedef typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type data_type;
+
+            data_type m_data;
+
+        public:
+
+            CollectionIterator() noexcept :
+                m_data(nullptr) {
+            }
+
+            CollectionIterator(data_type data) noexcept :
+                m_data(data) {
+            }
+
+            CollectionIterator<TMember>& operator++() {
+                m_data = reinterpret_cast<TMember*>(m_data)->next();
+                return *static_cast<CollectionIterator<TMember>*>(this);
+            }
+
+            CollectionIterator<TMember> operator++(int) {
+                CollectionIterator<TMember> tmp(*this);
+                operator++();
+                return tmp;
+            }
+
+            bool operator==(const CollectionIterator<TMember>& rhs) const noexcept {
+                return m_data == rhs.m_data;
+            }
+
+            bool operator!=(const CollectionIterator<TMember>& rhs) const noexcept {
+                return m_data != rhs.m_data;
+            }
+
+            unsigned char* data() const noexcept {
+                return m_data;
+            }
+
+            TMember& operator*() const {
+                return *reinterpret_cast<TMember*>(m_data);
+            }
+
+            TMember* operator->() const {
+                return reinterpret_cast<TMember*>(m_data);
+            }
+
+            template <typename TChar, typename TTraits>
+            friend std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const CollectionIterator<TMember>& iter) {
+                return out << static_cast<const void*>(iter.m_data);
+            }
+
+        }; // class CollectionIterator
+
+        template <class TMember, osmium::item_type TCollectionItemType>
+        class Collection : public Item {
+
+        public:
+
+            typedef CollectionIterator<TMember> iterator;
+            typedef CollectionIterator<const TMember> const_iterator;
+            typedef TMember value_type;
+
+            static constexpr osmium::item_type itemtype = TCollectionItemType;
+
+            Collection() :
+                Item(sizeof(Collection<TMember, TCollectionItemType>), TCollectionItemType) {
+            }
+
+            bool empty() const {
+                return sizeof(Collection<TMember, TCollectionItemType>) == byte_size();
+            }
+
+            iterator begin() {
+                return iterator(data() + sizeof(Collection<TMember, TCollectionItemType>));
+            }
+
+            iterator end() {
+                return iterator(data() + byte_size());
+            }
+
+            const_iterator cbegin() const {
+                return const_iterator(data() + sizeof(Collection<TMember, TCollectionItemType>));
+            }
+
+            const_iterator cend() const {
+                return const_iterator(data() + byte_size());
+            }
+
+            const_iterator begin() const {
+                return cbegin();
+            }
+
+            const_iterator end() const {
+                return cend();
+            }
+
+        }; // class Collection
+
+    } // namespace memory
+
+} // namespace osmium
+
+#endif // OSMIUM_MEMORY_COLLECTION_HPP
diff --git a/third_party/osmium/memory/item.hpp b/third_party/osmium/memory/item.hpp
new file mode 100644
index 0000000..2d22f94
--- /dev/null
+++ b/third_party/osmium/memory/item.hpp
@@ -0,0 +1,179 @@
+#ifndef OSMIUM_MEMORY_ITEM_HPP
+#define OSMIUM_MEMORY_ITEM_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <cstdint>
+#include <type_traits>
+
+namespace osmium {
+
+    // forward declaration, see osmium/osm/item_type.hpp for declaration
+    enum class item_type : uint16_t;
+
+    namespace builder {
+        class Builder;
+    }
+
+    namespace memory {
+
+        typedef uint32_t item_size_type;
+
+        // align datastructures to this many bytes
+        constexpr item_size_type align_bytes = 8;
+
+        template <typename T>
+        inline T padded_length(T length) noexcept {
+            static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
+                          "Template parameter must be unsigned integral type");
+            return (length + align_bytes - 1) & ~(align_bytes - 1);
+        }
+
+        /**
+         * @brief Namespace for Osmium internal use
+         */
+        namespace detail {
+
+            /**
+            * This class contains only a helper method used in several
+            * other classes.
+            */
+            class ItemHelper {
+
+            protected:
+
+                ItemHelper() = default;
+
+                ~ItemHelper() = default;
+
+                ItemHelper(const ItemHelper&) = default;
+                ItemHelper(ItemHelper&&) = default;
+
+                ItemHelper& operator=(const ItemHelper&) = default;
+                ItemHelper& operator=(ItemHelper&&) = default;
+
+            public:
+
+                unsigned char* data() noexcept {
+                    return reinterpret_cast<unsigned char*>(this);
+                }
+
+                const unsigned char* data() const noexcept {
+                    return reinterpret_cast<const unsigned char*>(this);
+                }
+
+            }; // class ItemHelper
+
+        } // namespace detail
+
+        class Item : public osmium::memory::detail::ItemHelper {
+
+            item_size_type m_size;
+            item_type m_type;
+            uint16_t m_removed : 1;
+            uint16_t m_padding : 15;
+
+            template <class TMember>
+            friend class CollectionIterator;
+
+            template <class TMember>
+            friend class ItemIterator;
+
+            friend class osmium::builder::Builder;
+
+            Item& add_size(const item_size_type size) noexcept {
+                m_size += size;
+                return *this;
+            }
+
+        protected:
+
+            explicit Item(item_size_type size=0, item_type type=item_type()) noexcept :
+                m_size(size),
+                m_type(type),
+                m_removed(false),
+                m_padding(0) {
+            }
+
+            Item(const Item&) = delete;
+            Item(Item&&) = delete;
+
+            Item& operator=(const Item&) = delete;
+            Item& operator=(Item&&) = delete;
+
+            Item& set_type(const item_type item_type) noexcept {
+                m_type = item_type;
+                return *this;
+            }
+
+        public:
+
+            unsigned char* next() noexcept {
+                return data() + padded_size();
+            }
+
+            const unsigned char* next() const noexcept {
+                return data() + padded_size();
+            }
+
+            item_size_type byte_size() const noexcept {
+                return m_size;
+            }
+
+            item_size_type padded_size() const {
+                return padded_length(m_size);
+            }
+
+            item_type type() const noexcept {
+                return m_type;
+            }
+
+            bool removed() const noexcept {
+                return m_removed;
+            }
+
+            void set_removed(bool removed) noexcept {
+                m_removed = removed;
+            }
+
+        }; // class Item
+
+        static_assert(sizeof(Item) == 8, "Class osmium::Item has wrong size!");
+        static_assert(sizeof(Item) % align_bytes == 0, "Class osmium::Item has wrong size to be aligned properly!");
+
+    } // namespace memory
+
+} // namespace osmium
+
+#endif // OSMIUM_MEMORY_ITEM_HPP
diff --git a/third_party/osmium/memory/item_iterator.hpp b/third_party/osmium/memory/item_iterator.hpp
new file mode 100644
index 0000000..34ed600
--- /dev/null
+++ b/third_party/osmium/memory/item_iterator.hpp
@@ -0,0 +1,234 @@
+#ifndef OSMIUM_ITEM_ITERATOR_HPP
+#define OSMIUM_ITEM_ITERATOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <iterator>
+#include <iosfwd>
+#include <type_traits>
+
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+
+namespace osmium {
+
+    class Node;
+    class Way;
+    class Relation;
+    class Area;
+    class Changeset;
+    class OSMObject;
+    class OSMEntity;
+    class TagList;
+    class WayNodeList;
+    class RelationMemberList;
+    class InnerRing;
+    class OuterRing;
+
+    namespace memory {
+
+        namespace detail {
+
+            template <class T>
+            inline bool type_is_compatible(osmium::item_type) noexcept {
+                return true;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::Node>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::node;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::Way>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::way;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::Relation>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::relation;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::Area>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::area;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::Changeset>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::changeset;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::OSMObject>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::node || t == osmium::item_type::way || t == osmium::item_type::relation || t == osmium::item_type::area;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::OSMEntity>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::node || t == osmium::item_type::way || t == osmium::item_type::relation || t == osmium::item_type::area || t == osmium::item_type::changeset;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::TagList>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::tag_list;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::WayNodeList>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::way_node_list;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::RelationMemberList>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::relation_member_list || t == osmium::item_type::relation_member_list_with_full_members;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::OuterRing>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::outer_ring;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::InnerRing>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::inner_ring;
+            }
+
+        } // namespace detail
+
+        template <class TMember>
+        class ItemIterator : public std::iterator<std::forward_iterator_tag, TMember> {
+
+            static_assert(std::is_base_of<osmium::memory::Item, TMember>::value, "TMember must derive from osmium::memory::Item");
+
+            // This data_type is either 'unsigned char*' or 'const unsigned char*' depending
+            // on whether TMember is const. This allows this class to be used as an iterator and
+            // as a const_iterator.
+            typedef typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type data_type;
+
+            data_type m_data;
+            data_type m_end;
+
+            void advance_to_next_item_of_right_type() {
+                while (m_data != m_end &&
+                       !detail::type_is_compatible<typename std::remove_const<TMember>::type>(reinterpret_cast<const osmium::memory::Item*>(m_data)->type())) {
+                    m_data = reinterpret_cast<TMember*>(m_data)->next();
+                }
+            }
+
+        public:
+
+            ItemIterator() noexcept :
+                m_data(nullptr),
+                m_end(nullptr) {
+            }
+
+            ItemIterator(data_type data, data_type end) :
+                m_data(data),
+                m_end(end) {
+                advance_to_next_item_of_right_type();
+            }
+
+            template <class T>
+            ItemIterator<T> cast() const {
+                return ItemIterator<T>(m_data, m_end);
+            }
+
+            ItemIterator<TMember>& operator++() {
+                assert(m_data);
+                assert(m_data != m_end);
+                m_data = reinterpret_cast<TMember*>(m_data)->next();
+                advance_to_next_item_of_right_type();
+                return *static_cast<ItemIterator<TMember>*>(this);
+            }
+
+            /**
+             * Like operator++() but will NOT skip items of unwanted
+             * types. Do not use this unless you know what you are
+             * doing.
+             */
+            ItemIterator<TMember>& advance_once() {
+                assert(m_data);
+                assert(m_data != m_end);
+                m_data = reinterpret_cast<TMember*>(m_data)->next();
+                return *static_cast<ItemIterator<TMember>*>(this);
+            }
+
+            ItemIterator<TMember> operator++(int) {
+                ItemIterator<TMember> tmp(*this);
+                operator++();
+                return tmp;
+            }
+
+            bool operator==(const ItemIterator<TMember>& rhs) const {
+                return m_data == rhs.m_data && m_end == rhs.m_end;
+            }
+
+            bool operator!=(const ItemIterator<TMember>& rhs) const {
+                return !(*this == rhs);
+            }
+
+            unsigned char* data() const {
+                assert(m_data);
+                return m_data;
+            }
+
+            TMember& operator*() const {
+                assert(m_data);
+                assert(m_data != m_end);
+                return *reinterpret_cast<TMember*>(m_data);
+            }
+
+            TMember* operator->() const {
+                assert(m_data);
+                assert(m_data != m_end);
+                return reinterpret_cast<TMember*>(m_data);
+            }
+
+            explicit operator bool() const {
+                return m_data != nullptr;
+            }
+
+            template <typename TChar, typename TTraits>
+            friend std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const ItemIterator<TMember>& iter) {
+                return out << static_cast<void*>(iter.m_data);
+            }
+
+        }; // class ItemIterator
+
+    } // namespace memory
+
+} // namespace osmium
+
+#endif // OSMIUM_ITEM_ITERATOR_HPP
diff --git a/third_party/osmium/object_pointer_collection.hpp b/third_party/osmium/object_pointer_collection.hpp
new file mode 100644
index 0000000..22029a1
--- /dev/null
+++ b/third_party/osmium/object_pointer_collection.hpp
@@ -0,0 +1,112 @@
+#ifndef OSMIUM_OBJECT_POINTER_COLLECTION_HPP
+#define OSMIUM_OBJECT_POINTER_COLLECTION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <utility>
+#include <vector>
+
+#include <boost/iterator/indirect_iterator.hpp>
+
+#include <osmium/handler.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/object.hpp>
+
+// IWYU pragma: no_forward_declare osmium::OSMObject
+// IWYU pragma: no_forward_declare osmium::memory::Item
+
+namespace osmium {
+
+    /**
+     * A collection of pointers to OSM objects. The pointers can be easily
+     * and quickly sorted or otherwise manipulated, while the objects
+     * themselves or the buffers they are in, do not have to be changed.
+     *
+     * An iterator is provided that can iterate over the pointers but looks
+     * like it is iterating over the underlying OSM objects.
+     *
+     * This class implements the visitor pattern which makes it easy to
+     * populate the collection from a buffer of OSM objects:
+     *
+     *   osmium::ObjectPointerCollection objects;
+     *   osmium::memory::Buffer buffer = reader.read();
+     *   osmium::apply(buffer, objects);
+     *
+     */
+    class ObjectPointerCollection : public osmium::handler::Handler {
+
+        std::vector<osmium::OSMObject*> m_objects;
+
+    public:
+
+        typedef boost::indirect_iterator<std::vector<osmium::OSMObject*>::iterator, osmium::OSMObject> iterator;
+        typedef boost::indirect_iterator<std::vector<osmium::OSMObject*>::const_iterator, const osmium::OSMObject> const_iterator;
+
+        ObjectPointerCollection() noexcept :
+            m_objects() {
+        }
+
+        void osm_object(osmium::OSMObject& object) {
+            m_objects.push_back(&object);
+        }
+
+        /**
+         * Sort objects according to the given order functor.
+         */
+        template <class TCompare>
+        void sort(TCompare&& compare) {
+            std::sort(m_objects.begin(), m_objects.end(), std::forward<TCompare>(compare));
+        }
+
+        iterator begin() {
+            return iterator { m_objects.begin() };
+        }
+
+        iterator end() {
+            return iterator { m_objects.end() };
+        }
+
+        const_iterator cbegin() const {
+            return const_iterator { m_objects.cbegin() };
+        }
+
+        const_iterator cend() const {
+            return const_iterator { m_objects.cend() };
+        }
+
+    }; // class ObjectPointerCollection
+
+} // namespace osmium
+
+#endif // OSMIUM_OBJECT_POINTER_COLLECTION_HPP
diff --git a/third_party/osmium/osm.hpp b/third_party/osmium/osm.hpp
new file mode 100644
index 0000000..bf21c19
--- /dev/null
+++ b/third_party/osmium/osm.hpp
@@ -0,0 +1,48 @@
+#ifndef OSMIUM_OSM_HPP
+#define OSMIUM_OSM_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/osm/node.hpp> // IWYU pragma: export
+#include <osmium/osm/way.hpp> // IWYU pragma: export
+#include <osmium/osm/relation.hpp> // IWYU pragma: export
+#include <osmium/osm/area.hpp> // IWYU pragma: export
+#include <osmium/osm/changeset.hpp> // IWYU pragma: export
+
+/**
+ * @brief Namespace for everything in the Osmium library.
+ */
+namespace osmium {
+} // namespace osmium
+
+#endif // OSMIUM_OSM_HPP
diff --git a/third_party/osmium/osm/area.hpp b/third_party/osmium/osm/area.hpp
new file mode 100644
index 0000000..a388de2
--- /dev/null
+++ b/third_party/osmium/osm/area.hpp
@@ -0,0 +1,193 @@
+#ifndef OSMIUM_OSM_AREA_HPP
+#define OSMIUM_OSM_AREA_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstdlib>
+#include <utility>
+
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/node_ref_list.hpp>
+
+namespace osmium {
+
+    namespace builder {
+        template <class T> class ObjectBuilder;
+    }
+
+    /**
+     * An outer ring of an Area.
+     */
+    class OuterRing : public NodeRefList<osmium::item_type::outer_ring> {
+
+    public:
+
+        OuterRing():
+            NodeRefList<osmium::item_type::outer_ring>() {
+        }
+
+    }; // class OuterRing
+
+    static_assert(sizeof(OuterRing) % osmium::memory::align_bytes == 0, "Class osmium::OuterRing has wrong size to be aligned properly!");
+
+    /**
+     * An inner ring of an Area.
+     */
+    class InnerRing : public NodeRefList<osmium::item_type::inner_ring> {
+
+    public:
+
+        InnerRing():
+            NodeRefList<osmium::item_type::inner_ring>() {
+        }
+
+    }; // class InnerRing
+
+    static_assert(sizeof(InnerRing) % osmium::memory::align_bytes == 0, "Class osmium::InnerRing has wrong size to be aligned properly!");
+
+    /**
+     * Convert way or (multipolygon) relation id into unique area id.
+     *
+     * @param id Id of a way or relation
+     * @param type Type of object (way or relation)
+     * @returns Area id
+     */
+    inline osmium::object_id_type object_id_to_area_id(osmium::object_id_type id, osmium::item_type type) {
+        osmium::object_id_type area_id = std::abs(id) * 2;
+        if (type == osmium::item_type::relation) {
+            ++area_id;
+        }
+        return id < 0 ? -area_id : area_id;
+    }
+
+    /**
+     * Convert area id into id of the way or relation it was created from.
+     *
+     * @param id Area id
+     * @returns Way or Relation id.
+     */
+    inline osmium::object_id_type area_id_to_object_id(osmium::object_id_type id) {
+        return id / 2;
+    }
+
+    /**
+     * An OSM area created out of a closed way or a multipolygon relation.
+     */
+    class Area : public OSMObject {
+
+        friend class osmium::builder::ObjectBuilder<osmium::Area>;
+
+        Area() :
+            OSMObject(sizeof(Area), osmium::item_type::area) {
+        }
+
+    public:
+
+        static constexpr osmium::item_type itemtype = osmium::item_type::area;
+
+        /**
+         * Was this area created from a way? (In contrast to areas
+         * created from a relation and their members.)
+         */
+        bool from_way() const noexcept {
+            return (positive_id() & 0x1) == 0;
+        }
+
+        /**
+         * Return the Id of the way or relation this area was created from.
+         */
+        osmium::object_id_type orig_id() const {
+            return osmium::area_id_to_object_id(id());
+        }
+
+        /**
+         * Count the number of outer and inner rings of this area.
+         */
+        std::pair<int, int> num_rings() const {
+            std::pair<int, int> counter;
+
+            for (auto it = cbegin(); it != cend(); ++it) {
+                switch (it->type()) {
+                    case osmium::item_type::outer_ring:
+                        ++counter.first;
+                        break;
+                    case osmium::item_type::inner_ring:
+                        ++counter.second;
+                        break;
+                    case osmium::item_type::tag_list:
+                        // ignore tags
+                        break;
+                    case osmium::item_type::undefined:
+                    case osmium::item_type::node:
+                    case osmium::item_type::way:
+                    case osmium::item_type::relation:
+                    case osmium::item_type::area:
+                    case osmium::item_type::changeset:
+                    case osmium::item_type::way_node_list:
+                    case osmium::item_type::relation_member_list:
+                    case osmium::item_type::relation_member_list_with_full_members:
+                        assert(false && "Children of Area can only be outer/inner_ring and tag_list.");
+                        break;
+                }
+            }
+
+            return counter;
+        }
+
+        /**
+         * Is this area a multipolygon, ie. has it more than one outer ring?
+         */
+        bool is_multipolygon() const {
+            return num_rings().first > 1;
+        }
+
+        osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cbegin(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
+            return it.cast<const osmium::InnerRing>();
+        }
+
+        osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cend(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
+            return std::next(it).cast<const osmium::InnerRing>();
+        }
+
+    }; // class Area
+
+    static_assert(sizeof(Area) % osmium::memory::align_bytes == 0, "Class osmium::Area has wrong size to be aligned properly!");
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_AREA_HPP
diff --git a/third_party/osmium/osm/box.hpp b/third_party/osmium/osm/box.hpp
new file mode 100644
index 0000000..2b761fe
--- /dev/null
+++ b/third_party/osmium/osm/box.hpp
@@ -0,0 +1,207 @@
+#ifndef OSMIUM_OSM_BOX_HPP
+#define OSMIUM_OSM_BOX_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <iosfwd>
+
+#include <osmium/util/compatibility.hpp>
+#include <osmium/osm/location.hpp>
+
+namespace osmium {
+
+    /**
+     * Bounding box.
+     */
+    class Box {
+
+        osmium::Location m_bottom_left;
+        osmium::Location m_top_right;
+
+    public:
+
+        /**
+         * Create undefined Box. Use the extend() function
+         * to add actual bounds.
+         */
+        constexpr Box() noexcept :
+            m_bottom_left(),
+            m_top_right() {
+        }
+
+        Box(double minx, double miny, double maxx, double maxy) :
+            m_bottom_left(minx, miny),
+            m_top_right(maxx, maxy) {
+        }
+
+        Box(const osmium::Location& bottom_left, const osmium::Location& top_right) :
+            m_bottom_left(bottom_left),
+            m_top_right(top_right) {
+        }
+
+        Box(const Box&) = default;
+        Box(Box&&) = default;
+        Box& operator=(const Box&) = default;
+        Box& operator=(Box&&) = default;
+        ~Box() = default;
+
+        /**
+         * Extend this bounding box by the given location. If the
+         * location is undefined, the bounding box is unchanged.
+         */
+        Box& extend(const Location& location) noexcept {
+            if (location) {
+                if (m_bottom_left) {
+                    if (location.x() < m_bottom_left.x()) {
+                        m_bottom_left.set_x(location.x());
+                    }
+                    if (location.x() > m_top_right.x()) {
+                        m_top_right.set_x(location.x());
+                    }
+                    if (location.y() < m_bottom_left.y()) {
+                        m_bottom_left.set_y(location.y());
+                    }
+                    if (location.y() > m_top_right.y()) {
+                        m_top_right.set_y(location.y());
+                    }
+                } else {
+                    m_bottom_left = location;
+                    m_top_right = location;
+                }
+            }
+            return *this;
+        }
+
+        /**
+         * Extend this bounding box by the given box. If the
+         * box is undefined, the bounding box is unchanged.
+         */
+        Box& extend(const Box& box) noexcept {
+            extend(box.bottom_left());
+            extend(box.top_right());
+            return *this;
+        }
+
+        /**
+         * Box are defined, ie. contains defined coordinates.
+         */
+        explicit constexpr operator bool() const noexcept {
+            return static_cast<bool>(m_bottom_left);
+        }
+
+        /**
+         * Box are valid, ie. defined and inside usual bounds
+         * (-180<=lon<=180, -90<=lat<=90).
+         */
+        constexpr bool valid() const noexcept {
+            return bottom_left().valid() && top_right().valid();
+        }
+
+        /**
+         * Bottom-left location.
+         */
+        OSMIUM_CONSTEXPR Location bottom_left() const noexcept {
+            return m_bottom_left;
+        }
+
+        /**
+         * Bottom-left location.
+         */
+        Location& bottom_left() noexcept {
+            return m_bottom_left;
+        }
+
+        /**
+         * Top-right location.
+         */
+        OSMIUM_CONSTEXPR Location top_right() const noexcept {
+            return m_top_right;
+        }
+
+        /**
+         * Top-right location.
+         */
+        Location& top_right() noexcept {
+            return m_top_right;
+        }
+
+        /**
+         * Is the location inside the box?
+         */
+        bool contains(const osmium::Location& location) const {
+            return location.x() >= bottom_left().x() && location.y() >= bottom_left().y() &&
+                   location.x() <= top_right().x() && location.y() <= top_right().y();
+        }
+
+        /**
+         * Calculate size of the box in square degrees.
+         *
+         * @throws osmium::invalid_location unless all coordinates are valid
+         */
+        double size() const {
+            return (m_top_right.lon() - m_bottom_left.lon()) *
+                   (m_top_right.lat() - m_bottom_left.lat());
+        }
+
+    }; // class Box
+
+    /**
+     * Boxes are equal if both locations are equal.
+     */
+    inline OSMIUM_CONSTEXPR bool operator==(const Box& lhs, const Box& rhs) noexcept {
+        return lhs.bottom_left() == rhs.bottom_left() && lhs.top_right() == rhs.top_right();
+    }
+
+    /**
+     * Output a box to a stream.
+     */
+    template <typename TChar, typename TTraits>
+    inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::Box& box) {
+        if (box) {
+            out << '('
+                << box.bottom_left().lon()
+                << ','
+                << box.bottom_left().lat()
+                << ','
+                << box.top_right().lon()
+                << ','
+                << box.top_right().lat()
+                << ')';
+        } else {
+            out << "(undefined)";
+        }
+        return out;
+    }
+} // namespace osmium
+
+#endif // OSMIUM_OSM_BOX_HPP
diff --git a/third_party/osmium/osm/changeset.hpp b/third_party/osmium/osm/changeset.hpp
new file mode 100644
index 0000000..2b79fb5
--- /dev/null
+++ b/third_party/osmium/osm/changeset.hpp
@@ -0,0 +1,336 @@
+#ifndef OSMIUM_OSM_CHANGESET_HPP
+#define OSMIUM_OSM_CHANGESET_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstdint>
+#include <cstring>
+
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/entity.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    namespace builder {
+        template <class T> class ObjectBuilder;
+    }
+
+    /**
+     * \brief An OSM Changeset, a group of changes made by a single user over
+     *        a short period of time.
+     *
+     * You can not create Changeset objects directly. Use the ChangesetBuilder
+     * class to create Changesets in a Buffer.
+     */
+    class Changeset : public osmium::OSMEntity {
+
+        friend class osmium::builder::ObjectBuilder<osmium::Changeset>;
+
+        osmium::Timestamp m_created_at;
+        osmium::Timestamp m_closed_at;
+        osmium::Box       m_bounds;
+        changeset_id_type m_id {0};
+        num_changes_type  m_num_changes {0};
+        user_id_type      m_uid {0};
+        string_size_type  m_user_size;
+
+        Changeset() :
+            OSMEntity(sizeof(Changeset), osmium::item_type::changeset) {
+        }
+
+        void set_user_size(string_size_type size) {
+            m_user_size = size;
+        }
+
+        unsigned char* subitems_position() {
+            return data() + osmium::memory::padded_length(sizeof(Changeset) + m_user_size);
+        }
+
+        const unsigned char* subitems_position() const {
+            return data() + osmium::memory::padded_length(sizeof(Changeset) + m_user_size);
+        }
+
+    public:
+
+        /// Get ID of this changeset
+        changeset_id_type id() const noexcept {
+            return m_id;
+        }
+
+        /**
+         * Set ID of this changeset
+         *
+         * @param id The id.
+         * @returns Reference to changeset to make calls chainable.
+         */
+        Changeset& set_id(changeset_id_type id) noexcept {
+            m_id = id;
+            return *this;
+        }
+
+        /**
+         * Set ID of this changeset.
+         *
+         * @param id The id.
+         * @returns Reference to object to make calls chainable.
+         */
+        Changeset& set_id(const char* id) {
+            return set_id(osmium::string_to_changeset_id(id));
+        }
+
+        /// Get user id.
+        user_id_type uid() const noexcept {
+            return m_uid;
+        }
+
+        /**
+         * Set user id.
+         *
+         * @param uid The user id.
+         * @returns Reference to changeset to make calls chainable.
+         */
+        Changeset& set_uid(user_id_type uid) noexcept {
+            m_uid = uid;
+            return *this;
+        }
+
+        /**
+         * Set user id to given uid or to 0 (anonymous user) if the given
+         * uid is smaller than 0.
+         *
+         * @param uid The user id.
+         * @returns Reference to changeset to make calls chainable.
+         */
+        Changeset& set_uid_from_signed(signed_user_id_type uid) noexcept {
+            m_uid = uid < 0 ? 0 : static_cast<user_id_type>(uid);
+            return *this;
+        }
+
+        /**
+         * Set user id to given uid or to 0 (anonymous user) if the given
+         * uid is smaller than 0.
+         *
+         * @returns Reference to changeset to make calls chainable.
+         */
+        Changeset& set_uid(const char* uid) {
+            return set_uid_from_signed(string_to_user_id(uid));
+        }
+
+        /// Is this user anonymous?
+        bool user_is_anonymous() const noexcept {
+            return m_uid == 0;
+        }
+
+        /// Get timestamp when this changeset was created.
+        osmium::Timestamp created_at() const noexcept {
+            return m_created_at;
+        }
+
+        /**
+         * Get timestamp when this changeset was closed.
+         *
+         * @returns Timestamp. Will return the empty Timestamp when the
+         *          changeset is not yet closed.
+         */
+        osmium::Timestamp closed_at() const noexcept {
+            return m_closed_at;
+        }
+
+        /// Is this changeset open?
+        bool open() const noexcept {
+            return m_closed_at == osmium::Timestamp();
+        }
+
+        /// Is this changeset closed?
+        bool closed() const noexcept {
+            return !open();
+        }
+
+        /**
+         * Set the timestamp when this changeset was created.
+         *
+         * @param timestamp Timestamp
+         * @returns Reference to changeset to make calls chainable.
+         */
+        Changeset& set_created_at(const osmium::Timestamp timestamp) {
+            m_created_at = timestamp;
+            return *this;
+        }
+
+        /**
+         * Set the timestamp when this changeset was closed.
+         *
+         * @param timestamp Timestamp
+         * @returns Reference to changeset to make calls chainable.
+         */
+        Changeset& set_closed_at(const osmium::Timestamp timestamp) {
+            m_closed_at = timestamp;
+            return *this;
+        }
+
+        /// Get the number of changes in this changeset
+        num_changes_type num_changes() const noexcept {
+            return m_num_changes;
+        }
+
+        /// Set the number of changes in this changeset
+        Changeset& set_num_changes(num_changes_type num_changes) noexcept {
+            m_num_changes = num_changes;
+            return *this;
+        }
+
+        /// Set the number of changes in this changeset
+        Changeset& set_num_changes(const char* num_changes) noexcept {
+            return set_num_changes(osmium::string_to_num_changes(num_changes));
+        }
+
+        /**
+         * Get the bounding box of this changeset.
+         *
+         * @returns Bounding box. Can be empty.
+         */
+        osmium::Box& bounds() noexcept {
+            return m_bounds;
+        }
+
+        /**
+         * Get the bounding box of this changeset.
+         *
+         * @returns Bounding box. Can be empty.
+         */
+        const osmium::Box& bounds() const noexcept {
+            return m_bounds;
+        }
+
+        /// Get user name.
+        const char* user() const {
+            return reinterpret_cast<const char*>(data() + sizeof(Changeset));
+        }
+
+        /// Get the list of tags.
+        const TagList& tags() const {
+            return osmium::detail::subitem_of_type<const TagList>(cbegin(), cend());
+        }
+
+        /**
+         * Set named attribute.
+         *
+         * @param attr Name of the attribute (must be one of "id", "version",
+         *             "changeset", "timestamp", "uid", "visible")
+         * @param value Value of the attribute
+         */
+        void set_attribute(const char* attr, const char* value) {
+            if (!strcmp(attr, "id")) {
+                set_id(value);
+            } else if (!strcmp(attr, "num_changes")) {
+                set_num_changes(value);
+            } else if (!strcmp(attr, "created_at")) {
+                set_created_at(osmium::Timestamp(value));
+            } else if (!strcmp(attr, "closed_at")) {
+                set_closed_at(osmium::Timestamp(value));
+            } else if (!strcmp(attr, "uid")) {
+                set_uid(value);
+            }
+        }
+
+        typedef osmium::memory::CollectionIterator<Item> iterator;
+        typedef osmium::memory::CollectionIterator<const Item> const_iterator;
+
+        iterator begin() {
+            return iterator(subitems_position());
+        }
+
+        iterator end() {
+            return iterator(data() + padded_size());
+        }
+
+        const_iterator cbegin() const {
+            return const_iterator(subitems_position());
+        }
+
+        const_iterator cend() const {
+            return const_iterator(data() + padded_size());
+        }
+
+        const_iterator begin() const {
+            return cbegin();
+        }
+
+        const_iterator end() const {
+            return cend();
+        }
+
+    }; // class Changeset
+
+    static_assert(sizeof(Changeset) % osmium::memory::align_bytes == 0,
+        "Class osmium::Changeset has wrong size to be aligned properly!");
+
+    /**
+     * Changesets are equal if their IDs are equal.
+     */
+    inline bool operator==(const Changeset& lhs, const Changeset& rhs) {
+        return lhs.id() == rhs.id();
+    }
+
+    inline bool operator!=(const Changeset& lhs, const Changeset& rhs) {
+        return ! (lhs == rhs);
+    }
+
+    /**
+     * Changesets can be ordered by id.
+     */
+    inline bool operator<(const Changeset& lhs, const Changeset& rhs) {
+        return lhs.id() < rhs.id();
+    }
+
+    inline bool operator>(const Changeset& lhs, const Changeset& rhs) {
+        return rhs < lhs;
+    }
+
+    inline bool operator<=(const Changeset& lhs, const Changeset& rhs) {
+        return ! (rhs < lhs);
+    }
+
+    inline bool operator>=(const Changeset& lhs, const Changeset& rhs) {
+        return ! (lhs < rhs);
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_CHANGESET_HPP
diff --git a/third_party/osmium/osm/diff_object.hpp b/third_party/osmium/osm/diff_object.hpp
new file mode 100644
index 0000000..a8f91ec
--- /dev/null
+++ b/third_party/osmium/osm/diff_object.hpp
@@ -0,0 +1,156 @@
+#ifndef OSMIUM_OSM_DIFF_OBJECT_HPP
+#define OSMIUM_OSM_DIFF_OBJECT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    class Node;
+    class Way;
+    class Relation;
+
+    class DiffObject {
+
+    protected:
+
+        osmium::OSMObject* m_prev;
+        osmium::OSMObject* m_curr;
+        osmium::OSMObject* m_next;
+
+    public:
+
+        DiffObject() noexcept :
+            m_prev(nullptr),
+            m_curr(nullptr),
+            m_next(nullptr) {
+        }
+
+        explicit DiffObject(osmium::OSMObject& prev, osmium::OSMObject& curr, osmium::OSMObject& next) noexcept :
+            m_prev(&prev),
+            m_curr(&curr),
+            m_next(&next) {
+        }
+
+        DiffObject(const DiffObject&) = default;
+        DiffObject& operator=(const DiffObject&) = default;
+
+        DiffObject(DiffObject&&) = default;
+        DiffObject& operator=(DiffObject&&) = default;
+
+        const osmium::OSMObject& prev() const noexcept {
+            return *m_prev;
+        }
+
+        const osmium::OSMObject& curr() const noexcept {
+            return *m_curr;
+        }
+
+        const osmium::OSMObject& next() const noexcept {
+            return *m_next;
+        }
+
+        bool first() const noexcept {
+            return m_prev == m_curr;
+        }
+
+        bool last() const noexcept {
+            return m_curr == m_next;
+        }
+
+        osmium::item_type type() const noexcept {
+            return m_curr->type();
+        }
+
+        osmium::object_id_type id() const noexcept {
+            return m_curr->id();
+        }
+
+        osmium::object_version_type version() const noexcept {
+            return m_curr->version();
+        }
+
+        osmium::changeset_id_type changeset() const noexcept {
+            return m_curr->changeset();
+        }
+
+        const osmium::Timestamp start_time() const noexcept {
+            return m_curr->timestamp();
+        }
+
+        const osmium::Timestamp end_time() const noexcept {
+            return last() ? osmium::Timestamp() : m_next->timestamp();
+        }
+
+    }; // class DiffObject
+
+    template <class T>
+    class DiffObjectDerived : public DiffObject {
+
+    public:
+
+        DiffObjectDerived(T& prev, T& curr, T& next) noexcept :
+            DiffObject(prev, curr, next) {
+        }
+
+        DiffObjectDerived(const DiffObjectDerived&) = default;
+        DiffObjectDerived& operator=(const DiffObjectDerived&) = default;
+
+        DiffObjectDerived(DiffObjectDerived&&) = default;
+        DiffObjectDerived& operator=(DiffObjectDerived&&) = default;
+
+        const T& prev() const noexcept {
+            return *static_cast<const T*>(m_prev);
+        }
+
+        const T& curr() const noexcept {
+            return *static_cast<const T*>(m_curr);
+        }
+
+        const T& next() const noexcept {
+            return *static_cast<const T*>(m_next);
+        }
+
+    }; // class DiffObjectDerived
+
+    typedef DiffObjectDerived<osmium::Node>     DiffNode;
+    typedef DiffObjectDerived<osmium::Way>      DiffWay;
+    typedef DiffObjectDerived<osmium::Relation> DiffRelation;
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_DIFF_OBJECT_HPP
diff --git a/third_party/osmium/osm/entity.hpp b/third_party/osmium/osm/entity.hpp
new file mode 100644
index 0000000..e37ed4c
--- /dev/null
+++ b/third_party/osmium/osm/entity.hpp
@@ -0,0 +1,74 @@
+#ifndef OSMIUM_OSM_ENTITY_HPP
+#define OSMIUM_OSM_ENTITY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/memory/item.hpp>
+
+namespace osmium {
+
+    namespace detail {
+
+        template <class TSubitem, class TIter>
+        inline TSubitem& subitem_of_type(TIter it, TIter end) {
+            for (; it != end; ++it) {
+                if (it->type() == TSubitem::itemtype) {
+                    return reinterpret_cast<TSubitem&>(*it);
+                }
+            }
+
+            // If no subitem of the TSubitem type was found,
+            // return a default constructed one.
+            static TSubitem subitem;
+            return subitem;
+        }
+
+    } // namespace detail
+
+    /**
+     * \brief OSMEntity is the abstract base class for the OSMObject and
+     *        Changeset classes.
+     */
+    class OSMEntity : public osmium::memory::Item {
+
+    public:
+
+        explicit OSMEntity(osmium::memory::item_size_type size, osmium::item_type type) :
+            Item(size, type) {
+        }
+
+    }; // class OSMEntity
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_ENTITY_HPP
diff --git a/third_party/osmium/osm/entity_bits.hpp b/third_party/osmium/osm/entity_bits.hpp
new file mode 100644
index 0000000..2a4d964
--- /dev/null
+++ b/third_party/osmium/osm/entity_bits.hpp
@@ -0,0 +1,99 @@
+#ifndef OSMIUM_OSM_ENTITY_BITS_HPP
+#define OSMIUM_OSM_ENTITY_BITS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+namespace osmium {
+
+    /**
+     * @brief Bitfield for OSM entity types.
+     */
+    namespace osm_entity_bits {
+
+        /**
+         * Describes zero or more OSM entities.
+         *
+         * Usage:
+         *
+         * @code{.cpp}
+         * osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::node | osmium::osm_entity_bits::way;
+         *
+         * entities |= osmium::osm_entity_bits::relation;
+         *
+         * assert(entities & osmium::osm_entity_bits::object);
+         *
+         * assert(! (entities & osmium::osm_entity_bits::changeset));
+         * @endcode
+         */
+        enum type : unsigned char {
+
+            nothing    = 0x00,
+            node       = 0x01,
+            way        = 0x02,
+            relation   = 0x04,
+            nwr        = 0x07, ///< node, way, or relation object
+            area       = 0x08,
+            nwra       = 0x0f, ///< node, way, relation, or area object
+            object     = 0x0f, ///< node, way, relation, or area object
+            changeset  = 0x10,
+            all        = 0x1f  ///< object or changeset
+
+        }; // enum type
+
+        inline type operator|(const type lhs, const type rhs) noexcept {
+            return static_cast<type>(static_cast<int>(lhs) | static_cast<int> (rhs));
+        }
+
+        inline type& operator|=(type& lhs, const type rhs) noexcept {
+            lhs = lhs | rhs;
+            return lhs;
+        }
+
+        inline type operator&(const type lhs, const type rhs) noexcept {
+            return static_cast<type>(static_cast<int>(lhs) & static_cast<int> (rhs));
+        }
+
+        inline type operator~(const type value) noexcept {
+            return static_cast<type>(~static_cast<int>(value));
+        }
+
+        inline type operator&=(type& lhs, const type rhs) noexcept {
+            lhs = lhs & rhs;
+            return lhs;
+        }
+
+    } // namespace osm_entity_bits
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_ENTITY_BITS_HPP
diff --git a/third_party/osmium/osm/item_type.hpp b/third_party/osmium/osm/item_type.hpp
new file mode 100644
index 0000000..d277e06
--- /dev/null
+++ b/third_party/osmium/osm/item_type.hpp
@@ -0,0 +1,173 @@
+#ifndef OSMIUM_OSM_ITEM_TYPE_HPP
+#define OSMIUM_OSM_ITEM_TYPE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstdint> // IWYU pragma: keep
+#include <iosfwd>
+#include <stdexcept>
+
+namespace osmium {
+
+    enum class item_type : uint16_t {
+
+        undefined                              = 0x00,
+        node                                   = 0x01,
+        way                                    = 0x02,
+        relation                               = 0x03,
+        area                                   = 0x04,
+        changeset                              = 0x05,
+        tag_list                               = 0x11,
+        way_node_list                          = 0x12,
+        relation_member_list                   = 0x13,
+        relation_member_list_with_full_members = 0x23,
+        outer_ring                             = 0x40,
+        inner_ring                             = 0x41
+
+    }; // enum class item_type
+
+    inline item_type char_to_item_type(const char c) noexcept {
+        switch (c) {
+            case 'X':
+                return item_type::undefined;
+            case 'n':
+                return item_type::node;
+            case 'w':
+                return item_type::way;
+            case 'r':
+                return item_type::relation;
+            case 'a':
+                return item_type::area;
+            case 'c':
+                return item_type::changeset;
+            case 'T':
+                return item_type::tag_list;
+            case 'N':
+                return item_type::way_node_list;
+            case 'M':
+                return item_type::relation_member_list;
+            case 'F':
+                return item_type::relation_member_list_with_full_members;
+            case 'O':
+                return item_type::outer_ring;
+            case 'I':
+                return item_type::inner_ring;
+            default:
+                return item_type::undefined;
+        }
+    }
+
+// avoid g++ false positive
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wreturn-type"
+    inline char item_type_to_char(const item_type type) noexcept {
+        switch (type) {
+            case item_type::undefined:
+                return 'X';
+            case item_type::node:
+                return 'n';
+            case item_type::way:
+                return 'w';
+            case item_type::relation:
+                return 'r';
+            case item_type::area:
+                return 'a';
+            case item_type::changeset:
+                return 'c';
+            case item_type::tag_list:
+                return 'T';
+            case item_type::way_node_list:
+                return 'N';
+            case item_type::relation_member_list:
+                return 'M';
+            case item_type::relation_member_list_with_full_members:
+                return 'F';
+            case item_type::outer_ring:
+                return 'O';
+            case item_type::inner_ring:
+                return 'I';
+        }
+    }
+
+    inline const char* item_type_to_name(const item_type type) noexcept {
+        switch (type) {
+            case item_type::undefined:
+                return "undefined";
+            case item_type::node:
+                return "node";
+            case item_type::way:
+                return "way";
+            case item_type::relation:
+                return "relation";
+            case item_type::area:
+                return "area";
+            case item_type::changeset:
+                return "changeset";
+            case item_type::tag_list:
+                return "tag_list";
+            case item_type::way_node_list:
+                return "way_node_list";
+            case item_type::relation_member_list:
+                return "relation_member_list";
+            case item_type::relation_member_list_with_full_members:
+                return "relation_member_list_with_full_members";
+            case item_type::outer_ring:
+                return "outer_ring";
+            case item_type::inner_ring:
+                return "inner_ring";
+        }
+    }
+#pragma GCC diagnostic pop
+
+    template <typename TChar, typename TTraits>
+    inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const item_type item_type) {
+        return out << item_type_to_char(item_type);
+    }
+
+    /**
+     * This exception is thrown when a visitor encounters an unknown item type.
+     * Under usual circumstance this should not happen. If it does happen, it
+     * probably means the buffer contains different kinds of objects than were
+     * expected or that there is some kind of data corruption.
+     */
+    struct unknown_type : public std::runtime_error {
+
+        unknown_type() :
+            std::runtime_error("unknown item type") {
+        }
+
+    }; // struct unknown_type
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_ITEM_TYPE_HPP
diff --git a/third_party/osmium/osm/location.hpp b/third_party/osmium/osm/location.hpp
new file mode 100644
index 0000000..cabecd5
--- /dev/null
+++ b/third_party/osmium/osm/location.hpp
@@ -0,0 +1,285 @@
+#ifndef OSMIUM_OSM_LOCATION_HPP
+#define OSMIUM_OSM_LOCATION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cmath>
+#include <cstdint>
+#include <iosfwd>
+#include <stdexcept>
+#include <string>
+
+#include <iostream>
+
+#include <osmium/util/compatibility.hpp>
+#include <osmium/util/double.hpp>
+
+namespace osmium {
+
+    /**
+     * Exception signaling an invalid location, ie a location
+     * outside the -180 to 180 and -90 to 90 degree range.
+     */
+    struct invalid_location : public std::range_error {
+
+        invalid_location(const std::string& what) :
+            std::range_error(what) {
+        }
+
+        invalid_location(const char* what) :
+            std::range_error(what) {
+        }
+
+    }; // struct invalid_location
+
+    /**
+     * Locations define a place on earth.
+     *
+     * Locations are stored in 32 bit integers for the x and y
+     * coordinates, respectively. This gives you an accuracy of a few
+     * centimeters, good enough for OSM use. (The main OSM database
+     * uses the same scheme.)
+     *
+     * An undefined Location can be created by calling the constructor
+     * without parameters.
+     *
+     * Coordinates are never checked on whether they are inside bounds.
+     * Call valid() to check this.
+     */
+    class Location {
+
+        int32_t m_x;
+        int32_t m_y;
+
+    public:
+
+        // this value is used for a coordinate to mark it as undefined
+        // MSVC doesn't declare std::numeric_limits<int32_t>::max() as
+        // constexpr, so we hard code this for the time being.
+        // static constexpr int32_t undefined_coordinate = std::numeric_limits<int32_t>::max();
+        static constexpr int32_t undefined_coordinate = 2147483647;
+
+        static constexpr int coordinate_precision = 10000000;
+
+        static int32_t double_to_fix(const double c) noexcept {
+            return static_cast<int32_t>(std::round(c * coordinate_precision));
+        }
+
+        static OSMIUM_CONSTEXPR double fix_to_double(const int32_t c) noexcept {
+            return static_cast<double>(c) / coordinate_precision;
+        }
+
+        /**
+         * Create undefined Location.
+         */
+        explicit constexpr Location() noexcept :
+            m_x(undefined_coordinate),
+            m_y(undefined_coordinate) {
+        }
+
+        /**
+         * Create Location with given x and y coordinates.
+         * Note that these coordinates are coordinate_precision
+         * times larger than the real coordinates.
+         */
+        constexpr Location(const int32_t x, const int32_t y) noexcept :
+            m_x(x),
+            m_y(y) {
+        }
+
+        /**
+         * Create Location with given x and y coordinates.
+         * Note that these coordinates are coordinate_precision
+         * times larger than the real coordinates.
+         */
+        constexpr Location(const int64_t x, const int64_t y) noexcept :
+            m_x(static_cast<int32_t>(x)),
+            m_y(static_cast<int32_t>(y)) {
+        }
+
+        /**
+         * Create Location with given longitude and latitude.
+         */
+        Location(const double lon, const double lat) :
+            m_x(double_to_fix(lon)),
+            m_y(double_to_fix(lat)) {
+        }
+
+        Location(const Location&) = default;
+        Location(Location&&) = default;
+        Location& operator=(const Location&) = default;
+        Location& operator=(Location&&) = default;
+        ~Location() = default;
+
+        /**
+         * Check whether the coordinates of this location
+         * are defined.
+         */
+        explicit constexpr operator bool() const noexcept {
+            return m_x != undefined_coordinate && m_y != undefined_coordinate;
+        }
+
+        /**
+         * Check whether the coordinates are inside the
+         * usual bounds (-180<=lon<=180, -90<=lat<=90).
+         */
+        constexpr bool valid() const noexcept {
+            return m_x >= -180 * coordinate_precision
+                && m_x <=  180 * coordinate_precision
+                && m_y >=  -90 * coordinate_precision
+                && m_y <=   90 * coordinate_precision;
+        }
+
+        constexpr int32_t x() const noexcept {
+            return m_x;
+        }
+
+        constexpr int32_t y() const noexcept {
+            return m_y;
+        }
+
+        Location& set_x(const int32_t x) noexcept {
+            m_x = x;
+            return *this;
+        }
+
+        Location& set_y(const int32_t y) noexcept {
+            m_y = y;
+            return *this;
+        }
+
+        /**
+         * Get longitude.
+         *
+         * @throws invalid_location if the location is invalid
+         */
+        double lon() const {
+            if (!valid()) {
+                throw osmium::invalid_location("invalid location");
+            }
+            return fix_to_double(m_x);
+        }
+
+        /**
+         * Get longitude without checking the validity.
+         */
+        double lon_without_check() const {
+            return fix_to_double(m_x);
+        }
+
+        /**
+         * Get latitude.
+         *
+         * @throws invalid_location if the location is invalid
+         */
+        double lat() const {
+            if (!valid()) {
+                throw osmium::invalid_location("invalid location");
+            }
+            return fix_to_double(m_y);
+        }
+
+        /**
+         * Get latitude without checking the validity.
+         */
+        double lat_without_check() const {
+            return fix_to_double(m_y);
+        }
+
+        Location& set_lon(double lon) noexcept {
+            m_x = double_to_fix(lon);
+            return *this;
+        }
+
+        Location& set_lat(double lat) noexcept {
+            m_y = double_to_fix(lat);
+            return *this;
+        }
+
+        template <typename T>
+        T as_string(T iterator, const char separator) const {
+            iterator = osmium::util::double2string(iterator, lon(), 7);
+            *iterator++ = separator;
+            return osmium::util::double2string(iterator, lat(), 7);
+        }
+
+    }; // class Location
+
+    /**
+     * Locations are equal if both coordinates are equal.
+     */
+    inline OSMIUM_CONSTEXPR bool operator==(const Location& lhs, const Location& rhs) noexcept {
+        return lhs.x() == rhs.x() && lhs.y() == rhs.y();
+    }
+
+    inline OSMIUM_CONSTEXPR bool operator!=(const Location& lhs, const Location& rhs) noexcept {
+        return ! (lhs == rhs);
+    }
+
+    /**
+     * Compare two locations by comparing first the x and then
+     * the y coordinate. If either of the locations is
+     * undefined the result is undefined.
+     */
+    inline OSMIUM_CONSTEXPR bool operator<(const Location& lhs, const Location& rhs) noexcept {
+        return (lhs.x() == rhs.x() && lhs.y() < rhs.y()) || lhs.x() < rhs.x();
+    }
+
+    inline OSMIUM_CONSTEXPR bool operator>(const Location& lhs, const Location& rhs) noexcept {
+        return rhs < lhs;
+    }
+
+    inline OSMIUM_CONSTEXPR bool operator<=(const Location& lhs, const Location& rhs) noexcept {
+        return ! (rhs < lhs);
+    }
+
+    inline OSMIUM_CONSTEXPR bool operator>=(const Location& lhs, const Location& rhs) noexcept {
+        return ! (lhs < rhs);
+    }
+
+    /**
+     * Output a location to a stream.
+     */
+    template <typename TChar, typename TTraits>
+    inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::Location& location) {
+        if (location) {
+            out << '(' << location.lon() << ',' << location.lat() << ')';
+        } else {
+            out << "(undefined,undefined)";
+        }
+        return out;
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_LOCATION_HPP
diff --git a/third_party/osmium/osm/node.hpp b/third_party/osmium/osm/node.hpp
new file mode 100644
index 0000000..50146c5
--- /dev/null
+++ b/third_party/osmium/osm/node.hpp
@@ -0,0 +1,76 @@
+#ifndef OSMIUM_OSM_NODE_HPP
+#define OSMIUM_OSM_NODE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/object.hpp>
+
+namespace osmium {
+
+    namespace builder {
+        template <class T> class ObjectBuilder;
+    }
+
+    class Node : public OSMObject {
+
+        friend class osmium::builder::ObjectBuilder<osmium::Node>;
+
+        osmium::Location m_location;
+
+        Node() :
+            OSMObject(sizeof(Node), osmium::item_type::node) {
+        }
+
+    public:
+
+        static constexpr osmium::item_type itemtype = osmium::item_type::node;
+
+        osmium::Location location() const noexcept {
+            return m_location;
+        }
+
+        Node& set_location(const osmium::Location& location) {
+            m_location = location;
+            return *this;
+        }
+
+    }; // class Node
+
+    static_assert(sizeof(Node) % osmium::memory::align_bytes == 0, "Class osmium::Node has wrong size to be aligned properly!");
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_NODE_HPP
diff --git a/third_party/osmium/osm/node_ref.hpp b/third_party/osmium/osm/node_ref.hpp
new file mode 100644
index 0000000..ed50b9e
--- /dev/null
+++ b/third_party/osmium/osm/node_ref.hpp
@@ -0,0 +1,173 @@
+#ifndef OSMIUM_OSM_NODE_REF_HPP
+#define OSMIUM_OSM_NODE_REF_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstdlib>
+#include <iosfwd>
+
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    /**
+     * This reference to a node contains a node ID and a (possibly empty)
+     * location.
+     */
+    class NodeRef : public osmium::memory::detail::ItemHelper {
+
+        osmium::object_id_type m_ref;
+        osmium::Location m_location;
+
+    public:
+
+        NodeRef(const osmium::object_id_type ref=0, const osmium::Location& location=Location()) noexcept :
+            m_ref(ref),
+            m_location(location) {
+        }
+
+        osmium::object_id_type ref() const noexcept {
+            return m_ref;
+        }
+
+        osmium::unsigned_object_id_type positive_ref() const noexcept {
+            return static_cast<osmium::unsigned_object_id_type>(std::abs(m_ref));
+        }
+
+        /**
+         * Get reference to location in this NodeRef. Can be used to update it.
+         */
+        osmium::Location& location() noexcept {
+            return m_location;
+        }
+
+        osmium::Location location() const noexcept {
+            return m_location;
+        }
+
+        double lon() const {
+            return m_location.lon();
+        }
+
+        double lat() const {
+            return m_location.lat();
+        }
+
+        int32_t x() const noexcept {
+            return m_location.x();
+        }
+
+        int32_t y() const noexcept {
+            return m_location.y();
+        }
+
+        NodeRef& set_ref(const osmium::object_id_type ref) noexcept {
+            m_ref = ref;
+            return *this;
+        }
+
+        NodeRef& set_location(const osmium::Location& location) noexcept {
+            m_location = location;
+            return *this;
+        }
+
+    }; // class NodeRef
+
+    inline bool operator==(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+        return lhs.ref() == rhs.ref();
+    }
+
+    inline bool operator!=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+        return ! (lhs == rhs);
+    }
+
+    inline bool operator<(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+        return lhs.ref() < rhs.ref();
+    }
+
+    inline bool operator>(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+        return rhs < lhs;
+    }
+
+    inline bool operator<=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+        return ! (rhs < lhs);
+    }
+
+    inline bool operator>=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+        return ! (lhs < rhs);
+    }
+
+    /**
+     * Output a NodeRef to a stream.
+     */
+    template <typename TChar, typename TTraits>
+    inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::NodeRef& nr) {
+        return out << "<" << nr.ref() << " " << nr.location() << ">";
+    }
+
+    /**
+     * Functor to compare NodeRefs by Location instead of id.
+     */
+    struct location_equal {
+
+        bool operator()(const NodeRef& lhs, const NodeRef& rhs) const noexcept {
+            return lhs.location() == rhs.location();
+        }
+
+        typedef NodeRef first_argument_type;
+        typedef NodeRef second_argument_type;
+        typedef bool result_type;
+
+    }; // struct location_equal
+
+    /**
+     * Functor to compare NodeRefs by Location instead of id.
+     */
+    struct location_less {
+
+        bool operator()(const NodeRef& lhs, const NodeRef& rhs) const noexcept {
+            return lhs.location() < rhs.location();
+        }
+
+        typedef NodeRef first_argument_type;
+        typedef NodeRef second_argument_type;
+        typedef bool result_type;
+
+    }; // struct location_less
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_NODE_REF_HPP
diff --git a/third_party/osmium/osm/node_ref_list.hpp b/third_party/osmium/osm/node_ref_list.hpp
new file mode 100644
index 0000000..321c952
--- /dev/null
+++ b/third_party/osmium/osm/node_ref_list.hpp
@@ -0,0 +1,135 @@
+#ifndef OSMIUM_OSM_NODE_REF_LIST_HPP
+#define OSMIUM_OSM_NODE_REF_LIST_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/node_ref.hpp>
+
+namespace osmium {
+
+    /**
+     * A vector of NodeRef objects. Usually this is not instatiated directly,
+     * but one of its subclasses are used.
+     */
+    template <osmium::item_type TItemType>
+    class NodeRefList : public osmium::memory::Item {
+
+    public:
+
+        static constexpr osmium::item_type itemtype = TItemType;
+
+        NodeRefList() noexcept :
+            osmium::memory::Item(sizeof(NodeRefList), TItemType) {
+        }
+
+        bool empty() const noexcept {
+            return sizeof(NodeRefList) == byte_size();
+        }
+
+        size_t size() const noexcept {
+            assert((osmium::memory::Item::byte_size() - sizeof(NodeRefList)) % sizeof(NodeRef) == 0);
+            return (osmium::memory::Item::byte_size() - sizeof(NodeRefList)) / sizeof(NodeRef);
+        }
+
+        const NodeRef& operator[](size_t n) const {
+            const NodeRef* node_ref = &*(cbegin());
+            return node_ref[n];
+        }
+
+        const NodeRef& front() const {
+            return operator[](0);
+        }
+
+        const NodeRef& back() const {
+            return operator[](size()-1);
+        }
+
+        bool is_closed() const {
+            return front().ref() == back().ref();
+        }
+
+        bool ends_have_same_id() const {
+            return front().ref() == back().ref();
+        }
+
+        bool ends_have_same_location() const {
+            return front().location() == back().location();
+        }
+
+        typedef NodeRef* iterator;
+        typedef const NodeRef* const_iterator;
+        typedef std::reverse_iterator<const NodeRef*> const_reverse_iterator;
+
+        iterator begin() {
+            return iterator(data() + sizeof(NodeRefList));
+        }
+
+        iterator end() {
+            return iterator(data() + byte_size());
+        }
+
+        const_iterator cbegin() const {
+            return const_iterator(data() + sizeof(NodeRefList));
+        }
+
+        const_iterator cend() const {
+            return const_iterator(data() + byte_size());
+        }
+
+        const_iterator begin() const {
+            return cbegin();
+        }
+
+        const_iterator end() const {
+            return cend();
+        }
+
+        const_reverse_iterator crbegin() const {
+            return const_reverse_iterator(cend());
+        }
+
+        const_reverse_iterator crend() const {
+            return const_reverse_iterator(cbegin());
+        }
+
+    }; // class NodeRefList
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_NODE_REF_LIST_HPP
diff --git a/third_party/osmium/osm/object.hpp b/third_party/osmium/osm/object.hpp
new file mode 100644
index 0000000..9c4d603
--- /dev/null
+++ b/third_party/osmium/osm/object.hpp
@@ -0,0 +1,437 @@
+#ifndef OSMIUM_OSM_OBJECT_HPP
+#define OSMIUM_OSM_OBJECT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <stdexcept>
+
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/memory/item_iterator.hpp>
+#include <osmium/osm/entity.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    /**
+     * OSMObject (Node, Way, Relation, or Area).
+     */
+    class OSMObject : public osmium::OSMEntity {
+
+        object_id_type      m_id;
+        bool                m_deleted : 1;
+        object_version_type m_version : 31;
+        osmium::Timestamp   m_timestamp;
+        user_id_type        m_uid;
+        changeset_id_type   m_changeset;
+
+        size_t sizeof_object() const noexcept {
+            return sizeof(OSMObject) + (type() == item_type::node ? sizeof(osmium::Location) : 0) + sizeof(string_size_type);
+        }
+
+        unsigned char* user_position() noexcept {
+            return data() + sizeof_object() - sizeof(string_size_type);
+        }
+
+        const unsigned char* user_position() const noexcept {
+            return data() + sizeof_object() - sizeof(string_size_type);
+        }
+
+        string_size_type user_size() const noexcept {
+            return *reinterpret_cast<const string_size_type*>(user_position());
+        }
+
+        unsigned char* subitems_position() {
+            return data() + osmium::memory::padded_length(sizeof_object() + user_size());
+        }
+
+        const unsigned char* subitems_position() const {
+            return data() + osmium::memory::padded_length(sizeof_object() + user_size());
+        }
+
+    protected:
+
+        OSMObject(osmium::memory::item_size_type size, osmium::item_type type) :
+            OSMEntity(size, type),
+            m_id(0),
+            m_deleted(false),
+            m_version(0),
+            m_timestamp(),
+            m_uid(0),
+            m_changeset(0) {
+        }
+
+        void set_user_size(string_size_type size) {
+            *reinterpret_cast<string_size_type*>(user_position()) = size;
+        }
+
+    public:
+
+        /// Get ID of this object.
+        object_id_type id() const noexcept {
+            return m_id;
+        }
+
+        /// Get absolute value of the ID of this object.
+        unsigned_object_id_type positive_id() const noexcept {
+            return static_cast<unsigned_object_id_type>(std::abs(m_id));
+        }
+
+        /**
+         * Set ID of this object.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_id(object_id_type id) noexcept {
+            m_id = id;
+            return *this;
+        }
+
+        /**
+         * Set ID of this object.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_id(const char* id) {
+            return set_id(osmium::string_to_object_id(id));
+        }
+
+        /// Is this object marked as deleted?
+        bool deleted() const noexcept {
+            return m_deleted;
+        }
+
+        /// Is this object marked visible (ie not deleted)?
+        bool visible() const noexcept {
+            return !deleted();
+        }
+
+        /**
+         * Mark this object as deleted (or not).
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_deleted(bool deleted) noexcept {
+            m_deleted = deleted;
+            return *this;
+        }
+
+        /**
+         * Mark this object as visible (ie not deleted) (or not).
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_visible(bool visible) noexcept {
+            m_deleted = !visible;
+            return *this;
+        }
+
+        /**
+         * Mark this object as visible (ie not deleted) or deleted.
+         *
+         * @param visible Either "true" or "false"
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_visible(const char* visible) {
+            if (!strcmp("true", visible)) {
+                set_visible(true);
+            } else if (!strcmp("false", visible)) {
+                set_visible(false);
+            } else {
+                throw std::invalid_argument("Unknown value for visible attribute (allowed is 'true' or 'false')");
+            }
+            return *this;
+        }
+
+        /// Get version of this object.
+        object_version_type version() const noexcept {
+            return m_version;
+        }
+
+        /**
+         * Set object version.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_version(object_version_type version) noexcept {
+            m_version = version;
+            return *this;
+        }
+
+        /**
+         * Set object version.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_version(const char* version) {
+            return set_version(string_to_object_version(version));
+        }
+
+        /// Get changeset id of this object.
+        changeset_id_type changeset() const noexcept {
+            return m_changeset;
+        }
+
+        /**
+         * Set changeset id of this object.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_changeset(changeset_id_type changeset) noexcept {
+            m_changeset = changeset;
+            return *this;
+        }
+
+        /**
+         * Set changeset id of this object.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_changeset(const char* changeset) {
+            return set_changeset(string_to_changeset_id(changeset));
+        }
+
+        /// Get user id of this object.
+        user_id_type uid() const noexcept {
+            return m_uid;
+        }
+
+        /**
+         * Set user id of this object.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_uid(user_id_type uid) noexcept {
+            m_uid = uid;
+            return *this;
+        }
+
+        /**
+         * Set user id of this object.
+         * Sets uid to 0 (anonymous) if the given uid is smaller than 0.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_uid_from_signed(signed_user_id_type uid) noexcept {
+            m_uid = uid < 0 ? 0 : static_cast<user_id_type>(uid);
+            return *this;
+        }
+
+        /**
+         * Set user id of this object.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_uid(const char* uid) {
+            return set_uid_from_signed(string_to_user_id(uid));
+        }
+
+        /// Is this user anonymous?
+        bool user_is_anonymous() const noexcept {
+            return m_uid == 0;
+        }
+
+        /// Get timestamp when this object last changed.
+        osmium::Timestamp timestamp() const noexcept {
+            return m_timestamp;
+        }
+
+        /**
+         * Set the timestamp when this object last changed.
+         *
+         * @param timestamp Timestamp
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_timestamp(const osmium::Timestamp timestamp) noexcept {
+            m_timestamp = timestamp;
+            return *this;
+        }
+
+        /// Get user name for this object.
+        const char* user() const noexcept {
+            return reinterpret_cast<const char*>(data() + sizeof_object());
+        }
+
+        /// Get the list of tags for this object.
+        const TagList& tags() const {
+            return osmium::detail::subitem_of_type<const TagList>(cbegin(), cend());
+        }
+
+        /**
+         * Get tag value by key.
+         *
+         * Convenience function that will forward to same function on TagList
+         * object.
+         */
+        const char* get_value_by_key(const char* key, const char* default_value = nullptr) const noexcept {
+            return tags().get_value_by_key(key, default_value);
+        }
+
+        /**
+         * Set named attribute.
+         *
+         * @param attr Name of the attribute (must be one of "id", "version", "changeset", "timestamp", "uid", "visible")
+         * @param value Value of the attribute
+         */
+        void set_attribute(const char* attr, const char* value) {
+            if (!strcmp(attr, "id")) {
+                set_id(value);
+            } else if (!strcmp(attr, "version")) {
+                set_version(value);
+            } else if (!strcmp(attr, "changeset")) {
+                set_changeset(value);
+            } else if (!strcmp(attr, "timestamp")) {
+                set_timestamp(osmium::Timestamp(value));
+            } else if (!strcmp(attr, "uid")) {
+                set_uid(value);
+            } else if (!strcmp(attr, "visible")) {
+                set_visible(value);
+            }
+        }
+
+        typedef osmium::memory::CollectionIterator<Item> iterator;
+        typedef osmium::memory::CollectionIterator<const Item> const_iterator;
+
+        iterator begin() {
+            return iterator(subitems_position());
+        }
+
+        iterator end() {
+            return iterator(next());
+        }
+
+        const_iterator cbegin() const {
+            return const_iterator(subitems_position());
+        }
+
+        const_iterator cend() const {
+            return const_iterator(next());
+        }
+
+        const_iterator begin() const {
+            return cbegin();
+        }
+
+        const_iterator end() const {
+            return cend();
+        }
+
+        template <class T>
+        using t_iterator = osmium::memory::ItemIterator<T>;
+
+        template <class T>
+        using t_const_iterator = osmium::memory::ItemIterator<const T>;
+
+        template <class T>
+        t_iterator<T> begin() {
+            return t_iterator<T>(subitems_position(), next());
+        }
+
+        template <class T>
+        t_iterator<T> end() {
+            return t_iterator<T>(next(), next());
+        }
+
+        template <class T>
+        t_const_iterator<T> cbegin() const {
+            return t_const_iterator<T>(subitems_position(), next());
+        }
+
+        template <class T>
+        t_const_iterator<T> cend() const {
+            return t_const_iterator<T>(next(), next());
+        }
+
+        template <class T>
+        t_const_iterator<T> begin() const {
+            return cbegin<T>();
+        }
+
+        template <class T>
+        t_const_iterator<T> end() const {
+            return cend<T>();
+        }
+
+    }; // class OSMObject
+
+    static_assert(sizeof(OSMObject) % osmium::memory::align_bytes == 0, "Class osmium::OSMObject has wrong size to be aligned properly!");
+
+    /**
+     * OSMObjects are equal if their type, id, and version are equal.
+     */
+    inline bool operator==(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+        return lhs.type() == rhs.type() &&
+               lhs.id() == rhs.id() &&
+               lhs.version() == rhs.version();
+    }
+
+    inline bool operator!=(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+        return ! (lhs == rhs);
+    }
+
+    /**
+     * OSMObjects can be ordered by type, id and version.
+     * Note that we use the absolute value of the id for a
+     * better ordering of objects with negative id.
+     */
+    inline bool operator<(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+        if (lhs.type() != rhs.type()) {
+            return lhs.type() < rhs.type();
+        }
+        return (lhs.id() == rhs.id() && lhs.version() < rhs.version()) ||
+               lhs.positive_id() < rhs.positive_id();
+    }
+
+    inline bool operator>(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+        return rhs < lhs;
+    }
+
+    inline bool operator<=(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+        return ! (rhs < lhs);
+    }
+
+    inline bool operator>=(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+        return ! (lhs < rhs);
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_OBJECT_HPP
diff --git a/third_party/osmium/osm/object_comparisons.hpp b/third_party/osmium/osm/object_comparisons.hpp
new file mode 100644
index 0000000..db11b0d
--- /dev/null
+++ b/third_party/osmium/osm/object_comparisons.hpp
@@ -0,0 +1,110 @@
+#ifndef OSMIUM_OSM_OBJECT_COMPARISONS_HPP
+#define OSMIUM_OSM_OBJECT_COMPARISONS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/osm/object.hpp>
+
+namespace osmium {
+
+    /**
+     * Function object class for comparing OSM objects for equality by type, id, and version.
+     */
+    struct object_equal_type_id_version {
+
+        bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
+            return lhs == rhs;
+        }
+
+        bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
+            return *lhs == *rhs;
+        }
+
+    }; // struct object_equal_type_id_version
+
+    /**
+     * Function object class for comparing OSM objects for equality by type and id,
+     * ignoring the version.
+     */
+    struct object_equal_type_id {
+
+        bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
+            return lhs.type() == rhs.type() &&
+                   lhs.id() == rhs.id();
+        }
+
+        bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
+            return operator()(*lhs, *rhs);
+        }
+
+    }; // struct object_equal_type_id
+
+    /**
+     * Function object class for ordering OSM objects by type, id, and version.
+     */
+    struct object_order_type_id_version {
+
+        bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
+            return lhs < rhs;
+        }
+
+        bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
+            return *lhs < *rhs;
+        }
+
+    }; // struct object_order_type_id_version
+
+    /**
+     * Function object class for ordering OSM objects by type, id, and reverse version,
+     * ie objects are ordered by type and id, but later versions of an object are
+     * ordered before earlier versions of the same object.
+     */
+    struct object_order_type_id_reverse_version {
+
+        bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
+            if (lhs.type() != rhs.type()) {
+                return lhs.type() < rhs.type();
+            }
+            return (lhs.id() == rhs.id() && lhs.version() > rhs.version()) ||
+                   lhs.positive_id() < rhs.positive_id();
+        }
+
+        bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
+            return operator()(*lhs, *rhs);
+        }
+
+    }; // struct object_order_type_id_reverse_version
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_OBJECT_COMPARISONS_HPP
diff --git a/third_party/osmium/osm/relation.hpp b/third_party/osmium/osm/relation.hpp
new file mode 100644
index 0000000..f5d0401
--- /dev/null
+++ b/third_party/osmium/osm/relation.hpp
@@ -0,0 +1,189 @@
+#ifndef OSMIUM_OSM_RELATION_HPP
+#define OSMIUM_OSM_RELATION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <iterator>
+
+#include <osmium/memory/collection.hpp> // IWYU pragma: keep
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    namespace builder {
+        template <class> class ObjectBuilder;
+        class RelationMemberListBuilder;
+    }
+
+    class RelationMember : public osmium::memory::detail::ItemHelper {
+
+        friend class osmium::builder::RelationMemberListBuilder;
+
+        object_id_type   m_ref;
+        item_type        m_type;
+        uint16_t         m_flags;
+        string_size_type m_role_size {0};
+
+        RelationMember(const RelationMember&) = delete;
+        RelationMember(RelationMember&&) = delete;
+
+        RelationMember& operator=(const RelationMember&) = delete;
+        RelationMember& operator=(RelationMember&&) = delete;
+
+        unsigned char* endpos() {
+            return data() + osmium::memory::padded_length(sizeof(RelationMember) + m_role_size);
+        }
+
+        const unsigned char* endpos() const {
+            return data() + osmium::memory::padded_length(sizeof(RelationMember) + m_role_size);
+        }
+
+        template <class TMember>
+        friend class osmium::memory::CollectionIterator;
+
+        unsigned char* next() {
+            if (full_member()) {
+                return endpos() + reinterpret_cast<osmium::memory::Item*>(endpos())->byte_size();
+            } else {
+                return endpos();
+            }
+        }
+
+        unsigned const char* next() const {
+            if (full_member()) {
+                return endpos() + reinterpret_cast<const osmium::memory::Item*>(endpos())->byte_size();
+            } else {
+                return endpos();
+            }
+        }
+
+        void set_role_size(string_size_type size) noexcept {
+            m_role_size = size;
+        }
+
+    public:
+
+        static constexpr item_type collection_type = item_type::relation_member_list;
+
+        RelationMember(const object_id_type ref=0, const item_type type=item_type(), const bool full=false) noexcept :
+            m_ref(ref),
+            m_type(type),
+            m_flags(full ? 1 : 0) {
+        }
+
+        object_id_type ref() const noexcept {
+            return m_ref;
+        }
+
+        RelationMember& ref(object_id_type ref) noexcept {
+            m_ref = ref;
+            return *this;
+        }
+
+        unsigned_object_id_type positive_ref() const noexcept {
+            return static_cast<unsigned_object_id_type>(std::abs(m_ref));
+        }
+
+        item_type type() const noexcept {
+            return m_type;
+        }
+
+        bool full_member() const noexcept {
+            return m_flags == 1;
+        }
+
+        const char* role() const noexcept {
+            return reinterpret_cast<const char*>(data() + sizeof(RelationMember));
+        }
+
+        OSMObject& get_object() {
+            return *reinterpret_cast<OSMObject*>(endpos());
+        }
+
+        const OSMObject& get_object() const {
+            return *reinterpret_cast<const OSMObject*>(endpos());
+        }
+
+    }; // class RelationMember
+
+    class RelationMemberList : public osmium::memory::Collection<RelationMember, osmium::item_type::relation_member_list> {
+
+    public:
+
+        typedef size_t size_type;
+
+        RelationMemberList() :
+            osmium::memory::Collection<RelationMember, osmium::item_type::relation_member_list>() {
+        }
+
+        size_type size() const noexcept {
+            return static_cast<size_type>(std::distance(begin(), end()));
+        }
+
+    }; // class RelationMemberList
+
+    static_assert(sizeof(RelationMemberList) % osmium::memory::align_bytes == 0, "Class osmium::RelationMemberList has wrong size to be aligned properly!");
+
+    class Relation : public OSMObject {
+
+        friend class osmium::builder::ObjectBuilder<osmium::Relation>;
+
+        Relation() noexcept :
+            OSMObject(sizeof(Relation), osmium::item_type::relation) {
+        }
+
+    public:
+
+        static constexpr osmium::item_type itemtype = osmium::item_type::relation;
+
+        RelationMemberList& members() {
+            return osmium::detail::subitem_of_type<RelationMemberList>(begin(), end());
+        }
+
+        const RelationMemberList& members() const {
+            return osmium::detail::subitem_of_type<const RelationMemberList>(cbegin(), cend());
+        }
+
+    }; // class Relation
+
+    static_assert(sizeof(Relation) % osmium::memory::align_bytes == 0, "Class osmium::Relation has wrong size to be aligned properly!");
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_RELATION_HPP
diff --git a/third_party/osmium/osm/segment.hpp b/third_party/osmium/osm/segment.hpp
new file mode 100644
index 0000000..205036e
--- /dev/null
+++ b/third_party/osmium/osm/segment.hpp
@@ -0,0 +1,105 @@
+#ifndef OSMIUM_OSM_SEGMENT_HPP
+#define OSMIUM_OSM_SEGMENT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <iosfwd>
+#include <utility>
+
+#include <osmium/osm/location.hpp>
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+    /**
+     * A Segment is the directed connection between two Locations.
+     */
+    class Segment {
+
+        osmium::Location m_first;
+        osmium::Location m_second;
+
+    public:
+
+        explicit constexpr Segment(const osmium::Location& location1, const osmium::Location& location2) noexcept :
+            m_first(location1),
+            m_second(location2) {
+        }
+
+        constexpr Segment(const Segment&) = default;
+        constexpr Segment(Segment&&) = default;
+
+        Segment& operator=(const Segment&) = default;
+        Segment& operator=(Segment&&) = default;
+
+        ~Segment() = default;
+
+        /// Return first Location of Segment.
+        OSMIUM_CONSTEXPR osmium::Location first() const noexcept {
+            return m_first;
+        }
+
+        /// Return second Location of Segment.
+        OSMIUM_CONSTEXPR osmium::Location second() const noexcept {
+            return m_second;
+        }
+
+    protected:
+
+        void swap_locations() {
+            using std::swap;
+            swap(m_first, m_second);
+        }
+
+    }; // class Segment
+
+    /// Segments are equal if both their locations are equal
+    inline OSMIUM_CONSTEXPR bool operator==(const Segment& lhs, const Segment& rhs) noexcept {
+        return lhs.first() == rhs.first() && lhs.second() == rhs.second();
+    }
+
+    inline OSMIUM_CONSTEXPR bool operator!=(const Segment& lhs, const Segment& rhs) noexcept {
+        return ! (lhs == rhs);
+    }
+
+    /**
+     * Output Segment to a stream.
+     */
+    template <typename TChar, typename TTraits>
+    inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::Segment& segment) {
+        return out << segment.first() << "->" << segment.second();
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_SEGMENT_HPP
diff --git a/third_party/osmium/osm/tag.hpp b/third_party/osmium/osm/tag.hpp
new file mode 100644
index 0000000..fe80de3
--- /dev/null
+++ b/third_party/osmium/osm/tag.hpp
@@ -0,0 +1,140 @@
+#ifndef OSMIUM_OSM_TAG_HPP
+#define OSMIUM_OSM_TAG_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstddef>
+#include <cstring>
+#include <iosfwd>
+#include <iterator>
+
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+
+namespace osmium {
+
+    class Tag : public osmium::memory::detail::ItemHelper {
+
+        Tag(const Tag&) = delete;
+        Tag(Tag&&) = delete;
+
+        Tag& operator=(const Tag&) = delete;
+        Tag& operator=(Tag&&) = delete;
+
+        template <class TMember>
+        friend class osmium::memory::CollectionIterator;
+
+        static unsigned char* after_null(unsigned char* ptr) {
+            return reinterpret_cast<unsigned char*>(std::strchr(reinterpret_cast<char*>(ptr), 0) + 1);
+        }
+
+        static const unsigned char* after_null(const unsigned char* ptr) {
+            return reinterpret_cast<const unsigned char*>(std::strchr(reinterpret_cast<const char*>(ptr), 0) + 1);
+        }
+
+        unsigned char* next() {
+            return after_null(after_null(data()));
+        }
+
+        const unsigned char* next() const {
+            return after_null(after_null(data()));
+        }
+
+    public:
+
+        static constexpr item_type collection_type = item_type::tag_list;
+
+        const char* key() const noexcept {
+            return reinterpret_cast<const char*>(data());
+        }
+
+        const char* value() const {
+            return reinterpret_cast<const char*>(after_null(data()));
+        }
+
+    }; // class Tag
+
+    inline bool operator==(const Tag& a, const Tag& b) {
+        return !std::strcmp(a.key(), b.key()) && !strcmp(a.value(), b.value());
+    }
+
+    inline bool operator<(const Tag& a, const Tag& b) {
+        return (!std::strcmp(a.key(), b.key()) && (std::strcmp(a.value(), b.value()) < 0)) || (std::strcmp(a.key(), b.key()) < 0);
+    }
+
+    /**
+     * Output a Tag to a stream.
+     */
+    template <typename TChar, typename TTraits>
+    inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const Tag& tag) {
+        return out << tag.key() << '=' << tag.value();
+    }
+
+    class TagList : public osmium::memory::Collection<Tag, osmium::item_type::tag_list> {
+
+    public:
+
+        typedef size_t size_type;
+
+        TagList() :
+            osmium::memory::Collection<Tag, osmium::item_type::tag_list>() {
+        }
+
+        size_type size() const noexcept {
+            return static_cast<size_type>(std::distance(begin(), end()));
+        }
+
+        const char* get_value_by_key(const char* key, const char* default_value = nullptr) const noexcept {
+            auto result = std::find_if(cbegin(), cend(), [key](const Tag& tag) {
+                return !strcmp(tag.key(), key);
+            });
+            if (result == cend()) {
+                return default_value;
+            } else {
+                return result->value();
+            }
+        }
+
+        const char* operator[](const char* key) const noexcept {
+            return get_value_by_key(key);
+        }
+
+    }; // class TagList
+
+    static_assert(sizeof(TagList) % osmium::memory::align_bytes == 0, "Class osmium::TagList has wrong size to be aligned properly!");
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_TAG_HPP
diff --git a/third_party/osmium/osm/timestamp.hpp b/third_party/osmium/osm/timestamp.hpp
new file mode 100644
index 0000000..662b61f
--- /dev/null
+++ b/third_party/osmium/osm/timestamp.hpp
@@ -0,0 +1,169 @@
+#ifndef OSMIUM_OSM_TIMESTAMP_HPP
+#define OSMIUM_OSM_TIMESTAMP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstdint>
+#include <ctime>
+#include <iosfwd>
+#include <limits>
+#include <stdexcept>
+#include <string>
+#include <time.h>
+
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+    /**
+     * A timestamp. Internal representation is an unsigned 32bit integer
+     * holding seconds since epoch, so this will overflow in 2038.
+     */
+    class Timestamp {
+
+        // length of ISO timestamp string yyyy-mm-ddThh:mm:ssZ\0
+        static constexpr int timestamp_length = 20 + 1;
+
+        /**
+         * The timestamp format for OSM timestamps in strftime(3) format.
+         * This is the ISO-Format yyyy-mm-ddThh:mm:ssZ
+         */
+        static const char* timestamp_format() {
+            static const char f[timestamp_length] = "%Y-%m-%dT%H:%M:%SZ";
+            return f;
+        }
+
+        uint32_t m_timestamp;
+
+    public:
+
+        constexpr Timestamp() noexcept :
+            m_timestamp(0) {
+        }
+
+        // Not "explicit" so that conversions from time_t work
+        // like in node.timestamp(123);
+        constexpr Timestamp(time_t timestamp) noexcept :
+            m_timestamp(static_cast<uint32_t>(timestamp)) {
+        }
+
+        /**
+         * Construct timestamp from ISO date/time string.
+         * Throws std::invalid_argument, if the timestamp can not be parsed.
+         */
+        explicit Timestamp(const char* timestamp) {
+#ifndef _WIN32
+            struct tm tm {
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+            };
+            if (strptime(timestamp, timestamp_format(), &tm) == nullptr) {
+                throw std::invalid_argument("can't parse timestamp");
+            }
+            m_timestamp = static_cast<uint32_t>(timegm(&tm));
+#else
+            struct tm tm;
+            int n = sscanf(timestamp, "%4d-%2d-%2dT%2d:%2d:%2dZ", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
+            if (n != 6) {
+                throw std::invalid_argument("can't parse timestamp");
+            }
+            tm.tm_year -= 1900;
+            tm.tm_mon--;
+            tm.tm_wday = 0;
+            tm.tm_yday = 0;
+            tm.tm_isdst = 0;
+            m_timestamp = _mkgmtime(&tm);
+#endif
+        }
+
+        constexpr time_t seconds_since_epoch() const noexcept {
+            return static_cast<time_t>(m_timestamp);
+        }
+
+        constexpr operator time_t() const noexcept {
+            return static_cast<time_t>(m_timestamp);
+        }
+
+        template <typename T>
+        void operator+=(T time_difference) noexcept {
+            m_timestamp += time_difference;
+        }
+
+        template <typename T>
+        void operator-=(T time_difference) noexcept {
+            m_timestamp -= time_difference;
+        }
+
+        /**
+         * Return UTC Unix time as string in ISO date/time format.
+         */
+        std::string to_iso() const {
+            if (m_timestamp == 0) {
+                return std::string("");
+            }
+            struct tm tm;
+            time_t sse = seconds_since_epoch();
+#ifndef _MSC_VER
+            gmtime_r(&sse, &tm);
+#else
+            gmtime_s(&tm, &sse);
+#endif
+
+            std::string s(timestamp_length, '\0');
+            /* This const_cast is ok, because we know we have enough space
+               in the string for the format we are using (well at least until
+               the year will have 5 digits). And by setting the size
+               afterwards from the result of strftime we make sure thats set
+               right, too. */
+            s.resize(strftime(const_cast<char*>(s.c_str()), timestamp_length, timestamp_format(), &tm));
+            return s;
+        }
+
+    }; // class Timestamp
+
+    inline OSMIUM_CONSTEXPR Timestamp start_of_time() noexcept {
+        return Timestamp(1);
+    }
+
+    inline OSMIUM_CONSTEXPR Timestamp end_of_time() noexcept {
+        return Timestamp(std::numeric_limits<time_t>::max());
+    }
+
+    template <typename TChar, typename TTraits>
+    inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, Timestamp timestamp) {
+        out << timestamp.to_iso();
+        return out;
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_TIMESTAMP_HPP
diff --git a/third_party/osmium/osm/types.hpp b/third_party/osmium/osm/types.hpp
new file mode 100644
index 0000000..532b549
--- /dev/null
+++ b/third_party/osmium/osm/types.hpp
@@ -0,0 +1,83 @@
+#ifndef OSMIUM_OSM_TYPES_HPP
+#define OSMIUM_OSM_TYPES_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstdint>
+#include <cstdlib>
+
+namespace osmium {
+
+    /*
+     * The following typedefs are chosen so that they can represent all needed
+     * numbers and still be reasonably space efficient. As the OSM database
+     * needs 64 bit IDs for nodes, this size is used for all object IDs.
+     */
+    typedef int64_t  object_id_type;          ///< Type for OSM object (node, way, or relation) IDs.
+    typedef uint64_t unsigned_object_id_type; ///< Type for OSM object (node, way, or relation) IDs where we only allow positive IDs.
+    typedef uint32_t object_version_type;     ///< Type for OSM object version number.
+    typedef uint32_t changeset_id_type;       ///< Type for OSM changeset IDs.
+    typedef uint32_t user_id_type;            ///< Type for OSM user IDs.
+    typedef int32_t  signed_user_id_type;     ///< Type for signed OSM user IDs.
+    typedef uint32_t num_changes_type;        ///< Type for changeset num_changes.
+
+    /**
+     * Size for strings in OSM data such as user names, tag keys, roles, etc.
+     * In Osmium they can be up to 2^16 bytes long, but OSM usually has lower
+     * defined limits.
+     */
+    typedef uint16_t string_size_type;
+
+    inline object_id_type string_to_object_id(const char* string) {
+        return std::atoll(string);
+    }
+
+    inline object_version_type string_to_object_version(const char* string) {
+        return static_cast<object_version_type>(std::atol(string));
+    }
+
+    inline changeset_id_type string_to_changeset_id(const char* string) {
+        return static_cast<changeset_id_type>(std::atol(string));
+    }
+
+    inline signed_user_id_type string_to_user_id(const char* string) {
+        return static_cast<signed_user_id_type>(std::atol(string));
+    }
+
+    inline num_changes_type string_to_num_changes(const char* string) {
+        return static_cast<num_changes_type>(std::atol(string));
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_TYPES_HPP
diff --git a/third_party/osmium/osm/undirected_segment.hpp b/third_party/osmium/osm/undirected_segment.hpp
new file mode 100644
index 0000000..487e7bf
--- /dev/null
+++ b/third_party/osmium/osm/undirected_segment.hpp
@@ -0,0 +1,100 @@
+#ifndef OSMIUM_OSM_UNDIRECTED_SEGMENT_HPP
+#define OSMIUM_OSM_UNDIRECTED_SEGMENT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <iosfwd>
+
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/segment.hpp>
+
+namespace osmium {
+
+    /**
+     * Undirected connection between two Locations. The first Location is
+     * always equal or "smaller" than the second Location, ie to the left
+     * and down.
+     */
+    class UndirectedSegment : public Segment {
+
+    public:
+
+        explicit UndirectedSegment(const osmium::Location& location1, const osmium::Location& location2) :
+            Segment(location1, location2) {
+            if (location2 < location1) {
+                swap_locations();
+            }
+        }
+
+        UndirectedSegment(const UndirectedSegment&) = default;
+        UndirectedSegment(UndirectedSegment&&) = default;
+
+        UndirectedSegment& operator=(const UndirectedSegment&) = default;
+        UndirectedSegment& operator=(UndirectedSegment&&) = default;
+
+        ~UndirectedSegment() = default;
+
+    }; // class UndirectedSegment
+
+    /**
+     * UndirectedSegments are "smaller" if they are to the left and down of another
+     * segment. The first() location is checked first() and only if they have the
+     * same first() location the second() location is taken into account.
+     */
+    inline bool operator<(const UndirectedSegment& lhs, const UndirectedSegment& rhs) noexcept {
+        return (lhs.first() == rhs.first() && lhs.second() < rhs.second()) || lhs.first() < rhs.first();
+    }
+
+    inline bool operator>(const UndirectedSegment& lhs, const UndirectedSegment& rhs) noexcept {
+        return rhs < lhs;
+    }
+
+    inline bool operator<=(const UndirectedSegment& lhs, const UndirectedSegment& rhs) noexcept {
+        return ! (rhs < lhs);
+    }
+
+    inline bool operator>=(const UndirectedSegment& lhs, const UndirectedSegment& rhs) noexcept {
+        return ! (lhs < rhs);
+    }
+
+    /**
+     * Output UndirectedSegment to a stream.
+     */
+    template <typename TChar, typename TTraits>
+    inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::UndirectedSegment& segment) {
+        return out << segment.first() << "--" << segment.second();
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_UNDIRECTED_SEGMENT_HPP
diff --git a/third_party/osmium/osm/way.hpp b/third_party/osmium/osm/way.hpp
new file mode 100644
index 0000000..a30cf91
--- /dev/null
+++ b/third_party/osmium/osm/way.hpp
@@ -0,0 +1,115 @@
+#ifndef OSMIUM_OSM_WAY_HPP
+#define OSMIUM_OSM_WAY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/node_ref_list.hpp>
+
+namespace osmium {
+
+    namespace builder {
+        template <class T> class ObjectBuilder;
+    }
+
+    /**
+     * List of node references (id and location) in a way.
+     */
+    class WayNodeList : public NodeRefList<osmium::item_type::way_node_list> {
+
+    public:
+
+        WayNodeList():
+            NodeRefList<osmium::item_type::way_node_list>() {
+        }
+
+    }; // class WayNodeList
+
+    static_assert(sizeof(WayNodeList) % osmium::memory::align_bytes == 0, "Class osmium::WayNodeList has wrong size to be aligned properly!");
+
+    class Way : public OSMObject {
+
+        friend class osmium::builder::ObjectBuilder<osmium::Way>;
+
+        Way() noexcept :
+            OSMObject(sizeof(Way), osmium::item_type::way) {
+        }
+
+    public:
+
+        WayNodeList& nodes() {
+            return osmium::detail::subitem_of_type<WayNodeList>(begin(), end());
+        }
+
+        const WayNodeList& nodes() const {
+            return osmium::detail::subitem_of_type<const WayNodeList>(cbegin(), cend());
+        }
+
+        /**
+         * Update all nodes in a way with the ID of the given NodeRef with the
+         * location of the given NodeRef.
+         */
+        void update_node_location(const NodeRef& new_node_ref) {
+            for (auto& node_ref : nodes()) {
+                if (node_ref.ref() == new_node_ref.ref()) {
+                    node_ref.set_location(new_node_ref.location());
+                }
+            }
+        }
+
+        /**
+         * Do the nodes in this way form a closed ring?
+         */
+        bool is_closed() const {
+            return nodes().is_closed();
+        }
+
+        bool ends_have_same_id() const {
+            return nodes().ends_have_same_id();
+        }
+
+        bool ends_have_same_location() const {
+            return nodes().ends_have_same_location();
+        }
+
+    }; // class Way
+
+    static_assert(sizeof(Way) % osmium::memory::align_bytes == 0, "Class osmium::Way has wrong size to be aligned properly!");
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_WAY_HPP
diff --git a/third_party/osmium/relations/collector.hpp b/third_party/osmium/relations/collector.hpp
new file mode 100644
index 0000000..60864d3
--- /dev/null
+++ b/third_party/osmium/relations/collector.hpp
@@ -0,0 +1,544 @@
+#ifndef OSMIUM_RELATIONS_COLLECTOR_HPP
+#define OSMIUM_RELATIONS_COLLECTOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <iomanip>
+#include <iostream>
+#include <vector>
+
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp> // IWYU pragma: keep
+#include <osmium/osm/types.hpp>
+#include <osmium/handler.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/visitor.hpp>
+
+#include <osmium/relations/detail/relation_meta.hpp>
+#include <osmium/relations/detail/member_meta.hpp>
+
+namespace osmium {
+
+    class Node;
+    class Way;
+
+    /**
+     * @brief Code related to the assembly of OSM relations
+     */
+    namespace relations {
+
+        /**
+         * The Collector class collects members of a relation. This is a generic
+         * base class that can be used to assemble all kinds of relations. It has numerous
+         * hooks you can implement in derived classes to customize its behaviour.
+         *
+         * The collector provides two handlers (HandlerPass1 and HandlerPass2) for a first
+         * and second pass through an input file, respectively. In the first pass all
+         * relations we are interested in are stored in RelationMeta objects in the
+         * m_relations vector. All members we are interested in are stored in MemberMeta
+         * objects in the m_member_meta vectors.
+         * The MemberMeta objects also store the information where the relations containing
+         * those members are to be found.
+         *
+         * Later the m_member_meta vectors are sorted according to the
+         * member ids so that a binary search (with std::equal_range) can be used in the second
+         * pass to find the parent relations for each node, way, or relation coming along.
+         * The member objects are stored together with their relation and once a relation
+         * is complete the complete_relation() method is called which you must overwrite in
+         * a derived class of Collector.
+         *
+         * @tparam TCollector Derived class of this class.
+         *
+         * @tparam TNodes Are we interested in member nodes?
+         *
+         * @tparam TWays Are we interested in member ways?
+         *
+         * @tparam TRelations Are we interested in member relations?
+         */
+        template <class TCollector, bool TNodes, bool TWays, bool TRelations>
+        class Collector {
+
+            /**
+             * This is the handler class for the first pass of the Collector.
+             */
+            class HandlerPass1 : public osmium::handler::Handler {
+
+                TCollector& m_collector;
+
+            public:
+
+                HandlerPass1(TCollector& collector) noexcept :
+                    m_collector(collector) {
+                }
+
+                void relation(const osmium::Relation& relation) {
+                    if (m_collector.keep_relation(relation)) {
+                        m_collector.add_relation(relation);
+                    }
+                }
+
+            }; // class HandlerPass1
+
+        public:
+
+            /**
+             * This is the handler class for the second pass of the Collector.
+             */
+            class HandlerPass2 : public osmium::handler::Handler {
+
+                TCollector& m_collector;
+
+                /**
+                 * This variable is initialized with the number of different
+                 * kinds of OSM objects we are interested in. If we only need
+                 * way members (for instance for the multipolygon collector)
+                 * it is intialized with 1 for instance. If node and way
+                 * members are needed, it is initialized with 2.
+                 *
+                 * In the after_* methods of this handler, it is decremented
+                 * and once it reaches 0, we know we have all members available
+                 * that we are ever going to get.
+                 */
+                int m_want_types;
+
+                /**
+                 * Find this object in the member vectors and add it to all
+                 * relations that need it.
+                 *
+                 * @returns true if the member was added to at least one
+                 *          relation and false otherwise
+                 */
+                bool find_and_add_object(const osmium::OSMObject& object) {
+                    auto& mmv = m_collector.member_meta(object.type());
+                    auto range = std::equal_range(mmv.begin(), mmv.end(), MemberMeta(object.id()));
+
+                    if (osmium::relations::count_not_removed(range.first, range.second) == 0) {
+                        // nothing found
+                        return false;
+                    }
+
+                    {
+                        m_collector.members_buffer().add_item(object);
+                        const size_t member_offset = m_collector.members_buffer().commit();
+
+                        for (auto it = range.first; it != range.second; ++it) {
+                            it->set_buffer_offset(member_offset);
+                        }
+                    }
+
+                    for (auto it = range.first; it != range.second; ++it) {
+                        MemberMeta& member_meta = *it;
+                        if (member_meta.removed()) {
+                            break;
+                        }
+                        assert(member_meta.member_id() == object.id());
+                        assert(member_meta.relation_pos() < m_collector.m_relations.size());
+                        RelationMeta& relation_meta = m_collector.m_relations[member_meta.relation_pos()];
+//                        std::cerr << "  => " << member_meta.member_pos() << " < " << m_collector.get_relation(relation_meta).members().size() << " (id=" << m_collector.get_relation(relation_meta).id() << ")\n";
+                        assert(member_meta.member_pos() < m_collector.get_relation(relation_meta).members().size());
+//                        std::cerr << "  add way " << member_meta.member_id() << " to rel " << m_collector.get_relation(relation_meta).id() << " at pos " << member_meta.member_pos() << "\n";
+                        relation_meta.got_one_member();
+                        if (relation_meta.has_all_members()) {
+                            const size_t relation_offset = member_meta.relation_pos();
+                            m_collector.complete_relation(relation_meta);
+                            m_collector.m_relations[relation_offset] = RelationMeta();
+                            m_collector.possibly_purge_removed_members();
+                        }
+                    }
+
+                    // Remove MemberMetas that were marked as removed.
+                    mmv.erase(std::remove_if(mmv.begin(), mmv.end(), [](MemberMeta& mm) {
+                        return mm.removed();
+                    }), mmv.end());
+
+                    return true;
+                }
+
+            public:
+
+                HandlerPass2(TCollector& collector) noexcept :
+                    m_collector(collector),
+                    m_want_types((TNodes?1:0) + (TWays?1:0) + (TRelations?1:0)) {
+                }
+
+                void node(const osmium::Node& node) {
+                    if (TNodes) {
+                        if (! find_and_add_object(node)) {
+                            m_collector.node_not_in_any_relation(node);
+                        }
+                    }
+                }
+
+                void way(const osmium::Way& way) {
+                    if (TWays) {
+                        if (! find_and_add_object(way)) {
+                            m_collector.way_not_in_any_relation(way);
+                        }
+                    }
+                }
+
+                void relation(const osmium::Relation& relation) {
+                    if (TRelations) {
+                        if (! find_and_add_object(relation)) {
+                            m_collector.relation_not_in_any_relation(relation);
+                        }
+                    }
+                }
+
+                void flush() {
+                    m_collector.flush();
+                }
+
+            }; // class HandlerPass2
+
+            HandlerPass2 m_handler_pass2;
+
+            // All relations we are interested in will be kept in this buffer
+            osmium::memory::Buffer m_relations_buffer;
+
+            // All members we are interested in will be kept in this buffer
+            osmium::memory::Buffer m_members_buffer;
+
+            /// Vector with all relations we are interested in
+            std::vector<RelationMeta> m_relations;
+
+            /**
+             * One vector each for nodes, ways, and relations containing all
+             * mappings from member ids to their relations.
+             */
+            std::vector<MemberMeta> m_member_meta[3];
+
+            int m_count_complete = 0;
+
+            typedef std::function<void(osmium::memory::Buffer&&)> callback_func_type;
+            callback_func_type m_callback;
+
+            static constexpr size_t initial_buffer_size = 1024 * 1024;
+
+        public:
+
+            /**
+             * Create an Collector.
+             */
+            Collector() :
+                m_handler_pass2(*static_cast<TCollector*>(this)),
+                m_relations_buffer(initial_buffer_size, osmium::memory::Buffer::auto_grow::yes),
+                m_members_buffer(initial_buffer_size, osmium::memory::Buffer::auto_grow::yes),
+                m_relations(),
+                m_member_meta() {
+            }
+
+        protected:
+
+            std::vector<MemberMeta>& member_meta(const item_type type) {
+                return m_member_meta[static_cast<uint16_t>(type) - 1];
+            }
+
+            callback_func_type callback() {
+                return m_callback;
+            }
+
+            const std::vector<RelationMeta>& relations() const {
+                return m_relations;
+            }
+
+            /**
+             * This method is called from the first pass handler for every
+             * relation in the input, to check whether it should be kept.
+             *
+             * Overwrite this method in a child class to only add relations
+             * you are interested in, for instance depending on the type tag.
+             * Storing relations takes a lot of memory, so it makes sense to
+             * filter this as much as possible.
+             */
+            bool keep_relation(const osmium::Relation& /*relation*/) const {
+                return true;
+            }
+
+            /**
+             * This method is called for every member of every relation that
+             * should be kept. It should decide if the member is interesting or
+             * not and return true or false to signal that. Only interesting
+             * members are later added to the relation.
+             *
+             * Overwrite this method in a child class. In the MultiPolygonCollector
+             * this is for instance used to only keep members of type way and
+             * ignore all others.
+             */
+            bool keep_member(const osmium::relations::RelationMeta& /*relation_meta*/, const osmium::RelationMember& /*member*/) const {
+                return true;
+            }
+
+            /**
+             * This method is called for all nodes that are not a member of
+             * any relation.
+             *
+             * Overwrite this method in a child class if you are interested
+             * in this.
+             */
+            void node_not_in_any_relation(const osmium::Node& /*node*/) {
+            }
+
+            /**
+             * This method is called for all ways that are not a member of
+             * any relation.
+             *
+             * Overwrite this method in a child class if you are interested
+             * in this.
+             */
+            void way_not_in_any_relation(const osmium::Way& /*way*/) {
+            }
+
+            /**
+             * This method is called for all relations that are not a member of
+             * any relation.
+             *
+             * Overwrite this method in a child class if you are interested
+             * in this.
+             */
+            void relation_not_in_any_relation(const osmium::Relation& /*relation*/) {
+            }
+
+            /**
+             * This method is called from the 2nd pass handler when all objects
+             * of types we are interested in have been seen.
+             *
+             * Overwrite this method in a child class if you are interested
+             * in this.
+             *
+             * Note that even after this call members might be missing if they
+             * were not in the input file! The derived class has to handle this
+             * case.
+             */
+            void flush() {
+            }
+
+            /**
+             * This removes all relations that have already been assembled
+             * from the m_relations vector.
+             */
+            void clean_assembled_relations() {
+                m_relations.erase(
+                    std::remove_if(m_relations.begin(), m_relations.end(), has_all_members()),
+                    m_relations.end()
+                );
+            }
+
+            const osmium::Relation& get_relation(size_t offset) const {
+                return m_relations_buffer.get<osmium::Relation>(offset);
+            }
+
+            /**
+             * Get the relation from a relation_meta.
+             */
+            const osmium::Relation& get_relation(const RelationMeta& relation_meta) const {
+                return get_relation(relation_meta.relation_offset());
+            }
+
+            osmium::OSMObject& get_member(size_t offset) const {
+                return m_members_buffer.get<osmium::OSMObject>(offset);
+            }
+
+            /**
+             * Tell the Collector that you are interested in this relation
+             * and want it kept until all members have been assembled and
+             * it is handed back to you.
+             *
+             * The relation is copied and stored in a buffer inside the
+             * collector.
+             */
+            void add_relation(const osmium::Relation& relation) {
+                const size_t offset = m_relations_buffer.committed();
+                m_relations_buffer.add_item(relation);
+
+                RelationMeta relation_meta(offset);
+
+                int n=0;
+                for (auto& member : m_relations_buffer.get<osmium::Relation>(offset).members()) {
+                    if (static_cast<TCollector*>(this)->keep_member(relation_meta, member)) {
+                        member_meta(member.type()).emplace_back(member.ref(), m_relations.size(), n);
+                        relation_meta.increment_need_members();
+                    } else {
+                        member.ref(0); // set member id to zero to indicate we are not interested
+                    }
+                    ++n;
+                }
+
+                assert(offset == m_relations_buffer.committed());
+                if (relation_meta.has_all_members()) {
+                    m_relations_buffer.rollback();
+                } else {
+                    m_relations_buffer.commit();
+                    m_relations.push_back(std::move(relation_meta));
+//                    std::cerr << "added relation id=" << relation.id() << "\n";
+                }
+            }
+
+            /**
+             * Sort the vectors with the member infos so that we can do binary
+             * search on them.
+             */
+            void sort_member_meta() {
+/*                std::cerr << "relations:        " << m_relations.size() << "\n";
+                std::cerr << "node members:     " << m_member_meta[0].size() << "\n";
+                std::cerr << "way members:      " << m_member_meta[1].size() << "\n";
+                std::cerr << "relation members: " << m_member_meta[2].size() << "\n";*/
+                std::sort(m_member_meta[0].begin(), m_member_meta[0].end());
+                std::sort(m_member_meta[1].begin(), m_member_meta[1].end());
+                std::sort(m_member_meta[2].begin(), m_member_meta[2].end());
+            }
+
+        public:
+
+            uint64_t used_memory() const {
+                const uint64_t nmembers = m_member_meta[0].capacity() + m_member_meta[1].capacity() + m_member_meta[2].capacity();
+                const uint64_t members = nmembers * sizeof(MemberMeta);
+                const uint64_t relations = m_relations.capacity() * sizeof(RelationMeta);
+                const uint64_t relations_buffer_capacity = m_relations_buffer.capacity();
+                const uint64_t members_buffer_capacity = m_members_buffer.capacity();
+
+                std::cout << "  nR  = m_relations.capacity() ........... = " << std::setw(12) << m_relations.capacity() << "\n";
+                std::cout << "  nMN = m_member_meta[NODE].capacity() ... = " << std::setw(12) << m_member_meta[0].capacity() << "\n";
+                std::cout << "  nMW = m_member_meta[WAY].capacity() .... = " << std::setw(12) << m_member_meta[1].capacity() << "\n";
+                std::cout << "  nMR = m_member_meta[RELATION].capacity() = " << std::setw(12) << m_member_meta[2].capacity() << "\n";
+                std::cout << "  nM  = m_member_meta[*].capacity() ...... = " << std::setw(12) << nmembers << "\n";
+
+                std::cout << "  sRM = sizeof(RelationMeta) ............. = " << std::setw(12) << sizeof(RelationMeta) << "\n";
+                std::cout << "  sMM = sizeof(MemberMeta) ............... = " << std::setw(12) << sizeof(MemberMeta) << "\n\n";
+
+                std::cout << "  nR * sRM ............................... = " << std::setw(12) << relations << "\n";
+                std::cout << "  nM * sMM ............................... = " << std::setw(12) << members << "\n";
+                std::cout << "  relations_buffer_capacity .............. = " << std::setw(12) << relations_buffer_capacity << "\n";
+                std::cout << "  members_buffer_capacity ................ = " << std::setw(12) << members_buffer_capacity << "\n";
+
+                const uint64_t total = relations + members + relations_buffer_capacity + members_buffer_capacity;
+
+                std::cout << "  total .................................. = " << std::setw(12) << total << "\n";
+                std::cout << "  =======================================================\n";
+
+                return relations_buffer_capacity + members_buffer_capacity + relations + members;
+            }
+
+            /**
+             * Return reference to second pass handler.
+             */
+            HandlerPass2& handler(const callback_func_type& callback = nullptr) {
+                m_callback = callback;
+                return m_handler_pass2;
+            }
+
+            osmium::memory::Buffer& members_buffer() {
+                return m_members_buffer;
+            }
+
+            size_t get_offset(osmium::item_type type, osmium::object_id_type id) {
+                const auto& mmv = member_meta(type);
+                const auto range = std::equal_range(mmv.cbegin(), mmv.cend(), MemberMeta(id));
+                assert(range.first != range.second);
+                return range.first->buffer_offset();
+            }
+
+            template <class TIter>
+            void read_relations(TIter begin, TIter end) {
+                HandlerPass1 handler(*static_cast<TCollector*>(this));
+                osmium::apply(begin, end, handler);
+                sort_member_meta();
+            }
+
+            template <class TSource>
+            void read_relations(TSource& source) {
+                read_relations(std::begin(source), std::end(source));
+                source.close();
+            }
+
+            void moving_in_buffer(size_t old_offset, size_t new_offset) {
+                const osmium::OSMObject& object = m_members_buffer.get<osmium::OSMObject>(old_offset);
+                auto& mmv = member_meta(object.type());
+                auto range = std::equal_range(mmv.begin(), mmv.end(), osmium::relations::MemberMeta(object.id()));
+                for (auto it = range.first; it != range.second; ++it) {
+                    assert(it->buffer_offset() == old_offset);
+                    it->set_buffer_offset(new_offset);
+                }
+            }
+
+            /**
+             * Decide whether to purge removed members and then do it.
+             *
+             * Currently the purging is done every thousand calls.
+             * This could probably be improved upon.
+             */
+            void possibly_purge_removed_members() {
+                ++m_count_complete;
+                if (m_count_complete > 10000) { // XXX
+                    const size_t size_before = m_members_buffer.committed();
+                    m_members_buffer.purge_removed(this);
+                    const size_t size_after = m_members_buffer.committed();
+                    double percent = size_before - size_after;
+                    percent /= size_before;
+                    percent *= 100;
+                    std::cerr << "PURGE (size before=" << size_before << " after=" << size_after << " purged=" << (size_before - size_after) << " / " << static_cast<int>(percent) << "%)\n";
+                    m_count_complete = 0;
+                }
+            }
+
+            /**
+             * Get a vector with pointers to all Relations that could not
+             * be completed, because members were missing in the input
+             * data.
+             *
+             * Note that these pointers point into memory allocated and
+             * owned by the Collector object.
+             */
+            std::vector<const osmium::Relation*> get_incomplete_relations() const {
+                std::vector<const osmium::Relation*> relations;
+                for (const auto& relation_meta : m_relations) {
+                    if (!relation_meta.has_all_members()) {
+                        relations.push_back(&get_relation(relation_meta));
+                    }
+                }
+                return relations;
+            }
+
+        }; // class Collector
+
+    } // namespace relations
+
+} // namespace osmium
+
+#endif // OSMIUM_RELATIONS_COLLECTOR_HPP
diff --git a/third_party/osmium/relations/detail/member_meta.hpp b/third_party/osmium/relations/detail/member_meta.hpp
new file mode 100644
index 0000000..5463a1c
--- /dev/null
+++ b/third_party/osmium/relations/detail/member_meta.hpp
@@ -0,0 +1,158 @@
+#ifndef OSMIUM_RELATIONS_DETAIL_MEMBER_META_HPP
+#define OSMIUM_RELATIONS_DETAIL_MEMBER_META_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstddef>
+#include <iosfwd>
+#include <iterator>
+
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    namespace relations {
+
+        /**
+         * Helper class for the Collector class.
+         *
+         * Stores an object ID and information where the object should be
+         * stored.
+         */
+        class MemberMeta {
+
+            /**
+             * Object ID of this relation member. Can be a node, way, or relation ID.
+             * It depends on the vector in which this object is stored which kind of
+             * object is referenced here.
+             */
+            osmium::object_id_type m_member_id;
+
+            /**
+             * Position of the relation this member is a part of in the
+             * m_relations vector.
+             */
+            size_t m_relation_pos;
+
+            /**
+             * Position of this member in the list of members of the
+             * relation this member is a part of.
+             */
+            size_t m_member_pos;
+
+            /**
+             * Offset in the buffer where the object is stored.
+             */
+            size_t m_buffer_offset { 0 };
+
+            bool m_removed = false;
+
+        public:
+
+            /**
+             * Create new MemberMeta. The variant with zeros for relation_pos and
+             * member_pos is used to create dummy MemberMeta that can be compared
+             * to the MemberMeta in the vectors using the equal_range algorithm.
+             */
+            explicit MemberMeta(osmium::object_id_type member_id, size_t relation_pos=0, size_t member_pos=0) noexcept :
+                m_member_id(member_id),
+                m_relation_pos(relation_pos),
+                m_member_pos(member_pos) {
+            }
+
+            osmium::object_id_type member_id() const noexcept {
+                return m_member_id;
+            }
+
+            size_t relation_pos() const noexcept {
+                return m_relation_pos;
+            }
+
+            size_t member_pos() const noexcept {
+                return m_member_pos;
+            }
+
+            size_t buffer_offset() const noexcept {
+                return m_buffer_offset;
+            }
+
+            void set_buffer_offset(size_t offset) noexcept {
+                m_buffer_offset = offset;
+            }
+
+            bool removed() const noexcept {
+                return m_removed;
+            }
+
+            void remove() noexcept {
+                m_removed = true;
+            }
+
+        }; // class MemberMeta
+
+        /**
+         * Compares two MemberMeta objects by only looking at the member id.
+         * Used to sort a vector of MemberMeta objects and to later find
+         * them using binary search.
+         */
+        inline bool operator<(const MemberMeta& a, const MemberMeta& b) noexcept {
+            return a.member_id() < b.member_id();
+        }
+
+        template <typename TChar, typename TTraits>
+        inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const MemberMeta& mm) {
+            out << "MemberMeta(member_id=" << mm.member_id() << " relation_pos=" << mm.relation_pos() << " member_pos=" << mm.member_pos() << " buffer_offset=" << mm.buffer_offset() << ")";
+            return out;
+        }
+
+        /**
+         * Count the number of MemberMeta objects in the iterator range
+         * that are not marked as removed.
+         *
+         * @tparam TIter Iterator that dereferences to a MemberMeta
+         * @param begin Begin of iterator range
+         * @param end End of iterator range
+         */
+        template <class TIter>
+        inline typename std::iterator_traits<TIter>::difference_type count_not_removed(TIter begin, TIter end) {
+            return std::count_if(begin, end, [](MemberMeta& mm) {
+                return !mm.removed();
+            });
+        }
+
+    } // namespace relations
+
+} // namespace osmium
+
+#endif // OSMIUM_RELATIONS_DETAIL_MEMBER_META_HPP
diff --git a/third_party/osmium/relations/detail/relation_meta.hpp b/third_party/osmium/relations/detail/relation_meta.hpp
new file mode 100644
index 0000000..77ca0c1
--- /dev/null
+++ b/third_party/osmium/relations/detail/relation_meta.hpp
@@ -0,0 +1,136 @@
+#ifndef OSMIUM_RELATIONS_DETAIL_RELATION_META_HPP
+#define OSMIUM_RELATIONS_DETAIL_RELATION_META_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstddef>
+#include <iosfwd>
+
+namespace osmium {
+
+    namespace relations {
+
+        /**
+         * Helper class for the Collector class.
+         *
+         * Stores information needed to collect all members of a relation. This
+         * includes the offset of the relation in a buffer plus the information
+         * needed to add members to this relation.
+         */
+        class RelationMeta {
+
+            /// The relation we are assembling.
+            size_t m_relation_offset;
+
+            /**
+             * The number of members still needed before the relation is
+             * complete. This will be set to the number of members we are
+             * interested in and then count down for every member we find.
+             * When it is 0, the relation is complete.
+             */
+            int m_need_members = 0;
+
+        public:
+
+            /**
+             * Initialize an empty RelationMeta. This is needed to zero out
+             * relations that have been completed.
+             */
+            RelationMeta() noexcept :
+                m_relation_offset(0) {
+            }
+
+            explicit RelationMeta(size_t relation_offset) noexcept :
+                m_relation_offset(relation_offset) {
+            }
+
+            /**
+             * Get offset of relation in buffer.
+             */
+            size_t relation_offset() const noexcept {
+                return m_relation_offset;
+            }
+
+            /**
+             * Increment the m_need_members counter.
+             */
+            void increment_need_members() noexcept {
+                ++m_need_members;
+            }
+
+            /**
+             * This decrements the "members needed" counter.
+             */
+            void got_one_member() {
+                assert(m_need_members > 0);
+                --m_need_members;
+            }
+
+            /**
+             * Returns true if all members for this relation are available.
+             */
+            bool has_all_members() const noexcept {
+                return m_need_members == 0;
+            }
+
+        }; // class RelationMeta
+
+        template <typename TChar, typename TTraits>
+        inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const RelationMeta& rm) {
+            out << "RelationMeta(relation_offset=" << rm.relation_offset() << " has_all_members=" << rm.has_all_members() << ")";
+            return out;
+        }
+
+        /**
+         * Function object to check if a relation is complete.
+         */
+        struct has_all_members {
+
+            typedef RelationMeta& argument_type;
+            typedef bool result_type;
+
+            /**
+             * @returns true if this relation is complete, false otherwise.
+             */
+            bool operator()(RelationMeta& relation_info) const {
+                return relation_info.has_all_members();
+            }
+
+        }; // struct has_all_members
+
+    } // namespace relations
+
+} // namespace osmium
+
+#endif // OSMIUM_RELATIONS_DETAIL_RELATION_META_HPP
diff --git a/third_party/osmium/tags/filter.hpp b/third_party/osmium/tags/filter.hpp
new file mode 100644
index 0000000..0a0fd3b
--- /dev/null
+++ b/third_party/osmium/tags/filter.hpp
@@ -0,0 +1,148 @@
+#ifndef OSMIUM_TAGS_FILTER_HPP
+#define OSMIUM_TAGS_FILTER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include <boost/iterator/filter_iterator.hpp>
+
+#include <osmium/memory/collection.hpp>
+#include <osmium/osm/tag.hpp>
+
+namespace osmium {
+
+    namespace tags {
+
+        template <class TKey>
+        struct match_key {
+            bool operator()(const TKey& rule_key, const char* tag_key) {
+                return rule_key == tag_key;
+            }
+        }; // struct match_key
+
+        struct match_key_prefix {
+            bool operator()(const std::string& rule_key, const char* tag_key) {
+                return rule_key.compare(0, std::string::npos, tag_key, 0, rule_key.size()) == 0;
+            }
+        }; // struct match_key_prefix
+
+        template <class TValue>
+        struct match_value {
+            bool operator()(const TValue& rule_value, const char* tag_value) {
+                return rule_value == tag_value;
+            }
+        }; // struct match_value
+
+        template <>
+        struct match_value<void> {
+            bool operator()(const bool, const char*) {
+                return true;
+            }
+        }; // struct match_value<void>
+
+        template <class TKey, class TValue=void, class TKeyComp=match_key<TKey>, class TValueComp=match_value<TValue>>
+        class Filter {
+
+            typedef TKey key_type;
+            typedef typename std::conditional<std::is_void<TValue>::value, bool, TValue>::type value_type;
+
+            struct Rule {
+                key_type key;
+                value_type value;
+                bool ignore_value;
+                bool result;
+
+                explicit Rule(bool r, bool ignore, const key_type& k, const value_type& v) :
+                    key(k),
+                    value(v),
+                    ignore_value(ignore),
+                    result(r) {
+                }
+
+                explicit Rule(bool r, bool ignore, const key_type& k) :
+                    key(k),
+                    value(),
+                    ignore_value(ignore),
+                    result(r) {
+                }
+
+            }; // struct Rule
+
+            std::vector<Rule> m_rules;
+            bool m_default_result;
+
+        public:
+
+            typedef Filter<TKey, TValue, TKeyComp, TValueComp> filter_type;
+            typedef const osmium::Tag& argument_type;
+            typedef bool result_type;
+            typedef boost::filter_iterator<filter_type, osmium::TagList::const_iterator> iterator;
+
+            explicit Filter(bool default_result = false) :
+                m_default_result(default_result) {
+            }
+
+            template <class V=TValue, typename std::enable_if<!std::is_void<V>::value, int>::type = 0>
+            Filter& add(bool result, const key_type& key, const value_type& value) {
+                m_rules.emplace_back(result, false, key, value);
+                return *this;
+            }
+
+            Filter& add(bool result, const key_type& key) {
+                m_rules.emplace_back(result, true, key);
+                return *this;
+            }
+
+            bool operator()(const osmium::Tag& tag) const {
+                for (const Rule& rule : m_rules) {
+                    if (TKeyComp()(rule.key, tag.key()) && (rule.ignore_value || TValueComp()(rule.value, tag.value()))) {
+                        return rule.result;
+                    }
+                }
+                return m_default_result;
+            }
+
+        }; // class Filter
+
+        typedef Filter<std::string, std::string> KeyValueFilter;
+        typedef Filter<std::string> KeyFilter;
+        typedef Filter<std::string, void, match_key_prefix> KeyPrefixFilter;
+
+    } // namespace tags
+
+} // namespace osmium
+
+#endif // OSMIUM_TAGS_FILTER_HPP
diff --git a/third_party/osmium/tags/regex_filter.hpp b/third_party/osmium/tags/regex_filter.hpp
new file mode 100644
index 0000000..ae2703a
--- /dev/null
+++ b/third_party/osmium/tags/regex_filter.hpp
@@ -0,0 +1,58 @@
+#ifndef OSMIUM_TAGS_REGEX_FILTER_HPP
+#define OSMIUM_TAGS_REGEX_FILTER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <regex>
+#include <string>
+
+#include <osmium/tags/filter.hpp>
+
+namespace osmium {
+
+    namespace tags {
+
+        template <>
+        struct match_value<std::regex> {
+            bool operator()(const std::regex& rule_value, const char* tag_value) {
+                return std::regex_match(tag_value, rule_value);
+            }
+        }; // struct match_value<std::regex>
+
+        typedef Filter<std::string, std::regex> RegexFilter;
+
+    } // namespace tags
+
+} // namespace osmium
+
+#endif // OSMIUM_TAGS_REGEX_FILTER_HPP
diff --git a/third_party/osmium/tags/taglist.hpp b/third_party/osmium/tags/taglist.hpp
new file mode 100644
index 0000000..41ef993
--- /dev/null
+++ b/third_party/osmium/tags/taglist.hpp
@@ -0,0 +1,67 @@
+#ifndef OSMIUM_TAGS_TAGLIST_HPP
+#define OSMIUM_TAGS_TAGLIST_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <utility>
+
+#include <osmium/osm/tag.hpp>
+
+namespace osmium {
+
+    /**
+     * @brief Code related to working with OSM tags
+     */
+    namespace tags {
+
+        template <class TFilter>
+        inline bool match_any_of(const osmium::TagList& tag_list, TFilter&& filter) {
+            return std::any_of(tag_list.begin(), tag_list.end(), std::forward<TFilter>(filter));
+        }
+
+        template <class TFilter>
+        inline bool match_all_of(const osmium::TagList& tag_list, TFilter&& filter) {
+            return std::all_of(tag_list.begin(), tag_list.end(), std::forward<TFilter>(filter));
+        }
+
+        template <class TFilter>
+        inline bool match_none_of(const osmium::TagList& tag_list, TFilter&& filter) {
+            return std::none_of(tag_list.begin(), tag_list.end(), std::forward<TFilter>(filter));
+        }
+
+    } // namespace tags
+
+} // namespace osmium
+
+#endif // OSMIUM_TAGS_TAGLIST_HPP
diff --git a/third_party/osmium/thread/checked_task.hpp b/third_party/osmium/thread/checked_task.hpp
new file mode 100644
index 0000000..75c664c
--- /dev/null
+++ b/third_party/osmium/thread/checked_task.hpp
@@ -0,0 +1,106 @@
+#ifndef OSMIUM_THREAD_CHECKED_TASK_HPP
+#define OSMIUM_THREAD_CHECKED_TASK_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <chrono>
+#include <future>
+#include <thread>
+#include <utility>
+
+namespace osmium {
+
+    namespace thread {
+
+        template <class T>
+        class CheckedTask {
+
+            std::thread m_thread;
+            std::future<bool> m_future;
+
+        public:
+
+            template <class... TArgs>
+            explicit CheckedTask(TArgs&&... args) {
+                std::packaged_task<bool()> pack_task(T(std::forward<TArgs>(args)...));
+                m_future = pack_task.get_future();
+                m_thread = std::thread(std::move(pack_task));
+            }
+
+            ~CheckedTask() {
+                // Make sure task is done.
+                if (m_thread.joinable()) {
+                    m_thread.join();
+                }
+            }
+
+            CheckedTask(const CheckedTask&) = delete;
+            CheckedTask& operator=(const CheckedTask&) = delete;
+
+            /**
+             * Check task for exceptions.
+             *
+             * If an exception happened in the task, re-throw it in this
+             * thread. This will not do anything if there was no exception.
+             */
+            void check_for_exception() {
+                if (m_future.valid() && m_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+                    m_future.get();
+                }
+            }
+
+            /**
+             * Close the task. This will raise in this thread any exception the
+             * task generated in the other thread.
+             */
+            void close() {
+                // If an exception happened in the task, re-throw
+                // it in this thread. This will block if the task
+                // isn't finished.
+                if (m_future.valid()) {
+                    m_future.get();
+                }
+
+                // Make sure task is done.
+                if (m_thread.joinable()) {
+                    m_thread.join();
+                }
+            }
+
+        }; // class CheckedTask
+
+    } // namespace thread
+
+} // namespace osmium
+
+#endif // OSMIUM_THREAD_CHECKED_TASK_HPP
diff --git a/third_party/osmium/thread/function_wrapper.hpp b/third_party/osmium/thread/function_wrapper.hpp
new file mode 100644
index 0000000..dbb47ff
--- /dev/null
+++ b/third_party/osmium/thread/function_wrapper.hpp
@@ -0,0 +1,110 @@
+#ifndef OSMIUM_THREAD_FUNCTION_WRAPPER_HPP
+#define OSMIUM_THREAD_FUNCTION_WRAPPER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <memory>
+
+namespace osmium {
+
+    namespace thread {
+
+        /**
+         * This function wrapper can collect move-only functions unlike
+         * std::function which needs copyable functions.
+         * Taken from the book "C++ Concurrency in Action".
+         */
+        class function_wrapper {
+
+            struct impl_base {
+
+                virtual ~impl_base() = default;
+                virtual void call() = 0;
+
+            }; // struct impl_base
+
+            std::unique_ptr<impl_base> impl;
+
+            template <typename F>
+            struct impl_type : impl_base {
+                F m_functor;
+
+                impl_type(F&& functor) :
+                    m_functor(std::move(functor)) {
+                }
+
+                void call() override {
+                    m_functor();
+                }
+            }; // struct impl_type
+
+        public:
+
+            // Constructor must not be "explicit" for wrapper
+            // to work seemlessly.
+            template <typename F>
+            function_wrapper(F&& f) :
+                impl(new impl_type<F>(std::move(f))) {
+            }
+
+            void operator()() {
+                impl->call();
+            }
+
+            function_wrapper() = default;
+
+            function_wrapper(function_wrapper&& other) :
+                impl(std::move(other.impl)) {
+            }
+
+            function_wrapper& operator=(function_wrapper&& other) {
+                impl = std::move(other.impl);
+                return *this;
+            }
+
+            function_wrapper(const function_wrapper&) = delete;
+            function_wrapper(function_wrapper&) = delete;
+            function_wrapper& operator=(const function_wrapper&) = delete;
+
+            explicit operator bool() const {
+                return static_cast<bool>(impl);
+            }
+
+        }; // class function_wrapper
+
+    } // namespace thread
+
+} // namespace osmium
+
+#endif // OSMIUM_THREAD_FUNCTION_WRAPPER_HPP
diff --git a/third_party/osmium/thread/name.hpp b/third_party/osmium/thread/name.hpp
new file mode 100644
index 0000000..20ec5c4
--- /dev/null
+++ b/third_party/osmium/thread/name.hpp
@@ -0,0 +1,61 @@
+#ifndef OSMIUM_THREAD_NAME_HPP
+#define OSMIUM_THREAD_NAME_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#ifdef __linux__
+# include <sys/prctl.h>
+#endif
+
+namespace osmium {
+
+    namespace thread {
+
+        /**
+         * Set name of current thread for debugging. This only works on Linux.
+         */
+#ifdef __linux__
+        inline void set_thread_name(const char* name) {
+            prctl(PR_SET_NAME, name, 0, 0, 0);
+        }
+#else
+        inline void set_thread_name(const char*) {
+            // intentionally left blank
+        }
+#endif
+
+    } // namespace thread
+
+} // namespace osmium
+
+#endif //  OSMIUM_THREAD_NAME_HPP
diff --git a/third_party/osmium/thread/pool.hpp b/third_party/osmium/thread/pool.hpp
new file mode 100644
index 0000000..702be66
--- /dev/null
+++ b/third_party/osmium/thread/pool.hpp
@@ -0,0 +1,180 @@
+#ifndef OSMIUM_THREAD_POOL_HPP
+#define OSMIUM_THREAD_POOL_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <atomic>
+#include <cstddef>
+#include <cstdlib>
+#include <future>
+#include <thread>
+#include <type_traits>
+#include <vector>
+
+#include <osmium/thread/function_wrapper.hpp>
+#include <osmium/thread/queue.hpp>
+#include <osmium/thread/util.hpp>
+#include <osmium/util/config.hpp>
+
+namespace osmium {
+
+    /**
+     * @brief Threading-related low-level code
+     */
+    namespace thread {
+
+        /**
+         *  Thread pool.
+         */
+        class Pool {
+
+            /**
+             * This class makes sure all pool threads will be joined when
+             * the pool is destructed.
+             */
+            class thread_joiner {
+
+                std::vector<std::thread>& m_threads;
+
+            public:
+
+                explicit thread_joiner(std::vector<std::thread>& threads) :
+                    m_threads(threads) {
+                }
+
+                ~thread_joiner() {
+                    for (auto& thread : m_threads) {
+                        if (thread.joinable()) {
+                            thread.join();
+                        }
+                    }
+                }
+
+            }; // class thread_joiner
+
+            std::atomic<bool> m_done;
+            osmium::thread::Queue<function_wrapper> m_work_queue;
+            std::vector<std::thread> m_threads;
+            thread_joiner m_joiner;
+            int m_num_threads;
+
+            void worker_thread() {
+                osmium::thread::set_thread_name("_osmium_worker");
+                while (!m_done) {
+                    function_wrapper task;
+                    m_work_queue.wait_and_pop_with_timeout(task);
+                    if (task) {
+                        task();
+                    }
+                }
+            }
+
+            /**
+             * Create thread pool with the given number of threads. If
+             * num_threads is 0, the number of threads is read from
+             * the environment variable OSMIUM_POOL_THREADS. The default
+             * value in that case is -2.
+             *
+             * If the number of threads is a negative number, it will be
+             * set to the actual number of cores on the system plus the
+             * given number, ie it will leave a number of cores unused.
+             *
+             * In all cases the minimum number of threads in the pool is 1.
+             */
+            explicit Pool(int num_threads, size_t max_queue_size) :
+                m_done(false),
+                m_work_queue(max_queue_size, "work"),
+                m_threads(),
+                m_joiner(m_threads),
+                m_num_threads(num_threads) {
+
+                if (m_num_threads == 0) {
+                    m_num_threads = osmium::config::get_pool_threads();
+                }
+
+                if (m_num_threads <= 0) {
+                    m_num_threads = std::max(1, static_cast<int>(std::thread::hardware_concurrency()) + m_num_threads);
+                }
+
+                try {
+                    for (int i=0; i < m_num_threads; ++i) {
+                        m_threads.push_back(std::thread(&Pool::worker_thread, this));
+                    }
+                } catch (...) {
+                    m_done = true;
+                    throw;
+                }
+            }
+
+        public:
+
+            static constexpr int default_num_threads = 0;
+            static constexpr size_t max_work_queue_size = 10;
+
+            static Pool& instance() {
+                static Pool pool(default_num_threads, max_work_queue_size);
+                return pool;
+            }
+
+            ~Pool() {
+                m_done = true;
+            }
+
+            size_t queue_size() const {
+                return m_work_queue.size();
+            }
+
+            bool queue_empty() const {
+                return m_work_queue.empty();
+            }
+
+            template <typename TFunction>
+            std::future<typename std::result_of<TFunction()>::type> submit(TFunction f) {
+
+                typedef typename std::result_of<TFunction()>::type result_type;
+
+                std::packaged_task<result_type()> task(std::move(f));
+                std::future<result_type> future_result(task.get_future());
+                m_work_queue.push(std::move(task));
+
+                return future_result;
+            }
+
+        }; // class Pool
+
+    } // namespace thread
+
+} // namespace osmium
+
+#endif // OSMIUM_THREAD_POOL_HPP
diff --git a/third_party/osmium/thread/queue.hpp b/third_party/osmium/thread/queue.hpp
new file mode 100644
index 0000000..b01dd39
--- /dev/null
+++ b/third_party/osmium/thread/queue.hpp
@@ -0,0 +1,178 @@
+#ifndef OSMIUM_THREAD_QUEUE_HPP
+#define OSMIUM_THREAD_QUEUE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <cstddef>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <utility>
+
+namespace osmium {
+
+    namespace thread {
+
+        constexpr std::chrono::milliseconds full_queue_sleep_duration { 10 }; // XXX
+
+        /**
+         *  A thread-safe queue.
+         */
+        template <typename T>
+        class Queue {
+
+            /// Maximum size of this queue. If the queue is full pushing to
+            /// the queue will block.
+            const size_t m_max_size;
+
+            /// Name of this queue (for debugging only).
+            const std::string m_name;
+
+            mutable std::mutex m_mutex;
+
+            std::queue<T> m_queue;
+
+            /// Used to signal readers when data is available in the queue.
+            std::condition_variable m_data_available;
+
+#ifdef OSMIUM_DEBUG_QUEUE_SIZE
+            /// The largest size the queue has been so far.
+            size_t m_largest_size;
+
+            /// The number of times the queue was full and a thread pushing
+            /// to the queue was blocked.
+            std::atomic<int> m_full_counter;
+#endif
+
+        public:
+
+            /**
+             * Construct a multithreaded queue.
+             *
+             * @param max_size Maximum number of elements in the queue. Set to
+             *                 0 for an unlimited size.
+             * @param name Optional name for this queue. (Used for debugging.)
+             */
+            Queue(size_t max_size = 0, const std::string& name = "") :
+                m_max_size(max_size),
+                m_name(name),
+                m_mutex(),
+                m_queue(),
+                m_data_available()
+#ifdef OSMIUM_DEBUG_QUEUE_SIZE
+                ,
+                m_largest_size(0),
+                m_full_counter(0)
+#endif
+            {
+            }
+
+            ~Queue() {
+#ifdef OSMIUM_DEBUG_QUEUE_SIZE
+                std::cerr << "queue '" << m_name << "' with max_size=" << m_max_size << " had largest size " << m_largest_size << " and was full " << m_full_counter << " times\n";
+#endif
+            }
+
+            /**
+             * Push an element onto the queue. If the queue has a max size, this
+             * call will block if the queue is full.
+             */
+            void push(T value) {
+                if (m_max_size) {
+                    while (size() >= m_max_size) {
+                        std::this_thread::sleep_for(full_queue_sleep_duration);
+#ifdef OSMIUM_DEBUG_QUEUE_SIZE
+                        ++m_full_counter;
+#endif
+                    }
+                }
+                std::lock_guard<std::mutex> lock(m_mutex);
+                m_queue.push(std::move(value));
+#ifdef OSMIUM_DEBUG_QUEUE_SIZE
+                if (m_largest_size < m_queue.size()) {
+                    m_largest_size = m_queue.size();
+                }
+#endif
+                m_data_available.notify_one();
+            }
+
+            void wait_and_pop(T& value) {
+                std::unique_lock<std::mutex> lock(m_mutex);
+                m_data_available.wait(lock, [this] {
+                    return !m_queue.empty();
+                });
+                value=std::move(m_queue.front());
+                m_queue.pop();
+            }
+
+            void wait_and_pop_with_timeout(T& value) {
+                std::unique_lock<std::mutex> lock(m_mutex);
+                if (!m_data_available.wait_for(lock, std::chrono::seconds(1), [this] {
+                    return !m_queue.empty();
+                })) {
+                    return;
+                }
+                value=std::move(m_queue.front());
+                m_queue.pop();
+            }
+
+            bool try_pop(T& value) {
+                std::lock_guard<std::mutex> lock(m_mutex);
+                if (m_queue.empty()) {
+                    return false;
+                }
+                value=std::move(m_queue.front());
+                m_queue.pop();
+                return true;
+            }
+
+            bool empty() const {
+                std::lock_guard<std::mutex> lock(m_mutex);
+                return m_queue.empty();
+            }
+
+            size_t size() const {
+                std::lock_guard<std::mutex> lock(m_mutex);
+                return m_queue.size();
+            }
+
+        }; // class Queue
+
+    } // namespace thread
+
+} // namespace osmium
+
+#endif // OSMIUM_THREAD_QUEUE_HPP
diff --git a/third_party/osmium/thread/sorted_queue.hpp b/third_party/osmium/thread/sorted_queue.hpp
new file mode 100644
index 0000000..e33dfe6
--- /dev/null
+++ b/third_party/osmium/thread/sorted_queue.hpp
@@ -0,0 +1,159 @@
+#ifndef OSMIUM_THREAD_SORTED_QUEUE_HPP
+#define OSMIUM_THREAD_SORTED_QUEUE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <condition_variable>
+#include <cstddef>
+#include <deque>
+#include <mutex>
+
+namespace osmium {
+
+    namespace thread {
+
+        /**
+         * This implements a sorted queue. It is a bit like a priority
+         * queue. We have n worker threads pushing items into the queue
+         * and one thread pulling them out again "in order". The order
+         * is defined by the monotonically increasing "num" parameter
+         * to the push() method. The wait_and_pop() and try_pop() methods
+         * will only give out the next numbered item. This way several
+         * workers can work in their own time on different pieces of
+         * some incoming data, but it all gets serialized properly again
+         * after the workers have done their work.
+         */
+        template <typename T>
+        class SortedQueue {
+
+            typedef typename std::deque<T>::size_type size_type;
+
+            mutable std::mutex m_mutex;
+            std::deque<T> m_queue;
+            std::condition_variable m_data_available;
+
+            size_type m_offset;
+
+            // this method expects that we already have the lock
+            bool empty_intern() const {
+                return m_queue.front() == T();
+            }
+
+        public:
+
+            SortedQueue() :
+                m_mutex(),
+                m_queue(1),
+                m_data_available(),
+                m_offset(0) {
+            }
+
+            /**
+             * Push an item into the queue.
+             *
+             * @param value The item to push into the queue.
+             * @param num Number to describe ordering for the items.
+             *            It must increase monotonically.
+             */
+            void push(T value, size_type num) {
+                std::lock_guard<std::mutex> lock(m_mutex);
+
+                num -= m_offset;
+                if (m_queue.size() <= num + 1) {
+                    m_queue.resize(num + 2);
+                }
+                m_queue[num] = std::move(value);
+
+                m_data_available.notify_one();
+            }
+
+            /**
+             * Wait until the next item becomes available and make it
+             * available through value.
+             */
+            void wait_and_pop(T& value) {
+                std::unique_lock<std::mutex> lock(m_mutex);
+
+                m_data_available.wait(lock, [this] {
+                    return !empty_intern();
+                });
+                value=std::move(m_queue.front());
+                m_queue.pop_front();
+                ++m_offset;
+            }
+
+            /**
+             * Get next item if it is available and return true. Or
+             * return false otherwise.
+             */
+            bool try_pop(T& value) {
+                std::lock_guard<std::mutex> lock(m_mutex);
+
+                if (empty_intern()) {
+                    return false;
+                }
+                value=std::move(m_queue.front());
+                m_queue.pop_front();
+                ++m_offset;
+                return true;
+            }
+
+            /**
+             * The queue is empty. This means try_pop() would fail if called.
+             * It does not mean that there is nothing on the queue. Because
+             * the queue is sorted, it could mean that the next item in the
+             * queue is not available, but other items are.
+             */
+            bool empty() const {
+                std::lock_guard<std::mutex> lock(m_mutex);
+
+                return empty_intern();
+            }
+
+            /**
+             * Returns the number of items in the queue, regardless of whether
+             * they can be accessed. If this is =0 it
+             * implies empty()==true, but not the other way around.
+             */
+            size_t size() const {
+                std::lock_guard<std::mutex> lock(m_mutex);
+                return m_queue.size();
+            }
+
+        }; // class SortedQueue
+
+    } // namespace thread
+
+} // namespace osmium
+
+#endif // OSMIUM_THREAD_SORTED_QUEUE_HPP
diff --git a/third_party/osmium/thread/util.hpp b/third_party/osmium/thread/util.hpp
new file mode 100644
index 0000000..286ea5e
--- /dev/null
+++ b/third_party/osmium/thread/util.hpp
@@ -0,0 +1,87 @@
+#ifndef OSMIUM_THREAD_UTIL_HPP
+#define OSMIUM_THREAD_UTIL_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <chrono>
+#include <future>
+
+#ifdef __linux__
+# include <sys/prctl.h>
+#endif
+
+namespace osmium {
+
+    namespace thread {
+
+        /**
+         * Check if the future resulted in an exception. This will re-throw
+         * the exception stored in the future if there was one. Otherwise it
+         * will just return.
+         */
+        template <class T>
+        inline void check_for_exception(std::future<T>& future) {
+            if (future.valid() && future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+                future.get();
+            }
+        }
+
+        /**
+         * Wait until the given future becomes ready. Will block if the future
+         * is not ready. Can be called more than once unless future.get().
+         */
+        template <class T>
+        inline void wait_until_done(std::future<T>& future) {
+            if (future.valid()) {
+                future.get();
+            }
+        }
+
+        /**
+         * Set name of current thread for debugging. This only works on Linux.
+         */
+#ifdef __linux__
+        inline void set_thread_name(const char* name) {
+            prctl(PR_SET_NAME, name, 0, 0, 0);
+        }
+#else
+        inline void set_thread_name(const char*) {
+            // intentionally left blank
+        }
+#endif
+
+    } // namespace thread
+
+} // namespace osmium
+
+#endif //  OSMIUM_THREAD_UTIL_HPP
diff --git a/third_party/osmium/util/cast.hpp b/third_party/osmium/util/cast.hpp
new file mode 100644
index 0000000..7503267
--- /dev/null
+++ b/third_party/osmium/util/cast.hpp
@@ -0,0 +1,72 @@
+#ifndef OSMIUM_UTIL_CAST_HPP
+#define OSMIUM_UTIL_CAST_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <limits>
+#include <type_traits>
+
+namespace osmium {
+
+    template <typename T, typename F, typename std::enable_if<std::is_integral<T>::value && std::is_integral<F>::value && std::is_signed<T>::value && std::is_signed<F>::value, int>::type = 0>
+    inline T static_cast_with_assert(const F value) {
+        static_assert(sizeof(T) < sizeof(F), "unnecessary static_cast_with_assert when casting into type of equal or larger size");
+        assert(value >= std::numeric_limits<T>::min() && value <= std::numeric_limits<T>::max());
+        return static_cast<T>(value);
+    }
+
+    template <typename T, typename F, typename std::enable_if<std::is_integral<T>::value && std::is_integral<F>::value && std::is_unsigned<T>::value && std::is_signed<F>::value, int>::type = 0>
+    inline T static_cast_with_assert(const F value) {
+        static_assert(sizeof(T) <= sizeof(F), "unnecessary static_cast_with_assert when casting into type of larger size");
+        assert(value >= 0 && static_cast<typename std::make_unsigned<F>::type>(value) <= std::numeric_limits<T>::max());
+        return static_cast<T>(value);
+    }
+
+    template <typename T, typename F, typename std::enable_if<std::is_integral<T>::value && std::is_integral<F>::value && std::is_unsigned<T>::value && std::is_unsigned<F>::value, int>::type = 0>
+    inline T static_cast_with_assert(const F value) {
+        static_assert(sizeof(T) < sizeof(F), "unnecessary static_cast_with_assert when casting into type of equal or larger size");
+        assert(value <= std::numeric_limits<T>::max());
+        return static_cast<T>(value);
+    }
+
+    template <typename T, typename F, typename std::enable_if<std::is_integral<T>::value && std::is_integral<F>::value && std::is_signed<T>::value && std::is_unsigned<F>::value, int>::type = 0>
+    inline T static_cast_with_assert(const F value) {
+        static_assert(sizeof(T) <= sizeof(F), "unnecessary static_cast_with_assert when casting into type of larger size");
+        assert(value <= std::numeric_limits<T>::max());
+        return static_cast<T>(value);
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_CAST_HPP
diff --git a/third_party/osmium/util/compatibility.hpp b/third_party/osmium/util/compatibility.hpp
new file mode 100644
index 0000000..48a6db0
--- /dev/null
+++ b/third_party/osmium/util/compatibility.hpp
@@ -0,0 +1,47 @@
+#ifndef OSMIUM_UTIL_COMPATIBILITY_HPP
+#define OSMIUM_UTIL_COMPATIBILITY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+// Workarounds for MSVC which doesn't support
+// * constexpr in all cases yet
+// * [[noreturn]]
+#ifdef _MSC_VER
+# define OSMIUM_CONSTEXPR
+# define OSMIUM_NORETURN __declspec(noreturn)
+#else
+# define OSMIUM_CONSTEXPR constexpr
+# define OSMIUM_NORETURN [[noreturn]]
+#endif
+
+#endif // OSMIUM_UTIL_COMPATIBILITY_HPP
diff --git a/third_party/osmium/util/config.hpp b/third_party/osmium/util/config.hpp
new file mode 100644
index 0000000..6c86d68
--- /dev/null
+++ b/third_party/osmium/util/config.hpp
@@ -0,0 +1,73 @@
+#ifndef OSMIUM_UTIL_CONFIG_HPP
+#define OSMIUM_UTIL_CONFIG_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstdlib>
+#include <cstring>
+
+#ifdef _MSC_VER 
+#define strncasecmp _strnicmp
+#define strcasecmp _stricmp
+#endif
+
+namespace osmium {
+
+    namespace config {
+
+        inline int get_pool_threads() {
+            const char* env = getenv("OSMIUM_POOL_THREADS");
+            if (env) {
+                return std::atoi(env);
+            }
+            return -2;
+        }
+
+        inline bool use_pool_threads_for_pbf_parsing() {
+            const char* env = getenv("OSMIUM_USE_POOL_THREADS_FOR_PBF_PARSING");
+            if (env) {
+                if (!strcasecmp(env, "off") ||
+                    !strcasecmp(env, "false") ||
+                    !strcasecmp(env, "no") ||
+                    !strcasecmp(env, "0")) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+    } // namespace config
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_CONFIG_HPP
diff --git a/third_party/osmium/util/double.hpp b/third_party/osmium/util/double.hpp
new file mode 100644
index 0000000..91f4ac7
--- /dev/null
+++ b/third_party/osmium/util/double.hpp
@@ -0,0 +1,91 @@
+#ifndef OSMIUM_UTIL_DOUBLE_HPP
+#define OSMIUM_UTIL_DOUBLE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <cstdio>
+
+namespace osmium {
+
+    namespace util {
+
+        constexpr int max_double_length = 20; // should fit any double
+
+        /**
+         * Write double to iterator, removing superfluous '0' characters at
+         * the end. The decimal dot will also be removed if necessary.
+         *
+         * @tparam T iterator type
+         * @param iterator output iterator
+         * @param value the value that should be written
+         * @param precision max number of digits after the decimal point (must be <= 17)
+         */
+        template <typename T>
+        inline T double2string(T iterator, double value, int precision) {
+            assert(precision <= 17);
+
+            char buffer[max_double_length];
+
+#ifndef _MSC_VER
+            int len = snprintf(buffer, max_double_length, "%.*f", precision, value);
+#else
+            int len = _snprintf(buffer, max_double_length, "%.*f", precision, value);
+#endif
+            assert(len > 0 && len < max_double_length);
+
+            while (buffer[len-1] == '0') --len;
+            if (buffer[len-1] == '.') --len;
+
+            return std::copy_n(buffer, len, iterator);
+        }
+
+        /**
+         * Write double to string, removing superfluous '0' characters at
+         * the end. The decimal dot will also be removed if necessary.
+         *
+         * @param out string
+         * @param value the value that should be written
+         * @param precision max number of digits after the decimal point
+         */
+        inline void double2string(std::string& out, double value, int precision) {
+            double2string(std::back_inserter(out), value, precision);
+        }
+
+    } // namespace util
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_DOUBLE_HPP
diff --git a/third_party/osmium/util/options.hpp b/third_party/osmium/util/options.hpp
new file mode 100644
index 0000000..fc74980
--- /dev/null
+++ b/third_party/osmium/util/options.hpp
@@ -0,0 +1,155 @@
+#ifndef OSMIUM_UTIL_OPTIONS_HPP
+#define OSMIUM_UTIL_OPTIONS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <initializer_list>
+#include <map>
+#include <string>
+#include <utility>
+
+namespace osmium {
+
+    namespace util {
+
+        /**
+         * Stores key=value type options. This class can be used stand-alone or
+         * as a base class. Options are stored and retrieved by key using the
+         * different set() and get() methods.
+         *
+         * You can iterate over all set options. Dereferencing an iterator
+         * yields a std::pair of the key and value strings.
+         */
+        class Options {
+
+            typedef std::map<std::string, std::string> option_map;
+            option_map m_options;
+
+        public:
+
+            typedef option_map::iterator iterator;
+            typedef option_map::const_iterator const_iterator;
+            typedef option_map::value_type value_type;
+
+            Options() = default;
+
+            explicit Options(const std::initializer_list<value_type>& values) :
+                m_options(values) {
+            }
+
+            Options(const Options&) = default;
+            Options& operator=(const Options&) = default;
+
+            Options(Options&&) = default;
+            Options& operator=(Options&&) = default;
+
+            ~Options() = default;
+
+            void set(const std::string& key, const std::string& value) {
+                m_options[key] = value;
+            }
+
+            void set(const std::string& key, const char* value) {
+                m_options[key] = value;
+            }
+
+            void set(const std::string& key, bool value) {
+                m_options[key] = value ? "true" : "false";
+            }
+
+            void set(std::string data) {
+                size_t pos = data.find_first_of('=');
+                if (pos == std::string::npos) {
+                    m_options[data] = "true";
+                } else {
+                    std::string value = data.substr(pos+1);
+                    data.erase(pos);
+                    set(data, value);
+                }
+            }
+
+            /**
+             * Get value of "key" option. If not set the default_value (or
+             * empty string) is returned.
+             */
+            std::string get(const std::string& key, const std::string& default_value="") const noexcept {
+                auto it = m_options.find(key);
+                if (it == m_options.end()) {
+                    return default_value;
+                }
+                return it->second;
+            }
+
+            /**
+             * Is this option set to a true value ("true" or "yes")?
+             */
+            bool is_true(const std::string& key) const noexcept {
+                std::string value = get(key);
+                return (value == "true" || value == "yes");
+            }
+
+            size_t size() const noexcept {
+                return m_options.size();
+            }
+
+            iterator begin() noexcept {
+                return m_options.begin();
+            }
+
+            iterator end() noexcept {
+                return m_options.end();
+            }
+
+            const_iterator begin() const noexcept {
+                return m_options.cbegin();
+            }
+
+            const_iterator end() const noexcept {
+                return m_options.cend();
+            }
+
+            const_iterator cbegin() const noexcept {
+                return m_options.cbegin();
+            }
+
+            const_iterator cend() const noexcept {
+                return m_options.cend();
+            }
+
+        }; // class Options
+
+    } // namespace util
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_OPTIONS_HPP
diff --git a/third_party/osmium/util/verbose_output.hpp b/third_party/osmium/util/verbose_output.hpp
new file mode 100644
index 0000000..8709441
--- /dev/null
+++ b/third_party/osmium/util/verbose_output.hpp
@@ -0,0 +1,139 @@
+#ifndef OSMIUM_UTIL_VERBOSE_OUTPUT_HPP
+#define OSMIUM_UTIL_VERBOSE_OUTPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <time.h>
+
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+namespace osmium {
+
+    /**
+     * @brief Helpful utility classes and functions not strictly OSM related
+     */
+    namespace util {
+
+        /**
+         * Osmium programs often run for a long time because of the amount of
+         * OSM data processed. This class helps with keeping the user up to
+         * date by offering an easy way for programs to optionally output
+         * verbose information about what's going on.
+         *
+         * Use an object of this class instead of std::cerr as an output
+         * stream. Nothing is actually written if the object is not set to
+         * verbose mode. If it is set to verbose mode, each line is prepended
+         * with the running time, ie the time since the VerboseOutput object
+         * was created.
+         */
+        class VerboseOutput {
+
+            /// all time output will be relative to this start time
+            time_t m_start;
+
+            /// is verbose mode enabled?
+            bool m_verbose;
+
+            /// a newline was written, start next output with runtime
+            bool m_newline;
+
+            /**
+             * If we remember that a newline was written as the last thing
+             * write out the time elapsed and reset the newline flag.
+             */
+            void start_line() {
+                if (m_newline) {
+                    time_t elapsed = runtime();
+
+                    char old_fill = std::cerr.fill();
+                    std::cerr << '[' << std::setw(2) << (elapsed / 60) << ':' << std::setw(2) << std::setfill('0') << (elapsed % 60) << "] ";
+                    std::cerr.fill(old_fill);
+
+                    m_newline = false;
+                }
+            }
+
+        public:
+
+            explicit VerboseOutput(bool verbose=false) noexcept :
+                m_start(time(NULL)),
+                m_verbose(verbose),
+                m_newline(true) {
+            }
+
+            ~VerboseOutput() = default;
+
+            VerboseOutput(const VerboseOutput&) = default;
+            VerboseOutput& operator=(const VerboseOutput&) = default;
+            VerboseOutput(VerboseOutput&&) = default;
+            VerboseOutput& operator=(VerboseOutput&&) = default;
+
+            time_t runtime() const noexcept {
+                return time(NULL) - m_start;
+            }
+
+            /// Get "verbose" setting.
+            bool verbose() const noexcept {
+                return m_verbose;
+            }
+
+            /// Set "verbose" setting.
+            void verbose(bool verbose) noexcept {
+                m_verbose = verbose;
+            }
+
+            template<typename T>
+            friend VerboseOutput& operator<<(VerboseOutput& verbose_output, const T& value) {
+                if (verbose_output.m_verbose) {
+                    verbose_output.start_line();
+                    std::cerr << value;
+
+                    // check if there was a newline a the end and remember that
+                    std::ostringstream output_buffer;
+                    output_buffer << value;
+                    if (!output_buffer.str().empty() && output_buffer.str().back() == '\n') {
+                        verbose_output.m_newline = true;
+                    }
+                }
+                return verbose_output;
+            }
+
+        }; // class VerboseOutput
+
+    } // namespace util
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_VERBOSE_OUTPUT_HPP
diff --git a/third_party/osmium/visitor.hpp b/third_party/osmium/visitor.hpp
new file mode 100644
index 0000000..d71a2e0
--- /dev/null
+++ b/third_party/osmium/visitor.hpp
@@ -0,0 +1,255 @@
+#ifndef OSMIUM_VISITOR_HPP
+#define OSMIUM_VISITOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <type_traits>
+
+#include <osmium/io/reader_iterator.hpp> // IWYU pragma: keep
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm.hpp>
+#include <osmium/osm/entity.hpp>
+#include <osmium/osm/item_type.hpp>
+
+namespace osmium {
+
+    class TagList;
+    class WayNodeList;
+    class RelationMemberList;
+    class OuterRing;
+    class InnerRing;
+
+    namespace memory {
+        class Item;
+    }
+
+    namespace detail {
+
+        template <typename T, typename U>
+        using ConstIfConst = typename std::conditional<std::is_const<T>::value, typename std::add_const<U>::type, U>::type;
+
+        template <class THandler, class TItem>
+        inline void apply_item_recurse(TItem& item, THandler& handler) {
+            switch (item.type()) {
+                case osmium::item_type::undefined:
+                    break;
+                case osmium::item_type::node:
+                    handler.osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
+                    handler.node(static_cast<ConstIfConst<TItem, osmium::Node>&>(item));
+                    break;
+                case osmium::item_type::way:
+                    handler.osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
+                    handler.way(static_cast<ConstIfConst<TItem, osmium::Way>&>(item));
+                    break;
+                case osmium::item_type::relation:
+                    handler.osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
+                    handler.relation(static_cast<ConstIfConst<TItem, osmium::Relation>&>(item));
+                    break;
+                case osmium::item_type::area:
+                    handler.osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
+                    handler.area(static_cast<ConstIfConst<TItem, osmium::Area>&>(item));
+                    break;
+                case osmium::item_type::changeset:
+                    handler.changeset(static_cast<ConstIfConst<TItem, osmium::Changeset>&>(item));
+                    break;
+                case osmium::item_type::tag_list:
+                    handler.tag_list(static_cast<ConstIfConst<TItem, osmium::TagList>&>(item));
+                    break;
+                case osmium::item_type::way_node_list:
+                    handler.way_node_list(static_cast<ConstIfConst<TItem, osmium::WayNodeList>&>(item));
+                    break;
+                case osmium::item_type::relation_member_list:
+                case osmium::item_type::relation_member_list_with_full_members:
+                    handler.relation_member_list(static_cast<ConstIfConst<TItem, osmium::RelationMemberList>&>(item));
+                    break;
+                case osmium::item_type::outer_ring:
+                    handler.outer_ring(static_cast<ConstIfConst<TItem, osmium::OuterRing>&>(item));
+                    break;
+                case osmium::item_type::inner_ring:
+                    handler.inner_ring(static_cast<ConstIfConst<TItem, osmium::InnerRing>&>(item));
+                    break;
+            }
+        }
+
+        template <class THandler>
+        inline void apply_item_recurse(const osmium::OSMEntity& item, THandler& handler) {
+            switch (item.type()) {
+                case osmium::item_type::node:
+                    handler.osm_object(static_cast<const osmium::OSMObject&>(item));
+                    handler.node(static_cast<const osmium::Node&>(item));
+                    break;
+                case osmium::item_type::way:
+                    handler.osm_object(static_cast<const osmium::OSMObject&>(item));
+                    handler.way(static_cast<const osmium::Way&>(item));
+                    break;
+                case osmium::item_type::relation:
+                    handler.osm_object(static_cast<const osmium::OSMObject&>(item));
+                    handler.relation(static_cast<const osmium::Relation&>(item));
+                    break;
+                case osmium::item_type::area:
+                    handler.osm_object(static_cast<const osmium::OSMObject&>(item));
+                    handler.area(static_cast<const osmium::Area&>(item));
+                    break;
+                case osmium::item_type::changeset:
+                    handler.changeset(static_cast<const osmium::Changeset&>(item));
+                    break;
+                default:
+                    throw osmium::unknown_type();
+            }
+        }
+
+        template <class THandler>
+        inline void apply_item_recurse(osmium::OSMEntity& item, THandler& handler) {
+            switch (item.type()) {
+                case osmium::item_type::node:
+                    handler.osm_object(static_cast<osmium::OSMObject&>(item));
+                    handler.node(static_cast<osmium::Node&>(item));
+                    break;
+                case osmium::item_type::way:
+                    handler.osm_object(static_cast<osmium::OSMObject&>(item));
+                    handler.way(static_cast<osmium::Way&>(item));
+                    break;
+                case osmium::item_type::relation:
+                    handler.osm_object(static_cast<osmium::OSMObject&>(item));
+                    handler.relation(static_cast<osmium::Relation&>(item));
+                    break;
+                case osmium::item_type::area:
+                    handler.osm_object(static_cast<osmium::OSMObject&>(item));
+                    handler.area(static_cast<osmium::Area&>(item));
+                    break;
+                case osmium::item_type::changeset:
+                    handler.changeset(static_cast<osmium::Changeset&>(item));
+                    break;
+                default:
+                    throw osmium::unknown_type();
+            }
+        }
+
+        template <class THandler>
+        inline void apply_item_recurse(const osmium::OSMObject& item, THandler& handler) {
+            switch (item.type()) {
+                case osmium::item_type::node:
+                    handler.osm_object(item);
+                    handler.node(static_cast<const osmium::Node&>(item));
+                    break;
+                case osmium::item_type::way:
+                    handler.osm_object(item);
+                    handler.way(static_cast<const osmium::Way&>(item));
+                    break;
+                case osmium::item_type::relation:
+                    handler.osm_object(item);
+                    handler.relation(static_cast<const osmium::Relation&>(item));
+                    break;
+                case osmium::item_type::area:
+                    handler.osm_object(item);
+                    handler.area(static_cast<const osmium::Area&>(item));
+                    break;
+                default:
+                    throw osmium::unknown_type();
+            }
+        }
+
+        template <class THandler>
+        inline void apply_item_recurse(osmium::OSMObject& item, THandler& handler) {
+            switch (item.type()) {
+                case osmium::item_type::node:
+                    handler.osm_object(item);
+                    handler.node(static_cast<osmium::Node&>(item));
+                    break;
+                case osmium::item_type::way:
+                    handler.osm_object(item);
+                    handler.way(static_cast<osmium::Way&>(item));
+                    break;
+                case osmium::item_type::relation:
+                    handler.osm_object(item);
+                    handler.relation(static_cast<osmium::Relation&>(item));
+                    break;
+                case osmium::item_type::area:
+                    handler.osm_object(item);
+                    handler.area(static_cast<osmium::Area&>(item));
+                    break;
+                default:
+                    throw osmium::unknown_type();
+            }
+        }
+
+        template <class THandler, class TItem, class ...TRest>
+        inline void apply_item_recurse(TItem& item, THandler& handler, TRest&... more) {
+            apply_item_recurse(item, handler);
+            apply_item_recurse(item, more...);
+        }
+
+        template <class THandler>
+        inline void flush_recurse(THandler& handler) {
+            handler.flush();
+        }
+
+        template <class THandler, class ...TRest>
+        inline void flush_recurse(THandler& handler, TRest&... more) {
+            flush_recurse(handler);
+            flush_recurse(more...);
+        }
+
+    } // namespace detail
+
+    template <class ...THandlers>
+    inline void apply_item(const osmium::memory::Item& item, THandlers&... handlers) {
+        detail::apply_item_recurse(item, handlers...);
+    }
+
+    template <class ...THandlers>
+    inline void apply_item(osmium::memory::Item& item, THandlers&... handlers) {
+        detail::apply_item_recurse(item, handlers...);
+    }
+
+    template <class TIterator, class ...THandlers>
+    inline void apply(TIterator it, TIterator end, THandlers&... handlers) {
+        for (; it != end; ++it) {
+            detail::apply_item_recurse(*it, handlers...);
+        }
+        detail::flush_recurse(handlers...);
+    }
+
+    template <class TContainer, class ...THandlers>
+    inline void apply(TContainer& c, THandlers&... handlers) {
+        apply(std::begin(c), std::end(c), handlers...);
+    }
+
+    template <class ...THandlers>
+    inline void apply(const osmium::memory::Buffer& buffer, THandlers&... handlers) {
+        apply(buffer.cbegin(), buffer.cend(), handlers...);
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_VISITOR_HPP
diff --git a/third_party/variant/optional.hpp b/third_party/variant/optional.hpp
new file mode 100644
index 0000000..133e2c8
--- /dev/null
+++ b/third_party/variant/optional.hpp
@@ -0,0 +1,69 @@
+#ifndef MAPBOX_UTIL_OPTIONAL_HPP
+#define MAPBOX_UTIL_OPTIONAL_HPP
+
+#include <type_traits>
+
+#include "variant.hpp"
+
+namespace mapbox
+{
+namespace util
+{
+
+template <typename T> class optional
+{
+    static_assert(!std::is_reference<T>::value, "optional doesn't support references");
+
+    struct none_type
+    {
+    };
+
+    variant<none_type, T> variant_;
+
+  public:
+    optional() = default;
+
+    optional(optional const &rhs)
+    {
+        if (this != &rhs)
+        { // protect against invalid self-assignment
+            variant_ = rhs.variant_;
+        }
+    }
+
+    optional(T const &v) { variant_ = v; }
+
+    explicit operator bool() const noexcept { return variant_.template is<T>(); }
+
+    T const &get() const { return variant_.template get<T>(); }
+    T &get() { return variant_.template get<T>(); }
+
+    T const &operator*() const { return this->get(); }
+    T operator*() { return this->get(); }
+
+    optional &operator=(T const &v)
+    {
+        variant_ = v;
+        return *this;
+    }
+
+    optional &operator=(optional const &rhs)
+    {
+        if (this != &rhs)
+        {
+            variant_ = rhs.variant_;
+        }
+        return *this;
+    }
+
+    template <typename... Args> void emplace(Args &&... args)
+    {
+        variant_ = T{std::forward<Args>(args)...};
+    }
+
+    void reset() { variant_ = none_type{}; }
+};
+}
+}
+
+#endif
diff --git a/third_party/variant/recursive_wrapper.hpp b/third_party/variant/recursive_wrapper.hpp
new file mode 100644
index 0000000..54b2763
--- /dev/null
+++ b/third_party/variant/recursive_wrapper.hpp
@@ -0,0 +1,127 @@
+#ifndef MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
+#define MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
+
+#include <utility>
+
+namespace mapbox { namespace util {
+
+template <typename T>
+class recursive_wrapper
+{
+public:
+    using type = T;
+private:
+
+    T* p_;
+
+public:
+
+    ~recursive_wrapper();
+    recursive_wrapper();
+
+    recursive_wrapper(recursive_wrapper const& operand);
+    recursive_wrapper(T const& operand);
+    recursive_wrapper(recursive_wrapper&& operand);
+    recursive_wrapper(T&& operand);
+
+private:
+
+    void assign(const T& rhs);
+
+public:
+
+    inline recursive_wrapper& operator=(recursive_wrapper const& rhs)
+    {
+        assign( rhs.get() );
+        return *this;
+    }
+
+    inline recursive_wrapper& operator=(T const& rhs)
+    {
+        assign( rhs );
+        return *this;
+    }
+
+    inline void swap(recursive_wrapper& operand) noexcept
+    {
+        T* temp = operand.p_;
+        operand.p_ = p_;
+        p_ = temp;
+    }
+
+
+    recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept
+    {
+        swap(rhs);
+        return *this;
+    }
+
+    recursive_wrapper& operator=(T&& rhs)
+    {
+        get() = std::move(rhs);
+        return *this;
+    }
+
+
+public:
+
+    T& get() { return *get_pointer(); }
+    const T& get() const { return *get_pointer(); }
+    T* get_pointer() { return p_; }
+    const T* get_pointer() const { return p_; }
+    operator T const&() const { return this->get(); }
+    operator T&() { return this->get(); }
+};
+
+template <typename T>
+recursive_wrapper<T>::~recursive_wrapper()
+{
+    delete p_;
+}
+
+template <typename T>
+recursive_wrapper<T>::recursive_wrapper()
+    : p_(new T)
+{
+}
+
+template <typename T>
+recursive_wrapper<T>::recursive_wrapper(recursive_wrapper const& operand)
+    : p_(new T( operand.get() ))
+{
+}
+
+template <typename T>
+recursive_wrapper<T>::recursive_wrapper(T const& operand)
+    : p_(new T(operand))
+{
+}
+
+template <typename T>
+recursive_wrapper<T>::recursive_wrapper(recursive_wrapper&& operand)
+    : p_(operand.p_)
+{
+    operand.p_ = nullptr;
+}
+
+template <typename T>
+recursive_wrapper<T>::recursive_wrapper(T&& operand)
+    : p_(new T( std::move(operand) ))
+{
+}
+
+template <typename T>
+void recursive_wrapper<T>::assign(const T& rhs)
+{
+    this->get() = rhs;
+}
+
+template <typename T>
+inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept
+{
+    lhs.swap(rhs);
+}
+
+}}
+
+#endif // MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
diff --git a/third_party/variant/variant.hpp b/third_party/variant/variant.hpp
new file mode 100644
index 0000000..3b56594
--- /dev/null
+++ b/third_party/variant/variant.hpp
@@ -0,0 +1,740 @@
+#ifndef MAPBOX_UTIL_VARIANT_HPP
+#define MAPBOX_UTIL_VARIANT_HPP
+
+#include <utility>
+#include <typeinfo>
+#include <type_traits>
+#include <stdexcept> // runtime_error
+#include <new> // operator new
+#include <cstddef> // size_t
+#include <iosfwd>
+#include <string>
+
+#include "recursive_wrapper.hpp"
+
+#ifdef _MSC_VER
+ // http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx
+ #ifdef NDEBUG
+  #define VARIANT_INLINE __forceinline
+ #else
+  #define VARIANT_INLINE __declspec(noinline)
+ #endif
+#else
+ #ifdef NDEBUG
+  #define VARIANT_INLINE inline __attribute__((always_inline))
+ #else
+  #define VARIANT_INLINE __attribute__((noinline))
+ #endif
+#endif
+
+#define VARIANT_MAJOR_VERSION 0
+#define VARIANT_MINOR_VERSION 1
+#define VARIANT_PATCH_VERSION 0
+
+// translates to 100
+#define VARIANT_VERSION (VARIANT_MAJOR_VERSION*100000) + (VARIANT_MINOR_VERSION*100) + (VARIANT_PATCH_VERSION)
+
+namespace mapbox { namespace util { namespace detail {
+
+static constexpr std::size_t invalid_value = std::size_t(-1);
+
+template <typename T, typename...Types>
+struct direct_type;
+
+template <typename T, typename First, typename...Types>
+struct direct_type<T, First, Types...>
+{
+    static constexpr std::size_t index = std::is_same<T, First>::value
+        ? sizeof...(Types) : direct_type<T, Types...>::index;
+};
+
+template <typename T>
+struct direct_type<T>
+{
+    static constexpr std::size_t index = invalid_value;
+};
+
+template <typename T, typename...Types>
+struct convertible_type;
+
+template <typename T, typename First, typename...Types>
+struct convertible_type<T, First, Types...>
+{
+    static constexpr std::size_t index = std::is_convertible<T, First>::value
+        ? sizeof...(Types) : convertible_type<T, Types...>::index;
+};
+
+template <typename T>
+struct convertible_type<T>
+{
+    static constexpr std::size_t index = invalid_value;
+};
+
+template <typename T, typename...Types>
+struct value_traits
+{
+    static constexpr std::size_t direct_index = direct_type<T, Types...>::index;
+    static constexpr std::size_t index =
+        (direct_index == invalid_value) ? convertible_type<T, Types...>::index : direct_index;
+};
+
+template <typename T, typename...Types>
+struct is_valid_type;
+
+template <typename T, typename First, typename... Types>
+struct is_valid_type<T, First, Types...>
+{
+    static constexpr bool value = std::is_convertible<T, First>::value
+        || is_valid_type<T, Types...>::value;
+};
+
+template <typename T>
+struct is_valid_type<T> : std::false_type {};
+
+template <std::size_t N, typename ... Types>
+struct select_type
+{
+    static_assert(N < sizeof...(Types), "index out of bounds");
+};
+
+template <std::size_t N, typename T, typename ... Types>
+struct select_type<N, T, Types...>
+{
+    using type = typename select_type<N - 1, Types...>::type;
+};
+
+template <typename T, typename ... Types>
+struct select_type<0, T, Types...>
+{
+    using type = T;
+};
+
+} // namespace detail
+
+// static visitor
+template <typename R = void>
+struct static_visitor
+{
+    using result_type = R;
+protected:
+    static_visitor() {}
+    ~static_visitor() {}
+};
+
+
+template <std::size_t arg1, std::size_t ... others>
+struct static_max;
+
+template <std::size_t arg>
+struct static_max<arg>
+{
+    static const std::size_t value = arg;
+};
+
+template <std::size_t arg1, std::size_t arg2, std::size_t ... others>
+struct static_max<arg1, arg2, others...>
+{
+    static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value :
+        static_max<arg2, others...>::value;
+};
+
+template<typename... Types>
+struct variant_helper;
+
+template<typename T, typename... Types>
+struct variant_helper<T, Types...>
+{
+    VARIANT_INLINE static void destroy(const std::size_t id, void * data)
+    {
+        if (id == sizeof...(Types))
+        {
+            reinterpret_cast<T*>(data)->~T();
+        }
+        else
+        {
+            variant_helper<Types...>::destroy(id, data);
+        }
+    }
+
+    VARIANT_INLINE static void move(const std::size_t old_id, void * old_value, void * new_value)
+    {
+        if (old_id == sizeof...(Types))
+        {
+            new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
+            //std::memcpy(new_value, old_value, sizeof(T));
+            // ^^  DANGER: this should only be considered for relocatable types e.g built-in types
+            // Also, I don't see any measurable performance benefit just yet
+        }
+        else
+        {
+            variant_helper<Types...>::move(old_id, old_value, new_value);
+        }
+    }
+
+    VARIANT_INLINE static void copy(const std::size_t old_id, const void * old_value, void * new_value)
+    {
+        if (old_id == sizeof...(Types))
+        {
+            new (new_value) T(*reinterpret_cast<const T*>(old_value));
+        }
+        else
+        {
+            variant_helper<Types...>::copy(old_id, old_value, new_value);
+        }
+    }
+};
+
+template<> struct variant_helper<>
+{
+    VARIANT_INLINE static void destroy(const std::size_t, void *) {}
+    VARIANT_INLINE static void move(const std::size_t, void *, void *) {}
+    VARIANT_INLINE static void copy(const std::size_t, const void *, void *) {}
+};
+
+namespace detail {
+
+template <typename T>
+struct unwrapper
+{
+    T const& operator() (T const& obj) const
+    {
+        return obj;
+    }
+
+    T& operator() (T & obj) const
+    {
+        return obj;
+    }
+};
+
+
+template <typename T>
+struct unwrapper<recursive_wrapper<T>>
+{
+    auto operator() (recursive_wrapper<T> const& obj) const
+        -> typename recursive_wrapper<T>::type const&
+    {
+        return obj.get();
+    }
+};
+
+
+template <typename F, typename V, typename...Types>
+struct dispatcher;
+
+template <typename F, typename V, typename T, typename...Types>
+struct dispatcher<F, V, T, Types...>
+{
+    using result_type = typename F::result_type;
+    VARIANT_INLINE static result_type apply_const(V const& v, F f)
+    {
+        if (v.get_type_index() == sizeof...(Types))
+        {
+            return f(unwrapper<T>()(v. template get<T>()));
+        }
+        else
+        {
+            return dispatcher<F, V, Types...>::apply_const(v, f);
+        }
+    }
+
+    VARIANT_INLINE static result_type apply(V & v, F f)
+    {
+        if (v.get_type_index() == sizeof...(Types))
+        {
+            return f(unwrapper<T>()(v. template get<T>()));
+        }
+        else
+        {
+            return dispatcher<F, V, Types...>::apply(v, f);
+        }
+    }
+};
+
+template<typename F, typename V>
+struct dispatcher<F, V>
+{
+    using result_type = typename F::result_type;
+    VARIANT_INLINE static result_type apply_const(V const&, F)
+    {
+        throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
+    }
+
+    VARIANT_INLINE static result_type apply(V &, F)
+    {
+        throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
+    }
+};
+
+
+template <typename F, typename V, typename T, typename...Types>
+struct binary_dispatcher_rhs;
+
+template <typename F, typename V, typename T0, typename T1, typename...Types>
+struct binary_dispatcher_rhs<F, V, T0, T1, Types...>
+{
+    using result_type = typename F::result_type;
+    VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
+    {
+        if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
+        {
+            return f(unwrapper<T0>()(lhs. template get<T0>()),
+                     unwrapper<T1>()(rhs. template get<T1>()));
+        }
+        else
+        {
+            return binary_dispatcher_rhs<F, V, T0, Types...>::apply_const(lhs, rhs, f);
+        }
+    }
+
+    VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f)
+    {
+        if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
+        {
+            return f(unwrapper<T0>()(lhs. template get<T0>()),
+                     unwrapper<T1>()(rhs. template get<T1>()));
+        }
+        else
+        {
+            return binary_dispatcher_rhs<F, V, T0, Types...>::apply(lhs, rhs, f);
+        }
+    }
+
+};
+
+template<typename F, typename V, typename T>
+struct binary_dispatcher_rhs<F, V, T>
+{
+    using result_type = typename F::result_type;
+    VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
+    {
+        throw std::runtime_error("binary dispatch: FAIL");
+    }
+    VARIANT_INLINE static result_type apply(V &, V &, F)
+    {
+        throw std::runtime_error("binary dispatch: FAIL");
+    }
+};
+
+
+template <typename F, typename V, typename T, typename...Types>
+struct binary_dispatcher_lhs;
+
+template <typename F, typename V, typename T0, typename T1, typename...Types>
+struct binary_dispatcher_lhs<F, V, T0, T1, Types...>
+{
+    using result_type = typename F::result_type;
+    VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
+    {
+        if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
+        {
+            return f(lhs. template get<T1>(), rhs. template get<T0>());
+        }
+        else
+        {
+            return binary_dispatcher_lhs<F, V, T0, Types...>::apply_const(lhs, rhs, f);
+        }
+    }
+
+    VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f)
+    {
+        if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
+        {
+            return f(lhs. template get<T1>(), rhs. template get<T0>());
+        }
+        else
+        {
+            return binary_dispatcher_lhs<F, V, T0, Types...>::apply(lhs, rhs, f);
+        }
+    }
+
+};
+
+template<typename F, typename V, typename T>
+struct binary_dispatcher_lhs<F, V, T>
+{
+    using result_type = typename F::result_type;
+    VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
+    {
+        throw std::runtime_error("binary dispatch: FAIL");
+    }
+
+    VARIANT_INLINE static result_type apply(V &, V &, F)
+    {
+        throw std::runtime_error("binary dispatch: FAIL");
+    }
+};
+
+template <typename F, typename V, typename...Types>
+struct binary_dispatcher;
+
+template <typename F, typename V, typename T, typename...Types>
+struct binary_dispatcher<F, V, T, Types...>
+{
+    using result_type = typename F::result_type;
+    VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f)
+    {
+        if (v0.get_type_index() == sizeof...(Types))
+        {
+            if (v0.get_type_index() == v1.get_type_index())
+            {
+                return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
+            }
+            else
+            {
+                return binary_dispatcher_rhs<F, V, T, Types...>::apply_const(v0, v1, f);
+            }
+        }
+        else if (v1.get_type_index() == sizeof...(Types))
+        {
+            return binary_dispatcher_lhs<F, V, T, Types...>::apply_const(v0, v1, f);
+        }
+        return binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f);
+    }
+
+    VARIANT_INLINE static result_type apply(V & v0, V & v1, F f)
+    {
+        if (v0.get_type_index() == sizeof...(Types))
+        {
+            if (v0.get_type_index() == v1.get_type_index())
+            {
+                return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
+            }
+            else
+            {
+                return binary_dispatcher_rhs<F, V, T, Types...>::apply(v0, v1, f);
+            }
+        }
+        else if (v1.get_type_index() == sizeof...(Types))
+        {
+            return binary_dispatcher_lhs<F, V, T, Types...>::apply(v0, v1, f);
+        }
+        return binary_dispatcher<F, V, Types...>::apply(v0, v1, f);
+    }
+};
+
+template<typename F, typename V>
+struct binary_dispatcher<F, V>
+{
+    using result_type = typename F::result_type;
+    VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
+    {
+        throw std::runtime_error("binary dispatch: FAIL");
+    }
+
+    VARIANT_INLINE static result_type apply(V &, V &, F)
+    {
+        throw std::runtime_error("binary dispatch: FAIL");
+    }
+};
+
+// comparator functors
+struct equal_comp
+{
+    template <typename T>
+    bool operator()(T const& lhs, T const& rhs) const
+    {
+        return lhs == rhs;
+    }
+};
+
+struct less_comp
+{
+    template <typename T>
+    bool operator()(T const& lhs, T const& rhs) const
+    {
+        return lhs < rhs;
+    }
+};
+
+template <typename Variant, typename Comp>
+class comparer : public static_visitor<bool>
+{
+public:
+    explicit comparer(Variant const& lhs) noexcept
+        : lhs_(lhs) {}
+    comparer& operator=(comparer const&) = delete;
+    // visitor
+    template<typename T>
+    bool operator()(T const& rhs_content) const
+    {
+        T const& lhs_content = lhs_.template get<T>();
+        return Comp()(lhs_content, rhs_content);
+    }
+private:
+    Variant const& lhs_;
+};
+
+// operator<< helper
+template <typename Out>
+class printer : public static_visitor<>
+{
+public:
+    explicit printer(Out & out)
+        : out_(out) {}
+    printer& operator=(printer const&) = delete;
+
+// visitor
+    template <typename T>
+    void operator()(T const& operand) const
+    {
+        out_ << operand;
+    }
+private:
+    Out & out_;
+};
+
+} // namespace detail
+
+struct no_init {};
+
+template<typename... Types>
+class variant
+{
+private:
+
+    static const std::size_t data_size = static_max<sizeof(Types)...>::value;
+    static const std::size_t data_align = static_max<alignof(Types)...>::value;
+
+    using data_type = typename std::aligned_storage<data_size, data_align>::type;
+    using helper_type = variant_helper<Types...>;
+
+    std::size_t type_index;
+    data_type data;
+
+public:
+
+
+    VARIANT_INLINE variant()
+        : type_index(sizeof...(Types) - 1)
+    {
+        new (&data) typename detail::select_type<0, Types...>::type();
+    }
+
+    VARIANT_INLINE variant(no_init)
+        : type_index(detail::invalid_value) {}
+
+    // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
+    template <typename T, class = typename std::enable_if<
+                          detail::is_valid_type<typename std::remove_reference<T>::type, Types...>::value>::type>
+    VARIANT_INLINE variant(T && val) noexcept
+        : type_index(detail::value_traits<typename std::remove_reference<T>::type, Types...>::index)
+    {
+        constexpr std::size_t index = sizeof...(Types) - detail::value_traits<typename std::remove_reference<T>::type, Types...>::index - 1;
+        using target_type = typename detail::select_type<index, Types...>::type;
+        new (&data) target_type(std::forward<T>(val)); // nothrow
+    }
+
+    VARIANT_INLINE variant(variant<Types...> const& old)
+        : type_index(old.type_index)
+    {
+        helper_type::copy(old.type_index, &old.data, &data);
+    }
+
+    VARIANT_INLINE variant(variant<Types...>&& old) noexcept
+        : type_index(old.type_index)
+    {
+        helper_type::move(old.type_index, &old.data, &data);
+    }
+
+    friend void swap(variant<Types...> & first, variant<Types...> & second)
+    {
+        using std::swap; //enable ADL
+        swap(first.type_index, second.type_index);
+        swap(first.data, second.data);
+    }
+
+    VARIANT_INLINE variant<Types...>& operator=(variant<Types...> other)
+    {
+        swap(*this, other);
+        return *this;
+    }
+
+    // conversions
+    // move-assign
+    template <typename T>
+    VARIANT_INLINE variant<Types...>& operator=(T && rhs) noexcept
+    {
+        variant<Types...> temp(std::forward<T>(rhs));
+        swap(*this, temp);
+        return *this;
+    }
+
+    // copy-assign
+    template <typename T>
+    VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
+    {
+        variant<Types...> temp(rhs);
+        swap(*this, temp);
+        return *this;
+    }
+
+    template<typename T>
+    VARIANT_INLINE bool is() const
+    {
+        return (type_index == detail::direct_type<T, Types...>::index);
+    }
+
+    VARIANT_INLINE bool valid() const
+    {
+        return (type_index != detail::invalid_value);
+    }
+
+    template<typename T, typename... Args>
+    VARIANT_INLINE void set(Args&&... args)
+    {
+        helper_type::destroy(type_index, &data);
+        new (&data) T(std::forward<Args>(args)...);
+        type_index = detail::direct_type<T, Types...>::index;
+    }
+
+    template<typename T>
+    VARIANT_INLINE T& get()
+    {
+        if (type_index == detail::direct_type<T, Types...>::index)
+        {
+            return *reinterpret_cast<T*>(&data);
+        }
+        else
+        {
+            throw std::runtime_error("in get()");
+        }
+    }
+
+    template<typename T>
+    VARIANT_INLINE T const& get() const
+    {
+        if (type_index == detail::direct_type<T, Types...>::index)
+        {
+            return *reinterpret_cast<T const*>(&data);
+        }
+        else
+        {
+            throw std::runtime_error("in get()");
+        }
+    }
+
+    VARIANT_INLINE std::size_t get_type_index() const
+    {
+        return type_index;
+    }
+
+    // visitor
+    // unary
+    template <typename F, typename V>
+    auto VARIANT_INLINE
+    static visit(V const& v, F f)
+        -> decltype(detail::dispatcher<F, V, Types...>::apply_const(v, f))
+    {
+        return detail::dispatcher<F, V, Types...>::apply_const(v, f);
+    }
+    // non-const
+    template <typename F, typename V>
+    auto VARIANT_INLINE
+    static visit(V & v, F f)
+        -> decltype(detail::dispatcher<F, V, Types...>::apply(v, f))
+    {
+        return detail::dispatcher<F, V, Types...>::apply(v, f);
+    }
+
+    // binary
+    // const
+    template <typename F, typename V>
+    auto VARIANT_INLINE
+    static binary_visit(V const& v0, V const& v1, F f)
+        -> decltype(detail::binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f))
+    {
+        return detail::binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f);
+    }
+    // non-const
+    template <typename F, typename V>
+    auto VARIANT_INLINE
+    static binary_visit(V& v0, V& v1, F f)
+        -> decltype(detail::binary_dispatcher<F, V, Types...>::apply(v0, v1, f))
+    {
+        return detail::binary_dispatcher<F, V, Types...>::apply(v0, v1, f);
+    }
+
+    ~variant() noexcept
+    {
+        helper_type::destroy(type_index, &data);
+    }
+
+    // comparison operators
+    // equality
+    VARIANT_INLINE bool operator==(variant const& rhs) const
+    {
+        if (this->get_type_index() != rhs.get_type_index())
+            return false;
+        detail::comparer<variant, detail::equal_comp> visitor(*this);
+        return visit(rhs, visitor);
+    }
+    // less than
+    VARIANT_INLINE bool operator<(variant const& rhs) const
+    {
+        if (this->get_type_index() != rhs.get_type_index())
+        {
+            return this->get_type_index() < rhs.get_type_index();
+            // ^^ borrowed from boost::variant
+        }
+        detail::comparer<variant, detail::less_comp> visitor(*this);
+        return visit(rhs, visitor);
+    }
+};
+
+// unary visitor interface
+
+// const
+template <typename V, typename F>
+auto VARIANT_INLINE static apply_visitor(F f, V const& v) -> decltype(V::visit(v, f))
+{
+    return V::visit(v, f);
+}
+// non-const
+template <typename V, typename F>
+auto VARIANT_INLINE static apply_visitor(F f, V & v) -> decltype(V::visit(v, f))
+{
+    return V::visit(v, f);
+}
+
+// binary visitor interface
+// const
+template <typename V, typename F>
+auto VARIANT_INLINE static apply_visitor(F f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, f))
+{
+    return V::binary_visit(v0, v1, f);
+}
+// non-const
+template <typename V, typename F>
+auto VARIANT_INLINE static apply_visitor(F f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, f))
+{
+    return V::binary_visit(v0, v1, f);
+}
+
+// getter interface
+template<typename ResultType, typename T>
+ResultType &  get(T & var)
+{
+    return var.template get<ResultType>();
+}
+
+template<typename ResultType, typename T>
+ResultType const&  get(T const& var)
+{
+    return var.template get<ResultType>();
+}
+
+
+// operator<<
+template <typename charT, typename traits, typename... Types>
+VARIANT_INLINE std::basic_ostream<charT, traits>&
+operator<< (std::basic_ostream<charT, traits>& out, variant<Types...> const& rhs)
+{
+    detail::printer<std::basic_ostream<charT, traits>> visitor(out);
+    apply_visitor(visitor, rhs);
+    return out;
+}
+
+}}
+
+#endif  // MAPBOX_UTIL_VARIANT_HPP
diff --git a/Tools/.gitignore b/tools/.gitignore
similarity index 100%
rename from Tools/.gitignore
rename to tools/.gitignore
diff --git a/tools/check-hsgr.cpp b/tools/check-hsgr.cpp
new file mode 100644
index 0000000..9173dc4
--- /dev/null
+++ b/tools/check-hsgr.cpp
@@ -0,0 +1,112 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+#include "../data_structures/percent.hpp"
+#include "../data_structures/query_edge.hpp"
+#include "../data_structures/static_graph.hpp"
+#include "../Util/integer_range.hpp"
+#include "../Util/graph_loader.hpp"
+#include "../Util/simple_logger.hpp"
+#include "../Util/osrm_exception.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/filesystem.hpp>
+
+#include <memory>
+#include <vector>
+
+using EdgeData = QueryEdge::EdgeData;
+using QueryGraph = StaticGraph<EdgeData>;
+
+int main(int argc, char *argv[])
+{
+    LogPolicy::GetInstance().Unmute();
+    try
+    {
+        if (argc != 2)
+        {
+            SimpleLogger().Write(logWARNING) << "usage: " << argv[0] << " <file.hsgr>";
+            return 1;
+        }
+
+        boost::filesystem::path hsgr_path(argv[1]);
+
+        std::vector<QueryGraph::NodeArrayEntry> node_list;
+        std::vector<QueryGraph::EdgeArrayEntry> edge_list;
+        SimpleLogger().Write() << "loading graph from " << hsgr_path.string();
+
+        unsigned m_check_sum = 0;
+        unsigned m_number_of_nodes =
+            readHSGRFromStream(hsgr_path, node_list, edge_list, &m_check_sum);
+        SimpleLogger().Write() << "expecting " << m_number_of_nodes
+                               << " nodes, checksum: " << m_check_sum;
+        BOOST_ASSERT_MSG(0 != node_list.size(), "node list empty");
+        SimpleLogger().Write() << "loaded " << node_list.size() << " nodes and " << edge_list.size()
+                               << " edges";
+        auto m_query_graph = std::make_shared<QueryGraph>(node_list, edge_list);
+
+        BOOST_ASSERT_MSG(0 == node_list.size(), "node list not flushed");
+        BOOST_ASSERT_MSG(0 == edge_list.size(), "edge list not flushed");
+
+        Percent progress(m_query_graph->GetNumberOfNodes());
+        for (const auto node_u : osrm::irange(0u, m_query_graph->GetNumberOfNodes()))
+        {
+            for (const auto eid : m_query_graph->GetAdjacentEdgeRange(node_u))
+            {
+                const EdgeData &data = m_query_graph->GetEdgeData(eid);
+                if (!data.shortcut)
+                {
+                    continue;
+                }
+                const unsigned node_v = m_query_graph->GetTarget(eid);
+                const EdgeID edge_id_1 = m_query_graph->FindEdgeInEitherDirection(node_u, data.id);
+                if (SPECIAL_EDGEID == edge_id_1)
+                {
+                    throw osrm::exception("cannot find first segment of edge (" +
+                                        std::to_string(node_u) + "," + std::to_string(data.id) +
+                                        "," + std::to_string(node_v) + "), eid: " +
+                                        std::to_string(eid));
+                }
+                const EdgeID edge_id_2 = m_query_graph->FindEdgeInEitherDirection(data.id, node_v);
+                if (SPECIAL_EDGEID == edge_id_2)
+                {
+                    throw osrm::exception("cannot find second segment of edge (" +
+                                        std::to_string(node_u) + "," + std::to_string(data.id) +
+                                        "," + std::to_string(node_v) + "), eid: " +
+                                        std::to_string(eid));
+                }
+            }
+            progress.printStatus(node_u);
+        }
+        m_query_graph.reset();
+        SimpleLogger().Write() << "Data file " << argv[0] << " appears to be OK";
+    }
+    catch (const std::exception &e)
+    {
+        SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+    }
+    return 0;
+}
diff --git a/tools/components.cpp b/tools/components.cpp
new file mode 100644
index 0000000..607d86b
--- /dev/null
+++ b/tools/components.cpp
@@ -0,0 +1,293 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "../typedefs.h"
+#include "../algorithms/tiny_components.hpp"
+#include "../data_structures/dynamic_graph.hpp"
+#include "../Util/graph_loader.hpp"
+#include "../Util/make_unique.hpp"
+#include "../Util/osrm_exception.hpp"
+#include "../Util/simple_logger.hpp"
+#include "../Util/FingerPrint.h"
+
+#include <boost/filesystem.hpp>
+
+#if defined(__APPLE__) || defined (_WIN32)
+#include <gdal.h>
+#include <ogrsf_frmts.h>
+#else
+#include <gdal/gdal.h>
+#include <gdal/ogrsf_frmts.h>
+#endif
+
+#include <osrm/Coordinate.h>
+
+#include <fstream>
+#include <memory>
+#include <string>
+#include <vector>
+
+std::vector<QueryNode> coordinate_list;
+std::vector<TurnRestriction> restriction_list;
+std::vector<NodeID> bollard_node_list;
+std::vector<NodeID> traffic_lights_list;
+
+struct TarjanEdgeData
+{
+    TarjanEdgeData() : distance(INVALID_EDGE_WEIGHT), name_id(INVALID_NAMEID) {}
+    TarjanEdgeData(int distance, unsigned name_id) : distance(distance), name_id(name_id) {}
+    int distance;
+    unsigned name_id;
+};
+
+using TarjanDynamicGraph = DynamicGraph<TarjanEdgeData>;
+using TarjanEdge = TarjanDynamicGraph::InputEdge;
+
+void DeleteFileIfExists(const std::string &file_name)
+{
+    if (boost::filesystem::exists(file_name))
+    {
+        boost::filesystem::remove(file_name);
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    LogPolicy::GetInstance().Unmute();
+    try
+    {
+        // enable logging
+        if (argc < 3)
+        {
+            SimpleLogger().Write(logWARNING) << "usage:\n" << argv[0]
+                                             << " <osrm> <osrm.restrictions>";
+            return -1;
+        }
+
+        SimpleLogger().Write() << "Using restrictions from file: " << argv[2];
+        std::ifstream restriction_ifstream(argv[2], std::ios::binary);
+        const FingerPrint fingerprint_orig;
+        FingerPrint fingerprint_loaded;
+        restriction_ifstream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
+
+        // check fingerprint and warn if necessary
+        if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
+        {
+            SimpleLogger().Write(logWARNING) << argv[2] << " was prepared with a different build. "
+                                                           "Reprocess to get rid of this warning.";
+        }
+
+        if (!restriction_ifstream.good())
+        {
+            throw osrm::exception("Could not access <osrm-restrictions> files");
+        }
+        uint32_t usable_restrictions = 0;
+        restriction_ifstream.read((char *)&usable_restrictions, sizeof(uint32_t));
+        restriction_list.resize(usable_restrictions);
+
+        // load restrictions
+        if (usable_restrictions > 0)
+        {
+            restriction_ifstream.read((char *)&(restriction_list[0]),
+                                      usable_restrictions * sizeof(TurnRestriction));
+        }
+        restriction_ifstream.close();
+
+        std::ifstream input_stream(argv[1], std::ifstream::in | std::ifstream::binary);
+        if (!input_stream.is_open())
+        {
+            throw osrm::exception("Cannot open osrm file");
+        }
+
+        // load graph data
+        std::vector<ImportEdge> edge_list;
+        const NodeID number_of_nodes = readBinaryOSRMGraphFromStream(input_stream,
+                                                                     edge_list,
+                                                                     bollard_node_list,
+                                                                     traffic_lights_list,
+                                                                     &coordinate_list,
+                                                                     restriction_list);
+        input_stream.close();
+
+
+        BOOST_ASSERT_MSG(restriction_list.size() == usable_restrictions,
+                         "size of restriction_list changed");
+
+        SimpleLogger().Write() << restriction_list.size() << " restrictions, "
+                               << bollard_node_list.size() << " bollard nodes, "
+                               << traffic_lights_list.size() << " traffic lights";
+
+        traffic_lights_list.clear();
+        traffic_lights_list.shrink_to_fit();
+
+        // Building an node-based graph
+        DeallocatingVector<TarjanEdge> graph_edge_list;
+        for (const NodeBasedEdge &input_edge : edge_list)
+        {
+            if (input_edge.source == input_edge.target)
+            {
+                continue;
+            }
+
+            if (input_edge.forward)
+            {
+                graph_edge_list.emplace_back(input_edge.source,
+                                       input_edge.target,
+                                       (std::max)((int)input_edge.weight, 1),
+                                       input_edge.name_id);
+            }
+            if (input_edge.backward)
+            {
+                graph_edge_list.emplace_back(input_edge.target,
+                                       input_edge.source,
+                                       (std::max)((int)input_edge.weight, 1),
+                                       input_edge.name_id);
+            }
+        }
+        edge_list.clear();
+        edge_list.shrink_to_fit();
+        BOOST_ASSERT_MSG(0 == edge_list.size() && 0 == edge_list.capacity(),
+                         "input edge vector not properly deallocated");
+
+        tbb::parallel_sort(graph_edge_list.begin(), graph_edge_list.end());
+        auto graph = std::make_shared<TarjanDynamicGraph>(number_of_nodes, graph_edge_list);
+        edge_list.clear();
+        edge_list.shrink_to_fit();
+
+        SimpleLogger().Write() << "Starting SCC graph traversal";
+
+        RestrictionMap restriction_map(restriction_list);
+        auto tarjan = osrm::make_unique<TarjanSCC<TarjanDynamicGraph>>(graph,
+                                                                       restriction_map,
+                                                                       bollard_node_list);
+        tarjan->run();
+        SimpleLogger().Write() << "identified: " << tarjan->get_number_of_components()
+                           << " many components";
+        SimpleLogger().Write() << "identified " << tarjan->get_size_one_count() << " SCCs of size 1";
+
+        // output
+        TIMER_START(SCC_RUN_SETUP);
+
+        // remove files from previous run if exist
+        DeleteFileIfExists("component.dbf");
+        DeleteFileIfExists("component.shx");
+        DeleteFileIfExists("component.shp");
+
+        Percent p(graph->GetNumberOfNodes());
+
+        OGRRegisterAll();
+
+        const char *pszDriverName = "ESRI Shapefile";
+        OGRSFDriver *poDriver =
+            OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(pszDriverName);
+        if (nullptr == poDriver)
+        {
+            throw osrm::exception("ESRI Shapefile driver not available");
+        }
+        OGRDataSource *poDS = poDriver->CreateDataSource("component.shp", nullptr);
+
+        if (nullptr == poDS)
+        {
+            throw osrm::exception("Creation of output file failed");
+        }
+
+        OGRSpatialReference *poSRS = new OGRSpatialReference();
+        poSRS->importFromEPSG(4326);
+
+        OGRLayer *poLayer = poDS->CreateLayer("component", poSRS, wkbLineString, nullptr);
+
+        if (nullptr == poLayer)
+        {
+            throw osrm::exception("Layer creation failed.");
+        }
+        TIMER_STOP(SCC_RUN_SETUP);
+        SimpleLogger().Write() << "shapefile setup took " << TIMER_MSEC(SCC_RUN_SETUP)/1000. << "s";
+
+        uint64_t total_network_distance = 0;
+        p.reinit(graph->GetNumberOfNodes());
+        TIMER_START(SCC_OUTPUT);
+        for (const NodeID source : osrm::irange(0u, graph->GetNumberOfNodes()))
+        {
+            p.printIncrement();
+            for (const auto current_edge : graph->GetAdjacentEdgeRange(source))
+            {
+                const TarjanDynamicGraph::NodeIterator target = graph->GetTarget(current_edge);
+
+                if (source < target || graph->EndEdges(target) == graph->FindEdge(target, source))
+                {
+                    total_network_distance +=
+                        100 * FixedPointCoordinate::ApproximateEuclideanDistance(
+                                  coordinate_list[source].lat,
+                                  coordinate_list[source].lon,
+                                  coordinate_list[target].lat,
+                                  coordinate_list[target].lon);
+
+                    BOOST_ASSERT(current_edge != SPECIAL_EDGEID);
+                    BOOST_ASSERT(source != SPECIAL_NODEID);
+                    BOOST_ASSERT(target != SPECIAL_NODEID);
+
+                    const unsigned size_of_containing_component =
+                        std::min(tarjan->get_component_size(source),
+                                 tarjan->get_component_size(target));
+
+                    // edges that end on bollard nodes may actually be in two distinct components
+                    if (size_of_containing_component < 1000)
+                    {
+                        OGRLineString lineString;
+                        lineString.addPoint(coordinate_list[source].lon / COORDINATE_PRECISION,
+                                            coordinate_list[source].lat / COORDINATE_PRECISION);
+                        lineString.addPoint(coordinate_list[target].lon / COORDINATE_PRECISION,
+                                            coordinate_list[target].lat / COORDINATE_PRECISION);
+
+                        OGRFeature *poFeature = OGRFeature::CreateFeature(poLayer->GetLayerDefn());
+
+                        poFeature->SetGeometry(&lineString);
+                        if (OGRERR_NONE != poLayer->CreateFeature(poFeature))
+                        {
+                            throw osrm::exception("Failed to create feature in shapefile.");
+                        }
+                        OGRFeature::DestroyFeature(poFeature);
+                    }
+                }
+            }
+        }
+        OGRSpatialReference::DestroySpatialReference(poSRS);
+        OGRDataSource::DestroyDataSource(poDS);
+        TIMER_STOP(SCC_OUTPUT);
+        SimpleLogger().Write() << "generating output took: " << TIMER_MSEC(SCC_OUTPUT)/1000. << "s";
+
+        SimpleLogger().Write() << "total network distance: "
+                               << (uint64_t)total_network_distance / 100 / 1000. << " km";
+
+        SimpleLogger().Write() << "finished component analysis";
+    }
+    catch (const std::exception &e)
+    {
+        SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+    }
+    return 0;
+}
diff --git a/Tools/io-benchmark.cpp b/tools/io-benchmark.cpp
similarity index 80%
rename from Tools/io-benchmark.cpp
rename to tools/io-benchmark.cpp
index 6304aae..c6da3ad 100644
--- a/Tools/io-benchmark.cpp
+++ b/tools/io-benchmark.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,17 +25,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "../Util/GitDescription.h"
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/TimingUtil.h"
+#include "../Util/git_sha.hpp"
+#include "../Util/osrm_exception.hpp"
+#include "../Util/simple_logger.hpp"
+#include "../Util/timing_util.hpp"
 
 #include <boost/filesystem.hpp>
 #include <boost/filesystem/fstream.hpp>
 
 #include <cmath>
 #include <cstdio>
-#include <cstdlib>
 #include <fcntl.h>
 #ifdef __linux__
 #include <malloc.h>
@@ -45,6 +44,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <chrono>
 #include <iomanip>
 #include <numeric>
+#include <random>
 #include <vector>
 
 const unsigned number_of_elements = 268435456;
@@ -70,40 +70,39 @@ void RunStatistics(std::vector<double> &timings_vector, Statistics &stats)
 
 int main(int argc, char *argv[])
 {
-    LogPolicy::GetInstance().Unmute();
-
-    SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION << ", "
-                           << "compiled at " << __DATE__ << ", " __TIME__;
 
 #ifdef __FreeBSD__
-    SimpleLogger().Write() << "Not supported on FreeBSD";
-    return 0;
+        SimpleLogger().Write() << "Not supported on FreeBSD";
+        return 0;
 #endif
-#ifdef WIN32
-    SimpleLogger().Write() << "Not supported on Windows";
-    return 0;
+#ifdef _WIN32
+        SimpleLogger().Write() << "Not supported on Windows";
+        return 0;
 #else
 
-
-    if (1 == argc)
+    LogPolicy::GetInstance().Unmute();
+    boost::filesystem::path test_path;
+    try
     {
-        SimpleLogger().Write(logWARNING) << "usage: " << argv[0] << " /path/on/device";
-        return -1;
-    }
+        SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION;
 
-    boost::filesystem::path test_path = boost::filesystem::path(argv[1]);
-    test_path /= "osrm.tst";
-    SimpleLogger().Write(logDEBUG) << "temporary file: " << test_path.string();
+        if (1 == argc)
+        {
+            SimpleLogger().Write(logWARNING) << "usage: " << argv[0] << " /path/on/device";
+            return -1;
+        }
+
+        test_path = boost::filesystem::path(argv[1]);
+        test_path /= "osrm.tst";
+        SimpleLogger().Write(logDEBUG) << "temporary file: " << test_path.string();
 
-    try
-    {
         // create files for testing
         if (2 == argc)
         {
             // create file to test
             if (boost::filesystem::exists(test_path))
             {
-                throw OSRMException("Data file already exists");
+                throw osrm::exception("Data file already exists");
             }
 
             int *random_array = new int[number_of_elements];
@@ -118,27 +117,26 @@ int main(int argc, char *argv[])
             fclose(fd);
 #endif
 #ifdef __linux__
-            int f =
+            int file_desc =
                 open(test_path.string().c_str(), O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, S_IRWXU);
-            if (-1 == f)
+            if (-1 == file_desc)
             {
-                throw OSRMException("Could not open random data file");
+                throw osrm::exception("Could not open random data file");
             }
             TIMER_START(write_1gb);
-            int ret = write(f, random_array, number_of_elements * sizeof(unsigned));
+            int ret = write(file_desc, random_array, number_of_elements * sizeof(unsigned));
             if (0 > ret)
             {
-                throw OSRMException("could not write random data file");
+                throw osrm::exception("could not write random data file");
             }
             TIMER_STOP(write_1gb);
-            close(f);
+            close(file_desc);
 #endif
             delete[] random_array;
             SimpleLogger().Write(logDEBUG) << "writing raw 1GB took " << TIMER_SEC(write_1gb)
                                            << "s";
             SimpleLogger().Write() << "raw write performance: " << std::setprecision(5)
-                                   << std::fixed << 1024 * 1024 / TIMER_SEC(write_1gb)
-                                   << "MB/sec";
+                                   << std::fixed << 1024 * 1024 / TIMER_SEC(write_1gb) << "MB/sec";
 
             SimpleLogger().Write(logDEBUG)
                 << "finished creation of random data. Flush disk cache now!";
@@ -148,7 +146,7 @@ int main(int argc, char *argv[])
             // Run Non-Cached I/O benchmarks
             if (!boost::filesystem::exists(test_path))
             {
-                throw OSRMException("data file does not exist");
+                throw osrm::exception("data file does not exist");
             }
 
             // volatiles do not get optimized
@@ -164,8 +162,8 @@ int main(int argc, char *argv[])
 #ifdef __linux__
             char *single_block = (char *)memalign(512, 1024 * sizeof(unsigned));
 
-            int f = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
-            if (-1 == f)
+            int file_desc = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
+            if (-1 == file_desc)
             {
                 SimpleLogger().Write(logDEBUG) << "opened, error: " << strerror(errno);
                 return -1;
@@ -179,17 +177,16 @@ int main(int argc, char *argv[])
             fd = fopen(test_path.string().c_str(), "r");
 #endif
 #ifdef __linux__
-            int ret = read(f, raw_array, number_of_elements * sizeof(unsigned));
+            int ret = read(file_desc, raw_array, number_of_elements * sizeof(unsigned));
             SimpleLogger().Write(logDEBUG) << "read " << ret
                                            << " bytes, error: " << strerror(errno);
-            close(f);
-            f = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
+            close(file_desc);
+            file_desc = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
             SimpleLogger().Write(logDEBUG) << "opened, error: " << strerror(errno);
 #endif
             TIMER_STOP(read_1gb);
 
-            SimpleLogger().Write(logDEBUG) << "reading raw 1GB took " << TIMER_SEC(read_1gb)
-                                           << "s";
+            SimpleLogger().Write(logDEBUG) << "reading raw 1GB took " << TIMER_SEC(read_1gb) << "s";
             SimpleLogger().Write() << "raw read performance: " << std::setprecision(5) << std::fixed
                                    << 1024 * 1024 / TIMER_SEC(read_1gb) << "MB/sec";
 
@@ -200,13 +197,16 @@ int main(int argc, char *argv[])
             fseek(fd, 0, SEEK_SET);
 #endif
 #ifdef __linux__
-            lseek(f, 0, SEEK_SET);
+            lseek(file_desc, 0, SEEK_SET);
 #endif
             // make 1000 random access, time each I/O seperately
             unsigned number_of_blocks = (number_of_elements * sizeof(unsigned) - 1) / 4096;
+            std::random_device rd;
+            std::default_random_engine e1(rd());
+            std::uniform_int_distribution<unsigned> uniform_dist(0, number_of_blocks - 1);
             for (unsigned i = 0; i < 1000; ++i)
             {
-                unsigned block_to_read = std::rand() % number_of_blocks;
+                unsigned block_to_read =uniform_dist(e1);
                 off_t current_offset = block_to_read * 4096;
                 TIMER_START(random_access);
 #ifdef __APPLE__
@@ -220,21 +220,21 @@ int main(int argc, char *argv[])
 #endif
 
 #ifdef __linux__
-                int ret1 = lseek(f, current_offset, SEEK_SET);
-                int ret2 = read(f, (char *)single_block, 4096);
+                int ret1 = lseek(file_desc, current_offset, SEEK_SET);
+                int ret2 = read(file_desc, (char *)single_block, 4096);
 #endif
                 TIMER_STOP(random_access);
-                if (((off_t) - 1) == ret1)
+                if (((off_t)-1) == ret1)
                 {
                     SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
                     SimpleLogger().Write(logWARNING) << "seek error " << strerror(errno);
-                    throw OSRMException("seek error");
+                    throw osrm::exception("seek error");
                 }
                 if (-1 == ret2)
                 {
                     SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
                     SimpleLogger().Write(logWARNING) << "read error " << strerror(errno);
-                    throw OSRMException("read error");
+                    throw osrm::exception("read error");
                 }
                 timing_results_raw_random.push_back(TIMER_SEC(random_access));
             }
@@ -261,7 +261,7 @@ int main(int argc, char *argv[])
             fseek(fd, 0, SEEK_SET);
 #endif
 #ifdef __linux__
-            lseek(f, 0, SEEK_SET);
+            lseek(file_desc, 0, SEEK_SET);
 #endif
 
             // read every 100th block
@@ -280,22 +280,22 @@ int main(int argc, char *argv[])
 #endif
 
 #ifdef __linux__
-                int ret1 = lseek(f, current_offset, SEEK_SET);
+                int ret1 = lseek(file_desc, current_offset, SEEK_SET);
 
-                int ret2 = read(f, (char *)single_block, 4096);
+                int ret2 = read(file_desc, (char *)single_block, 4096);
 #endif
                 TIMER_STOP(read_every_100);
-                if (((off_t) - 1) == ret1)
+                if (((off_t)-1) == ret1)
                 {
                     SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
                     SimpleLogger().Write(logWARNING) << "seek error " << strerror(errno);
-                    throw OSRMException("seek error");
+                    throw osrm::exception("seek error");
                 }
                 if (-1 == ret2)
                 {
                     SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
                     SimpleLogger().Write(logWARNING) << "read error " << strerror(errno);
-                    throw OSRMException("read error");
+                    throw osrm::exception("read error");
                 }
                 timing_results_raw_seq.push_back(TIMER_SEC(read_every_100));
             }
@@ -306,7 +306,7 @@ int main(int argc, char *argv[])
 // free(single_block);
 #endif
 #ifdef __linux__
-            close(f);
+            close(file_desc);
 #endif
             // Do statistics
             SimpleLogger().Write(logDEBUG) << "running sequential I/O statistics";
diff --git a/Tools/simpleclient.cpp b/tools/simpleclient.cpp
similarity index 84%
rename from Tools/simpleclient.cpp
rename to tools/simpleclient.cpp
index 68d4b1d..d9c8217 100644
--- a/Tools/simpleclient.cpp
+++ b/tools/simpleclient.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -26,9 +26,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "../Library/OSRM.h"
-#include "../Util/GitDescription.h"
+#include "../Util/git_sha.hpp"
 #include "../Util/ProgramOptions.h"
-#include "../Util/SimpleLogger.h"
+#include "../Util/simple_logger.hpp"
 
 #include <osrm/Reply.h>
 #include <osrm/RouteParameters.h>
@@ -66,22 +66,24 @@ int main(int argc, const char *argv[])
     {
         std::string ip_address;
         int ip_port, requested_thread_num;
-        bool use_shared_memory = false, trial = false;
+        bool use_shared_memory = false, trial_run = false;
         ServerPaths server_paths;
-        if (!GenerateServerProgramOptions(argc,
-                                          argv,
-                                          server_paths,
-                                          ip_address,
-                                          ip_port,
-                                          requested_thread_num,
-                                          use_shared_memory,
-                                          trial))
+
+        const unsigned init_result = GenerateServerProgramOptions(argc,
+                                                                  argv,
+                                                                  server_paths,
+                                                                  ip_address,
+                                                                  ip_port,
+                                                                  requested_thread_num,
+                                                                  use_shared_memory,
+                                                                  trial_run);
+
+        if (init_result == INIT_FAILED)
         {
             return 0;
         }
 
-        SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION << ", "
-                               << "compiled at " << __DATE__ << ", " __TIME__;
+        SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION;
 
         OSRM routing_machine(server_paths, use_shared_memory);
 
diff --git a/tools/springclean.cpp b/tools/springclean.cpp
new file mode 100644
index 0000000..878940a
--- /dev/null
+++ b/tools/springclean.cpp
@@ -0,0 +1,102 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <cstdio>
+
+#include "../data_structures/shared_memory_factory.hpp"
+#include "../Server/DataStructures/SharedDataType.h"
+#include "../Util/git_sha.hpp"
+#include "../Util/simple_logger.hpp"
+
+void delete_region(const SharedDataType region)
+{
+    if (SharedMemory::RegionExists(region) && !SharedMemory::Remove(region))
+    {
+        const std::string name = [&]
+        {
+            switch (region)
+            {
+            case CURRENT_REGIONS:
+                return "CURRENT_REGIONS";
+            case LAYOUT_1:
+                return "LAYOUT_1";
+            case DATA_1:
+                return "DATA_1";
+            case LAYOUT_2:
+                return "LAYOUT_2";
+            case DATA_2:
+                return "DATA_2";
+            case LAYOUT_NONE:
+                return "LAYOUT_NONE";
+            default: // DATA_NONE:
+                return "DATA_NONE";
+            }
+        }();
+
+        SimpleLogger().Write(logWARNING) << "could not delete shared memory region " << name;
+    }
+}
+
+// find all existing shmem regions and remove them.
+void springclean()
+{
+    SimpleLogger().Write() << "spring-cleaning all shared memory regions";
+    delete_region(DATA_1);
+    delete_region(LAYOUT_1);
+    delete_region(DATA_2);
+    delete_region(LAYOUT_2);
+    delete_region(CURRENT_REGIONS);
+}
+
+int main()
+{
+    LogPolicy::GetInstance().Unmute();
+    try
+    {
+        SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION << "\n\n";
+        SimpleLogger().Write() << "Releasing all locks";
+        SimpleLogger().Write() << "ATTENTION! BE CAREFUL!";
+        SimpleLogger().Write() << "----------------------";
+        SimpleLogger().Write() << "This tool may put osrm-routed into an undefined state!";
+        SimpleLogger().Write() << "Type 'Y' to acknowledge that you know what your are doing.";
+        SimpleLogger().Write() << "\n\nDo you want to purge all shared memory allocated " <<
+                                  "by osrm-datastore? [type 'Y' to confirm]";
+
+        const auto letter = getchar();
+        if (letter != 'Y')
+        {
+            SimpleLogger().Write() << "aborted.";
+            return 0;
+        }
+        springclean();
+    }
+    catch (const std::exception &e)
+    {
+        SimpleLogger().Write(logWARNING) << "[excpetion] " << e.what();
+    }
+    return 0;
+}
diff --git a/Tools/unlock_all_mutexes.cpp b/tools/unlock_all_mutexes.cpp
similarity index 88%
rename from Tools/unlock_all_mutexes.cpp
rename to tools/unlock_all_mutexes.cpp
index 4d4156f..faef736 100644
--- a/Tools/unlock_all_mutexes.cpp
+++ b/tools/unlock_all_mutexes.cpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "../Util/GitDescription.h"
-#include "../Util/SimpleLogger.h"
+#include "../Util/git_sha.hpp"
+#include "../Util/simple_logger.hpp"
 #include "../Server/DataStructures/SharedBarriers.h"
 
 #include <iostream>
@@ -36,8 +36,7 @@ int main()
     LogPolicy::GetInstance().Unmute();
     try
     {
-        SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION << ", "
-                               << "compiled at " << __DATE__ << ", " __TIME__;
+        SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION;
         SimpleLogger().Write() << "Releasing all locks";
         SharedBarriers barrier;
         barrier.pending_update_mutex.unlock();
diff --git a/typedefs.h b/typedefs.h
index ff1d2a1..d1b0a53 100644
--- a/typedefs.h
+++ b/typedefs.h
@@ -32,19 +32,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // Necessary workaround for Windows as VS doesn't implement C99
 #ifdef _MSC_VER
+#define WIN32_LEAN_AND_MEAN
 #ifndef M_PI
 #define M_PI 3.14159265358979323846
 #endif
-#define constexpr const static
 #endif
 
-typedef unsigned int NodeID;
-typedef unsigned int EdgeID;
-typedef int EdgeWeight;
+using NodeID = unsigned int;
+using EdgeID = unsigned int;
+using EdgeWeight = int;
 
-constexpr NodeID SPECIAL_NODEID = std::numeric_limits<unsigned>::max();
-constexpr EdgeID SPECIAL_EDGEID = std::numeric_limits<unsigned>::max();
-constexpr unsigned INVALID_NAMEID = std::numeric_limits<unsigned>::max();
-constexpr EdgeWeight INVALID_EDGE_WEIGHT = std::numeric_limits<int>::max();
+static const NodeID SPECIAL_NODEID = std::numeric_limits<unsigned>::max();
+static const EdgeID SPECIAL_EDGEID = std::numeric_limits<unsigned>::max();
+static const unsigned INVALID_NAMEID = std::numeric_limits<unsigned>::max();
+static const EdgeWeight INVALID_EDGE_WEIGHT = std::numeric_limits<int>::max();
 
 #endif /* TYPEDEFS_H */

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



More information about the Pkg-grass-devel mailing list