[osrm] 02/22: Imported Upstream version 5.0.0~rc1+ds

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Fri Apr 29 22:44:12 UTC 2016


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

sebastic pushed a commit to branch master
in repository osrm.

commit 1d9c10ad08ef3e47f6395fc4ec9300058592a35c
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Fri Apr 29 23:13:06 2016 +0200

    Imported Upstream version 5.0.0~rc1+ds
---
 .cncc.style                                        |    14 +
 .eslintrc                                          |    28 +
 .gitignore                                         |     9 +
 .travis.yml                                        |   139 +-
 CHANGELOG.md                                       |    17 +
 CMakeLists.txt                                     |   332 +-
 Doxyfile.in                                        |     1 +
 Gemfile                                            |     7 -
 Gemfile.lock                                       |    35 -
 LICENCE.TXT                                        |     2 +-
 Rakefile                                           |   190 -
 algorithms/bfs_components.hpp                      |   174 -
 algorithms/coordinate_calculation.cpp              |   273 -
 algorithms/coordinate_calculation.hpp              |    82 -
 algorithms/douglas_peucker.cpp                     |   164 -
 algorithms/douglas_peucker.hpp                     |    81 -
 algorithms/geospatial_query.hpp                    |   180 -
 algorithms/graph_compressor.hpp                    |    62 -
 algorithms/object_encoder.hpp                      |    89 -
 algorithms/polyline_compressor.cpp                 |   128 -
 algorithms/polyline_compressor.hpp                 |    51 -
 algorithms/polyline_formatter.cpp                  |    56 -
 algorithms/route_name_extraction.hpp               |   162 -
 appveyor-build.bat                                 |    50 +-
 appveyor.yml                                       |    11 +-
 benchmarks/static_rtree.cpp                        |   152 -
 build-local.bat                                    |     3 +-
 cmake/CPackDebianConfig.cmake                      |    15 +-
 cmake/FindLua52.cmake                              |     2 +-
 cmake/FindSTXXL.cmake                              |     2 +-
 cmake/FingerPrint-Config.cmake                     |    12 +-
 cmake/cmake_options_script.py                      |    10 +-
 cmake/cmake_uninstall.cmake.in                     |    21 +
 cmake/pkgconfig.in                                 |     6 +-
 cmake/postinst.in                                  |     2 -
 config/cucumber.yml                                |     9 -
 contractor/contractor_options.cpp                  |   142 -
 contractor/processing_chain.cpp                    |   441 -
 contractor/processing_chain.hpp                    |    84 -
 cucumber.js                                        |    11 +
 data_structures/compressed_edge_container.hpp      |    69 -
 data_structures/coordinate.cpp                     |    87 -
 data_structures/edge_based_node.hpp                |   113 -
 data_structures/external_memory_node.cpp           |    66 -
 data_structures/external_memory_node.hpp           |    57 -
 data_structures/fixed_point_number.hpp             |   216 -
 data_structures/hilbert_value.cpp                  |   100 -
 data_structures/hilbert_value.hpp                  |    49 -
 data_structures/import_edge.cpp                    |   113 -
 data_structures/import_edge.hpp                    |   108 -
 data_structures/internal_route_result.hpp          |    87 -
 data_structures/lru_cache.hpp                      |    97 -
 data_structures/matrix_graph_wrapper.hpp           |    70 -
 data_structures/node_based_graph.hpp               |   103 -
 data_structures/node_id.hpp                        |    41 -
 data_structures/original_edge_data.hpp             |    63 -
 data_structures/phantom_node.cpp                   |   105 -
 data_structures/phantom_node.hpp                   |   162 -
 data_structures/query_node.hpp                     |    85 -
 data_structures/rectangle.hpp                      |   203 -
 data_structures/route_parameters.cpp               |   179 -
 data_structures/search_engine.hpp                  |    69 -
 data_structures/search_engine_data.cpp             |    93 -
 data_structures/search_engine_data.hpp             |    61 -
 data_structures/segment_information.hpp            |    80 -
 data_structures/static_kdtree.hpp                  |   260 -
 data_structures/turn_instructions.hpp              |   105 -
 data_structures/upper_bound.hpp                    |    77 -
 data_structures/xor_fast_hash.hpp                  |   115 -
 data_structures/xor_fast_hash_storage.hpp          |   101 -
 descriptors/description_factory.cpp                |   249 -
 descriptors/description_factory.hpp                |    96 -
 descriptors/descriptor_base.hpp                    |    87 -
 descriptors/gpx_descriptor.hpp                     |    94 -
 descriptors/json_descriptor.hpp                    |   403 -
 docker/Dockerfile                                  |     2 -
 example/CMakeLists.txt                             |    33 +
 example/cmake/FindLibOSRM.cmake                    |    65 +
 example/cmake/FindTBB.cmake                        |   283 +
 example/example.cpp                                |    85 +
 extract.cpp                                        |    89 -
 extractor/edge_based_graph_factory.cpp             |   702 --
 extractor/edge_based_graph_factory.hpp             |   142 -
 extractor/extraction_node.hpp                      |    38 -
 extractor/extraction_way.hpp                       |   129 -
 extractor/extractor_options.cpp                    |   230 -
 extractor/first_and_last_segment_of_way.hpp        |    89 -
 extractor/restriction_parser.hpp                   |    77 -
 extractor/scripting_environment.cpp                |   175 -
 extractor/scripting_environment.hpp                |    60 -
 extractor/speed_profile.hpp                        |    16 -
 features/bicycle/area.feature                      |    85 +-
 features/bicycle/bridge.feature                    |    32 +-
 features/bicycle/ferry.feature                     |    22 +-
 features/bicycle/maxspeed.feature                  |     6 +-
 features/bicycle/mode.feature                      |   118 +-
 features/bicycle/names.feature                     |     8 +-
 features/bicycle/oneway.feature                    |    10 +-
 features/bicycle/pushing.feature                   |    46 +-
 features/bicycle/ref.feature                       |    10 +-
 features/bicycle/restrictions.feature              |    94 +-
 features/bicycle/roundabout.feature                |    14 +-
 features/bicycle/stop_area.feature                 |     8 +-
 features/bicycle/turn_penalty.feature              |    16 +-
 features/car/advisory.feature                      |    38 +-
 features/car/bridge.feature                        |    28 +-
 features/car/ferry.feature                         |    38 +-
 features/car/link.feature                          |    30 +-
 features/car/maxspeed.feature                      |    18 +-
 features/car/mode.feature                          |    18 +-
 features/car/names.feature                         |     8 +-
 features/car/oneway.feature                        |    10 +-
 features/car/restrictions.feature                  |   120 +-
 features/car/roundabout.feature                    |    14 +-
 features/car/shuttle_train.feature                 |    20 +-
 features/car/traffic.feature                       |    47 +
 features/foot/area.feature                         |    78 +-
 features/foot/ferry.feature                        |    24 +-
 features/foot/names.feature                        |     8 +-
 features/foot/ref.feature                          |    10 +-
 features/foot/restrictions.feature                 |    94 +-
 features/foot/roundabout.feature                   |    18 +-
 features/guidance/motorway.feature                 |   202 +
 features/guidance/roundabout.feature               |   173 +
 .../options/{prepare => contract}/files.feature    |    15 +-
 .../options/{prepare => contract}/help.feature     |    32 +-
 .../options/{prepare => contract}/invalid.feature  |     6 +-
 .../options/{prepare => contract}/version.feature  |    10 +-
 features/options/extract/help.feature              |     6 -
 features/options/routed/files.feature              |    10 +-
 features/options/routed/help.feature               |    27 -
 features/options/routed/invalid.feature            |     3 +-
 features/raster/weights.feature                    |    65 +-
 features/step_definitions/data.js                  |   273 +
 features/step_definitions/data.rb                  |   192 -
 features/step_definitions/distance_matrix.js       |    81 +
 features/step_definitions/distance_matrix.rb       |    66 -
 features/step_definitions/hooks.js                 |    30 +
 features/step_definitions/matching.js              |   174 +
 features/step_definitions/matching.rb              |   124 -
 features/step_definitions/nearest.js               |    53 +
 features/step_definitions/nearest.rb               |    51 -
 features/step_definitions/options.js               |    69 +
 features/step_definitions/options.rb               |    57 -
 features/step_definitions/requests.js              |    60 +
 features/step_definitions/requests.rb              |    46 -
 features/step_definitions/routability.js           |   120 +
 features/step_definitions/routability.rb           |    78 -
 features/step_definitions/routing.js               |    16 +
 features/step_definitions/routing.rb               |   165 -
 features/step_definitions/timestamp.js             |    13 +
 features/step_definitions/timestamp.rb             |     7 -
 features/step_definitions/trip.js                  |   141 +
 features/step_definitions/trip.rb                  |   121 -
 features/support/build_osm.js                      |   165 +
 features/support/config.js                         |   115 +
 features/support/config.rb                         |    16 -
 features/support/data.js                           |   340 +
 features/support/data.rb                           |   325 -
 features/support/data_classes.js                   |    85 +
 features/support/env.js                            |   125 +
 features/support/env.rb                            |    98 -
 features/support/exception_classes.js              |   132 +
 features/support/exceptions.js                     |    15 +
 features/support/exceptions.rb                     |    62 -
 features/support/file.rb                           |    34 -
 features/support/fuzzy.js                          |     5 +
 features/support/fuzzy.rb                          |    32 -
 features/support/hash.js                           |    37 +
 features/support/hash.rb                           |    63 -
 features/support/hooks.js                          |    37 +
 features/support/hooks.rb                          |    35 -
 features/support/http.js                           |    51 +
 features/support/http.rb                           |    37 -
 features/support/launch.js                         |     5 +
 features/support/launch.rb                         |   137 -
 features/support/launch_classes.js                 |   163 +
 features/support/log.js                            |    90 +
 features/support/log.rb                            |    88 -
 features/support/osm_parser.rb                     |    25 -
 features/support/osmlib.rb                         |    14 -
 features/support/route.js                          |   166 +
 features/support/route.rb                          |   181 -
 features/support/run.js                            |    40 +
 features/support/run.rb                            |    28 -
 features/support/shared_steps.js                   |   202 +
 features/support/shortcuts.rb                      |     3 -
 features/support/table_patch.js                    |    11 +
 features/testbot/64bit.feature                     |     4 +-
 features/testbot/alternative.feature               |    16 +-
 features/testbot/alternative_loop.feature          |    29 +
 features/testbot/bad.feature                       |     8 +-
 features/testbot/basic.feature                     |   170 +-
 features/testbot/bearing.feature                   |   150 +-
 features/testbot/bearing_param.feature             |    44 +-
 features/testbot/compression.feature               |     6 +-
 features/testbot/datastore.feature                 |     8 +-
 features/testbot/distance.feature                  |   136 +-
 features/testbot/distance_matrix.feature           |   100 +-
 features/testbot/duration.feature                  |    18 +-
 features/testbot/example.feature                   |    30 +-
 features/testbot/fastest.feature                   |    12 +-
 features/testbot/ferry.feature                     |    76 +-
 features/testbot/fixed.feature                     |     4 +-
 features/testbot/geometry.feature                  |     8 +-
 features/testbot/graph.feature                     |     8 +-
 features/testbot/load.feature                      |    18 +-
 features/testbot/loop.feature                      |    24 +-
 features/testbot/matching.feature                  |    31 +
 features/testbot/matching_turns.feature            |   121 -
 features/testbot/mode.feature                      |   171 +-
 features/testbot/oneway.feature                    |    44 +-
 features/testbot/opposite.feature                  |     6 +-
 features/testbot/origin.feature                    |    24 +-
 features/testbot/penalty.feature                   |    46 +-
 features/testbot/planetary.feature                 |    12 +-
 features/testbot/post.feature                      |    83 -
 features/testbot/projection.feature                |    20 +-
 features/testbot/protobuffer.feature               |   156 -
 features/testbot/roundabout.feature                |    60 +-
 features/testbot/snap.feature                      |    98 +-
 features/testbot/speed.feature                     |     6 +-
 features/testbot/status.feature                    |    52 +-
 features/testbot/time.feature                      |   134 +-
 features/testbot/trip.feature                      |    15 +
 features/testbot/turn_angles.feature               |    74 +
 features/testbot/turns.feature                     |   140 +-
 features/testbot/utf.feature                       |     8 +-
 features/testbot/uturn.feature                     |    16 +-
 features/testbot/via.feature                       |   147 +-
 features/timestamp/timestamp.feature               |    11 -
 include/contractor/contractor.hpp                  |    96 +
 .../contractor/contractor_config.hpp               |    55 +-
 .../contractor}/crc32_processor.hpp                |    34 +-
 .../contractor/graph_contractor.hpp                |   560 +-
 .../contractor}/query_edge.hpp                     |    36 +-
 include/engine/api/base_api.hpp                    |    64 +
 include/engine/api/base_parameters.hpp             |    90 +
 include/engine/api/json_factory.hpp                |    81 +
 include/engine/api/match_api.hpp                   |   119 +
 .../engine/api/match_parameters.hpp                |    78 +-
 include/engine/api/nearest_api.hpp                 |    57 +
 .../engine/api/nearest_parameters.hpp              |    45 +-
 include/engine/api/route_api.hpp                   |   190 +
 include/engine/api/route_parameters.hpp            |    96 +
 include/engine/api/table_api.hpp                   |   133 +
 include/engine/api/table_parameters.hpp            |   110 +
 .../engine/api/tile_parameters.hpp                 |    66 +-
 include/engine/api/trip_api.hpp                    |   111 +
 .../engine/api/trip_parameters.hpp                 |    33 +-
 include/engine/base64.hpp                          |   141 +
 .../engine/bearing.hpp                             |    29 +-
 include/engine/datafacade/datafacade_base.hpp      |   153 +
 include/engine/datafacade/internal_datafacade.hpp  |   658 ++
 include/engine/datafacade/shared_datafacade.hpp    |   717 ++
 include/engine/douglas_peucker.hpp                 |    60 +
 include/engine/engine.hpp                          |    88 +
 .../engine_config.hpp}                             |    39 +-
 include/engine/geospatial_query.hpp                |   467 +
 include/engine/guidance/assemble_geometry.hpp      |    81 +
 include/engine/guidance/assemble_leg.hpp           |   169 +
 include/engine/guidance/assemble_overview.hpp      |    24 +
 include/engine/guidance/assemble_route.hpp         |    22 +
 include/engine/guidance/assemble_steps.hpp         |   157 +
 include/engine/guidance/leg_geometry.hpp           |    54 +
 include/engine/guidance/post_processing.hpp        |    44 +
 include/engine/guidance/route.hpp                  |    20 +
 include/engine/guidance/route_leg.hpp              |    29 +
 include/engine/guidance/route_step.hpp             |    40 +
 include/engine/guidance/step_maneuver.hpp          |    45 +
 include/engine/guidance/toolkit.hpp                |    63 +
 include/engine/hint.hpp                            |    81 +
 include/engine/internal_route_result.hpp           |    63 +
 .../engine/map_matching}/bayes_classifier.hpp      |    47 +-
 .../engine/map_matching}/hidden_markov_model.hpp   |    86 +-
 .../engine/map_matching/matching_confidence.hpp    |    58 +
 include/engine/map_matching/sub_matching.hpp       |    25 +
 include/engine/phantom_node.hpp                    |   214 +
 include/engine/plugins/match.hpp                   |    48 +
 include/engine/plugins/nearest.hpp                 |    26 +
 include/engine/plugins/plugin_base.hpp             |   284 +
 include/engine/plugins/table.hpp                   |    35 +
 include/engine/plugins/tile.hpp                    |    35 +
 include/engine/plugins/trip.hpp                    |    54 +
 include/engine/plugins/viaroute.hpp                |    47 +
 include/engine/polyline_compressor.hpp             |    31 +
 .../routing_algorithms}/alternative_path.hpp       |   187 +-
 .../routing_algorithms}/direct_shortest_path.hpp   |   104 +-
 .../engine/routing_algorithms}/many_to_many.hpp    |   171 +-
 .../engine/routing_algorithms}/map_matching.hpp    |   260 +-
 include/engine/routing_algorithms/routing_base.hpp |   906 ++
 .../engine/routing_algorithms}/shortest_path.hpp   |   343 +-
 include/engine/search_engine_data.hpp              |    42 +
 .../engine/status.hpp                              |    24 +-
 .../engine/trip}/trip_brute_force.hpp              |    46 +-
 .../engine/trip}/trip_farthest_insertion.hpp       |    62 +-
 .../engine/trip}/trip_nearest_neighbour.hpp        |    47 +-
 include/engine/trip/trip_tabu_search.hpp           |    41 +
 include/extractor/compressed_edge_container.hpp    |    57 +
 include/extractor/edge_based_edge.hpp              |    80 +
 include/extractor/edge_based_graph_factory.hpp     |   134 +
 include/extractor/edge_based_node.hpp              |    76 +
 include/extractor/external_memory_node.hpp         |    56 +
 .../extractor}/extraction_containers.hpp           |    53 +-
 .../extractor}/extraction_helper_functions.hpp     |    54 +-
 include/extractor/extraction_node.hpp              |    19 +
 include/extractor/extraction_way.hpp               |    58 +
 {extractor => include/extractor}/extractor.hpp     |    45 +-
 .../extractor}/extractor_callbacks.hpp             |    51 +-
 .../extractor/extractor_config.hpp                 |    64 +-
 .../extractor/first_and_last_segment_of_way.hpp    |    60 +
 include/extractor/graph_compressor.hpp             |    38 +
 include/extractor/guidance/classification_data.hpp |    67 +
 include/extractor/guidance/discrete_angle.hpp      |    19 +
 include/extractor/guidance/toolkit.hpp             |   404 +
 include/extractor/guidance/turn_analysis.hpp       |   202 +
 include/extractor/guidance/turn_classification.hpp |   123 +
 include/extractor/guidance/turn_instruction.hpp    |   127 +
 .../extractor}/internal_extractor_edge.hpp         |    90 +-
 include/extractor/node_based_edge.hpp              |   143 +
 include/extractor/original_edge_data.hpp           |    42 +
 include/extractor/profile_properties.hpp           |    48 +
 include/extractor/query_node.hpp                   |    51 +
 .../extractor}/raster_source.hpp                   |    49 +-
 .../extractor}/restriction.hpp                     |    38 +-
 .../extractor}/restriction_map.hpp                 |    57 +-
 include/extractor/restriction_parser.hpp           |    58 +
 include/extractor/scripting_environment.hpp        |    54 +
 {algorithms => include/extractor}/tarjan_scc.hpp   |    62 +-
 .../extractor}/travel_mode.hpp                     |    28 +-
 .../tribool.hpp => include/osrm/bearing.hpp        |    18 +-
 include/osrm/coordinate.hpp                        |    47 +-
 .../osrm/engine_config.hpp                         |    16 +-
 include/osrm/json_container.hpp                    |    75 +-
 .../osrm/match_parameters.hpp                      |    18 +-
 .../osrm/nearest_parameters.hpp                    |    18 +-
 include/osrm/osrm.hpp                              |   116 +-
 .../osrm/osrm_fwd.hpp                              |    44 +-
 include/osrm/route_parameters.hpp                  |    94 +-
 util/fingerprint.cpp => include/osrm/status.hpp    |    15 +-
 .../osrm/storage_config.hpp                        |    16 +-
 include/osrm/strong_typedef.hpp                    |    68 -
 .../osrm/table_parameters.hpp                      |    18 +-
 .../osrm/tile_parameters.hpp                       |    18 +-
 .../osrm/trip_parameters.hpp                       |    18 +-
 include/server/api/base_parameters_grammar.hpp     |   108 +
 include/server/api/match_parameter_grammar.hpp     |    88 +
 include/server/api/nearest_parameter_grammar.hpp   |    48 +
 include/server/api/parameters_parser.hpp           |    49 +
 include/server/api/parsed_url.hpp                  |    27 +
 include/server/api/route_parameters_grammar.hpp    |    96 +
 include/server/api/table_parameter_grammar.hpp     |    61 +
 include/server/api/tile_parameter_grammar.hpp      |    59 +
 include/server/api/trip_parameter_grammar.hpp      |    81 +
 include/server/api/url_parser.hpp                  |    29 +
 include/server/connection.hpp                      |    72 +
 include/server/http/compression_type.hpp           |    21 +
 include/server/http/header.hpp                     |    34 +
 include/server/http/reply.hpp                      |    45 +
 include/server/http/request.hpp                    |    26 +
 include/server/request_handler.hpp                 |    37 +
 include/server/request_parser.hpp                  |    76 +
 {server => include/server}/server.hpp              |    60 +-
 include/server/service/base_service.hpp            |    39 +
 include/server/service/match_service.hpp           |    33 +
 include/server/service/nearest_service.hpp         |    33 +
 include/server/service/route_service.hpp           |    33 +
 include/server/service/table_service.hpp           |    33 +
 include/server/service/tile_service.hpp            |    33 +
 include/server/service/trip_service.hpp            |    33 +
 include/server/service/utils.hpp                   |    29 +
 include/server/service_handler.hpp                 |    41 +
 include/storage/shared_barriers.hpp                |    39 +
 include/storage/shared_datatype.hpp                |   136 +
 .../storage/shared_memory.hpp                      |   128 +-
 include/storage/storage.hpp                        |    26 +
 include/storage/storage_config.hpp                 |    44 +
 include/util/assert.hpp                            |    20 +
 {util => include/util}/bearing.hpp                 |    34 +-
 {data_structures => include/util}/binary_heap.hpp  |    41 +-
 include/util/cast.hpp                              |    49 +
 include/util/container.hpp                         |    20 +
 include/util/coordinate.hpp                        |   187 +
 include/util/coordinate_calculation.hpp            |    92 +
 .../util}/deallocating_vector.hpp                  |    58 +-
 {util => include/util}/dist_table_wrapper.hpp      |    36 +-
 .../util}/dynamic_graph.hpp                        |    63 +-
 include/util/exception.hpp                         |    30 +
 include/util/fingerprint.hpp                       |    39 +
 {util => include/util}/fingerprint_impl.hpp.in     |    47 +-
 include/util/for_each_pair.hpp                     |    45 +
 {util => include/util}/graph_loader.hpp            |    79 +-
 {util => include/util}/graph_utils.hpp             |    26 +-
 include/util/hilbert_value.hpp                     |    18 +
 include/util/integer_range.hpp                     |    58 +
 include/util/io.hpp                                |   127 +
 .../util}/iso_8601_duration_parser.hpp             |    34 +-
 include/{osrm => util}/json_container.hpp          |    74 +-
 include/util/json_deep_compare.hpp                 |   158 +
 include/util/json_logger.hpp                       |    62 +
 {util => include/util}/json_renderer.hpp           |    46 +-
 include/util/json_util.hpp                         |    58 +
 include/util/lua_util.hpp                          |    54 +
 {util => include/util}/make_unique.hpp             |    32 +-
 include/util/matrix_graph_wrapper.hpp              |    51 +
 include/util/name_table.hpp                        |    31 +
 include/util/node_based_graph.hpp                  |    95 +
 {data_structures => include/util}/percent.hpp      |    34 +-
 {data_structures => include/util}/range_table.hpp  |    52 +-
 include/util/rectangle.hpp                         |   182 +
 .../util}/shared_memory_vector_wrapper.hpp         |    69 +-
 include/util/simple_logger.hpp                     |    55 +
 {data_structures => include/util}/static_graph.hpp |    65 +-
 {data_structures => include/util}/static_rtree.hpp |   380 +-
 include/util/std_hash.hpp                          |    41 +
 {util => include/util}/string_util.hpp             |    36 +-
 include/util/strong_typedef.hpp                    |    84 +
 {util => include/util}/timing_util.hpp             |    34 +-
 {util => include/util}/trigonometry_table.hpp      |    64 +-
 typedefs.h => include/util/typedefs.hpp            |    35 +-
 include/util/version.hpp.in                        |    10 +
 include/util/viewport.hpp                          |    51 +
 include/util/xor_fast_hash.hpp                     |    71 +
 include/util/xor_fast_hash_storage.hpp             |    84 +
 library/osrm_impl.cpp                              |   183 -
 library/osrm_impl.hpp                              |    71 -
 package.json                                       |    39 +
 plugins/distance_table.hpp                         |   247 -
 plugins/hello_world.hpp                            |   106 -
 plugins/match.hpp                                  |   417 -
 plugins/nearest.hpp                                |   128 -
 plugins/plugin_base.hpp                            |   136 -
 plugins/timestamp.hpp                              |    62 -
 plugins/trip.hpp                                   |   398 -
 plugins/viaroute.hpp                               |   215 -
 prepare.cpp                                        |   109 -
 profiles/bicycle.lua                               |    81 +-
 profiles/car.lua                                   |    58 +-
 profiles/foot.lua                                  |    23 +-
 profiles/rasterbot.lua                             |    11 +-
 .../{rasterbot-interp.lua => rasterbotinterp.lua}  |    11 +-
 profiles/testbot.lua                               |    37 +-
 routed.cpp                                         |   198 -
 routing_algorithms/routing_base.hpp                |   687 --
 scripts/check_taginfo.py                           |    51 +
 scripts/format.sh                                  |    22 +
 scripts/install_node.sh                            |     9 +
 scripts/modernize.sh                               |    15 +-
 scripts/tidy.sh                                    |    10 +-
 scripts/update_depdendencies.sh                    |     4 +-
 server/api_grammar.hpp                             |   122 -
 server/connection.hpp                              |    95 -
 server/data_structures/datafacade_base.hpp         |   126 -
 server/data_structures/internal_datafacade.hpp     |   469 -
 server/data_structures/shared_barriers.hpp         |    60 -
 server/data_structures/shared_datafacade.hpp       |   503 -
 server/data_structures/shared_datatype.hpp         |   196 -
 server/http/header.hpp                             |    54 -
 server/http/reply.hpp                              |    65 -
 server/http/request.hpp                            |    48 -
 server/request_handler.cpp                         |   177 -
 server/request_handler.hpp                         |    59 -
 server/request_parser.cpp                          |   393 -
 server/request_parser.hpp                          |    98 -
 src/benchmarks/static_rtree.cpp                    |   115 +
 src/contractor/contractor.cpp                      |   686 ++
 src/engine/api/json_factory.cpp                    |   230 +
 src/engine/douglas_peucker.cpp                     |   100 +
 src/engine/engine.cpp                              |   190 +
 src/engine/engine_config.cpp                       |    27 +
 src/engine/guidance/assemble_overview.cpp          |   103 +
 src/engine/guidance/assemble_route.cpp             |    30 +
 src/engine/guidance/assemble_steps.cpp             |    82 +
 src/engine/guidance/post_processing.cpp            |   494 +
 src/engine/hint.cpp                                |    59 +
 src/engine/plugins/match.cpp                       |   197 +
 src/engine/plugins/nearest.cpp                     |    49 +
 src/engine/plugins/table.cpp                       |    76 +
 src/engine/plugins/tile.cpp                        |   455 +
 src/engine/plugins/trip.cpp                        |   245 +
 src/engine/plugins/viaroute.cpp                    |   129 +
 src/engine/polyline_compressor.cpp                 |   128 +
 src/engine/search_engine_data.cpp                  |    80 +
 .../extractor}/compressed_edge_container.cpp       |   140 +-
 src/extractor/edge_based_graph_factory.cpp         |   481 +
 .../extractor}/extraction_containers.cpp           |   284 +-
 {extractor => src/extractor}/extractor.cpp         |   368 +-
 .../extractor}/extractor_callbacks.cpp             |   125 +-
 {algorithms => src/extractor}/graph_compressor.cpp |   101 +-
 src/extractor/guidance/classification_data.cpp     |    53 +
 src/extractor/guidance/turn_analysis.cpp           |  2313 ++++
 .../extractor}/raster_source.cpp                   |    91 +-
 .../extractor}/restriction_map.cpp                 |    43 +-
 .../extractor}/restriction_parser.cpp              |   469 +-
 src/extractor/scripting_environment.cpp            |   184 +
 src/osrm/osrm.cpp                                  |    54 +
 src/server/api/parameters_parser.cpp               |    86 +
 src/server/api/url_parser.cpp                      |    88 +
 {server => src/server}/connection.cpp              |    63 +-
 {server => src/server}/http/reply.cpp              |    45 +-
 src/server/request_handler.cpp                     |   151 +
 src/server/request_parser.cpp                      |   299 +
 src/server/service/match_service.cpp               |    73 +
 src/server/service/nearest_service.cpp             |    72 +
 src/server/service/route_service.cpp               |    69 +
 src/server/service/table_service.cpp               |    90 +
 src/server/service/tile_service.cpp                |    51 +
 src/server/service/trip_service.cpp                |    73 +
 src/server/service_handler.cpp                     |    54 +
 datastore.cpp => src/storage/storage.cpp           |   464 +-
 src/storage/storage_config.cpp                     |    38 +
 {tools => src/tools}/.gitignore                    |     0
 src/tools/components.cpp                           |   233 +
 src/tools/contract.cpp                             |   159 +
 src/tools/extract.cpp                              |   160 +
 src/tools/io-benchmark.cpp                         |   325 +
 src/tools/routed.cpp                               |   348 +
 src/tools/springclean.cpp                          |    82 +
 src/tools/store.cpp                                |   104 +
 src/tools/unlock_all_mutexes.cpp                   |    20 +
 src/util/assert.cpp                                |    29 +
 src/util/coordinate.cpp                            |   100 +
 src/util/coordinate_calculation.cpp                |   325 +
 src/util/exception.cpp                             |    21 +
 src/util/fingerprint.cpp                           |     2 +
 src/util/hilbert_value.cpp                         |    84 +
 src/util/name_table.cpp                            |    62 +
 {util => src/util}/simple_logger.cpp               |    36 +-
 taginfo.json                                       |   147 +-
 test/data/Makefile                                 |    29 +
 test/data/data.md5sum                              |     1 +
 third_party/variant/.clang-format                  |    89 +
 third_party/variant/.gitignore                     |     3 +
 third_party/variant/.travis.yml                    |   133 +-
 third_party/variant/.ycm_extra_conf.py             |    40 +
 third_party/variant/Jamroot                        |     8 +-
 third_party/variant/LICENSE_1_0.txt                |    23 +
 third_party/variant/Makefile                       |    44 +-
 third_party/variant/README.md                      |    92 +-
 third_party/variant/doc/other_implementations.md   |    15 +
 third_party/variant/doc/standards_effort.md        |    28 +
 third_party/variant/optional.hpp                   |    39 +-
 third_party/variant/recursive_wrapper.hpp          |   133 +-
 third_party/variant/scripts/build-appveyor.bat     |     2 +-
 third_party/variant/scripts/linux.sh               |    59 -
 third_party/variant/scripts/osx.sh                 |    20 -
 .../scripts/run_compilation_failure_tests.sh       |    50 +
 third_party/variant/test/bench_variant.cpp         |    52 +-
 third_party/variant/test/binary_visitor_test.cpp   |    40 +-
 .../variant/test/boost_variant_hello_world.cpp     |     7 +-
 third_party/variant/test/catch.hpp                 |  8683 --------------
 .../compilation_failure/default_constructor.cpp    |    22 +
 .../test/compilation_failure/empty_typelist.cpp    |    11 +
 .../variant/test/compilation_failure/equality.cpp  |    11 +
 .../variant/test/compilation_failure/get_type.cpp  |    10 +
 .../variant/test/compilation_failure/is_type.cpp   |    10 +
 .../mutating_visitor_on_const.cpp                  |    24 +
 .../test/compilation_failure/no-reference.cpp      |     9 +
 third_party/variant/test/include/catch.hpp         | 11613 +++++++++++++++++++
 third_party/variant/test/optional_unit.cpp         |    82 -
 .../variant/test/our_variant_hello_world.cpp       |    20 +
 .../variant/test/recursive_wrapper_test.cpp        |    67 +-
 .../variant/test/reference_wrapper_test.cpp        |    42 +-
 third_party/variant/test/t/binary_visitor_1.cpp    |     7 +
 third_party/variant/test/t/binary_visitor_2.cpp    |     7 +
 third_party/variant/test/t/binary_visitor_3.cpp    |     7 +
 third_party/variant/test/t/binary_visitor_4.cpp    |     7 +
 third_party/variant/test/t/binary_visitor_5.cpp    |     7 +
 third_party/variant/test/t/binary_visitor_6.cpp    |     7 +
 third_party/variant/test/t/binary_visitor_impl.hpp |   204 +
 third_party/variant/test/t/issue21.cpp             |    48 +
 third_party/variant/test/t/mutating_visitor.cpp    |    36 +
 third_party/variant/test/t/optional.cpp            |   102 +
 third_party/variant/test/t/recursive_wrapper.cpp   |   158 +
 third_party/variant/test/t/sizeof.cpp              |    52 +
 third_party/variant/test/t/unary_visitor.cpp       |   127 +
 third_party/variant/test/t/variant.cpp             |   570 +
 third_party/variant/test/unique_ptr_test.cpp       |    68 +-
 third_party/variant/test/unit.cpp                  |   314 +-
 third_party/variant/test/variant_hello_world.cpp   |    22 -
 third_party/variant/variant.gyp                    |    20 +-
 third_party/variant/variant.hpp                    |   635 +-
 third_party/variant/variant_io.hpp                 |    32 +-
 third_party/variant/vcbuild.bat                    |     8 -
 tools/check-hsgr.cpp                               |   112 -
 tools/components.cpp                               |   257 -
 tools/io-benchmark.cpp                             |   348 -
 tools/simpleclient.cpp                             |    97 -
 tools/springclean.cpp                              |   102 -
 tools/unlock_all_mutexes.cpp                       |    51 -
 unit_tests/algorithms/douglas_peucker.cpp          |   104 -
 unit_tests/algorithms/duration_parsing.cpp         |    64 -
 unit_tests/algorithms/geometry_string.cpp          |    74 -
 unit_tests/algorithms/string_util.cpp              |    65 -
 unit_tests/data_structures/coordinate.cpp          |    50 -
 unit_tests/data_structures/dynamic_graph.cpp       |    93 -
 unit_tests/data_structures/static_rtree.cpp        |   480 -
 unit_tests/engine/base64.cpp                       |    80 +
 unit_tests/engine/douglas_peucker.cpp              |   109 +
 unit_tests/engine/geometry_string.cpp              |    45 +
 unit_tests/engine/guidance_assembly.cpp            |    20 +
 unit_tests/engine_tests.cpp                        |     7 +
 .../compressed_edge_container.cpp                  |     7 +-
 .../{algorithms => extractor}/graph_compressor.cpp |   125 +-
 .../raster_source.cpp                              |    44 +-
 unit_tests/extractor_tests.cpp                     |     7 +
 unit_tests/library/args.hpp                        |    16 +
 unit_tests/library/coordinates.hpp                 |    28 +
 unit_tests/library/equal_json.hpp                  |    27 +
 unit_tests/library/fixture.hpp                     |    21 +
 unit_tests/library/limits.cpp                      |   139 +
 unit_tests/library/match.cpp                       |    37 +
 unit_tests/library/nearest.cpp                     |   116 +
 unit_tests/library/route.cpp                       |   232 +
 unit_tests/library/table.cpp                       |    37 +
 unit_tests/library/tile.cpp                        |    31 +
 unit_tests/library/trip.cpp                        |    37 +
 unit_tests/library_tests.cpp                       |     7 +
 unit_tests/mocks/mock_datafacade.hpp               |   178 +
 unit_tests/server/parameters_parser.cpp            |   330 +
 unit_tests/server/url_parser.cpp                   |   102 +
 unit_tests/server_tests.cpp                        |     7 +
 unit_tests/util/bearing.cpp                        |    37 +-
 .../{data_structures => util}/binary_heap.cpp      |    34 +-
 unit_tests/util/coordinate_calculation.cpp         |   191 +
 unit_tests/util/duration_parsing.cpp               |    40 +
 unit_tests/util/dynamic_graph.cpp                  |    66 +
 unit_tests/util/io.cpp                             |    42 +
 .../{data_structures => util}/range_table.cpp      |    38 +-
 unit_tests/util/rectangle.cpp                      |   107 +
 .../{data_structures => util}/static_graph.cpp     |    53 +-
 unit_tests/util/static_rtree.cpp                   |   456 +
 unit_tests/util/string_util.cpp                    |    41 +
 unit_tests/util/viewport.cpp                       |    25 +
 unit_tests/util_tests.cpp                          |    27 -
 util/cast.hpp                                      |    69 -
 util/compute_angle.cpp                             |    54 -
 util/compute_angle.hpp                             |    42 -
 util/container.hpp                                 |   111 -
 util/datastore_options.hpp                         |   282 -
 util/debug_geometry.hpp                            |   198 -
 util/fingerprint.hpp                               |    61 -
 util/ini_file.hpp                                  |    51 -
 util/integer_range.hpp                             |    80 -
 util/json_util.hpp                                 |   103 -
 util/lua_util.hpp                                  |    65 -
 util/matching_debug_info.hpp                       |   155 -
 util/mercator.cpp                                  |    40 -
 util/mercator.hpp                                  |    38 -
 util/osrm_exception.cpp                            |    43 -
 util/routed_options.hpp                            |   284 -
 util/simple_logger.hpp                             |    74 -
 util/std_hash.hpp                                  |    72 -
 util/version.hpp.in                                |    37 -
 util/xml_renderer.hpp                              |   137 -
 655 files changed, 47552 insertions(+), 36007 deletions(-)

diff --git a/.cncc.style b/.cncc.style
new file mode 100644
index 0000000..bdece58
--- /dev/null
+++ b/.cncc.style
@@ -0,0 +1,14 @@
+# Kind-specific patterns to check AST nodes against. Both python-clang and
+# libclang docs explain CursorKind, with differences in detail. See also:
+#  - https://github.com/llvm-mirror/clang/blob/aca4fe314a55cacae29e1548cb7bfd2119c6df4c/bindings/python/clang/cindex.py#L599
+#  - http://clang.llvm.org/doxygen/group__CINDEX.html#gaaccc432245b4cd9f2d470913f9ef0013
+#  - https://docs.python.org/2/library/re.html#regular-expression-syntax
+
+class_decl: '^([A-Z]+[a-z]+)+$'
+struct_decl: '^([A-Z]+[a-z]+)+$'
+field_decl: '^[a-z_]+$'
+var_decl: '^[a-z]+[a-z0-9_]*$'
+parm_decl: '^[a-z]*[a-z0-9_]*$'
+namespace: '^[a-z_]*$'
+cxx_method: '^([A-Z]+[a-z]+)+$'
+function_decl: '^[a-z]+([A-Z]+[a-z]+)*$'
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..d6d517d
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,28 @@
+{
+    "rules": {
+        "indent": [
+            2,
+            4
+        ],
+        "quotes": [
+            1,
+            "single"
+        ],
+        "linebreak-style": [
+            2,
+            "unix"
+        ],
+        "semi": [
+            2,
+            "always"
+        ],
+        "no-console": [
+            1
+        ]
+    },
+    "env": {
+        "es6": true,
+        "node": true
+    },
+    "extends": "eslint:recommended"
+}
diff --git a/.gitignore b/.gitignore
index 21608e3..83f572d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,6 +40,8 @@ Thumbs.db
 # build related files #
 #######################
 /build/
+/example/build/
+/test/data/monaco*
 /cmake/postinst
 
 # Eclipse related files #
@@ -73,8 +75,15 @@ stxxl.errlog
 ###################
 /sandbox/
 
+# Test related files #
+######################
 /test/profile.lua
+/test/cache
+/test/speeds.csv
+node_modules
 
 # Deprecated config file #
 ##########################
 /server.ini
+
+*.swp
diff --git a/.travis.yml b/.travis.yml
index c065949..553cf56 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,9 @@
-language: cpp
+#language: cpp
+# This makes travis use the thin image which boots faster
+language: generic
+
+
+# sudo:required is needed for trusty images
 sudo: required
 dist: trusty
 
@@ -11,67 +16,86 @@ branches:
     - develop
 
 matrix:
+  fast_finish: true
+
   include:
 
-    # 1/ Linux Clang Builds
+    # Debug Builds
+    - os: linux
+      compiler: gcc
+      addons: &gcc5
+        apt:
+          sources: ['ubuntu-toolchain-r-test']
+          packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
+      env: COMPILER='g++-5' BUILD_TYPE='Debug'
 
     - os: linux
-      compiler: clang
-      addons: &clang38
+      compiler: gcc
+      addons: &gcc48
         apt:
-          sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test']
-          packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'rubygems-integration', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
-      env: COMPILER='clang++-3.8' BUILD_TYPE='Release'
+          sources: ['ubuntu-toolchain-r-test']
+          packages: ['g++-4.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
+      env: COMPILER='g++-4.8' BUILD_TYPE='Debug'
 
     - os: linux
       compiler: clang
       addons: &clang38
         apt:
           sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test']
-          packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'rubygems-integration', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
-      env: COMPILER='clang++-3.8' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
+          packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
+      env: COMPILER='clang++-3.8' BUILD_TYPE='Debug' RUN_CLANG_FORMAT=ON
 
-    - os: linux
+    - os: osx
+      osx_image: xcode7.3
       compiler: clang
-      addons: *clang38
-      env: COMPILER='clang++-3.8' BUILD_TYPE='Debug'
+      env: COMPILER='clang++' BUILD_TYPE='Debug'
 
-
-    # 2/ Linux GCC Builds
+    # Release Builds
     - os: linux
       compiler: gcc
-      addons: &gcc48
+      addons: &gcc5
         apt:
           sources: ['ubuntu-toolchain-r-test']
-          packages: ['g++-4.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'rubygems-integration', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
-      env: COMPILER='g++-4.8' BUILD_TYPE='Release'
+          packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
+      env: COMPILER='g++-5' BUILD_TYPE='Release'
 
     - os: linux
       compiler: gcc
-      addons: *gcc48
-      env: COMPILER='g++-4.8' BUILD_TYPE='Debug'
-
+      addons: &gcc48
+        apt:
+          sources: ['ubuntu-toolchain-r-test']
+          packages: ['g++-4.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
+      env: COMPILER='g++-4.8' BUILD_TYPE='Release'
 
     - os: linux
-      compiler: gcc
-      addons: &gcc5
+      compiler: clang
+      addons: &clang38
         apt:
-          sources: ['ubuntu-toolchain-r-test']
-          packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'rubygems-integration', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
-      env: COMPILER='g++-5' BUILD_TYPE='Release'
+          sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test']
+          packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
+      env: COMPILER='clang++-3.8' BUILD_TYPE='Release'
 
+    - os: osx
+      osx_image: xcode7.3
+      compiler: clang
+      env: COMPILER='clang++' BUILD_TYPE='Release'
+
+    # Shared Library
     - os: linux
       compiler: gcc
       addons: &gcc5
         apt:
           sources: ['ubuntu-toolchain-r-test']
-          packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'rubygems-integration', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
+          packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
       env: COMPILER='g++-5' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
 
     - os: linux
-      compiler: gcc
-      addons: *gcc5
-      env: COMPILER='g++-5' BUILD_TYPE='Debug'
+      compiler: clang
+      addons: &clang38
+        apt:
+          sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test']
+          packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
+      env: COMPILER='clang++-3.8' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
 
 
     # Disabled until tests all pass on OSX:
@@ -95,20 +119,13 @@ matrix:
     #- os: osx
     #  osx_image: xcode7
     #  compiler: clang
-    #  env: COMPILER='clang++' BUILD_TYPE='Debug'
-
-    #- os: osx
-    #  osx_image: xcode7
-    #  compiler: clang
-    #  env: COMPILER='clang++' BUILD_TYPE='Release'
-
-    #- os: osx
-    #  osx_image: xcode7
-    #  compiler: clang
     #  env: COMPILER='clang++' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
 
+before_install:
+  - source ./scripts/install_node.sh 4
 
 install:
+  - npm install
   - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
   - mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR}
   - |
@@ -117,30 +134,44 @@ install:
       mkdir cmake && travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
       export PATH=${DEPS_DIR}/cmake/bin:${PATH}
 
-      OSMOSIS_URL="http://bretth.dev.openstreetmap.org/osmosis-build/osmosis-latest.tgz"
-      mkdir osmosis && travis_retry wget --quiet -O - ${OSMOSIS_URL} | tar -xz -C osmosis
-      export PATH=${DEPS_DIR}/osmosis/bin:${PATH}
-
     elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
-      brew install cmake boost libzip libstxxl libxml2 lua51 luabind tbb GDAL osmosis
+      # implicit deps, but seem to be installed by default with recent images: libxml2 GDAL boost
+      brew install cmake libzip libstxxl lua51 luabind tbb md5sha1sum
     fi
 
 before_script:
   - cd ${TRAVIS_BUILD_DIR}
-  - rvm use 1.9.3
-  - gem install bundler
-  - bundle install
-  - mkdir build && cd build
+  - |
+    if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
+      ./scripts/check_taginfo.py taginfo.json profiles/car.lua
+    fi
+  - mkdir build && pushd build
   - export CXX=${COMPILER}
-  - export OSRM_PORT=5000 OSRM_TIMEOUT=60
-  - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS:-OFF} -DBUILD_TOOLS=1
+  - export OSRM_PORT=5000 OSRM_TIMEOUT=6000
+  - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS:-OFF} -DBUILD_TOOLS=1 -DENABLE_CCACHE=0
 
 script:
   - make --jobs=2
   - make tests --jobs=2
   - make benchmarks
-  - ./algorithm-tests
-  - ./datastructure-tests
+  - sudo make install
+  - |
+    if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
+      sudo ldconfig
+    fi
+  - ./extractor-tests
+  - ./engine-tests
   - ./util-tests
-  - cd ..
-  - cucumber -p verify
+  - popd
+  - npm test
+  - make -C test/data
+  - ./build/library-tests test/data/monaco.osrm
+  - mkdir example/build && pushd example/build
+  - cmake ..
+  - make
+  - ./osrm-example ../../test/data/monaco.osrm
+  - popd
+  - |
+    if [ -n "$RUN_CLANG_FORMAT" ]; then
+      ./scripts/format.sh || true # we don't want to fail just yet
+    fi
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..168b5ad
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,17 @@
+# 5.0.0 RC1
+   - Renamed osrm-prepare into osrm-contract
+   - osrm-contract does not need a profile parameter anymore
+   - New public HTTP API, find documentation [here](https://github.com/Project-OSRM/osrm-backend/wiki/New-Server-api)
+   - POST support is discontinued, please use library bindings for more complex requests
+   - Removed timestamp plugin
+   - Coordinate order is now Longitude,Latitude
+   - Cucumber tests now based on Javascript (run with `npm test`)
+   - Profile API changed:
+      - `forward_mode` and `backward_mode` now need to be selected from a pre-defined list
+      - Global profile properties are now stored in a global `properties` element. This includes:
+        - `properties.traffic_signal_penalty`
+        - `properties.use_turn_restrictions`
+        - `properties.u_turn_penalty`
+        - `properties.allow_u_turn_at_via`
+
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b8fecc5..3ca9c8a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,8 +7,8 @@ This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. P
 endif()
 
 project(OSRM C CXX)
-set(OSRM_VERSION_MAJOR 4)
-set(OSRM_VERSION_MINOR 9)
+set(OSRM_VERSION_MAJOR 5)
+set(OSRM_VERSION_MINOR 0)
 set(OSRM_VERSION_PATCH 0)
 
 set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
@@ -29,15 +29,15 @@ 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(ENABLE_CCACHE "Speed up incremental rebuilds via ccache" ON)
 option(ENABLE_JSON_LOGGING "Adds additional JSON debug logging to the response" OFF)
-option(DEBUG_GEOMETRY "Enables an option to dump GeoJSON of the final routing graph" OFF)
 option(BUILD_TOOLS "Build OSRM tools" OFF)
+option(BUILD_COMPONENTS "Build OSRM tools" ON)
+option(ENABLE_ASSERTIONS OFF)
 
-include_directories(${CMAKE_CURRENT_SOURCE_DIR})
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
-include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/)
+include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include/)
+include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include/)
 include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/)
-include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include/)
 
 add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND}
   "-DOUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR}"
@@ -46,74 +46,61 @@ add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND}
   COMMENT "Configuring revision fingerprint"
   VERBATIM)
 
-add_custom_target(tests DEPENDS datastructure-tests algorithm-tests util-tests)
+add_custom_target(tests DEPENDS engine-tests extractor-tests util-tests server-tests library-tests)
 add_custom_target(benchmarks DEPENDS rtree-bench)
 
 set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread unit_test_framework)
 
 configure_file(
-  ${CMAKE_CURRENT_SOURCE_DIR}/util/version.hpp.in
-  ${CMAKE_CURRENT_BINARY_DIR}/util/version.hpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/include/util/version.hpp.in
+  ${CMAKE_CURRENT_BINARY_DIR}/include/util/version.hpp
 )
-file(GLOB ExtractorGlob extractor/*.cpp data_structures/hilbert_value.cpp)
-file(GLOB ImporterGlob data_structures/import_edge.cpp data_structures/external_memory_node.cpp data_structures/raster_source.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(RASTERSOURCE OBJECT data_structures/raster_source.cpp)
-add_library(EXCEPTION OBJECT util/osrm_exception.cpp)
-add_library(MERCATOR OBJECT util/mercator.cpp)
-add_library(ANGLE OBJECT util/compute_angle.cpp)
-
-set(ExtractorSources extract.cpp ${ExtractorGlob})
-add_executable(osrm-extract ${ExtractorSources} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR> $<TARGET_OBJECTS:COMPRESSEDEDGE> $<TARGET_OBJECTS:GRAPHCOMPRESSOR> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:ANGLE>)
-
-add_library(RESTRICTION OBJECT data_structures/restriction_map.cpp)
-add_library(COMPRESSEDEDGE OBJECT data_structures/compressed_edge_container.cpp)
-add_library(GRAPHCOMPRESSOR OBJECT algorithms/graph_compressor.cpp)
-
-file(GLOB PrepareGlob contractor/*.cpp data_structures/hilbert_value.cpp {RestrictionMapGlob})
-set(PrepareSources prepare.cpp ${PrepareGlob})
-add_executable(osrm-prepare ${PrepareSources} $<TARGET_OBJECTS:ANGLE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR> $<TARGET_OBJECTS:COMPRESSEDEDGE> $<TARGET_OBJECTS:GRAPHCOMPRESSOR>)
-
-file(GLOB ServerGlob server/*.cpp)
-file(GLOB DescriptorGlob descriptors/*.cpp)
-file(GLOB DatastructureGlob data_structures/search_engine_data.cpp data_structures/route_parameters.cpp util/bearing.cpp)
-file(GLOB CoordinateGlob data_structures/coordinate.cpp algorithms/coordinate_calculation.cpp)
-file(GLOB AlgorithmGlob algorithms/polyline_compressor.cpp algorithms/polyline_formatter.cpp algorithms/douglas_peucker.cpp)
-file(GLOB HttpGlob server/http/*.cpp)
-file(GLOB LibOSRMGlob library/*.cpp)
-file(GLOB DataStructureTestsGlob unit_tests/data_structures/*.cpp data_structures/hilbert_value.cpp)
-file(GLOB AlgorithmTestsGlob unit_tests/algorithms/*.cpp algorithms/graph_compressor.cpp)
+file(GLOB UtilGlob src/util/*.cpp)
+file(GLOB ExtractorGlob src/extractor/*.cpp src/extractor/*/*.cpp)
+file(GLOB ContractorGlob src/contractor/*.cpp)
+file(GLOB StorageGlob src/storage/*.cpp)
+file(GLOB ServerGlob src/server/*.cpp src/server/**/*.cpp)
+file(GLOB EngineGlob src/engine/*.cpp src/engine/**/*.cpp)
+file(GLOB ExtractorTestsGlob unit_tests/extractor/*.cpp)
+file(GLOB EngineTestsGlob unit_tests/engine/*.cpp)
 file(GLOB UtilTestsGlob unit_tests/util/*.cpp)
-
-set(
-  OSRMSources
-  ${LibOSRMGlob}
-  ${DescriptorGlob}
-  ${DatastructureGlob}
-  ${AlgorithmGlob}
-  ${HttpGlob}
-)
-
-add_library(COORDINATE OBJECT ${CoordinateGlob})
-add_library(OSRM ${OSRMSources} $<TARGET_OBJECTS:ANGLE> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR> $<TARGET_OBJECTS:IMPORT>)
-
-add_library(FINGERPRINT OBJECT util/fingerprint.cpp)
-add_dependencies(FINGERPRINT FingerPrintConfigure)
-add_dependencies(OSRM FingerPrintConfigure)
-set_target_properties(FINGERPRINT PROPERTIES LINKER_LANGUAGE CXX)
-
-add_executable(osrm-routed routed.cpp ${ServerGlob} $<TARGET_OBJECTS:EXCEPTION>)
-add_executable(osrm-datastore datastore.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
+file(GLOB ServerTestsGlob unit_tests/server/*.cpp)
+file(GLOB LibraryTestsGlob unit_tests/library/*.cpp)
+file(GLOB IOTestsGlob unit_tests/io/*.cpp)
+
+add_library(UTIL OBJECT ${UtilGlob})
+add_library(EXTRACTOR OBJECT ${ExtractorGlob})
+add_library(CONTRACTOR OBJECT ${ContractorGlob})
+add_library(STORAGE OBJECT ${StorageGlob})
+add_library(ENGINE OBJECT ${EngineGlob})
+add_library(SERVER OBJECT ${ServerGlob})
+
+add_dependencies(UTIL FingerPrintConfigure)
+set_target_properties(UTIL PROPERTIES LINKER_LANGUAGE CXX)
+
+add_executable(osrm-extract src/tools/extract.cpp)
+add_executable(osrm-contract src/tools/contract.cpp)
+add_executable(osrm-routed src/tools/routed.cpp $<TARGET_OBJECTS:SERVER> $<TARGET_OBJECTS:UTIL>)
+add_executable(osrm-datastore src/tools/store.cpp $<TARGET_OBJECTS:UTIL>)
+add_library(osrm src/osrm/osrm.cpp $<TARGET_OBJECTS:ENGINE> $<TARGET_OBJECTS:UTIL> $<TARGET_OBJECTS:STORAGE>)
+add_library(osrm_extract $<TARGET_OBJECTS:EXTRACTOR> $<TARGET_OBJECTS:UTIL>)
+add_library(osrm_contract $<TARGET_OBJECTS:CONTRACTOR> $<TARGET_OBJECTS:UTIL>)
+add_library(osrm_store $<TARGET_OBJECTS:STORAGE> $<TARGET_OBJECTS:UTIL>)
 
 # Unit tests
-add_executable(datastructure-tests EXCLUDE_FROM_ALL unit_tests/datastructure_tests.cpp ${DataStructureTestsGlob} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR> $<TARGET_OBJECTS:COMPRESSEDEDGE> $<TARGET_OBJECTS:GRAPHCOMPRESSOR> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:RASTERSOURCE>)
-add_executable(algorithm-tests EXCLUDE_FROM_ALL unit_tests/algorithm_tests.cpp ${AlgorithmTestsGlob} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:COMPRESSEDEDGE>)
-add_executable(util-tests EXCLUDE_FROM_ALL unit_tests/util_tests.cpp ${UtilTestsGlob})
+add_executable(engine-tests EXCLUDE_FROM_ALL unit_tests/engine_tests.cpp ${EngineTestsGlob} $<TARGET_OBJECTS:ENGINE> $<TARGET_OBJECTS:STORAGE> $<TARGET_OBJECTS:UTIL>)
+add_executable(extractor-tests EXCLUDE_FROM_ALL unit_tests/extractor_tests.cpp ${ExtractorTestsGlob} $<TARGET_OBJECTS:EXTRACTOR> $<TARGET_OBJECTS:UTIL>)
+add_executable(util-tests EXCLUDE_FROM_ALL unit_tests/util_tests.cpp ${UtilTestsGlob} $<TARGET_OBJECTS:UTIL>)
+add_executable(server-tests EXCLUDE_FROM_ALL unit_tests/server_tests.cpp ${ServerTestsGlob} $<TARGET_OBJECTS:UTIL> $<TARGET_OBJECTS:SERVER>)
+add_executable(library-tests EXCLUDE_FROM_ALL unit_tests/library_tests.cpp ${LibraryTestsGlob})
 
 # Benchmarks
-add_executable(rtree-bench EXCLUDE_FROM_ALL benchmarks/static_rtree.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
+add_executable(rtree-bench EXCLUDE_FROM_ALL src/benchmarks/static_rtree.cpp $<TARGET_OBJECTS:UTIL>)
+
+target_include_directories(engine-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/unit_tests)
+target_include_directories(util-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/unit_tests)
+target_include_directories(library-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/)
+target_include_directories(rtree-bench PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/unit_tests)
 
 # Check the release mode
 if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
@@ -121,6 +108,7 @@ if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
 endif()
 if(CMAKE_BUILD_TYPE MATCHES Debug)
   message(STATUS "Configuring OSRM in debug mode")
+  set(ENABLE_ASSERTIONS ON)
   if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
 
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-inline -fno-omit-frame-pointer")
@@ -175,7 +163,7 @@ endif()
 
 # Configuring compilers
 if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wuninitialized -Wunreachable-code -Wstrict-overflow=2 -D_FORTIFY_SOURCE=2 -fPIC")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wuninitialized -Wunreachable-code -Wstrict-overflow=2 -D_FORTIFY_SOURCE=2 -fPIC -fcolor-diagnostics")
 elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
   set(COLOR_FLAG "-fdiagnostics-color=auto")
   check_cxx_compiler_flag("-fdiagnostics-color=auto" HAS_COLOR_FLAG)
@@ -185,7 +173,6 @@ elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
   # using GCC
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wuninitialized -Wunreachable-code -Wstrict-overflow=1 -D_FORTIFY_SOURCE=2 ${COLOR_FLAG} -fPIC")
   if(WIN32) # using mingw
-    add_definitions(-D_USE_MATH_DEFINES) # define M_PI, M_1_PI etc.
     add_definitions(-DWIN32)
     set(OPTIONAL_SOCKET_LIBS ws2_32 wsock32)
   endif()
@@ -195,9 +182,10 @@ elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel")
 elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
   # using Visual Studio C++
   set(BOOST_COMPONENTS ${BOOST_COMPONENTS} date_time chrono zlib)
+  add_definitions(-DBOOST_LIB_DIAGNOSTIC)
   add_definitions(-D_CRT_SECURE_NO_WARNINGS)
   add_definitions(-DNOMINMAX) # avoid min and max macros that can break compilation
-  add_definitions(-D_USE_MATH_DEFINES) # define M_PI
+  add_definitions(-D_USE_MATH_DEFINES) #needed for M_PI with cmath.h
   add_definitions(-D_WIN32_WINNT=0x0501)
   add_definitions(-DXML_STATIC)
   find_library(ws2_32_LIBRARY_PATH ws2_32)
@@ -245,76 +233,45 @@ if(APPLE)
 endif()
 
 if(UNIX AND NOT APPLE)
-  target_link_libraries(osrm-prepare rt)
-  target_link_libraries(osrm-datastore rt)
-  target_link_libraries(OSRM rt)
+  set(MAYBE_RT_LIBRARY rt)
 endif()
 
-#Check Boost
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/cmake")
+set(OSMIUM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include")
+find_package(Osmium REQUIRED COMPONENTS io)
+include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS})
+
+
 find_package(Boost 1.49.0 COMPONENTS ${BOOST_COMPONENTS} REQUIRED)
-if(NOT Boost_FOUND)
-  message(FATAL_ERROR "Fatal error: Boost (version >= 1.49.0) required.\n")
+if(NOT WIN32)
+  add_definitions(-DBOOST_TEST_DYN_LINK)
 endif()
+add_definitions(-DBOOST_SPIRIT_USE_PHOENIX_V3 -DBOOST_RESULT_OF_USE_DECLTYPE)
 include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
 
-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(util-tests ${Boost_LIBRARIES})
-target_link_libraries(rtree-bench ${Boost_LIBRARIES})
-
 find_package(Threads REQUIRED)
-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)
+include_directories(SYSTEM ${TBB_INCLUDE_DIR})
 if(WIN32 AND CMAKE_BUILD_TYPE MATCHES Debug)
   set(TBB_LIBRARIES ${TBB_DEBUG_LIBRARIES})
 endif()
-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(SYSTEM ${TBB_INCLUDE_DIR})
 
 find_package( Luabind REQUIRED )
 include(check_luabind)
-
 include_directories(SYSTEM ${LUABIND_INCLUDE_DIR})
-target_link_libraries(osrm-extract ${LUABIND_LIBRARY})
-target_link_libraries(osrm-prepare ${LUABIND_LIBRARY})
 
+set(USED_LUA_LIBRARIES ${LUA_LIBRARY})
 if(LUAJIT_FOUND)
-  target_link_libraries(osrm-extract ${LUAJIT_LIBRARIES})
-  target_link_libraries(osrm-prepare ${LUAJIT_LIBRARIES})
-else()
-  target_link_libraries(osrm-extract ${LUA_LIBRARY})
-  target_link_libraries(osrm-prepare ${LUA_LIBRARY})
+  set(USED_LUA_LIBRARIES, LUAJIT_LIBRARIES)
 endif()
 include_directories(SYSTEM ${LUA_INCLUDE_DIR})
 
 find_package(EXPAT REQUIRED)
 include_directories(SYSTEM ${EXPAT_INCLUDE_DIRS})
-target_link_libraries(osrm-extract ${EXPAT_LIBRARIES})
 
 find_package(STXXL REQUIRED)
 include_directories(SYSTEM ${STXXL_INCLUDE_DIR})
-target_link_libraries(OSRM ${STXXL_LIBRARY})
-target_link_libraries(osrm-extract ${STXXL_LIBRARY})
-target_link_libraries(osrm-prepare ${STXXL_LIBRARY})
-target_link_libraries(datastructure-tests ${STXXL_LIBRARY})
 
 set(OpenMP_FIND_QUIETLY ON)
 find_package(OpenMP)
@@ -325,91 +282,144 @@ endif()
 
 find_package(BZip2 REQUIRED)
 include_directories(SYSTEM ${BZIP_INCLUDE_DIRS})
-target_link_libraries(osrm-extract ${BZIP2_LIBRARIES})
 
 find_package(ZLIB REQUIRED)
 include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS})
-target_link_libraries(osrm-extract ${ZLIB_LIBRARY})
-target_link_libraries(osrm-routed ${ZLIB_LIBRARY})
 
 if (ENABLE_JSON_LOGGING)
   message(STATUS "Enabling json logging")
   add_definitions(-DENABLE_JSON_LOGGING)
 endif()
 
-if (DEBUG_GEOMETRY)
-  message(STATUS "Enabling final edge weight GeoJSON output option")
-  add_definitions(-DDEBUG_GEOMETRY)
-endif()
-
-if(BUILD_TOOLS)
-  message(STATUS "Activating OSRM internal tools")
+# Binaries
+target_link_libraries(osrm-datastore osrm_store ${Boost_LIBRARIES})
+target_link_libraries(osrm-extract osrm_extract ${Boost_LIBRARIES})
+target_link_libraries(osrm-contract osrm_contract ${Boost_LIBRARIES})
+target_link_libraries(osrm-routed osrm ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} ${ZLIB_LIBRARY})
+
+set(EXTRACTOR_LIBRARIES
+    ${BZIP2_LIBRARIES}
+    ${Boost_LIBRARIES}
+    ${CMAKE_THREAD_LIBS_INIT}
+    ${EXPAT_LIBRARIES}
+    ${LUABIND_LIBRARY}
+    ${USED_LUA_LIBRARIES}
+    ${OSMIUM_LIBRARIES}
+    ${STXXL_LIBRARY}
+    ${TBB_LIBRARIES}
+    ${ZLIB_LIBRARY})
+set(CONTRACTOR_LIBRARIES
+    ${Boost_LIBRARIES}
+    ${CMAKE_THREAD_LIBS_INIT}
+    ${LUABIND_LIBRARY}
+    ${USED_LUA_LIBRARIES}
+    ${STXXL_LIBRARY}
+    ${TBB_LIBRARIES}
+    ${MAYBE_RT_LIBRARY})
+set(ENGINE_LIBRARIES
+    ${Boost_LIBRARIES}
+    ${CMAKE_THREAD_LIBS_INIT}
+    ${STXXL_LIBRARY}
+    ${TBB_LIBRARIES}
+    ${MAYBE_RT_LIBRARY})
+set(STORAGE_LIBRARIES
+    ${Boost_LIBRARIES}
+    ${CMAKE_THREAD_LIBS_INIT}
+    ${TBB_LIBRARIES}
+    ${MAYBE_RT_LIBRARY})
+set(UTIL_LIBRARIES
+    ${Boost_LIBRARIES}
+    ${CMAKE_THREAD_LIBS_INIT}
+    ${STXXL_LIBRARY}
+    ${TBB_LIBRARIES})
+# Libraries
+target_link_libraries(osrm ${ENGINE_LIBRARIES})
+target_link_libraries(osrm_contract ${CONTRACTOR_LIBRARIES})
+target_link_libraries(osrm_extract ${EXTRACTOR_LIBRARIES})
+target_link_libraries(osrm_store ${STORAGE_LIBRARIES})
+# Tests
+target_link_libraries(engine-tests ${ENGINE_LIBRARIES})
+target_link_libraries(server-tests osrm ${Boost_LIBRARIES})
+target_link_libraries(extractor-tests ${EXTRACTOR_LIBRARIES})
+target_link_libraries(rtree-bench ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${TBB_LIBRARIES})
+target_link_libraries(util-tests ${UTIL_LIBRARIES})
+target_link_libraries(library-tests osrm ${Boost_LIBRARIES})
+
+if(BUILD_COMPONENTS)
   find_package(GDAL)
   if(GDAL_FOUND)
-    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_OBJECTS:MERCATOR>)
+    add_executable(osrm-components src/tools/components.cpp $<TARGET_OBJECTS:UTIL>)
     target_link_libraries(osrm-components ${TBB_LIBRARIES})
     include_directories(SYSTEM ${GDAL_INCLUDE_DIR})
     target_link_libraries(osrm-components ${GDAL_LIBRARIES} ${Boost_LIBRARIES})
     install(TARGETS osrm-components DESTINATION bin)
   else()
-    message(FATAL_ERROR "libgdal and/or development headers not found")
+    message(WARNING "libgdal and/or development headers not found")
   endif()
-  add_executable(osrm-cli tools/simpleclient.cpp $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:COORDINATE>)
-  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_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:LOGGER>)
+endif()
+
+if(BUILD_TOOLS)
+  message(STATUS "Activating OSRM internal tools")
+  add_executable(osrm-io-benchmark src/tools/io-benchmark.cpp $<TARGET_OBJECTS:UTIL>)
   target_link_libraries(osrm-io-benchmark ${Boost_LIBRARIES})
-  add_executable(osrm-unlock-all tools/unlock_all_mutexes.cpp $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION>)
+  add_executable(osrm-unlock-all src/tools/unlock_all_mutexes.cpp $<TARGET_OBJECTS:UTIL>)
   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:FINGERPRINT> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:IMPORT>)
-  target_link_libraries(osrm-check-hsgr ${Boost_LIBRARIES} ${TBB_LIBRARIES})
-  add_executable(osrm-springclean tools/springclean.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION>)
+  add_executable(osrm-springclean src/tools/springclean.cpp $<TARGET_OBJECTS:UTIL>)
   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/*.hpp)
-file(GLOB VariantGlob third_party/variant/*.hpp)
+if (ENABLE_ASSERTIONS)
+  message(STATUS "Enabling assertions")
+  add_definitions(-DBOOST_ENABLE_ASSERT_HANDLER)
+endif()
 
 # Add RPATH info to executables so that when they are run after being installed
 # (i.e., from /usr/local/bin/) the linker can find library dependencies. For
 # more info see http://www.cmake.org/Wiki/CMake_RPATH_handling
 set_property(TARGET osrm-extract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
-set_property(TARGET osrm-prepare PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
+set_property(TARGET osrm-contract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
 set_property(TARGET osrm-datastore PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
 set_property(TARGET osrm-routed PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
 
-install(FILES ${InstallGlob} DESTINATION include/osrm)
+file(GLOB VariantGlob third_party/variant/*.hpp)
+file(GLOB LibraryGlob include/osrm/*.hpp)
+file(GLOB ParametersGlob include/engine/api/*_parameters.hpp)
+set(EngineHeader include/engine/status.hpp include/engine/engine_config.hpp include/engine/hint.hpp include/engine/bearing.hpp include/engine/phantom_node.hpp)
+set(UtilHeader include/util/coordinate.hpp include/util/json_container.hpp include/util/typedefs.hpp include/util/strong_typedef.hpp)
+set(ExtractorHeader include/extractor/extractor.hpp include/extractor/extractor_config.hpp include/extractor/travel_mode.hpp)
+set(ContractorHeader include/contractor/contractor.hpp include/contractor/contractor_config.hpp)
+set(StorageHeader include/storage/storage.hpp include/storage/storage_config.hpp)
+install(FILES ${EngineHeader} DESTINATION include/osrm/engine)
+install(FILES ${UtilHeader} DESTINATION include/osrm/util)
+install(FILES ${StorageHeader} DESTINATION include/osrm/storage)
+install(FILES ${ExtractorHeader} DESTINATION include/osrm/extractor)
+install(FILES ${ContractorHeader} DESTINATION include/osrm/contractor)
+install(FILES ${LibraryGlob} DESTINATION include/osrm)
+install(FILES ${ParametersGlob} DESTINATION include/osrm/engine/api)
 install(FILES ${VariantGlob} DESTINATION include/variant)
 install(TARGETS osrm-extract DESTINATION bin)
-install(TARGETS osrm-prepare DESTINATION bin)
+install(TARGETS osrm-contract DESTINATION bin)
 install(TARGETS osrm-datastore DESTINATION bin)
 install(TARGETS osrm-routed DESTINATION bin)
-install(TARGETS OSRM DESTINATION lib)
-
-list(GET Boost_LIBRARIES 1 BOOST_LIBRARY_FIRST)
-get_filename_component(BOOST_LIBRARY_LISTING "${BOOST_LIBRARY_FIRST}" PATH)
-set(BOOST_LIBRARY_LISTING "-L${BOOST_LIBRARY_LISTING}")
-foreach(lib ${Boost_LIBRARIES})
-  get_filename_component(BOOST_LIBRARY_NAME "${lib}" NAME_WE)
-  string(REPLACE "lib" "" BOOST_LIBRARY_NAME ${BOOST_LIBRARY_NAME})
-  set(BOOST_LIBRARY_LISTING "${BOOST_LIBRARY_LISTING} -l${BOOST_LIBRARY_NAME}")
-endforeach()
-list(GET TBB_LIBRARIES 1 TBB_LIBRARY_FIRST)
-get_filename_component(TBB_LIBRARY_LISTING "${TBB_LIBRARY_FIRST}" PATH)
-set(TBB_LIBRARY_LISTING "-L${TBB_LIBRARY_LISTING}")
-foreach(lib ${TBB_LIBRARIES})
-  get_filename_component(TBB_LIBRARY_NAME "${lib}" NAME_WE)
-  string(REPLACE "lib" "" TBB_LIBRARY_NAME ${TBB_LIBRARY_NAME})
-  set(TBB_LIBRARY_LISTING "${TBB_LIBRARY_LISTING} -l${TBB_LIBRARY_NAME}")
+install(TARGETS osrm DESTINATION lib)
+install(TARGETS osrm_extract DESTINATION lib)
+install(TARGETS osrm_contract DESTINATION lib)
+install(TARGETS osrm_store DESTINATION lib)
+
+list(GET ENGINE_LIBRARIES 1 ENGINE_LIBRARY_FIRST)
+foreach(lib ${ENGINE_LIBRARIES})
+  get_filename_component(ENGINE_LIBRARY_PATH "${ENGINE_LIBRARY_FIRST}" PATH)
+  get_filename_component(ENGINE_LIBRARY_NAME "${lib}" NAME_WE)
+  string(REPLACE "lib" "" ENGINE_LIBRARY_NAME ${ENGINE_LIBRARY_NAME})
+  string(REPLACE "-l" "" ENGINE_LIBRARY_NAME ${ENGINE_LIBRARY_NAME})
+  set(ENGINE_LIBRARY_LISTING "${ENGINE_LIBRARY_LISTING} -L${ENGINE_LIBRARY_PATH} -l${ENGINE_LIBRARY_NAME}")
 endforeach()
 
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY)
@@ -432,11 +442,21 @@ COMMENT "Generating API documentation with Doxygen" VERBATIM
 endif()
 
 # prefix compilation with ccache by default if available and on clang or gcc
-if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
+if(ENABLE_CCACHE AND (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU"))
   find_program(CCACHE_FOUND ccache)
   if(CCACHE_FOUND)
+    message(STATUS "Using ccache to speed up incremental builds")
     set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
     set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
     set(ENV{CCACHE_CPP2} "true")
   endif()
 endif()
+
+# uninstall target
+configure_file(
+    "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
+    "${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake"
+    IMMEDIATE @ONLY)
+
+add_custom_target(uninstall
+    COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake)
diff --git a/Doxyfile.in b/Doxyfile.in
index 5842f6b..dd51b16 100644
--- a/Doxyfile.in
+++ b/Doxyfile.in
@@ -18,6 +18,7 @@ RECURSIVE              = YES
 
 EXCLUDE                = @CMAKE_CURRENT_SOURCE_DIR@/third_party \
                          @CMAKE_CURRENT_SOURCE_DIR@/build \
+                         @CMAKE_CURRENT_SOURCE_DIR@/node_modules \
                          @CMAKE_CURRENT_SOURCE_DIR@/unit_tests \
 			 @CMAKE_CURRENT_SOURCE_DIR@/benchmarks \
                          @CMAKE_CURRENT_SOURCE_DIR@/features
diff --git a/Gemfile b/Gemfile
deleted file mode 100644
index 31d044b..0000000
--- a/Gemfile
+++ /dev/null
@@ -1,7 +0,0 @@
-source "http://rubygems.org"
-
-gem "cucumber"
-gem "rake"
-gem "osmlib-base"
-gem "sys-proctable"
-gem "rspec-expectations"
diff --git a/Gemfile.lock b/Gemfile.lock
deleted file mode 100644
index 3363e92..0000000
--- a/Gemfile.lock
+++ /dev/null
@@ -1,35 +0,0 @@
-GEM
-  remote: http://rubygems.org/
-  specs:
-    builder (3.2.2)
-    cucumber (2.0.0)
-      builder (>= 2.1.2)
-      cucumber-core (~> 1.1.3)
-      diff-lcs (>= 1.1.3)
-      gherkin (~> 2.12)
-      multi_json (>= 1.7.5, < 2.0)
-      multi_test (>= 0.1.2)
-    cucumber-core (1.1.3)
-      gherkin (~> 2.12.0)
-    diff-lcs (1.2.5)
-    gherkin (2.12.2)
-      multi_json (~> 1.3)
-    multi_json (1.11.0)
-    multi_test (0.1.2)
-    osmlib-base (0.1.4)
-    rake (10.4.2)
-    rspec-expectations (3.2.1)
-      diff-lcs (>= 1.2.0, < 2.0)
-      rspec-support (~> 3.2.0)
-    rspec-support (3.2.2)
-    sys-proctable (0.9.8)
-
-PLATFORMS
-  ruby
-
-DEPENDENCIES
-  cucumber
-  osmlib-base
-  rake
-  rspec-expectations
-  sys-proctable
diff --git a/LICENCE.TXT b/LICENCE.TXT
index c77e5cd..143580e 100644
--- a/LICENCE.TXT
+++ b/LICENCE.TXT
@@ -1,4 +1,4 @@
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
diff --git a/Rakefile b/Rakefile
deleted file mode 100644
index 1c848bb..0000000
--- a/Rakefile
+++ /dev/null
@@ -1,190 +0,0 @@
-require 'OSM/StreamParser'
-require 'socket'
-require 'digest/sha1'
-require 'cucumber/rake/task'
-require 'sys/proctable'
-
-BUILD_FOLDER = 'build'
-DATA_FOLDER = 'sandbox'
-PROFILE = 'bicycle'
-OSRM_PORT = 5000
-PROFILES_FOLDER = '../profiles'
-
-Cucumber::Rake::Task.new do |t|
-  t.cucumber_opts = %w{--format pretty}
-end
-
-areas = {
-  :kbh => { :country => 'denmark', :bbox => 'top=55.6972 left=12.5222 right=12.624 bottom=55.6376' },
-  :frd => { :country => 'denmark', :bbox => 'top=55.7007 left=12.4765 bottom=55.6576 right=12.5698' },
-  :regh => { :country => 'denmark', :bbox => 'top=56.164 left=11.792 bottom=55.403 right=12.731' },
-  :denmark => { :country => 'denmark', :bbox => nil },
-  :skaane => { :country => 'sweden', :bbox => 'top=56.55 left=12.4 bottom=55.3 right=14.6' }
-}
-
-
-
-osm_data_area_name = ARGV[1] ? ARGV[1].to_s.to_sym : :kbh
-raise "Unknown data area." unless areas[osm_data_area_name]
-osm_data_country = areas[osm_data_area_name][:country]
-osm_data_area_bbox = areas[osm_data_area_name][:bbox]
-
-
-task osm_data_area_name.to_sym {}   #define empty task to prevent rake from whining. will break if area has same name as a task
-
-
-def each_process name, &block
-  Sys::ProcTable.ps do |process|
-    if process.comm.strip == name.strip && process.state != 'zombie'
-      yield process.pid.to_i, process.state.strip
-    end
-  end
-end
-
-def up?
-  find_pid('osrm-routed') != nil
-end
-
-def find_pid name
-  each_process(name) { |pid,state| return pid.to_i }
-  return nil
-end
-
-def wait_for_shutdown name
-  timeout = 10
-  (timeout*10).times do
-    return if find_pid(name) == nil
-    sleep 0.1
-  end
-  raise "*** Could not terminate #{name}."
-end
-
-
-desc "Rebuild and run tests."
-task :default => [:build]
-
-desc "Build using CMake."
-task :build do
-  if Dir.exists? BUILD_FOLDER
-    Dir.chdir BUILD_FOLDER do
-      system "make"
-    end
-  else
-    system "mkdir build; cd build; cmake ..; make"
-  end
-end
-
-desc "Setup config files."
-task :setup do
-end
-
-desc "Download OSM data."
-task :download do
-  Dir.mkdir "#{DATA_FOLDER}" unless File.exist? "#{DATA_FOLDER}"
-  puts "Downloading..."
-  puts "curl http://download.geofabrik.de/europe/#{osm_data_country}-latest.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf"
-  raise "Error while downloading data." unless system "curl http://download.geofabrik.de/europe/#{osm_data_country}-latest.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf"
-  if osm_data_area_bbox
-    puts "Cropping and converting to protobuffer..."
-    raise "Error while cropping data." unless system "osmosis --read-pbf file=#{DATA_FOLDER}/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=#{DATA_FOLDER}/#{osm_data_area_name}.osm.pbf omitmetadata=true"
-  end
-end
-
-desc "Crop OSM data"
-task :crop do
-  if osm_data_area_bbox
-    raise "Error while cropping data." unless system "osmosis --read-pbf file=#{DATA_FOLDER}/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=#{DATA_FOLDER}/#{osm_data_area_name}.osm.pbf omitmetadata=true"
-  end
-end
-
-desc "Reprocess OSM data."
-task :process => [:extract,:prepare] do
-end
-
-desc "Extract OSM data."
-task :extract do
-  Dir.chdir DATA_FOLDER do
-    raise "Error while extracting data." unless system "../#{BUILD_FOLDER}/osrm-extract #{osm_data_area_name}.osm.pbf --profile ../profiles/#{PROFILE}.lua"
-  end
-end
-
-desc "Prepare OSM data."
-task :prepare do
-  Dir.chdir DATA_FOLDER do
-    raise "Error while preparing data." unless system "../#{BUILD_FOLDER}/osrm-prepare #{osm_data_area_name}.osrm --profile ../profiles/#{PROFILE}.lua"
-  end
-end
-
-desc "Delete preprocessing files."
-task :clean do
-  File.delete *Dir.glob("#{DATA_FOLDER}/*.osrm")
-  File.delete *Dir.glob("#{DATA_FOLDER}/*.osrm.*")
-end
-
-desc "Run all cucumber test"
-task :test do
-  system "cucumber"
-  puts
-end
-
-desc "Run the routing server in the terminal. Press Ctrl-C to stop."
-task :run do
-  Dir.chdir DATA_FOLDER do
-    system "../#{BUILD_FOLDER}/osrm-routed #{osm_data_area_name}.osrm --port #{OSRM_PORT}"
-  end
-end
-
-desc "Launch the routing server in the background. Use rake:down to stop it."
-task :up do
-  Dir.chdir DATA_FOLDER do
-    abort("Already up.") if up?
-    pipe = IO.popen("../#{BUILD_FOLDER}/osrm-routed #{osm_data_area_name}.osrm --port #{OSRM_PORT} 1>>osrm-routed.log 2>>osrm-routed.log")
-    timeout = 5
-    (timeout*10).times do
-      begin
-        socket = TCPSocket.new('localhost', OSRM_PORT)
-        socket.puts 'ping'
-      rescue Errno::ECONNREFUSED
-        sleep 0.1
-      end
-    end
-  end
-end
-
-desc "Stop the routing server."
-task :down do
-  pid = find_pid 'osrm-routed'
-  if pid
-    Process.kill 'TERM', pid
-  else
-    puts "Already down."
-  end 
-end
-
-desc "Kill all osrm-extract, osrm-prepare and osrm-routed processes."
-task :kill do
-  each_process('osrm-routed') { |pid,state| Process.kill 'KILL', pid }
-  each_process('osrm-prepare') { |pid,state| Process.kill 'KILL', pid }
-  each_process('osrm-extract') { |pid,state| Process.kill 'KILL', pid }
-  wait_for_shutdown 'osrm-routed'
-  wait_for_shutdown 'osrm-prepare'
-  wait_for_shutdown 'osrm-extract'  
-end
-
-desc "Get PIDs of all osrm-extract, osrm-prepare and osrm-routed processes."
-task :pid do
-  each_process 'osrm-routed' do |pid,state|
-    puts "#{pid}\t#{state}"
-  end
-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/algorithms/bfs_components.hpp b/algorithms/bfs_components.hpp
deleted file mode 100644
index b3f5364..0000000
--- a/algorithms/bfs_components.hpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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/coordinate_calculation.cpp b/algorithms/coordinate_calculation.cpp
deleted file mode 100644
index ff7626e..0000000
--- a/algorithms/coordinate_calculation.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "coordinate_calculation.hpp"
-
-#include "../util/mercator.hpp"
-#include "../util/string_util.hpp"
-
-#include <boost/assert.hpp>
-
-#include <osrm/coordinate.hpp>
-
-#include <cmath>
-
-#include <limits>
-
-namespace
-{
-constexpr static const float RAD = 0.017453292519943295769236907684886f;
-// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
-// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
-constexpr static const float earth_radius = 6372797.560856f;
-}
-
-namespace coordinate_calculation
-{
-
-double haversine_distance(const int lat1,
-                                                     const int lon1,
-                                                     const int lat2,
-                                                     const int lon2)
-{
-    BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
-    BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
-    BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
-    BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
-    const double lt1 = lat1 / COORDINATE_PRECISION;
-    const double ln1 = lon1 / COORDINATE_PRECISION;
-    const double lt2 = lat2 / COORDINATE_PRECISION;
-    const double ln2 = lon2 / COORDINATE_PRECISION;
-    const double dlat1 = lt1 * (RAD);
-
-    const double dlong1 = ln1 * (RAD);
-    const double dlat2 = lt2 * (RAD);
-    const double dlong2 = ln2 * (RAD);
-
-    const double dLong = dlong1 - dlong2;
-    const double dLat = dlat1 - dlat2;
-
-    const double aHarv = std::pow(std::sin(dLat / 2.0), 2.0) +
-                         std::cos(dlat1) * std::cos(dlat2) * std::pow(std::sin(dLong / 2.), 2);
-    const double cHarv = 2. * std::atan2(std::sqrt(aHarv), std::sqrt(1.0 - aHarv));
-    return earth_radius * cHarv;
-}
-
-double haversine_distance(const FixedPointCoordinate &coordinate_1,
-                                                     const FixedPointCoordinate &coordinate_2)
-{
-    return haversine_distance(coordinate_1.lat, coordinate_1.lon, coordinate_2.lat,
-                                 coordinate_2.lon);
-}
-
-float great_circle_distance(const FixedPointCoordinate &coordinate_1,
-                                                 const FixedPointCoordinate &coordinate_2)
-{
-    return great_circle_distance(coordinate_1.lat, coordinate_1.lon, coordinate_2.lat,
-                              coordinate_2.lon);
-}
-
-float great_circle_distance(const int lat1,
-                                                 const int lon1,
-                                                 const int lat2,
-                                                 const int lon2)
-{
-    BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
-    BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
-    BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
-    BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
-
-    const float float_lat1 = (lat1 / COORDINATE_PRECISION) * RAD;
-    const float float_lon1 = (lon1 / COORDINATE_PRECISION) * RAD;
-    const float float_lat2 = (lat2 / COORDINATE_PRECISION) * RAD;
-    const float float_lon2 = (lon2 / COORDINATE_PRECISION) * RAD;
-
-    const float x_value = (float_lon2 - float_lon1) * std::cos((float_lat1 + float_lat2) / 2.f);
-    const float y_value = float_lat2 - float_lat1;
-    return std::hypot(x_value, y_value) * earth_radius;
-}
-
-float perpendicular_distance(const FixedPointCoordinate &source_coordinate,
-                                                     const FixedPointCoordinate &target_coordinate,
-                                                     const FixedPointCoordinate &query_location)
-{
-    float ratio;
-    FixedPointCoordinate nearest_location;
-
-    return perpendicular_distance(source_coordinate, target_coordinate, query_location,
-                                  nearest_location, ratio);
-}
-
-float perpendicular_distance(const FixedPointCoordinate &segment_source,
-                                                     const FixedPointCoordinate &segment_target,
-                                                     const FixedPointCoordinate &query_location,
-                                                     FixedPointCoordinate &nearest_location,
-                                                     float &ratio)
-{
-    return perpendicular_distance_from_projected_coordinate(
-        segment_source, segment_target, query_location,
-        {mercator::lat2y(query_location.lat / COORDINATE_PRECISION),
-         query_location.lon / COORDINATE_PRECISION},
-        nearest_location, ratio);
-}
-
-float perpendicular_distance_from_projected_coordinate(
-    const FixedPointCoordinate &source_coordinate,
-    const FixedPointCoordinate &target_coordinate,
-    const FixedPointCoordinate &query_location,
-    const std::pair<double, double> &projected_coordinate)
-{
-    float ratio;
-    FixedPointCoordinate nearest_location;
-
-    return perpendicular_distance_from_projected_coordinate(source_coordinate, target_coordinate,
-                                                            query_location, projected_coordinate,
-                                                            nearest_location, ratio);
-}
-
-float perpendicular_distance_from_projected_coordinate(
-    const FixedPointCoordinate &segment_source,
-    const FixedPointCoordinate &segment_target,
-    const FixedPointCoordinate &query_location,
-    const std::pair<double, double> &projected_coordinate,
-    FixedPointCoordinate &nearest_location,
-    float &ratio)
-{
-    BOOST_ASSERT(query_location.is_valid());
-
-    // initialize values
-    const double x = projected_coordinate.first;
-    const double y = projected_coordinate.second;
-    const double a = mercator::lat2y(segment_source.lat / COORDINATE_PRECISION);
-    const double b = segment_source.lon / COORDINATE_PRECISION;
-    const double c = mercator::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 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);
-    }
-    else
-    {
-        p = c;
-        q = y;
-    }
-    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 =
-        static_cast<float>((p - nY * a) / c); // These values are actually n/m+n and m/m+n , we need
-    // not calculate the explicit values of m an n as we
-    // are just interested in the ratio
-    if (std::isnan(ratio))
-    {
-        ratio = (segment_target == query_location ? 1.f : 0.f);
-    }
-    else if (std::abs(ratio) <= std::numeric_limits<float>::epsilon())
-    {
-        ratio = 0.f;
-    }
-    else if (std::abs(ratio - 1.f) <= std::numeric_limits<float>::epsilon())
-    {
-        ratio = 1.f;
-    }
-
-    // compute nearest location
-    BOOST_ASSERT(!std::isnan(ratio));
-    if (ratio <= 0.f)
-    {
-        nearest_location = segment_source;
-    }
-    else if (ratio >= 1.f)
-    {
-        nearest_location = segment_target;
-    }
-    else
-    {
-        // point lies in between
-        nearest_location.lat = static_cast<int>(mercator::y2lat(p) * COORDINATE_PRECISION);
-        nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
-    }
-    BOOST_ASSERT(nearest_location.is_valid());
-
-    const float approximate_distance =
-        great_circle_distance(query_location, nearest_location);
-    BOOST_ASSERT(0.f <= approximate_distance);
-    return approximate_distance;
-}
-
-void lat_or_lon_to_string(const int value, std::string &output)
-{
-    char buffer[12];
-    buffer[11] = 0; // zero termination
-    output = printInt<11, 6>(buffer, value);
-}
-
-float deg_to_rad(const float degree)
-{
-    return degree * (static_cast<float>(M_PI) / 180.f);
-}
-
-float rad_to_deg(const float radian)
-{
-    return radian * (180.f * static_cast<float>(M_1_PI));
-}
-
-float bearing(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_delta = deg_to_rad(lon_diff);
-    const float lat1 = deg_to_rad(first_coordinate.lat / COORDINATE_PRECISION);
-    const float lat2 = deg_to_rad(second_coordinate.lat / COORDINATE_PRECISION);
-    const float y = std::sin(lon_delta) * std::cos(lat2);
-    const float x =
-        std::cos(lat1) * std::sin(lat2) - std::sin(lat1) * std::cos(lat2) * std::cos(lon_delta);
-    float result = rad_to_deg(std::atan2(y, x));
-    while (result < 0.f)
-    {
-        result += 360.f;
-    }
-
-    while (result >= 360.f)
-    {
-        result -= 360.f;
-    }
-    return result;
-}
-
-}
diff --git a/algorithms/coordinate_calculation.hpp b/algorithms/coordinate_calculation.hpp
deleted file mode 100644
index 80ec7c2..0000000
--- a/algorithms/coordinate_calculation.hpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 COORDINATE_CALCULATION
-#define COORDINATE_CALCULATION
-
-struct FixedPointCoordinate;
-
-#include <string>
-#include <utility>
-
-namespace coordinate_calculation
-{
-    double
-    haversine_distance(const int lat1, const int lon1, const int lat2, const int lon2);
-
-    double haversine_distance(const FixedPointCoordinate &first_coordinate,
-                                 const FixedPointCoordinate &second_coordinate);
-
-    float great_circle_distance(const FixedPointCoordinate &first_coordinate,
-                             const FixedPointCoordinate &second_coordinate);
-
-    float great_circle_distance(const int lat1, const int lon1, const int lat2, const int lon2);
-
-    void lat_or_lon_to_string(const int value, std::string &output);
-
-    float perpendicular_distance(const FixedPointCoordinate &segment_source,
-                                 const FixedPointCoordinate &segment_target,
-                                 const FixedPointCoordinate &query_location);
-
-    float perpendicular_distance(const FixedPointCoordinate &segment_source,
-                                 const FixedPointCoordinate &segment_target,
-                                 const FixedPointCoordinate &query_location,
-                                 FixedPointCoordinate &nearest_location,
-                                 float &ratio);
-
-    float perpendicular_distance_from_projected_coordinate(
-        const FixedPointCoordinate &segment_source,
-        const FixedPointCoordinate &segment_target,
-        const FixedPointCoordinate &query_location,
-        const std::pair<double, double> &projected_coordinate);
-
-    float perpendicular_distance_from_projected_coordinate(
-        const FixedPointCoordinate &segment_source,
-        const FixedPointCoordinate &segment_target,
-        const FixedPointCoordinate &query_location,
-        const std::pair<double, double> &projected_coordinate,
-        FixedPointCoordinate &nearest_location,
-        float &ratio);
-
-    float deg_to_rad(const float degree);
-    float rad_to_deg(const float radian);
-
-    float bearing(const FixedPointCoordinate &first_coordinate,
-                  const FixedPointCoordinate &second_coordinate);
-}
-
-#endif // COORDINATE_CALCULATION
diff --git a/algorithms/douglas_peucker.cpp b/algorithms/douglas_peucker.cpp
deleted file mode 100644
index 280c90f..0000000
--- a/algorithms/douglas_peucker.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "douglas_peucker.hpp"
-
-#include "../data_structures/segment_information.hpp"
-
-#include <boost/assert.hpp>
-#include <osrm/coordinate.hpp>
-
-#include <cmath>
-#include <algorithm>
-#include <iterator>
-
-namespace
-{
-struct CoordinatePairCalculator
-{
-    CoordinatePairCalculator() = delete;
-    CoordinatePairCalculator(const FixedPointCoordinate &coordinate_a,
-                             const FixedPointCoordinate &coordinate_b)
-    {
-        // initialize distance calculator with two fixed coordinates a, b
-        const float RAD = 0.017453292519943295769236907684886f;
-        first_lat = (coordinate_a.lat / COORDINATE_PRECISION) * RAD;
-        first_lon = (coordinate_a.lon / COORDINATE_PRECISION) * RAD;
-        second_lat = (coordinate_b.lat / COORDINATE_PRECISION) * RAD;
-        second_lon = (coordinate_b.lon / COORDINATE_PRECISION) * RAD;
-    }
-
-    int operator()(FixedPointCoordinate &other) const
-    {
-        // set third coordinate c
-        const float RAD = 0.017453292519943295769236907684886f;
-        const float earth_radius = 6372797.560856f;
-        const float float_lat1 = (other.lat / COORDINATE_PRECISION) * RAD;
-        const float float_lon1 = (other.lon / COORDINATE_PRECISION) * RAD;
-
-        // compute distance (a,c)
-        const float x_value_1 = (first_lon - float_lon1) * cos((float_lat1 + first_lat) / 2.f);
-        const float y_value_1 = first_lat - float_lat1;
-        const float dist1 = std::hypot(x_value_1, y_value_1) * earth_radius;
-
-        // compute distance (b,c)
-        const float x_value_2 = (second_lon - float_lon1) * cos((float_lat1 + second_lat) / 2.f);
-        const float y_value_2 = second_lat - float_lat1;
-        const float dist2 = std::hypot(x_value_2, y_value_2) * earth_radius;
-
-        // return the minimum
-        return static_cast<int>(std::min(dist1, dist2));
-    }
-
-    float first_lat;
-    float first_lon;
-    float second_lat;
-    float second_lon;
-};
-}
-
-void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level)
-{
-    Run(std::begin(input_geometry), std::end(input_geometry), zoom_level);
-}
-
-void DouglasPeucker::Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level)
-{
-    const auto size = std::distance(begin, end);
-    if (size < 2)
-    {
-        return;
-    }
-
-    begin->necessary = true;
-    std::prev(end)->necessary = true;
-
-    {
-        BOOST_ASSERT_MSG(zoom_level < DOUGLAS_PEUCKER_THRESHOLDS.size(), "unsupported zoom level");
-        auto left_border = begin;
-        auto 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 (right_border->necessary)
-            {
-                // sanity checks
-                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 != end);
-    }
-
-    // mark locations as 'necessary' by divide-and-conquer
-    while (!recursion_stack.empty())
-    {
-        // pop next element
-        const GeometryRange pair = recursion_stack.top();
-        recursion_stack.pop();
-        // sanity checks
-        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;
-        auto farthest_entry_it = pair.second;
-        const CoordinatePairCalculator dist_calc(pair.first->location, pair.second->location);
-
-        // sweep over range to find the maximum
-        for (auto it = std::next(pair.first); it != pair.second; ++it)
-        {
-            const int distance = dist_calc(it->location);
-            // found new feasible maximum?
-            if (distance > max_int_distance && distance > DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
-            {
-                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])
-        {
-            //  mark idx as necessary
-            farthest_entry_it->necessary = true;
-            if (1 < std::distance(pair.first, farthest_entry_it))
-            {
-                recursion_stack.emplace(pair.first, farthest_entry_it);
-            }
-            if (1 < std::distance(farthest_entry_it, pair.second))
-            {
-                recursion_stack.emplace(farthest_entry_it, pair.second);
-            }
-        }
-    }
-}
diff --git a/algorithms/douglas_peucker.hpp b/algorithms/douglas_peucker.hpp
deleted file mode 100644
index da02982..0000000
--- a/algorithms/douglas_peucker.hpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-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 DOUGLAS_PEUCKER_HPP_
-#define DOUGLAS_PEUCKER_HPP_
-
-#include "../data_structures/segment_information.hpp"
-
-#include <array>
-#include <stack>
-#include <utility>
-#include <vector>
-
-/* This class object computes the bitvector of indicating generalized input
- * points according to the (Ramer-)Douglas-Peucker algorithm.
- *
- * Input is vector of pairs. Each pair consists of the point information and a
- * bit indicating if the points is present in the generalization.
- * Note: points may also be pre-selected*/
-
-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
-{
-  public:
-    using RandomAccessIt = std::vector<SegmentInformation>::iterator;
-
-    using GeometryRange = std::pair<RandomAccessIt, RandomAccessIt>;
-    // Stack to simulate the recursion
-    std::stack<GeometryRange> recursion_stack;
-
-  public:
-    void Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level);
-    void Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level);
-};
-
-#endif /* DOUGLAS_PEUCKER_HPP_ */
diff --git a/algorithms/geospatial_query.hpp b/algorithms/geospatial_query.hpp
deleted file mode 100644
index 96b4fc5..0000000
--- a/algorithms/geospatial_query.hpp
+++ /dev/null
@@ -1,180 +0,0 @@
-#ifndef GEOSPATIAL_QUERY_HPP
-#define GEOSPATIAL_QUERY_HPP
-
-#include "coordinate_calculation.hpp"
-#include "../typedefs.h"
-#include "../data_structures/phantom_node.hpp"
-#include "../util/bearing.hpp"
-
-#include <osrm/coordinate.hpp>
-
-#include <vector>
-#include <memory>
-#include <algorithm>
-
-// Implements complex queries on top of an RTree and builds PhantomNodes from it.
-//
-// Only holds a weak reference on the RTree!
-template <typename RTreeT> class GeospatialQuery
-{
-    using EdgeData = typename RTreeT::EdgeData;
-    using CoordinateList = typename RTreeT::CoordinateList;
-
-  public:
-    GeospatialQuery(RTreeT &rtree_, std::shared_ptr<CoordinateList> coordinates_)
-        : rtree(rtree_), coordinates(coordinates_)
-    {
-    }
-
-    // Returns nearest PhantomNodes in the given bearing range within max_distance.
-    // Does not filter by small/big component!
-    std::vector<PhantomNodeWithDistance>
-    NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate,
-                               const float max_distance,
-                               const int bearing = 0,
-                               const int bearing_range = 180)
-    {
-        auto results =
-            rtree.Nearest(input_coordinate,
-                          [this, bearing, bearing_range, max_distance](const EdgeData &data)
-                          {
-                              return checkSegmentBearing(data, bearing, bearing_range);
-                          },
-                          [max_distance](const std::size_t, const float min_dist)
-                          {
-                              return min_dist > max_distance;
-                          });
-
-        return MakePhantomNodes(input_coordinate, results);
-    }
-
-    // Returns max_results nearest PhantomNodes in the given bearing range.
-    // Does not filter by small/big component!
-    std::vector<PhantomNodeWithDistance>
-    NearestPhantomNodes(const FixedPointCoordinate &input_coordinate,
-                        const unsigned max_results,
-                        const int bearing = 0,
-                        const int bearing_range = 180)
-    {
-        auto results = rtree.Nearest(input_coordinate,
-                                     [this, bearing, bearing_range](const EdgeData &data)
-                                     {
-                                         return checkSegmentBearing(data, bearing, bearing_range);
-                                     },
-                                     [max_results](const std::size_t num_results, const float)
-                                     {
-                                         return num_results >= max_results;
-                                     });
-
-        return MakePhantomNodes(input_coordinate, results);
-    }
-
-    // Returns the nearest phantom node. If this phantom node is not from a big component
-    // a second phantom node is return that is the nearest coordinate in a big component.
-    std::pair<PhantomNode, PhantomNode>
-    NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate,
-                                                      const int bearing = 0,
-                                                      const int bearing_range = 180)
-    {
-        bool has_small_component = false;
-        bool has_big_component = false;
-        auto results = rtree.Nearest(
-            input_coordinate,
-            [this, bearing, bearing_range, &has_big_component,
-             &has_small_component](const EdgeData &data)
-            {
-                auto use_segment =
-                    (!has_small_component || (!has_big_component && !data.component.is_tiny));
-                auto use_directions = std::make_pair(use_segment, use_segment);
-
-                if (use_segment)
-                {
-                    use_directions = checkSegmentBearing(data, bearing, bearing_range);
-                    if (use_directions.first || use_directions.second)
-                    {
-                        has_big_component = has_big_component || !data.component.is_tiny;
-                        has_small_component = has_small_component || data.component.is_tiny;
-                    }
-                }
-
-                return use_directions;
-            },
-            [&has_big_component](const std::size_t num_results, const float)
-            {
-                return num_results > 0 && has_big_component;
-            });
-
-        if (results.size() == 0)
-        {
-            return std::make_pair(PhantomNode{}, PhantomNode{});
-        }
-
-        BOOST_ASSERT(results.size() > 0);
-        return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
-                              MakePhantomNode(input_coordinate, results.back()).phantom_node);
-    }
-
-  private:
-    std::vector<PhantomNodeWithDistance>
-    MakePhantomNodes(const FixedPointCoordinate &input_coordinate,
-                     const std::vector<EdgeData> &results) const
-    {
-        std::vector<PhantomNodeWithDistance> distance_and_phantoms(results.size());
-        std::transform(results.begin(), results.end(), distance_and_phantoms.begin(),
-                       [this, &input_coordinate](const EdgeData &data)
-                       {
-                           return MakePhantomNode(input_coordinate, data);
-                       });
-        return distance_and_phantoms;
-    }
-
-    PhantomNodeWithDistance MakePhantomNode(const FixedPointCoordinate &input_coordinate,
-                                                   const EdgeData &data) const
-    {
-        FixedPointCoordinate point_on_segment;
-        float ratio;
-        const auto current_perpendicular_distance = coordinate_calculation::perpendicular_distance(
-            coordinates->at(data.u), coordinates->at(data.v), input_coordinate, point_on_segment,
-            ratio);
-
-        auto transformed =
-            PhantomNodeWithDistance { PhantomNode{data, point_on_segment}, current_perpendicular_distance };
-
-        ratio = std::min(1.f, std::max(0.f, ratio));
-
-        if (SPECIAL_NODEID != transformed.phantom_node.forward_node_id)
-        {
-            transformed.phantom_node.forward_weight *= ratio;
-        }
-        if (SPECIAL_NODEID != transformed.phantom_node.reverse_node_id)
-        {
-            transformed.phantom_node.reverse_weight *= 1.f - ratio;
-        }
-        return transformed;
-    }
-
-    std::pair<bool, bool> checkSegmentBearing(const EdgeData &segment,
-                                              const float filter_bearing,
-                                              const float filter_bearing_range)
-    {
-        const float forward_edge_bearing =
-            coordinate_calculation::bearing(coordinates->at(segment.u), coordinates->at(segment.v));
-
-        const float backward_edge_bearing = (forward_edge_bearing + 180) > 360
-                                                ? (forward_edge_bearing - 180)
-                                                : (forward_edge_bearing + 180);
-
-        const bool forward_bearing_valid =
-            bearing::CheckInBounds(forward_edge_bearing, filter_bearing, filter_bearing_range) &&
-            segment.forward_edge_based_node_id != SPECIAL_NODEID;
-        const bool backward_bearing_valid =
-            bearing::CheckInBounds(backward_edge_bearing, filter_bearing, filter_bearing_range) &&
-            segment.reverse_edge_based_node_id != SPECIAL_NODEID;
-        return std::make_pair(forward_bearing_valid, backward_bearing_valid);
-    }
-
-    RTreeT &rtree;
-    const std::shared_ptr<CoordinateList> coordinates;
-};
-
-#endif
diff --git a/algorithms/graph_compressor.hpp b/algorithms/graph_compressor.hpp
deleted file mode 100644
index 8096a92..0000000
--- a/algorithms/graph_compressor.hpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-
-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 GEOMETRY_COMPRESSOR_HPP
-#define GEOMETRY_COMPRESSOR_HPP
-
-#include "../typedefs.h"
-
-#include "../extractor/speed_profile.hpp"
-#include "../data_structures/node_based_graph.hpp"
-
-#include <memory>
-#include <unordered_set>
-
-class CompressedEdgeContainer;
-class RestrictionMap;
-
-class GraphCompressor
-{
-    using EdgeData = NodeBasedDynamicGraph::EdgeData;
-
-public:
-  GraphCompressor(SpeedProfileProperties speed_profile);
-
-    void Compress(const std::unordered_set<NodeID>& barrier_nodes,
-                  const std::unordered_set<NodeID>& traffic_lights,
-                  RestrictionMap& restriction_map,
-                  NodeBasedDynamicGraph& graph,
-                  CompressedEdgeContainer& geometry_compressor);
-private:
-
-   void PrintStatistics(unsigned original_number_of_nodes,
-                        unsigned original_number_of_edges,
-                        const NodeBasedDynamicGraph& graph) const;
-
-    SpeedProfileProperties speed_profile;
-};
-
-#endif
diff --git a/algorithms/object_encoder.hpp b/algorithms/object_encoder.hpp
deleted file mode 100644
index 581b396..0000000
--- a/algorithms/object_encoder.hpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 <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 <iterator>
-#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 = reinterpret_cast<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)));
-        std::replace(begin(encoded), end(encoded), '+', '-');
-        std::replace(begin(encoded), end(encoded), '/', '_');
-    }
-
-    template <class ObjectT> static void DecodeFromBase64(const std::string &input, ObjectT &object)
-    {
-        try
-        {
-            std::string encoded(input);
-            std::replace(begin(encoded), end(encoded), '-', '+');
-            std::replace(begin(encoded), end(encoded), '_', '/');
-
-            std::copy(binary_t(encoded.begin()), binary_t(encoded.begin() + encoded.length()),
-                      reinterpret_cast<char *>(&object));
-        }
-        catch (...)
-        {
-        }
-    }
-};
-
-#endif /* OBJECT_ENCODER_HPP */
diff --git a/algorithms/polyline_compressor.cpp b/algorithms/polyline_compressor.cpp
deleted file mode 100644
index 0db75dc..0000000
--- a/algorithms/polyline_compressor.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 "polyline_compressor.hpp"
-#include "../data_structures/segment_information.hpp"
-
-#include <osrm/coordinate.hpp>
-
-std::string PolylineCompressor::encode_vector(std::vector<int> &numbers) const
-{
-    std::string output;
-    const auto end = numbers.size();
-    for (std::size_t i = 0; i < end; ++i)
-    {
-        numbers[i] <<= 1;
-        if (numbers[i] < 0)
-        {
-            numbers[i] = ~(numbers[i]);
-        }
-    }
-    for (const int number : numbers)
-    {
-        output += encode_number(number);
-    }
-    return output;
-}
-
-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;
-        output += static_cast<char>(next_value);
-        number_to_encode >>= 5;
-    }
-
-    number_to_encode += 63;
-    output += static_cast<char>(number_to_encode);
-    return output;
-}
-
-std::string
-PolylineCompressor::get_encoded_string(const std::vector<SegmentInformation> &polyline) const
-{
-    if (polyline.empty())
-    {
-        return {};
-    }
-
-    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)
-        {
-            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 encode_vector(delta_numbers);
-}
-
-std::vector<FixedPointCoordinate> PolylineCompressor::decode_string(const std::string &geometry_string) const
-{
-    std::vector<FixedPointCoordinate> new_coordinates;
-    int index = 0, len = geometry_string.size();
-    int lat = 0, lng = 0;
-  
-    while (index < len) 
-    {
-        int b, shift = 0, result = 0;
-        do 
-        {
-            b = geometry_string.at(index++) - 63;
-            result |= (b & 0x1f) << shift;
-            shift += 5;
-        } while (b >= 0x20);
-        int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
-        lat += dlat;
-
-        shift = 0;
-        result = 0;
-        do 
-        {
-            b = geometry_string.at(index++) - 63;
-            result |= (b & 0x1f) << shift;
-            shift += 5;
-        } while (b >= 0x20);
-        int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
-        lng += dlng;
-
-        FixedPointCoordinate p;
-        p.lat = COORDINATE_PRECISION * (((double) lat / 1E6));
-        p.lon = COORDINATE_PRECISION * (((double) lng / 1E6));
-        new_coordinates.push_back(p);
-    }
-
-    return new_coordinates;
-}
diff --git a/algorithms/polyline_compressor.hpp b/algorithms/polyline_compressor.hpp
deleted file mode 100644
index a148200..0000000
--- a/algorithms/polyline_compressor.hpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-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 POLYLINECOMPRESSOR_H_
-#define POLYLINECOMPRESSOR_H_
-
-struct SegmentInformation;
-
-#include <osrm/coordinate.hpp>
-
-#include <string>
-#include <vector>
-
-class PolylineCompressor
-{
-  private:
-    std::string encode_vector(std::vector<int> &numbers) const;
-
-    std::string encode_number(const int number_to_encode) const;
-
-  public:
-    std::string get_encoded_string(const std::vector<SegmentInformation> &polyline) const;
-    
-    std::vector<FixedPointCoordinate> decode_string(const std::string &geometry_string) const;
-};
-
-#endif /* POLYLINECOMPRESSOR_H_ */
diff --git a/algorithms/polyline_formatter.cpp b/algorithms/polyline_formatter.cpp
deleted file mode 100644
index 670a612..0000000
--- a/algorithms/polyline_formatter.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "polyline_formatter.hpp"
-
-#include "polyline_compressor.hpp"
-#include "../data_structures/segment_information.hpp"
-
-#include <osrm/coordinate.hpp>
-
-osrm::json::String
-PolylineFormatter::printEncodedString(const std::vector<SegmentInformation> &polyline) const
-{
-    return osrm::json::String(PolylineCompressor().get_encoded_string(polyline));
-}
-
-osrm::json::Array
-PolylineFormatter::printUnencodedString(const std::vector<SegmentInformation> &polyline) const
-{
-    osrm::json::Array json_geometry_array;
-    for (const auto &segment : polyline)
-    {
-        if (segment.necessary)
-        {
-            osrm::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/route_name_extraction.hpp b/algorithms/route_name_extraction.hpp
deleted file mode 100644
index 00dae89..0000000
--- a/algorithms/route_name_extraction.hpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 EXTRACT_ROUTE_NAMES_H
-#define EXTRACT_ROUTE_NAMES_H
-
-#include <boost/assert.hpp>
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-struct RouteNames
-{
-    std::string shortest_path_name_1;
-    std::string shortest_path_name_2;
-    std::string alternative_path_name_1;
-    std::string alternative_path_name_2;
-};
-
-// construct routes names
-template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
-{
-  private:
-    SegmentT PickNextLongestSegment(const std::vector<SegmentT> &segment_list,
-                                    const unsigned blocked_name_id) const
-    {
-        SegmentT result_segment;
-        result_segment.length = 0;
-
-        for (const SegmentT &segment : segment_list)
-        {
-            if (segment.name_id != blocked_name_id && segment.length > result_segment.length &&
-                segment.name_id != 0)
-            {
-                result_segment = segment;
-            }
-        }
-        return result_segment;
-    }
-
-  public:
-    RouteNames operator()(std::vector<SegmentT> &shortest_path_segments,
-                          std::vector<SegmentT> &alternative_path_segments,
-                          const DataFacadeT *facade) const
-    {
-        RouteNames route_names;
-
-        SegmentT shortest_segment_1, shortest_segment_2;
-        SegmentT alternative_segment_1, alternative_segment_2;
-
-        auto length_comperator = [](const SegmentT &a, const SegmentT &b)
-        {
-            return a.length > b.length;
-        };
-        auto name_id_comperator = [](const SegmentT &a, const SegmentT &b)
-        {
-            return a.name_id < b.name_id;
-        };
-
-        if (shortest_path_segments.empty())
-        {
-            return route_names;
-        }
-
-        // pick the longest segment for the shortest path.
-        std::sort(shortest_path_segments.begin(), shortest_path_segments.end(), length_comperator);
-        shortest_segment_1 = shortest_path_segments[0];
-        if (!alternative_path_segments.empty())
-        {
-            std::sort(alternative_path_segments.begin(), alternative_path_segments.end(),
-                      length_comperator);
-
-            // also pick the longest segment for the alternative path
-            alternative_segment_1 = alternative_path_segments[0];
-        }
-
-        // compute the set difference (for shortest path) depending on names between shortest and
-        // alternative
-        std::vector<SegmentT> shortest_path_set_difference(shortest_path_segments.size());
-        std::sort(shortest_path_segments.begin(), shortest_path_segments.end(), name_id_comperator);
-        std::sort(alternative_path_segments.begin(), alternative_path_segments.end(),
-                  name_id_comperator);
-        std::set_difference(shortest_path_segments.begin(), shortest_path_segments.end(),
-                            alternative_path_segments.begin(), alternative_path_segments.end(),
-                            shortest_path_set_difference.begin(), name_id_comperator);
-
-        std::sort(shortest_path_set_difference.begin(), shortest_path_set_difference.end(),
-                  length_comperator);
-        shortest_segment_2 =
-            PickNextLongestSegment(shortest_path_set_difference, shortest_segment_1.name_id);
-
-        // compute the set difference (for alternative path) depending on names between shortest and
-        // alternative
-        // vectors are still sorted, no need to do again
-        BOOST_ASSERT(std::is_sorted(shortest_path_segments.begin(), shortest_path_segments.end(),
-                                    name_id_comperator));
-        BOOST_ASSERT(std::is_sorted(alternative_path_segments.begin(),
-                                    alternative_path_segments.end(), name_id_comperator));
-
-        std::vector<SegmentT> alternative_path_set_difference(alternative_path_segments.size());
-        std::set_difference(alternative_path_segments.begin(), alternative_path_segments.end(),
-                            shortest_path_segments.begin(), shortest_path_segments.end(),
-                            alternative_path_set_difference.begin(), name_id_comperator);
-
-        std::sort(alternative_path_set_difference.begin(), alternative_path_set_difference.end(),
-                  length_comperator);
-
-        if (!alternative_path_segments.empty())
-        {
-            alternative_segment_2 = PickNextLongestSegment(alternative_path_set_difference,
-                                                           alternative_segment_1.name_id);
-        }
-
-        // move the segments into the order in which they occur.
-        if (shortest_segment_1.position > shortest_segment_2.position)
-        {
-            std::swap(shortest_segment_1, shortest_segment_2);
-        }
-        if (alternative_segment_1.position > alternative_segment_2.position)
-        {
-            std::swap(alternative_segment_1, alternative_segment_2);
-        }
-
-        // fetching names for the selected segments
-        route_names.shortest_path_name_1 = facade->get_name_for_id(shortest_segment_1.name_id);
-        route_names.shortest_path_name_2 = facade->get_name_for_id(shortest_segment_2.name_id);
-
-        route_names.alternative_path_name_1 =
-            facade->get_name_for_id(alternative_segment_1.name_id);
-        route_names.alternative_path_name_2 =
-            facade->get_name_for_id(alternative_segment_2.name_id);
-
-        return route_names;
-    }
-};
-
-#endif // EXTRACT_ROUTE_NAMES_H
diff --git a/appveyor-build.bat b/appveyor-build.bat
index a1e9603..568998b 100644
--- a/appveyor-build.bat
+++ b/appveyor-build.bat
@@ -8,16 +8,39 @@ SET PROJECT_DIR=%CD%
 ECHO PROJECT_DIR^: %PROJECT_DIR%
 ECHO NUMBER_OF_PROCESSORS^: %NUMBER_OF_PROCESSORS%
 ECHO cmake^: && cmake --version
+IF %ERRORLEVEL% NEQ 0 ECHO CMAKE not found GOTO ERROR
+
+FOR /F %%G IN ("--version") DO cmake %%G 2>&1 | findstr /C:"3.5.0" > nul && goto CMAKE_NOT_OK
+GOTO CMAKE_OK
+
+:CMAKE_NOT_OK
+ECHO CMAKE NOT OK - downloading new CMake
+IF NOT EXIST cm.zip powershell Invoke-WebRequest https://cmake.org/files/v3.5/cmake-3.5.1-win32-x86.zip -OutFile $env:PROJECT_DIR\cm.zip
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+IF NOT EXIST cmake-3.5.1-win32-x86 7z -y x cm.zip | %windir%\system32\FIND "ing archive"
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+SET PATH=%PROJECT_DIR%\cmake-3.5.1-win32-x86\bin;%PATH%
+
+:CMAKE_OK
+ECHO CMAKE_OK
+cmake --version
 
 ECHO activating VS command prompt ...
 SET PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH%
 CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
 
 ECHO platform^: %platform%
+
+ECHO cl.exe version
+cl
+ECHO msbuild version
+msbuild /version
+
 :: HARDCODE "x64" as it is uppercase on AppVeyor and download from S3 is case sensitive
 SET DEPSPKG=osrm-deps-win-x64-14.0.7z
 
 :: local development
+ECHO.
 ECHO LOCAL_DEV^: %LOCAL_DEV%
 IF NOT DEFINED LOCAL_DEV SET LOCAL_DEV=0
 IF DEFINED LOCAL_DEV IF %LOCAL_DEV% EQU 1 IF EXIST %DEPSPKG% ECHO skipping deps download && GOTO SKIPDL
@@ -33,27 +56,39 @@ IF %ERRORLEVEL% NEQ 0 GOTO ERROR
 
 IF EXIST osrm-deps ECHO deleting osrm-deps... && RD /S /Q osrm-deps
 IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-IF EXIST build ECHO deletings build dir... && RD /S /Q build
+IF EXIST build ECHO deleting build dir... && RD /S /Q build
 IF %ERRORLEVEL% NEQ 0 GOTO ERROR
 
 7z -y x %DEPSPKG% | %windir%\system32\FIND "ing archive"
 IF %ERRORLEVEL% NEQ 0 GOTO ERROR
 
+::tree osrm-deps
+
 MKDIR build
 IF %ERRORLEVEL% NEQ 0 GOTO ERROR
 cd build
 IF %ERRORLEVEL% NEQ 0 GOTO ERROR
 
-SET OSRMDEPSDIR=%PROJECT_DIR%\osrm-deps
+SET OSRMDEPSDIR=%PROJECT_DIR%/osrm-deps
 set PREFIX=%OSRMDEPSDIR%/libs
 set BOOST_ROOT=%OSRMDEPSDIR%/boost
+set BOOST_LIBRARYDIR=%BOOST_ROOT%/lib
 set TBB_INSTALL_DIR=%OSRMDEPSDIR%/tbb
 set TBB_ARCH_PLATFORM=intel64/vc14
 
+ECHO OSRMDEPSDIR       ^: %OSRMDEPSDIR%
+ECHO PREFIX            ^: %PREFIX%
+ECHO BOOST_ROOT        ^: %BOOST_ROOT%
+ECHO BOOST_LIBRARYDIR  ^: %BOOST_LIBRARYDIR%
+ECHO TBB_INSTALL_DIR   ^: %TBB_INSTALL_DIR%
+ECHO TBB_ARCH_PLATFORM ^: %TBB_ARCH_PLATFORM%
+
+
 ECHO calling cmake ....
 cmake .. ^
 -G "Visual Studio 14 2015 Win64" ^
 -DBOOST_ROOT=%BOOST_ROOT% ^
+-DBOOST_LIBRARYDIR=%BOOST_LIBRARYDIR% ^
 -DBoost_ADDITIONAL_VERSIONS=1.58 ^
 -DBoost_USE_MULTITHREADED=ON ^
 -DBoost_USE_STATIC_LIBS=ON ^
@@ -81,11 +116,14 @@ IF %ERRORLEVEL% NEQ 0 GOTO ERROR
 
 SET PATH=%PROJECT_DIR%\osrm-deps\libs\bin;%PATH%
 
-ECHO running datastructure-tests.exe ...
-%Configuration%\datastructure-tests.exe
+ECHO running engine-tests.exe ...
+%Configuration%\engine-tests.exe
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+ECHO running extractor-tests.exe ...
+%Configuration%\extractor-tests.exe
 IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-ECHO running algorithm-tests.exe ...
-%Configuration%\algorithm-tests.exe
+ECHO running util-tests.exe ...
+%Configuration%\util-tests.exe
 IF %ERRORLEVEL% NEQ 0 GOTO ERROR
 
 IF NOT "%APPVEYOR_REPO_BRANCH%"=="develop" GOTO DONE
diff --git a/appveyor.yml b/appveyor.yml
index b8fb979..b7e09ef 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -25,6 +25,11 @@ artifacts:
 #  - path: osrm_Debug.zip
 #    name: osrm_Debug.zip
 
+branches:
+  only:
+    - master
+    - develop
+
 deploy:
   provider: FTP
   server:
@@ -36,9 +41,3 @@ deploy:
   folder: /
   enable_ssl: true
   active_mode: false
-
-# notifications:
-#   - provider: HipChat
-#     auth_token:
-#       secure: boLE7BjcahdIUxv9jkN7U3F8iOASF+MkhtctlVoWJoo=
-#     room: Directions
diff --git a/benchmarks/static_rtree.cpp b/benchmarks/static_rtree.cpp
deleted file mode 100644
index ebe055c..0000000
--- a/benchmarks/static_rtree.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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/query_node.hpp"
-#include "../data_structures/static_rtree.hpp"
-#include "../data_structures/edge_based_node.hpp"
-#include "../algorithms/geospatial_query.hpp"
-#include "../util/timing_util.hpp"
-
-#include <osrm/coordinate.hpp>
-
-#include <random>
-#include <iostream>
-
-// 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>;
-using BenchQuery = GeospatialQuery<BenchStaticRTree>;
-
-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;
-}
-
-template <typename QueryT>
-void BenchmarkQuery(const std::vector<FixedPointCoordinate> &queries,
-                    const std::string& name,
-                    QueryT query)
-{
-    std::cout << "Running " << name << " with " << queries.size() << " coordinates: " << std::flush;
-
-    TIMER_START(query);
-    for (const auto &q : queries)
-    {
-        auto result = query(q);
-    }
-    TIMER_STOP(query);
-
-    std::cout << "Took " << TIMER_SEC(query) << " seconds "
-              << "(" << TIMER_MSEC(query) << "ms"
-              << ")  ->  " << TIMER_MSEC(query) / queries.size() << " ms/query "
-              << "(" << TIMER_MSEC(query) << "ms"
-              << ")" << std::endl;
-}
-
-void Benchmark(BenchStaticRTree &rtree, BenchQuery &geo_query, 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(lat_udist(mt_rand), lon_udist(mt_rand));
-    }
-
-    BenchmarkQuery(queries, "raw RTree queries (1 result)", [&rtree](const FixedPointCoordinate &q)
-                   {
-                       return rtree.Nearest(q, 1);
-                   });
-    BenchmarkQuery(queries, "raw RTree queries (10 results)",
-                   [&rtree](const FixedPointCoordinate &q)
-                   {
-                       return rtree.Nearest(q, 10);
-                   });
-
-    BenchmarkQuery(queries, "big component alternative queries",
-                   [&geo_query](const FixedPointCoordinate &q)
-                   {
-                       return geo_query.NearestPhantomNodeWithAlternativeFromBigComponent(q);
-                   });
-    BenchmarkQuery(queries, "max distance 1000", [&geo_query](const FixedPointCoordinate &q)
-                   {
-                       return geo_query.NearestPhantomNodesInRange(q, 1000);
-                   });
-    BenchmarkQuery(queries, "PhantomNode query (1 result)", [&geo_query](const FixedPointCoordinate &q)
-                   {
-                       return geo_query.NearestPhantomNodes(q, 1);
-                   });
-    BenchmarkQuery(queries, "PhantomNode query (10 result)", [&geo_query](const FixedPointCoordinate &q)
-                   {
-                       return geo_query.NearestPhantomNodes(q, 10);
-                   });
-}
-
-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);
-    BenchQuery query(rtree, coords);
-
-    Benchmark(rtree, query, 10000);
-
-    return 0;
-}
diff --git a/build-local.bat b/build-local.bat
index b26c415..a90c0aa 100644
--- a/build-local.bat
+++ b/build-local.bat
@@ -11,7 +11,8 @@ SET CONFIGURATION=Release
 FOR /F "tokens=*" %%i in ('git rev-parse --abbrev-ref HEAD') do SET APPVEYOR_REPO_BRANCH=%%i
 ECHO APPVEYOR_REPO_BRANCH^: %APPVEYOR_REPO_BRANCH%
 
-SET PATH=C:\mb\windows-builds-64\tmp-bin\cmake-3.4.0-win32-x86\bin;%PATH%
+::SET PATH=C:\mb\windows-builds-64\tmp-bin\cmake-3.5.0-win32-x86\bin;%PATH%
+SET PATH=C:\mb\windows-builds-64\tmp-bin\cmake-3.5.1-win32-x86\bin;%PATH%
 SET PATH=C:\Program Files\7-Zip;%PATH%
 
 powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted -Force
diff --git a/cmake/CPackDebianConfig.cmake b/cmake/CPackDebianConfig.cmake
index bd434ee..13216dd 100644
--- a/cmake/CPackDebianConfig.cmake
+++ b/cmake/CPackDebianConfig.cmake
@@ -7,15 +7,13 @@ 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}")
+SET(CPACK_PACKAGE_UPSTREAM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
+SET(CPACK_PACKAGE_DEBIAN_REVISION "1")
+SET(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_UPSTREAM_VERSION}-${CPACK_PACKAGE_DEBIAN_REVISION}")
 
 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_SOURCE_PACKAGE_FILE_NAME "${LOWER_PROJECT_NAME}_${CPACK_PACKAGE_UPSTREAM_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.")
 
@@ -27,7 +25,7 @@ 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_VERSION     "${CPACK_PACKAGE_VERSION}")
 SET(CPACK_DEBIAN_PACKAGE_MAINTAINER  "Dennis Luxen <info at project-osrm.org>")
 SET(CPACK_DEBIAN_PACKAGE_PRIORITY    "optional")
 SET(CPACK_DEBIAN_PACKAGE_SECTION     "devel")
@@ -38,7 +36,6 @@ SET(CPACK_DEBIAN_PACKAGE_DEPENDS     "libc6-dev, libbz2-1.0, libstxxl1, libxml2,
 
 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;")
+set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${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/FindLua52.cmake b/cmake/FindLua52.cmake
index d17fbf6..4aeaf94 100644
--- a/cmake/FindLua52.cmake
+++ b/cmake/FindLua52.cmake
@@ -14,7 +14,7 @@
 
 #=============================================================================
 # Copyright 2007-2009 Kitware, Inc.
-# Copyright 2013 for Project-OSRM, Lua5.1 => Lua5.2
+# Copyright 2016 for Project-OSRM, Lua5.1 => Lua5.2
 #
 # Distributed under the OSI-approved BSD License (the "License");
 # see accompanying file Copyright.txt for details.
diff --git a/cmake/FindSTXXL.cmake b/cmake/FindSTXXL.cmake
index 76a2722..473fb6a 100644
--- a/cmake/FindSTXXL.cmake
+++ b/cmake/FindSTXXL.cmake
@@ -24,7 +24,7 @@ FIND_PATH(STXXL_INCLUDE_DIR stxxl.h
 )
 
 FIND_LIBRARY(STXXL_LIBRARY
-  NAMES stxxl
+  NAMES stxxl stxxl_debug
   HINTS
   $ENV{STXXL_DIR}
   PATH_SUFFIXES lib64 lib
diff --git a/cmake/FingerPrint-Config.cmake b/cmake/FingerPrint-Config.cmake
index d36b622..0672b34 100644
--- a/cmake/FingerPrint-Config.cmake
+++ b/cmake/FingerPrint-Config.cmake
@@ -1,10 +1,10 @@
-set(OLDFILE ${OUTPUT_DIR}/util/fingerprint_impl.hpp)
+set(OLDFILE ${OUTPUT_DIR}/include/util/fingerprint_impl.hpp)
 set(NEWFILE ${OLDFILE}.tmp)
-set(INFILE ${SOURCE_DIR}/util/fingerprint_impl.hpp.in)
-file(MD5 ${SOURCE_DIR}/prepare.cpp MD5PREPARE)
-file(MD5 ${SOURCE_DIR}/data_structures/static_rtree.hpp MD5RTREE)
-file(MD5 ${SOURCE_DIR}/util/graph_loader.hpp MD5GRAPH)
-file(MD5 ${SOURCE_DIR}/server/data_structures/internal_datafacade.hpp MD5OBJECTS)
+set(INFILE ${SOURCE_DIR}/include/util/fingerprint_impl.hpp.in)
+file(MD5 ${SOURCE_DIR}/src/tools/contract.cpp MD5PREPARE)
+file(MD5 ${SOURCE_DIR}/include/util/static_rtree.hpp MD5RTREE)
+file(MD5 ${SOURCE_DIR}/include/util/graph_loader.hpp MD5GRAPH)
+file(MD5 ${SOURCE_DIR}/include/engine/datafacade/internal_datafacade.hpp MD5OBJECTS)
 
 CONFIGURE_FILE(${INFILE} ${NEWFILE})
 
diff --git a/cmake/cmake_options_script.py b/cmake/cmake_options_script.py
index 52e943e..8d30604 100644
--- a/cmake/cmake_options_script.py
+++ b/cmake/cmake_options_script.py
@@ -32,13 +32,11 @@ cache_file = "%s/cached_options.txt" % (scriptpath)
 db = None
 if os.access(cache_file, os.R_OK) == 0:
     db = load_db(sys.argv[1])
-    f = open(cache_file, "wb")
-    pickle.dump(db, f)
-    f.close()
+    with open(cache_file, "wb") as f:
+        pickle.dump(db, f)
 else:
-    f = open(cache_file)
-    db = pickle.load(f)
-    f.close()
+    with open(cache_file) as f:
+        db = pickle.load(f)
 
 if db and sys.argv[2] in db:
     for option in db[sys.argv[2]]:
diff --git a/cmake/cmake_uninstall.cmake.in b/cmake/cmake_uninstall.cmake.in
new file mode 100644
index 0000000..2037e36
--- /dev/null
+++ b/cmake/cmake_uninstall.cmake.in
@@ -0,0 +1,21 @@
+if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+  message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+string(REGEX REPLACE "\n" ";" files "${files}")
+foreach(file ${files})
+  message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
+  if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+    exec_program(
+      "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+      OUTPUT_VARIABLE rm_out
+      RETURN_VALUE rm_retval
+      )
+    if(NOT "${rm_retval}" STREQUAL 0)
+      message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
+    endif(NOT "${rm_retval}" STREQUAL 0)
+  else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+    message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
+  endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+endforeach(file)
diff --git a/cmake/pkgconfig.in b/cmake/pkgconfig.in
index 16263bf..92fe403 100644
--- a/cmake/pkgconfig.in
+++ b/cmake/pkgconfig.in
@@ -1,11 +1,11 @@
 prefix=@CMAKE_INSTALL_PREFIX@
-includedir=${prefix}/include
+includedir=${prefix}/include ${prefix}/include/osrm
 libdir=${prefix}/lib
 
 Name: libOSRM
 Description: Project OSRM library
 Version: v at OSRM_VERSION_MAJOR@. at OSRM_VERSION_MINOR@. at OSRM_VERSION_PATCH@
 Requires:
-Libs: -L${libdir} -lOSRM
-Libs.private: @BOOST_LIBRARY_LISTING@ @TBB_LIBRARY_LISTING@
+Libs: -L${libdir} -losrm
+Libs.private: @ENGINE_LIBRARY_LISTING@
 Cflags: -I${includedir}
diff --git a/cmake/postinst.in b/cmake/postinst.in
deleted file mode 100644
index 92f2fde..0000000
--- a/cmake/postinst.in
+++ /dev/null
@@ -1,2 +0,0 @@
-#/usr/bin/env bash
-ln -s /usr/share/doc/@CMAKE_PROJECT_NAME@/profiles/car.lua @CMAKE_INSTALL_PREFIX@/profile.lua
diff --git a/config/cucumber.yml b/config/cucumber.yml
deleted file mode 100644
index 2cdea36..0000000
--- a/config/cucumber.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-# config/cucumber.yml
-##YAML Template
----
-default: --require features --tags ~@todo --tags ~@bug --tag ~@stress
-verify: --require features --tags ~@todo --tags ~@bug --tags ~@stress -f progress
-jenkins: --require features --tags ~@todo --tags ~@bug --tags ~@stress --tags ~@options -f progress
-bugs: --require features --tags @bug
-todo: --require features --tags @todo
-all: --require features
diff --git a/contractor/contractor_options.cpp b/contractor/contractor_options.cpp
deleted file mode 100644
index d483465..0000000
--- a/contractor/contractor_options.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "contractor_options.hpp"
-
-#include "util/version.hpp"
-#include "../util/simple_logger.hpp"
-
-#include <boost/filesystem.hpp>
-#include <boost/program_options.hpp>
-
-#include <tbb/task_scheduler_init.h>
-
-return_code
-ContractorOptions::ParseArguments(int argc, char *argv[], ContractorConfig &contractor_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>(&contractor_config.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()(
-        "profile,p",
-        boost::program_options::value<boost::filesystem::path>(&contractor_config.profile_path)
-            ->default_value("profile.lua"),
-        "Path to LUA routing profile")(
-        "threads,t",
-        boost::program_options::value<unsigned int>(&contractor_config.requested_num_threads)
-            ->default_value(tbb::task_scheduler_init::default_num_threads()),
-        "Number of threads to use")(
-		"core,k", boost::program_options::value<double>(&contractor_config.core_factor)
-						 ->default_value(1.0),"Percentage of the graph (in vertices) to contract [0..1]")(
-		"segment-speed-file", boost::program_options::value<std::string>(&contractor_config.segment_speed_lookup_path),
-						 "Lookup file containing nodeA,nodeB,speed data to adjust edge weights")(
-        "level-cache,o",
-        boost::program_options::value<bool>(&contractor_config.use_cached_priority)->default_value(false),
-        "Use .level file to retain the contaction level for each node from the last run.");
-
-#ifdef DEBUG_GEOMETRY
-    config_options.add_options()(
-		"debug-geometry", boost::program_options::value<std::string>(&contractor_config.debug_geometry_path)
-						 ,"Write out edge-weight debugging geometry data in GeoJSON format to this file");
-#endif
-
-    // 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>(&contractor_config.osrm_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() << OSRM_VERSION;
-        return return_code::exit;
-    }
-
-    if (option_variables.count("help"))
-    {
-        SimpleLogger().Write() << "\n" << visible_options;
-        return return_code::exit;
-    }
-
-    boost::program_options::notify(option_variables);
-
-    if (!option_variables.count("input"))
-    {
-        SimpleLogger().Write() << "\n" << visible_options;
-        return return_code::fail;
-    }
-
-    return return_code::ok;
-}
-
-void ContractorOptions::GenerateOutputFilesNames(ContractorConfig &contractor_config)
-{
-    contractor_config.level_output_path = contractor_config.osrm_input_path.string() + ".level";
-    contractor_config.core_output_path = contractor_config.osrm_input_path.string() + ".core";
-    contractor_config.graph_output_path = contractor_config.osrm_input_path.string() + ".hsgr";
-    contractor_config.edge_based_graph_path = contractor_config.osrm_input_path.string() + ".ebg";
-    contractor_config.edge_segment_lookup_path = contractor_config.osrm_input_path.string() + ".edge_segment_lookup";
-    contractor_config.edge_penalty_path = contractor_config.osrm_input_path.string() + ".edge_penalties";
-}
diff --git a/contractor/processing_chain.cpp b/contractor/processing_chain.cpp
deleted file mode 100644
index 2bd5350..0000000
--- a/contractor/processing_chain.cpp
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
-
-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 "contractor.hpp"
-
-#include "../data_structures/deallocating_vector.hpp"
-
-#include "../algorithms/crc32_processor.hpp"
-#include "../util/graph_loader.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/lua_util.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 <fast-cpp-csv-parser/csv.h>
-
-#include <boost/filesystem/fstream.hpp>
-#include <boost/program_options.hpp>
-
-#include <tbb/parallel_sort.h>
-
-#include <chrono>
-#include <memory>
-#include <string>
-#include <thread>
-#include <vector>
-
-#include "../util/debug_geometry.hpp"
-
-Prepare::~Prepare() {}
-
-int Prepare::Run()
-{
-#ifdef WIN32
-#pragma message("Memory consumption on Windows can be higher due to different bit packing")
-#else
-    static_assert(sizeof(NodeBasedEdge) == 20,
-                  "changing NodeBasedEdge type has influence on memory consumption!");
-    static_assert(sizeof(EdgeBasedEdge) == 16,
-                  "changing EdgeBasedEdge type has influence on memory consumption!");
-#endif
-
-    if (config.core_factor > 1.0 || config.core_factor < 0) 
-    {
-       throw osrm::exception("Core factor must be between 0.0 to 1.0 (inclusive)");
-    }
-
-    TIMER_START(preparing);
-
-    // Create a new lua state
-
-    SimpleLogger().Write() << "Loading edge-expanded graph representation";
-
-    DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
-
-    size_t max_edge_id = LoadEdgeExpandedGraph(
-        config.edge_based_graph_path, edge_based_edge_list, config.edge_segment_lookup_path,
-        config.edge_penalty_path, config.segment_speed_lookup_path);
-
-    // Contracting the edge-expanded graph
-
-    TIMER_START(contraction);
-    std::vector<bool> is_core_node;
-    std::vector<float> node_levels;
-    if (config.use_cached_priority)
-    {
-        ReadNodeLevels(node_levels);
-    }
-    DeallocatingVector<QueryEdge> contracted_edge_list;
-    ContractGraph(max_edge_id, edge_based_edge_list, contracted_edge_list, is_core_node,
-                  node_levels);
-    TIMER_STOP(contraction);
-
-    SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
-
-    std::size_t number_of_used_edges = WriteContractedGraph(max_edge_id, contracted_edge_list);
-    WriteCoreNodeMarker(std::move(is_core_node));
-    if (!config.use_cached_priority)
-    {
-        WriteNodeLevels(std::move(node_levels));
-    }
-
-    TIMER_STOP(preparing);
-
-    SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
-    SimpleLogger().Write() << "Contraction: " << ((max_edge_id + 1) / TIMER_SEC(contraction))
-                           << " nodes/sec and " << number_of_used_edges / TIMER_SEC(contraction)
-                           << " edges/sec";
-
-    SimpleLogger().Write() << "finished preprocessing";
-
-    return 0;
-}
-
-namespace std
-{
-
-template <> struct hash<std::pair<OSMNodeID, OSMNodeID>>
-{
-    std::size_t operator()(const std::pair<OSMNodeID, OSMNodeID> &k) const
-    {
-        return OSMNodeID_to_uint64_t(k.first) ^ (OSMNodeID_to_uint64_t(k.second) << 12);
-    }
-};
-}
-
-std::size_t Prepare::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
-                                           DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
-                                           const std::string &edge_segment_lookup_filename,
-                                           const std::string &edge_penalty_filename,
-                                           const std::string &segment_speed_filename)
-{
-    SimpleLogger().Write() << "Opening " << edge_based_graph_filename;
-    boost::filesystem::ifstream input_stream(edge_based_graph_filename, std::ios::binary);
-
-    const bool update_edge_weights = segment_speed_filename != "";
-
-    boost::filesystem::ifstream edge_segment_input_stream;
-    boost::filesystem::ifstream edge_fixed_penalties_input_stream;
-
-    if (update_edge_weights)
-    {
-        edge_segment_input_stream.open(edge_segment_lookup_filename, std::ios::binary);
-        edge_fixed_penalties_input_stream.open(edge_penalty_filename, std::ios::binary);
-        if (!edge_segment_input_stream || !edge_fixed_penalties_input_stream)
-        {
-            throw osrm::exception("Could not load .edge_segment_lookup or .edge_penalties, did you "
-                                  "run osrm-extract with '--generate-edge-lookup'?");
-        }
-    }
-
-    const FingerPrint fingerprint_valid = FingerPrint::GetValid();
-    FingerPrint fingerprint_loaded;
-    input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
-    fingerprint_loaded.TestPrepare(fingerprint_valid);
-
-    size_t number_of_edges = 0;
-    size_t max_edge_id = SPECIAL_EDGEID;
-    input_stream.read((char *)&number_of_edges, sizeof(size_t));
-    input_stream.read((char *)&max_edge_id, sizeof(size_t));
-
-    edge_based_edge_list.resize(number_of_edges);
-    SimpleLogger().Write() << "Reading " << number_of_edges << " edges from the edge based graph";
-
-    std::unordered_map<std::pair<OSMNodeID, OSMNodeID>, unsigned> segment_speed_lookup;
-
-    if (update_edge_weights)
-    {
-        SimpleLogger().Write() << "Segment speed data supplied, will update edge weights from "
-                               << segment_speed_filename;
-        io::CSVReader<3> csv_in(segment_speed_filename);
-        csv_in.set_header("from_node", "to_node", "speed");
-        uint64_t from_node_id;
-        uint64_t to_node_id;
-        unsigned speed;
-        while (csv_in.read_row(from_node_id, to_node_id, speed))
-        {
-            segment_speed_lookup[std::make_pair(OSMNodeID(from_node_id), OSMNodeID(to_node_id))] = speed;
-        }
-    }
-
-    DEBUG_GEOMETRY_START(config);
-
-    // TODO: can we read this in bulk?  DeallocatingVector isn't necessarily
-    // all stored contiguously
-    for (; number_of_edges > 0; --number_of_edges)
-    {
-        EdgeBasedEdge inbuffer;
-        input_stream.read((char *) &inbuffer, sizeof(EdgeBasedEdge));
-
-        if (update_edge_weights)
-        {
-            // Processing-time edge updates
-            unsigned fixed_penalty;
-            edge_fixed_penalties_input_stream.read(reinterpret_cast<char *>(&fixed_penalty),
-                                                   sizeof(fixed_penalty));
-
-            int new_weight = 0;
-
-            unsigned num_osm_nodes = 0;
-            edge_segment_input_stream.read(reinterpret_cast<char *>(&num_osm_nodes),
-                                           sizeof(num_osm_nodes));
-            OSMNodeID previous_osm_node_id;
-            edge_segment_input_stream.read(reinterpret_cast<char *>(&previous_osm_node_id),
-                                           sizeof(previous_osm_node_id));
-            OSMNodeID this_osm_node_id;
-            double segment_length;
-            int segment_weight;
-            --num_osm_nodes;
-            for (; num_osm_nodes != 0; --num_osm_nodes)
-            {
-                edge_segment_input_stream.read(reinterpret_cast<char *>(&this_osm_node_id),
-                                               sizeof(this_osm_node_id));
-                edge_segment_input_stream.read(reinterpret_cast<char *>(&segment_length),
-                                               sizeof(segment_length));
-                edge_segment_input_stream.read(reinterpret_cast<char *>(&segment_weight),
-                                               sizeof(segment_weight));
-
-                auto speed_iter = segment_speed_lookup.find(
-                    std::make_pair(previous_osm_node_id, this_osm_node_id));
-                if (speed_iter != segment_speed_lookup.end())
-                {
-                    // This sets the segment weight using the same formula as the
-                    // EdgeBasedGraphFactory for consistency.  The *why* of this formula
-                    // is lost in the annals of time.
-                    int new_segment_weight =
-                        std::max(1, static_cast<int>(std::floor(
-                                        (segment_length * 10.) / (speed_iter->second / 3.6) + .5)));
-                    new_weight += new_segment_weight;
-
-                    DEBUG_GEOMETRY_EDGE( 
-                            new_segment_weight, 
-                            segment_length,
-                            previous_osm_node_id,
-                            this_osm_node_id);
-                }
-                else
-                {
-                    // If no lookup found, use the original weight value for this segment
-                    new_weight += segment_weight;
-
-                    DEBUG_GEOMETRY_EDGE(
-                            segment_weight,
-                            segment_length,
-                            previous_osm_node_id,
-                            this_osm_node_id);
-                }
-
-                previous_osm_node_id = this_osm_node_id;
-            }
-
-            inbuffer.weight = fixed_penalty + new_weight;
-        }
-
-        edge_based_edge_list.emplace_back(std::move(inbuffer));
-    }
-
-    DEBUG_GEOMETRY_STOP();
-    SimpleLogger().Write() << "Done reading edges";
-    return max_edge_id;
-}
-
-void Prepare::ReadNodeLevels(std::vector<float> &node_levels) const
-{
-    boost::filesystem::ifstream order_input_stream(config.level_output_path, std::ios::binary);
-
-    unsigned level_size;
-    order_input_stream.read((char *)&level_size, sizeof(unsigned));
-    node_levels.resize(level_size);
-    order_input_stream.read((char *)node_levels.data(), sizeof(float) * node_levels.size());
-}
-
-void Prepare::WriteNodeLevels(std::vector<float> &&in_node_levels) const
-{
-    std::vector<float> node_levels(std::move(in_node_levels));
-
-    boost::filesystem::ofstream order_output_stream(config.level_output_path, std::ios::binary);
-
-    unsigned level_size = node_levels.size();
-    order_output_stream.write((char *)&level_size, sizeof(unsigned));
-    order_output_stream.write((char *)node_levels.data(), sizeof(float) * node_levels.size());
-}
-
-void Prepare::WriteCoreNodeMarker(std::vector<bool> &&in_is_core_node) const
-{
-    std::vector<bool> is_core_node(std::move(in_is_core_node));
-    std::vector<char> unpacked_bool_flags(std::move(is_core_node.size()));
-    for (auto i = 0u; i < is_core_node.size(); ++i)
-    {
-        unpacked_bool_flags[i] = is_core_node[i] ? 1 : 0;
-    }
-
-    boost::filesystem::ofstream core_marker_output_stream(config.core_output_path,
-                                                          std::ios::binary);
-    unsigned size = unpacked_bool_flags.size();
-    core_marker_output_stream.write((char *)&size, sizeof(unsigned));
-    core_marker_output_stream.write((char *)unpacked_bool_flags.data(),
-                                    sizeof(char) * unpacked_bool_flags.size());
-}
-
-std::size_t Prepare::WriteContractedGraph(unsigned max_node_id,
-                                          const DeallocatingVector<QueryEdge> &contracted_edge_list)
-{
-    // 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";
-
-    const FingerPrint fingerprint = FingerPrint::GetValid();
-    boost::filesystem::ofstream hsgr_output_stream(config.graph_output_path, std::ios::binary);
-    hsgr_output_stream.write((char *)&fingerprint, sizeof(FingerPrint));
-    const unsigned max_used_node_id = [&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 " << (max_node_id + 1) << " nodes";
-    SimpleLogger().Write(logDEBUG) << "contracted graph has " << (max_used_node_id + 1) << " nodes";
-
-    std::vector<StaticGraph<EdgeData>::NodeArrayEntry> node_array;
-    // make sure we have at least one sentinel
-    node_array.resize(max_node_id + 2);
-
-    SimpleLogger().Write() << "Building node array";
-    StaticGraph<EdgeData>::EdgeIterator edge = 0;
-    StaticGraph<EdgeData>::EdgeIterator position = 0;
-    StaticGraph<EdgeData>::EdgeIterator last_edge;
-
-    // initializing 'first_edge'-field of nodes:
-    for (const auto node : osrm::irange(0u, max_used_node_id + 1))
-    {
-        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 + 1, node_array.size()))
-    {
-        // sentinel element, guarded against underflow
-        node_array[sentinel_counter].first_edge = contracted_edge_count;
-    }
-
-    SimpleLogger().Write() << "Serializing node array";
-
-    RangebasedCRC32 crc32_calculator;
-    const unsigned edges_crc32 = crc32_calculator(contracted_edge_list);
-    SimpleLogger().Write() << "Writing CRC32: " << edges_crc32;
-
-    const unsigned node_array_size = node_array.size();
-    // serialize crc32, aka checksum
-    hsgr_output_stream.write((char *)&edges_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";
-    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;
-    }
-
-    return number_of_used_edges;
-}
-
-/**
- \brief Build contracted graph.
- */
-void Prepare::ContractGraph(const unsigned max_edge_id,
-                            DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
-                            DeallocatingVector<QueryEdge> &contracted_edge_list,
-                            std::vector<bool> &is_core_node,
-                            std::vector<float> &inout_node_levels) const
-{
-    std::vector<float> node_levels;
-    node_levels.swap(inout_node_levels);
-
-    Contractor contractor(max_edge_id + 1, edge_based_edge_list, std::move(node_levels));
-    contractor.Run(config.core_factor);
-    contractor.GetEdges(contracted_edge_list);
-    contractor.GetCoreMarker(is_core_node);
-    contractor.GetNodeLevels(inout_node_levels);
-}
diff --git a/contractor/processing_chain.hpp b/contractor/processing_chain.hpp
deleted file mode 100644
index 0eb6555..0000000
--- a/contractor/processing_chain.hpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
-
-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 "contractor.hpp"
-#include "contractor_options.hpp"
-#include "../data_structures/query_edge.hpp"
-#include "../data_structures/static_graph.hpp"
-#include "../data_structures/deallocating_vector.hpp"
-#include "../data_structures/node_based_graph.hpp"
-
-struct SpeedProfileProperties;
-struct EdgeBasedNode;
-struct lua_State;
-
-#include <boost/filesystem.hpp>
-
-#include <vector>
-
-/**
-    \brief class of 'prepare' utility.
- */
-class Prepare
-{
-  public:
-    using EdgeData = QueryEdge::EdgeData;
-
-    explicit Prepare(ContractorConfig contractor_config) : config(std::move(contractor_config)) {}
-    Prepare(const Prepare &) = delete;
-    ~Prepare();
-
-    int Run();
-
-  protected:
-    void ContractGraph(const unsigned max_edge_id,
-                       DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
-                       DeallocatingVector<QueryEdge> &contracted_edge_list,
-                       std::vector<bool> &is_core_node,
-                       std::vector<float> &node_levels) const;
-    void WriteCoreNodeMarker(std::vector<bool> &&is_core_node) const;
-    void WriteNodeLevels(std::vector<float> &&node_levels) const;
-    void ReadNodeLevels(std::vector<float> &contraction_order) const;
-    std::size_t WriteContractedGraph(unsigned number_of_edge_based_nodes,
-                                     const DeallocatingVector<QueryEdge> &contracted_edge_list);
-    void FindComponents(unsigned max_edge_id,
-                        const DeallocatingVector<EdgeBasedEdge> &edges,
-                        std::vector<EdgeBasedNode> &nodes) const;
-
-  private:
-    ContractorConfig config;
-    std::size_t LoadEdgeExpandedGraph(const std::string &edge_based_graph_path,
-                                      DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
-                                      const std::string &edge_segment_lookup_path,
-                                      const std::string &edge_penalty_path,
-                                      const std::string &segment_speed_path);
-};
-
-#endif // PROCESSING_CHAIN_HPP
diff --git a/cucumber.js b/cucumber.js
new file mode 100644
index 0000000..c16104c
--- /dev/null
+++ b/cucumber.js
@@ -0,0 +1,11 @@
+module.exports = {
+    default: '--require features --tags ~@todo --tags ~@bug --tags ~@stress --tags ~@guidance',
+    verify: '--require features --tags ~@todo --tags ~@bug --tags ~@stress -f progress --tags ~@guidance',
+    jenkins: '--require features --tags ~@todo --tags ~@bug --tags ~@stress --tags ~@options -f progress',
+    bugs: '--require features --tags @bug',
+    todo: '--require features --tags @todo',
+    all: '--require features'
+}
+
+
+
diff --git a/data_structures/compressed_edge_container.hpp b/data_structures/compressed_edge_container.hpp
deleted file mode 100644
index 5d94ee6..0000000
--- a/data_structures/compressed_edge_container.hpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-
-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 GEOMETRY_COMPRESSOR_HPP_
-#define GEOMETRY_COMPRESSOR_HPP_
-
-#include "../typedefs.h"
-
-#include <unordered_map>
-
-#include <string>
-#include <vector>
-
-class CompressedEdgeContainer
-{
-  public:
-    using CompressedNode = std::pair<NodeID, EdgeWeight>;
-    using EdgeBucket = std::vector<CompressedNode>;
-
-    CompressedEdgeContainer();
-    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 EdgeBucket& GetBucketReference(const EdgeID edge_id) const;
-    NodeID GetFirstEdgeTargetID(const EdgeID edge_id) const;
-    NodeID GetLastEdgeSourceID(const EdgeID edge_id) const;
-
-  private:
-    int free_list_maximum = 0;
-
-    void IncreaseFreeList();
-    std::vector<EdgeBucket> m_compressed_geometries;
-    std::vector<unsigned> m_free_list;
-    std::unordered_map<EdgeID, unsigned> m_edge_id_to_list_index_map;
-};
-
-#endif // GEOMETRY_COMPRESSOR_HPP_
diff --git a/data_structures/coordinate.cpp b/data_structures/coordinate.cpp
deleted file mode 100644
index 208f3eb..0000000
--- a/data_structures/coordinate.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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/coordinate_calculation.hpp"
-
-#ifndef NDEBUG
-#include "../util/simple_logger.hpp"
-#endif
-#include <osrm/coordinate.hpp>
-
-#ifndef NDEBUG
-#include <bitset>
-#endif
-#include <iostream>
-#include <limits>
-
-FixedPointCoordinate::FixedPointCoordinate()
-    : lat(std::numeric_limits<int>::min()), lon(std::numeric_limits<int>::min())
-{
-}
-
-FixedPointCoordinate::FixedPointCoordinate(int lat, int lon) : lat(lat), lon(lon)
-{
-#ifndef NDEBUG
-    if (0 != (std::abs(lat) >> 30))
-    {
-        std::bitset<32> y_coordinate_vector(lat);
-        SimpleLogger().Write(logDEBUG) << "broken lat: " << lat
-                                       << ", bits: " << y_coordinate_vector;
-    }
-    if (0 != (std::abs(lon) >> 30))
-    {
-        std::bitset<32> x_coordinate_vector(lon);
-        SimpleLogger().Write(logDEBUG) << "broken lon: " << lon
-                                       << ", bits: " << x_coordinate_vector;
-    }
-#endif
-}
-
-bool FixedPointCoordinate::is_valid() const
-{
-    if (lat > 90 * COORDINATE_PRECISION || lat < -90 * COORDINATE_PRECISION ||
-        lon > 180 * COORDINATE_PRECISION || lon < -180 * COORDINATE_PRECISION)
-    {
-        return false;
-    }
-    return true;
-}
-
-bool FixedPointCoordinate::operator==(const FixedPointCoordinate &other) const
-{
-    return lat == other.lat && lon == other.lon;
-}
-
-void FixedPointCoordinate::output(std::ostream &out) const
-{
-    out << "(" << lat / COORDINATE_PRECISION << "," << lon / COORDINATE_PRECISION << ")";
-}
-
-float FixedPointCoordinate::bearing(const FixedPointCoordinate &other) const
-{
-    return coordinate_calculation::bearing(other, *this);
-}
diff --git a/data_structures/edge_based_node.hpp b/data_structures/edge_based_node.hpp
deleted file mode 100644
index 8efbf01..0000000
--- a/data_structures/edge_based_node.hpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 <boost/assert.hpp>
-
-#include <osrm/coordinate.hpp>
-
-#include <limits>
-
-/// This is what StaticRTree serialized and stores on disk
-/// It is generated in EdgeBasedGraphFactory.
-struct EdgeBasedNode
-{
-    EdgeBasedNode()
-        : forward_edge_based_node_id(SPECIAL_NODEID), reverse_edge_based_node_id(SPECIAL_NODEID),
-          u(SPECIAL_NODEID), v(SPECIAL_NODEID), name_id(0),
-          forward_weight(INVALID_EDGE_WEIGHT >> 1), reverse_weight(INVALID_EDGE_WEIGHT >> 1),
-          forward_offset(0), reverse_offset(0), packed_geometry_id(SPECIAL_EDGEID),
-          component{INVALID_COMPONENTID, false}, fwd_segment_position(std::numeric_limits<unsigned short>::max()),
-          forward_travel_mode(TRAVEL_MODE_INACCESSIBLE),
-          backward_travel_mode(TRAVEL_MODE_INACCESSIBLE)
-    {
-    }
-
-    explicit EdgeBasedNode(NodeID forward_edge_based_node_id,
-                           NodeID reverse_edge_based_node_id,
-                           NodeID u,
-                           NodeID v,
-                           unsigned name_id,
-                           int forward_weight,
-                           int reverse_weight,
-                           int forward_offset,
-                           int reverse_offset,
-                           unsigned packed_geometry_id,
-                           bool is_tiny_component,
-                           unsigned component_id,
-                           unsigned short fwd_segment_position,
-                           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), u(u), v(v), 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{component_id, is_tiny_component},
-          fwd_segment_position(fwd_segment_position), 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));
-    }
-
-    static inline FixedPointCoordinate Centroid(const FixedPointCoordinate &a,
-                                                const FixedPointCoordinate &b)
-    {
-        FixedPointCoordinate centroid;
-        // The coordinates of the midpoint are given by:
-        centroid.lat = (a.lat + b.lat) / 2;
-        centroid.lon = (a.lon + b.lon) / 2;
-        return centroid;
-    }
-
-    bool IsCompressed() const { return packed_geometry_id != SPECIAL_EDGEID; }
-
-    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
-    NodeID v;                          // indices into the coordinates array
-    unsigned name_id;                  // id of the edge name
-    int forward_weight;                // weight of the edge
-    int reverse_weight;                // weight in the other direction (may be different)
-    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
-    struct {
-        unsigned id : 31;
-        bool is_tiny : 1;
-    } component;
-    unsigned short fwd_segment_position; // segment id in a compressed geometry
-    TravelMode forward_travel_mode : 4;
-    TravelMode backward_travel_mode : 4;
-};
-
-#endif // EDGE_BASED_NODE_HPP
diff --git a/data_structures/external_memory_node.cpp b/data_structures/external_memory_node.cpp
deleted file mode 100644
index d144f52..0000000
--- a/data_structures/external_memory_node.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 "external_memory_node.hpp"
-#include "query_node.hpp"
-
-#include <limits>
-
-ExternalMemoryNode::ExternalMemoryNode(
-    int lat, int lon, OSMNodeID node_id, bool barrier, bool traffic_lights)
-    : QueryNode(lat, lon, node_id), barrier(barrier), traffic_lights(traffic_lights)
-{
-}
-
-ExternalMemoryNode::ExternalMemoryNode() : barrier(false), traffic_lights(false) {}
-
-ExternalMemoryNode ExternalMemoryNode::min_value()
-{
-    return ExternalMemoryNode(0, 0, MIN_OSM_NODEID, false, false);
-}
-
-ExternalMemoryNode ExternalMemoryNode::max_value()
-{
-    return ExternalMemoryNode(std::numeric_limits<int>::max(), std::numeric_limits<int>::max(),
-                              MAX_OSM_NODEID, false, false);
-}
-
-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()
-{
-    return ExternalMemoryNode::min_value();
-}
diff --git a/data_structures/external_memory_node.hpp b/data_structures/external_memory_node.hpp
deleted file mode 100644
index a48d1a1..0000000
--- a/data_structures/external_memory_node.hpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 EXTERNAL_MEMORY_NODE_HPP_
-#define EXTERNAL_MEMORY_NODE_HPP_
-
-#include "query_node.hpp"
-
-#include "../typedefs.h"
-
-struct ExternalMemoryNode : QueryNode
-{
-    ExternalMemoryNode(int lat, int lon, OSMNodeID id, bool barrier, bool traffic_light);
-
-    ExternalMemoryNode();
-
-    static ExternalMemoryNode min_value();
-
-    static ExternalMemoryNode max_value();
-
-    bool barrier;
-    bool traffic_lights;
-};
-
-struct ExternalMemoryNodeSTXXLCompare
-{
-    using value_type = ExternalMemoryNode;
-    bool operator()(const ExternalMemoryNode &left, const ExternalMemoryNode &right) const;
-    value_type max_value();
-    value_type min_value();
-};
-
-#endif /* EXTERNAL_MEMORY_NODE_HPP_ */
diff --git a/data_structures/fixed_point_number.hpp b/data_structures/fixed_point_number.hpp
deleted file mode 100644
index c7ed257..0000000
--- a/data_structures/fixed_point_number.hpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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/data_structures/hilbert_value.cpp b/data_structures/hilbert_value.cpp
deleted file mode 100644
index d0d61e6..0000000
--- a/data_structures/hilbert_value.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 "hilbert_value.hpp"
-
-#include <osrm/coordinate.hpp>
-
-uint64_t HilbertCode::operator()(const FixedPointCoordinate &current_coordinate) const
-{
-    unsigned location[2];
-    location[0] = current_coordinate.lat + static_cast<int>(90 * COORDINATE_PRECISION);
-    location[1] = current_coordinate.lon + static_cast<int>(180 * COORDINATE_PRECISION);
-
-    TransposeCoordinate(location);
-    return BitInterleaving(location[0], location[1]);
-}
-
-uint64_t HilbertCode::BitInterleaving(const uint32_t latitude, const uint32_t longitude) const
-{
-    uint64_t result = 0;
-    for (int8_t index = 31; index >= 0; --index)
-    {
-        result |= (latitude >> index) & 1;
-        result <<= 1;
-        result |= (longitude >> index) & 1;
-        if (0 != index)
-        {
-            result <<= 1;
-        }
-    }
-    return result;
-}
-
-void HilbertCode::TransposeCoordinate(uint32_t *X) const
-{
-    uint32_t M = 1u << (32 - 1), P, Q, t;
-    int i;
-    // Inverse undo
-    for (Q = M; Q > 1; Q >>= 1)
-    {
-        P = Q - 1;
-        for (i = 0; i < 2; ++i)
-        {
-
-            const bool condition = (X[i] & Q);
-            if (condition)
-            {
-                X[0] ^= P; // invert
-            }
-            else
-            {
-                t = (X[0] ^ X[i]) & P;
-                X[0] ^= t;
-                X[i] ^= t;
-            }
-        } // exchange
-    }
-    // Gray encode
-    for (i = 1; i < 2; ++i)
-    {
-        X[i] ^= X[i - 1];
-    }
-    t = 0;
-    for (Q = M; Q > 1; Q >>= 1)
-    {
-        const bool condition = (X[2 - 1] & Q);
-        if (condition)
-        {
-            t ^= Q - 1;
-        }
-    } // check if this for loop is wrong
-    for (i = 0; i < 2; ++i)
-    {
-        X[i] ^= t;
-    }
-}
diff --git a/data_structures/hilbert_value.hpp b/data_structures/hilbert_value.hpp
deleted file mode 100644
index 7b8bffa..0000000
--- a/data_structures/hilbert_value.hpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 HILBERT_VALUE_HPP
-#define HILBERT_VALUE_HPP
-
-#include <cstdint>
-
-// computes a 64 bit value that corresponds to the hilbert space filling curve
-
-struct FixedPointCoordinate;
-
-class HilbertCode
-{
-  public:
-    uint64_t operator()(const FixedPointCoordinate &current_coordinate) const;
-    HilbertCode() {}
-    HilbertCode(const HilbertCode &) = delete;
-
-  private:
-    inline uint64_t BitInterleaving(const uint32_t a, const uint32_t b) const;
-    inline void TransposeCoordinate(uint32_t *X) const;
-};
-
-#endif /* HILBERT_VALUE_HPP */
diff --git a/data_structures/import_edge.cpp b/data_structures/import_edge.cpp
deleted file mode 100644
index bf2829d..0000000
--- a/data_structures/import_edge.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 "import_edge.hpp"
-
-#include "travel_mode.hpp"
-#include "../typedefs.h"
-
-bool NodeBasedEdge::operator<(const NodeBasedEdge &other) const
-{
-    if (source == other.source)
-    {
-        if (target == other.target)
-        {
-            if (weight == other.weight)
-            {
-                return forward && backward && ((!other.forward) || (!other.backward));
-            }
-            return weight < other.weight;
-        }
-        return target < other.target;
-    }
-    return source < other.source;
-}
-
-NodeBasedEdge::NodeBasedEdge()
-    : source(SPECIAL_NODEID), target(SPECIAL_NODEID), name_id(0), weight(0), forward(false),
-      backward(false), roundabout(false),
-      access_restricted(false), startpoint(true), is_split(false), travel_mode(false)
-{
-}
-
-NodeBasedEdge::NodeBasedEdge(NodeID source,
-                             NodeID target,
-                             NodeID name_id,
-                             EdgeWeight weight,
-                             bool forward,
-                             bool backward,
-                             bool roundabout,
-                             bool access_restricted,
-                             bool startpoint,
-                             TravelMode travel_mode,
-                             bool is_split)
-    : source(source), target(target), name_id(name_id), weight(weight), forward(forward),
-      backward(backward), roundabout(roundabout),
-      access_restricted(access_restricted), startpoint(startpoint), is_split(is_split), travel_mode(travel_mode)
-{
-}
-
-bool EdgeBasedEdge::operator<(const EdgeBasedEdge &other) const
-{
-    if (source == other.source)
-    {
-        if (target == other.target)
-        {
-            if (weight == other.weight)
-            {
-                return forward && backward && ((!other.forward) || (!other.backward));
-            }
-            return weight < other.weight;
-        }
-        return target < other.target;
-    }
-    return source < other.source;
-}
-
-template <class EdgeT>
-EdgeBasedEdge::EdgeBasedEdge(const EdgeT &other)
-    : source(other.source), target(other.target), edge_id(other.data.via),
-      weight(other.data.distance), forward(other.data.forward), backward(other.data.backward)
-{
-}
-
-/** Default constructor. target and weight are set to 0.*/
-EdgeBasedEdge::EdgeBasedEdge()
-    : source(0), target(0), edge_id(0), weight(0), forward(false), backward(false)
-{
-}
-
-EdgeBasedEdge::EdgeBasedEdge(const NodeID source,
-                             const NodeID target,
-                             const NodeID edge_id,
-                             const EdgeWeight weight,
-                             const bool forward,
-                             const bool backward)
-    : source(source), target(target), edge_id(edge_id), weight(weight), forward(forward),
-      backward(backward)
-{
-}
diff --git a/data_structures/import_edge.hpp b/data_structures/import_edge.hpp
deleted file mode 100644
index 449ded2..0000000
--- a/data_structures/import_edge.hpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-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 IMPORT_EDGE_HPP
-#define IMPORT_EDGE_HPP
-
-#include "../data_structures/travel_mode.hpp"
-#include "../typedefs.h"
-
-struct NodeBasedEdge
-{
-    bool operator<(const NodeBasedEdge &e) const;
-
-    NodeBasedEdge();
-    explicit NodeBasedEdge(NodeID source,
-                           NodeID target,
-                           NodeID name_id,
-                           EdgeWeight weight,
-                           bool forward,
-                           bool backward,
-                           bool roundabout,
-                           bool access_restricted,
-                           bool startpoint,
-                           TravelMode travel_mode,
-                           bool is_split);
-
-    NodeID source;
-    NodeID target;
-    NodeID name_id;
-    EdgeWeight weight;
-    bool forward : 1;
-    bool backward : 1;
-    bool roundabout : 1;
-    bool access_restricted : 1;
-    bool startpoint : 1;
-    bool is_split : 1;
-    TravelMode travel_mode : 4;
-};
-
-struct NodeBasedEdgeWithOSM : NodeBasedEdge
-{
-    explicit NodeBasedEdgeWithOSM(OSMNodeID source,
-                           OSMNodeID target,
-                           NodeID name_id,
-                           EdgeWeight weight,
-                           bool forward,
-                           bool backward,
-                           bool roundabout,
-                           bool access_restricted,
-                           bool startpoint,
-                           TravelMode travel_mode,
-                           bool is_split)
-        : NodeBasedEdge(SPECIAL_NODEID, SPECIAL_NODEID, name_id, weight, forward, backward, roundabout, access_restricted, startpoint, travel_mode, is_split),
-        osm_source_id(source), osm_target_id(target) {}
-
-    OSMNodeID osm_source_id;
-    OSMNodeID osm_target_id;
-};
-
-struct EdgeBasedEdge
-{
-
-  public:
-    bool operator<(const EdgeBasedEdge &e) const;
-
-    template <class EdgeT> explicit EdgeBasedEdge(const EdgeT &myEdge);
-
-    EdgeBasedEdge();
-
-    explicit EdgeBasedEdge(const NodeID source,
-                           const NodeID target,
-                           const NodeID edge_id,
-                           const EdgeWeight weight,
-                           const bool forward,
-                           const bool backward);
-    NodeID source;
-    NodeID target;
-    NodeID edge_id;
-    EdgeWeight weight : 30;
-    bool forward : 1;
-    bool backward : 1;
-};
-
-#endif /* IMPORT_EDGE_HPP */
diff --git a/data_structures/internal_route_result.hpp b/data_structures/internal_route_result.hpp
deleted file mode 100644
index 068b63a..0000000
--- a/data_structures/internal_route_result.hpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-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 RAW_ROUTE_DATA_H
-#define RAW_ROUTE_DATA_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.hpp>
-
-#include <vector>
-
-struct PathData
-{
-    PathData()
-        : node(SPECIAL_NODEID), name_id(INVALID_EDGE_WEIGHT), segment_duration(INVALID_EDGE_WEIGHT),
-          turn_instruction(TurnInstruction::NoTurn), travel_mode(TRAVEL_MODE_INACCESSIBLE)
-    {
-    }
-
-    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 InternalRouteResult
-{
-    std::vector<std::vector<PathData>> unpacked_path_segments;
-    std::vector<PathData> unpacked_alternative;
-    std::vector<PhantomNodes> segment_end_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;
-    int shortest_path_length;
-    int alternative_path_length;
-
-    bool is_via_leg(const std::size_t leg) const
-    {
-        return (leg != unpacked_path_segments.size() - 1);
-    }
-
-    InternalRouteResult()
-        : shortest_path_length(INVALID_EDGE_WEIGHT), alternative_path_length(INVALID_EDGE_WEIGHT)
-    {
-    }
-};
-
-#endif // RAW_ROUTE_DATA_H
diff --git a/data_structures/lru_cache.hpp b/data_structures/lru_cache.hpp
deleted file mode 100644
index 155ab1e..0000000
--- a/data_structures/lru_cache.hpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 LRUCACHE_HPP
-#define LRUCACHE_HPP
-
-#include <list>
-#include <unordered_map>
-
-template <typename KeyT, typename ValueT> class LRUCache
-{
-  private:
-    struct CacheEntry
-    {
-        CacheEntry(KeyT k, ValueT v) : key(k), value(v) {}
-        KeyT key;
-        ValueT value;
-    };
-    unsigned capacity;
-    std::list<CacheEntry> itemsInCache;
-    std::unordered_map<KeyT, typename std::list<CacheEntry>::iterator> positionMap;
-
-  public:
-    explicit LRUCache(unsigned c) : capacity(c) {}
-
-    bool Holds(KeyT key)
-    {
-        if (positionMap.find(key) != positionMap.end())
-        {
-            return true;
-        }
-        return false;
-    }
-
-    void Insert(const KeyT key, ValueT &value)
-    {
-        itemsInCache.push_front(CacheEntry(key, value));
-        positionMap.insert(std::make_pair(key, itemsInCache.begin()));
-        if (itemsInCache.size() > capacity)
-        {
-            positionMap.erase(itemsInCache.back().key);
-            itemsInCache.pop_back();
-        }
-    }
-
-    void Insert(const KeyT key, ValueT value)
-    {
-        itemsInCache.push_front(CacheEntry(key, value));
-        positionMap.insert(std::make_pair(key, itemsInCache.begin()));
-        if (itemsInCache.size() > capacity)
-        {
-            positionMap.erase(itemsInCache.back().key);
-            itemsInCache.pop_back();
-        }
-    }
-
-    bool Fetch(const KeyT key, ValueT &result)
-    {
-        if (Holds(key))
-        {
-            CacheEntry e = *(positionMap.find(key)->second);
-            result = e.value;
-
-            // move to front
-            itemsInCache.splice(itemsInCache.begin(), itemsInCache, positionMap.find(key)->second);
-            positionMap.find(key)->second = itemsInCache.begin();
-            return true;
-        }
-        return false;
-    }
-    unsigned Size() const { return itemsInCache.size(); }
-};
-#endif // LRUCACHE_HPP
diff --git a/data_structures/matrix_graph_wrapper.hpp b/data_structures/matrix_graph_wrapper.hpp
deleted file mode 100644
index f8b3e65..0000000
--- a/data_structures/matrix_graph_wrapper.hpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 MATRIX_GRAPH_WRAPPER_H
-#define MATRIX_GRAPH_WRAPPER_H
-
-#include <vector>
-#include <cstddef>
-#include <iterator>
-
-#include "../typedefs.h"
-
-// This Wrapper provides all methods that are needed for TarjanSCC, when the graph is given in a
-// matrix representation (e.g. as output from a distance table call)
-
-template <typename T> class MatrixGraphWrapper
-{
-  public:
-    MatrixGraphWrapper(std::vector<T> table, const std::size_t number_of_nodes)
-        : table_(std::move(table)), number_of_nodes_(number_of_nodes){};
-
-    std::size_t GetNumberOfNodes() const { return number_of_nodes_; }
-
-    std::vector<T> GetAdjacentEdgeRange(const NodeID node) const
-    {
-
-        std::vector<T> edges;
-        // find all valid adjacent edges and move to vector `edges`
-        for (std::size_t i = 0; i < number_of_nodes_; ++i)
-        {
-            if (*(std::begin(table_) + node * number_of_nodes_ + i) != INVALID_EDGE_WEIGHT)
-            {
-                edges.push_back(i);
-            }
-        }
-        return edges;
-    }
-
-    EdgeWeight GetTarget(const EdgeWeight edge) const { return edge; }
-
-  private:
-    const std::vector<T> table_;
-    const std::size_t number_of_nodes_;
-};
-
-#endif // MATRIX_GRAPH_WRAPPER_H
diff --git a/data_structures/node_based_graph.hpp b/data_structures/node_based_graph.hpp
deleted file mode 100644
index e58cfce..0000000
--- a/data_structures/node_based_graph.hpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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/graph_utils.hpp"
-
-#include <tbb/parallel_sort.h>
-
-#include <memory>
-
-struct NodeBasedEdgeData
-{
-    NodeBasedEdgeData()
-        : distance(INVALID_EDGE_WEIGHT), edge_id(SPECIAL_NODEID),
-          name_id(std::numeric_limits<unsigned>::max()), access_restricted(false),
-          reversed(false), roundabout(false), travel_mode(TRAVEL_MODE_INACCESSIBLE)
-    {
-    }
-
-    NodeBasedEdgeData(int distance, unsigned edge_id, unsigned name_id,
-            bool access_restricted, bool reversed,
-            bool roundabout, bool startpoint, TravelMode travel_mode)
-        : distance(distance), edge_id(edge_id), name_id(name_id),
-          access_restricted(access_restricted), reversed(reversed),
-          roundabout(roundabout), startpoint(startpoint), travel_mode(travel_mode)
-    {
-    }
-
-    int distance;
-    unsigned edge_id;
-    unsigned name_id;
-    bool access_restricted : 1;
-    bool reversed : 1;
-    bool roundabout : 1;
-    bool startpoint : 1;
-    TravelMode travel_mode : 4;
-
-    bool IsCompatibleTo(const NodeBasedEdgeData &other) const
-    {
-        return (reversed == other.reversed) && (name_id == other.name_id) &&
-               (travel_mode == other.travel_mode);
-    }
-};
-
-using NodeBasedDynamicGraph = DynamicGraph<NodeBasedEdgeData>;
-
-/// Factory method to create NodeBasedDynamicGraph from NodeBasedEdges
-/// Since DynamicGraph expects directed edges, we need to insert
-/// two edges for undirected edges.
-inline std::shared_ptr<NodeBasedDynamicGraph>
-NodeBasedDynamicGraphFromEdges(std::size_t number_of_nodes, const std::vector<NodeBasedEdge> &input_edge_list)
-{
-    auto edges_list = directedEdgesFromCompressed<NodeBasedDynamicGraph::InputEdge>(input_edge_list,
-        [](NodeBasedDynamicGraph::InputEdge& output_edge, const NodeBasedEdge& input_edge)
-        {
-            output_edge.data.distance = static_cast<int>(input_edge.weight);
-            BOOST_ASSERT(output_edge.data.distance > 0);
-
-            output_edge.data.roundabout = input_edge.roundabout;
-            output_edge.data.name_id = input_edge.name_id;
-            output_edge.data.access_restricted = input_edge.access_restricted;
-            output_edge.data.travel_mode = input_edge.travel_mode;
-            output_edge.data.startpoint = input_edge.startpoint;
-        }
-    );
-
-    tbb::parallel_sort(edges_list.begin(), edges_list.end());
-
-    auto graph = std::make_shared<NodeBasedDynamicGraph>(
-        static_cast<NodeBasedDynamicGraph::NodeIterator>(number_of_nodes), edges_list);
-
-    return graph;
-}
-
-#endif // NODE_BASED_GRAPH_HPP
diff --git a/data_structures/node_id.hpp b/data_structures/node_id.hpp
deleted file mode 100644
index 0671a4d..0000000
--- a/data_structures/node_id.hpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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_ID_HPP
-#define NODE_ID_HPP
-
-#include "../typedefs.h"
-
-struct Cmp
-{
-    using value_type = OSMNodeID;
-    bool operator()(const value_type left, const value_type right) const { return left < right; }
-    value_type max_value() { return MAX_OSM_NODEID; }
-    value_type min_value() { return MIN_OSM_NODEID; }
-};
-
-#endif // NODE_ID_HPP
diff --git a/data_structures/original_edge_data.hpp b/data_structures/original_edge_data.hpp
deleted file mode 100644
index cbbc1b2..0000000
--- a/data_structures/original_edge_data.hpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 ORIGINAL_EDGE_DATA_HPP
-#define ORIGINAL_EDGE_DATA_HPP
-
-#include "travel_mode.hpp"
-#include "turn_instructions.hpp"
-#include "../typedefs.h"
-
-#include <limits>
-
-struct OriginalEdgeData
-{
-    explicit OriginalEdgeData(NodeID via_node,
-                              unsigned name_id,
-                              TurnInstruction turn_instruction,
-                              bool compressed_geometry,
-                              TravelMode travel_mode)
-        : via_node(via_node), name_id(name_id), turn_instruction(turn_instruction),
-          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), travel_mode(TRAVEL_MODE_INACCESSIBLE)
-    {
-    }
-
-    NodeID via_node;
-    unsigned name_id;
-    TurnInstruction turn_instruction;
-    bool compressed_geometry;
-    TravelMode travel_mode;
-};
-
-#endif // ORIGINAL_EDGE_DATA_HPP
diff --git a/data_structures/phantom_node.cpp b/data_structures/phantom_node.cpp
deleted file mode 100644
index 95c5bbb..0000000
--- a/data_structures/phantom_node.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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"
-
-#include "../typedefs.h"
-#include "travel_mode.hpp"
-
-#include <osrm/coordinate.hpp>
-
-#include <limits>
-
-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,
-                         bool is_tiny_component,
-                         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{component_id, is_tiny_component}, 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{INVALID_COMPONENTID, false},
-      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)) &&
-           (component.id != INVALID_COMPONENTID) && (name_id != INVALID_NAMEID);
-}
-
-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
deleted file mode 100644
index b12c4fe..0000000
--- a/data_structures/phantom_node.hpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "travel_mode.hpp"
-#include "../typedefs.h"
-
-#include <osrm/coordinate.hpp>
-
-#include <iostream>
-#include <utility>
-#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,
-                bool is_tiny_component,
-                unsigned component_id,
-                FixedPointCoordinate &location,
-                unsigned short fwd_segment_position,
-                TravelMode forward_travel_mode,
-                TravelMode backward_travel_mode);
-
-    PhantomNode();
-
-    template <class OtherT> PhantomNode(const OtherT &other, const FixedPointCoordinate &foot_point)
-    {
-        forward_node_id = other.forward_edge_based_node_id;
-        reverse_node_id = other.reverse_edge_based_node_id;
-        name_id = other.name_id;
-
-        forward_weight = other.forward_weight;
-        reverse_weight = other.reverse_weight;
-
-        forward_offset = other.forward_offset;
-        reverse_offset = other.reverse_offset;
-
-        packed_geometry_id = other.packed_geometry_id;
-
-        component.id = other.component.id;
-        component.is_tiny = other.component.is_tiny;
-
-        location = foot_point;
-        fwd_segment_position = other.fwd_segment_position;
-
-        forward_travel_mode = other.forward_travel_mode;
-        backward_travel_mode = other.backward_travel_mode;
-    }
-
-    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;
-    struct ComponentType {
-        uint32_t id : 31;
-        bool is_tiny : 1;
-    } component;
-// bit-fields are broken on Windows
-#ifndef _MSC_VER
-    static_assert(sizeof(ComponentType) == 4, "ComponentType needs to 4 bytes big");
-#endif
-    FixedPointCoordinate location;
-    unsigned short fwd_segment_position;
-    // note 4 bits would suffice for each,
-    // but the saved byte would be padding anyway
-    TravelMode forward_travel_mode;
-    TravelMode backward_travel_mode;
-
-    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 operator==(const PhantomNode &other) const;
-};
-
-#ifndef _MSC_VER
-static_assert(sizeof(PhantomNode) == 48, "PhantomNode has more padding then expected");
-#endif
-
-using PhantomNodePair = std::pair<PhantomNode, PhantomNode>;
-
-struct PhantomNodeWithDistance
-{
-    PhantomNode phantom_node;
-    double distance;
-};
-
-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.is_tiny << " / " << pn.component.id << ", "
-        << "pos: " << pn.fwd_segment_position << ", "
-        << "loc: " << pn.location;
-    return out;
-}
-
-#endif // PHANTOM_NODES_H
diff --git a/data_structures/query_node.hpp b/data_structures/query_node.hpp
deleted file mode 100644
index 0f32a53..0000000
--- a/data_structures/query_node.hpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 QUERY_NODE_HPP
-#define QUERY_NODE_HPP
-
-#include "../typedefs.h"
-
-#include <boost/assert.hpp>
-
-#include <osrm/coordinate.hpp>
-
-#include <limits>
-
-struct QueryNode
-{
-    using key_type = OSMNodeID; // type of NodeID
-    using value_type = int;  // type of lat,lons
-
-    explicit QueryNode(int lat, int lon, OSMNodeID 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(SPECIAL_OSM_NODEID)
-    {
-    }
-
-    int lat;
-    int lon;
-    OSMNodeID node_id;
-
-    static QueryNode min_value()
-    {
-        return QueryNode(static_cast<int>(-90 * COORDINATE_PRECISION),
-                         static_cast<int>(-180 * COORDINATE_PRECISION),
-                         MIN_OSM_NODEID);
-    }
-
-    static QueryNode max_value()
-    {
-        return QueryNode(static_cast<int>(90 * COORDINATE_PRECISION),
-                         static_cast<int>(180 * COORDINATE_PRECISION),
-                         MAX_OSM_NODEID);
-    }
-
-    value_type operator[](const std::size_t n) const
-    {
-        switch (n)
-        {
-        case 1:
-            return lat;
-        case 0:
-            return lon;
-        default:
-            break;
-        }
-        BOOST_ASSERT_MSG(false, "should not happen");
-        return std::numeric_limits<int>::lowest();
-    }
-};
-
-#endif // QUERY_NODE_HPP
diff --git a/data_structures/rectangle.hpp b/data_structures/rectangle.hpp
deleted file mode 100644
index 7f6704a..0000000
--- a/data_structures/rectangle.hpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "../algorithms/coordinate_calculation.hpp"
-
-#include <boost/assert.hpp>
-
-#include <osrm/coordinate.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;
-
-    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());
-    }
-
-    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;
-    }
-
-    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));
-    }
-
-    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 = coordinate_calculation::great_circle_distance(
-                location, FixedPointCoordinate(max_lat, location.lon));
-            break;
-        case SOUTH:
-            min_dist = coordinate_calculation::great_circle_distance(
-                location, FixedPointCoordinate(min_lat, location.lon));
-            break;
-        case WEST:
-            min_dist = coordinate_calculation::great_circle_distance(
-                location, FixedPointCoordinate(location.lat, min_lon));
-            break;
-        case EAST:
-            min_dist = coordinate_calculation::great_circle_distance(
-                location, FixedPointCoordinate(location.lat, max_lon));
-            break;
-        case NORTH_EAST:
-            min_dist = coordinate_calculation::great_circle_distance(
-                location, FixedPointCoordinate(max_lat, max_lon));
-            break;
-        case NORTH_WEST:
-            min_dist = coordinate_calculation::great_circle_distance(
-                location, FixedPointCoordinate(max_lat, min_lon));
-            break;
-        case SOUTH_EAST:
-            min_dist = coordinate_calculation::great_circle_distance(
-                location, FixedPointCoordinate(min_lat, max_lon));
-            break;
-        case SOUTH_WEST:
-            min_dist = coordinate_calculation::great_circle_distance(
-                location, FixedPointCoordinate(min_lat, min_lon));
-            break;
-        default:
-            break;
-        }
-
-        BOOST_ASSERT(min_dist < std::numeric_limits<float>::max());
-
-        return min_dist;
-    }
-
-    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(coordinate_calculation::great_circle_distance(location, upper_left),
-                     coordinate_calculation::great_circle_distance(location, upper_right)));
-
-        min_max_dist = std::min(
-            min_max_dist,
-            std::max(coordinate_calculation::great_circle_distance(location, upper_right),
-                     coordinate_calculation::great_circle_distance(location, lower_right)));
-
-        min_max_dist =
-            std::min(min_max_dist,
-                     std::max(coordinate_calculation::great_circle_distance(location, lower_right),
-                              coordinate_calculation::great_circle_distance(location, lower_left)));
-
-        min_max_dist =
-            std::min(min_max_dist,
-                     std::max(coordinate_calculation::great_circle_distance(location, lower_left),
-                              coordinate_calculation::great_circle_distance(location, upper_left)));
-        return min_max_dist;
-    }
-
-    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;
-    }
-};
-
-#endif
diff --git a/data_structures/route_parameters.cpp b/data_structures/route_parameters.cpp
deleted file mode 100644
index 61789bb..0000000
--- a/data_structures/route_parameters.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 <boost/fusion/container/vector.hpp>
-#include <boost/fusion/sequence/intrinsic.hpp>
-#include <boost/fusion/include/at_c.hpp>
-#include <boost/spirit/include/qi.hpp>
-
-#include <osrm/route_parameters.hpp>
-
-#include "../algorithms/polyline_compressor.hpp"
-
-RouteParameters::RouteParameters()
-    : zoom_level(18), print_instructions(false), alternate_route(true), geometry(true),
-      compression(true), deprecatedAPI(false), uturn_default(false), classify(false),
-      matching_beta(5), gps_precision(5), check_sum(-1), num_results(1)
-{
-}
-
-void RouteParameters::setZoomLevel(const short level)
-{
-    if (18 >= level && 0 <= level)
-    {
-        zoom_level = 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)
-{
-    // the API grammar should make sure this never happens
-    BOOST_ASSERT(!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; }
-
-void RouteParameters::setInstructionFlag(const bool flag) { print_instructions = flag; }
-
-void RouteParameters::setService(const std::string &service_string) { service = service_string; }
-
-void RouteParameters::setClassify(const bool flag) { classify = flag; }
-
-void RouteParameters::setMatchingBeta(const double beta) { matching_beta = beta; }
-
-void RouteParameters::setGPSPrecision(const double precision) { gps_precision = precision; }
-
-void RouteParameters::setOutputFormat(const std::string &format) { output_format = format; }
-
-void RouteParameters::setJSONpParameter(const std::string &parameter)
-{
-    jsonp_parameter = parameter;
-}
-
-void RouteParameters::addHint(const std::string &hint)
-{
-    hints.resize(coordinates.size());
-    if (!hints.empty())
-    {
-        hints.back() = hint;
-    }
-}
-
-void RouteParameters::addTimestamp(const unsigned timestamp)
-{
-    timestamps.resize(coordinates.size());
-    if (!timestamps.empty())
-    {
-        timestamps.back() = timestamp;
-    }
-}
-
-void RouteParameters::addBearing(
-    const boost::fusion::vector<int, boost::optional<int>> &received_bearing,
-        boost::spirit::qi::unused_type /* unused */, bool& pass)
-{
-    pass = false;
-    const int bearing = boost::fusion::at_c<0>(received_bearing);
-    const boost::optional<int> range = boost::fusion::at_c<1>(received_bearing);
-    if (bearing < 0 || bearing > 359) return;
-    if (range && (*range < 0 || *range > 180)) return;
-    bearings.emplace_back(std::make_pair(bearing,range));
-    pass = true;
-}
-
-void RouteParameters::setLanguage(const std::string &language_string)
-{
-    language = language_string;
-}
-
-void RouteParameters::setGeometryFlag(const bool flag) { geometry = flag; }
-
-void RouteParameters::setCompressionFlag(const bool flag) { compression = flag; }
-
-void RouteParameters::addCoordinate(
-    const boost::fusion::vector<double, double> &received_coordinates)
-{
-    coordinates.emplace_back(
-        static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<0>(received_coordinates)),
-        static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<1>(received_coordinates)));
-    is_source.push_back(true);
-    is_destination.push_back(true);
-    uturns.push_back(uturn_default);
-}
-
-void RouteParameters::addDestination(
-    const boost::fusion::vector<double, double> &received_coordinates)
-{
-    coordinates.emplace_back(
-        static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<0>(received_coordinates)),
-        static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<1>(received_coordinates)));
-    is_source.push_back(false);
-    is_destination.push_back(true);
-    uturns.push_back(uturn_default);
-}
-
-void RouteParameters::addSource(
-    const boost::fusion::vector<double, double> &received_coordinates)
-{
-    coordinates.emplace_back(
-        static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<0>(received_coordinates)),
-        static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<1>(received_coordinates)));
-    is_source.push_back(true);
-    is_destination.push_back(false);
-    uturns.push_back(uturn_default);
-}
-
-void RouteParameters::getCoordinatesFromGeometry(const std::string &geometry_string)
-{
-    PolylineCompressor pc;
-    coordinates = pc.decode_string(geometry_string);
-}
-
diff --git a/data_structures/search_engine.hpp b/data_structures/search_engine.hpp
deleted file mode 100644
index 5af734e..0000000
--- a/data_structures/search_engine.hpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 SEARCH_ENGINE_HPP
-#define SEARCH_ENGINE_HPP
-
-#include "search_engine_data.hpp"
-#include "../routing_algorithms/alternative_path.hpp"
-#include "../routing_algorithms/many_to_many.hpp"
-#include "../routing_algorithms/map_matching.hpp"
-#include "../routing_algorithms/shortest_path.hpp"
-#include "../routing_algorithms/direct_shortest_path.hpp"
-
-#include <type_traits>
-
-template <class DataFacadeT> class SearchEngine
-{
-  private:
-    DataFacadeT *facade;
-    SearchEngineData engine_working_data;
-
-  public:
-    ShortestPathRouting<DataFacadeT> shortest_path;
-    DirectShortestPathRouting<DataFacadeT> direct_shortest_path;
-    AlternativeRouting<DataFacadeT> alternative_path;
-    ManyToManyRouting<DataFacadeT> distance_table;
-    MapMatching<DataFacadeT> map_matching;
-
-    explicit SearchEngine(DataFacadeT *facade)
-        : facade(facade),
-          shortest_path(facade, engine_working_data),
-          direct_shortest_path(facade, engine_working_data),
-          alternative_path(facade, engine_working_data),
-          distance_table(facade, engine_working_data),
-          map_matching(facade, engine_working_data)
-    {
-        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");
-    }
-
-    ~SearchEngine() {}
-};
-
-#endif // SEARCH_ENGINE_HPP
diff --git a/data_structures/search_engine_data.cpp b/data_structures/search_engine_data.cpp
deleted file mode 100644
index 3282a0c..0000000
--- a/data_structures/search_engine_data.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-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 "search_engine_data.hpp"
-
-#include "binary_heap.hpp"
-
-void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes)
-{
-    if (forward_heap_1.get())
-    {
-        forward_heap_1->Clear();
-    }
-    else
-    {
-        forward_heap_1.reset(new QueryHeap(number_of_nodes));
-    }
-
-    if (reverse_heap_1.get())
-    {
-        reverse_heap_1->Clear();
-    }
-    else
-    {
-        reverse_heap_1.reset(new QueryHeap(number_of_nodes));
-    }
-}
-
-void SearchEngineData::InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes)
-{
-    if (forward_heap_2.get())
-    {
-        forward_heap_2->Clear();
-    }
-    else
-    {
-        forward_heap_2.reset(new QueryHeap(number_of_nodes));
-    }
-
-    if (reverse_heap_2.get())
-    {
-        reverse_heap_2->Clear();
-    }
-    else
-    {
-        reverse_heap_2.reset(new QueryHeap(number_of_nodes));
-    }
-}
-
-void SearchEngineData::InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes)
-{
-    if (forward_heap_3.get())
-    {
-        forward_heap_3->Clear();
-    }
-    else
-    {
-        forward_heap_3.reset(new QueryHeap(number_of_nodes));
-    }
-
-    if (reverse_heap_3.get())
-    {
-        reverse_heap_3->Clear();
-    }
-    else
-    {
-        reverse_heap_3.reset(new QueryHeap(number_of_nodes));
-    }
-}
diff --git a/data_structures/search_engine_data.hpp b/data_structures/search_engine_data.hpp
deleted file mode 100644
index 8c1c161..0000000
--- a/data_structures/search_engine_data.hpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 SEARCH_ENGINE_DATA_HPP
-#define SEARCH_ENGINE_DATA_HPP
-
-#include <boost/thread/tss.hpp>
-
-#include "../typedefs.h"
-#include "binary_heap.hpp"
-
-struct HeapData
-{
-    NodeID parent;
-    /* explicit */ HeapData(NodeID p) : parent(p) {}
-};
-
-struct SearchEngineData
-{
-    using QueryHeap = BinaryHeap<NodeID, NodeID, int, HeapData, UnorderedMapStorage<NodeID, int>>;
-    using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
-
-    static SearchEngineHeapPtr forward_heap_1;
-    static SearchEngineHeapPtr reverse_heap_1;
-    static SearchEngineHeapPtr forward_heap_2;
-    static SearchEngineHeapPtr reverse_heap_2;
-    static SearchEngineHeapPtr forward_heap_3;
-    static SearchEngineHeapPtr reverse_heap_3;
-
-    void InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes);
-
-    void InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes);
-
-    void InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes);
-};
-
-#endif // SEARCH_ENGINE_DATA_HPP
diff --git a/data_structures/segment_information.hpp b/data_structures/segment_information.hpp
deleted file mode 100644
index d9cdc81..0000000
--- a/data_structures/segment_information.hpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 SEGMENT_INFORMATION_HPP
-#define SEGMENT_INFORMATION_HPP
-
-#include "turn_instructions.hpp"
-
-#include "../data_structures/travel_mode.hpp"
-#include "../typedefs.h"
-
-#include <osrm/coordinate.hpp>
-#include <utility>
-
-// Struct fits everything in one cache line
-struct SegmentInformation
-{
-    FixedPointCoordinate location;
-    NodeID name_id;
-    EdgeWeight duration;
-    float length;
-    short pre_turn_bearing; // more than enough [0..3600] fits into 12 bits
-    short post_turn_bearing;
-    TurnInstruction turn_instruction;
-    TravelMode travel_mode;
-    bool necessary;
-    bool is_via_location;
-
-    explicit SegmentInformation(FixedPointCoordinate location,
-                                const NodeID name_id,
-                                const EdgeWeight duration,
-                                const float length,
-                                const TurnInstruction turn_instruction,
-                                const bool necessary,
-                                const bool is_via_location,
-                                const TravelMode travel_mode)
-        : location(std::move(location)), name_id(name_id), duration(duration), length(length),
-          pre_turn_bearing(0), post_turn_bearing(0), turn_instruction(turn_instruction), travel_mode(travel_mode),
-          necessary(necessary), is_via_location(is_via_location)
-    {
-    }
-
-    explicit SegmentInformation(FixedPointCoordinate location,
-                                const NodeID name_id,
-                                const EdgeWeight duration,
-                                const float length,
-                                const TurnInstruction turn_instruction,
-                                const TravelMode travel_mode)
-        : location(std::move(location)), name_id(name_id), duration(duration), length(length),
-          pre_turn_bearing(0), post_turn_bearing(0), turn_instruction(turn_instruction), travel_mode(travel_mode),
-          necessary(turn_instruction != TurnInstruction::NoTurn), is_via_location(false)
-    {
-    }
-};
-
-#endif /* SEGMENT_INFORMATION_HPP */
diff --git a/data_structures/static_kdtree.hpp b/data_structures/static_kdtree.hpp
deleted file mode 100644
index 1e65dc8..0000000
--- a/data_structures/static_kdtree.hpp
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-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.
-
-*/
-
-// KD Tree coded by Christian Vetter, Monav Project
-
-#ifndef STATICKDTREE_HPP
-#define STATICKDTREE_HPP
-
-#include <boost/assert.hpp>
-#include <vector>
-#include <algorithm>
-#include <stack>
-#include <limits>
-
-namespace KDTree
-{
-
-#define KDTREE_BASESIZE (8)
-
-template <unsigned k, typename T> class BoundingBox
-{
-  public:
-    BoundingBox()
-    {
-        for (unsigned dim = 0; dim < k; ++dim)
-        {
-            min[dim] = std::numeric_limits<T>::min();
-            max[dim] = std::numeric_limits<T>::max();
-        }
-    }
-
-    T min[k];
-    T max[k];
-};
-
-struct NoData
-{
-};
-
-template <unsigned k, typename T> class EuclidianMetric
-{
-  public:
-    double operator()(const T left[k], const T right[k])
-    {
-        double result = 0;
-        for (unsigned i = 0; i < k; ++i)
-        {
-            double temp = (double)left[i] - (double)right[i];
-            result += temp * temp;
-        }
-        return result;
-    }
-
-    double operator()(const BoundingBox<k, T> &box, const T point[k])
-    {
-        T nearest[k];
-        for (unsigned dim = 0; dim < k; ++dim)
-        {
-            if (point[dim] < box.min[dim])
-                nearest[dim] = box.min[dim];
-            else if (point[dim] > box.max[dim])
-                nearest[dim] = box.max[dim];
-            else
-                nearest[dim] = point[dim];
-        }
-        return operator()(point, nearest);
-    }
-};
-
-template <unsigned k, typename T, typename Data = NoData, typename Metric = EuclidianMetric<k, T>>
-class StaticKDTree
-{
-  public:
-    struct InputPoint
-    {
-        T coordinates[k];
-        Data data;
-        bool operator==(const InputPoint &right)
-        {
-            for (int i = 0; i < k; i++)
-            {
-                if (coordinates[i] != right.coordinates[i])
-                    return false;
-            }
-            return true;
-        }
-    };
-
-    explicit StaticKDTree(std::vector<InputPoint> *points)
-    {
-        BOOST_ASSERT(k > 0);
-        BOOST_ASSERT(points->size() > 0);
-        size = points->size();
-        kdtree = new InputPoint[size];
-        for (Iterator i = 0; i != size; ++i)
-        {
-            kdtree[i] = points->at(i);
-            for (unsigned dim = 0; dim < k; ++dim)
-            {
-                if (kdtree[i].coordinates[dim] < boundingBox.min[dim])
-                    boundingBox.min[dim] = kdtree[i].coordinates[dim];
-                if (kdtree[i].coordinates[dim] > boundingBox.max[dim])
-                    boundingBox.max[dim] = kdtree[i].coordinates[dim];
-            }
-        }
-        std::stack<Tree> s;
-        s.push(Tree(0, size, 0));
-        while (!s.empty())
-        {
-            Tree tree = s.top();
-            s.pop();
-
-            if (tree.right - tree.left < KDTREE_BASESIZE)
-                continue;
-
-            Iterator middle = tree.left + (tree.right - tree.left) / 2;
-            std::nth_element(kdtree + tree.left, kdtree + middle, kdtree + tree.right,
-                             Less(tree.dimension));
-            s.push(Tree(tree.left, middle, (tree.dimension + 1) % k));
-            s.push(Tree(middle + 1, tree.right, (tree.dimension + 1) % k));
-        }
-    }
-
-    ~StaticKDTree() { delete[] kdtree; }
-
-    bool NearestNeighbor(InputPoint *result, const InputPoint &point)
-    {
-        Metric distance;
-        bool found = false;
-        double nearestDistance = std::numeric_limits<T>::max();
-        std::stack<NNTree> s;
-        s.push(NNTree(0, size, 0, boundingBox));
-        while (!s.empty())
-        {
-            NNTree tree = s.top();
-            s.pop();
-
-            if (distance(tree.box, point.coordinates) >= nearestDistance)
-                continue;
-
-            if (tree.right - tree.left < KDTREE_BASESIZE)
-            {
-                for (unsigned i = tree.left; i < tree.right; i++)
-                {
-                    double newDistance = distance(kdtree[i].coordinates, point.coordinates);
-                    if (newDistance < nearestDistance)
-                    {
-                        nearestDistance = newDistance;
-                        *result = kdtree[i];
-                        found = true;
-                    }
-                }
-                continue;
-            }
-
-            Iterator middle = tree.left + (tree.right - tree.left) / 2;
-
-            double newDistance = distance(kdtree[middle].coordinates, point.coordinates);
-            if (newDistance < nearestDistance)
-            {
-                nearestDistance = newDistance;
-                *result = kdtree[middle];
-                found = true;
-            }
-
-            Less comperator(tree.dimension);
-            if (!comperator(point, kdtree[middle]))
-            {
-                NNTree first(middle + 1, tree.right, (tree.dimension + 1) % k, tree.box);
-                NNTree second(tree.left, middle, (tree.dimension + 1) % k, tree.box);
-                first.box.min[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
-                second.box.max[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
-                s.push(second);
-                s.push(first);
-            }
-            else
-            {
-                NNTree first(middle + 1, tree.right, (tree.dimension + 1) % k, tree.box);
-                NNTree second(tree.left, middle, (tree.dimension + 1) % k, tree.box);
-                first.box.min[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
-                second.box.max[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
-                s.push(first);
-                s.push(second);
-            }
-        }
-        return found;
-    }
-
-  private:
-    using Iterator = unsigned;
-    struct Tree
-    {
-        Iterator left;
-        Iterator right;
-        unsigned dimension;
-        Tree() {}
-        Tree(Iterator l, Iterator r, unsigned d) : left(l), right(r), dimension(d) {}
-    };
-    struct NNTree
-    {
-        Iterator left;
-        Iterator right;
-        unsigned dimension;
-        BoundingBox<k, T> box;
-        NNTree() {}
-        NNTree(Iterator l, Iterator r, unsigned d, const BoundingBox<k, T> &b)
-            : left(l), right(r), dimension(d), box(b)
-        {
-        }
-    };
-    class Less
-    {
-      public:
-        explicit Less(unsigned d)
-        {
-            dimension = d;
-            BOOST_ASSERT(dimension < k);
-        }
-
-        bool operator()(const InputPoint &left, const InputPoint &right)
-        {
-            BOOST_ASSERT(dimension < k);
-            return left.coordinates[dimension] < right.coordinates[dimension];
-        }
-
-      private:
-        unsigned dimension;
-    };
-
-    BoundingBox<k, T> boundingBox;
-    InputPoint *kdtree;
-    Iterator size;
-};
-}
-
-#endif // STATICKDTREE_HPP
diff --git a/data_structures/turn_instructions.hpp b/data_structures/turn_instructions.hpp
deleted file mode 100644
index 1ca065f..0000000
--- a/data_structures/turn_instructions.hpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 TURN_INSTRUCTIONS_HPP
-#define TURN_INSTRUCTIONS_HPP
-
-enum class TurnInstruction : unsigned char
-{
-    NoTurn = 0,
-    GoStraight,
-    TurnSlightRight,
-    TurnRight,
-    TurnSharpRight,
-    UTurn,
-    TurnSharpLeft,
-    TurnLeft,
-    TurnSlightLeft,
-    ReachViaLocation,
-    HeadOn,
-    EnterRoundAbout,
-    LeaveRoundAbout,
-    StayOnRoundAbout,
-    StartAtEndOfStreet,
-    ReachedYourDestination,
-    EnterAgainstAllowedDirection,
-    LeaveAgainstAllowedDirection,
-    InverseAccessRestrictionFlag = 127,
-    AccessRestrictionFlag = 128,
-    AccessRestrictionPenalty = 129
-};
-
-struct TurnInstructionsClass
-{
-    TurnInstructionsClass() = delete;
-    TurnInstructionsClass(const TurnInstructionsClass &) = delete;
-
-    static inline TurnInstruction GetTurnDirectionOfInstruction(const double angle)
-    {
-        if (angle >= 23 && angle < 67)
-        {
-            return TurnInstruction::TurnSharpRight;
-        }
-        if (angle >= 67 && angle < 113)
-        {
-            return TurnInstruction::TurnRight;
-        }
-        if (angle >= 113 && angle < 158)
-        {
-            return TurnInstruction::TurnSlightRight;
-        }
-        if (angle >= 158 && angle < 202)
-        {
-            return TurnInstruction::GoStraight;
-        }
-        if (angle >= 202 && angle < 248)
-        {
-            return TurnInstruction::TurnSlightLeft;
-        }
-        if (angle >= 248 && angle < 292)
-        {
-            return TurnInstruction::TurnLeft;
-        }
-        if (angle >= 292 && angle < 336)
-        {
-            return TurnInstruction::TurnSharpLeft;
-        }
-        return TurnInstruction::UTurn;
-    }
-
-    static inline bool TurnIsNecessary(const TurnInstruction turn_instruction)
-    {
-        if (TurnInstruction::NoTurn == turn_instruction ||
-            TurnInstruction::StayOnRoundAbout == turn_instruction)
-        {
-            return false;
-        }
-        return true;
-    }
-};
-
-#endif /* TURN_INSTRUCTIONS_HPP */
diff --git a/data_structures/upper_bound.hpp b/data_structures/upper_bound.hpp
deleted file mode 100644
index 80695f2..0000000
--- a/data_structures/upper_bound.hpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 LOWER_BOUND_HPP
-#define LOWER_BOUND_HPP
-
-#include <functional>
-#include <limits>
-#include <queue>
-#include <type_traits>
-
-// max pq holds k elements
-// insert if key is smaller than max
-// if size > k then remove element
-// get() always yields a bound to the k smallest element in the stream
-
-template <typename key_type> class upper_bound
-{
-  private:
-    using parameter_type =
-        typename std::conditional<std::is_fundamental<key_type>::value, key_type, key_type &>::type;
-
-  public:
-    upper_bound() = delete;
-    upper_bound(std::size_t size) : size(size) {}
-
-    key_type get() const
-    {
-        if (queue.size() < size)
-        {
-            return std::numeric_limits<key_type>::max();
-        }
-        return queue.top();
-    }
-
-    void insert(const parameter_type key)
-    {
-        if (key < get())
-        {
-            queue.emplace(key);
-            while (queue.size() > size)
-            {
-                queue.pop();
-            }
-        }
-    }
-
-  private:
-    std::priority_queue<key_type, std::vector<key_type>, std::less<key_type>> queue;
-    const std::size_t size;
-};
-
-#endif // LOWER_BOUND_HPP
diff --git a/data_structures/xor_fast_hash.hpp b/data_structures/xor_fast_hash.hpp
deleted file mode 100644
index 3af5ab1..0000000
--- a/data_structures/xor_fast_hash.hpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-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 XOR_FAST_HASH_HPP
-#define XOR_FAST_HASH_HPP
-
-#include <algorithm>
-#include <vector>
-
-/*
-    This is an implementation of Tabulation hashing, which has suprising properties like
-   universality.
-    The space requirement is 2*2^16 = 256 kb of memory, which fits into L2 cache.
-    Evaluation boils down to 10 or less assembly instruction on any recent X86 CPU:
-
-    1: movq    table2(%rip), %rdx
-    2: movl    %edi, %eax
-    3: movzwl  %di, %edi
-    4: shrl    $16, %eax
-    5: movzwl  %ax, %eax
-    6: movzbl  (%rdx,%rax), %eax
-    7: movq    table1(%rip), %rdx
-    8: xorb    (%rdx,%rdi), %al
-    9: movzbl  %al, %eax
-    10: ret
-
-*/
-class XORFastHash
-{ // 65k entries
-    std::vector<unsigned short> table1;
-    std::vector<unsigned short> table2;
-
-  public:
-    XORFastHash()
-    {
-        table1.resize(2 << 16);
-        table2.resize(2 << 16);
-        for (unsigned i = 0; i < (2 << 16); ++i)
-        {
-            table1[i] = static_cast<unsigned short>(i);
-            table2[i] = static_cast<unsigned short>(i);
-        }
-        std::random_shuffle(table1.begin(), table1.end());
-        std::random_shuffle(table2.begin(), table2.end());
-    }
-
-    inline unsigned short operator()(const unsigned originalValue) const
-    {
-        unsigned short lsb = ((originalValue)&0xffff);
-        unsigned short msb = (((originalValue) >> 16) & 0xffff);
-        return table1[lsb] ^ table2[msb];
-    }
-};
-
-class XORMiniHash
-{ // 256 entries
-    std::vector<unsigned char> table1;
-    std::vector<unsigned char> table2;
-    std::vector<unsigned char> table3;
-    std::vector<unsigned char> table4;
-
-  public:
-    XORMiniHash()
-    {
-        table1.resize(1 << 8);
-        table2.resize(1 << 8);
-        table3.resize(1 << 8);
-        table4.resize(1 << 8);
-        for (unsigned i = 0; i < (1 << 8); ++i)
-        {
-            table1[i] = static_cast<unsigned char>(i);
-            table2[i] = static_cast<unsigned char>(i);
-            table3[i] = static_cast<unsigned char>(i);
-            table4[i] = static_cast<unsigned char>(i);
-        }
-        std::random_shuffle(table1.begin(), table1.end());
-        std::random_shuffle(table2.begin(), table2.end());
-        std::random_shuffle(table3.begin(), table3.end());
-        std::random_shuffle(table4.begin(), table4.end());
-    }
-    unsigned char operator()(const unsigned originalValue) const
-    {
-        unsigned char byte1 = ((originalValue)&0xff);
-        unsigned char byte2 = ((originalValue >> 8) & 0xff);
-        unsigned char byte3 = ((originalValue >> 16) & 0xff);
-        unsigned char byte4 = ((originalValue >> 24) & 0xff);
-        return table1[byte1] ^ table2[byte2] ^ table3[byte3] ^ table4[byte4];
-    }
-};
-
-#endif // XOR_FAST_HASH_HPP
diff --git a/data_structures/xor_fast_hash_storage.hpp b/data_structures/xor_fast_hash_storage.hpp
deleted file mode 100644
index ff65717..0000000
--- a/data_structures/xor_fast_hash_storage.hpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-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 XOR_FAST_HASH_STORAGE_HPP
-#define XOR_FAST_HASH_STORAGE_HPP
-
-#include "xor_fast_hash.hpp"
-
-#include <limits>
-#include <vector>
-
-template <typename NodeID, typename Key> class XORFastHashStorage
-{
-  public:
-    struct HashCell
-    {
-        unsigned time;
-        NodeID id;
-        Key key;
-        HashCell()
-            : time(std::numeric_limits<unsigned>::max()), id(std::numeric_limits<unsigned>::max()),
-              key(std::numeric_limits<unsigned>::max())
-        {
-        }
-
-        HashCell(const HashCell &other) : time(other.key), id(other.id), key(other.time) {}
-
-        operator Key() const { return key; }
-
-        void operator=(const Key key_to_insert) { key = key_to_insert; }
-    };
-
-    XORFastHashStorage() = delete;
-
-    explicit XORFastHashStorage(size_t) : positions(2 << 16), current_timestamp(0) {}
-
-    HashCell &operator[](const NodeID node)
-    {
-        unsigned short position = fast_hasher(node);
-        while ((positions[position].time == current_timestamp) && (positions[position].id != node))
-        {
-            ++position %= (2 << 16);
-        }
-
-        positions[position].time = current_timestamp;
-        positions[position].id = node;
-        return positions[position];
-    }
-
-    // peek into table, get key for node, think of it as a read-only operator[]
-    Key peek_index(const NodeID node) const
-    {
-        unsigned short position = fast_hasher(node);
-        while ((positions[position].time == current_timestamp) && (positions[position].id != node))
-        {
-            ++position %= (2 << 16);
-        }
-        return positions[position].key;
-    }
-
-    void Clear()
-    {
-        ++current_timestamp;
-        if (std::numeric_limits<unsigned>::max() == current_timestamp)
-        {
-            positions.clear();
-            positions.resize(2 << 16);
-        }
-    }
-
-  private:
-    std::vector<HashCell> positions;
-    XORFastHash fast_hasher;
-    unsigned current_timestamp;
-};
-
-#endif // XOR_FAST_HASH_STORAGE_HPP
diff --git a/descriptors/description_factory.cpp b/descriptors/description_factory.cpp
deleted file mode 100644
index 5086e0d..0000000
--- a/descriptors/description_factory.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "description_factory.hpp"
-
-#include "../algorithms/polyline_formatter.hpp"
-#include "../algorithms/coordinate_calculation.hpp"
-#include "../data_structures/internal_route_result.hpp"
-#include "../data_structures/turn_instructions.hpp"
-#include "../util/container.hpp"
-#include "../util/integer_range.hpp"
-#include "../typedefs.h"
-
-DescriptionFactory::DescriptionFactory() : entire_length(0) { via_indices.push_back(0); }
-
-std::vector<unsigned> const &DescriptionFactory::GetViaIndices() const { return via_indices; }
-
-void DescriptionFactory::SetStartSegment(const PhantomNode &source, const bool traversed_in_reverse)
-{
-    start_phantom = source;
-    const EdgeWeight segment_duration =
-        (traversed_in_reverse ? source.reverse_weight : source.forward_weight);
-    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,
-                                       const bool is_via_location)
-{
-    target_phantom = target;
-    const EdgeWeight segment_duration =
-        (traversed_in_reverse ? target.reverse_weight : target.forward_weight);
-    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 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))
-    {
-        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.f,
-                                  turn, path_point.travel_mode);
-}
-
-osrm::json::Value DescriptionFactory::AppendGeometryString(const bool return_encoded)
-{
-    if (return_encoded)
-    {
-        return PolylineFormatter().printEncodedString(path_description);
-    }
-    return PolylineFormatter().printUnencodedString(path_description);
-}
-
-void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time)
-{
-    summary.source_name_id = start_phantom.name_id;
-    summary.target_name_id = target_phantom.name_id;
-    summary.BuildDurationAndLengthStrings(distance, time);
-}
-
-void DescriptionFactory::Run(const unsigned zoom_level)
-{
-    if (path_description.empty())
-    {
-        return;
-    }
-
-    /** starts at index 1 */
-    path_description[0].length = 0.f;
-    for (const auto i : osrm::irange<std::size_t>(1, path_description.size()))
-    {
-        // move down names by one, q&d hack
-        path_description[i - 1].name_id = path_description[i].name_id;
-        path_description[i].length = coordinate_calculation::great_circle_distance(
-            path_description[i - 1].location, path_description[i].location);
-    }
-
-    /*Simplify turn instructions
-    Input :
-    10. Turn left on B 36 for 20 km
-    11. Continue on B 35; B 36 for 2 km
-    12. Continue on B 36 for 13 km
-
-    becomes:
-    10. Turn left on B 36 for 35 km
-    */
-    // TODO: rework to check only end and start of string.
-    //      stl string is way to expensive
-
-    //    unsigned lastTurn = 0;
-    //    for(unsigned i = 1; i < path_description.size(); ++i) {
-    //        string1 = sEngine.GetEscapedNameForNameID(path_description[i].name_id);
-    //        if(TurnInstruction::GoStraight == path_description[i].turn_instruction) {
-    //            if(std::string::npos != string0.find(string1+";")
-    //                  || std::string::npos != string0.find(";"+string1)
-    //                  || std::string::npos != string0.find(string1+" ;")
-    //                    || std::string::npos != string0.find("; "+string1)
-    //                    ){
-    //                SimpleLogger().Write() << "->next correct: " << string0 << " contains " <<
-    //                string1;
-    //                for(; lastTurn != i; ++lastTurn)
-    //                    path_description[lastTurn].name_id = path_description[i].name_id;
-    //                path_description[i].turn_instruction = TurnInstruction::NoTurn;
-    //            } else if(std::string::npos != string1.find(string0+";")
-    //                  || std::string::npos != string1.find(";"+string0)
-    //                    || std::string::npos != string1.find(string0+" ;")
-    //                    || std::string::npos != string1.find("; "+string0)
-    //                    ){
-    //                SimpleLogger().Write() << "->prev correct: " << string1 << " contains " <<
-    //                string0;
-    //                path_description[i].name_id = path_description[i-1].name_id;
-    //                path_description[i].turn_instruction = TurnInstruction::NoTurn;
-    //            }
-    //        }
-    //        if (TurnInstruction::NoTurn != path_description[i].turn_instruction) {
-    //            lastTurn = i;
-    //        }
-    //        string0 = string1;
-    //    }
-    //
-
-    float segment_length = 0.;
-    EdgeWeight segment_duration = 0;
-    std::size_t segment_start_index = 0;
-
-    for (const auto i : osrm::irange<std::size_t>(1, path_description.size()))
-    {
-        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;
-        path_description[segment_start_index].duration = segment_duration;
-
-        if (TurnInstruction::NoTurn != path_description[i].turn_instruction)
-        {
-            BOOST_ASSERT(path_description[i].necessary);
-            segment_length = 0;
-            segment_duration = 0;
-            segment_start_index = i;
-        }
-    }
-
-    // Post-processing to remove empty or nearly empty path segments
-    if (path_description.size() > 2 &&
-        std::numeric_limits<float>::epsilon() > path_description.back().length &&
-        !(path_description.end() - 2)->is_via_location)
-    {
-        path_description.pop_back();
-        path_description.back().necessary = true;
-        path_description.back().turn_instruction = TurnInstruction::NoTurn;
-        target_phantom.name_id = (path_description.end() - 2)->name_id;
-    }
-
-    if (path_description.size() > 2 &&
-        std::numeric_limits<float>::epsilon() > path_description.front().length &&
-        !(path_description.begin() + 1)->is_via_location)
-    {
-        path_description.erase(path_description.begin());
-        path_description.front().turn_instruction = TurnInstruction::HeadOn;
-        path_description.front().necessary = true;
-        start_phantom.name_id = path_description.front().name_id;
-    }
-
-    // Generalize poly line
-    polyline_generalizer.Run(path_description.begin(), path_description.end(), zoom_level);
-
-    // fix what needs to be fixed else
-    unsigned necessary_segments = 0; // a running index that counts the necessary pieces
-    osrm::for_each_pair(
-        path_description, [&](SegmentInformation &first, const SegmentInformation &second)
-        {
-            if (!first.necessary)
-            {
-                return;
-            }
-
-            if (first.is_via_location)
-            { // mark the end of a leg (of several segments)
-                via_indices.push_back(necessary_segments);
-            }
-
-            const double post_turn_bearing = coordinate_calculation::bearing(first.location, second.location);
-            const double pre_turn_bearing = coordinate_calculation::bearing(second.location, first.location);
-            first.post_turn_bearing = static_cast<short>(post_turn_bearing * 10);
-            first.pre_turn_bearing = static_cast<short>(pre_turn_bearing * 10);
-
-            ++necessary_segments;
-        });
-
-    via_indices.push_back(necessary_segments);
-    BOOST_ASSERT(via_indices.size() >= 2);
-    return;
-}
diff --git a/descriptors/description_factory.hpp b/descriptors/description_factory.hpp
deleted file mode 100644
index 985f9c1..0000000
--- a/descriptors/description_factory.hpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 DESCRIPTION_FACTORY_HPP
-#define DESCRIPTION_FACTORY_HPP
-
-#include "../algorithms/douglas_peucker.hpp"
-#include "../data_structures/phantom_node.hpp"
-#include "../data_structures/segment_information.hpp"
-#include "../data_structures/turn_instructions.hpp"
-
-#include <boost/assert.hpp>
-
-#include <osrm/coordinate.hpp>
-#include <osrm/json_container.hpp>
-
-#include <cmath>
-
-#include <limits>
-#include <vector>
-
-struct PathData;
-/* This class is fed with all way segments in consecutive order
- *  and produces the description plus the encoded polyline */
-
-class DescriptionFactory
-{
-    DouglasPeucker polyline_generalizer;
-    PhantomNode start_phantom, target_phantom;
-
-    double DegreeToRadian(const double degree) const;
-    double RadianToDegree(const double degree) const;
-
-    std::vector<unsigned> via_indices;
-
-    double entire_length;
-
-  public:
-    struct RouteSummary
-    {
-        unsigned distance;
-        EdgeWeight duration;
-        unsigned source_name_id;
-        unsigned target_name_id;
-        RouteSummary() : distance(0), duration(0), source_name_id(0), target_name_id(0) {}
-
-        void BuildDurationAndLengthStrings(const double raw_distance, const unsigned raw_duration)
-        {
-            // compute distance/duration for route summary
-            distance = static_cast<unsigned>(std::round(raw_distance));
-            duration = static_cast<EdgeWeight>(std::round(raw_duration / 10.));
-        }
-    } summary;
-
-    // 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,
-                       const bool is_via_location = false);
-    osrm::json::Value AppendGeometryString(const bool return_encoded);
-    std::vector<unsigned> const &GetViaIndices() const;
-
-    double get_entire_length() const { return entire_length; }
-
-    void Run(const unsigned zoom_level);
-};
-
-#endif /* DESCRIPTION_FACTORY_HPP */
diff --git a/descriptors/descriptor_base.hpp b/descriptors/descriptor_base.hpp
deleted file mode 100644
index e85ea90..0000000
--- a/descriptors/descriptor_base.hpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 DESCRIPTOR_BASE_HPP
-#define DESCRIPTOR_BASE_HPP
-
-#include "../algorithms/coordinate_calculation.hpp"
-#include "../data_structures/internal_route_result.hpp"
-#include "../data_structures/phantom_node.hpp"
-#include "../typedefs.h"
-
-#include <boost/assert.hpp>
-
-#include <osrm/json_container.hpp>
-
-#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;
-    short zoom_level;
-};
-
-template <class DataFacadeT> class BaseDescriptor
-{
-  public:
-    BaseDescriptor() {}
-    // Maybe someone can explain the pure virtual destructor thing to me (dennis)
-    virtual ~BaseDescriptor() {}
-    virtual void Run(const InternalRouteResult &raw_route, osrm::json::Object &json_result) = 0;
-    virtual void SetConfig(const DescriptorConfig &c) = 0;
-};
-
-#endif // DESCRIPTOR_BASE_HPP
diff --git a/descriptors/gpx_descriptor.hpp b/descriptors/gpx_descriptor.hpp
deleted file mode 100644
index fb4c5b9..0000000
--- a/descriptors/gpx_descriptor.hpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "../util/xml_renderer.hpp"
-
-#include <osrm/json_container.hpp>
-
-#include <iostream>
-
-template <class DataFacadeT> class GPXDescriptor final : public BaseDescriptor<DataFacadeT>
-{
-  private:
-    DescriptorConfig config;
-    DataFacadeT *facade;
-
-    void AddRoutePoint(const FixedPointCoordinate &coordinate, osrm::json::Array &json_route)
-    {
-        osrm::json::Object json_lat;
-        osrm::json::Object json_lon;
-        osrm::json::Array json_row;
-
-        std::string tmp;
-
-        coordinate_calculation::lat_or_lon_to_string(coordinate.lat, tmp);
-        json_lat.values["_lat"] = tmp;
-
-        coordinate_calculation::lat_or_lon_to_string(coordinate.lon, tmp);
-        json_lon.values["_lon"] = tmp;
-
-        json_row.values.push_back(json_lat);
-        json_row.values.push_back(json_lon);
-        osrm::json::Object entry;
-        entry.values["rtept"] = json_row;
-        json_route.values.push_back(entry);
-    }
-
-  public:
-    explicit GPXDescriptor(DataFacadeT *facade) : facade(facade) {}
-
-    virtual void SetConfig(const DescriptorConfig &c) final { config = c; }
-
-    virtual void Run(const InternalRouteResult &raw_route, osrm::json::Object &json_result) final
-    {
-        osrm::json::Array json_route;
-        if (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT)
-        {
-            AddRoutePoint(raw_route.segment_end_coordinates.front().source_phantom.location,
-                          json_route);
-
-            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_route);
-                }
-            }
-            AddRoutePoint(raw_route.segment_end_coordinates.back().target_phantom.location,
-                          json_route);
-        }
-        // osrm::json::gpx_render(reply.content, json_route);
-        json_result.values["route"] = json_route;
-    }
-};
-#endif // GPX_DESCRIPTOR_HPP
diff --git a/descriptors/json_descriptor.hpp b/descriptors/json_descriptor.hpp
deleted file mode 100644
index e476dd8..0000000
--- a/descriptors/json_descriptor.hpp
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 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/segment_information.hpp"
-#include "../data_structures/turn_instructions.hpp"
-#include "../util/bearing.hpp"
-#include "../util/cast.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 <osrm/json_container.hpp>
-
-#include <limits>
-#include <algorithm>
-#include <string>
-
-template <class DataFacadeT> class JSONDescriptor final : public BaseDescriptor<DataFacadeT>
-{
-  private:
-    DataFacadeT *facade;
-    DescriptorConfig config;
-    DescriptionFactory description_factory, alternate_description_factory;
-    FixedPointCoordinate current;
-
-  public:
-    struct Segment
-    {
-        Segment() : name_id(INVALID_NAMEID), length(-1), position(0) {}
-        Segment(unsigned n, int l, unsigned p) : name_id(n), length(l), position(p) {}
-        unsigned name_id;
-        int length;
-        unsigned position;
-    };
-  private:
-    std::vector<Segment> shortest_path_segments, alternative_path_segments;
-    ExtractRouteNames<DataFacadeT, Segment> GenerateRouteNames;
-
-  public:
-    explicit JSONDescriptor(DataFacadeT *facade) : facade(facade)
-    {
-    }
-
-    virtual void SetConfig(const DescriptorConfig &c) override final { config = c; }
-
-    unsigned DescribeLeg(const std::vector<PathData> &route_leg,
-                         const PhantomNodes &leg_phantoms,
-                         const bool target_traversed_in_reverse,
-                         const bool is_via_leg)
-    {
-        unsigned added_element_count = 0;
-        // Get all the coordinates for the computed route
-        FixedPointCoordinate current_coordinate;
-        for (const PathData &path_data : route_leg)
-        {
-            current_coordinate = facade->GetCoordinateOfNode(path_data.node);
-            description_factory.AppendSegment(current_coordinate, path_data);
-            ++added_element_count;
-        }
-        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;
-    }
-
-    virtual void Run(const InternalRouteResult &raw_route,
-                     osrm::json::Object &json_result) override final
-    {
-        if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
-        {
-            // We do not need to do much, if there is no route ;-)
-            return;
-        }
-
-        // check if first segment is non-zero
-        BOOST_ASSERT(raw_route.unpacked_path_segments.size() ==
-                     raw_route.segment_end_coordinates.size());
-
-        description_factory.SetStartSegment(
-            raw_route.segment_end_coordinates.front().source_phantom,
-            raw_route.source_traversed_in_reverse.front());
-
-        // for each unpacked segment add the leg to the description
-        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.is_via_leg(i));
-            BOOST_ASSERT(0 < added_segments);
-        }
-        description_factory.Run(config.zoom_level);
-
-        if (config.geometry)
-        {
-            osrm::json::Value route_geometry =
-                description_factory.AppendGeometryString(config.encode_geometry);
-            json_result.values["route_geometry"] = route_geometry;
-        }
-        if (config.instructions)
-        {
-            osrm::json::Array json_route_instructions = BuildTextualDescription(description_factory, shortest_path_segments);
-            json_result.values["route_instructions"] = json_route_instructions;
-        }
-        description_factory.BuildRouteSummary(description_factory.get_entire_length(),
-                                              raw_route.shortest_path_length);
-        osrm::json::Object json_route_summary;
-        json_route_summary.values["total_distance"] = description_factory.summary.distance;
-        json_route_summary.values["total_time"] = description_factory.summary.duration;
-        json_route_summary.values["start_point"] =
-            facade->get_name_for_id(description_factory.summary.source_name_id);
-        json_route_summary.values["end_point"] =
-            facade->get_name_for_id(description_factory.summary.target_name_id);
-        json_result.values["route_summary"] = json_route_summary;
-
-        BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
-
-        osrm::json::Array json_via_points_array;
-        osrm::json::Array json_first_coordinate;
-        json_first_coordinate.values.push_back(
-            raw_route.segment_end_coordinates.front().source_phantom.location.lat /
-            COORDINATE_PRECISION);
-        json_first_coordinate.values.push_back(
-            raw_route.segment_end_coordinates.front().source_phantom.location.lon /
-            COORDINATE_PRECISION);
-        json_via_points_array.values.push_back(json_first_coordinate);
-        for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
-        {
-            std::string tmp;
-            osrm::json::Array json_coordinate;
-            json_coordinate.values.push_back(nodes.target_phantom.location.lat /
-                                             COORDINATE_PRECISION);
-            json_coordinate.values.push_back(nodes.target_phantom.location.lon /
-                                             COORDINATE_PRECISION);
-            json_via_points_array.values.push_back(json_coordinate);
-        }
-        json_result.values["via_points"] = json_via_points_array;
-
-        osrm::json::Array json_via_indices_array;
-
-        std::vector<unsigned> const &shortest_leg_end_indices = description_factory.GetViaIndices();
-        json_via_indices_array.values.insert(json_via_indices_array.values.end(),
-                                             shortest_leg_end_indices.begin(),
-                                             shortest_leg_end_indices.end());
-        json_result.values["via_indices"] = json_via_indices_array;
-
-        // only one alternative route is computed at this time, so this is hardcoded
-        if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
-        {
-            json_result.values["found_alternative"] = osrm::json::True();
-            BOOST_ASSERT(!raw_route.alt_source_traversed_in_reverse.empty());
-            alternate_description_factory.SetStartSegment(
-                raw_route.segment_end_coordinates.front().source_phantom,
-                raw_route.alt_source_traversed_in_reverse.front());
-            // Get all the coordinates for the computed route
-            for (const PathData &path_data : raw_route.unpacked_alternative)
-            {
-                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(config.zoom_level);
-
-            if (config.geometry)
-            {
-                osrm::json::Value alternate_geometry_string =
-                    alternate_description_factory.AppendGeometryString(config.encode_geometry);
-                osrm::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;
-            }
-            // Generate instructions for each alternative (simulated here)
-            osrm::json::Array json_alt_instructions;
-            osrm::json::Array json_current_alt_instructions;
-            if (config.instructions)
-            {
-                json_current_alt_instructions = BuildTextualDescription(alternate_description_factory, alternative_path_segments);
-                json_alt_instructions.values.push_back(json_current_alt_instructions);
-                json_result.values["alternative_instructions"] = json_alt_instructions;
-            }
-            alternate_description_factory.BuildRouteSummary(
-                alternate_description_factory.get_entire_length(),
-                raw_route.alternative_path_length);
-
-            osrm::json::Object json_alternate_route_summary;
-            osrm::json::Array json_alternate_route_summary_array;
-            json_alternate_route_summary.values["total_distance"] =
-                alternate_description_factory.summary.distance;
-            json_alternate_route_summary.values["total_time"] =
-                alternate_description_factory.summary.duration;
-            json_alternate_route_summary.values["start_point"] =
-                facade->get_name_for_id(alternate_description_factory.summary.source_name_id);
-            json_alternate_route_summary.values["end_point"] =
-                facade->get_name_for_id(alternate_description_factory.summary.target_name_id);
-            json_alternate_route_summary_array.values.push_back(json_alternate_route_summary);
-            json_result.values["alternative_summaries"] = json_alternate_route_summary_array;
-
-            std::vector<unsigned> const &alternate_leg_end_indices =
-                alternate_description_factory.GetViaIndices();
-            osrm::json::Array json_altenative_indices_array;
-            json_altenative_indices_array.values.insert(json_altenative_indices_array.values.end(),
-                                                        alternate_leg_end_indices.begin(),
-                                                        alternate_leg_end_indices.end());
-            json_result.values["alternative_indices"] = json_altenative_indices_array;
-        }
-        else
-        {
-            json_result.values["found_alternative"] = osrm::json::False();
-        }
-
-        // Get Names for both routes
-        RouteNames route_names =
-            GenerateRouteNames(shortest_path_segments, alternative_path_segments, facade);
-        osrm::json::Array json_route_names;
-        json_route_names.values.push_back(route_names.shortest_path_name_1);
-        json_route_names.values.push_back(route_names.shortest_path_name_2);
-        json_result.values["route_name"] = json_route_names;
-
-        if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
-        {
-            osrm::json::Array json_alternate_names_array;
-            osrm::json::Array json_alternate_names;
-            json_alternate_names.values.push_back(route_names.alternative_path_name_1);
-            json_alternate_names.values.push_back(route_names.alternative_path_name_2);
-            json_alternate_names_array.values.push_back(json_alternate_names);
-            json_result.values["alternative_names"] = json_alternate_names_array;
-        }
-
-        json_result.values["hint_data"] = BuildHintData(raw_route);
-    }
-
-    inline osrm::json::Object BuildHintData(const InternalRouteResult& raw_route) const
-    {
-        osrm::json::Object json_hint_object;
-        json_hint_object.values["checksum"] = facade->GetCheckSum();
-        osrm::json::Array json_location_hint_array;
-        std::string hint;
-        for (const auto i : osrm::irange<std::size_t>(0, raw_route.segment_end_coordinates.size()))
-        {
-            ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates[i].source_phantom,
-                                          hint);
-            json_location_hint_array.values.push_back(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;
-
-        return json_hint_object;
-    }
-
-    inline osrm::json::Array BuildTextualDescription(const DescriptionFactory &description_factory,
-                                                     std::vector<Segment> &route_segments_list) const
-    {
-        osrm::json::Array json_instruction_array;
-        // Segment information has following format:
-        //["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
-        unsigned necessary_segments_running_index = 0;
-
-        struct RoundAbout
-        {
-            RoundAbout() : start_index(std::numeric_limits<int>::max()), name_id(INVALID_NAMEID), leave_at_exit(std::numeric_limits<int>::max()) {}
-            int start_index;
-            unsigned name_id;
-            int leave_at_exit;
-        } round_about;
-
-        round_about.leave_at_exit = 0;
-        round_about.name_id = 0;
-        std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
-        TravelMode last_travel_mode = TRAVEL_MODE_DEFAULT;
-
-        // Fetch data from Factory and generate a string from it.
-        for (const SegmentInformation &segment : description_factory.path_description)
-        {
-            osrm::json::Array json_instruction_row;
-            TurnInstruction current_instruction = segment.turn_instruction;
-            if (TurnInstructionsClass::TurnIsNecessary(current_instruction))
-            {
-                if (TurnInstruction::EnterRoundAbout == current_instruction)
-                {
-                    round_about.name_id = segment.name_id;
-                    round_about.start_index = necessary_segments_running_index;
-                }
-                else
-                {
-                    std::string current_turn_instruction;
-                    if (TurnInstruction::LeaveRoundAbout == current_instruction)
-                    {
-                        temp_instruction = std::to_string(
-                            cast::enum_to_underlying(TurnInstruction::EnterRoundAbout));
-                        current_turn_instruction += temp_instruction;
-                        current_turn_instruction += "-";
-                        temp_instruction = std::to_string(round_about.leave_at_exit + 1);
-                        current_turn_instruction += temp_instruction;
-                        round_about.leave_at_exit = 0;
-                    }
-                    else
-                    {
-                        temp_instruction =
-                            std::to_string(cast::enum_to_underlying(current_instruction));
-                        current_turn_instruction += temp_instruction;
-                    }
-                    json_instruction_row.values.push_back(current_turn_instruction);
-
-                    json_instruction_row.values.push_back(facade->get_name_for_id(segment.name_id));
-                    json_instruction_row.values.push_back(std::round(segment.length));
-                    json_instruction_row.values.push_back(necessary_segments_running_index);
-                    json_instruction_row.values.push_back(std::round(segment.duration / 10.));
-                    json_instruction_row.values.push_back(
-                        std::to_string(static_cast<unsigned>(segment.length)) + "m");
-
-                    // post turn bearing
-                    const double post_turn_bearing_value = (segment.post_turn_bearing / 10.);
-                    json_instruction_row.values.push_back(bearing::get(post_turn_bearing_value));
-                    json_instruction_row.values.push_back(
-                        static_cast<unsigned>(round(post_turn_bearing_value)));
-
-                    json_instruction_row.values.push_back(segment.travel_mode);
-                    last_travel_mode = segment.travel_mode;
-
-                    // pre turn bearing
-                    const double pre_turn_bearing_value = (segment.pre_turn_bearing / 10.);
-                    json_instruction_row.values.push_back(bearing::get(pre_turn_bearing_value));
-                    json_instruction_row.values.push_back(
-                        static_cast<unsigned>(round(pre_turn_bearing_value)));
-
-                    json_instruction_array.values.push_back(json_instruction_row);
-
-                    route_segments_list.emplace_back(
-                        segment.name_id, static_cast<int>(segment.length),
-                        static_cast<unsigned>(route_segments_list.size()));
-                }
-            }
-            else if (TurnInstruction::StayOnRoundAbout == current_instruction)
-            {
-                ++round_about.leave_at_exit;
-            }
-            if (segment.necessary)
-            {
-                ++necessary_segments_running_index;
-            }
-        }
-
-        osrm::json::Array json_last_instruction_row;
-        temp_instruction =
-            std::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_last_instruction_row.values.push_back(last_travel_mode);
-        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);
-
-        return json_instruction_array;
-    }
-};
-
-#endif /* JSON_DESCRIPTOR_H_ */
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 4535949..aa37682 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -12,8 +12,6 @@ RUN pip install awscli
 
 # luabind
 RUN curl https://gist.githubusercontent.com/DennisOSRM/f2eb7b948e6fe1ae319e/raw/install-luabind.sh | sudo bash
-# osmosis
-RUN curl -s https://gist.githubusercontent.com/DennisOSRM/803a64a9178ec375069f/raw/ | sudo bash
 
 RUN useradd -ms /bin/bash mapbox
 USER mapbox
diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt
new file mode 100644
index 0000000..86a8a7f
--- /dev/null
+++ b/example/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 2.8.8)
+
+if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_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-example C CXX)
+
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ")
+
+set(bitness 32)
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+  set(bitness 64)
+  message(STATUS "Building on a 64 bit system")
+else()
+  message(WARNING "Building on a 32 bit system is unsupported")
+endif()
+
+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()
+
+add_executable(osrm-example example.cpp)
+
+find_package(LibOSRM REQUIRED)
+find_package(Boost 1.49.0 COMPONENTS filesystem system thread REQUIRED)
+
+target_link_libraries(osrm-example ${LibOSRM_LIBRARIES} ${Boost_LIBRARIES})
+include_directories(SYSTEM ${LibOSRM_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
+
diff --git a/example/cmake/FindLibOSRM.cmake b/example/cmake/FindLibOSRM.cmake
new file mode 100644
index 0000000..8475c74
--- /dev/null
+++ b/example/cmake/FindLibOSRM.cmake
@@ -0,0 +1,65 @@
+# - Try to find LibOSRM
+# Once done this will define
+#  LibOSRM_FOUND - System has LibOSRM
+#  LibOSRM_INCLUDE_DIRS - The LibOSRM include directories
+#  LibOSRM_LIBRARIES - The libraries needed to use LibOSRM
+#  LibOSRM_DEFINITIONS - Compiler switches required for using LibOSRM
+
+find_package(PkgConfig)
+pkg_check_modules(PC_LibOSRM QUIET libosrm)
+set(LibOSRM_DEFINITIONS ${PC_LibOSRM_CFLAGS_OTHER})
+
+find_path(LibOSRM_INCLUDE_DIR osrm/osrm.hpp
+  PATH_SUFFIXES osrm include/osrm include
+  HINTS ${PC_LibOSRM_INCLUDEDIR} ${PC_LibOSRM_INCLUDE_DIRS}
+  ~/Library/Frameworks
+  /Library/Frameworks
+  /usr/local
+  /usr
+  /opt/local
+  /opt)
+
+set(LibOSRM_INCLUDE_DIRS ${LibOSRM_INCLUDE_DIR} ${LibOSRM_INCLUDE_DIR}/osrm)
+
+find_library(TEST_LibOSRM_STATIC_LIBRARY Names osrm.lib libosrm.a
+  PATH_SUFFIXES osrm lib/osrm lib
+  HINTS ${PC_LibOSRM_LIBDIR} ${PC_LibOSRM_LIBRARY_DIRS}
+  ~/Library/Frameworks
+  /Library/Frameworks
+  /usr/local
+  /usr
+  /opt/local
+  /opt)
+find_library(TEST_LibOSRM_DYNAMIC_LIBRARY Names osrm.dynlib libosrm.so
+  PATH_SUFFIXES osrm lib/osrm lib
+  HINTS ${PC_LibOSRM_LIBDIR} ${PC_LibOSRM_LIBRARY_DIRS}
+  ~/Library/Frameworks
+  /Library/Frameworks
+  /usr/local
+  /usr
+  /opt/local
+  /opt)
+
+if (NOT ("${TEST_LibOSRM_STATIC_LIBRARY}" STREQUAL "TEST_LibOSRM_STATIC_LIBRARY-NOTFOUND"))
+  if ("${PC_LibOSRM_STATIC_LIBRARIES}" STREQUAL "")
+    set(LibOSRM_STATIC_LIBRARIES ${TEST_LibOSRM_STATIC_LIBRARY})
+  else()
+    set(LibOSRM_STATIC_LIBRARIES ${PC_LibOSRM_STATIC_LIBRARIES})
+  endif()
+  set(LibOSRM_LIBRARIES ${LibOSRM_STATIC_LIBRARIES})
+endif()
+
+if (NOT ("${TEST_LibOSRM_DYNAMIC_LIBRARY}" STREQUAL "TEST_LibOSRM_DYNAMIC_LIBRARY-NOTFOUND"))
+  if ("${PC_LibOSRM_LIBRARIES}" STREQUAL "")
+    set(LibOSRM_DYNAMIC_LIBRARIES ${TEST_LibOSRM_DYNAMIC_LIBRARY})
+  else()
+    set(LibOSRM_DYNAMIC_LIBRARIES ${PC_LibOSRM_LIBRARIES})
+  endif()
+  set(LibOSRM_LIBRARIES ${LibOSRM_DYNAMIC_LIBRARIES})
+endif()
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set LIBOSRM_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(LibOSRM DEFAULT_MSG
+                                LibOSRM_LIBRARIES LibOSRM_INCLUDE_DIR)
diff --git a/example/cmake/FindTBB.cmake b/example/cmake/FindTBB.cmake
new file mode 100644
index 0000000..f9e3e0f
--- /dev/null
+++ b/example/cmake/FindTBB.cmake
@@ -0,0 +1,283 @@
+# Locate Intel Threading Building Blocks include paths and libraries
+# FindTBB.cmake can be found at https://code.google.com/p/findtbb/
+# Written by Hannes Hofmann <hannes.hofmann _at_ informatik.uni-erlangen.de>
+# Improvements by Gino van den Bergen <gino _at_ dtecta.com>,
+#   Florian Uhlig <F.Uhlig _at_ gsi.de>,
+#   Jiri Marsik <jiri.marsik89 _at_ gmail.com>
+
+# The MIT License
+#
+# Copyright (c) 2011 Hannes Hofmann
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+# GvdB: This module uses the environment variable TBB_ARCH_PLATFORM which defines architecture and compiler.
+#   e.g. "ia32/vc8" or "em64t/cc4.1.0_libc2.4_kernel2.6.16.21"
+#   TBB_ARCH_PLATFORM is set by the build script tbbvars[.bat|.sh|.csh], which can be found
+#   in the TBB installation directory (TBB_INSTALL_DIR).
+#
+# GvdB: Mac OS X distribution places libraries directly in lib directory.
+#
+# For backwards compatibility, you may explicitely set the CMake variables TBB_ARCHITECTURE and TBB_COMPILER.
+# TBB_ARCHITECTURE [ ia32 | em64t | itanium ]
+#   which architecture to use
+# TBB_COMPILER e.g. vc9 or cc3.2.3_libc2.3.2_kernel2.4.21 or cc4.0.1_os10.4.9
+#   which compiler to use (detected automatically on Windows)
+
+# This module respects
+# TBB_INSTALL_DIR or $ENV{TBB21_INSTALL_DIR} or $ENV{TBB_INSTALL_DIR}
+
+# This module defines
+# TBB_INCLUDE_DIRS, where to find task_scheduler_init.h, etc.
+# TBB_LIBRARY_DIRS, where to find libtbb, libtbbmalloc
+# TBB_DEBUG_LIBRARY_DIRS, where to find libtbb_debug, libtbbmalloc_debug
+# TBB_INSTALL_DIR, the base TBB install directory
+# TBB_LIBRARIES, the libraries to link against to use TBB.
+# TBB_DEBUG_LIBRARIES, the libraries to link against to use TBB with debug symbols.
+# TBB_FOUND, If false, don't try to use TBB.
+# TBB_INTERFACE_VERSION, as defined in tbb/tbb_stddef.h
+
+
+if (WIN32)
+    # has em64t/vc8 em64t/vc9
+    # has ia32/vc7.1 ia32/vc8 ia32/vc9
+    set(_TBB_DEFAULT_INSTALL_DIR "C:/Program Files/Intel/TBB" "C:/Program Files (x86)/Intel/TBB")
+    set(_TBB_LIB_NAME "tbb")
+    set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc")
+    set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug")
+    set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug")
+    if (MSVC71)
+        set (_TBB_COMPILER "vc7.1")
+    endif(MSVC71)
+    if (MSVC80)
+        set(_TBB_COMPILER "vc8")
+    endif(MSVC80)
+    if (MSVC90)
+        set(_TBB_COMPILER "vc9")
+    endif(MSVC90)
+    if(MSVC10)
+        set(_TBB_COMPILER "vc10")
+    endif(MSVC10)
+    # Todo: add other Windows compilers such as ICL.
+    set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE})
+endif (WIN32)
+
+if (UNIX)
+    if (APPLE)
+        # MAC
+        set(_TBB_DEFAULT_INSTALL_DIR "/Library/Frameworks/Intel_TBB.framework/Versions")
+        # libs: libtbb.dylib, libtbbmalloc.dylib, *_debug
+        set(_TBB_LIB_NAME "tbb")
+        set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc")
+        set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug")
+        set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug")
+        # default flavor on apple: ia32/cc4.0.1_os10.4.9
+        # Jiri: There is no reason to presume there is only one flavor and
+        #       that user's setting of variables should be ignored.
+        if(NOT TBB_COMPILER)
+            set(_TBB_COMPILER "cc4.0.1_os10.4.9")
+        elseif (NOT TBB_COMPILER)
+            set(_TBB_COMPILER ${TBB_COMPILER})
+        endif(NOT TBB_COMPILER)
+        if(NOT TBB_ARCHITECTURE)
+            set(_TBB_ARCHITECTURE "ia32")
+        elseif(NOT TBB_ARCHITECTURE)
+            set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE})
+        endif(NOT TBB_ARCHITECTURE)
+    else (APPLE)
+        # LINUX
+        set(_TBB_DEFAULT_INSTALL_DIR "/opt/intel/tbb" "/usr/local/include" "/usr/include")
+        set(_TBB_LIB_NAME "tbb")
+        set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc")
+        set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug")
+        set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug")
+        # has em64t/cc3.2.3_libc2.3.2_kernel2.4.21 em64t/cc3.3.3_libc2.3.3_kernel2.6.5 em64t/cc3.4.3_libc2.3.4_kernel2.6.9 em64t/cc4.1.0_libc2.4_kernel2.6.16.21
+        # has ia32/*
+        # has itanium/*
+        set(_TBB_COMPILER ${TBB_COMPILER})
+        set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE})
+    endif (APPLE)
+endif (UNIX)
+
+if (CMAKE_SYSTEM MATCHES "SunOS.*")
+# SUN
+# not yet supported
+# has em64t/cc3.4.3_kernel5.10
+# has ia32/*
+endif (CMAKE_SYSTEM MATCHES "SunOS.*")
+
+
+#-- Clear the public variables
+set (TBB_FOUND "NO")
+
+
+#-- Find TBB install dir and set ${_TBB_INSTALL_DIR} and cached ${TBB_INSTALL_DIR}
+# first: use CMake variable TBB_INSTALL_DIR
+if (TBB_INSTALL_DIR)
+    set (_TBB_INSTALL_DIR ${TBB_INSTALL_DIR})
+endif (TBB_INSTALL_DIR)
+# second: use environment variable
+if (NOT _TBB_INSTALL_DIR)
+    if (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "")
+        set (_TBB_INSTALL_DIR $ENV{TBB_INSTALL_DIR})
+    endif (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "")
+    # Intel recommends setting TBB21_INSTALL_DIR
+    if (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "")
+        set (_TBB_INSTALL_DIR $ENV{TBB21_INSTALL_DIR})
+    endif (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "")
+    if (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "")
+        set (_TBB_INSTALL_DIR $ENV{TBB22_INSTALL_DIR})
+    endif (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "")
+    if (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "")
+        set (_TBB_INSTALL_DIR $ENV{TBB30_INSTALL_DIR})
+    endif (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "")
+endif (NOT _TBB_INSTALL_DIR)
+# third: try to find path automatically
+if (NOT _TBB_INSTALL_DIR)
+    if (_TBB_DEFAULT_INSTALL_DIR)
+        set (_TBB_INSTALL_DIR ${_TBB_DEFAULT_INSTALL_DIR})
+    endif (_TBB_DEFAULT_INSTALL_DIR)
+endif (NOT _TBB_INSTALL_DIR)
+# sanity check
+if (NOT _TBB_INSTALL_DIR)
+    message ("ERROR: Unable to find Intel TBB install directory. ${_TBB_INSTALL_DIR}")
+else (NOT _TBB_INSTALL_DIR)
+# finally: set the cached CMake variable TBB_INSTALL_DIR
+if (NOT TBB_INSTALL_DIR)
+    set (TBB_INSTALL_DIR ${_TBB_INSTALL_DIR} CACHE PATH "Intel TBB install directory")
+    mark_as_advanced(TBB_INSTALL_DIR)
+endif (NOT TBB_INSTALL_DIR)
+
+
+#-- A macro to rewrite the paths of the library. This is necessary, because
+#   find_library() always found the em64t/vc9 version of the TBB libs
+macro(TBB_CORRECT_LIB_DIR var_name)
+#    if (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t")
+        string(REPLACE em64t "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}})
+#    endif (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t")
+    string(REPLACE ia32 "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}})
+    string(REPLACE vc7.1 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+    string(REPLACE vc8 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+    string(REPLACE vc9 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+    string(REPLACE vc10 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+endmacro(TBB_CORRECT_LIB_DIR var_content)
+
+
+#-- Look for include directory and set ${TBB_INCLUDE_DIR}
+set (TBB_INC_SEARCH_DIR ${_TBB_INSTALL_DIR}/include)
+# Jiri: tbbvars now sets the CPATH environment variable to the directory
+#       containing the headers.
+find_path(TBB_INCLUDE_DIR
+    tbb/task_scheduler_init.h
+    PATHS ${TBB_INC_SEARCH_DIR} ENV CPATH
+)
+mark_as_advanced(TBB_INCLUDE_DIR)
+
+
+#-- Look for libraries
+# GvdB: $ENV{TBB_ARCH_PLATFORM} is set by the build script tbbvars[.bat|.sh|.csh]
+if (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "")
+    set (_TBB_LIBRARY_DIR 
+         ${_TBB_INSTALL_DIR}/lib/$ENV{TBB_ARCH_PLATFORM}
+         ${_TBB_INSTALL_DIR}/$ENV{TBB_ARCH_PLATFORM}/lib
+        )
+endif (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "")
+# Jiri: This block isn't mutually exclusive with the previous one
+#       (hence no else), instead I test if the user really specified
+#       the variables in question.
+if ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL ""))
+    # HH: deprecated
+    message(STATUS "[Warning] FindTBB.cmake: The use of TBB_ARCHITECTURE and TBB_COMPILER is deprecated and may not be supported in future versions. Please set \$ENV{TBB_ARCH_PLATFORM} (using tbbvars.[bat|csh|sh]).")
+    # Jiri: It doesn't hurt to look in more places, so I store the hints from
+    #       ENV{TBB_ARCH_PLATFORM} and the TBB_ARCHITECTURE and TBB_COMPILER
+    #       variables and search them both.
+    set (_TBB_LIBRARY_DIR "${_TBB_INSTALL_DIR}/${_TBB_ARCHITECTURE}/${_TBB_COMPILER}/lib" ${_TBB_LIBRARY_DIR})
+endif ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL ""))
+
+# GvdB: Mac OS X distribution places libraries directly in lib directory.
+list(APPEND _TBB_LIBRARY_DIR ${_TBB_INSTALL_DIR}/lib)
+
+# Jiri: No reason not to check the default paths. From recent versions,
+#       tbbvars has started exporting the LIBRARY_PATH and LD_LIBRARY_PATH
+#       variables, which now point to the directories of the lib files.
+#       It all makes more sense to use the ${_TBB_LIBRARY_DIR} as a HINTS
+#       argument instead of the implicit PATHS as it isn't hard-coded
+#       but computed by system introspection. Searching the LIBRARY_PATH
+#       and LD_LIBRARY_PATH environment variables is now even more important
+#       that tbbvars doesn't export TBB_ARCH_PLATFORM and it facilitates
+#       the use of TBB built from sources.
+find_library(TBB_LIBRARY ${_TBB_LIB_NAME} HINTS ${_TBB_LIBRARY_DIR}
+        PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+find_library(TBB_MALLOC_LIBRARY ${_TBB_LIB_MALLOC_NAME} HINTS ${_TBB_LIBRARY_DIR}
+        PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+
+#Extract path from TBB_LIBRARY name
+get_filename_component(TBB_LIBRARY_DIR ${TBB_LIBRARY} PATH)
+
+#TBB_CORRECT_LIB_DIR(TBB_LIBRARY)
+#TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY)
+mark_as_advanced(TBB_LIBRARY TBB_MALLOC_LIBRARY)
+
+#-- Look for debug libraries
+# Jiri: Changed the same way as for the release libraries.
+find_library(TBB_LIBRARY_DEBUG ${_TBB_LIB_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR}
+        PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+find_library(TBB_MALLOC_LIBRARY_DEBUG ${_TBB_LIB_MALLOC_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR}
+        PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+
+# Jiri: Self-built TBB stores the debug libraries in a separate directory.
+#       Extract path from TBB_LIBRARY_DEBUG name
+get_filename_component(TBB_LIBRARY_DEBUG_DIR ${TBB_LIBRARY_DEBUG} PATH)
+
+#TBB_CORRECT_LIB_DIR(TBB_LIBRARY_DEBUG)
+#TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY_DEBUG)
+mark_as_advanced(TBB_LIBRARY_DEBUG TBB_MALLOC_LIBRARY_DEBUG)
+
+
+if (TBB_INCLUDE_DIR)
+    if (TBB_LIBRARY)
+        set (TBB_FOUND "YES")
+        set (TBB_LIBRARIES ${TBB_LIBRARY} ${TBB_MALLOC_LIBRARY} ${TBB_LIBRARIES})
+        set (TBB_DEBUG_LIBRARIES ${TBB_LIBRARY_DEBUG} ${TBB_MALLOC_LIBRARY_DEBUG} ${TBB_DEBUG_LIBRARIES})
+        set (TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR} CACHE PATH "TBB include directory" FORCE)
+        set (TBB_LIBRARY_DIRS ${TBB_LIBRARY_DIR} CACHE PATH "TBB library directory" FORCE)
+        # Jiri: Self-built TBB stores the debug libraries in a separate directory.
+        set (TBB_DEBUG_LIBRARY_DIRS ${TBB_LIBRARY_DEBUG_DIR} CACHE PATH "TBB debug library directory" FORCE)
+        mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARY_DIRS TBB_DEBUG_LIBRARY_DIRS TBB_LIBRARIES TBB_DEBUG_LIBRARIES)
+        message(STATUS "Found Intel TBB")
+    endif (TBB_LIBRARY)
+endif (TBB_INCLUDE_DIR)
+
+if (NOT TBB_FOUND)
+    message("ERROR: Intel TBB NOT found!")
+    message(STATUS "Looked for Threading Building Blocks in ${_TBB_INSTALL_DIR}")
+    # do only throw fatal, if this pkg is REQUIRED
+    if (TBB_FIND_REQUIRED)
+        message(FATAL_ERROR "Could NOT find TBB library.")
+    endif (TBB_FIND_REQUIRED)
+endif (NOT TBB_FOUND)
+
+endif (NOT _TBB_INSTALL_DIR)
+
+if (TBB_FOUND)
+	set(TBB_INTERFACE_VERSION 0)
+	FILE(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _TBB_VERSION_CONTENTS)
+	STRING(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" TBB_INTERFACE_VERSION "${_TBB_VERSION_CONTENTS}")
+	set(TBB_INTERFACE_VERSION "${TBB_INTERFACE_VERSION}")
+endif (TBB_FOUND)
diff --git a/example/example.cpp b/example/example.cpp
new file mode 100644
index 0000000..fe1de36
--- /dev/null
+++ b/example/example.cpp
@@ -0,0 +1,85 @@
+#include "osrm/route_parameters.hpp"
+#include "osrm/table_parameters.hpp"
+#include "osrm/nearest_parameters.hpp"
+#include "osrm/trip_parameters.hpp"
+#include "osrm/match_parameters.hpp"
+
+#include "osrm/coordinate.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/json_container.hpp"
+
+#include "osrm/status.hpp"
+#include "osrm/osrm.hpp"
+
+#include <string>
+#include <utility>
+#include <iostream>
+#include <exception>
+
+#include <cstdlib>
+
+int main(int argc, const char *argv[]) try
+{
+    if (argc < 2)
+    {
+        std::cerr << "Usage: " << argv[0] << " data.osrm\n";
+        return EXIT_FAILURE;
+    }
+
+    using namespace osrm;
+
+    // Configure based on a .osrm base path, and no datasets in shared mem from osrm-datastore
+    EngineConfig config;
+    config.storage_config = {argv[1]};
+    config.use_shared_memory = false;
+
+    // Routing machine with several services (such as Route, Table, Nearest, Trip, Match)
+    OSRM osrm{config};
+
+    // The following shows how to use the Route service; configure this service
+    RouteParameters params;
+
+    // Route in monaco
+    params.coordinates.push_back({util::FloatLongitude(7.419758), util::FloatLatitude(43.731142)});
+    params.coordinates.push_back({util::FloatLongitude(7.419505), util::FloatLatitude(43.736825)});
+
+    // Response is in JSON format
+    json::Object result;
+
+    // Execute routing request, this does the heavy lifting
+    const auto status = osrm.Route(params, result);
+
+    if (status == Status::Ok)
+    {
+        auto &routes = result.values["routes"].get<json::Array>();
+
+        // Let's just use the first route
+        auto &route = routes.values.at(0).get<json::Object>();
+        const auto distance = route.values["distance"].get<json::Number>().value;
+        const auto duration = route.values["duration"].get<json::Number>().value;
+
+        // Warn users if extract does not contain the default Berlin coordinates from above
+        if (distance == 0 or duration == 0)
+        {
+            std::cout << "Note: distance or duration is zero. ";
+            std::cout << "You are probably doing a query outside of the OSM extract.\n\n";
+        }
+
+        std::cout << "Distance: " << distance << " meter\n";
+        std::cout << "Duration: " << duration << " seconds\n";
+    }
+    else if (status == Status::Error)
+    {
+        const auto code = result.values["code"].get<json::String>().value;
+        const auto message = result.values["message"].get<json::String>().value;
+
+        std::cout << "Code: " << code << "\n";
+        std::cout << "Message: " << code << "\n";
+        return EXIT_FAILURE;
+    }
+}
+catch (const std::exception &e)
+{
+    std::cerr << "Error: " << e.what() << std::endl;
+    return EXIT_FAILURE;
+}
diff --git a/extract.cpp b/extract.cpp
deleted file mode 100644
index dabc19a..0000000
--- a/extract.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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/extractor.hpp"
-#include "extractor/extractor_options.hpp"
-#include "util/simple_logger.hpp"
-
-#include <boost/filesystem.hpp>
-
-#include <cstdlib>
-#include <exception>
-#include <new>
-
-int main(int argc, char *argv[]) try
-{
-    LogPolicy::GetInstance().Unmute();
-    ExtractorConfig extractor_config;
-
-    const return_code result = ExtractorOptions::ParseArguments(argc, argv, extractor_config);
-
-    if (return_code::fail == result)
-    {
-        return EXIT_FAILURE;
-    }
-
-    if (return_code::exit == result)
-    {
-        return EXIT_SUCCESS;
-    }
-
-    ExtractorOptions::GenerateOutputFilesNames(extractor_config);
-
-    if (1 > extractor_config.requested_num_threads)
-    {
-        SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
-        return EXIT_FAILURE;
-    }
-
-    if (!boost::filesystem::is_regular_file(extractor_config.input_path))
-    {
-        SimpleLogger().Write(logWARNING) << "Input file " << extractor_config.input_path.string()
-                                         << " not found!";
-        return EXIT_FAILURE;
-    }
-
-    if (!boost::filesystem::is_regular_file(extractor_config.profile_path))
-    {
-        SimpleLogger().Write(logWARNING) << "Profile " << extractor_config.profile_path.string()
-                                         << " not found!";
-        return EXIT_FAILURE;
-    }
-    return extractor(extractor_config).run();
-}
-catch (const std::bad_alloc &e)
-{
-    SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
-    SimpleLogger().Write(logWARNING)
-        << "Please provide more memory or consider using a larger swapfile";
-    return EXIT_FAILURE;
-}
-catch (const std::exception &e)
-{
-    SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
-    return EXIT_FAILURE;
-}
diff --git a/extractor/edge_based_graph_factory.cpp b/extractor/edge_based_graph_factory.cpp
deleted file mode 100644
index 1ddeb6a..0000000
--- a/extractor/edge_based_graph_factory.cpp
+++ /dev/null
@@ -1,702 +0,0 @@
-/*
-
-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 "edge_based_graph_factory.hpp"
-#include "../algorithms/coordinate_calculation.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 "../util/osrm_exception.hpp"
-
-#include "../util/debug_geometry.hpp"
-
-#include <boost/assert.hpp>
-
-#include <fstream>
-#include <iomanip>
-#include <limits>
-
-EdgeBasedGraphFactory::EdgeBasedGraphFactory(
-    std::shared_ptr<NodeBasedDynamicGraph> node_based_graph,
-    const CompressedEdgeContainer &compressed_edge_container,
-    const std::unordered_set<NodeID> &barrier_nodes,
-    const std::unordered_set<NodeID> &traffic_lights,
-    std::shared_ptr<const RestrictionMap> restriction_map,
-    const std::vector<QueryNode> &node_info_list,
-    SpeedProfileProperties speed_profile)
-    : m_max_edge_id(0), m_node_info_list(node_info_list), m_node_based_graph(std::move(node_based_graph)),
-      m_restriction_map(std::move(restriction_map)), m_barrier_nodes(barrier_nodes),
-      m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container),
-      speed_profile(std::move(speed_profile))
-{
-}
-
-void EdgeBasedGraphFactory::GetEdgeBasedEdges(DeallocatingVector<EdgeBasedEdge> &output_edge_list)
-{
-    BOOST_ASSERT_MSG(0 == output_edge_list.size(), "Vector is not empty");
-    using std::swap; // Koenig swap
-    swap(m_edge_based_edge_list, output_edge_list);
-}
-
-void EdgeBasedGraphFactory::GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes)
-{
-#ifndef NDEBUG
-    for (const EdgeBasedNode &node : m_edge_based_node_list)
-    {
-        BOOST_ASSERT(m_node_info_list.at(node.u).lat != INT_MAX);
-        BOOST_ASSERT(m_node_info_list.at(node.u).lon != INT_MAX);
-        BOOST_ASSERT(m_node_info_list.at(node.v).lon != INT_MAX);
-        BOOST_ASSERT(m_node_info_list.at(node.v).lat != INT_MAX);
-    }
-#endif
-    using std::swap; // Koenig swap
-    swap(nodes, m_edge_based_node_list);
-}
-
-void EdgeBasedGraphFactory::GetStartPointMarkers(std::vector<bool> &node_is_startpoint)
-{
-    using std::swap; // Koenig swap
-    swap(m_edge_based_node_is_startpoint, node_is_startpoint);
-}
-
-unsigned EdgeBasedGraphFactory::GetHighestEdgeID()
-{
-    return m_max_edge_id;
-}
-
-void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u,
-                                                const NodeID node_v)
-{
-    // merge edges together into one EdgeBasedNode
-    BOOST_ASSERT(node_u != SPECIAL_NODEID);
-    BOOST_ASSERT(node_v != SPECIAL_NODEID);
-
-    // find forward edge id and
-    const EdgeID edge_id_1 = m_node_based_graph->FindEdge(node_u, node_v);
-    BOOST_ASSERT(edge_id_1 != SPECIAL_EDGEID);
-
-    const EdgeData &forward_data = m_node_based_graph->GetEdgeData(edge_id_1);
-
-    // find reverse edge id and
-    const EdgeID edge_id_2 = m_node_based_graph->FindEdge(node_v, node_u);
-    BOOST_ASSERT(edge_id_2 != SPECIAL_EDGEID);
-
-    const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(edge_id_2);
-
-    if (forward_data.edge_id == SPECIAL_NODEID &&
-        reverse_data.edge_id == SPECIAL_NODEID)
-    {
-        return;
-    }
-
-    BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_1) ==
-                 m_compressed_edge_container.HasEntryForID(edge_id_2));
-    if (m_compressed_edge_container.HasEntryForID(edge_id_1))
-    {
-        BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_2));
-
-        // reconstruct geometry and put in each individual edge with its offset
-        const auto& forward_geometry = m_compressed_edge_container.GetBucketReference(edge_id_1);
-        const auto& reverse_geometry = m_compressed_edge_container.GetBucketReference(edge_id_2);
-        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
-
-        std::vector<int> forward_dist_prefix_sum(forward_geometry.size(), 0);
-        std::vector<int> reverse_dist_prefix_sum(reverse_geometry.size(), 0);
-
-        // quick'n'dirty prefix sum as std::partial_sum needs addtional casts
-        // TODO: move to lambda function with C++11
-        int temp_sum = 0;
-
-        for (const auto i : osrm::irange(0u, geometry_size))
-        {
-            forward_dist_prefix_sum[i] = temp_sum;
-            temp_sum += forward_geometry[i].second;
-
-            BOOST_ASSERT(forward_data.distance >= temp_sum);
-        }
-
-        temp_sum = 0;
-        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);
-        }
-
-        NodeID current_edge_source_coordinate_id = node_u;
-
-        // traverse arrays from start and end respectively
-        for (const auto i : osrm::irange(0u, geometry_size))
-        {
-            BOOST_ASSERT(current_edge_source_coordinate_id ==
-                         reverse_geometry[geometry_size - 1 - i].first);
-            const NodeID current_edge_target_coordinate_id = forward_geometry[i].first;
-            BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id);
-
-            // build edges
-            m_edge_based_node_list.emplace_back(
-                forward_data.edge_id, reverse_data.edge_id,
-                current_edge_source_coordinate_id, current_edge_target_coordinate_id,
-                forward_data.name_id, forward_geometry[i].second,
-                reverse_geometry[geometry_size - 1 - i].second, forward_dist_prefix_sum[i],
-                reverse_dist_prefix_sum[i], m_compressed_edge_container.GetPositionForID(edge_id_1),
-                false, INVALID_COMPONENTID, i, forward_data.travel_mode, reverse_data.travel_mode);
-            m_edge_based_node_is_startpoint.push_back(forward_data.startpoint || reverse_data.startpoint);
-            current_edge_source_coordinate_id = current_edge_target_coordinate_id;
-
-            BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
-
-            BOOST_ASSERT(node_u != m_edge_based_node_list.back().u ||
-                         node_v != m_edge_based_node_list.back().v);
-
-            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 == node_v);
-        BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
-    }
-    else
-    {
-        BOOST_ASSERT(!m_compressed_edge_container.HasEntryForID(edge_id_2));
-
-        if (forward_data.edge_id != SPECIAL_NODEID)
-        {
-            BOOST_ASSERT(!forward_data.reversed);
-        }
-        else
-        {
-            BOOST_ASSERT(forward_data.reversed);
-        }
-
-        if (reverse_data.edge_id != SPECIAL_NODEID)
-        {
-            BOOST_ASSERT(!reverse_data.reversed);
-        }
-        else
-        {
-            BOOST_ASSERT(reverse_data.reversed);
-        }
-
-        BOOST_ASSERT(forward_data.edge_id != SPECIAL_NODEID ||
-                     reverse_data.edge_id != SPECIAL_NODEID);
-
-        m_edge_based_node_list.emplace_back(
-            forward_data.edge_id, reverse_data.edge_id, node_u, node_v,
-            forward_data.name_id, forward_data.distance, reverse_data.distance, 0, 0, SPECIAL_EDGEID,
-            false, INVALID_COMPONENTID, 0, forward_data.travel_mode, reverse_data.travel_mode);
-        m_edge_based_node_is_startpoint.push_back(forward_data.startpoint || reverse_data.startpoint);
-        BOOST_ASSERT(!m_edge_based_node_list.back().IsCompressed());
-    }
-}
-
-void EdgeBasedGraphFactory::FlushVectorToStream(
-    std::ofstream &edge_data_file, std::vector<OriginalEdgeData> &original_edge_data_vector) const
-{
-    if (original_edge_data_vector.empty())
-    {
-        return;
-    }
-    edge_data_file.write((char *)&(original_edge_data_vector[0]),
-                         original_edge_data_vector.size() * sizeof(OriginalEdgeData));
-    original_edge_data_vector.clear();
-}
-
-#ifdef DEBUG_GEOMETRY
-void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename,
-                                lua_State *lua_state,
-                                const std::string &edge_segment_lookup_filename,
-                                const std::string &edge_penalty_filename,
-                                const bool generate_edge_lookup,
-                                const std::string &debug_turns_path)
-#else
-void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename,
-                                lua_State *lua_state,
-                                const std::string &edge_segment_lookup_filename,
-                                const std::string &edge_penalty_filename,
-                                const bool generate_edge_lookup)
-#endif
-{
-    TIMER_START(renumber);
-    m_max_edge_id = RenumberEdges() - 1;
-    TIMER_STOP(renumber);
-
-    TIMER_START(generate_nodes);
-    GenerateEdgeExpandedNodes();
-    TIMER_STOP(generate_nodes);
-
-    TIMER_START(generate_edges);
-#ifdef DEBUG_GEOMETRY
-    GenerateEdgeExpandedEdges(original_edge_data_filename, lua_state,
-            edge_segment_lookup_filename,edge_penalty_filename, 
-            generate_edge_lookup, debug_turns_path);
-#else
-    GenerateEdgeExpandedEdges(original_edge_data_filename, lua_state,
-            edge_segment_lookup_filename,edge_penalty_filename, 
-            generate_edge_lookup);
-#endif
-
-    TIMER_STOP(generate_edges);
-
-    SimpleLogger().Write() << "Timing statistics for edge-expanded graph:";
-    SimpleLogger().Write() << "Renumbering edges: " << TIMER_SEC(renumber) << "s";
-    SimpleLogger().Write() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s";
-    SimpleLogger().Write() << "Generating edges: " << TIMER_SEC(generate_edges) << "s";
-}
-
-
-/// Renumbers all _forward_ edges and sets the edge_id.
-/// A specific numbering is not important. Any unique ID will do.
-/// Returns the number of edge based nodes.
-unsigned EdgeBasedGraphFactory::RenumberEdges()
-{
-    // renumber edge based node of outgoing edges
-    unsigned numbered_edges_count = 0;
-    for (const auto current_node : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
-    {
-        for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
-        {
-            EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
-
-            // only number incoming edges
-            if (edge_data.reversed)
-            {
-                continue;
-            }
-
-            BOOST_ASSERT(numbered_edges_count < m_node_based_graph->GetNumberOfEdges());
-            edge_data.edge_id = numbered_edges_count;
-            ++numbered_edges_count;
-
-            BOOST_ASSERT(SPECIAL_NODEID != edge_data.edge_id);
-        }
-    }
-
-    return numbered_edges_count;
-}
-
-/// Creates the nodes in the edge expanded graph from edges in the node-based graph.
-void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
-{
-    Percent progress(m_node_based_graph->GetNumberOfNodes());
-
-    // loop over all edges and generate new set of nodes
-    for (const auto node_u : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
-    {
-        BOOST_ASSERT(node_u != SPECIAL_NODEID);
-        BOOST_ASSERT(node_u < m_node_based_graph->GetNumberOfNodes());
-        progress.printStatus(node_u);
-        for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
-        {
-            const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
-            BOOST_ASSERT(e1 != SPECIAL_EDGEID);
-            const NodeID node_v = m_node_based_graph->GetTarget(e1);
-
-            BOOST_ASSERT(SPECIAL_NODEID != node_v);
-            // pick only every other edge, since we have every edge as an outgoing
-            // and incoming egde
-            if (node_u > node_v)
-            {
-                continue;
-            }
-
-            BOOST_ASSERT(node_u < node_v);
-
-            // if we found a non-forward edge reverse and try again
-            if (edge_data.edge_id == SPECIAL_NODEID)
-            {
-                InsertEdgeBasedNode(node_v, node_u);
-            }
-            else
-            {
-                InsertEdgeBasedNode(node_u, node_v);
-            }
-        }
-    }
-
-    BOOST_ASSERT(m_edge_based_node_list.size() == m_edge_based_node_is_startpoint.size());
-
-    SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
-                           << " nodes in edge-expanded graph";
-}
-
-/// Actually it also generates OriginalEdgeData and serializes them...
-#ifdef DEBUG_GEOMETRY
-void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
-    const std::string &original_edge_data_filename, lua_State *lua_state,
-    const std::string &edge_segment_lookup_filename,
-    const std::string &edge_fixed_penalties_filename,
-    const bool generate_edge_lookup, 
-    const std::string &debug_turns_path)
-#else
-void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
-    const std::string &original_edge_data_filename, lua_State *lua_state,
-    const std::string &edge_segment_lookup_filename,
-    const std::string &edge_fixed_penalties_filename,
-    const bool generate_edge_lookup)
-#endif
-{
-    SimpleLogger().Write() << "generating edge-expanded edges";
-
-    unsigned node_based_edge_counter = 0;
-    unsigned original_edges_counter = 0;
-
-    std::ofstream edge_data_file(original_edge_data_filename.c_str(), std::ios::binary);
-    std::ofstream edge_segment_file;
-    std::ofstream edge_penalty_file;
-
-    if (generate_edge_lookup)
-    {
-        edge_segment_file.open(edge_segment_lookup_filename.c_str(), std::ios::binary);
-        edge_penalty_file.open(edge_fixed_penalties_filename.c_str(), std::ios::binary);
-    }
-
-    // writes a dummy value that is updated later
-    edge_data_file.write((char *)&original_edges_counter, sizeof(unsigned));
-
-    std::vector<OriginalEdgeData> original_edge_data_vector;
-    original_edge_data_vector.reserve(1024 * 1024);
-
-    // Loop over all turns and generate new set of edges.
-    // Three nested loop look super-linear, but we are dealing with a (kind of)
-    // linear number of turns only.
-    unsigned restricted_turns_counter = 0;
-    unsigned skipped_uturns_counter = 0;
-    unsigned skipped_barrier_turns_counter = 0;
-    unsigned compressed = 0;
-
-    Percent progress(m_node_based_graph->GetNumberOfNodes());
-
-#ifdef DEBUG_GEOMETRY
-    DEBUG_TURNS_START(debug_turns_path);
-#endif
-
-    for (const auto node_u : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
-    {
-        //progress.printStatus(node_u);
-        for (const EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
-        {
-            if (m_node_based_graph->GetEdgeData(e1).reversed)
-            {
-                continue;
-            }
-
-            ++node_based_edge_counter;
-            const NodeID node_v = m_node_based_graph->GetTarget(e1);
-            const NodeID only_restriction_to_node =
-                m_restriction_map->CheckForEmanatingIsOnlyTurn(node_u, node_v);
-            const bool is_barrier_node = m_barrier_nodes.find(node_v) != m_barrier_nodes.end();
-
-            for (const EdgeID e2 : m_node_based_graph->GetAdjacentEdgeRange(node_v))
-            {
-                if (m_node_based_graph->GetEdgeData(e2).reversed)
-                {
-                    continue;
-                }
-                const NodeID node_w = m_node_based_graph->GetTarget(e2);
-
-                if ((only_restriction_to_node != SPECIAL_NODEID) &&
-                    (node_w != only_restriction_to_node))
-                {
-                    // We are at an only_-restriction but not at the right turn.
-                    ++restricted_turns_counter;
-                    continue;
-                }
-
-                if (is_barrier_node)
-                {
-                    if (node_u != node_w)
-                    {
-                        ++skipped_barrier_turns_counter;
-                        continue;
-                    }
-                }
-                else
-                {
-                    if (node_u == node_w && m_node_based_graph->GetOutDegree(node_v) > 1)
-                    {
-                        auto number_of_emmiting_bidirectional_edges = 0;
-                        for (auto edge : m_node_based_graph->GetAdjacentEdgeRange(node_v))
-                        {
-                            auto target = m_node_based_graph->GetTarget(edge);
-                            auto reverse_edge = m_node_based_graph->FindEdge(target, node_v);
-                            if (!m_node_based_graph->GetEdgeData(reverse_edge).reversed)
-                            {
-                                ++number_of_emmiting_bidirectional_edges;
-                            }
-                        }
-                        if (number_of_emmiting_bidirectional_edges > 1)
-                        {
-                            ++skipped_uturns_counter;
-                            continue;
-                        }
-                    }
-                }
-
-                // 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(node_u, node_v, node_w) &&
-                    (only_restriction_to_node == SPECIAL_NODEID) &&
-                    (node_w != only_restriction_to_node))
-                {
-                    // We are at an only_-restriction but not at the right turn.
-                    ++restricted_turns_counter;
-                    continue;
-                }
-
-                // only add an edge if turn is not prohibited
-                const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(e1);
-                const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(e2);
-
-                BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
-                BOOST_ASSERT(!edge_data1.reversed);
-                BOOST_ASSERT(!edge_data2.reversed);
-
-                // the following is the core of the loop.
-                unsigned distance = edge_data1.distance;
-                if (m_traffic_lights.find(node_v) != m_traffic_lights.end())
-                {
-                    distance += speed_profile.traffic_signal_penalty;
-
-                    DEBUG_SIGNAL(node_v, m_node_info_list, speed_profile.traffic_signal_penalty);
-                }
-
-                // unpack last node of first segment if packed
-                const auto first_coordinate =
-                    m_node_info_list[(m_compressed_edge_container.HasEntryForID(e1)
-                                          ? m_compressed_edge_container.GetLastEdgeSourceID(e1)
-                                          : node_u)];
-
-                // unpack first node of second segment if packed
-                const auto third_coordinate =
-                    m_node_info_list[(m_compressed_edge_container.HasEntryForID(e2)
-                                          ? m_compressed_edge_container.GetFirstEdgeTargetID(e2)
-                                          : node_w)];
-
-                const double turn_angle = ComputeAngle::OfThreeFixedPointCoordinates(
-                    first_coordinate, m_node_info_list[node_v], third_coordinate);
-
-                const int turn_penalty = GetTurnPenalty(turn_angle, lua_state);
-                TurnInstruction turn_instruction = AnalyzeTurn(node_u, node_v, node_w, turn_angle);
-                if (turn_instruction == TurnInstruction::UTurn)
-                {
-                    distance += speed_profile.u_turn_penalty;
-
-                    DEBUG_UTURN(node_v, m_node_info_list, speed_profile.u_turn_penalty);
-                } 
-
-                DEBUG_TURN(node_v, m_node_info_list, first_coordinate, turn_angle, turn_penalty);
-
-                distance += turn_penalty;
-
-                const bool edge_is_compressed = m_compressed_edge_container.HasEntryForID(e1);
-
-                if (edge_is_compressed)
-                {
-                    ++compressed;
-                }
-
-                original_edge_data_vector.emplace_back(
-                    (edge_is_compressed ? m_compressed_edge_container.GetPositionForID(e1) : node_v),
-                    edge_data1.name_id, turn_instruction, edge_is_compressed,
-                    edge_data2.travel_mode);
-
-                ++original_edges_counter;
-
-                if (original_edge_data_vector.size() > 1024 * 1024 * 10)
-                {
-                    FlushVectorToStream(edge_data_file, original_edge_data_vector);
-                }
-
-                BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id);
-                BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id);
-
-
-                // NOTE: potential overflow here if we hit 2^32 routable edges
-                BOOST_ASSERT(m_edge_based_edge_list.size() <= std::numeric_limits<NodeID>::max());
-                m_edge_based_edge_list.emplace_back(edge_data1.edge_id, edge_data2.edge_id,
-                                  m_edge_based_edge_list.size(), distance, true, false);
-
-
-                // Here is where we write out the mapping between the edge-expanded edges, and
-                // the node-based edges that are originally used to calculate the `distance`
-                // for the edge-expanded edges.  About 40 lines back, there is:
-                //
-                //                 unsigned distance = edge_data1.distance;
-                //
-                // This tells us that the weight for an edge-expanded-edge is based on the weight
-                // of the *source* node-based edge.  Therefore, we will look up the individual
-                // segments of the source node-based edge, and write out a mapping between
-                // those and the edge-based-edge ID.
-                // External programs can then use this mapping to quickly perform
-                // updates to the edge-expanded-edge based directly on its ID.
-                if (generate_edge_lookup)
-                {
-                    unsigned fixed_penalty = distance - edge_data1.distance;
-                    edge_penalty_file.write(reinterpret_cast<const char *>(&fixed_penalty), sizeof(fixed_penalty));
-                    if (edge_is_compressed)
-                    {
-                        const auto node_based_edges = m_compressed_edge_container.GetBucketReference(e1);
-                        NodeID previous = node_u;
-
-                        const unsigned node_count = node_based_edges.size()+1;
-                        edge_segment_file.write(reinterpret_cast<const char *>(&node_count), sizeof(node_count));
-                        const QueryNode &first_node = m_node_info_list[previous];
-                        edge_segment_file.write(reinterpret_cast<const char *>(&first_node.node_id), sizeof(first_node.node_id));
-
-                        for (auto target_node : node_based_edges)
-                        {
-                            const QueryNode &from = m_node_info_list[previous];
-                            const QueryNode &to = m_node_info_list[target_node.first];
-                            const double segment_length = coordinate_calculation::great_circle_distance(from.lat, from.lon, to.lat, to.lon);
-
-                            edge_segment_file.write(reinterpret_cast<const char *>(&to.node_id), sizeof(to.node_id));
-                            edge_segment_file.write(reinterpret_cast<const char *>(&segment_length), sizeof(segment_length));
-                            edge_segment_file.write(reinterpret_cast<const char *>(&target_node.second), sizeof(target_node.second));
-                            previous = target_node.first;
-                        }
-                    }
-                    else
-                    {
-                        static const unsigned node_count = 2;
-                        const QueryNode from = m_node_info_list[node_u];
-                        const QueryNode to = m_node_info_list[node_v];
-                        const double segment_length = coordinate_calculation::great_circle_distance(from.lat, from.lon, to.lat, to.lon);
-                        edge_segment_file.write(reinterpret_cast<const char *>(&node_count), sizeof(node_count));
-                        edge_segment_file.write(reinterpret_cast<const char *>(&from.node_id), sizeof(from.node_id));
-                        edge_segment_file.write(reinterpret_cast<const char *>(&to.node_id), sizeof(to.node_id));
-                        edge_segment_file.write(reinterpret_cast<const char *>(&segment_length), sizeof(segment_length));
-                        edge_segment_file.write(reinterpret_cast<const char *>(&edge_data1.distance), sizeof(edge_data1.distance));
-                    }
-                }
-            }
-        }
-    }
-
-    DEBUG_TURNS_STOP();
-
-    FlushVectorToStream(edge_data_file, original_edge_data_vector);
-
-    edge_data_file.seekp(std::ios::beg);
-    edge_data_file.write((char *)&original_edges_counter, sizeof(unsigned));
-    edge_data_file.close();
-
-    SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size() << " edge based nodes";
-    SimpleLogger().Write() << "Node-based graph contains " << node_based_edge_counter << " edges";
-    SimpleLogger().Write() << "Edge-expanded graph ...";
-    SimpleLogger().Write() << "  contains " << m_edge_based_edge_list.size() << " edges";
-    SimpleLogger().Write() << "  skips " << restricted_turns_counter << " turns, "
-                                                                        "defined by "
-                           << m_restriction_map->size() << " restrictions";
-    SimpleLogger().Write() << "  skips " << skipped_uturns_counter << " U turns";
-    SimpleLogger().Write() << "  skips " << skipped_barrier_turns_counter << " turns over barriers";
-}
-
-int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) const
-{
-
-    if (speed_profile.has_turn_penalty_function)
-    {
-        try
-        {
-            // call lua profile to compute turn penalty
-            double penalty = luabind::call_function<double>(lua_state, "turn_function", 180. - angle);
-            return static_cast<int>(penalty);
-        }
-        catch (const luabind::error &er)
-        {
-            SimpleLogger().Write(logWARNING) << er.what();
-        }
-    }
-    return 0;
-}
-
-TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID node_u,
-                                                   const NodeID node_v,
-                                                   const NodeID node_w,
-                                                   const double angle) const
-{
-    if (node_u == node_w)
-    {
-        return TurnInstruction::UTurn;
-    }
-
-    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);
-
-    // 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(node_v))
-        {
-            // No turn possible.
-            return TurnInstruction::NoTurn;
-        }
-        return TurnInstruction::StayOnRoundAbout;
-    }
-    // Does turn start or end on roundabout?
-    if (data1.roundabout || data2.roundabout)
-    {
-        // We are entering the roundabout
-        if ((!data1.roundabout) && data2.roundabout)
-        {
-            return TurnInstruction::EnterRoundAbout;
-        }
-        // We are leaving the roundabout
-        if (data1.roundabout && (!data2.roundabout))
-        {
-            return TurnInstruction::LeaveRoundAbout;
-        }
-    }
-
-    // If street names stay the same and if we are certain that it is not a
-    // a segment of a roundabout, we skip it.
-    if (data1.name_id == data2.name_id && data1.travel_mode == data2.travel_mode)
-    {
-        // TODO: Here we should also do a small graph exploration to check for
-        //      more complex situations
-        if (0 != data1.name_id || m_node_based_graph->GetOutDegree(node_v) <= 2)
-        {
-            return TurnInstruction::NoTurn;
-        }
-    }
-
-    return TurnInstructionsClass::GetTurnDirectionOfInstruction(angle);
-}
-
diff --git a/extractor/edge_based_graph_factory.hpp b/extractor/edge_based_graph_factory.hpp
deleted file mode 100644
index 997c7ea..0000000
--- a/extractor/edge_based_graph_factory.hpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
-
-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.
-
-*/
-
-//  This class constructs the edge-expanded routing graph
-
-#ifndef EDGE_BASED_GRAPH_FACTORY_HPP_
-#define EDGE_BASED_GRAPH_FACTORY_HPP_
-
-#include "speed_profile.hpp"
-#include "../typedefs.h"
-#include "../data_structures/compressed_edge_container.hpp"
-#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>
-#include <memory>
-#include <queue>
-#include <string>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-#include <boost/filesystem/fstream.hpp>
-
-struct lua_State;
-
-class EdgeBasedGraphFactory
-{
-  public:
-    EdgeBasedGraphFactory() = delete;
-    EdgeBasedGraphFactory(const EdgeBasedGraphFactory &) = delete;
-
-    explicit EdgeBasedGraphFactory(std::shared_ptr<NodeBasedDynamicGraph> node_based_graph,
-                                   const CompressedEdgeContainer &compressed_edge_container,
-                                   const std::unordered_set<NodeID> &barrier_nodes,
-                                   const std::unordered_set<NodeID> &traffic_lights,
-                                   std::shared_ptr<const RestrictionMap> restriction_map,
-                                   const std::vector<QueryNode> &node_info_list,
-                                   SpeedProfileProperties speed_profile);
-
-#ifdef DEBUG_GEOMETRY
-    void Run(const std::string &original_edge_data_filename,
-             lua_State *lua_state,
-             const std::string &edge_segment_lookup_filename,
-             const std::string &edge_penalty_filename,
-             const bool generate_edge_lookup,
-             const std::string &debug_turns_path);
-#else
-    void Run(const std::string &original_edge_data_filename,
-             lua_State *lua_state,
-             const std::string &edge_segment_lookup_filename,
-             const std::string &edge_penalty_filename,
-             const bool generate_edge_lookup);
-#endif
-
-    void GetEdgeBasedEdges(DeallocatingVector<EdgeBasedEdge> &edges);
-
-    void GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes);
-    void GetStartPointMarkers(std::vector<bool> &node_is_startpoint);
-
-    unsigned GetHighestEdgeID();
-
-    TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, const double angle) const;
-
-    int GetTurnPenalty(double angle, lua_State *lua_state) const;
-
-  private:
-    using EdgeData = NodeBasedDynamicGraph::EdgeData;
-
-    //! maps index from m_edge_based_node_list to ture/false if the node is an entry point to the graph
-    std::vector<bool> m_edge_based_node_is_startpoint;
-    //! list of edge based nodes (compressed segments)
-    std::vector<EdgeBasedNode> m_edge_based_node_list;
-    DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
-    unsigned m_max_edge_id;
-
-    const std::vector<QueryNode>& m_node_info_list;
-    std::shared_ptr<NodeBasedDynamicGraph> m_node_based_graph;
-    std::shared_ptr<RestrictionMap const> m_restriction_map;
-
-    const std::unordered_set<NodeID>& m_barrier_nodes;
-    const std::unordered_set<NodeID>& m_traffic_lights;
-    const CompressedEdgeContainer& m_compressed_edge_container;
-
-    SpeedProfileProperties speed_profile;
-
-    void CompressGeometry();
-    unsigned RenumberEdges();
-    void GenerateEdgeExpandedNodes();
-#ifdef DEBUG_GEOMETRY
-    void GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
-                                   lua_State *lua_state,
-                                   const std::string &edge_segment_lookup_filename,
-                                   const std::string &edge_fixed_penalties_filename,
-                                   const bool generate_edge_lookup,
-                                   const std::string &debug_turns_path);
-#else
-    void GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
-                                   lua_State *lua_state,
-                                   const std::string &edge_segment_lookup_filename,
-                                   const std::string &edge_fixed_penalties_filename,
-                                   const bool generate_edge_lookup);
-#endif 
-
-    void InsertEdgeBasedNode(const NodeID u, const NodeID v);
-
-    void FlushVectorToStream(std::ofstream &edge_data_file,
-                             std::vector<OriginalEdgeData> &original_edge_data_vector) const;
-
-};
-
-#endif /* EDGE_BASED_GRAPH_FACTORY_HPP_ */
diff --git a/extractor/extraction_node.hpp b/extractor/extraction_node.hpp
deleted file mode 100644
index e821d6f..0000000
--- a/extractor/extraction_node.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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_NODE_HPP
-#define EXTRACTION_NODE_HPP
-
-struct ExtractionNode
-{
-    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
deleted file mode 100644
index 094c10a..0000000
--- a/extractor/extraction_way.hpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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>
-
-/**
- * This struct is the direct result of the call to ```way_function```
- * in the lua based profile.
- *
- * It is split into multiple edge segments in the ExtractorCallback.
- */
-struct ExtractionWay
-{
-    ExtractionWay() { clear(); }
-
-    void clear()
-    {
-        forward_speed = -1;
-        backward_speed = -1;
-        duration = -1;
-        roundabout = false;
-        is_startpoint = true;
-        is_access_restricted = 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 is_startpoint;
-    TravelMode forward_travel_mode : 4;
-    TravelMode backward_travel_mode : 4;
-};
-
-#endif // EXTRACTION_WAY_HPP
diff --git a/extractor/extractor_options.cpp b/extractor/extractor_options.cpp
deleted file mode 100644
index b607dca..0000000
--- a/extractor/extractor_options.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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/version.hpp"
-#include "../util/ini_file.hpp"
-#include "../util/simple_logger.hpp"
-
-#include <boost/filesystem.hpp>
-#include <boost/program_options.hpp>
-
-#include <tbb/task_scheduler_init.h>
-
-return_code
-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")(
-        /*
-         * TODO: re-enable this
-        "restrictions,r",
-        boost::program_options::value<boost::filesystem::path>(&extractor_config.restrictions_path),
-        "Restrictions file in .osrm.restrictions format")(
-        */
-        "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")(
-            "generate-edge-lookup",boost::program_options::value<bool>(
-                                                &extractor_config.generate_edge_lookup)->implicit_value(true)->default_value(false),
-                                 "Generate a lookup table for internal edge-expanded-edge IDs to OSM node pairs")(
-        "small-component-size",
-        boost::program_options::value<unsigned int>(&extractor_config.small_component_size)
-            ->default_value(1000),
-        "Number of nodes required before a strongly-connected-componennt is considered big (affects nearest neighbor snapping)");
-
-#ifdef DEBUG_GEOMETRY
-        config_options.add_options()("debug-turns",
-            boost::program_options::value<std::string>(&extractor_config.debug_turns_path),
-            "Write out GeoJSON with turn penalty data");
-#endif // DEBUG_GEOMETRY
-
-    // 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
-    try
-    {
-        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() << OSRM_VERSION;
-            return return_code::exit;
-        }
-
-        if (option_variables.count("help"))
-        {
-            SimpleLogger().Write() << visible_options;
-            return return_code::exit;
-        }
-
-        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 =
-                read_file_lower_content(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 return_code::exit;
-        }
-    }
-    catch (std::exception &e)
-    {
-        SimpleLogger().Write(logWARNING) << e.what();
-        return return_code::fail;
-    }
-
-    return return_code::ok;
-}
-
-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.names_file_name = input_path.string();
-    extractor_config.timestamp_file_name = input_path.string();
-    extractor_config.geometry_output_path = input_path.string();
-    extractor_config.edge_output_path = input_path.string();
-    extractor_config.edge_graph_output_path = input_path.string();
-    extractor_config.node_output_path = input_path.string();
-    extractor_config.rtree_nodes_output_path = input_path.string();
-    extractor_config.rtree_leafs_output_path = input_path.string();
-    extractor_config.edge_segment_lookup_path = input_path.string();
-    extractor_config.edge_penalty_path = 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.names_file_name.append(".osrm.names");
-            extractor_config.timestamp_file_name.append(".osrm.timestamp");
-            extractor_config.geometry_output_path.append(".osrm.geometry");
-            extractor_config.node_output_path.append(".osrm.nodes");
-            extractor_config.edge_output_path.append(".osrm.edges");
-            extractor_config.edge_graph_output_path.append(".osrm.ebg");
-            extractor_config.rtree_nodes_output_path.append(".osrm.ramIndex");
-            extractor_config.rtree_leafs_output_path.append(".osrm.fileIndex");
-            extractor_config.edge_segment_lookup_path.append(".osrm.edge_segment_lookup");
-            extractor_config.edge_penalty_path.append(".osrm.edge_penalties");
-        }
-        else
-        {
-            extractor_config.output_file_name.replace(pos, 5, ".osrm");
-            extractor_config.restriction_file_name.replace(pos, 5, ".osrm.restrictions");
-            extractor_config.names_file_name.replace(pos, 5, ".osrm.names");
-            extractor_config.timestamp_file_name.replace(pos, 5, ".osrm.timestamp");
-            extractor_config.geometry_output_path.replace(pos, 5, ".osrm.geometry");
-            extractor_config.node_output_path.replace(pos, 5, ".osrm.nodes");
-            extractor_config.edge_output_path.replace(pos, 5, ".osrm.edges");
-            extractor_config.edge_graph_output_path.replace(pos, 5, ".osrm.ebg");
-            extractor_config.rtree_nodes_output_path.replace(pos, 5, ".osrm.ramIndex");
-            extractor_config.rtree_leafs_output_path.replace(pos, 5, ".osrm.fileIndex");
-            extractor_config.edge_segment_lookup_path.replace(pos,5, ".osrm.edge_segment_lookup");
-            extractor_config.edge_penalty_path.replace(pos,5, ".osrm.edge_penalties");
-        }
-    }
-    else
-    {
-        extractor_config.output_file_name.replace(pos, 8, ".osrm");
-        extractor_config.restriction_file_name.replace(pos, 8, ".osrm.restrictions");
-        extractor_config.names_file_name.replace(pos, 8, ".osrm.names");
-        extractor_config.timestamp_file_name.replace(pos, 8, ".osrm.timestamp");
-        extractor_config.geometry_output_path.replace(pos, 8, ".osrm.geometry");
-        extractor_config.node_output_path.replace(pos, 8, ".osrm.nodes");
-        extractor_config.edge_output_path.replace(pos, 8, ".osrm.edges");
-        extractor_config.edge_graph_output_path.replace(pos, 8, ".osrm.ebg");
-        extractor_config.rtree_nodes_output_path.replace(pos, 8, ".osrm.ramIndex");
-        extractor_config.rtree_leafs_output_path.replace(pos, 8, ".osrm.fileIndex");
-        extractor_config.edge_segment_lookup_path.replace(pos,8, ".osrm.edge_segment_lookup");
-        extractor_config.edge_penalty_path.replace(pos,8, ".osrm.edge_penalties");
-    }
-}
diff --git a/extractor/first_and_last_segment_of_way.hpp b/extractor/first_and_last_segment_of_way.hpp
deleted file mode 100644
index ead8b4c..0000000
--- a/extractor/first_and_last_segment_of_way.hpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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
-{
-    OSMWayID way_id;
-    OSMNodeID first_segment_source_id;
-    OSMNodeID first_segment_target_id;
-    OSMNodeID last_segment_source_id;
-    OSMNodeID last_segment_target_id;
-
-    FirstAndLastSegmentOfWay()
-        : way_id(SPECIAL_OSM_WAYID),
-          first_segment_source_id(SPECIAL_OSM_NODEID),
-          first_segment_target_id(SPECIAL_OSM_NODEID),
-          last_segment_source_id(SPECIAL_OSM_NODEID),
-          last_segment_target_id(SPECIAL_OSM_NODEID)
-    {
-    }
-
-    FirstAndLastSegmentOfWay(OSMWayID w, OSMNodeID fs, OSMNodeID ft, OSMNodeID ls, OSMNodeID 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 {MIN_OSM_WAYID,
-                MIN_OSM_NODEID,
-                MIN_OSM_NODEID,
-                MIN_OSM_NODEID,
-                MIN_OSM_NODEID};
-    }
-    static FirstAndLastSegmentOfWay max_value()
-    {
-        return {MAX_OSM_WAYID,
-                MAX_OSM_NODEID,
-                MAX_OSM_NODEID,
-                MAX_OSM_NODEID,
-                MAX_OSM_NODEID};
-    }
-};
-
-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/restriction_parser.hpp b/extractor/restriction_parser.hpp
deleted file mode 100644
index 11f94ee..0000000
--- a/extractor/restriction_parser.hpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 RESTRICTION_PARSER_HPP
-#define RESTRICTION_PARSER_HPP
-
-#include "../data_structures/restriction.hpp"
-
-#include <boost/optional/optional.hpp>
-
-#include <string>
-#include <vector>
-
-struct lua_State;
-namespace osmium
-{
-class Relation;
-}
-
-/**
- * Parses the relations that represents turn restrictions.
- *
- * Currently only restrictions where the via objects is a node are supported.
- *  from   via   to
- * ------->(x)-------->
- *
- * While this class does not directly invoke any lua code _per relation_ it does
- * load configuration values from the profile, that are saved in variables.
- * Namely ```use_turn_restrictions``` and ```get_exceptions```.
- *
- * The restriction is represented by the osm id of the from way, the osm id of the
- * to way and the osm id of the via node. This representation must be post-processed
- * in the extractor to work with the edge-based data-model of OSRM:
- * Since the from and to way share the via-node a turn will have the following form:
- * ...----(a)-----(via)------(b)----...
- * So it can be represented by the tripe (a, via, b).
- */
-class RestrictionParser
-{
-  public:
-    RestrictionParser(lua_State *lua_state);
-    boost::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;
-
-    std::vector<std::string> restriction_exceptions;
-    bool use_turn_restrictions;
-};
-
-#endif /* RESTRICTION_PARSER_HPP */
diff --git a/extractor/scripting_environment.cpp b/extractor/scripting_environment.cpp
deleted file mode 100644
index 7ccc08a..0000000
--- a/extractor/scripting_environment.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "internal_extractor_edge.hpp"
-#include "../data_structures/external_memory_node.hpp"
-#include "../data_structures/raster_source.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 <luabind/operator.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()
-{
-    std::string error_msg = lua_tostring(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_<SourceContainer>("sources")
-            .def(luabind::constructor<>())
-            .def("load", &SourceContainer::loadRasterSource)
-            .def("query", &SourceContainer::getRasterDataFromSource)
-            .def("interpolate", &SourceContainer::getRasterInterpolateFromSource),
-        luabind::class_<const float>("constants")
-            .enum_("enums")[luabind::value("precision", COORDINATE_PRECISION)],
-
-        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("location", &osmium::Node::location)
-            .def("get_value_by_key", &osmium::Node::get_value_by_key)
-            .def("get_value_by_key", &get_value_by_key<osmium::Node>)
-            .def("id", &osmium::Node::id),
-
-        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("is_startpoint", &ExtractionWay::is_startpoint)
-            .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>)
-            .def("id", &osmium::Way::id),
-        luabind::class_<InternalExtractorEdge>("EdgeSource")
-            .property("source_coordinate", &InternalExtractorEdge::source_coordinate)
-            .property("weight_data", &InternalExtractorEdge::weight_data),
-        luabind::class_<InternalExtractorEdge::WeightData>("WeightData")
-            .def_readwrite("speed", &InternalExtractorEdge::WeightData::speed),
-        luabind::class_<ExternalMemoryNode>("EdgeTarget")
-            .property("lat", &ExternalMemoryNode::lat)
-            .property("lon", &ExternalMemoryNode::lon),
-        luabind::class_<FixedPointCoordinate>("Coordinate")
-            .property("lat", &FixedPointCoordinate::lat)
-            .property("lon", &FixedPointCoordinate::lon),
-        luabind::class_<RasterDatum>("RasterDatum")
-            .property("datum", &RasterDatum::datum)
-            .def("invalid_data", &RasterDatum::get_invalid)
-    ];
-
-    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/scripting_environment.hpp b/extractor/scripting_environment.hpp
deleted file mode 100644
index 8722aee..0000000
--- a/extractor/scripting_environment.hpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 SCRIPTING_ENVIRONMENT_HPP
-#define SCRIPTING_ENVIRONMENT_HPP
-
-#include <string>
-#include <memory>
-#include <mutex>
-#include <tbb/enumerable_thread_specific.h>
-
-struct lua_State;
-
-/**
- * Creates a lua context and binds osmium way, node and relation objects and
- * ExtractionWay and ExtractionNode to lua objects.
- *
- * Each thread has its own lua state which is implemented with thread specific
- * storage from TBB.
- */
-class ScriptingEnvironment
-{
-  public:
-    ScriptingEnvironment() = delete;
-    explicit ScriptingEnvironment(const std::string &file_name);
-
-    lua_State *get_lua_state();
-
-  private:
-    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 /* SCRIPTING_ENVIRONMENT_HPP */
diff --git a/extractor/speed_profile.hpp b/extractor/speed_profile.hpp
deleted file mode 100644
index 534ccce..0000000
--- a/extractor/speed_profile.hpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef SPEED_PROFILE_PROPERTIES_HPP
-#define SPEED_PROFILE_PROPERTIES_HPP
-
-struct SpeedProfileProperties
-{
-  SpeedProfileProperties()
-    : traffic_signal_penalty(0), u_turn_penalty(0), has_turn_penalty_function(false)
-  {
-  }
-
-  int traffic_signal_penalty;
-  int u_turn_penalty;
-  bool has_turn_penalty_function;
-};
-
-#endif
diff --git a/features/bicycle/area.feature b/features/bicycle/area.feature
index 062e86f..626b383 100644
--- a/features/bicycle/area.feature
+++ b/features/bicycle/area.feature
@@ -4,7 +4,7 @@ Feature: Bike - Squares and other areas
     Background:
         Given the profile "bicycle"
 
-    @square
+    @square @mokob @2154
     Scenario: Bike - Route along edge of a squares
         Given the node map
             | x |   |
@@ -17,15 +17,15 @@ Feature: Bike - Squares and other areas
             | abcda | yes  | residential |
 
         When I route I should get
-            | from | to | route |
-            | a    | b  | abcda |
-            | a    | d  | abcda |
-            | b    | c  | abcda |
-            | c    | b  | abcda |
-            | c    | d  | abcda |
-            | d    | c  | abcda |
-            | d    | a  | abcda |
-            | a    | d  | abcda |
+            | from | to | route       |
+            | a    | b  | abcda,abcda |
+            | a    | d  | abcda,abcda |
+            | b    | c  | abcda,abcda |
+            | c    | b  | abcda,abcda |
+            | c    | d  | abcda,abcda |
+            | d    | c  | abcda,abcda |
+            | d    | a  | abcda,abcda |
+            | a    | d  | abcda,abcda |
 
     @building
     Scenario: Bike - Don't route on buildings
@@ -41,16 +41,16 @@ Feature: Bike - Squares and other areas
 
         When I route I should get
             | from | to | route |
-            | a    | b  | xa    |
-            | a    | d  | xa    |
-            | b    | c  | xa    |
-            | c    | b  | xa    |
-            | c    | d  | xa    |
-            | d    | c  | xa    |
-            | d    | a  | xa    |
-            | a    | d  | xa    |
+            | a    | b  | xa,xa |
+            | a    | d  | xa,xa |
+            | b    | c  | xa,xa |
+            | c    | b  | xa,xa |
+            | c    | d  | xa,xa |
+            | d    | c  | xa,xa |
+            | d    | a  | xa,xa |
+            | a    | d  | xa,xa |
 
-    @parking
+    @parking @mokob @2154
     Scenario: Bike - parking areas
         Given the node map
             | e |   |   | f |
@@ -65,19 +65,20 @@ Feature: Bike - Squares and other areas
             | abcda | (nil)   | parking |
 
         When I route I should get
-            | from | to | route       |
-            | x    | y  | xa,abcda,by |
-            | y    | x  | by,abcda,xa |
-            | a    | b  | abcda       |
-            | a    | d  | abcda       |
-            | b    | c  | abcda       |
-            | c    | b  | abcda       |
-            | c    | d  | abcda       |
-            | d    | c  | abcda       |
-            | d    | a  | abcda       |
-            | a    | d  | abcda       |
+            | from | to | route          |
+            | x    | y  | xa,abcda,by,by |
+            | y    | x  | by,abcda,xa,xa |
+            | a    | b  | abcda,abcda    |
+            | a    | d  | abcda,abcda    |
+            | b    | c  | abcda,abcda    |
+            | c    | b  | abcda,abcda    |
+            | c    | d  | abcda,abcda    |
+            | d    | c  | abcda,abcda    |
+            | d    | a  | abcda,abcda    |
+            | a    | d  | abcda,abcda    |
 
-    @train @platform
+
+    @train @platform @mokob @2154
     Scenario: Bike - railway platforms
         Given the node map
             | x | a | b | y |
@@ -90,14 +91,14 @@ Feature: Bike - Squares and other areas
             | abcda | (nil)   | platform |
 
         When I route I should get
-            | from | to | route       |
-            | x    | y  | xa,abcda,by |
-            | y    | x  | by,abcda,xa |
-            | a    | b  | abcda       |
-            | a    | d  | abcda       |
-            | b    | c  | abcda       |
-            | c    | b  | abcda       |
-            | c    | d  | abcda       |
-            | d    | c  | abcda       |
-            | d    | a  | abcda       |
-            | a    | d  | abcda       |
+            | from | to | route          |
+            | x    | y  | xa,abcda,by,by |
+            | y    | x  | by,abcda,xa,xa |
+            | a    | b  | abcda,abcda    |
+            | a    | d  | abcda,abcda    |
+            | b    | c  | abcda,abcda    |
+            | c    | b  | abcda,abcda    |
+            | c    | d  | abcda,abcda    |
+            | d    | c  | abcda,abcda    |
+            | d    | a  | abcda,abcda    |
+            | a    | d  | abcda,abcda    |
diff --git a/features/bicycle/bridge.feature b/features/bicycle/bridge.feature
index 8c26ee9..e691ae1 100644
--- a/features/bicycle/bridge.feature
+++ b/features/bicycle/bridge.feature
@@ -4,7 +4,7 @@ Feature: Bicycle - Handle movable bridge
     Background:
         Given the profile "bicycle"
 
-    Scenario: Car - Use a ferry route
+    Scenario: Bicycle - Use a ferry route
         Given the node map
             | a | b | c |   |   |
             |   |   | d |   |   |
@@ -17,17 +17,17 @@ Feature: Bicycle - Handle movable bridge
             | efg   | primary |         |         |
 
         When I route I should get
-            | from | to | route       | modes |
-            | a    | g  | abc,cde,efg | 1,5,1 |
-            | b    | f  | abc,cde,efg | 1,5,1 |
-            | e    | c  | cde         | 5     |
-            | e    | b  | cde,abc     | 5,1   |
-            | e    | a  | cde,abc     | 5,1   |
-            | c    | e  | cde         | 5     |
-            | c    | f  | cde,efg     | 5,1   |
-            | c    | g  | cde,efg     | 5,1   |
+            | from | to | route           | modes                                  |
+            | a    | g  | abc,cde,efg,efg | cycling,movable bridge,cycling,cycling |
+            | b    | f  | abc,cde,efg,efg | cycling,movable bridge,cycling,cycling |
+            | e    | c  | cde,cde         | movable bridge,movable bridge          |
+            | e    | b  | cde,abc,abc     | movable bridge,cycling,cycling         |
+            | e    | a  | cde,abc,abc     | movable bridge,cycling,cycling         |
+            | c    | e  | cde,cde         | movable bridge,movable bridge          |
+            | c    | f  | cde,efg,efg     | movable bridge,cycling,cycling         |
+            | c    | g  | cde,efg,efg     | movable bridge,cycling,cycling         |
 
-    Scenario: Car - Properly handle durations
+    Scenario: Bicycle - Properly handle durations
         Given the node map
             | a | b | c |   |   |
             |   |   | d |   |   |
@@ -40,8 +40,8 @@ Feature: Bicycle - Handle movable bridge
             | efg   | primary |         |          |
 
         When I route I should get
-            | from | to | route       | modes | speed   |
-            | a    | g  | abc,cde,efg | 1,5,1 | 5 km/h |
-            | b    | f  | abc,cde,efg | 1,5,1 | 4 km/h |
-            | c    | e  | cde         | 5     | 2 km/h |
-            | e    | c  | cde         | 5     | 2 km/h |
+            | from | to | route           | modes                                  | speed  |
+            | a    | g  | abc,cde,efg,efg | cycling,movable bridge,cycling,cycling | 5 km/h |
+            | b    | f  | abc,cde,efg,efg | cycling,movable bridge,cycling,cycling | 4 km/h |
+            | c    | e  | cde,cde         | movable bridge,movable bridge          | 2 km/h |
+            | e    | c  | cde,cde         | movable bridge,movable bridge          | 2 km/h |
diff --git a/features/bicycle/ferry.feature b/features/bicycle/ferry.feature
index 85c925f..aaec0ef 100644
--- a/features/bicycle/ferry.feature
+++ b/features/bicycle/ferry.feature
@@ -17,15 +17,15 @@ Feature: Bike - 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           |
+            | a    | g  | abc,cde,efg,efg |
+            | b    | f  | abc,cde,efg,efg |
+            | e    | c  | cde,cde         |
+            | e    | b  | cde,abc,abc     |
+            | e    | a  | cde,abc,abc     |
+            | c    | e  | cde,cde         |
+            | c    | f  | cde,efg,efg     |
+            | c    | g  | cde,efg,efg     |
 
     Scenario: Bike - Ferry duration, single node
         Given the node map
@@ -59,5 +59,5 @@ Feature: Bike - Handle ferry routes
 
         When I route I should get
             | from | to | route | time       |
-            | a    | d  | abcd  | 3600s +-10 |
-            | d    | a  | abcd  | 3600s +-10 |
+            | a    | d  | abcd,abcd  | 3600s +-10 |
+            | d    | a  | abcd,abcd  | 3600s +-10 |
diff --git a/features/bicycle/maxspeed.feature b/features/bicycle/maxspeed.feature
index ba5bfba..ad2c2bf 100644
--- a/features/bicycle/maxspeed.feature
+++ b/features/bicycle/maxspeed.feature
@@ -48,9 +48,9 @@ Feature: Bike - Max speed restrictions
             | bc    | residential | 80       |
 
         When I route I should get
-            | from | to | route | speed   |
-            | a    | b  | ab    | 15 km/h |
-            | b    | c  | bc    | 15 km/h |
+            | from | to | route    | speed   |
+            | a    | b  | ab,ab    | 15 km/h |
+            | b    | c  | bc,bc    | 15 km/h |
 
     Scenario: Bike - Forward/backward maxspeed
         Given the shortcuts
diff --git a/features/bicycle/mode.feature b/features/bicycle/mode.feature
index 2bfa4de..3587f6c 100644
--- a/features/bicycle/mode.feature
+++ b/features/bicycle/mode.feature
@@ -1,15 +1,9 @@
 @routing @bicycle @mode
 Feature: Bike - Mode flag
 
-# bicycle modes:
-# 1 bike
-# 2 pushing
-# 3 ferry
-# 4 train
-
 	Background:
 		Given the profile "bicycle"
-    
+
     Scenario: Bike - Mode when using a ferry
     	Given the node map
     	 | a | b |   |
@@ -22,13 +16,13 @@ Feature: Bike - Mode flag
     	 | cd    | primary |       |          |
 
     	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   |
+    	 | from | to | route       | turns                    | modes                         |
+    	 | a    | d  | ab,bc,cd,cd | depart,right,left,arrive | cycling,ferry,cycling,cycling |
+    	 | d    | a  | cd,bc,ab,ab | depart,right,left,arrive | cycling,ferry,cycling,cycling |
+    	 | c    | a  | bc,ab,ab    | depart,left,arrive       | ferry,cycling,cycling         |
+    	 | d    | b  | cd,bc,bc    | depart,right,arrive      | cycling,ferry,ferry           |
+    	 | a    | c  | ab,bc,bc    | depart,right,arrive      | cycling,ferry,ferry           |
+    	 | b    | d  | bc,cd,cd    | depart,left,arrive       | ferry,cycling,cycling         |
 
      Scenario: Bike - Mode when using a train
      	Given the node map
@@ -42,13 +36,13 @@ Feature: Bike - Mode flag
      	 | 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   |
+     	 | from | to | route       | turns                    | modes                         |
+     	 | a    | d  | ab,bc,cd,cd | depart,right,left,arrive | cycling,train,cycling,cycling |
+     	 | d    | a  | cd,bc,ab,ab | depart,right,left,arrive | cycling,train,cycling,cycling |
+     	 | c    | a  | bc,ab,ab    | depart,left,arrive       | train,cycling,cycling         |
+     	 | d    | b  | cd,bc,bc    | depart,right,arrive      | cycling,train,train           |
+     	 | a    | c  | ab,bc,bc    | depart,right,arrive      | cycling,train,train           |
+     	 | b    | d  | bc,cd,cd    | depart,left,arrive       | train,cycling,cycling         |
 
      Scenario: Bike - Mode when pushing bike against oneways
      	Given the node map
@@ -62,13 +56,13 @@ Feature: Bike - Mode flag
      	 | 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   |
+     	 | from | to | route       | turns                                   | modes                                |
+     	 | a    | d  | ab,bc,cd,cd | depart,right,left,arrive                | cycling,cycling,cycling,cycling      |
+     	 | d    | a  | cd,bc,ab,ab | depart,right,left,arrive                | cycling,pushing bike,cycling,cycling |
+     	 | c    | a  | bc,ab,ab    | depart,left,arrive                      | pushing bike,cycling,cycling         |
+     	 | d    | b  | cd,bc,bc    | depart,right,arrive                     | cycling,pushing bike,pushing bike    |
+     	 | a    | c  | ab,bc,bc    | depart,right,arrive                     | cycling,cycling,cycling              |
+     	 | b    | d  | bc,cd,cd    | depart,left,arrive                      | cycling,cycling,cycling              |
 
      Scenario: Bike - Mode when pushing on pedestrain streets
      	Given the node map
@@ -82,13 +76,13 @@ Feature: Bike - Mode flag
      	 | 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   |
+     	 | from | to | route       | turns                    | modes                                |
+     	 | a    | d  | ab,bc,cd,cd | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
+     	 | d    | a  | cd,bc,ab,ab | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
+     	 | c    | a  | bc,ab,ab    | depart,left,arrive       | pushing bike,cycling,cycling         |
+     	 | d    | b  | cd,bc,bc    | depart,right,arrive      | cycling,pushing bike,pushing bike    |
+     	 | a    | c  | ab,bc,bc    | depart,right,arrive      | cycling,pushing bike,pushing bike    |
+     	 | b    | d  | bc,cd,cd    | depart,left,arrive       | pushing bike,cycling,cycling         |
 
      Scenario: Bike - Mode when pushing on pedestrain areas
      	Given the node map
@@ -102,13 +96,13 @@ Feature: Bike - Mode flag
      	 | 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   |
+     	 | from | to | route        | modes                                |
+     	 | a    | f  | ab,bcd,df,df | cycling,pushing bike,cycling,cycling |
+     	 | f    | a  | df,bcd,ab,ab | cycling,pushing bike,cycling,cycling |
+     	 | d    | a  | bcd,ab,ab    | pushing bike,cycling,cycling         |
+     	 | f    | b  | df,bcd,bcd   | cycling,pushing bike,pushing bike    |
+     	 | a    | d  | ab,bcd,bcd   | cycling,pushing bike,pushing bike    |
+     	 | b    | f  | bcd,df,df    | pushing bike,cycling,cycling         |
 
      Scenario: Bike - Mode when pushing on steps
      	Given the node map
@@ -122,13 +116,13 @@ Feature: Bike - Mode flag
     	 | 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   |
+    	 | from | to | route       | turns                    | modes                                |
+    	 | a    | d  | ab,bc,cd,cd | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
+    	 | d    | a  | cd,bc,ab,ab | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
+    	 | c    | a  | bc,ab,ab    | depart,left,arrive       | pushing bike,cycling,cycling         |
+    	 | d    | b  | cd,bc,bc    | depart,right,arrive      | cycling,pushing bike,pushing bike    |
+    	 | a    | c  | ab,bc,bc    | depart,right,arrive      | cycling,pushing bike,pushing bike    |
+    	 | b    | d  | bc,cd,cd    | depart,left,arrive       | pushing bike,cycling,cycling         |
 
      Scenario: Bike - Mode when bicycle=dismount
      	Given the node map
@@ -142,13 +136,13 @@ Feature: Bike - Mode flag
     	 | 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   |
+    	 | from | to | route       | turns                    | modes                                |
+    	 | a    | d  | ab,bc,cd,cd | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
+    	 | d    | a  | cd,bc,ab,ab | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
+    	 | c    | a  | bc,ab,ab    | depart,left,arrive       | pushing bike,cycling,cycling         |
+    	 | d    | b  | cd,bc,bc    | depart,right,arrive      | cycling,pushing bike,pushing bike    |
+    	 | a    | c  | ab,bc,bc    | depart,right,arrive      | cycling,pushing bike,pushing bike    |
+         | b    | d  | bc,cd,cd    | depart,left,arrive       | pushing bike,cycling,cycling         |
 
     Scenario: Bicycle - Modes when starting on forward oneway
         Given the node map
@@ -159,9 +153,9 @@ Feature: Bike - Mode flag
          | ab    | yes    |
 
         When I route I should get
-         | from | to | route | modes |
-         | a    | b  | ab    | 1     |
-         | b    | a  | ab    | 2     |
+         | from | to | route | modes                     |
+         | a    | b  | ab,ab | cycling,cycling           |
+         | b    | a  | ab,ab | pushing bike,pushing bike |
 
     Scenario: Bicycle - Modes when starting on reverse oneway
         Given the node map
@@ -172,6 +166,6 @@ Feature: Bike - Mode flag
          | ab    | -1     |
 
         When I route I should get
-         | from | to | route | modes |
-         | a    | b  | ab    | 2     |
-         | b    | a  | ab    | 1     |
+         | from | to | route | modes                     |
+         | a    | b  | ab,ab | pushing bike,pushing bike |
+         | b    | a  | ab,ab | cycling,cycling           |
diff --git a/features/bicycle/names.feature b/features/bicycle/names.feature
index b0e2ec0..f67f6b1 100644
--- a/features/bicycle/names.feature
+++ b/features/bicycle/names.feature
@@ -15,8 +15,8 @@ Feature: Bike - Street names in instructions
             | bc    | Your Way |
 
         When I route I should get
-            | from | to | route           |
-            | a    | c  | My Way,Your Way |
+            | from | to | route                    |
+            | a    | c  | My Way,Your Way,Your Way |
 
     @unnamed
     Scenario: Bike - Use way type to describe unnamed ways
@@ -29,5 +29,5 @@ Feature: Bike - Street names in instructions
             | bcd   | track    |      |
 
         When I route I should get
-            | from | to | route                              |
-            | a    | d  | {highway:cycleway},{highway:track} |
+            | from | to | route                                              |
+            | a    | d  | {highway:cycleway},{highway:track},{highway:track} |
diff --git a/features/bicycle/oneway.feature b/features/bicycle/oneway.feature
index 4dd9e1f..0cb774c 100644
--- a/features/bicycle/oneway.feature
+++ b/features/bicycle/oneway.feature
@@ -29,9 +29,9 @@ Feature: Bike - Oneway streets
             | da    |        | no   |
 
         When I route I should get
-            | from | to | route    |
-            | a    | b  | ab       |
-            | b    | a  | bc,cd,da |
+            | from | to | route       |
+            | a    | b  | ab,ab       |
+            | b    | a  | bc,cd,da,da |
 
     Scenario: Bike - Handle various oneway tag values
         Then routability should be
@@ -124,5 +124,5 @@ Feature: Bike - Oneway streets
 
 
         When I route I should get
-            | from | to | route |
-            | a    | c  | ab,bc |
+            | from | to | route    |
+            | a    | c  | ab,bc,bc |
diff --git a/features/bicycle/pushing.feature b/features/bicycle/pushing.feature
index 5741fb1..3d00b53 100644
--- a/features/bicycle/pushing.feature
+++ b/features/bicycle/pushing.feature
@@ -32,7 +32,7 @@ Feature: Bike - Accessability of different way types
             | primary    | -1     | foot | bike  |
             | pedestrian | -1     | foot | foot  |
 
-    @square    
+    @square
     Scenario: Bike - Push bikes on pedestrian areas
         Given the node map
             | x |   |
@@ -46,14 +46,14 @@ Feature: Bike - Accessability of different way types
 
         When I route I should get
             | from | to | route |
-            | a    | b  | abcda |
-            | a    | d  | abcda |
-            | b    | c  | abcda |
-            | c    | b  | abcda |
-            | c    | d  | abcda |
-            | d    | c  | abcda |
-            | d    | a  | abcda |
-            | a    | d  | abcda |
+            | a    | b  | abcda,abcda |
+            | a    | d  | abcda,abcda |
+            | b    | c  | abcda,abcda |
+            | c    | b  | abcda,abcda |
+            | c    | d  | abcda,abcda |
+            | d    | c  | abcda,abcda |
+            | d    | a  | abcda,abcda |
+            | a    | d  | abcda,abcda |
 
     Scenario: Bike - Pushing bikes on ways with foot=yes
         Then routability should be
@@ -62,7 +62,7 @@ Feature: Bike - Accessability of different way types
             | motorway | yes  | foot |       |
             | runway   |      |      |       |
             | runway   | yes  | foot | foot  |
-    
+
     @todo
     Scenario: Bike - Pushing bikes on ways with foot=yes in one direction
         Then routability should be
@@ -72,20 +72,20 @@ Feature: Bike - Accessability of different way types
             | motorway |              | yes           |      | foot  |
 
     @construction
-    Scenario: Bike - Don't allow routing on ways still under construction 
+    Scenario: Bike - Don't allow routing on ways still under construction
         Then routability should be
             | highway      | foot | bicycle | bothw |
             | primary      |      |         | x     |
             | construction |      |         |       |
             | construction | yes  |         |       |
             | construction |      | yes     |       |
-        
+
     @roundabout
     Scenario: Bike - Don't push bikes against oneway flow on roundabouts
         Then routability should be
             | junction   | forw | backw |
             | roundabout | x    |       |
- 
+
     Scenario: Bike - Instructions when pushing bike on oneways
         Given the node map
             | a | b |   |
@@ -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,right,left,destination |
-            | c    | a  | bc,ab    | head,left,destination       |
-            | d    | b  | cd,bc    | head,right,destination      |
+            | from | to | route       | turns                                   |
+            | a    | d  | ab,bc,cd,cd | depart,right,left,arrive                |
+            | d    | a  | cd,bc,ab,ab | depart,right,left,arrive                |
+            | c    | a  | bc,ab,ab    | depart,left,arrive                      |
+            | d    | b  | cd,bc,bc    | depart,right,arrive                     |
 
     @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,right,left,destination |
-            | c    | a  | bc,ab    | head,left,destination       |
-            | d    | b  | cd,bc    | head,right,destination      |
+            | from | to | route       | turns                    |
+            | a    | d  | ab,bc,cd,cd | depart,right,left,arrive |
+            | d    | a  | cd,bc,ab,ab | depart,right,left,arrive |
+            | c    | a  | bc,ab,ab    | depart,left,arrive       |
+            | d    | b  | cd,bc,bc    | depart,right,arrive      |
diff --git a/features/bicycle/ref.feature b/features/bicycle/ref.feature
index 3afde77..195089e 100644
--- a/features/bicycle/ref.feature
+++ b/features/bicycle/ref.feature
@@ -13,8 +13,8 @@ Feature: Bike - Way ref
             | ab    | Utopia Drive | E7  |
 
         When I route I should get
-            | from | to | route             |
-            | a    | b  | Utopia Drive / E7 |
+            | from | to | route                               |
+            | a    | b  | Utopia Drive / E7,Utopia Drive / E7 |
 
     Scenario: Bike - Way with only ref
         Given the node map
@@ -26,7 +26,7 @@ Feature: Bike - Way ref
 
         When I route I should get
             | from | to | route |
-            | a    | b  | E7    |
+            | a    | b  | E7,E7 |
 
     Scenario: Bike - Way with only name
         Given the node map
@@ -37,5 +37,5 @@ Feature: Bike - Way ref
             | ab    | Utopia Drive |
 
         When I route I should get
-            | from | to | route        |
-            | a    | b  | Utopia Drive |
+            | from | to | route                     |
+            | a    | b  | Utopia Drive,Utopia Drive |
diff --git a/features/bicycle/restrictions.feature b/features/bicycle/restrictions.feature
index 6218d81..1f60471 100644
--- a/features/bicycle/restrictions.feature
+++ b/features/bicycle/restrictions.feature
@@ -25,10 +25,10 @@ Feature: Bike - Turn restrictions
             | restriction | sj       | wj     | j        | no_left_turn |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @no_turning
     Scenario: Bike - No right turn
@@ -49,10 +49,10 @@ Feature: Bike - Turn restrictions
             | restriction | sj       | ej     | j        | no_right_turn |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @no_turning
     Scenario: Bike - No u-turn
@@ -73,10 +73,10 @@ Feature: Bike - Turn restrictions
             | restriction | sj       | wj     | j        | no_u_turn   |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @no_turning
     Scenario: Bike - Handle any no_* relation
@@ -97,10 +97,10 @@ Feature: Bike - Turn restrictions
             | restriction | sj       | wj     | j        | no_weird_zigzags |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @only_turning
     Scenario: Bike - Only left turn
@@ -121,10 +121,10 @@ Feature: Bike - Turn restrictions
             | restriction | sj       | wj     | j        | only_left_turn |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @only_turning
     Scenario: Bike - Only right turn
@@ -145,10 +145,10 @@ Feature: Bike - Turn restrictions
             | restriction | sj       | ej     | j        | only_right_turn |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @only_turning
     Scenario: Bike - Only straight on
@@ -169,10 +169,10 @@ Feature: Bike - Turn restrictions
             | restriction | sj       | nj     | j        | only_straight_on |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @no_turning
     Scenario: Bike - Handle any only_* restriction
@@ -193,10 +193,10 @@ Feature: Bike - Turn restrictions
             | restriction | sj       | nj     | j        | only_weird_zigzags |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @except
     Scenario: Bike - Except tag and on no_ restrictions
@@ -222,11 +222,11 @@ Feature: Bike - Turn restrictions
             | restriction | sj       | dj     | j        | no_right_turn | bicycle |
 
         When I route I should get
-            | from | to | route |
-            | s    | a  | sj,aj |
-            | s    | b  | sj,bj |
-            | s    | c  | sj,cj |
-            | s    | d  | sj,dj |
+            | from | to | route    |
+            | s    | a  | sj,aj,aj |
+            | s    | b  | sj,bj,bj |
+            | s    | c  | sj,cj,cj |
+            | s    | d  | sj,dj,dj |
 
     @except
     Scenario: Bike - Except tag and on only_ restrictions
@@ -246,9 +246,9 @@ Feature: Bike - Turn restrictions
             | restriction | sj       | aj     | j        | only_straight_on | bicycle |
 
         When I route I should get
-            | from | to | route |
-            | s    | a  | sj,aj |
-            | s    | b  | sj,bj |
+            | from | to | route    |
+            | s    | a  | sj,aj,aj |
+            | s    | b  | sj,bj,bj |
 
     @except
     Scenario: Bike - Multiple except tag values
@@ -280,10 +280,10 @@ Feature: Bike - Turn restrictions
             | restriction | sj       | jf     | j        | no_straight_on | bicycle, bus     |
 
         When I route I should get
-            | from | to | route |
-            | s    | a  | sj,ja |
-            | s    | b  | sj,jb |
-            | s    | c  | sj,jc |
-            | s    | d  | sj,jd |
-            | s    | e  | sj,je |
-            | s    | f  | sj,jf |
+            | from | to | route    |
+            | s    | a  | sj,ja,ja |
+            | s    | b  | sj,jb,jb |
+            | s    | c  | sj,jc,jc |
+            | s    | d  | sj,jd,jd |
+            | s    | e  | sj,je,je |
+            | s    | f  | sj,jf,jf |
diff --git a/features/bicycle/roundabout.feature b/features/bicycle/roundabout.feature
index 6123280..2e0d099 100644
--- a/features/bicycle/roundabout.feature
+++ b/features/bicycle/roundabout.feature
@@ -21,10 +21,10 @@ Feature: Roundabout Instructions
             | abcda | roundabout |
 
         When I route I should get
-            | from | to | route | turns                               |
-            | s    | t  | sa,tb | head,enter_roundabout-1,destination |
-            | s    | u  | sa,uc | head,enter_roundabout-2,destination |
-            | s    | v  | sa,vd | head,enter_roundabout-3,destination |
-            | u    | v  | uc,vd | head,enter_roundabout-1,destination |
-            | u    | s  | uc,sa | head,enter_roundabout-2,destination |
-            | u    | t  | uc,tb | head,enter_roundabout-3,destination |
+            | from | to | route    | turns                           |
+            | s    | t  | sa,tb,tb | depart,roundabout-exit-1,arrive |
+            | s    | u  | sa,uc,uc | depart,roundabout-exit-2,arrive |
+            | s    | v  | sa,vd,vd | depart,roundabout-exit-3,arrive |
+            | u    | v  | uc,vd,vd | depart,roundabout-exit-1,arrive |
+            | u    | s  | uc,sa,sa | depart,roundabout-exit-2,arrive |
+            | u    | t  | uc,tb,tb | depart,roundabout-exit-3,arrive |
diff --git a/features/bicycle/stop_area.feature b/features/bicycle/stop_area.feature
index 5f6c3bc..9d02c13 100644
--- a/features/bicycle/stop_area.feature
+++ b/features/bicycle/stop_area.feature
@@ -31,7 +31,7 @@ Feature: Bike - Stop areas for public transport
             | public_transport | stop_area        | c         | st           |
 
         When I route I should get
-            | from | to | route        |
-            | a    | d  | abcd         |
-            | s    | t  | st           |
-            | s    | d  | /st,.+,abcd/ |
+            | from | to | route              |
+            | a    | d  | abcd,abcd          |
+            | s    | t  | st,st              |
+            | s    | d  | /st,.+,abcd/,abcd/ |
diff --git a/features/bicycle/turn_penalty.feature b/features/bicycle/turn_penalty.feature
index d8c46b8..4d66cc3 100644
--- a/features/bicycle/turn_penalty.feature
+++ b/features/bicycle/turn_penalty.feature
@@ -23,11 +23,11 @@ Feature: Turn Penalties
             | jg    |
 
         When I route I should get
-            | from | to | route | time    | distance |
-            | s    | a  | sj,ja | 39s +-1 | 242m +-1 |
-            | s    | b  | sj,jb | 30s +-1 | 200m +-1 |
-            | s    | c  | sj,jc | 29s +-1 | 242m +-1 |
-            | s    | d  | sj,jd | 20s +-1 | 200m +-1 |
-            | s    | e  | sj,je | 29s +-1 | 242m +-1 |
-            | s    | f  | sj,jf | 30s +-1 | 200m +-1 |
-            | s    | g  | sj,jg | 39s +-1 | 242m +-1 |
\ No newline at end of file
+            | from | to | route    | time    | distance |
+            | s    | a  | sj,ja,ja | 39s +-1 | 242m +-1 |
+            | s    | b  | sj,jb,jb | 30s +-1 | 200m +-1 |
+            | s    | c  | sj,jc,jc | 29s +-1 | 242m +-1 |
+            | s    | d  | sj,jd,jd | 20s +-1 | 200m +-1 |
+            | s    | e  | sj,je,je | 29s +-1 | 242m +-1 |
+            | s    | f  | sj,jf,jf | 30s +-1 | 200m +-1 |
+            | s    | g  | sj,jg,jg | 39s +-1 | 242m +-1 |
diff --git a/features/car/advisory.feature b/features/car/advisory.feature
index db5e66d..b84ff05 100644
--- a/features/car/advisory.feature
+++ b/features/car/advisory.feature
@@ -17,8 +17,8 @@ OSRM will use 4/5 of the projected free-flow speed.
 
         When I route I should get
             | from | to | route | speed        |
-            | a    | b  | ab    | 47 km/h +- 1 |
-            | b    | c  | bc    | 47 km/h +- 1 |
+            | a    | b  | ab,ab | 47 km/h +- 1 |
+            | b    | c  | bc,bc | 47 km/h +- 1 |
 
     Scenario: Car - Advisory speed overwrites forward maxspeed
         Given the node map
@@ -31,9 +31,10 @@ OSRM will use 4/5 of the projected free-flow speed.
 
         When I route I should get
             | from | to | route | speed        |
-            | a    | b  | ab    | 47 km/h +- 1 |
-            | b    | c  | bc    | 47 km/h +- 1 |
+            | a    | b  | ab,ab | 47 km/h +- 1 |
+            | b    | c  | bc,bc | 47 km/h +- 1 |
 
+    @mokob @2162
     Scenario: Car - Advisory speed overwrites backwards maxspeed
         Given the node map
             | a | b | c |
@@ -45,9 +46,26 @@ OSRM will use 4/5 of the projected free-flow speed.
 
         When I route I should get
             | from | to | route | speed        |
-            | b    | a  | ab    | 47 km/h +- 1 |
-            | c    | b  | bc    | 47 km/h +- 1 |
+            | b    | a  | ab,ab | 47 km/h +- 1 |
+            | c    | b  | bc,bc | 47 km/h +- 1 |
 
+    @mokob @2162 @deleteme
+    Scenario: Car - Advisory speed overwrites backwards maxspeed
+        Given the node map
+            | a | b | c | d |
+
+        And the ways
+            | nodes | highway       | maxspeed:backward | maxspeed:advisory:backward |
+            | ab    | residential   |                   | 45                         |
+            | bc    | residential   | 90                | 45                         |
+            | cd    | residential   |                   | 45                         |
+
+        When I route I should get
+            | from | to | route | speed        |
+            | c    | b  | bc,bc | 47 km/h +- 1 |
+            | d    | c  | cd,cd | 47 km/h +- 1 |
+
+    @mokob @2162
     Scenario: Car - Directional advisory speeds play nice with eachother
         Given the node map
             | a | b | c |
@@ -59,9 +77,9 @@ OSRM will use 4/5 of the projected free-flow speed.
 
         When I route I should get
             | from | to | route | speed        |
-            | a    | b  | ab    | 47 km/h +- 1 |
-            | b    | a  | ab    | 59 km/h +- 1 |
-            | b    | c  | bc    | 59 km/h +- 1 |
-            | c    | b  | bc    | 47 km/h +- 1 |
+            | a    | b  | ab,ab | 47 km/h +- 1 |
+            | b    | a  | ab,ab | 59 km/h +- 1 |
+            | b    | c  | bc,bc | 59 km/h +- 1 |
+            | c    | b  | bc,bc | 47 km/h +- 1 |
 
 
diff --git a/features/car/bridge.feature b/features/car/bridge.feature
index d3e470e..931f1d9 100644
--- a/features/car/bridge.feature
+++ b/features/car/bridge.feature
@@ -17,15 +17,15 @@ Feature: Car - Handle movable bridge
             | efg   | primary |         |         |
 
         When I route I should get
-            | from | to | route       | modes |
-            | a    | g  | abc,cde,efg | 1,3,1 |
-            | b    | f  | abc,cde,efg | 1,3,1 |
-            | e    | c  | cde         | 3     |
-            | e    | b  | cde,abc     | 3,1   |
-            | e    | a  | cde,abc     | 3,1   |
-            | c    | e  | cde         | 3     |
-            | c    | f  | cde,efg     | 3,1   |
-            | c    | g  | cde,efg     | 3,1   |
+            | from | to | route           | modes                                  |
+            | a    | g  | abc,cde,efg,efg | driving,movable bridge,driving,driving |
+            | b    | f  | abc,cde,efg,efg | driving,movable bridge,driving,driving |
+            | e    | c  | cde,cde         | movable bridge,movable bridge          |
+            | e    | b  | cde,abc,abc     | movable bridge,driving,driving         |
+            | e    | a  | cde,abc,abc     | movable bridge,driving,driving         |
+            | c    | e  | cde,cde         | movable bridge,movable bridge          |
+            | c    | f  | cde,efg,efg     | movable bridge,driving,driving         |
+            | c    | g  | cde,efg,efg     | movable bridge,driving,driving         |
 
     Scenario: Car - Properly handle durations
         Given the node map
@@ -40,8 +40,8 @@ Feature: Car - Handle movable bridge
             | efg   | primary |         |          |
 
         When I route I should get
-            | from | to | route       | modes | speed   |
-            | a    | g  | abc,cde,efg | 1,3,1 | 7 km/h |
-            | b    | f  | abc,cde,efg | 1,3,1 | 5 km/h |
-            | c    | e  | cde         | 3     | 2 km/h |
-            | e    | c  | cde         | 3     | 2 km/h |
+            | from | to | route           | modes                                  | speed  |
+            | a    | g  | abc,cde,efg,efg | driving,movable bridge,driving,driving | 7 km/h |
+            | b    | f  | abc,cde,efg,efg | driving,movable bridge,driving,driving | 5 km/h |
+            | c    | e  | cde,cde         | movable bridge,movable bridge          | 2 km/h |
+            | e    | c  | cde,cde         | movable bridge,movable bridge          | 2 km/h |
diff --git a/features/car/ferry.feature b/features/car/ferry.feature
index 37f520e..c6adc9f 100644
--- a/features/car/ferry.feature
+++ b/features/car/ferry.feature
@@ -17,15 +17,15 @@ Feature: Car - Handle ferry routes
             | efg   | primary |       |         |
 
         When I route I should get
-            | 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   |
+            | from | to | route           | modes                         |
+            | a    | g  | abc,cde,efg,efg | driving,ferry,driving,driving |
+            | b    | f  | abc,cde,efg,efg | driving,ferry,driving,driving |
+            | e    | c  | cde,cde         | ferry,ferry                   |
+            | e    | b  | cde,abc,abc     | ferry,driving,driving         |
+            | e    | a  | cde,abc,abc     | ferry,driving,driving         |
+            | c    | e  | cde,cde         | ferry,ferry                   |
+            | c    | f  | cde,efg,efg     | ferry,driving,driving         |
+            | c    | g  | cde,efg,efg     | ferry,driving,driving         |
 
     Scenario: Car - Properly handle simple durations
         Given the node map
@@ -40,11 +40,11 @@ Feature: Car - Handle ferry routes
             | efg   | primary |       |          |
 
         When I route I should get
-            | from | to | route       | modes | speed   |
-            | a    | g  | abc,cde,efg | 1,2,1 | 25 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 |
+            | from | to | route           | modes                         | speed   |
+            | a    | g  | abc,cde,efg,efg | driving,ferry,driving,driving | 25 km/h |
+            | b    | f  | abc,cde,efg,efg | driving,ferry,driving,driving | 20 km/h |
+            | c    | e  | cde,cde         | ferry,ferry                   | 12 km/h |
+            | e    | c  | cde,cde         | ferry,ferry                   | 12 km/h |
 
     Scenario: Car - Properly handle ISO 8601 durations
         Given the node map
@@ -59,8 +59,8 @@ Feature: Car - Handle ferry routes
             | efg   | primary |       |          |
 
         When I route I should get
-            | from | to | route       | modes | speed   |
-            | a    | g  | abc,cde,efg | 1,2,1 | 25 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 |
+            | from | to | route           | modes                         | speed   |
+            | a    | g  | abc,cde,efg,efg | driving,ferry,driving,driving | 25 km/h |
+            | b    | f  | abc,cde,efg,efg | driving,ferry,driving,driving | 20 km/h |
+            | c    | e  | cde,cde         | ferry,ferry                   | 12 km/h |
+            | e    | c  | cde,cde         | ferry,ferry                   | 12 km/h |
diff --git a/features/car/link.feature b/features/car/link.feature
index f4628e4..26f32d1 100644
--- a/features/car/link.feature
+++ b/features/car/link.feature
@@ -24,9 +24,9 @@ Feature: Car - Speed on links
             | dy    | unclassified  |
 
         When I route I should get
-            | from | to | route          |
-            | x    | y  | xa,ae,ef,fd,dy |
-            | b    | c  | bc             |
+            | from | to | route             |
+            | x    | y  | xa,ae,ef,fd,dy,dy |
+            | b    | c  | bc,bc             |
 
     Scenario: Car - Use trunk_link when reasonable
         Given the node map
@@ -44,9 +44,9 @@ Feature: Car - Speed on links
             | fd    | trunk        |
             | dy    | unclassified |
         When I route I should get
-            | from | to | route          |
-            | x    | y  | xa,ae,ef,fd,dy |
-            | b    | c  | bc             |
+            | from | to | route             |
+            | x    | y  | xa,ae,ef,fd,dy,dy |
+            | b    | c  | bc,bc             |
 
     Scenario: Car - Use primary_link when reasonable
         Given the node map
@@ -64,9 +64,9 @@ Feature: Car - Speed on links
             | fd    | primary        |
             | dy    | unclassified |
         When I route I should get
-            | from | to | route          |
-            | x    | y  | xa,ae,ef,fd,dy |
-            | b    | c  | bc             |
+            | from | to | route             |
+            | x    | y  | xa,ae,ef,fd,dy,dy |
+            | b    | c  | bc,bc             |
 
     Scenario: Car - Use secondary_link when reasonable
         Given the node map
@@ -85,9 +85,9 @@ Feature: Car - Speed on links
             | dy    | unclassified     |
 
         When I route I should get
-            | from | to | route          |
-            | x    | y  | xa,ae,ef,fd,dy |
-            | b    | c  | bc             |
+            | from | to | route             |
+            | x    | y  | xa,ae,ef,fd,dy,dy |
+            | b    | c  | bc,bc             |
 
     Scenario: Car - Use tertiary_link when reasonable
         Given the node map
@@ -106,6 +106,6 @@ Feature: Car - Speed on links
             | dy    | unclassified    |
 
         When I route I should get
-            | from | to | route          |
-            | x    | y  | xa,ae,ef,fd,dy |
-            | b    | c  | bc             |
+            | from | to | route             |
+            | x    | y  | xa,ae,ef,fd,dy,dy |
+            | b    | c  | bc,bc             |
diff --git a/features/car/maxspeed.feature b/features/car/maxspeed.feature
index e2d26e0..3b94ac7 100644
--- a/features/car/maxspeed.feature
+++ b/features/car/maxspeed.feature
@@ -21,12 +21,12 @@ OSRM will use 4/5 of the projected free-flow speed.
 
         When I route I should get
             | from | to | route | speed         |
-            | a    | b  | ab    |  78 km/h      |
-            | b    | c  | bc    |  59 km/h +- 1 |
-            | c    | d  | cd    |  51 km/h      |
-            | d    | e  | de    |  75 km/h      |
-            | e    | f  | ef    |  90 km/h      |
-            | f    | g  | fg    | 106 km/h      |
+            | a    | b  | ab,ab |  79 km/h      |
+            | b    | c  | bc,bc |  59 km/h +- 1 |
+            | c    | d  | cd,cd |  51 km/h      |
+            | d    | e  | de,de |  75 km/h      |
+            | e    | f  | ef,ef |  91 km/h      |
+            | f    | g  | fg,fg | 107 km/h      |
 
     Scenario: Car - Do not ignore maxspeed when higher than way speed
         Given the node map
@@ -40,9 +40,9 @@ OSRM will use 4/5 of the projected free-flow speed.
 
         When I route I should get
             | from | to | route | speed        |
-            | a    | b  | ab    | 31 km/h      |
-            | b    | c  | bc    | 83 km/h +- 1 |
-            | c    | d  | cd    | 51 km/h      |
+            | a    | b  | ab,ab | 31 km/h      |
+            | b    | c  | bc,bc | 83 km/h +- 1 |
+            | c    | d  | cd,cd | 51 km/h      |
 
     Scenario: Car - Forward/backward maxspeed
         Given a grid size of 100 meters
diff --git a/features/car/mode.feature b/features/car/mode.feature
index ff156a0..f390982 100644
--- a/features/car/mode.feature
+++ b/features/car/mode.feature
@@ -15,13 +15,13 @@ Feature: Car - Mode flag
             | 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   |
+            | from | to | route       | turns                    | modes                         |
+            | a    | d  | ab,bc,cd,cd | depart,right,left,arrive | driving,ferry,driving,driving |
+            | d    | a  | cd,bc,ab,ab | depart,right,left,arrive | driving,ferry,driving,driving |
+            | c    | a  | bc,ab,ab    | depart,left,arrive       | ferry,driving,driving         |
+            | d    | b  | cd,bc,bc    | depart,right,arrive      | driving,ferry,ferry           |
+            | a    | c  | ab,bc,bc    | depart,right,arrive      | driving,ferry,ferry           |
+            | b    | d  | bc,cd,cd    | depart,left,arrive       | ferry,driving,driving         |
 
     Scenario: Car - Snapping when using a ferry
         Given the node map
@@ -34,7 +34,7 @@ Feature: Car - Mode flag
             | ef    | primary |       |          |
 
         When I route I should get
-            | from | to | route | turns            | modes   | time  |
-            | c    | d  | bcde  | head,destination | 2       | 600s  |
+            | from | to | route     | turns         | modes       | time  |
+            | c    | d  | bcde,bcde | depart,arrive | ferry,ferry | 600s  |
 
 
diff --git a/features/car/names.feature b/features/car/names.feature
index b6a95ae..7a47253 100644
--- a/features/car/names.feature
+++ b/features/car/names.feature
@@ -15,8 +15,8 @@ Feature: Car - Street names in instructions
             | bc    | Your Way | A1  |
 
         When I route I should get
-            | from | to | route                |
-            | a    | c  | My Way,Your Way (A1) |
+            | from | to | route                              |
+            | a    | c  | My Way,Your Way (A1),Your Way (A1) |
 
     @todo
     Scenario: Car - Use way type to describe unnamed ways
@@ -29,5 +29,5 @@ Feature: Car - Street names in instructions
             | bcd   | residential |      |
 
         When I route I should get
-            | from | to | route                |
-            | a    | c  | tertiary,residential |
+            | from | to | route                            |
+            | a    | c  | tertiary,residential,residential |
diff --git a/features/car/oneway.feature b/features/car/oneway.feature
index b47c3c6..b1b08bf 100644
--- a/features/car/oneway.feature
+++ b/features/car/oneway.feature
@@ -44,9 +44,9 @@ Feature: Car - Oneway streets
             | da    |        |
 
         When I route I should get
-            | from | to | route    |
-            | a    | b  | ab       |
-            | b    | a  | bc,cd,da |
+            | from | to | route       |
+            | a    | b  | ab,ab       |
+            | b    | a  | bc,cd,da,da |
 
     Scenario: Car - Cars should not be affected by bicycle tags
         Then routability should be
@@ -75,5 +75,5 @@ Feature: Car - Oneway streets
 
 
         When I route I should get
-            | from | to | route |
-            | a    | c  | ab,bc |
+            | from | to | route    |
+            | a    | c  | ab,bc,bc |
diff --git a/features/car/restrictions.feature b/features/car/restrictions.feature
index 89fffff..d311fb0 100644
--- a/features/car/restrictions.feature
+++ b/features/car/restrictions.feature
@@ -25,10 +25,10 @@ Feature: Car - Turn restrictions
             | restriction | sj       | wj     | j        | no_left_turn |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  |       |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  |          |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @no_turning
     Scenario: Car - No straight on
@@ -55,8 +55,8 @@ Feature: Car - Turn restrictions
             | restriction | bj       | jd     | j        | no_straight_on |
 
         When I route I should get
-            | from | to | route             |
-            | a    | e  | av,vw,wx,xy,yz,ze |
+            | from | to | route                |
+            | a    | e  | av,vw,wx,xy,yz,ze,ze |
 
     @no_turning
     Scenario: Car - No right turn
@@ -77,10 +77,10 @@ Feature: Car - Turn restrictions
             | restriction | sj       | ej     | j        | no_right_turn |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  |       |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  |          |
 
     @no_turning
     Scenario: Car - No u-turn
@@ -101,10 +101,10 @@ Feature: Car - Turn restrictions
             | restriction | sj       | wj     | j        | no_u_turn   |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  |       |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  |          |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @no_turning
     Scenario: Car - Handle any no_* relation
@@ -125,10 +125,10 @@ Feature: Car - Turn restrictions
             | restriction | sj       | wj     | j        | no_weird_zigzags |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  |       |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  |          |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @only_turning
     Scenario: Car - Only left turn
@@ -149,10 +149,10 @@ Feature: Car - Turn restrictions
             | restriction | sj       | wj     | j        | only_left_turn |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  |       |
-            | s    | e  |       |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  |          |
+            | s    | e  |          |
 
     @only_turning
     Scenario: Car - Only right turn
@@ -173,10 +173,10 @@ Feature: Car - Turn restrictions
             | restriction | sj       | ej     | j        | only_right_turn |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  |       |
-            | s    | n  |       |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  |          |
+            | s    | n  |          |
+            | s    | e  | sj,ej,ej |
 
     @only_turning
     Scenario: Car - Only straight on
@@ -197,10 +197,10 @@ Feature: Car - Turn restrictions
             | restriction | sj       | nj     | j        | only_straight_on |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  |       |
-            | s    | n  | sj,nj |
-            | s    | e  |       |
+            | from | to | route    |
+            | s    | w  |          |
+            | s    | n  | sj,nj,nj |
+            | s    | e  |          |
 
     @no_turning
     Scenario: Car - Handle any only_* restriction
@@ -221,10 +221,10 @@ Feature: Car - Turn restrictions
             | restriction | sj       | nj     | j        | only_weird_zigzags |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  |       |
-            | s    | n  | sj,nj |
-            | s    | e  |       |
+            | from | to | route    |
+            | s    | w  |          |
+            | s    | n  | sj,nj,nj |
+            | s    | e  |          |
 
     @specific
     Scenario: Car - :hgv-qualified on a standard turn restriction
@@ -245,10 +245,10 @@ Feature: Car - Turn restrictions
             | restriction | sj       | nj     | j        | no_straight_on  |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @specific
     Scenario: Car - :motorcar-qualified on a standard turn restriction
@@ -269,10 +269,10 @@ Feature: Car - Turn restrictions
             | restriction | sj       | nj     | j        | no_straight_on       |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  |       |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  |          |
+            | s    | e  | sj,ej,ej |
 
     @except
     Scenario: Car - Except tag and on no_ restrictions
@@ -298,11 +298,11 @@ Feature: Car - Turn restrictions
             | restriction | sj       | dj     | j        | no_right_turn | motorcar |
 
         When I route I should get
-            | from | to | route |
-            | s    | a  | sj,aj |
-            | s    | b  |       |
-            | s    | c  |       |
-            | s    | d  | sj,dj |
+            | from | to | route    |
+            | s    | a  | sj,aj,aj |
+            | s    | b  |          |
+            | s    | c  |          |
+            | s    | d  | sj,dj,dj |
 
     @except
     Scenario: Car - Except tag and on only_ restrictions
@@ -322,9 +322,9 @@ Feature: Car - Turn restrictions
             | restriction | sj       | aj     | j        | only_straight_on | motorcar |
 
         When I route I should get
-            | from | to | route |
-            | s    | a  | sj,aj |
-            | s    | b  | sj,bj |
+            | from | to | route    |
+            | s    | a  | sj,aj,aj |
+            | s    | b  | sj,bj,bj |
 
     @except
     Scenario: Car - Several only_ restrictions at the same segment
@@ -356,10 +356,10 @@ Feature: Car - Turn restrictions
             | restriction | da       | ae     | a        | only_right_turn  |
 
         When I route I should get
-            | from | to | route                            |
-            | 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    |
+            | from | to | route                               |
+            | e    | f  | ae,xa,bx,fb,fb                      |
+            | c    | f  | dc,da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb |
+            | d    | f  | da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb    |
 
     @except
     Scenario: Car - two only_ restrictions share same to-way
@@ -391,9 +391,9 @@ Feature: Car - Turn restrictions
             | 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 |
+            | from | to | route       |
+            | a    | b  | ax,xy,yb,yb |
+            | b    | a  | yb,xy,ax,ax |
 
     @except
     Scenario: Car - two only_ restrictions share same from-way
@@ -425,7 +425,7 @@ Feature: Car - Turn restrictions
             | 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 |
+            | from | to | route       |
+            | a    | b  | ax,xy,yb,yb |
+            | b    | a  | yb,xy,ax,ax |
 
diff --git a/features/car/roundabout.feature b/features/car/roundabout.feature
index 2965479..beb5d4e 100644
--- a/features/car/roundabout.feature
+++ b/features/car/roundabout.feature
@@ -21,10 +21,10 @@ Feature: Roundabout Instructions
             | abcda | roundabout |
 
         When I route I should get
-            | from | to | route | turns                               |
-            | s    | t  | sa,tb | head,enter_roundabout-1,destination |
-            | s    | u  | sa,uc | head,enter_roundabout-2,destination |
-            | s    | v  | sa,vd | head,enter_roundabout-3,destination |
-            | u    | v  | uc,vd | head,enter_roundabout-1,destination |
-            | u    | s  | uc,sa | head,enter_roundabout-2,destination |
-            | u    | t  | uc,tb | head,enter_roundabout-3,destination |
+            | from | to | route    | turns                            |
+            | s    | t  | sa,tb,tb | depart,roundabout-exit-1,arrive |
+            | s    | u  | sa,uc,uc | depart,roundabout-exit-2,arrive |
+            | s    | v  | sa,vd,vd | depart,roundabout-exit-3,arrive |
+            | u    | v  | uc,vd,vd | depart,roundabout-exit-1,arrive |
+            | u    | s  | uc,sa,sa | depart,roundabout-exit-2,arrive |
+            | u    | t  | uc,tb,tb | depart,roundabout-exit-3,arrive |
diff --git a/features/car/shuttle_train.feature b/features/car/shuttle_train.feature
index 97f32e5..f6e8b84 100644
--- a/features/car/shuttle_train.feature
+++ b/features/car/shuttle_train.feature
@@ -19,13 +19,13 @@ Feature: Car - Handle ferryshuttle train routes
             | gh    | primary |               | no      |
 
         When I route I should get
-            | from | to | route      |
-            | a    | f  | abc,cde,ef |
-            | b    | f  | abc,cde,ef |
-            | e    | c  | cde        |
-            | e    | b  | cde,abc    |
-            | e    | a  | cde,abc    |
-            | c    | e  | cde        |
-            | c    | f  | cde,ef     |
-            | f    | g  |            |
-            | g    | h  | gh         |
+            | from | to | route         |
+            | a    | f  | abc,cde,ef,ef |
+            | b    | f  | abc,cde,ef,ef |
+            | e    | c  | cde,cde       |
+            | e    | b  | cde,abc,abc   |
+            | e    | a  | cde,abc,abc   |
+            | c    | e  | cde,cde       |
+            | c    | f  | cde,ef,ef     |
+            | f    | g  |               |
+            | g    | h  | gh,gh         |
diff --git a/features/car/traffic.feature b/features/car/traffic.feature
new file mode 100644
index 0000000..6d0c62d
--- /dev/null
+++ b/features/car/traffic.feature
@@ -0,0 +1,47 @@
+ at routing @speed @traffic
+Feature: Traffic - speeds
+
+    Background: Use specific speeds
+        Given the node locations
+            | node | lat        | lon      |
+            | a    | 0.1        | 0.1      |
+            | b    | .05        | 0.1      |
+            | c    | 0.0        | 0.1      |
+            | d    | .05        | .03      |
+            | e    | .05        | .066     |
+            | f    | .075       | .066     |
+            | g    | .075       | 0.1      |
+        And the ways
+            | nodes | highway |
+            | ab    | primary |
+            | ad    | primary |
+            | bc    | primary |
+            | dc    | primary |
+            | de    | primary |
+            | eb    | primary |
+            | df    | primary |
+            | fb    | primary |
+        And the speed file
+        """
+        1,2,27
+        2,1,27
+        2,3,27
+        3,2,27
+        1,4,27
+        4,1,27
+        """
+
+    Scenario: Weighting not based on raster sources
+        Given the profile "testbot"
+        Given the extract extra arguments "--generate-edge-lookup"
+        Given the contract extra arguments "--segment-speed-file speeds.csv"
+        And I route I should get
+            | from | to | route    | speed   |
+            | a    | b  | ab,ab    | 27 km/h |
+            | a    | c  | ab,bc,bc | 27 km/h |
+            | b    | c  | bc,bc    | 27 km/h |
+            | a    | d  | ad,ad    | 27 km/h |
+            | d    | c  | dc,dc    | 36 km/h |
+            | g    | b  | ab,ab    | 27 km/h |
+            | a    | g  | ab,ab    | 27 km/h |
+
diff --git a/features/foot/area.feature b/features/foot/area.feature
index 6edd585..8cfc0a8 100644
--- a/features/foot/area.feature
+++ b/features/foot/area.feature
@@ -17,15 +17,15 @@ Feature: Foot - Squares and other areas
             | abcda | yes  | residential |
 
         When I route I should get
-            | from | to | route |
-            | a    | b  | abcda |
-            | a    | d  | abcda |
-            | b    | c  | abcda |
-            | c    | b  | abcda |
-            | c    | d  | abcda |
-            | d    | c  | abcda |
-            | d    | a  | abcda |
-            | a    | d  | abcda |
+            | from | to | route       |
+            | a    | b  | abcda,abcda |
+            | a    | d  | abcda,abcda |
+            | b    | c  | abcda,abcda |
+            | c    | b  | abcda,abcda |
+            | c    | d  | abcda,abcda |
+            | d    | c  | abcda,abcda |
+            | d    | a  | abcda,abcda |
+            | a    | d  | abcda,abcda |
 
     @building
     Scenario: Foot - Don't route on buildings
@@ -41,14 +41,14 @@ Feature: Foot - Squares and other areas
 
         When I route I should get
             | from | to | route |
-            | a    | b  | xa    |
-            | a    | d  | xa    |
-            | b    | c  | xa    |
-            | c    | b  | xa    |
-            | c    | d  | xa    |
-            | d    | c  | xa    |
-            | d    | a  | xa    |
-            | a    | d  | xa    |
+            | a    | b  | xa,xa |
+            | a    | d  | xa,xa |
+            | b    | c  | xa,xa |
+            | c    | b  | xa,xa |
+            | c    | d  | xa,xa |
+            | d    | c  | xa,xa |
+            | d    | a  | xa,xa |
+            | a    | d  | xa,xa |
 
     @parking
     Scenario: Foot - parking areas
@@ -65,17 +65,17 @@ Feature: Foot - Squares and other areas
             | abcda | (nil)   | parking |
 
         When I route I should get
-            | from | to | route       |
-            | x    | y  | xa,abcda,by |
-            | y    | x  | by,abcda,xa |
-            | a    | b  | abcda       |
-            | a    | d  | abcda       |
-            | b    | c  | abcda       |
-            | c    | b  | abcda       |
-            | c    | d  | abcda       |
-            | d    | c  | abcda       |
-            | d    | a  | abcda       |
-            | a    | d  | abcda       |
+            | from | to | route          |
+            | x    | y  | xa,abcda,by,by |
+            | y    | x  | by,abcda,xa,xa |
+            | a    | b  | abcda,abcda    |
+            | a    | d  | abcda,abcda    |
+            | b    | c  | abcda,abcda    |
+            | c    | b  | abcda,abcda    |
+            | c    | d  | abcda,abcda    |
+            | d    | c  | abcda,abcda    |
+            | d    | a  | abcda,abcda    |
+            | a    | d  | abcda,abcda    |
 
     @train @platform
     Scenario: Foot - railway platforms
@@ -90,14 +90,14 @@ Feature: Foot - Squares and other areas
             | abcda | (nil)   | platform |
 
         When I route I should get
-            | from | to | route       |
-            | x    | y  | xa,abcda,by |
-            | y    | x  | by,abcda,xa |
-            | a    | b  | abcda       |
-            | a    | d  | abcda       |
-            | b    | c  | abcda       |
-            | c    | b  | abcda       |
-            | c    | d  | abcda       |
-            | d    | c  | abcda       |
-            | d    | a  | abcda       |
-            | a    | d  | abcda       |
+            | from | to | route          |
+            | x    | y  | xa,abcda,by,by |
+            | y    | x  | by,abcda,xa,xa |
+            | a    | b  | abcda,abcda    |
+            | a    | d  | abcda,abcda    |
+            | b    | c  | abcda,abcda    |
+            | c    | b  | abcda,abcda    |
+            | c    | d  | abcda,abcda    |
+            | d    | c  | abcda,abcda    |
+            | d    | a  | abcda,abcda    |
+            | a    | d  | abcda,abcda    |
diff --git a/features/foot/ferry.feature b/features/foot/ferry.feature
index 866644d..9ad1c9d 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       | 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   |
+            | from | to | route           | modes                         |
+            | a    | g  | abc,cde,efg,efg | walking,ferry,walking,walking |
+            | b    | f  | abc,cde,efg,efg | walking,ferry,walking,walking |
+            | e    | c  | cde,cde         | ferry,ferry                   |
+            | e    | b  | cde,abc,abc     | ferry,walking,walking         |
+            | e    | a  | cde,abc,abc     | ferry,walking,walking         |
+            | c    | e  | cde,cde         | ferry,ferry                   |
+            | c    | f  | cde,efg,efg     | ferry,walking,walking         |
+            | c    | g  | cde,efg,efg     | ferry,walking,walking         |
 
     Scenario: Foot - Ferry duration, single node
         Given the node map
@@ -58,6 +58,6 @@ Feature: Foot - Handle ferry routes
             | abcd  |         | ferry | yes  | 1:00     |
 
         When I route I should get
-            | from | to | route | time       |
-            | a    | d  | abcd  | 3600s +-10 |
-            | d    | a  | abcd  | 3600s +-10 |
+            | from | to | route     | time       |
+            | a    | d  | abcd,abcd | 3600s +-10 |
+            | d    | a  | abcd,abcd | 3600s +-10 |
diff --git a/features/foot/names.feature b/features/foot/names.feature
index d5fdcc7..a765de6 100644
--- a/features/foot/names.feature
+++ b/features/foot/names.feature
@@ -15,8 +15,8 @@ Feature: Foot - Street names in instructions
             | bc    | Your Way |
 
         When I route I should get
-            | from | to | route           |
-            | a    | c  | My Way,Your Way |
+            | from | to | route                    |
+            | a    | c  | My Way,Your Way,Your Way |
 
     @unnamed
     Scenario: Foot - Use way type to describe unnamed ways
@@ -29,5 +29,5 @@ Feature: Foot - Street names in instructions
             | bcd   | track   |      |
 
         When I route I should get
-            | from | to | route                             |
-            | a    | d  | {highway:footway},{highway:track} |
+            | from | to | route                                             |
+            | a    | d  | {highway:footway},{highway:track},{highway:track} |
diff --git a/features/foot/ref.feature b/features/foot/ref.feature
index bc0c77e..8fed586 100644
--- a/features/foot/ref.feature
+++ b/features/foot/ref.feature
@@ -13,8 +13,8 @@ Feature: Foot - Way ref
             | ab    | Utopia Drive | E7  |
 
         When I route I should get
-            | from | to | route             |
-            | a    | b  | Utopia Drive / E7 |
+            | from | to | route                               |
+            | a    | b  | Utopia Drive / E7,Utopia Drive / E7 |
 
     Scenario: Foot - Way with only ref
         Given the node map
@@ -26,7 +26,7 @@ Feature: Foot - Way ref
 
         When I route I should get
             | from | to | route |
-            | a    | b  | E7    |
+            | a    | b  | E7,E7 |
 
     Scenario: Foot - Way with only name
         Given the node map
@@ -37,5 +37,5 @@ Feature: Foot - Way ref
             | ab    | Utopia Drive |
 
         When I route I should get
-            | from | to | route        |
-            | a    | b  | Utopia Drive |
+            | from | to | route                     |
+            | a    | b  | Utopia Drive,Utopia Drive |
diff --git a/features/foot/restrictions.feature b/features/foot/restrictions.feature
index 8d6a029..ae66658 100644
--- a/features/foot/restrictions.feature
+++ b/features/foot/restrictions.feature
@@ -24,10 +24,10 @@ Feature: Foot - Turn restrictions
             | restriction | sj       | wj     | j        | no_left_turn |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @no_turning
     Scenario: Foot - No right turn
@@ -48,10 +48,10 @@ Feature: Foot - Turn restrictions
             | restriction | sj       | ej     | j        | no_right_turn |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @no_turning
     Scenario: Foot - No u-turn
@@ -72,10 +72,10 @@ Feature: Foot - Turn restrictions
             | restriction | sj       | wj     | j        | no_u_turn   |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @no_turning
     Scenario: Foot - Handle any no_* relation
@@ -96,10 +96,10 @@ Feature: Foot - Turn restrictions
             | restriction | sj       | wj     | j        | no_weird_zigzags |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @only_turning
     Scenario: Foot - Only left turn
@@ -120,10 +120,10 @@ Feature: Foot - Turn restrictions
             | restriction | sj       | wj     | j        | only_left_turn |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @only_turning
     Scenario: Foot - Only right turn
@@ -144,10 +144,10 @@ Feature: Foot - Turn restrictions
             | restriction | sj       | ej     | j        | only_right_turn |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @only_turning
     Scenario: Foot - Only straight on
@@ -168,10 +168,10 @@ Feature: Foot - Turn restrictions
             | restriction | sj       | nj     | j        | only_straight_on |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @no_turning
     Scenario: Foot - Handle any only_* restriction
@@ -192,10 +192,10 @@ Feature: Foot - Turn restrictions
             | restriction | sj       | nj     | j        | only_weird_zigzags |
 
         When I route I should get
-            | from | to | route |
-            | s    | w  | sj,wj |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
+            | from | to | route    |
+            | s    | w  | sj,wj,wj |
+            | s    | n  | sj,nj,nj |
+            | s    | e  | sj,ej,ej |
 
     @except
     Scenario: Foot - Except tag and on no_ restrictions
@@ -221,11 +221,11 @@ Feature: Foot - Turn restrictions
             | restriction | sj       | dj     | j        | no_right_turn | foot   |
 
         When I route I should get
-            | from | to | route |
-            | s    | a  | sj,aj |
-            | s    | b  | sj,bj |
-            | s    | c  | sj,cj |
-            | s    | d  | sj,dj |
+            | from | to | route    |
+            | s    | a  | sj,aj,aj |
+            | s    | b  | sj,bj,bj |
+            | s    | c  | sj,cj,cj |
+            | s    | d  | sj,dj,dj |
 
     @except
     Scenario: Foot - Except tag and on only_ restrictions
@@ -245,9 +245,9 @@ Feature: Foot - Turn restrictions
             | restriction | sj       | aj     | j        | only_straight_on | foot   |
 
         When I route I should get
-            | from | to | route |
-            | s    | a  | sj,aj |
-            | s    | b  | sj,bj |
+            | from | to | route    |
+            | s    | a  | sj,aj,aj |
+            | s    | b  | sj,bj,bj |
 
     @except
     Scenario: Foot - Multiple except tag values
@@ -279,10 +279,10 @@ Feature: Foot - Turn restrictions
             | restriction | sj       | jf     | j        | no_straight_on | foot, bus     |
 
         When I route I should get
-            | from | to | route |
-            | s    | a  | sj,ja |
-            | s    | b  | sj,jb |
-            | s    | c  | sj,jc |
-            | s    | d  | sj,jd |
-            | s    | e  | sj,je |
-            | s    | f  | sj,jf |
+            | from | to | route    |
+            | s    | a  | sj,ja,ja |
+            | s    | b  | sj,jb,jb |
+            | s    | c  | sj,jc,jc |
+            | s    | d  | sj,jd,jd |
+            | s    | e  | sj,je,je |
+            | s    | f  | sj,jf,jf |
diff --git a/features/foot/roundabout.feature b/features/foot/roundabout.feature
index 5aa9860..181f240 100644
--- a/features/foot/roundabout.feature
+++ b/features/foot/roundabout.feature
@@ -3,12 +3,12 @@ Feature: Roundabout Instructions
 
     Background:
         Given the profile "foot"
-    
+
     @todo
     Scenario: Foot - Roundabout instructions
     # You can walk in both directions on a roundabout, bu the normal roundabout instructions don't
     # make sense when you're going the opposite way around the roundabout.
-    
+
         Given the node map
             |   |   | v |   |   |
             |   |   | d |   |   |
@@ -25,10 +25,10 @@ Feature: Roundabout Instructions
             | abcda | roundabout |
 
         When I route I should get
-            | from | to | route | turns                               |
-            | s    | t  | sa,tb | head,enter_roundabout-1,destination |
-            | s    | u  | sa,uc | head,enter_roundabout-2,destination |
-            | s    | v  | sa,vd | head,enter_roundabout-3,destination |
-            | u    | v  | uc,vd | head,enter_roundabout-1,destination |
-            | u    | s  | uc,sa | head,enter_roundabout-2,destination |
-            | u    | t  | uc,tb | head,enter_roundabout-3,destination |
+            | from | to | route | turns                            |
+            | s    | t  | sa,tb | depart,roundabout-exit-1,arrive |
+            | s    | u  | sa,uc | depart,roundabout-exit-2,arrive |
+            | s    | v  | sa,vd | depart,roundabout-exit-3,arrive |
+            | u    | v  | uc,vd | depart,roundabout-exit-1,arrive |
+            | u    | s  | uc,sa | depart,roundabout-exit-2,arrive |
+            | u    | t  | uc,tb | depart,roundabout-exit-3,arrive |
diff --git a/features/guidance/motorway.feature b/features/guidance/motorway.feature
new file mode 100644
index 0000000..bcde322
--- /dev/null
+++ b/features/guidance/motorway.feature
@@ -0,0 +1,202 @@
+ at routing  @guidance
+Feature: Basic Roundabout
+
+    Background:
+        Given the profile "testbot"
+        Given a grid size of 10 meters
+
+    Scenario: Ramp Exit Right
+        Given the node map
+            | a | b | c | d | e |
+            |   |   |   | f | g |
+
+        And the ways
+            | nodes  | highway       |
+            | abcde  | motorway      |
+            | bfg    | motorway_link |
+
+       When I route I should get
+            | waypoints | route           | turns                             |
+            | a,e       | abcde, abcde    | depart, arrive                    |
+            | a,g       | abcde, bfg, bfg | depart, ramp-slight-right, arrive |
+
+    Scenario: Ramp Exit Right Curved Right
+        Given the node map
+            | a | b | c |   |   |
+            |   |   | f | d |   |
+            |   |   |   | g | e |
+
+        And the ways
+            | nodes  | highway       |
+            | abcde  | motorway      |
+            | bfg    | motorway_link |
+
+       When I route I should get
+            | waypoints | route           | turns                             |
+            | a,e       | abcde, abcde    | depart, arrive                    |
+            | a,g       | abcde, bfg, bfg | depart, ramp-slight-right, arrive |
+
+    Scenario: Ramp Exit Right Curved Left
+        Given the node map
+            |   |   |   |   | e |
+            |   |   |   | d | g |
+            | a | b | c | f |   |
+
+
+        And the ways
+            | nodes  | highway       |
+            | abcde  | motorway      |
+            | cfg    | motorway_link |
+
+       When I route I should get
+            | waypoints | route           | turns                             |
+            | a,e       | abcde, abcde    | depart, arrive                    |
+            | a,g       | abcde, cfg, cfg | depart, ramp-slight-right, arrive |
+
+
+    Scenario: Ramp Exit Left
+        Given the node map
+            |   |   |   | f | g |
+            | a | b | c | d | e |
+
+        And the ways
+            | nodes  | highway       |
+            | abcde  | motorway      |
+            | bfg    | motorway_link |
+
+       When I route I should get
+            | waypoints | route           | turns                            |
+            | a,e       | abcde, abcde    | depart, arrive                   |
+            | a,g       | abcde, bfg, bfg | depart, ramp-slight-left, arrive |
+
+    Scenario: Ramp Exit Left Curved Left
+        Given the node map
+            |   |   |   | g | e |
+            |   |   | f | d |   |
+            | a | b | c |   |   |
+
+        And the ways
+            | nodes  | highway       |
+            | abcde  | motorway      |
+            | bfg    | motorway_link |
+
+       When I route I should get
+            | waypoints | route           | turns                            |
+            | a,e       | abcde, abcde    | depart, arrive                   |
+            | a,g       | abcde, bfg, bfg | depart, ramp-slight-left, arrive |
+
+    Scenario: Ramp Exit Left Curved Right
+        Given the node map
+            | a | b | c | f |   |
+            |   |   |   | d | g |
+            |   |   |   |   | e |
+
+        And the ways
+            | nodes  | highway       |
+            | abcde  | motorway      |
+            | cfg    | motorway_link |
+
+       When I route I should get
+            | waypoints | route           | turns                            |
+            | a,e       | abcde, abcde    | depart, arrive                   |
+            | a,g       | abcde, cfg, cfg | depart, ramp-slight-left, arrive |
+
+    Scenario: On Ramp Right
+        Given the node map
+            | a | b | c | d | e |
+            | f | g |   |   |   |
+
+        And the ways
+            | nodes  | highway       |
+            | abcde  | motorway      |
+            | fgd    | motorway_link |
+
+       When I route I should get
+            | waypoints | route           | turns                             |
+            | a,e       | abcde, abcde    | depart, arrive                    |
+            | f,e       | abcde, fgd, fgd | depart, merge-slight-left, arrive |
+
+    Scenario: On Ramp Left
+        Given the node map
+            | f | g |   |   |   |
+            | a | b | c | d | e |
+
+        And the ways
+            | nodes  | highway       |
+            | abcde  | motorway      |
+            | fgd    | motorway_link |
+
+       When I route I should get
+            | waypoints | route           | turns                              |
+            | a,e       | abcde, abcde    | depart, arrive                     |
+            | f,e       | abcde, fgd, fgd | depart, merge-slight-right, arrive |
+
+    Scenario: Highway Fork
+        Given the node map
+            |   |   |   |   | d | e |
+            | a | b | c |   |   |   |
+            |   |   |   |   | f | g |
+
+        And the ways
+            | nodes  | highway  |
+            | abcde  | motorway |
+            | cfg    | motorway |
+
+       When I route I should get
+            | waypoints | route               | turns                      |
+            | a,e       | abcde, abcde, abcde | depart, fork-left, arrive  |
+            | a,g       | abcde, cfg, cfg     | depart, fork-right, arrive |
+
+     Scenario: Fork After Ramp
+       Given the node map
+            |   |   |   |   | d | e |
+            | a | b | c |   |   |   |
+            |   |   |   |   | f | g |
+
+        And the ways
+            | nodes  | highway       |
+            | abc    | motorway_link |
+            | cde    | motorway      |
+            | cfg    | motorway      |
+
+       When I route I should get
+            | waypoints | route         | turns                      |
+            | a,e       | abc, cde, cde | depart, fork-left, arrive  |
+            | a,g       | abc, cfg, cfg | depart, fork-right, arrive |
+
+     Scenario: On And Off Ramp Right
+       Given the node map
+            | a | b |   | c |   | d | e |
+            | f | g |   |   |   | h | i |
+
+        And the ways
+            | nodes  | highway       |
+            | abcde  | motorway      |
+            | fgc    | motorway_link |
+            | chi    | motorway_link |
+
+       When I route I should get
+            | waypoints | route             | turns                             |
+            | a,e       | abcde, abcde      | depart, arrive                    |
+            | f,e       | fgc, abcde, abcde | depart, merge-slight-left, arrive |
+            | a,i       | abcde, chi, chi   | depart, ramp-slight-right, arrive |
+            | f,i       | fgc, chi, chi     | depart, turn-slight-right, arrive |
+
+    Scenario: On And Off Ramp Left
+       Given the node map
+            | f | g |   |   |   | h | i |
+            | a | b |   | c |   | d | e |
+
+        And the ways
+            | nodes  | highway       |
+            | abcde  | motorway      |
+            | fgc    | motorway_link |
+            | chi    | motorway_link |
+
+       When I route I should get
+            | waypoints | route             | turns                              |
+            | a,e       | abcde, abcde      | depart, arrive                     |
+            | f,e       | fgc, abcde, abcde | depart, merge-slight-right, arrive |
+            | a,i       | abcde, chi, chi   | depart, ramp-slight-left, arrive   |
+            | f,i       | fgc, chi, chi     | depart, turn-slight-left, arrive   |
+
diff --git a/features/guidance/roundabout.feature b/features/guidance/roundabout.feature
new file mode 100644
index 0000000..21d6530
--- /dev/null
+++ b/features/guidance/roundabout.feature
@@ -0,0 +1,173 @@
+ at routing  @guidance
+Feature: Basic Roundabout
+
+    Background:
+        Given the profile "testbot"
+        Given a grid size of 10 meters
+
+    Scenario: Enter and Exit
+        Given the node map
+            |   |   | a |   |   |
+            |   |   | b |   |   |
+            | h | g |   | c | d |
+            |   |   | e |   |   |
+            |   |   | f |   |   |
+
+       And the ways
+            | nodes  | junction   |
+            | ab     |            |
+            | cd     |            |
+            | ef     |            |
+            | gh     |            |
+            | bcegb  | roundabout |
+
+       When I route I should get
+           | waypoints | route    | turns                           |
+           | a,d       | ab,cd,cd | depart,roundabout-exit-1,arrive |
+           | a,f       | ab,ef,ef | depart,roundabout-exit-2,arrive |
+           | a,h       | ab,gh,gh | depart,roundabout-exit-3,arrive |
+           | d,f       | cd,ef,ef | depart,roundabout-exit-1,arrive |
+           | d,h       | cd,gh,gh | depart,roundabout-exit-2,arrive |
+           | d,a       | cd,ab,ab | depart,roundabout-exit-3,arrive |
+           | f,h       | ef,gh,gh | depart,roundabout-exit-1,arrive |
+           | f,a       | ef,ab,ab | depart,roundabout-exit-2,arrive |
+           | f,d       | ef,cd,cd | depart,roundabout-exit-3,arrive |
+           | h,a       | gh,ab,ab | depart,roundabout-exit-1,arrive |
+           | h,d       | gh,cd,cd | depart,roundabout-exit-2,arrive |
+           | h,f       | gh,ef,ef | depart,roundabout-exit-3,arrive |
+
+    Scenario: Only Enter
+        Given the node map
+            |   |   | a |   |   |
+            |   |   | b |   |   |
+            | h | g |   | c | d |
+            |   |   | e |   |   |
+            |   |   | f |   |   |
+
+       And the ways
+            | nodes  | junction   |
+            | ab     |            |
+            | cd     |            |
+            | ef     |            |
+            | gh     |            |
+            | bcegb  | roundabout |
+
+       When I route I should get
+           | waypoints | route    | turns                          |
+           | a,b       | ab,ab    | depart,arrive                  |
+           | a,c       | ab,bcegb | depart,roundabout-enter,arrive |
+           | a,e       | ab,bcegb | depart,roundabout-enter,arrive |
+           | a,g       | ab,bcegb | depart,roundabout-enter,arrive |
+           | d,c       | cd,cd    | depart,arrive                  |
+           | d,e       | cd,bcegb | depart,roundabout-enter,arrive |
+           | d,g       | cd,bcegb | depart,roundabout-enter,arrive |
+           | d,b       | cd,bcegb | depart,roundabout-enter,arrive |
+           | f,e       | ef,ef    | depart,arrive                  |
+           | f,g       | ef,bcegb | depart,roundabout-enter,arrive |
+           | f,b       | ef,bcegb | depart,roundabout-enter,arrive |
+           | f,c       | ef,bcegb | depart,roundabout-enter,arrive |
+           | h,g       | gh,gh    | depart,arrive                  |
+           | h,b       | gh,bcegb | depart,roundabout-enter,arrive |
+           | h,c       | gh,bcegb | depart,roundabout-enter,arrive |
+           | h,e       | gh,bcegb | depart,roundabout-enter,arrive |
+
+    Scenario: Only Exit
+        Given the node map
+            |   |   | a |   |   |
+            |   |   | b |   |   |
+            | h | g |   | c | d |
+            |   |   | e |   |   |
+            |   |   | f |   |   |
+
+       And the ways
+            | nodes  | junction   |
+            | ab     |            |
+            | cd     |            |
+            | ef     |            |
+            | gh     |            |
+            | bcegb  | roundabout |
+
+       When I route I should get
+           | waypoints | route       | turns                           |
+           | b,a       | ab,ab       | depart,arrive                   |
+           | b,d       | bcegb,cd,cd | depart,roundabout-exit-1,arrive |
+           | b,f       | bcegb,ef,ef | depart,roundabout-exit-2,arrive |
+           | b,h       | bcegb,gh,gh | depart,roundabout-exit-3,arrive |
+           | c,d       | cd,cd       | depart,arrive                   |
+           | c,f       | bcegb,ef,ef | depart,roundabout-exit-1,arrive |
+           | c,h       | bcegb,gh,gh | depart,roundabout-exit-2,arrive |
+           | c,a       | bcegb,ab,ab | depart,roundabout-exit-3,arrive |
+           | e,f       | ef,ef       | depart,arrive                   |
+           | e,h       | bcegb,gh,gh | depart,roundabout-exit-1,arrive |
+           | e,a       | bcegb,ab,ab | depart,roundabout-exit-2,arrive |
+           | e,d       | bcegb,cd,cd | depart,roundabout-exit-3,arrive |
+           | g,h       | gh,gh       | depart,arrive                   |
+           | g,a       | bcegb,ab,ab | depart,roundabout-exit-1,arrive |
+           | g,d       | bcegb,cd,cd | depart,roundabout-exit-2,arrive |
+           | g,f       | bcegb,ef,ef | depart,roundabout-exit-3,arrive |
+
+    Scenario: Drive Around
+        Given the node map
+            |   |   | a |   |   |
+            |   |   | b |   |   |
+            | h | g |   | c | d |
+            |   |   | e |   |   |
+            |   |   | f |   |   |
+
+       And the ways
+            | nodes  | junction   |
+            | ab     |            |
+            | cd     |            |
+            | ef     |            |
+            | gh     |            |
+            | bcegb  | roundabout |
+
+       When I route I should get
+           | waypoints | route       | turns         |
+           | b,c       | bcegb,bcegb | depart,arrive |
+           | b,e       | bcegb,bcegb | depart,arrive |
+           | b,g       | bcegb,bcegb | depart,arrive |
+           | c,e       | bcegb,bcegb | depart,arrive |
+           | c,g       | bcegb,bcegb | depart,arrive |
+           | c,b       | bcegb,bcegb | depart,arrive |
+           | e,g       | bcegb,bcegb | depart,arrive |
+           | e,b       | bcegb,bcegb | depart,arrive |
+           | e,c       | bcegb,bcegb | depart,arrive |
+           | g,b       | bcegb,bcegb | depart,arrive |
+           | g,c       | bcegb,bcegb | depart,arrive |
+           | g,e       | bcegb,bcegb | depart,arrive |
+
+     Scenario: Mixed Entry and Exit
+        Given the node map
+           |   | a |   | c |   |
+           | l |   | b |   | d |
+           |   | k |   | e |   |
+           | j |   | h |   | f |
+           |   | i |   | g |   |
+
+        And the ways
+           | nodes | junction   | oneway |
+           | abc   |            | yes    |
+           | def   |            | yes    |
+           | ghi   |            | yes    |
+           | jkl   |            | yes    |
+           | behkb | roundabout | yes    |
+
+        When I route I should get
+           | waypoints | route       | turns                           |
+           | a,c       | abc,abc,abc | depart,roundabout-exit-1,arrive |
+           | a,f       | abc,def,def | depart,roundabout-exit-2,arrive |
+           | a,i       | abc,ghi,ghi | depart,roundabout-exit-3,arrive |
+           | a,l       | abc,jkl,jkl | depart,roundabout-exit-4,arrive |
+           | d,f       | def,def,def | depart,roundabout-exit-1,arrive |
+           | d,i       | def,ghi,ghi | depart,roundabout-exit-2,arrive |
+           | d,l       | def,jkl,jkl | depart,roundabout-exit-3,arrive |
+           | d,c       | def,abc,abc | depart,roundabout-exit-4,arrive |
+           | g,i       | ghi,ghi,ghi | depart,roundabout-exit-1,arrive |
+           | g,l       | ghi,jkl,jkl | depart,roundabout-exit-2,arrive |
+           | g,c       | ghi,abc,abc | depart,roundabout-exit-3,arrive |
+           | g,f       | ghi,edf,edf | depart,roundabout-exit-4,arrive |
+           | j,l       | jkl,jkl,jkl | depart,roundabout-exit-1,arrive |
+           | j,c       | jkl,abc,abc | depart,roundabout-exit-2,arrive |
+           | j,f       | jkl,def,def | depart,roundabout-exit-3,arrive |
+           | j,i       | jkl,ghi,ghi | depart,roundabout-exit-4,arrive |
diff --git a/features/options/prepare/files.feature b/features/options/contract/files.feature
similarity index 52%
rename from features/options/prepare/files.feature
rename to features/options/contract/files.feature
index 6e82a6b..5e50e14 100644
--- a/features/options/prepare/files.feature
+++ b/features/options/contract/files.feature
@@ -1,5 +1,5 @@
 @prepare @options @files
-Feature: osrm-prepare command line options: files
+Feature: osrm-contract command line options: files
 # expansions:
 # {extracted_base} => path to current extracted input file
 # {profile} => path to current profile script
@@ -13,18 +13,13 @@ Feature: osrm-prepare command line options: files
             | ab    |
         And the data has been extracted
 
-    Scenario: osrm-prepare - Passing base file
-        When I run "osrm-prepare {extracted_base}.osrm --profile {profile}"
+    Scenario: osrm-contract - Passing base file
+        When I run "osrm-contract {extracted_base}.osrm"
         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} {extracted_base}.osrm"
-        Then stderr should be empty
-        And it should exit with code 0
-
-    Scenario: osrm-prepare - Missing input file
-        When I run "osrm-prepare over-the-rainbow.osrm --profile {profile}"
+    Scenario: osrm-contract - Missing input file
+        When I run "osrm-contract over-the-rainbow.osrm"
         And stderr should contain "over-the-rainbow.osrm"
         And stderr should contain "not found"
         And it should exit with code 1
diff --git a/features/options/prepare/help.feature b/features/options/contract/help.feature
similarity index 58%
rename from features/options/prepare/help.feature
rename to features/options/contract/help.feature
index 34ec3d5..411bc55 100644
--- a/features/options/prepare/help.feature
+++ b/features/options/contract/help.feature
@@ -1,56 +1,44 @@
 @prepare @options @help
-Feature: osrm-prepare command line options: help
+Feature: osrm-contract command line options: help
 
-    Background:
-        Given the profile "testbot"
-
-    Scenario: osrm-prepare - Help should be shown when no options are passed
-        When I run "osrm-prepare"
+    Scenario: osrm-contract - Help should be shown when no options are passed
+        When I run "osrm-contract"
         Then stderr should be empty
-        And stdout should contain "osrm-prepare <input.osrm> [options]:"
+        And stdout should contain "osrm-contract <input.osrm> [options]:"
         And stdout should contain "Options:"
         And stdout should contain "--version"
         And stdout should contain "--help"
-        And stdout should contain "--config"
         And stdout should contain "Configuration:"
-        And stdout should contain "--profile"
         And stdout should contain "--threads"
         And stdout should contain "--core"
         And stdout should contain "--level-cache"
         And stdout should contain "--segment-speed-file"
-        And stdout should contain 21 lines
         And it should exit with code 1
 
-    Scenario: osrm-prepare - Help, short
-        When I run "osrm-prepare -h"
+    Scenario: osrm-contract - Help, short
+        When I run "osrm-contract -h"
         Then stderr should be empty
-        And stdout should contain "osrm-prepare <input.osrm> [options]:"
+        And stdout should contain "osrm-contract <input.osrm> [options]:"
         And stdout should contain "Options:"
         And stdout should contain "--version"
         And stdout should contain "--help"
-        And stdout should contain "--config"
         And stdout should contain "Configuration:"
-        And stdout should contain "--profile"
         And stdout should contain "--threads"
         And stdout should contain "--core"
         And stdout should contain "--level-cache"
         And stdout should contain "--segment-speed-file"
-        And stdout should contain 21 lines
         And it should exit with code 0
 
-    Scenario: osrm-prepare - Help, long
-        When I run "osrm-prepare --help"
+    Scenario: osrm-contract - Help, long
+        When I run "osrm-contract --help"
         Then stderr should be empty
-        And stdout should contain "osrm-prepare <input.osrm> [options]:"
+        And stdout should contain "osrm-contract <input.osrm> [options]:"
         And stdout should contain "Options:"
         And stdout should contain "--version"
         And stdout should contain "--help"
-        And stdout should contain "--config"
         And stdout should contain "Configuration:"
-        And stdout should contain "--profile"
         And stdout should contain "--threads"
         And stdout should contain "--core"
         And stdout should contain "--level-cache"
         And stdout should contain "--segment-speed-file"
-        And stdout should contain 21 lines
         And it should exit with code 0
diff --git a/features/options/prepare/invalid.feature b/features/options/contract/invalid.feature
similarity index 60%
rename from features/options/prepare/invalid.feature
rename to features/options/contract/invalid.feature
index 7450390..38ee3ac 100644
--- a/features/options/prepare/invalid.feature
+++ b/features/options/contract/invalid.feature
@@ -1,11 +1,11 @@
 @prepare @options @invalid
-Feature: osrm-prepare command line options: invalid options
+Feature: osrm-contract command line options: invalid options
 
     Background:
         Given the profile "testbot"
 
-    Scenario: osrm-prepare - Non-existing option
-        When I run "osrm-prepare --fly-me-to-the-moon"
+    Scenario: osrm-contract - Non-existing option
+        When I run "osrm-contract --fly-me-to-the-moon"
         Then stdout should be empty
         And stderr should contain "option"
         And stderr should contain "fly-me-to-the-moon"
diff --git a/features/options/prepare/version.feature b/features/options/contract/version.feature
similarity index 74%
rename from features/options/prepare/version.feature
rename to features/options/contract/version.feature
index 7a821c6..be99bbe 100644
--- a/features/options/prepare/version.feature
+++ b/features/options/contract/version.feature
@@ -1,5 +1,5 @@
 @prepare @options @version
-Feature: osrm-prepare command line options: version
+Feature: osrm-contract command line options: version
 # the regex will match these two formats:
 # v0.3.7.0          # this is the normal format when you build from a git clone
 # -128-NOTFOUND     # if you build from a shallow clone (used on Travis)
@@ -7,15 +7,15 @@ Feature: osrm-prepare command line options: version
     Background:
         Given the profile "testbot"
     
-    Scenario: osrm-prepare - Version, short
-        When I run "osrm-prepare --v"
+    Scenario: osrm-contract - Version, short
+        When I run "osrm-contract --v"
         Then stderr should be empty
         And stdout should contain 1 line
         And stdout should contain /(v\d{1,2}\.\d{1,2}\.\d{1,2}|\w*-\d+-\w+)/
         And it should exit with code 0
 
-    Scenario: osrm-prepare - Version, long
-        When I run "osrm-prepare --version"
+    Scenario: osrm-contract - Version, long
+        When I run "osrm-contract --version"
         Then stderr should be empty
         And stdout should contain 1 line
         And stdout should contain /(v\d{1,2}\.\d{1,2}\.\d{1,2}|\w*-\d+-\w+)/
diff --git a/features/options/extract/help.feature b/features/options/extract/help.feature
index 722c4dc..cdf1eb9 100644
--- a/features/options/extract/help.feature
+++ b/features/options/extract/help.feature
@@ -11,13 +11,11 @@ Feature: osrm-extract command line options: help
         And stdout should contain "Options:"
         And stdout should contain "--version"
         And stdout should contain "--help"
-        And stdout should contain "--config"
         And stdout should contain "Configuration:"
         And stdout should contain "--profile"
         And stdout should contain "--threads"
         And stdout should contain "--generate-edge-lookup"
         And stdout should contain "--small-component-size"
-        And stdout should contain 20 lines
         And it should exit with code 0
 
     Scenario: osrm-extract - Help, short
@@ -27,13 +25,11 @@ Feature: osrm-extract command line options: help
         And stdout should contain "Options:"
         And stdout should contain "--version"
         And stdout should contain "--help"
-        And stdout should contain "--config"
         And stdout should contain "Configuration:"
         And stdout should contain "--profile"
         And stdout should contain "--threads"
         And stdout should contain "--generate-edge-lookup"
         And stdout should contain "--small-component-size"
-        And stdout should contain 20 lines
         And it should exit with code 0
 
     Scenario: osrm-extract - Help, long
@@ -43,11 +39,9 @@ Feature: osrm-extract command line options: help
         And stdout should contain "Options:"
         And stdout should contain "--version"
         And stdout should contain "--help"
-        And stdout should contain "--config"
         And stdout should contain "Configuration:"
         And stdout should contain "--profile"
         And stdout should contain "--threads"
         And stdout should contain "--generate-edge-lookup"
         And stdout should contain "--small-component-size"
-        And stdout should contain 20 lines
         And it should exit with code 0
diff --git a/features/options/routed/files.feature b/features/options/routed/files.feature
index 15ce679..59ce7c2 100644
--- a/features/options/routed/files.feature
+++ b/features/options/routed/files.feature
@@ -4,8 +4,8 @@ Feature: osrm-routed command line options: files
 # 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 {prepared_base} part of the options to osrm-routed will be expanded to the actual base path of
-# the prepared input file.
+# The {contracted_base} part of the options to osrm-routed will be expanded to the actual base path of
+# the contracted input file.
 
 # TODO
 # Since we're not using osmr-datastore for all testing, osrm-routed is kept running.
@@ -19,14 +19,14 @@ Feature: osrm-routed command line options: files
         And the ways
             | nodes |
             | ab    |
-        And the data has been prepared
+        And the data has been contracted
 
     Scenario: osrm-routed - Passing base file
-        When I run "osrm-routed {prepared_base}.osrm --trial"
+        When I run "osrm-routed {contracted_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/
         And stdout should contain /^\[info\] loaded plugin: viaroute/
         And stdout should contain /^\[info\] trial run/
         And stdout should contain /^\[info\] shutdown completed/
-        And it should exit with code 0
\ No newline at end of file
+        And it should exit with code 0
diff --git a/features/options/routed/help.feature b/features/options/routed/help.feature
index 34c6ee2..8f64bd9 100644
--- a/features/options/routed/help.feature
+++ b/features/options/routed/help.feature
@@ -11,16 +11,8 @@ Feature: osrm-routed command line options: help
         And stdout should contain "Options:"
         And stdout should contain "--version"
         And stdout should contain "--help"
-        And stdout should contain "--config"
         And stdout should contain "--trial"
         And stdout should contain "Configuration:"
-        And stdout should contain "--hsgrdata arg"
-        And stdout should contain "--nodesdata arg"
-        And stdout should contain "--edgesdata arg"
-        And stdout should contain "--ramindex arg"
-        And stdout should contain "--fileindex arg"
-        And stdout should contain "--namesdata arg"
-        And stdout should contain "--timestamp arg"
         And stdout should contain "--ip"
         And stdout should contain "--port"
         And stdout should contain "--threads"
@@ -29,7 +21,6 @@ Feature: osrm-routed command line options: help
         And stdout should contain "--max-trip-size"
         And stdout should contain "--max-table-size"
         And stdout should contain "--max-matching-size"
-        And stdout should contain 30 lines
         And it should exit with code 0
 
     Scenario: osrm-routed - Help, short
@@ -39,16 +30,8 @@ Feature: osrm-routed command line options: help
         And stdout should contain "Options:"
         And stdout should contain "--version"
         And stdout should contain "--help"
-        And stdout should contain "--config"
         And stdout should contain "--trial"
         And stdout should contain "Configuration:"
-        And stdout should contain "--hsgrdata arg"
-        And stdout should contain "--nodesdata arg"
-        And stdout should contain "--edgesdata arg"
-        And stdout should contain "--ramindex arg"
-        And stdout should contain "--fileindex arg"
-        And stdout should contain "--namesdata arg"
-        And stdout should contain "--timestamp arg"
         And stdout should contain "--ip"
         And stdout should contain "--port"
         And stdout should contain "--threads"
@@ -57,7 +40,6 @@ Feature: osrm-routed command line options: help
         And stdout should contain "--max-trip-size"
         And stdout should contain "--max-table-size"
         And stdout should contain "--max-matching-size"
-        And stdout should contain 30 lines
         And it should exit with code 0
 
     Scenario: osrm-routed - Help, long
@@ -67,16 +49,8 @@ Feature: osrm-routed command line options: help
         And stdout should contain "Options:"
         And stdout should contain "--version"
         And stdout should contain "--help"
-        And stdout should contain "--config"
         And stdout should contain "--trial"
         And stdout should contain "Configuration:"
-        And stdout should contain "--hsgrdata arg"
-        And stdout should contain "--nodesdata arg"
-        And stdout should contain "--edgesdata arg"
-        And stdout should contain "--ramindex arg"
-        And stdout should contain "--fileindex arg"
-        And stdout should contain "--namesdata arg"
-        And stdout should contain "--timestamp arg"
         And stdout should contain "--ip"
         And stdout should contain "--port"
         And stdout should contain "--threads"
@@ -85,5 +59,4 @@ Feature: osrm-routed command line options: help
         And stdout should contain "--max-table-size"
         And stdout should contain "--max-table-size"
         And stdout should contain "--max-matching-size"
-        And stdout should contain 30 lines
         And it should exit with code 0
diff --git a/features/options/routed/invalid.feature b/features/options/routed/invalid.feature
index a6d62d7..f3d90ea 100644
--- a/features/options/routed/invalid.feature
+++ b/features/options/routed/invalid.feature
@@ -13,7 +13,6 @@ Feature: osrm-routed command line options: invalid options
 
     Scenario: osrm-routed - Missing file
         When I run "osrm-routed over-the-rainbow.osrm"
-        Then stdout should contain "over-the-rainbow.osrm"
-        And stderr should contain "exception"
+        Then stderr should contain "over-the-rainbow.osrm"
         And stderr should contain "not found"
         And it should exit with code 1
diff --git a/features/raster/weights.feature b/features/raster/weights.feature
index 1d521d0..ae782a7 100644
--- a/features/raster/weights.feature
+++ b/features/raster/weights.feature
@@ -28,51 +28,52 @@ Feature: Raster - weights
             0  0  0   250
             0  0  0   0
             """
+        And the data has been saved to disk
 
     Scenario: Weighting not based on raster sources
         Given the profile "testbot"
         When I run "osrm-extract {osm_base}.osm -p {profile}"
-        And I run "osrm-prepare {osm_base}.osm"
+        And I run "osrm-contract {osm_base}.osm"
         And I route I should get
-            | from | to | route | speed   |
-            | a    | b  | ab    | 36 km/h |
-            | a    | c  | ab,bc | 36 km/h |
-            | b    | c  | bc    | 36 km/h |
-            | a    | d  | ad    | 36 km/h |
-            | d    | c  | dc    | 36 km/h |
+            | from | to | route    | speed   |
+            | a    | b  | ab,ab    | 36 km/h |
+            | a    | c  | ab,bc,bc | 36 km/h |
+            | b    | c  | bc,bc    | 36 km/h |
+            | a    | d  | ad,ad    | 36 km/h |
+            | d    | c  | dc,dc    | 36 km/h |
 
     Scenario: Weighting based on raster sources
         Given the profile "rasterbot"
         When I run "osrm-extract {osm_base}.osm -p {profile}"
         Then stdout should contain "evaluating segment"
-        And I run "osrm-prepare {osm_base}.osm"
+        And I run "osrm-contract {osm_base}.osm"
         And I route I should get
-            | from | to | route | speed   |
-            | a    | b  | ab    | 8 km/h  |
-            | a    | c  | ad,dc | 15 km/h |
-            | b    | c  | bc    | 8 km/h  |
-            | a    | d  | ad    | 15 km/h |
-            | d    | c  | dc    | 15 km/h |
-            | d    | e  | de    | 10 km/h |
-            | e    | b  | eb    | 10 km/h |
-            | d    | f  | df    | 15 km/h |
-            | f    | b  | fb    | 7 km/h  |
-            | d    | b  | de,eb | 10 km/h |
+            | from | to | route    | speed   |
+            | a    | b  | ab,ab    | 8 km/h  |
+            | a    | c  | ad,dc,dc | 15 km/h |
+            | b    | c  | bc,bc    | 8 km/h  |
+            | a    | d  | ad,ad    | 15 km/h |
+            | d    | c  | dc,dc    | 15 km/h |
+            | d    | e  | de,de    | 10 km/h |
+            | e    | b  | eb,eb    | 10 km/h |
+            | d    | f  | df,df    | 15 km/h |
+            | f    | b  | fb,fb    | 7 km/h  |
+            | d    | b  | de,eb,eb | 10 km/h |
 
     Scenario: Weighting based on raster sources
-        Given the profile "rasterbot-interp"
+        Given the profile "rasterbotinterp"
         When I run "osrm-extract {osm_base}.osm -p {profile}"
         Then stdout should contain "evaluating segment"
-        And I run "osrm-prepare {osm_base}.osm"
+        And I run "osrm-contract {osm_base}.osm"
         And I route I should get
-            | from | to | route | speed   |
-            | a    | b  | ab    | 8 km/h  |
-            | a    | c  | ad,dc | 15 km/h |
-            | b    | c  | bc    | 8 km/h  |
-            | a    | d  | ad    | 15 km/h |
-            | d    | c  | dc    | 15 km/h |
-            | d    | e  | de    | 10 km/h |
-            | e    | b  | eb    | 10 km/h |
-            | d    | f  | df    | 15 km/h |
-            | f    | b  | fb    | 7 km/h  |
-            | d    | b  | de,eb | 10 km/h |
+            | from | to | route    | speed   |
+            | a    | b  | ab,ab    | 8 km/h  |
+            | a    | c  | ad,dc,dc | 15 km/h |
+            | b    | c  | bc,bc    | 8 km/h  |
+            | a    | d  | ad,ad    | 15 km/h |
+            | d    | c  | dc,dc    | 15 km/h |
+            | d    | e  | de,de    | 10 km/h |
+            | e    | b  | eb,eb    | 10 km/h |
+            | d    | f  | df,df    | 15 km/h |
+            | f    | b  | fb,fb    | 7 km/h  |
+            | d    | b  | de,eb,eb | 10 km/h |
diff --git a/features/step_definitions/data.js b/features/step_definitions/data.js
new file mode 100644
index 0000000..db0071c
--- /dev/null
+++ b/features/step_definitions/data.js
@@ -0,0 +1,273 @@
+var util = require('util');
+var path = require('path');
+var fs = require('fs');
+var d3 = require('d3-queue');
+var OSM = require('../support/build_osm');
+
+module.exports = function () {
+    this.Given(/^the profile "([^"]*)"$/, (profile, callback) => {
+        this.setProfile(profile, callback);
+    });
+
+    this.Given(/^the extract extra arguments "(.*?)"$/, (args, callback) => {
+        this.setExtractArgs(args);
+        callback();
+    });
+
+    this.Given(/^the contract extra arguments "(.*?)"$/, (args, callback) => {
+        this.setContractArgs(args);
+        callback();
+    });
+
+    this.Given(/^a grid size of (\d+) meters$/, (meters, callback) => {
+        this.setGridSize(meters);
+        callback();
+    });
+
+    this.Given(/^the origin ([-+]?[0-9]*\.?[0-9]+),([-+]?[0-9]*\.?[0-9]+)$/, (lat, lon, callback) => {
+        this.setOrigin([parseFloat(lon), parseFloat(lat)]);
+        callback();
+    });
+
+    this.Given(/^the shortcuts$/, (table, callback) => {
+        var q = d3.queue();
+
+        var addShortcut = (row, cb) => {
+            this.shortcutsHash[row.key] = row.value;
+            cb();
+        };
+
+        table.hashes().forEach((row) => {
+            q.defer(addShortcut, row);
+        });
+
+        q.awaitAll(callback);
+    });
+
+    this.Given(/^the node map$/, (table, callback) => {
+        var q = d3.queue();
+
+        var addNode = (name, ri, ci, cb) => {
+            if (name) {
+                if (name.length !== 1) throw new Error(util.format('*** node invalid name %s, must be single characters', name));
+                if (!name.match(/[a-z0-9]/)) throw new Error(util.format('*** invalid node name %s, must me alphanumeric', name));
+
+                var lonLat;
+                if (name.match(/[a-z]/)) {
+                    if (this.nameNodeHash[name]) throw new Error(util.format('*** duplicate node %s', name));
+                    lonLat = this.tableCoordToLonLat(ci, ri);
+                    this.addOSMNode(name, lonLat[0], lonLat[1], null);
+                } else {
+                    if (this.locationHash[name]) throw new Error(util.format('*** duplicate node %s'), name);
+                    lonLat = this.tableCoordToLonLat(ci, ri);
+                    this.addLocation(name, lonLat[0], lonLat[1], null);
+                }
+
+                cb();
+            }
+            else cb();
+        };
+
+        table.raw().forEach((row, ri) => {
+            row.forEach((name, ci) => {
+                q.defer(addNode, name, ri, ci);
+            });
+        });
+
+        q.awaitAll(callback);
+    });
+
+    this.Given(/^the node locations$/, (table, callback) => {
+        var q = d3.queue();
+
+        var addNodeLocations = (row, cb) => {
+            var name = row.node;
+            if (this.findNodeByName(name)) throw new Error(util.format('*** duplicate node %s'), name);
+
+            if (name.match(/[a-z]/)) {
+                var id = row.id && parseInt(row.id);
+                this.addOSMNode(name, row.lon, row.lat, id);
+            } else {
+                this.addLocation(name, row.lon, row.lat);
+            }
+
+            cb();
+        };
+
+        table.hashes().forEach((row) => q.defer(addNodeLocations, row));
+
+        q.awaitAll(callback);
+    });
+
+    this.Given(/^the nodes$/, (table, callback) => {
+        var q = d3.queue();
+
+        var addNode = (row, cb) => {
+            var name = row.node,
+                node = this.findNodeByName(name);
+            delete row.node;
+            if (!node) throw new Error(util.format('*** unknown node %s'), name);
+            for (var key in row) {
+                node.addTag(key, row[key]);
+            }
+            cb();
+        };
+
+        table.hashes().forEach((row) => q.defer(addNode, row));
+
+        q.awaitAll(callback);
+    });
+
+    this.Given(/^the ways$/, (table, callback) => {
+        if (this.osm_str) throw new Error('*** Map data already defined - did you pass an input file in this scenario?');
+
+        var q = d3.queue();
+
+        var addWay = (row, cb) => {
+            var way = new OSM.Way(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID);
+
+            var nodes = row.nodes;
+            if (this.nameWayHash.nodes) throw new Error(util.format('*** duplicate way %s', nodes));
+
+            for (var i=0; i<nodes.length; i++) {
+                var c = nodes[i];
+                if (!c.match(/[a-z]/)) throw new Error(util.format('*** ways can only use names a-z (%s)', c));
+                var node = this.findNodeByName(c);
+                if (!node) throw new Error(util.format('*** unknown node %s', c));
+                way.addNode(node);
+            }
+
+            var tags = {
+                highway: 'primary'
+            };
+
+            for (var key in row) {
+                tags[key] = row[key];
+            }
+
+            delete tags.nodes;
+
+            if (row.highway === '(nil)') delete tags.highway;
+
+            if (row.name === undefined)
+                tags.name = nodes;
+            else if (row.name === '""' || row.name === "''") // eslint-disable-line quotes
+                tags.name = '';
+            else if (row.name === '' || row.name === '(nil)')
+                delete tags.name;
+            else
+                tags.name = row.name;
+
+            way.setTags(tags);
+            this.OSMDB.addWay(way);
+            this.nameWayHash[nodes] = way;
+            cb();
+        };
+
+        table.hashes().forEach((row) => q.defer(addWay, row));
+
+        q.awaitAll(callback);
+    });
+
+    this.Given(/^the relations$/, (table, callback) => {
+        if (this.osm_str) throw new Error('*** Map data already defined - did you pass an input file in this scenario?');
+
+        var q = d3.queue();
+
+        var addRelation = (row, cb) => {
+            var relation = new OSM.Relation(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID);
+
+            for (var key in row) {
+                var isNode = key.match(/^node:(.*)/),
+                    isWay = key.match(/^way:(.*)/),
+                    isColonSeparated = key.match(/^(.*):(.*)/);
+                if (isNode) {
+                    row[key].split(',').map(function(v) { return v.trim(); }).forEach((nodeName) => {
+                        if (nodeName.length !== 1) throw new Error(util.format('*** invalid relation node member "%s"'), nodeName);
+                        var node = this.findNodeByName(nodeName);
+                        if (!node) throw new Error(util.format('*** unknown relation node member "%s"'), nodeName);
+                        relation.addMember('node', node.id, isNode[1]);
+                    });
+                } else if (isWay) {
+                    row[key].split(',').map(function(v) { return v.trim(); }).forEach((wayName) => {
+                        var way = this.findWayByName(wayName);
+                        if (!way) throw new Error(util.format('*** unknown relation way member "%s"'), wayName);
+                        relation.addMember('way', way.id, isWay[1]);
+                    });
+                } else if (isColonSeparated && isColonSeparated[1] !== 'restriction') {
+                    throw new Error(util.format('*** unknown relation member type "%s:%s", must be either "node" or "way"'), isColonSeparated[1], isColonSeparated[2]);
+                } else {
+                    relation.addTag(key, row[key]);
+                }
+            }
+            relation.uid = this.OSM_UID;
+
+            this.OSMDB.addRelation(relation);
+
+            cb();
+        };
+
+        table.hashes().forEach((row) => q.defer(addRelation, row));
+
+        q.awaitAll(callback);
+    });
+
+    this.Given(/^the input file ([^"]*)$/, (file, callback) => {
+        if (path.extname(file) !== '.osm') throw new Error('*** Input file must be in .osm format');
+        fs.readFile(file, 'utf8', (err, data) => {
+            if (!err) this.osm_str = data.toString();
+            callback(err);
+        });
+    });
+
+    this.Given(/^the raster source$/, (data, callback) => {
+        fs.writeFile(path.resolve(this.TEST_FOLDER, 'rastersource.asc'), data, callback);
+    });
+
+    this.Given(/^the speed file$/, (data, callback) => {
+        fs.writeFile(path.resolve(this.TEST_FOLDER, 'speeds.csv'), data, callback);
+    });
+
+    this.Given(/^the data has been saved to disk$/, (callback) => {
+        try {
+            this.reprocess(callback);
+        } catch(e) {
+            this.processError = e;
+            callback(e);
+        }
+    });
+
+    this.Given(/^the data has been extracted$/, (callback) => {
+        this.writeAndExtract((err) => {
+            if (err) this.processError = err;
+            callback();
+        });
+    });
+
+    this.Given(/^the data has been contracted$/, (callback) => {
+        this.reprocess((err) => {
+            if (err) this.processError = err;
+            callback();
+        });
+    });
+
+    this.Given(/^osrm\-routed is stopped$/, (callback) => {
+        this.OSRMLoader.shutdown((err) => {
+            if (err) this.processError = err;
+            callback();
+        });
+    });
+
+    this.Given(/^data is loaded directly/, () => {
+        this.loadMethod = 'directly';
+    });
+
+    this.Given(/^data is loaded with datastore$/, () => {
+        this.loadMethod = 'datastore';
+    });
+
+    this.Given(/^the HTTP method "([^"]*)"$/, (method, callback) => {
+        this.httpMethod = method;
+        callback();
+    });
+};
diff --git a/features/step_definitions/data.rb b/features/step_definitions/data.rb
deleted file mode 100644
index 3e4ccc9..0000000
--- a/features/step_definitions/data.rb
+++ /dev/null
@@ -1,192 +0,0 @@
-Given /^the profile "([^"]*)"$/ do |profile|
-  set_profile profile
-end
-
-Given(/^the import format "(.*?)"$/) do |format|
-  set_input_format format
-end
-
-Given /^the extract extra arguments "(.*?)"$/ do |args|
-    set_extract_args args
-end
-
-Given /^a grid size of (\d+) meters$/ do |meters|
-  set_grid_size meters
-end
-
-Given /^the origin ([-+]?[0-9]*\.?[0-9]+),([-+]?[0-9]*\.?[0-9]+)$/ do |lat,lon|
-  set_origin [lon.to_f,lat.to_f]
-end
-
-Given /^the shortcuts$/ do |table|
-  table.hashes.each do |row|
-    shortcuts_hash[ row['key'] ] = row['value']
-  end
-end
-
-Given /^the node map$/ do |table|
-  table.raw.each_with_index do |row,ri|
-    row.each_with_index do |name,ci|
-      unless name.empty?
-        raise "*** node invalid name '#{name}', must be single characters" unless name.size == 1
-        raise "*** invalid node name '#{name}', must me alphanumeric" unless name.match /[a-z0-9]/
-        if name.match /[a-z]/
-          raise "*** duplicate node '#{name}'" if name_node_hash[name]
-          add_osm_node name, *table_coord_to_lonlat(ci,ri), nil
-        else
-          raise "*** duplicate node '#{name}'" if location_hash[name]
-          add_location name, *table_coord_to_lonlat(ci,ri)
-        end
-      end
-    end
-  end
-end
-
-Given /^the node locations$/ do |table|
-  table.hashes.each do |row|
-    name = row['node']
-    raise "*** duplicate node '#{name}'" if find_node_by_name name
-    if name.match /[a-z]/
-      id = row['id']
-      id = id.to_i if id
-      add_osm_node name, row['lon'].to_f, row['lat'].to_f, id
-    else
-      add_location name, row['lon'].to_f, row['lat'].to_f
-    end
-  end
-end
-
-Given /^the nodes$/ do |table|
-  table.hashes.each do |row|
-    name = row.delete 'node'
-    node = find_node_by_name(name)
-    raise "*** unknown node '#{c}'" unless node
-    node << row
-  end
-end
-
-Given /^the ways$/ do |table|
-  raise "*** Map data already defined - did you pass an input file in this scenaria?" if @osm_str
-  table.hashes.each do |row|
-    way = OSM::Way.new make_osm_id, OSM_USER, OSM_TIMESTAMP
-    way.uid = OSM_UID
-
-    nodes = row.delete 'nodes'
-    raise "*** duplicate way '#{nodes}'" if name_way_hash[nodes]
-    nodes.each_char do |c|
-      raise "*** ways can only use names a-z, '#{name}'" unless c.match /[a-z]/
-      node = find_node_by_name(c)
-      raise "*** unknown node '#{c}'" unless node
-      way << node
-    end
-
-    defaults = { 'highway' => 'primary' }
-    tags = defaults.merge(row)
-
-    if row['highway'] == '(nil)'
-      tags.delete 'highway'
-    end
-
-    if row['name'] == nil
-      tags['name'] = nodes
-    elsif (row['name'] == '""') || (row['name'] == "''")
-      tags['name'] = ''
-    elsif row['name'] == '' || row['name'] == '(nil)'
-      tags.delete 'name'
-    else
-      tags['name'] = row['name']
-    end
-
-    way << tags
-    osm_db << way
-    name_way_hash[nodes] = way
-  end
-end
-
-Given /^the relations$/ do |table|
-  raise "*** Map data already defined - did you pass an input file in this scenaria?" if @osm_str
-  table.hashes.each do |row|
-    relation = OSM::Relation.new make_osm_id, OSM_USER, OSM_TIMESTAMP
-    row.each_pair do |key,value|
-      if key =~ /^node:(.*)/
-        value.split(',').map { |v| v.strip }.each do |node_name|
-          raise "***invalid relation node member '#{node_name}', must be single character" unless node_name.size == 1
-          node = find_node_by_name(node_name)
-          raise "*** unknown relation node member '#{node_name}'" unless node
-          relation << OSM::Member.new( 'node', node.id, $1 )
-        end
-      elsif key =~ /^way:(.*)/
-        value.split(',').map { |v| v.strip }.each do |way_name|
-          way = find_way_by_name(way_name)
-          raise "*** unknown relation way member '#{way_name}'" unless way
-          relation << OSM::Member.new( 'way', way.id, $1 )
-        end
-      elsif key =~ /^(.*):(.*)/ && "#{$1}" != 'restriction'
-        raise "*** unknown relation member type '#{$1}:#{$2}', must be either 'node' or 'way'"
-      else
-        relation << { key => value }
-      end
-    end
-    relation.uid = OSM_UID
-    osm_db << relation
-  end
-end
-
-Given /^the defaults$/ do
-end
-
-Given /^the input file ([^"]*)$/ do |file|
-  raise "*** Input file must in .osm format" unless File.extname(file)=='.osm'
-  @osm_str = File.read file
-end
-
-Given /^the raster source$/ do |data|
-  Dir.chdir TEST_FOLDER do
-    File.open("rastersource.asc", "w") {|f| f.write(data)}
-  end
-end
-
-Given /^the data has been saved to disk$/ do
-  begin
-    write_input_data
-  rescue OSRMError => e
-    @process_error = e
-  end
-end
-
-Given /^the data has been extracted$/ do
-  begin
-    write_input_data
-    extract_data unless extracted?
-  rescue OSRMError => e
-    @process_error = e
-  end
-end
-
-Given /^the data has been prepared$/ do
-  begin
-    reprocess
-  rescue OSRMError => e
-    @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
-
-Given /^the HTTP method "([^"]*)"$/ do |method|
-  @http_method = method
-end
diff --git a/features/step_definitions/distance_matrix.js b/features/step_definitions/distance_matrix.js
new file mode 100644
index 0000000..735847d
--- /dev/null
+++ b/features/step_definitions/distance_matrix.js
@@ -0,0 +1,81 @@
+var util = require('util');
+
+module.exports = function () {
+    this.When(/^I request a travel time matrix I should get$/, (table, callback) => {
+        var NO_ROUTE = 2147483647;    // MAX_INT
+
+        var tableRows = table.raw();
+
+        if (tableRows[0][0] !== '') throw new Error('*** Top-left cell of matrix table must be empty');
+
+        var waypoints = [],
+            columnHeaders = tableRows[0].slice(1),
+            rowHeaders = tableRows.map((h) => h[0]).slice(1),
+            symmetric = columnHeaders.every((ele, i) => ele === rowHeaders[i]);
+
+        if (symmetric) {
+            columnHeaders.forEach((nodeName) => {
+                var node = this.findNodeByName(nodeName);
+                if (!node) throw new Error(util.format('*** unknown node "%s"'), nodeName);
+                waypoints.push({ coord: node, type: 'loc' });
+            });
+        } else {
+            columnHeaders.forEach((nodeName) => {
+                var node = this.findNodeByName(nodeName);
+                if (!node) throw new Error(util.format('*** unknown node "%s"'), nodeName);
+                waypoints.push({ coord: node, type: 'dst' });
+            });
+            rowHeaders.forEach((nodeName) => {
+                var node = this.findNodeByName(nodeName);
+                if (!node) throw new Error(util.format('*** unknown node "%s"'), nodeName);
+                waypoints.push({ coord: node, type: 'src' });
+            });
+        }
+
+        var actual = [];
+        actual.push(table.headers);
+
+        this.reprocessAndLoadData(() => {
+            // compute matrix
+            var params = this.queryParams;
+
+            this.requestTable(waypoints, params, (err, response) => {
+                if (err) return callback(err);
+                if (!response.body.length) return callback(new Error('Invalid response body'));
+
+                var json = JSON.parse(response.body);
+
+                var result = json['durations'].map(row => {
+                    var hashes = {};
+                    row.forEach((v, i) => { hashes[tableRows[0][i+1]] = isNaN(parseInt(v)) ? '' : v; });
+                    return hashes;
+                });
+
+                var testRow = (row, ri, cb) => {
+                    var ok = true;
+
+                    for (var k in result[ri]) {
+                        if (this.FuzzyMatch.match(result[ri][k], row[k])) {
+                            result[ri][k] = row[k];
+                        } else if (row[k] === '' && result[ri][k] === NO_ROUTE) {
+                            result[ri][k] = '';
+                        } else {
+                            result[ri][k] = result[ri][k].toString();
+                            ok = false;
+                        }
+                    }
+
+                    if (!ok) {
+                        var failed = { attempt: 'distance_matrix', query: this.query, response: response };
+                        this.logFail(row, result[ri], [failed]);
+                    }
+
+                    result[ri][''] = row[''];
+                    cb(null, result[ri]);
+                };
+
+                this.processRowsAndDiff(table, testRow, callback);
+            });
+        });
+    });
+};
diff --git a/features/step_definitions/distance_matrix.rb b/features/step_definitions/distance_matrix.rb
deleted file mode 100644
index 2143d37..0000000
--- a/features/step_definitions/distance_matrix.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-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]==""
-  
-  waypoints = []
-  column_headers = table.headers[1..-1]
-  row_headers = table.rows.map { |h| h.first }
-  symmetric = Set.new(column_headers) == Set.new(row_headers)
-  if symmetric then
-    column_headers.each do |node_name|
-      node = find_node_by_name(node_name)
-      raise "*** unknown node '#{node_name}" unless node
-      waypoints << {:coord => node, :type => "loc"}
-    end
-  else
-    column_headers.each do |node_name|
-      node = find_node_by_name(node_name)
-      raise "*** unknown node '#{node_name}" unless node
-      waypoints << {:coord => node, :type => "dst"}
-    end
-    row_headers.each do |node_name|
-      node = find_node_by_name(node_name)
-      raise "*** unknown node '#{node_name}" unless node
-      waypoints << {:coord => node, :type => "src"}
-    end
-  end
-  
-  reprocess
-  actual = []
-  actual << table.headers
-  OSRMLoader.load(self,"#{prepared_file}.osrm") do
-    
-    # compute matrix
-    params = @query_params
-    response = request_table waypoints, params
-    if response.body.empty? == false
-      json_result = JSON.parse response.body
-      result = json_result["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(result[ri].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.diff! actual
-end
diff --git a/features/step_definitions/hooks.js b/features/step_definitions/hooks.js
new file mode 100644
index 0000000..07b4719
--- /dev/null
+++ b/features/step_definitions/hooks.js
@@ -0,0 +1,30 @@
+var util = require('util');
+
+module.exports = function () {
+    this.Before((scenario, callback) => {
+        this.scenarioTitle = scenario.getName();
+
+        this.loadMethod = this.DEFAULT_LOAD_METHOD;
+        this.queryParams = {};
+        var d = new Date();
+        this.scenarioTime = util.format('%d-%d-%dT%s:%s:%sZ', d.getFullYear(), d.getMonth()+1, d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds());
+        this.resetData();
+        this.hasLoggedPreprocessInfo = false;
+        this.hasLoggedScenarioInfo = false;
+        this.setGridSize(this.DEFAULT_GRID_SIZE);
+        this.setOrigin(this.DEFAULT_ORIGIN);
+        callback();
+    });
+
+    this.Before('@ignore-platform-windows', () => {
+        this.skipThisScenario();
+    });
+
+    this.Before('@ignore-platform-unix', () => {
+        this.skipThisScenario();
+    });
+
+    this.Before('@ignore-platform-mac', () => {
+        this.skipThisScenario();
+    });
+};
diff --git a/features/step_definitions/matching.js b/features/step_definitions/matching.js
new file mode 100644
index 0000000..1b770d7
--- /dev/null
+++ b/features/step_definitions/matching.js
@@ -0,0 +1,174 @@
+var util = require('util');
+var d3 = require('d3-queue');
+
+module.exports = function () {
+    this.When(/^I match I should get$/, (table, callback) => {
+        var got;
+
+        this.reprocessAndLoadData(() => {
+            var testRow = (row, ri, cb) => {
+                var afterRequest = (err, res) => {
+                    if (err) return cb(err);
+                    var json;
+
+                    var headers = new Set(table.raw()[0]);
+
+                    if (res.body.length) {
+                        json = JSON.parse(res.body);
+                    }
+
+                    if (headers.has('status')) {
+                        got.status = json.status.toString();
+                    }
+
+                    if (headers.has('message')) {
+                        got.message = json.status_message;
+                    }
+
+                    if (headers.has('#')) {
+                        // comment column
+                        got['#'] = row['#'];
+                    }
+
+                    var subMatchings = [],
+                        turns = '',
+                        route = '',
+                        duration = '';
+
+                    if (res.statusCode === 200) {
+                        if (headers.has('matchings')) {
+                            subMatchings = json.matchings.filter(m => !!m).map(sub => sub.matched_points);
+                        }
+
+                        if (headers.has('turns')) {
+                            if (json.matchings.length != 1) throw new Error('*** Checking turns only supported for matchings with one subtrace');
+                            turns = this.turnList(json.matchings[0].instructions);
+                        }
+
+                        if (headers.has('route')) {
+                            if (json.matchings.length != 1) throw new Error('*** Checking route only supported for matchings with one subtrace');
+                            route = this.wayList(json.matchings[0]);
+                        }
+
+                        if (headers.has('duration')) {
+                            if (json.matchings.length != 1) throw new Error('*** Checking duration only supported for matchings with one subtrace');
+                            duration = json.matchings[0].duration;
+                        }
+                    }
+
+                    if (headers.has('turns')) {
+                        got.turns = turns;
+                    }
+
+                    if (headers.has('route')) {
+                        got.route = route;
+                    }
+
+                    if (headers.has('duration')) {
+                        got.duration = duration.toString();
+                    }
+
+                    var ok = true;
+                    var encodedResult = '',
+                        extendedTarget = '';
+
+                    var q = d3.queue();
+
+                    var testSubMatching = (sub, si, scb) => {
+                        if (si >= subMatchings.length) {
+                            ok = false;
+                            q.abort();
+                            scb();
+                        } else {
+                            var sq = d3.queue();
+
+                            var testSubNode = (ni, ncb) => {
+                                var node = this.findNodeByName(sub[ni]),
+                                    outNode = subMatchings[si][ni];
+
+                                if (this.FuzzyMatch.matchLocation(outNode, node)) {
+                                    encodedResult += sub[ni];
+                                    extendedTarget += sub[ni];
+                                } else {
+                                    encodedResult += util.format('? [%s,%s]', outNode[0], outNode[1]);
+                                    extendedTarget += util.format('%s [%d,%d]', node.lat, node.lon);
+                                    ok = false;
+                                }
+                                ncb();
+                            };
+
+                            for (var i=0; i<sub.length; i++) {
+                                sq.defer(testSubNode, i);
+                            }
+
+                            sq.awaitAll(scb);
+                        }
+                    };
+
+                    row.matchings.split(',').forEach((sub, si) => {
+                        q.defer(testSubMatching, sub, si);
+                    });
+
+                    q.awaitAll(() => {
+                        if (ok) {
+                            if (headers.has('matchings')) {
+                                got.matchings = row.matchings;
+                            }
+
+                            if (headers.has('timestamps')) {
+                                got.timestamps = row.timestamps;
+                            }
+                        } else {
+                            got.matchings = encodedResult;
+                            row.matchings = extendedTarget;
+                            this.logFail(row, got, { matching: { query: this.query, response: res } });
+                        }
+
+                        cb(null, got);
+                    });
+                };
+
+                if (row.request) {
+                    got = {};
+                    got.request = row.request;
+                    this.requestUrl(row.request, afterRequest);
+                } else {
+                    var params = this.queryParams;
+                    got = {};
+                    for (var k in row) {
+                        var match = k.match(/param:(.*)/);
+                        if (match) {
+                            if (row[k] === '(nil)') {
+                                params[match[1]] = null;
+                            } else if (row[k]) {
+                                params[match[1]] = [row[k]];
+                            }
+                            got[k] = row[k];
+                        }
+                    }
+
+                    var trace = [],
+                        timestamps = [];
+
+                    if (row.trace) {
+                        for (var i=0; i<row.trace.length; i++) {
+                            var n = row.trace[i],
+                                node = this.findNodeByName(n);
+                            if (!node) throw new Error(util.format('*** unknown waypoint node "%s"'), n);
+                            trace.push(node);
+                        }
+                        if (row.timestamps) {
+                            timestamps = row.timestamps.split(' ').filter(s => !!s).map(t => parseInt(t, 10));
+                        }
+                        got.trace = row.trace;
+                        this.requestMatching(trace, timestamps, params, afterRequest);
+                    } else {
+                        throw new Error('*** no trace');
+                    }
+                }
+            };
+
+            this.processRowsAndDiff(table, testRow, callback);
+        });
+    });
+};
diff --git a/features/step_definitions/matching.rb b/features/step_definitions/matching.rb
deleted file mode 100644
index c490b46..0000000
--- a/features/step_definitions/matching.rb
+++ /dev/null
@@ -1,124 +0,0 @@
-When /^I match I should get$/ do |table|
-  reprocess
-  actual = []
-  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 = @query_params
-        got = {}
-        row.each_pair do |k,v|
-          if k =~ /param:(.*)/
-            if v=='(nil)'
-              params[$1]=nil
-            elsif v!=nil
-              params[$1]=[v]
-            end
-            got[k]=v
-          end
-        end
-        trace = []
-        timestamps = []
-        if row['trace']
-          row['trace'].each_char do |n|
-            node = find_node_by_name(n.strip)
-            raise "*** unknown waypoint node '#{n.strip}" unless node
-            trace << node
-          end
-          if row['timestamps']
-              timestamps = row['timestamps'].split(" ").compact.map { |t| t.to_i}
-          end
-          got = got.merge({'trace' => row['trace'] })
-          response = request_matching trace, timestamps, params
-        else
-          raise "*** no trace"
-        end
-      end
-
-      if response.body.empty? == false
-        json = JSON.parse response.body
-      end
-
-      if table.headers.include? 'status'
-        got['status'] = json['status'].to_s
-      end
-      if table.headers.include? 'message'
-        got['message'] = json['status_message']
-      end
-      if table.headers.include? '#'   # comment column
-        got['#'] = row['#']           # copy value so it always match
-      end
-
-      sub_matchings = []
-      turns = ''
-      route = ''
-      duration = ''
-      if response.code == "200"
-        if table.headers.include? 'matchings'
-          sub_matchings = json['matchings'].compact.map { |sub| sub['matched_points']}
-        end
-        if table.headers.include? 'turns'
-          raise "*** Checking turns only support for matchings with one subtrace" unless json['matchings'].size == 1
-          turns = turn_list json['matchings'][0]['instructions']
-        end
-        if table.headers.include? 'route'
-          raise "*** Checking route only support for matchings with one subtrace" unless json['matchings'].size == 1
-          route = way_list json['matchings'][0]['instructions']
-        if table.headers.include? 'duration'
-          raise "*** Checking duration only support for matchings with one subtrace" unless json['matchings'].size == 1
-          duration = json['matchings'][0]['route_summary']['total_time']
-        end
-        end
-      end
-
-      if table.headers.include? 'turns'
-        got['turns'] = turns
-      end
-      if table.headers.include? 'route'
-        got['route'] = route
-      end
-      if table.headers.include? 'duration'
-        got['duration'] = duration.to_s
-      end
-
-      ok = true
-      encoded_result = ""
-      extended_target = ""
-      row['matchings'].split(',').each_with_index do |sub, sub_idx|
-        if sub_idx >= sub_matchings.length
-          ok = false
-          break
-        end
-        sub.length.times do |node_idx|
-          node = find_node_by_name(sub[node_idx])
-          out_node = sub_matchings[sub_idx][node_idx]
-          if FuzzyMatch.match_location out_node, node
-            encoded_result += sub[node_idx]
-            extended_target += sub[node_idx]
-          else
-            encoded_result += "? [#{out_node[0]},#{out_node[1]}]"
-            extended_target += "#{sub[node_idx]} [#{node.lat},#{node.lon}]"
-            ok = false
-          end
-        end
-      end
-      if ok
-        if table.headers.include? 'matchings'
-          got['matchings'] = row['matchings']
-        end
-        if table.headers.include? 'timestamps'
-          got['timestamps'] = row['timestamps']
-        end
-      else
-        got['matchings'] = encoded_result
-        row['matchings'] = extended_target
-        log_fail row,got, { 'matching' => {:query => @query, :response => response} }
-      end
-
-      actual << got
-    end
-  end
-  table.diff! actual
-end
diff --git a/features/step_definitions/nearest.js b/features/step_definitions/nearest.js
new file mode 100644
index 0000000..300eefe
--- /dev/null
+++ b/features/step_definitions/nearest.js
@@ -0,0 +1,53 @@
+var util = require('util');
+
+module.exports = function () {
+    this.When(/^I request nearest I should get$/, (table, callback) => {
+        this.reprocessAndLoadData(() => {
+            var testRow = (row, ri, cb) => {
+                var inNode = this.findNodeByName(row.in);
+                if (!inNode) throw new Error(util.format('*** unknown in-node "%s"'), row.in);
+
+                var outNode = this.findNodeByName(row.out);
+                if (!outNode) throw new Error(util.format('*** unknown out-node "%s"'), row.out);
+
+                this.requestNearest(inNode, this.queryParams, (err, response) => {
+                    if (err) return cb(err);
+                    var coord;
+
+                    if (response.statusCode === 200 && response.body.length) {
+                        var json = JSON.parse(response.body);
+
+                        coord = json.waypoints[0].location;
+
+                        var got = { in: row.in, out: row.out };
+
+                        var ok = true;
+
+                        Object.keys(row).forEach((key) => {
+                            if (key === 'out') {
+                                if (this.FuzzyMatch.matchLocation(coord, outNode)) {
+                                    got[key] = row[key];
+                                } else {
+                                    row[key] = util.format('%s [%d,%d]', row[key], outNode.lat, outNode.lon);
+                                    ok = false;
+                                }
+                            }
+                        });
+
+                        if (!ok) {
+                            var failed = { attempt: 'nearest', query: this.query, response: response };
+                            this.logFail(row, got, [failed]);
+                        }
+
+                        cb(null, got);
+                    }
+                    else {
+                        cb();
+                    }
+                });
+            };
+
+            this.processRowsAndDiff(table, testRow, callback);
+        });
+    });
+};
diff --git a/features/step_definitions/nearest.rb b/features/step_definitions/nearest.rb
deleted file mode 100644
index b0b5f94..0000000
--- a/features/step_definitions/nearest.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-When /^I request nearest I should get$/ do |table|
-  reprocess
-  actual = []
-  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
-
-      out_node = find_node_by_name row['out']
-      raise "*** unknown out-node '#{row['out']}" unless out_node
-
-      response = request_nearest in_node, @query_params
-      if response.code == "200" && response.body.empty? == false
-        json = JSON.parse response.body
-        if json['status'] == 200
-          coord =  json['mapped_coordinate']
-        end
-      end
-
-      got = {'in' => row['in'], 'out' => coord }
-
-      ok = true
-      row.keys.each do |key|
-        if key=='out'
-          if FuzzyMatch.match_location coord, out_node
-            got[key] = row[key]
-          else
-            row[key] = "#{row[key]} [#{out_node.lat},#{out_node.lon}]"
-            ok = false
-          end
-        end
-      end
-
-      unless ok
-        failed = { :attempt => 'nearest', :query => @query, :response => response }
-        log_fail row,got,[failed]
-      end
-
-      actual << got
-    end
-  end
-  table.diff! actual
-end
-
-When /^I request nearest (\d+) times I should get$/ do |n,table|
-  ok = true
-  n.to_i.times do
-    ok = false unless step "I request nearest I should get", table
-  end
-  ok
-end
diff --git a/features/step_definitions/options.js b/features/step_definitions/options.js
new file mode 100644
index 0000000..27d6fd3
--- /dev/null
+++ b/features/step_definitions/options.js
@@ -0,0 +1,69 @@
+var assert = require('assert');
+
+module.exports = function () {
+    this.When(/^I run "osrm\-routed\s?(.*?)"$/, { timeout: this.SHUTDOWN_TIMEOUT }, (options, callback) => {
+        this.runBin('osrm-routed', options, () => {
+            callback();
+        });
+    });
+
+    this.When(/^I run "osrm\-extract\s?(.*?)"$/, (options, callback) => {
+        this.runBin('osrm-extract', options, () => {
+            callback();
+        });
+    });
+
+    this.When(/^I run "osrm\-contract\s?(.*?)"$/, (options, callback) => {
+        this.runBin('osrm-contract', options, () => {
+            callback();
+        });
+    });
+
+    this.When(/^I run "osrm\-datastore\s?(.*?)"$/, (options, callback) => {
+        this.runBin('osrm-datastore', options, () => {
+            callback();
+        });
+    });
+
+    this.Then(/^it should exit with code (\d+)$/, (code) => {
+        assert.equal(this.exitCode, parseInt(code));
+    });
+
+    this.Then(/^stdout should contain "(.*?)"$/, (str) => {
+        assert.ok(this.stdout.indexOf(str) > -1);
+    });
+
+    this.Then(/^stderr should contain "(.*?)"$/, (str) => {
+        assert.ok(this.stderr.indexOf(str) > -1);
+    });
+
+    this.Then(/^stdout should contain \/(.*)\/$/, (regexStr) => {
+        var re = new RegExp(regexStr);
+        assert.ok(this.stdout.match(re));
+    });
+
+    this.Then(/^stderr should contain \/(.*)\/$/, (regexStr) => {
+        var re = new RegExp(regexStr);
+        assert.ok(this.stdout.match(re));
+    });
+
+    this.Then(/^stdout should be empty$/, () => {
+        assert.equal(this.stdout.trim(), '');
+    });
+
+    this.Then(/^stderr should be empty$/, () => {
+        assert.equal(this.stderr.trim(), '');
+    });
+
+    this.Then(/^stdout should contain (\d+) lines?$/, (lines) => {
+        assert.equal(this.stdout.split('\n').length - 1, parseInt(lines));
+    });
+
+    this.Given(/^the query options$/, (table, callback) => {
+        table.raw().forEach(tuple => {
+            this.queryParams[tuple[0]] = tuple[1];
+        });
+
+        callback();
+    });
+};
diff --git a/features/step_definitions/options.rb b/features/step_definitions/options.rb
deleted file mode 100644
index 62329d5..0000000
--- a/features/step_definitions/options.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-When(/^I run "osrm\-routed\s?(.*?)"$/) do |options|
-  begin
-    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
-end
-
-When(/^I run "osrm\-extract\s?(.*?)"$/) do |options|
-  run_bin 'osrm-extract', options
-end
-
-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|
-  expect(@exit_code).to eq( code.to_i )
-end
-
-Then /^stdout should contain "(.*?)"$/ do |str|
-  expect(@stdout).to include(str)
-end
-
-Then /^stderr should contain "(.*?)"$/ do |str|
-  expect(@stderr).to include(str)
-end
-
-Then(/^stdout should contain \/(.*)\/$/) do |regex_str|
-  regex = Regexp.new regex_str
-  expect(@stdout).to match( regex )
-end
-
-Then(/^stderr should contain \/(.*)\/$/) do |regex_str|
-  regex = Regexp.new regex_str
-  expect(@stderr).to match( regex )
-end
-
-Then /^stdout should be empty$/ do
-  expect(@stdout).to eq("")
-end
-
-Then /^stderr should be empty$/ do
-  expect(@stderr).to eq("")
-end
-
-Then /^stdout should contain (\d+) lines?$/ do |lines|
-  expect(@stdout.lines.count).to eq( lines.to_i )
-end
-
-Given (/^the query options$/) do |table|
-  table.rows_hash.each { |k,v| @query_params << [k, v] }
-end
diff --git a/features/step_definitions/requests.js b/features/step_definitions/requests.js
new file mode 100644
index 0000000..dcaf5cc
--- /dev/null
+++ b/features/step_definitions/requests.js
@@ -0,0 +1,60 @@
+var assert = require('assert');
+
+module.exports = function () {
+    this.When(/^I request \/(.*)$/, (path, callback) => {
+        this.reprocessAndLoadData(() => {
+            this.requestPath(path, {}, (err, res, body) => {
+                this.response = res;
+                callback(err, res, body);
+            });
+        });
+    });
+
+    this.Then(/^I should get a response/, () => {
+        this.ShouldGetAResponse();
+    });
+
+    this.Then(/^response should be valid JSON$/, (callback) => {
+        this.ShouldBeValidJSON(callback);
+    });
+
+    this.Then(/^response should be well-formed$/, () => {
+        this.ShouldBeWellFormed();
+    });
+
+    this.Then(/^status code should be (\d+)$/, (code, callback) => {
+        try {
+            this.json = JSON.parse(this.response.body);
+        } catch(e) {
+            return callback(e);
+        }
+        assert.equal(this.json.status, parseInt(code));
+        callback();
+    });
+
+    this.Then(/^status message should be "(.*?)"$/, (message, callback) => {
+        try {
+            this.json = JSON.parse(this.response.body);
+        } catch(e) {
+            return callback(e);
+        }
+        assert(this.json.status_message, message);
+        callback();
+    });
+
+    this.Then(/^response should be a well-formed route$/, () => {
+        this.ShouldBeWellFormed();
+        assert.equal(typeof this.json.status_message, 'string');
+        assert.equal(typeof this.json.route_summary, 'object');
+        assert.equal(typeof this.json.route_geometry, 'string');
+        assert.ok(Array.isArray(this.json.route_instructions));
+        assert.ok(Array.isArray(this.json.via_points));
+        assert.ok(Array.isArray(this.json.via_indices));
+    });
+
+    this.Then(/^"([^"]*)" should return code (\d+)$/, (binary, code) => {
+        assert.ok(this.processError instanceof this.OSRMError);
+        assert.equal(this.processError.process, binary);
+        assert.equal(parseInt(this.processError.code), parseInt(code));
+    });
+};
diff --git a/features/step_definitions/requests.rb b/features/step_definitions/requests.rb
deleted file mode 100644
index 1c012d7..0000000
--- a/features/step_definitions/requests.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-When /^I request \/(.*)$/ do |path|
-  reprocess
-  OSRMLoader.load(self,"#{prepared_file}.osrm") do
-    @response = request_path path, []
-  end
-end
-
-Then /^I should get a response/ do
-  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
-  @json = JSON.parse @response.body
-end
-
-Then /^response should be well-formed$/ do
-  expect(@json['status'].class).to eq(Fixnum)
-end
-
-Then /^status code should be (\d+)$/ do |code|
-  @json = JSON.parse @response.body
-  expect(@json['status']).to eq(code.to_i)
-end
-
-Then /^status message should be "(.*?)"$/ do |message|
-  @json = JSON.parse @response.body
-  expect(@json['status_message']).to eq(message)
-end
-
-Then /^response should be a well-formed route$/ do
-  step "response should be well-formed"
-  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|
-  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.js b/features/step_definitions/routability.js
new file mode 100644
index 0000000..1ef8643
--- /dev/null
+++ b/features/step_definitions/routability.js
@@ -0,0 +1,120 @@
+var util = require('util');
+var d3 = require('d3-queue');
+var classes = require('../support/data_classes');
+
+module.exports = function () {
+    this.Then(/^routability should be$/, (table, callback) => {
+        this.buildWaysFromTable(table, () => {
+            var directions = ['forw','backw','bothw'],
+                headers = new Set(Object.keys(table.hashes()[0]));
+
+            if (!directions.some(k => !!headers.has(k))) {
+                throw new Error('*** routability table must contain either "forw", "backw" or "bothw" column');
+            }
+
+            this.reprocessAndLoadData(() => {
+                var testRow = (row, i, cb) => {
+                    var outputRow = row;
+
+                    testRoutabilityRow(i, (err, result) => {
+                        if (err) return cb(err);
+                        directions.filter(d => headers.has(d)).forEach((direction) => {
+                            var want = this.shortcutsHash[row[direction]] || row[direction];
+
+                            switch (true) {
+                            case '' === want:
+                            case 'x' === want:
+                                outputRow[direction] = result[direction].status ?
+                                    result[direction].status.toString() : '';
+                                break;
+                            case /^\d+s/.test(want):
+                                break;
+                            case /^\d+ km\/h/.test(want):
+                                break;
+                            default:
+                                throw new Error(util.format('*** Unknown expectation format: %s', want));
+                            }
+
+                            if (this.FuzzyMatch.match(outputRow[direction], want)) {
+                                outputRow[direction] = row[direction];
+                            }
+                        });
+
+                        if (outputRow != row) {
+                            this.logFail(row, outputRow, result);
+                        }
+
+                        cb(null, outputRow);
+                    });
+                };
+
+                this.processRowsAndDiff(table, testRow, callback);
+            });
+        });
+    });
+
+    var testRoutabilityRow = (i, cb) => {
+        var result = {};
+
+        var testDirection = (dir, callback) => {
+            var a = new classes.Location(this.origin[0] + (1+this.WAY_SPACING*i) * this.zoom, this.origin[1]),
+                b = new classes.Location(this.origin[0] + (3+this.WAY_SPACING*i) * this.zoom, this.origin[1]),
+                r = {};
+
+            r.which = dir;
+
+            this.requestRoute((dir === 'forw' ? [a, b] : [b, a]), [], this.queryParams, (err, res, body) => {
+                if (err) return callback(err);
+
+                r.query = this.query;
+                r.json = JSON.parse(body);
+                r.status = res.statusCode === 200 ? 'x' : null;
+                if (r.status) {
+                    r.route = this.wayList(r.json.routes[0]);
+
+                    if (r.route.split(',')[0] === util.format('w%d', i)) {
+                        r.time = r.json.routes[0].duration;
+                        r.distance = r.json.routes[0].distance;
+                        r.speed = r.time > 0 ? parseInt(3.6 * r.distance / r.time) : null;
+                    } else {
+                        r.status = null;
+                    }
+                }
+
+                callback(null, r);
+            });
+        };
+
+        d3.queue(1)
+            .defer(testDirection, 'forw')
+            .defer(testDirection, 'backw')
+            .awaitAll((err, res) => {
+                if (err) return cb(err);
+                // check if forw and backw returned the same values
+                res.forEach((dirRes) => {
+                    var which = dirRes.which;
+                    delete dirRes.which;
+                    result[which] = dirRes;
+                });
+
+                result.bothw = {};
+
+                var sq = d3.queue();
+
+                var parseRes = (key, scb) => {
+                    if (result.forw[key] === result.backw[key]) {
+                        result.bothw[key] = result.forw[key];
+                    } else {
+                        result.bothw[key] = 'diff';
+                    }
+                    scb();
+                };
+
+                ['status', 'time', 'distance', 'speed'].forEach((key) => {
+                    sq.defer(parseRes, key);
+                });
+
+                sq.awaitAll(() => { cb(null, result); });
+            });
+    };
+};
diff --git a/features/step_definitions/routability.rb b/features/step_definitions/routability.rb
deleted file mode 100644
index 6b5134c..0000000
--- a/features/step_definitions/routability.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-def test_routability_row i
-  result = {}
-  ['forw','backw'].each do |direction|
-    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]), [], @query_params
-    r[:query] = @query
-    r[:json] = JSON.parse(r[:response].body)
-
-    r[:status] = (route_status r[:response]) == 200 ? 'x' : nil
-    if r[:status] then
-      r[:route] = way_list r[:json]['route_instructions']
-
-      if r[:route]=="w#{i}"
-        r[:time] = r[:json]['route_summary']['total_time']
-        r[:distance] = r[:json]['route_summary']['total_distance']
-        r[:speed] = r[:time]>0 ? (3.6*r[:distance]/r[:time]).to_i : nil
-      else
-        # if we hit the wrong way segment, we assume it's
-        # because the one we tested was not unroutable
-        r[:status] = nil
-      end
-    end
-    result[direction] = r
-  end
-
-  # check if forw and backw returned the same values
-  result['bothw'] = {}
-  [:status,:time,:distance,:speed].each do |key|
-    if result['forw'][key] == result['backw'][key]
-      result['bothw'][key] = result['forw'][key]
-    else
-      result['bothw'][key] = 'diff'
-    end
-  end
-  result
-end
-
-Then /^routability should be$/ do |table|
-  build_ways_from_table table
-  reprocess
-  actual = []
-  if table.headers&["forw","backw","bothw"] == []
-    raise "*** routability tabel must contain either 'forw', 'backw' or 'bothw' column"
-  end
-  OSRMLoader.load(self,"#{prepared_file}.osrm") do
-    table.hashes.each_with_index do |row,i|
-      output_row = row.dup
-      attempts = []
-      result = test_routability_row i
-      directions = ['forw','backw','bothw']
-      (directions & table.headers).each do |direction|
-        want = shortcuts_hash[row[direction]] || row[direction]     #expand shortcuts
-        case want
-        when '', 'x'
-          output_row[direction] = result[direction][:status] ? result[direction][:status].to_s : ''
-        when /^\d+s/
-          output_row[direction] = result[direction][:time] ? "#{result[direction][:time]}s" : ''
-        when /^\d+ km\/h/
-          output_row[direction] = result[direction][:speed] ? "#{result[direction][:speed]} km/h" : ''
-        else
-          raise "*** Unknown expectation format: #{want}"
-        end
-
-        if FuzzyMatch.match output_row[direction], want
-          output_row[direction] = row[direction]
-        end
-      end
-
-      if output_row != row
-        log_fail row,output_row,result
-      end
-      actual << output_row
-    end
-  end
-  table.diff! actual
-end
diff --git a/features/step_definitions/routing.js b/features/step_definitions/routing.js
new file mode 100644
index 0000000..d48573e
--- /dev/null
+++ b/features/step_definitions/routing.js
@@ -0,0 +1,16 @@
+var d3 = require('d3-queue');
+
+module.exports = function () {
+    this.When(/^I route I should get$/, this.WhenIRouteIShouldGet);
+
+    // This is used to route 100 times; timeout for entire step is therefore set to 100 * STRESS_TIMEOUT
+    this.When(/^I route (\d+) times I should get$/, { timeout: 30000 }, (n, table, callback) => {
+        var q = d3.queue(1);
+
+        for (var i=0; i<n; i++) {
+            q.defer(this.WhenIRouteIShouldGet, table);
+        }
+
+        q.awaitAll(callback);
+    });
+};
diff --git a/features/step_definitions/routing.rb b/features/step_definitions/routing.rb
deleted file mode 100644
index f1e9590..0000000
--- a/features/step_definitions/routing.rb
+++ /dev/null
@@ -1,165 +0,0 @@
-When /^I route I should get$/ do |table|
-  reprocess
-  actual = []
-  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
-        default_params = @query_params
-        user_params = []
-        got = {}
-        row.each_pair do |k,v|
-          if k =~ /param:(.*)/
-            if v=='(nil)'
-              user_params << [$1, nil]
-            elsif v!=nil
-              user_params << [$1, v]
-            end
-            got[k]=v
-          end
-        end
-        params = overwrite_params default_params, user_params
-        waypoints = []
-        bearings = []
-        if row['bearings']
-          got['bearings'] = row['bearings']
-          bearings = row['bearings'].split(' ').compact
-        end
-        if row['from'] and row['to']
-          node = find_node_by_name(row['from'])
-          raise "*** unknown from-node '#{row['from']}" unless node
-          waypoints << node
-
-          node = find_node_by_name(row['to'])
-          raise "*** unknown to-node '#{row['to']}" unless node
-          waypoints << node
-
-          got = got.merge({'from' => row['from'], 'to' => row['to'] })
-          response = request_route waypoints, bearings, params
-        elsif row['waypoints']
-          row['waypoints'].split(',').each do |n|
-            node = find_node_by_name(n.strip)
-            raise "*** unknown waypoint node '#{n.strip}" unless node
-            waypoints << node
-          end
-          got = got.merge({'waypoints' => row['waypoints'] })
-          response = request_route waypoints, bearings, params
-        else
-          raise "*** no waypoints"
-        end
-      end
-
-      if response.body.empty? == false
-        json = JSON.parse response.body
-      end
-
-      if response.body.empty? == false
-        if json['status'] == 200
-          instructions = way_list json['route_instructions']
-          bearings = bearing_list json['route_instructions']
-          compasses = compass_list json['route_instructions']
-          turns = turn_list json['route_instructions']
-          modes = mode_list json['route_instructions']
-          times = time_list json['route_instructions']
-          distances = distance_list json['route_instructions']
-        end
-      end
-
-      if table.headers.include? 'status'
-        got['status'] = json['status'].to_s
-      end
-      if table.headers.include? 'message'
-        got['message'] = json['status_message']
-      end
-      if table.headers.include? '#'   # comment column
-        got['#'] = row['#']           # copy value so it always match
-      end
-
-      if table.headers.include? 'start'
-        got['start'] = instructions ? json['route_summary']['start_point'] : nil
-      end
-      if table.headers.include? 'end'
-        got['end'] = instructions ? json['route_summary']['end_point'] : nil
-      end
-      if table.headers.include? 'geometry'
-          got['geometry'] = json['route_geometry']
-      end
-      if table.headers.include? 'route'
-        got['route'] = (instructions || '').strip
-        if table.headers.include?('alternative')
-          got['alternative'] =
-            if json['found_alternative']
-              way_list json['alternative_instructions'].first
-            else
-              ""
-            end
-        end
-        if table.headers.include?('distance')
-          if row['distance']!=''
-            raise "*** Distance must be specied in meters. (ex: 250m)" unless row['distance'] =~ /\d+m/
-          end
-          got['distance'] = instructions ? "#{json['route_summary']['total_distance'].to_s}m" : ''
-        end
-        if table.headers.include?('time')
-          raise "*** Time must be specied in seconds. (ex: 60s)" unless row['time'] =~ /\d+s/
-          got['time'] = instructions ? "#{json['route_summary']['total_time'].to_s}s" : ''
-        end
-        if table.headers.include?('speed')
-          if row['speed'] != '' && instructions
-            raise "*** Speed must be specied in km/h. (ex: 50 km/h)" unless row['speed'] =~ /\d+ km\/h/
-              time = json['route_summary']['total_time']
-              distance = json['route_summary']['total_distance']
-              speed = time>0 ? (3.6*distance/time).round : nil
-              got['speed'] =  "#{speed} km/h"
-          else
-            got['speed'] = ''
-          end
-        end
-        if table.headers.include? 'bearing'
-          got['bearing'] = instructions ? bearings : ''
-        end
-        if table.headers.include? 'compass'
-          got['compass'] = instructions ? compasses : ''
-        end
-        if table.headers.include? 'turns'
-          got['turns'] = instructions ? turns : ''
-        end
-        if table.headers.include? 'modes'
-          got['modes'] = instructions ? modes : ''
-        end
-        if table.headers.include? 'times'
-          got['times'] = instructions ? times : ''
-        end
-        if table.headers.include? 'distances'
-          got['distances'] = instructions ? distances : ''
-        end
-      end
-
-      ok = true
-      row.keys.each do |key|
-        if FuzzyMatch.match got[key], row[key]
-          got[key] = row[key]
-        else
-          ok = false
-        end
-      end
-
-      unless ok
-        log_fail row,got, { 'route' => {:query => @query, :response => response} }
-      end
-
-      actual << got
-    end
-  end
-  table.diff! actual
-end
-
-When /^I route (\d+) times I should get$/ do |n,table|
-  ok = true
-  n.to_i.times do
-    ok = false unless step "I route I should get", table
-  end
-  ok
-end
diff --git a/features/step_definitions/timestamp.js b/features/step_definitions/timestamp.js
new file mode 100644
index 0000000..55af74b
--- /dev/null
+++ b/features/step_definitions/timestamp.js
@@ -0,0 +1,13 @@
+var assert = require('assert');
+
+module.exports = function () {
+    this.Then(/^I should get a valid timestamp/, (callback) => {
+        this.ShouldGetAResponse();
+        this.ShouldBeValidJSON((err) => {
+            this.ShouldBeWellFormed();
+            assert.equal(typeof this.json.timestamp, 'string');
+            assert.equal(this.json.timestamp, '2000-01-01T00:00:00Z');
+            callback(err);
+        });
+    });
+};
diff --git a/features/step_definitions/timestamp.rb b/features/step_definitions/timestamp.rb
deleted file mode 100644
index df45615..0000000
--- a/features/step_definitions/timestamp.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-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"
-  expect(@json['timestamp'].class).to eq(String)
-  expect(@json['timestamp']).to eq("2000-01-01T00:00:00Z")
-end
diff --git a/features/step_definitions/trip.js b/features/step_definitions/trip.js
new file mode 100644
index 0000000..b1727da
--- /dev/null
+++ b/features/step_definitions/trip.js
@@ -0,0 +1,141 @@
+var util = require('util');
+
+module.exports = function () {
+    this.When(/^I plan a trip I should get$/, (table, callback) => {
+        var got;
+
+        this.reprocessAndLoadData(() => {
+            var testRow = (row, ri, cb) => {
+                var afterRequest = (err, res) => {
+                    if (err) return cb(err);
+                    var headers = new Set(table.raw()[0]);
+
+                    for (var k in row) {
+                        var match = k.match(/param:(.*)/);
+                        if (match) {
+                            if (row[k] === '(nil)') {
+                                params[match[1]] = null;
+                            } else if (row[k]) {
+                                params[match[1]] = [row[k]];
+                            }
+
+                            got[k] = row[k];
+                        }
+                    }
+
+                    var json;
+                    if (res.body.length) {
+                        json = JSON.parse(res.body);
+                    }
+
+                    if (headers.has('status')) {
+                        got.status = json.status.toString();
+                    }
+
+                    if (headers.has('message')) {
+                        got.message = json.status_message;
+                    }
+
+                    if (headers.has('#')) {
+                        // comment column
+                        got['#'] = row['#'];
+                    }
+
+                    var subTrips;
+                    if (res.statusCode === 200) {
+                        if (headers.has('trips')) {
+                            subTrips = json.trips.filter(t => !!t).map(t => t.legs).map(tl => Array.prototype.concat.apply([], tl.map((sl, i) => {
+                                var toAdd = [];
+                                if (i === 0) toAdd.push(sl.steps[0].maneuver.location);
+                                toAdd.push(sl.steps[sl.steps.length-1].maneuver.location);
+                                return toAdd;
+                            })));
+                        }
+                    }
+
+                    var ok = true,
+                        encodedResult = '',
+                        extendedTarget = '';
+
+                    row.trips.split(',').forEach((sub, si) => {
+                        if (si >= subTrips.length) {
+                            ok = false;
+                        } else {
+                            ok = false;
+                            // TODO: Check all rotations of the round trip
+                            for (var ni=0; ni<sub.length; ni++) {
+                                var node = this.findNodeByName(sub[ni]),
+                                    outNode = subTrips[si][ni];
+                                if (this.FuzzyMatch.matchLocation(outNode, node)) {
+                                    encodedResult += sub[ni];
+                                    extendedTarget += sub[ni];
+                                    ok = true;
+                                } else {
+                                    encodedResult += util.format('? [%s,%s]', outNode[0], outNode[1]);
+                                    extendedTarget += util.format('%s [%d,%d]', sub[ni], node.lat, node.lon);
+                                }
+                            }
+                        }
+                    });
+
+                    if (ok) {
+                        got.trips = row.trips;
+                        got.via_points = row.via_points;
+                    } else {
+                        got.trips = encodedResult;
+                        got.trips = extendedTarget;
+                        this.logFail(row, got, { trip: { query: this.query, response: res }});
+                    }
+
+                    ok = true;
+
+                    for (var key in row) {
+                        if (this.FuzzyMatch.match(got[key], row[key])) {
+                            got[key] = row[key];
+                        } else {
+                            ok = false;
+                        }
+                    }
+
+                    if (!ok) {
+                        this.logFail(row, got, { trip: { query: this.query, response: res }});
+                    }
+
+                    cb(null, got);
+                };
+
+                if (row.request) {
+                    got.request = row.request;
+                    this.requestUrl(row.request, afterRequest);
+                } else {
+                    var params = this.queryParams,
+                        waypoints = [];
+                    if (row.from && row.to) {
+                        var fromNode = this.findNodeByName(row.from);
+                        if (!fromNode) throw new Error(util.format('*** unknown from-node "%s"', row.from));
+                        waypoints.push(fromNode);
+
+                        var toNode = this.findNodeByName(row.to);
+                        if (!toNode) throw new Error(util.format('*** unknown to-node "%s"', row.to));
+                        waypoints.push(toNode);
+
+                        got = { from: row.from, to: row.to };
+                        this.requestTrip(waypoints, params, afterRequest);
+                    } else if (row.waypoints) {
+                        row.waypoints.split(',').forEach((n) => {
+                            var node = this.findNodeByName(n);
+                            if (!node) throw new Error(util.format('*** unknown waypoint node "%s"', n.trim()));
+                            waypoints.push(node);
+                        });
+                        got = { waypoints: row.waypoints };
+                        this.requestTrip(waypoints, params, afterRequest);
+                    } else {
+                        throw new Error('*** no waypoints');
+                    }
+                }
+            };
+
+            this.processRowsAndDiff(table, testRow, callback);
+        });
+    });
+};
diff --git a/features/step_definitions/trip.rb b/features/step_definitions/trip.rb
deleted file mode 100644
index ecb4c77..0000000
--- a/features/step_definitions/trip.rb
+++ /dev/null
@@ -1,121 +0,0 @@
-When /^I plan a trip I should get$/ do |table|
-  reprocess
-  actual = []
-  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 = @query_params
-        waypoints = []
-        if row['from'] and row['to']
-          node = find_node_by_name(row['from'])
-          raise "*** unknown from-node '#{row['from']}" unless node
-          waypoints << node
-
-          node = find_node_by_name(row['to'])
-          raise "*** unknown to-node '#{row['to']}" unless node
-          waypoints << node
-
-          got = {'from' => row['from'], 'to' => row['to'] }
-          response = request_trip waypoints, params
-        elsif row['waypoints']
-          row['waypoints'].split(',').each do |n|
-            node = find_node_by_name(n.strip)
-            raise "*** unknown waypoint node '#{n.strip}" unless node
-            waypoints << node
-          end
-          got = {'waypoints' => row['waypoints'] }
-          response = request_trip waypoints, params
-        else
-          raise "*** no waypoints"
-        end
-      end
-
-      row.each_pair do |k,v|
-        if k =~ /param:(.*)/
-          if v=='(nil)'
-            params[$1]=nil
-          elsif v!=nil
-            params[$1]=[v]
-          end
-          got[k]=v
-        end
-      end
-
-      if response.body.empty? == false
-        json = JSON.parse response.body
-      end
-
-      if table.headers.include? 'status'
-        got['status'] = json['status'].to_s
-      end
-      if table.headers.include? 'message'
-        got['message'] = json['status_message']
-      end
-      if table.headers.include? '#'   # comment column
-        got['#'] = row['#']           # copy value so it always match
-      end
-
-      if response.code == "200"
-        if table.headers.include? 'trips'
-          sub_trips = json['trips'].compact.map { |sub| sub['via_points']}
-        end
-      end
-
-      ######################
-      ok = true
-      encoded_result = ""
-      extended_target = ""
-      row['trips'].split(',').each_with_index do |sub, sub_idx|
-        if sub_idx >= sub_trips.length
-          ok = false
-          break
-        end
-
-        ok = false;
-        #TODO: Check all rotations of the round trip
-        sub.length.times do |node_idx|
-          node = find_node_by_name(sub[node_idx])
-          out_node = sub_trips[sub_idx][node_idx]
-          if FuzzyMatch.match_location out_node, node
-            encoded_result += sub[node_idx]
-            extended_target += sub[node_idx]
-            ok = true
-          else
-            encoded_result += "? [#{out_node[0]},#{out_node[1]}]"
-            extended_target += "#{sub[node_idx]} [#{node.lat},#{node.lon}]"
-          end
-        end
-      end
-
-      if ok
-        got['trips'] = row['trips']
-        got['via_points'] = row['via_points']
-      else
-        got['trips'] = encoded_result
-        row['trips'] = extended_target
-        log_fail row,got, { 'trip' => {:query => @query, :response => response} }
-      end
-
-
-      ok = true
-      row.keys.each do |key|
-        if FuzzyMatch.match got[key], row[key]
-          got[key] = row[key]
-        else
-          ok = false
-        end
-      end
-
-      unless ok
-        log_fail row,got, { 'trip' => {:query => @query, :response => response} }
-      end
-
-      actual << got
-    end
-  end
-  table.diff! actual
-end
-
diff --git a/features/support/build_osm.js b/features/support/build_osm.js
new file mode 100644
index 0000000..7fe6874
--- /dev/null
+++ b/features/support/build_osm.js
@@ -0,0 +1,165 @@
+'use strict';
+
+var builder = require('xmlbuilder');
+
+var ensureDecimal = (i) => {
+    if (parseInt(i) === i) return i.toFixed(1);
+    else return i;
+};
+
+class DB {
+    constructor () {
+        this.nodes = new Array();
+        this.ways = new Array();
+        this.relations = new Array();
+    }
+
+    addNode (node) {
+        this.nodes.push(node);
+    }
+
+    addWay (way) {
+        this.ways.push(way);
+    }
+
+    addRelation (relation) {
+        this.relations.push(relation);
+    }
+
+    clear () {
+        this.nodes = [];
+        this.ways = [];
+        this.relations = [];
+    }
+
+    toXML (callback) {
+        var xml = builder.create('osm', {'encoding':'UTF-8'});
+        xml.att('generator', 'osrm-test')
+            .att('version', '0.6');
+
+        this.nodes.forEach((n) => {
+            var node = xml.ele('node', {
+                id: n.id,
+                version: 1,
+                uid: n.OSM_UID,
+                user: n.OSM_USER,
+                timestamp: n.OSM_TIMESTAMP,
+                lon: ensureDecimal(n.lon),
+                lat: ensureDecimal(n.lat)
+            });
+
+            for (var k in n.tags) {
+                node.ele('tag')
+                    .att('k', k)
+                    .att('v', n.tags[k]);
+            }
+        });
+
+        this.ways.forEach((w) => {
+            var way = xml.ele('way', {
+                id: w.id,
+                version: 1,
+                uid: w.OSM_UID,
+                user: w.OSM_USER,
+                timestamp: w.OSM_TIMESTAMP
+            });
+
+            w.nodes.forEach((k) => {
+                way.ele('nd')
+                    .att('ref', k.id);
+            });
+
+            for (var k in w.tags) {
+                way.ele('tag')
+                    .att('k', k)
+                    .att('v', w.tags[k]);
+            }
+        });
+
+        this.relations.forEach((r) => {
+            var relation = xml.ele('relation', {
+                id: r.id,
+                user: r.OSM_USER,
+                timestamp: r.OSM_TIMESTAMP,
+                uid: r.OSM_UID
+            });
+
+            r.members.forEach((m) => {
+                relation.ele('member', {
+                    type: m.type,
+                    ref: m.id,
+                    role: m.role
+                });
+            });
+
+            for (var k in r.tags) {
+                relation.ele('tag')
+                    .att('k', k)
+                    .att('v', r.tags[k]);
+            }
+        });
+
+        callback(xml.end({ pretty: true, indent: '  ' }));
+    }
+}
+
+class Node {
+    constructor (id, OSM_USER, OSM_TIMESTAMP, OSM_UID, lon, lat, tags) {
+        this.id = id;
+        this.OSM_USER = OSM_USER;
+        this.OSM_TIMESTAMP = OSM_TIMESTAMP;
+        this.OSM_UID = OSM_UID;
+        this.lon = lon;
+        this.lat = lat;
+        this.tags = tags;
+    }
+
+    addTag (k, v) {
+        this.tags[k] = v;
+    }
+}
+
+class Way {
+    constructor (id, OSM_USER, OSM_TIMESTAMP, OSM_UID) {
+        this.id = id;
+        this.OSM_USER = OSM_USER;
+        this.OSM_TIMESTAMP = OSM_TIMESTAMP;
+        this.OSM_UID = OSM_UID;
+        this.tags = {};
+        this.nodes = [];
+    }
+
+    addNode (node) {
+        this.nodes.push(node);
+    }
+
+    setTags (tags) {
+        this.tags = tags;
+    }
+}
+
+class Relation {
+    constructor (id, OSM_USER, OSM_TIMESTAMP, OSM_UID) {
+        this.id = id;
+        this.OSM_USER = OSM_USER;
+        this.OSM_TIMESTAMP = OSM_TIMESTAMP;
+        this.OSM_UID = OSM_UID;
+        this.members = [];
+        this.tags = {};
+    }
+
+    addMember (memberType, id, role) {
+        this.members.push({type: memberType, id: id, role: role});
+    }
+
+    addTag (k, v) {
+        this.tags[k] = v;
+    }
+}
+
+module.exports = {
+    DB: DB,
+    Node: Node,
+    Way: Way,
+    Relation: Relation
+};
diff --git a/features/support/config.js b/features/support/config.js
new file mode 100644
index 0000000..cae7398
--- /dev/null
+++ b/features/support/config.js
@@ -0,0 +1,115 @@
+var fs = require('fs');
+var path = require('path');
+var util = require('util');
+var d3 = require('d3-queue');
+var OSM = require('./build_osm');
+var classes = require('./data_classes');
+
+module.exports = function () {
+    this.initializeOptions = (callback) => {
+        this.profile = this.profile || this.DEFAULT_SPEEDPROFILE;
+
+        this.OSMDB = this.OSMDB || new OSM.DB();
+
+        this.nameNodeHash = this.nameNodeHash || {};
+
+        this.locationHash = this.locationHash || {};
+
+        this.nameWayHash = this.nameWayHash || {};
+
+        this.osmData = new classes.osmData(this);
+
+        this.STRESS_TIMEOUT = 300;
+
+        this.OSRMLoader = this._OSRMLoader();
+
+        this.PREPROCESS_LOG_FILE = path.resolve(this.TEST_FOLDER, 'preprocessing.log');
+
+        this.LOG_FILE = path.resolve(this.TEST_FOLDER, 'fail.log');
+
+        this.HOST = 'http://127.0.0.1:' + this.OSRM_PORT;
+
+        this.DESTINATION_REACHED = 15;  // OSRM instruction code
+
+        this.shortcutsHash = this.shortcutsHash || {};
+
+        var hashLuaLib = (cb) => {
+            fs.readdir(path.normalize(this.PROFILES_PATH + '/lib/'), (err, files) => {
+                if (err) cb(err);
+                var luaFiles = files.filter(f => !!f.match(/\.lua$/)).map(f => path.normalize(this.PROFILES_PATH + '/lib/' + f));
+                this.hashOfFiles(luaFiles, hash => {
+                    this.luaLibHash = hash;
+                    cb();
+                });
+            });
+        };
+
+        var hashProfile = (cb) => {
+            this.hashProfile((hash) => {
+                this.profileHash = hash;
+                cb();
+            });
+        };
+
+        var hashExtract = (cb) => {
+            this.hashOfFiles(util.format('%s/osrm-extract%s', this.BIN_PATH, this.EXE), (hash) => {
+                this.binExtractHash = hash;
+                cb();
+            });
+        };
+
+        var hashContract = (cb) => {
+            this.hashOfFiles(util.format('%s/osrm-contract%s', this.BIN_PATH, this.EXE), (hash) => {
+                this.binContractHash = hash;
+                this.fingerprintContract = this.hashString(this.binContractHash);
+                cb();
+            });
+        };
+
+        var hashRouted = (cb) => {
+            this.hashOfFiles(util.format('%s/osrm-routed%s', this.BIN_PATH, this.EXE), (hash) => {
+                this.binRoutedHash = hash;
+                this.fingerprintRoute = this.hashString(this.binRoutedHash);
+                cb();
+            });
+        };
+
+        d3.queue()
+            .defer(hashLuaLib)
+            .defer(hashProfile)
+            .defer(hashExtract)
+            .defer(hashContract)
+            .defer(hashRouted)
+            .awaitAll(() => {
+                this.fingerprintExtract = this.hashString([this.profileHash, this.luaLibHash, this.binExtractHash].join('-'));
+                this.AfterConfiguration(() => {
+                    callback();
+                });
+            });
+    };
+
+    this.setProfileBasedHashes = () => {
+        this.fingerprintExtract = this.hashString([this.profileHash, this.luaLibHash, this.binExtractHash].join('-'));
+        this.fingerprintContract = this.hashString(this.binContractHash);
+    };
+
+    this.setProfile = (profile, cb) => {
+        var lastProfile = this.profile;
+        if (profile !== lastProfile) {
+            this.profile = profile;
+            this.hashProfile((hash) => {
+                this.profileHash = hash;
+                this.setProfileBasedHashes();
+                cb();
+            });
+        } else cb();
+    };
+
+    this.setExtractArgs = (args) => {
+        this.extractArgs = args;
+    };
+
+    this.setContractArgs = (args) => {
+        this.contractArgs = args;
+    };
+};
diff --git a/features/support/config.rb b/features/support/config.rb
deleted file mode 100644
index 434b4ec..0000000
--- a/features/support/config.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-def profile
-  @profile ||= reset_profile
-end
-
-def reset_profile
-  @profile = nil
-  set_profile DEFAULT_SPEEDPROFILE
-end
-
-def set_profile profile
-  @profile = profile
-end
-
-def set_extract_args args
-    @extract_args = args
-end
diff --git a/features/support/data.js b/features/support/data.js
new file mode 100644
index 0000000..29e5170
--- /dev/null
+++ b/features/support/data.js
@@ -0,0 +1,340 @@
+var fs = require('fs');
+var path = require('path');
+var util = require('util');
+var exec = require('child_process').exec;
+var d3 = require('d3-queue');
+
+var OSM = require('./build_osm');
+var classes = require('./data_classes');
+
+module.exports = function () {
+    this.setGridSize = (meters) => {
+        // the constant is calculated (with BigDecimal as: 1.0/(DEG_TO_RAD*EARTH_RADIUS_IN_METERS
+        // see ApproximateDistance() in ExtractorStructs.h
+        // it's only accurate when measuring along the equator, or going exactly north-south
+        this.zoom = parseFloat(meters) * 0.8990679362704610899694577444566908445396483347536032203503E-5;
+    };
+
+    this.setOrigin = (origin) => {
+        this.origin = origin;
+    };
+
+    this.buildWaysFromTable = (table, callback) => {
+        // add one unconnected way for each row
+        var buildRow = (row, ri, cb) => {
+            // comments ported directly from ruby suite:
+            // NOTE: currently osrm crashes when processing an isolated oneway with just 2 nodes, so we use 4 edges
+            // this is related to the fact that a oneway dead-end street doesn't make a lot of sense
+
+            // if we stack ways on different x coordinates, routability tests get messed up, because osrm might pick a neighboring way if the one test can't be used.
+            // instead we place all lines as a string on the same y coordinate. this prevents using neighboring ways.
+
+            // add some nodes
+
+            var makeFakeNode = (namePrefix, offset) => {
+                return new OSM.Node(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP,
+                    this.OSM_UID, this.origin[0]+(offset + this.WAY_SPACING * ri) * this.zoom,
+                    this.origin[1], {name: util.format('%s%d', namePrefix, ri)});
+            };
+
+            var nodes = ['a','b','c','d','e'].map((l, i) => makeFakeNode(l, i));
+
+            nodes.forEach(node => { this.OSMDB.addNode(node); });
+
+            // ...with a way between them
+            var way = new OSM.Way(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID);
+
+            nodes.forEach(node => { way.addNode(node); });
+
+            // remove tags that describe expected test result, reject empty tags
+            var tags = {};
+            for (var rkey in row) {
+                if (!rkey.match(/^forw\b/) &&
+                    !rkey.match(/^backw\b/) &&
+                    !rkey.match(/^bothw\b/) &&
+                    row[rkey].length)
+                    tags[rkey] = row[rkey];
+            }
+
+            var wayTags = { highway: 'primary' },
+                nodeTags = {};
+
+            for (var key in tags) {
+                var nodeMatch = key.match(/node\/(.*)/);
+                if (nodeMatch) {
+                    if (tags[key] === '(nil)') {
+                        delete nodeTags[key];
+                    } else {
+                        nodeTags[nodeMatch[1]] = tags[key];
+                    }
+                } else {
+                    if (tags[key] === '(nil)') {
+                        delete wayTags[key];
+                    } else {
+                        wayTags[key] = tags[key];
+                    }
+                }
+            }
+
+            wayTags.name = util.format('w%d', ri);
+            way.setTags(wayTags);
+            this.OSMDB.addWay(way);
+
+            for (var k in nodeTags) {
+                nodes[2].addTag(k, nodeTags[k]);
+            }
+            cb();
+        };
+
+        var q = d3.queue();
+        table.hashes().forEach((row, ri) => {
+            q.defer(buildRow, row, ri);
+        });
+
+        q.awaitAll(callback);
+    };
+
+    this.ensureDecimal = (i) => {
+        if (parseInt(i) === i) return i.toFixed(1);
+        else return i;
+    };
+
+    this.tableCoordToLonLat = (ci, ri) => {
+        return [this.origin[0] + ci * this.zoom, this.origin[1] - ri * this.zoom].map(this.ensureDecimal);
+    };
+
+    this.addOSMNode = (name, lon, lat, id) => {
+        id = id || this.makeOSMId();
+        var node = new OSM.Node(id, this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID, lon, lat, {name: name});
+        this.OSMDB.addNode(node);
+        this.nameNodeHash[name] = node;
+    };
+
+    this.addLocation = (name, lon, lat) => {
+        this.locationHash[name] = new classes.Location(lon, lat);
+    };
+
+    this.findNodeByName = (s) => {
+        if (s.length !== 1) throw new Error(util.format('*** invalid node name "%s", must be single characters', s));
+        if (!s.match(/[a-z0-9]/)) throw new Error(util.format('*** invalid node name "%s", must be alphanumeric', s));
+
+        var fromNode;
+        if (s.match(/[a-z]/)) {
+            fromNode = this.nameNodeHash[s.toString()];
+        } else {
+            fromNode = this.locationHash[s.toString()];
+        }
+
+        return fromNode;
+    };
+
+    this.findWayByName = (s) => {
+        return this.nameWayHash[s.toString()] || this.nameWayHash[s.toString().split('').reverse().join('')];
+    };
+
+    this.resetData = () => {
+        this.resetOSM();
+    };
+
+    this.makeOSMId = () => {
+        this.osmID = this.osmID + 1;
+        return this.osmID;
+    };
+
+    this.resetOSM = () => {
+        this.OSMDB.clear();
+        this.osmData.reset();
+        this.nameNodeHash = {};
+        this.locationHash = {};
+        this.nameWayHash = {};
+        this.osmID = 0;
+    };
+
+    this.writeOSM = (callback) => {
+        fs.exists(this.DATA_FOLDER, (exists) => {
+            var mkDirFn = exists ? (cb) => { cb(); } : fs.mkdir.bind(fs.mkdir, this.DATA_FOLDER);
+            mkDirFn((err) => {
+                if (err) return callback(err);
+                var osmPath = path.resolve(this.DATA_FOLDER, util.format('%s.osm', this.osmData.osmFile));
+                fs.exists(osmPath, (exists) => {
+                    if (!exists) fs.writeFile(osmPath, this.osmData.str, callback);
+                    else callback();
+                });
+            });
+        });
+    };
+
+    this.isExtracted = (callback) => {
+        fs.exists(util.format('%s.osrm', this.osmData.extractedFile), (core) => {
+            if (!core) return callback(false);
+            fs.exists(util.format('%s.osrm.names', this.osmData.extractedFile), (names) => {
+                if (!names) return callback(false);
+                fs.exists(util.format('%s.osrm.restrictions', this.osmData.extractedFile), (restrictions) => {
+                    return callback(restrictions);
+                });
+            });
+        });
+    };
+
+    this.isContracted = (callback) => {
+        fs.exists(util.format('%s.osrm.hsgr', this.osmData.contractedFile), callback);
+    };
+
+    this.writeTimestamp = (callback) => {
+        fs.writeFile(util.format('%s.osrm.timestamp', this.osmData.contractedFile), this.OSM_TIMESTAMP, callback);
+    };
+
+    this.writeInputData = (callback) => {
+        this.writeOSM((err) => {
+            if (err) return callback(err);
+            this.writeTimestamp(callback);
+        });
+    };
+
+    this.extractData = (callback) => {
+        this.logPreprocessInfo();
+        this.log(util.format('== Extracting %s.osm...', this.osmData.osmFile), 'preprocess');
+        var cmd = util.format('%s%s/osrm-extract %s.osm %s --profile %s/%s.lua >>%s 2>&1',
+            this.LOAD_LIBRARIES, this.BIN_PATH, this.osmData.osmFile, this.extractArgs || '', this.PROFILES_PATH, this.profile, this.PREPROCESS_LOG_FILE);
+        this.log(cmd);
+        process.chdir(this.TEST_FOLDER);
+        exec(cmd, (err) => {
+            if (err) {
+                this.log(util.format('*** Exited with code %d', err.code), 'preprocess');
+                process.chdir('../');
+                return callback(this.ExtractError(err.code, util.format('osrm-extract exited with code %d', err.code)));
+            }
+
+            var q = d3.queue();
+
+            var rename = (file, cb) => {
+                this.log(util.format('Renaming %s.%s to %s.%s', this.osmData.osmFile, file, this.osmData.extractedFile, file), 'preprocess');
+                fs.rename([this.osmData.osmFile, file].join('.'), [this.osmData.extractedFile, file].join('.'), (err) => {
+                    if (err) return cb(this.FileError(null, 'failed to rename data file after extracting'));
+                    cb();
+                });
+            };
+
+            var renameIfExists = (file, cb) => {
+                fs.stat([this.osmData.osmFile, file].join('.'), (doesNotExistErr, exists) => {
+                    if (exists) rename(file, cb);
+                    else cb();
+                });
+            };
+
+            ['osrm','osrm.names','osrm.restrictions','osrm.ebg','osrm.enw','osrm.edges','osrm.fileIndex','osrm.geometry','osrm.nodes','osrm.ramIndex','osrm.properties'].forEach(file => {
+                q.defer(rename, file);
+            });
+
+            ['osrm.edge_segment_lookup','osrm.edge_penalties'].forEach(file => {
+                q.defer(renameIfExists, file);
+            });
+
+            q.awaitAll((err) => {
+                this.log('Finished extracting ' + this.osmData.extractedFile, 'preprocess');
+                process.chdir('../');
+                callback(err);
+            });
+        });
+    };
+
+    this.contractData = (callback) => {
+        this.logPreprocessInfo();
+        this.log(util.format('== Contracting %s.osm...', this.osmData.extractedFile), 'preprocess');
+        var cmd = util.format('%s%s/osrm-contract %s %s.osrm >>%s 2>&1',
+            this.LOAD_LIBRARIES, this.BIN_PATH, this.contractArgs || '', this.osmData.extractedFile, this.PREPROCESS_LOG_FILE);
+        this.log(cmd);
+        process.chdir(this.TEST_FOLDER);
+        exec(cmd, (err) => {
+            if (err) {
+                this.log(util.format('*** Exited with code %d', err.code), 'preprocess');
+                process.chdir('../');
+                return callback(this.ContractError(err.code, util.format('osrm-contract exited with code %d', err.code)));
+            }
+
+            var rename = (file, cb) => {
+                this.log(util.format('Renaming %s.%s to %s.%s', this.osmData.extractedFile, file, this.osmData.contractedFile, file), 'preprocess');
+                fs.rename([this.osmData.extractedFile, file].join('.'), [this.osmData.contractedFile, file].join('.'), (err) => {
+                    if (err) return cb(this.FileError(null, 'failed to rename data file after contracting.'));
+                    cb();
+                });
+            };
+
+            var copy = (file, cb) => {
+                this.log(util.format('Copying %s.%s to %s.%s', this.osmData.extractedFile, file, this.osmData.contractedFile, file), 'preprocess');
+                fs.createReadStream([this.osmData.extractedFile, file].join('.'))
+                    .pipe(fs.createWriteStream([this.osmData.contractedFile, file].join('.'))
+                            .on('finish', cb)
+                        )
+                    .on('error', () => {
+                        return cb(this.FileError(null, 'failed to copy data after contracting.'));
+                    });
+            };
+
+            var q = d3.queue();
+
+            ['osrm.hsgr','osrm.fileIndex','osrm.geometry','osrm.nodes','osrm.ramIndex','osrm.core','osrm.edges','osrm.datasource_indexes','osrm.datasource_names','osrm.level'].forEach((file) => {
+                q.defer(rename, file);
+            });
+
+            ['osrm.names','osrm.restrictions','osrm.properties','osrm'].forEach((file) => {
+                q.defer(copy, file);
+            });
+
+            q.awaitAll((err) => {
+                this.log('Finished contracting ' + this.osmData.contractedFile, 'preprocess');
+                process.chdir('../');
+                callback(err);
+            });
+        });
+    };
+
+    var noop = (cb) => cb();
+
+    this.reprocess = (callback) => {
+        this.writeAndExtract((e) => {
+            if (e) return callback(e);
+            this.isContracted((isContracted) => {
+                var contractFn = isContracted ? noop : this.contractData;
+                if (isContracted) this.log('Already contracted ' + this.osmData.contractedFile, 'preprocess');
+                contractFn((e) => {
+                    if (e) return callback(e);
+                    this.logPreprocessDone();
+                    callback();
+                });
+            });
+        });
+    };
+
+    this.writeAndExtract = (callback) => {
+        this.osmData.populate(() => {
+            this.writeInputData((e) => {
+                if (e) return callback(e);
+                this.isExtracted((isExtracted) => {
+                    var extractFn = isExtracted ? noop : this.extractData;
+                    if (isExtracted) this.log('Already extracted ' + this.osmData.extractedFile, 'preprocess');
+                    extractFn((e) => {
+                        callback(e);
+                    });
+                });
+            });
+        });
+    };
+
+    this.reprocessAndLoadData = (callback) => {
+        this.reprocess(() => {
+            this.OSRMLoader.load(util.format('%s.osrm', this.osmData.contractedFile), callback);
+        });
+    };
+
+    this.processRowsAndDiff = (table, fn, callback) => {
+        var q = d3.queue(1);
+
+        table.hashes().forEach((row, i) => { q.defer(fn, row, i); });
+
+        q.awaitAll((err, actual) => {
+            if (err) return callback(err);
+            this.diffTables(table, actual, {}, callback);
+        });
+    };
+};
diff --git a/features/support/data.rb b/features/support/data.rb
deleted file mode 100644
index 62ed7d3..0000000
--- a/features/support/data.rb
+++ /dev/null
@@ -1,325 +0,0 @@
-require 'OSM/objects'       #osmlib gem
-require 'OSM/Database'
-require 'builder'
-require 'fileutils'
-
-class Location
-  attr_accessor :lon,:lat
-
-  def initialize lon,lat
-    @lat = lat
-    @lon = lon
-  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
-end
-
-def input_format
-  @input_format || DEFAULT_INPUT_FORMAT
-end
-
-def sanitized_scenario_title
-  @sanitized_scenario_title ||= @scenario_title.to_s.gsub /[^0-9A-Za-z.\-]/, '_'
-end
-
-def set_grid_size meters
-  #the constant is calculated (with BigDecimal as: 1.0/(DEG_TO_RAD*EARTH_RADIUS_IN_METERS
-  #see ApproximateDistance() in ExtractorStructs.h
-  #it's only accurate when measuring along the equator, or going exactly north-south
-  @zoom = meters.to_f*0.8990679362704610899694577444566908445396483347536032203503E-5
-end
-
-def set_origin origin
-  @origin = origin
-end
-
-def build_ways_from_table table
-  #add one unconnected way for each row
-  table.hashes.each_with_index do |row,ri|
-    #NOTE:
-    #currently osrm crashes when processing an isolated oneway with just 2 nodes, so we use 4 edges
-    #this is relatated to the fact that a oneway dead-end street doesn't make a lot of sense
-
-    #if we stack ways on different x coordinates, routability tests get messed up, because osrm might pick a neighboring way if the one test can't be used.
-    #instead we place all lines as a string on the same y coordinate. this prevents using neightboring ways.
-
-    #a few nodes...
-    node1 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, @origin[0]+(0+WAY_SPACING*ri)*@zoom, @origin[1]
-    node2 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, @origin[0]+(1+WAY_SPACING*ri)*@zoom, @origin[1]
-    node3 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, @origin[0]+(2+WAY_SPACING*ri)*@zoom, @origin[1]
-    node4 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, @origin[0]+(3+WAY_SPACING*ri)*@zoom, @origin[1]
-    node5 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, @origin[0]+(4+WAY_SPACING*ri)*@zoom, @origin[1]
-    node1.uid = OSM_UID
-    node2.uid = OSM_UID
-    node3.uid = OSM_UID
-    node4.uid = OSM_UID
-    node5.uid = OSM_UID
-    node1 << { :name => "a#{ri}" }
-    node2 << { :name => "b#{ri}" }
-    node3 << { :name => "c#{ri}" }
-    node4 << { :name => "d#{ri}" }
-    node5 << { :name => "e#{ri}" }
-
-    osm_db << node1
-    osm_db << node2
-    osm_db << node3
-    osm_db << node4
-    osm_db << node5
-
-    #...with a way between them
-    way = OSM::Way.new make_osm_id, OSM_USER, OSM_TIMESTAMP
-    way.uid = OSM_UID
-    way << node1
-    way << node2
-    way << node3
-    way << node4
-    way << node5
-
-    tags = row.dup
-
-    # remove tags that describe expected test result
-    tags.reject! do |k,v|
-      k =~ /^forw\b/ ||
-      k =~ /^backw\b/ ||
-      k =~ /^bothw\b/
-    end
-
-    ##remove empty tags
-    tags.reject! { |k,v| v=='' }
-
-    # sort tag keys in the form of 'node/....'
-    way_tags = { 'highway' => 'primary' }
-
-    node_tags = {}
-    tags.each_pair do |k,v|
-      if k =~ /node\/(.*)/
-        if v=='(nil)'
-          node_tags.delete k
-        else
-          node_tags[$1] = v
-        end
-      else
-        if v=='(nil)'
-          way_tags.delete k
-        else
-          way_tags[k] = v
-        end
-      end
-    end
-
-    way_tags['name'] = "w#{ri}"
-    way << way_tags
-    node3 << node_tags
-
-    osm_db << way
-  end
-end
-
-def table_coord_to_lonlat ci,ri
-  [@origin[0]+ci*@zoom, @origin[1]-ri*@zoom]
-end
-
-def add_osm_node name,lon,lat,id
-  id = make_osm_id if id == nil
-  node = OSM::Node.new id, OSM_USER, OSM_TIMESTAMP, lon, lat
-  node << { :name => name }
-  node.uid = OSM_UID
-  osm_db << node
-  name_node_hash[name] = node
-end
-
-def add_location name,lon,lat
-  location_hash[name] = Location.new(lon,lat)
-end
-
-def find_node_by_name s
-  raise "***invalid node name '#{s}', must be single characters" unless s.size == 1
-  raise "*** invalid node name '#{s}', must be alphanumeric" unless s.match /[a-z0-9]/
-  if s.match /[a-z]/
-    from_node = name_node_hash[ s.to_s ]
-  else
-    from_node = location_hash[ s.to_s ]
-  end
-end
-
-def find_way_by_name s
-  name_way_hash[s.to_s] || name_way_hash[s.to_s.reverse]
-end
-
-def reset_data
-  Dir.chdir TEST_FOLDER do
-    #clear_log
-    #clear_data_files
-  end
-  reset_profile
-  reset_osm
-  @fingerprint_osm = nil
-  @fingerprint_extract = nil
-  @fingerprint_prepare = nil
-  @fingerprint_route = nil
-end
-
-def make_osm_id
-  @osm_id = @osm_id+1
-end
-
-def reset_osm
-  osm_db.clear
-  name_node_hash.clear
-  location_hash.clear
-  name_way_hash.clear
-  @osm_str = nil
-  @osm_hash = nil
-  @osm_id = 0
-end
-
-def clear_data_files
-  File.delete *Dir.glob("#{DATA_FOLDER}/test.*")
-end
-
-def clear_log
-  File.delete *Dir.glob("*.log")
-end
-
-def osm_db
-  @osm_db ||= OSM::Database.new
-end
-
-def name_node_hash
-  @name_node_hash ||= {}
-end
-
-def location_hash
-  @location_hash ||= {}
-end
-
-def name_way_hash
-  @name_way_hash ||= {}
-end
-
-def osm_str
-  return @osm_str if @osm_str
-  @osm_str = ''
-  doc = Builder::XmlMarkup.new :indent => 2, :target => @osm_str
-  doc.instruct!
-  osm_db.to_xml doc, OSM_GENERATOR
-  @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
-  Dir.mkdir DATA_FOLDER unless File.exist? DATA_FOLDER
-  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")
-    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"
-      raise OsmosisError.new $?, "osmosis exited with code #{$?.exitstatus}"
-    end
-    log '', :preprocess
-  end
-end
-
-def extracted?
-  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?
-  Dir.chdir TEST_FOLDER do
-    File.exist?("#{prepared_file}.osrm.hsgr")
-  end
-end
-
-def write_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
-    write_timestamp
-    convert_osm_to_pbf if pbf?
-  end
-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?} #{@extract_args} --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
-    begin
-      ["osrm","osrm.names","osrm.restrictions","osrm.ebg","osrm.edges","osrm.fileIndex","osrm.geometry","osrm.nodes","osrm.ramIndex"].each do |file|
-        log "Renaming #{osm_file}.#{file} to #{extracted_file}.#{file}", :preprocess
-        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 #{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","osrm.core","osrm.edges"].each do |file|
-        log "Renaming #{extracted_file}.#{file} to #{prepared_file}.#{file}", :preprocess
-        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.restrictions","osrm"].each do |file|
-        log "Copying #{extracted_file}.#{file} to #{prepared_file}.#{file}", :preprocess
-        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
-
-def reprocess
-  write_input_data
-  extract_data unless extracted?
-  prepare_data unless prepared?
-  log_preprocess_done
-end
diff --git a/features/support/data_classes.js b/features/support/data_classes.js
new file mode 100644
index 0000000..8eeaab3
--- /dev/null
+++ b/features/support/data_classes.js
@@ -0,0 +1,85 @@
+'use strict';
+
+var util = require('util');
+var path = require('path');
+
+module.exports = {
+    Location: class {
+        constructor (lon, lat) {
+            this.lon = lon;
+            this.lat = lat;
+        }
+    },
+
+    osmData: class {
+        constructor (scope) {
+            this.scope          = scope;
+            this.str            = null;
+            this.hash           = null;
+            this.fingerprintOSM = null;
+            this.osmFile        = null;
+            this.extractedFile  = null;
+            this.contractedFile   = null;
+        }
+
+        populate (callback) {
+            this.scope.OSMDB.toXML((str) => {
+                this.str = str;
+
+                this.hash = this.scope.hashString(str);
+                this.fingerprintOSM = this.scope.hashString(this.hash);
+
+                this.osmFile        = path.resolve(this.scope.DATA_FOLDER, this.fingerprintOSM);
+
+                this.extractedFile  = path.resolve([this.osmFile, this.scope.fingerprintExtract].join('_'));
+                this.contractedFile   = path.resolve([this.osmFile, this.scope.fingerprintExtract, this.scope.fingerprintContract].join('_'));
+
+                callback();
+            });
+        }
+
+        reset () {
+            this.str            = null;
+            this.hash           = null;
+            this.fingerprintOSM = null;
+            this.osmFile        = null;
+            this.extractedFile  = null;
+            this.contractedFile   = null;
+        }
+    },
+
+    FuzzyMatch: class {
+        match (got, want) {
+            var matchPercent = want.match(/(.*)\s+~(.+)%$/),
+                matchAbs = want.match(/(.*)\s+\+\-(.+)$/),
+                matchRe = want.match(/^\/(.*)\/$/);
+
+            if (got === want) {
+                return true;
+            } else if (matchPercent) {         // percentage range: 100 ~ 5%
+                var target = parseFloat(matchPercent[1]),
+                    percentage = parseFloat(matchPercent[2]);
+                if (target === 0) {
+                    return true;
+                } else {
+                    var ratio = Math.abs(1 - parseFloat(got) / target);
+                    return 100 * ratio < percentage;
+                }
+            } else if (matchAbs) {             // absolute range: 100 +-5
+                var margin = parseFloat(matchAbs[2]),
+                    fromR = parseFloat(matchAbs[1]) - margin,
+                    toR = parseFloat(matchAbs[1]) + margin;
+                return parseFloat(got) >= fromR && parseFloat(got) <= toR;
+            } else if (matchRe) {               // regex: /a,b,.*/
+                return got.match(matchRe[1]);
+            } else {
+                return false;
+            }
+        }
+
+        matchLocation (got, want) {
+            return this.match(got[0], util.format('%d ~0.0025%', want.lon)) &&
+                this.match(got[1], util.format('%d ~0.0025%', want.lat));
+        }
+    }
+};
diff --git a/features/support/env.js b/features/support/env.js
new file mode 100644
index 0000000..cae361c
--- /dev/null
+++ b/features/support/env.js
@@ -0,0 +1,125 @@
+var path = require('path');
+var util = require('util');
+var fs = require('fs');
+var exec = require('child_process').exec;
+var d3 = require('d3-queue');
+
+module.exports = function () {
+    this.initializeEnv = (callback) => {
+        this.DEFAULT_PORT = 5000;
+        this.DEFAULT_TIMEOUT = 2000;
+        this.setDefaultTimeout(this.DEFAULT_TIMEOUT);
+        this.ROOT_FOLDER = process.cwd();
+        this.OSM_USER = 'osrm';
+        this.OSM_GENERATOR = 'osrm-test';
+        this.OSM_UID = 1;
+        this.TEST_FOLDER = path.resolve(this.ROOT_FOLDER, 'test');
+        this.DATA_FOLDER = path.resolve(this.TEST_FOLDER, 'cache');
+        this.OSM_TIMESTAMP = '2000-01-01T00:00:00Z';
+        this.DEFAULT_SPEEDPROFILE = 'bicycle';
+        this.WAY_SPACING = 100;
+        this.DEFAULT_GRID_SIZE = 100;    // meters
+        this.PROFILES_PATH = path.resolve(this.ROOT_FOLDER, 'profiles');
+        this.FIXTURES_PATH = path.resolve(this.ROOT_FOLDER, 'unit_tests/fixtures');
+        this.BIN_PATH = path.resolve(this.ROOT_FOLDER, 'build');
+        this.DEFAULT_INPUT_FORMAT = 'osm';
+        this.DEFAULT_ORIGIN = [1,1];
+        this.LAUNCH_TIMEOUT = 1000;
+        this.SHUTDOWN_TIMEOUT = 10000;
+        this.DEFAULT_LOAD_METHOD = 'datastore';
+        this.OSRM_ROUTED_LOG_FILE = path.resolve(this.TEST_FOLDER, 'osrm-routed.log');
+        this.ERROR_LOG_FILE = path.resolve(this.TEST_FOLDER, 'error.log');
+
+        // OS X shim to ensure shared libraries from custom locations can be loaded
+        // This is needed in OS X >= 10.11 because DYLD_LIBRARY_PATH is blocked
+        // https://forums.developer.apple.com/thread/9233
+        this.LOAD_LIBRARIES = process.env.OSRM_SHARED_LIBRARY_PATH ? util.format('DYLD_LIBRARY_PATH=%s ', process.env.OSRM_SHARED_LIBRARY_PATH) : '';
+
+        // TODO make sure this works on win
+        if (process.platform.match(/indows.*/)) {
+            this.TERMSIGNAL = 9;
+            this.EXE = '.exe';
+            this.QQ = '"';
+        } else {
+            this.TERMSIGNAL = 'SIGTERM';
+            this.EXE = '';
+            this.QQ = '';
+        }
+
+        // eslint-disable-next-line no-console
+        console.info(util.format('Node Version', process.version));
+        if (parseInt(process.version.match(/v(\d)/)[1]) < 4) throw new Error('*** PLease upgrade to Node 4.+ to run OSRM cucumber tests');
+
+        if (process.env.OSRM_PORT) {
+            this.OSRM_PORT = parseInt(process.env.OSRM_PORT);
+            // eslint-disable-next-line no-console
+            console.info(util.format('Port set to %d', this.OSRM_PORT));
+        } else {
+            this.OSRM_PORT = this.DEFAULT_PORT;
+            // eslint-disable-next-line no-console
+            console.info(util.format('Using default port %d', this.OSRM_PORT));
+        }
+
+        if (process.env.OSRM_TIMEOUT) {
+            this.OSRM_TIMEOUT = parseInt(process.env.OSRM_TIMEOUT);
+            // eslint-disable-next-line no-console
+            console.info(util.format('Timeout set to %d', this.OSRM_TIMEOUT));
+        } else {
+            this.OSRM_TIMEOUT = this.DEFAULT_TIMEOUT;
+            // eslint-disable-next-line no-console
+            console.info(util.format('Using default timeout %d', this.OSRM_TIMEOUT));
+        }
+
+        fs.exists(this.TEST_FOLDER, (exists) => {
+            if (!exists) throw new Error(util.format('*** Test folder %s doesn\'t exist.', this.TEST_FOLDER));
+            callback();
+        });
+    };
+
+    this.verifyOSRMIsNotRunning = () => {
+        if (this.OSRMLoader.up()) {
+            throw new Error('*** osrm-routed is already running.');
+        }
+    };
+
+    this.verifyExistenceOfBinaries = (callback) => {
+        var verify = (bin, cb) => {
+            var binPath = path.resolve(util.format('%s/%s%s', this.BIN_PATH, bin, this.EXE));
+            fs.exists(binPath, (exists) => {
+                if (!exists) throw new Error(util.format('%s is missing. Build failed?', binPath));
+                var helpPath = util.format('%s%s --help > /dev/null 2>&1', this.LOAD_LIBRARIES, binPath);
+                exec(helpPath, (err) => {
+                    if (err) {
+                        this.log(util.format('*** Exited with code %d', err.code), 'preprocess');
+                        throw new Error(util.format('*** %s exited with code %d', helpPath, err.code));
+                    }
+                    cb();
+                });
+            });
+        };
+
+        var q = d3.queue();
+        ['osrm-extract', 'osrm-contract', 'osrm-routed'].forEach(bin => { q.defer(verify, bin); });
+        q.awaitAll(() => {
+            callback();
+        });
+    };
+
+    this.AfterConfiguration = (callback) => {
+        this.clearLogFiles(() => {
+            this.verifyOSRMIsNotRunning();
+            this.verifyExistenceOfBinaries(() => {
+                callback();
+            });
+        });
+    };
+
+    process.on('exit', () => {
+        if (this.OSRMLoader.loader) this.OSRMLoader.shutdown(() => {});
+    });
+
+    process.on('SIGINT', () => {
+        process.exit(2);
+        // TODO need to handle for windows??
+    });
+};
diff --git a/features/support/env.rb b/features/support/env.rb
deleted file mode 100644
index cb707f9..0000000
--- a/features/support/env.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-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-01-01T00:00:00Z'
-DEFAULT_SPEEDPROFILE = 'bicycle'
-WAY_SPACING = 100
-DEFAULT_GRID_SIZE = 100   #meters
-PROFILES_PATH = File.join ROOT_FOLDER, 'profiles'
-FIXTURES_PATH = File.join ROOT_FOLDER, 'unit_tests/fixtures'
-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=9
-else
-  TERMSIGNAL='TERM'
-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}"
-unless RUBY_VERSION.to_f >= 1.9
-  raise "*** Please upgrade to Ruby 1.9.x to run the OSRM cucumber tests"
-end
-
-if ENV["OSRM_PORT"]
-  OSRM_PORT = ENV["OSRM_PORT"].to_i
-  puts "Port set to #{OSRM_PORT}"
-else
-  OSRM_PORT = DEFAULT_PORT
-  puts "Using default port #{OSRM_PORT}"
-end
-
-if ENV["OSRM_TIMEOUT"]
-  OSRM_TIMEOUT = ENV["OSRM_TIMEOUT"].to_i
-  puts "Timeout set to #{OSRM_TIMEOUT}"
-else
-  OSRM_TIMEOUT = DEFAULT_TIMEOUT
-  puts "Using default timeout #{OSRM_TIMEOUT}"
-end
-
-unless File.exists? TEST_FOLDER
-  raise "*** Test folder #{TEST_FOLDER} doesn't exist."
-end
-
-def verify_osrm_is_not_running
-  if OSRMLoader::OSRMBaseLoader.new.osrm_up?
-    raise "*** osrm-routed is already running."
-  end
-end
-
-def verify_existance_of_binaries
-  ["osrm-extract", "osrm-prepare", "osrm-routed"].each do |bin|
-    unless File.exists? "#{BIN_PATH}/#{bin}#{EXE}"
-      raise "*** #{BIN_PATH}/#{bin}#{EXE} is missing. Build failed?"
-    end
-  end
-end
-
-if ENV['OS']=~/Windows.*/ then
-   EXE='.exe'
-   QQ='"'
-else
-   EXE=''
-   QQ=''
-end
-
-AfterConfiguration do |config|
-  clear_log_files
-  verify_osrm_is_not_running
-  verify_existance_of_binaries
-end
-
-at_exit do
-  OSRMLoader::OSRMBaseLoader.new.shutdown
-end
diff --git a/features/support/exception_classes.js b/features/support/exception_classes.js
new file mode 100644
index 0000000..36bdffe
--- /dev/null
+++ b/features/support/exception_classes.js
@@ -0,0 +1,132 @@
+'use strict';
+
+var util = require('util');
+var path = require('path');
+var fs = require('fs');
+var chalk = require('chalk');
+
+var OSRMError = class extends Error {
+    constructor (process, code, msg, log, lines) {
+        super(msg);
+        this.process = process;
+        this.code = code;
+        this.msg = msg;
+        this.lines = lines;
+        this.log = log;
+    }
+
+    extract (callback) {
+        this.logTail(this.log, this.lines, callback);
+    }
+
+    // toString (callback) {
+    //     this.extract((tail) => {
+    //         callback(util.format('*** %s\nLast %s from %s:\n%s\n', this.msg, this.lines, this.log, tail));
+    //     });
+    // }
+
+    logTail (logPath, n, callback) {
+        var expanded = path.resolve(this.TEST_FOLDER, logPath);
+        fs.exists(expanded, (exists) => {
+            if (exists) {
+                fs.readFile(expanded, (err, data) => {
+                    var lines = data.toString().trim().split('\n');
+                    callback(lines
+                        .slice(lines.length - n)
+                        .map(line => util.format('    %s', line))
+                        .join('\n'));
+                });
+            } else {
+                callback(util.format('File %s does not exist!', expanded));
+            }
+        });
+    }
+};
+
+var unescapeStr = (str) => str.replace(/\\\|/g, '\|').replace(/\\\\/g, '\\');
+
+module.exports = {
+    OSRMError: OSRMError,
+
+    FileError: class extends OSRMError {
+        constructor (logFile, code, msg) {
+            super ('fileutil', code, msg, logFile, 5);
+        }
+    },
+
+    LaunchError: class extends OSRMError {
+        constructor (logFile, launchProcess, code, msg) {
+            super (launchProcess, code, msg, logFile, 5);
+        }
+    },
+
+    ExtractError: class extends OSRMError {
+        constructor (logFile, code, msg) {
+            super('osrm-extract', code, msg, logFile, 3);
+        }
+    },
+
+    ContractError:  class extends OSRMError {
+        constructor (logFile, code, msg) {
+            super('osrm-contract', code, msg, logFile, 3);
+        }
+    },
+
+    RoutedError: class extends OSRMError {
+        constructor (logFile, msg) {
+            super('osrm-routed', null, msg, logFile, 3);
+        }
+    },
+
+    TableDiffError: class extends Error {
+        constructor (expected, actual) {
+            super();
+            this.headers = expected.raw()[0];
+            this.expected = expected.hashes();
+            this.actual = actual;
+            this.diff = [];
+            this.hasErrors = false;
+
+            var good = 0, bad = 0;
+
+            this.expected.forEach((row, i) => {
+                var rowError = false;
+
+                for (var j in row) {
+                    if (unescapeStr(row[j]) != actual[i][j]) {
+                        rowError = true;
+                        this.hasErrors = true;
+                        break;
+                    }
+                }
+
+                if (rowError) {
+                    bad++;
+                    this.diff.push(Object.assign({}, row, {c_status: 'undefined'}));
+                    this.diff.push(Object.assign({}, actual[i], {c_status: 'comment'}));
+                } else {
+                    good++;
+                    this.diff.push(row);
+                }
+            });
+        }
+
+        get string () {
+            if (!this.hasErrors) return null;
+
+            var s = ['Tables were not identical:'];
+            s.push(this.headers.map(key => '    ' + key).join(' | '));
+            this.diff.forEach((row) => {
+                var rowString = '| ';
+                this.headers.forEach((header) => {
+                    if (!row.c_status) rowString += chalk.green('    ' + row[header] + ' | ');
+                    else if (row.c_status === 'undefined') rowString += chalk.yellow('(-) ' + row[header] + ' | ');
+                    else rowString += chalk.red('(+) ' + row[header] + ' | ');
+                });
+                s.push(rowString);
+            });
+
+            return s.join('\n') + '\nTODO this is a temp workaround waiting for https://github.com/cucumber/cucumber-js/issues/534';
+        }
+    }
+};
diff --git a/features/support/exceptions.js b/features/support/exceptions.js
new file mode 100644
index 0000000..6af1a93
--- /dev/null
+++ b/features/support/exceptions.js
@@ -0,0 +1,15 @@
+var exceptions = require('./exception_classes');
+
+module.exports = function () {
+    this.OSRMError = exceptions.OSRMError,
+
+    this.FileError = (code, msg) => new (exceptions.FileError.bind(exceptions.FileError, this.PREPROCESS_LOG_FILE))(code, msg);
+
+    this.LaunchError = (code, launchProcess, msg) => new (exceptions.LaunchError.bind(exceptions.LaunchError, this.ERROR_LOG_FILE))(code, launchProcess, msg);
+
+    this.ExtractError = (code, msg) => new (exceptions.ExtractError.bind(exceptions.ExtractError, this.PREPROCESS_LOG_FILE))(code, msg);
+
+    this.ContractError = (code, msg) => new (exceptions.ContractError.bind(exceptions.ContractError, this.PREPROCESS_LOG_FILE))(code, msg);
+
+    this.RoutedError = (msg) => new (exceptions.RoutedError.bind(exceptions.RoutedError, this.OSRM_ROUTED_LOG_FILE))(msg);
+};
diff --git a/features/support/exceptions.rb b/features/support/exceptions.rb
deleted file mode 100644
index 02f59d3..0000000
--- a/features/support/exceptions.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-
-class OSRMError < StandardError
-  attr_accessor :msg, :code, :process
-
-  def initialize process, code, msg, log, lines
-    @process = process
-    @code = code
-    @msg = msg
-    @lines = lines
-    @log = log
-    @extract = log_tail @log, @lines
-  end
-
-  def to_s
-    "*** #{@msg}\nLast #{@lines} lines from #{@log}:\n#{@extract}\n"
-  end
-
-  private
-
-  def log_tail path, n
-    Dir.chdir TEST_FOLDER do
-      expanded = File.expand_path path
-      if File.exists? expanded
-        File.open(expanded) do |f|
-          return f.tail(n).map { |line| "    #{line}" }.join "\n"
-        end
-      else
-        return "File '#{expanded} does not exist!"
-      end
-    end
-  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
-  end
-end
-
-class ExtractError < OSRMError
-  def initialize code, msg
-    super 'osrm-extract', code, msg, PREPROCESS_LOG_FILE, 3
-  end
-end
-
-class PrepareError < OSRMError
-  def initialize code, msg
-    super 'osrm-prepare', code, msg, PREPROCESS_LOG_FILE, 3
-  end
-end
-
-class RoutedError < OSRMError
-  def initialize msg
-    super 'osrm-routed', nil, msg, OSRM_ROUTED_LOG_FILE, 3
-  end
-end
diff --git a/features/support/file.rb b/features/support/file.rb
deleted file mode 100644
index dfaae0a..0000000
--- a/features/support/file.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-class File
-
-  # read last n lines of a file (trailing newlines are ignored)
-  def tail(n)
-    return [] if size==0
-    buffer = 1024
-    str = nil
-
-    if size>buffer
-      chunks = []
-      lines = 0
-      idx = size
-      begin
-        idx -= buffer     # rewind
-        if idx<0
-          buffer += idx   # adjust last read to avoid negative index
-          idx = 0
-        end
-        seek(idx)
-        chunk = read(buffer)
-        chunk.gsub!(/\n+\Z/,"") if chunks.empty? # strip newlines from end of file (first chunk)
-        lines += chunk.count("\n")  # update total lines found
-        chunks.unshift chunk        # prepend
-      end while lines<(n) && idx>0  # stop when enough lines found or no more to read
-      str = chunks.join('')
-    else
-      str = read(buffer)
-    end
-
-    # return last n lines of str
-    lines = str.split("\n")
-    lines.size>=n ? lines[-n,n] : lines
-  end
-end
\ No newline at end of file
diff --git a/features/support/fuzzy.js b/features/support/fuzzy.js
new file mode 100644
index 0000000..6eebe0a
--- /dev/null
+++ b/features/support/fuzzy.js
@@ -0,0 +1,5 @@
+var classes = require('./data_classes');
+
+module.exports = function() {
+    this.FuzzyMatch = new classes.FuzzyMatch();
+};
diff --git a/features/support/fuzzy.rb b/features/support/fuzzy.rb
deleted file mode 100644
index 066d9c5..0000000
--- a/features/support/fuzzy.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-class FuzzyMatch
-
-  def self.match got, want
-    if got == want
-      return true
-    elsif want.match /(.*)\s+~(.+)%$/       #percentage range: 100 ~5%
-      target = $1.to_f
-      percentage = $2.to_f
-      if target==0
-        return true
-      else
-        ratio = (1-(got.to_f / target)).abs;
-        return 100*ratio < percentage;
-      end
-    elsif want.match /(.*)\s+\+\-(.+)$/    #absolute range: 100 +-5
-      margin = $2.to_f
-      from = $1.to_f-margin
-      to = $1.to_f+margin
-      return got.to_f >= from && got.to_f <= to
-    elsif want =~ /^\/(.*)\/$/             #regex: /a,b,.*/
-      return got =~ /#{$1}/
-    else
-      return false
-    end
-  end
-
-  def self.match_location got, want
-    match( got[0], "#{want.lat} ~0.0025%" ) &&
-    match( got[1], "#{want.lon} ~0.0025%" )
-  end
-
-end
diff --git a/features/support/hash.js b/features/support/hash.js
new file mode 100644
index 0000000..6ab44ad
--- /dev/null
+++ b/features/support/hash.js
@@ -0,0 +1,37 @@
+var fs = require('fs');
+var path = require('path');
+var crypto = require('crypto');
+var d3 = require('d3-queue');
+
+module.exports = function () {
+    this.hashOfFiles = (paths, cb) => {
+        paths = Array.isArray(paths) ? paths : [paths];
+        var shasum = crypto.createHash('sha1');
+
+        var q = d3.queue(1);
+
+        var addFile = (path, cb) => {
+            fs.readFile(path, (err, data) => {
+                shasum.update(data);
+                cb(err);
+            });
+        };
+
+        paths.forEach(path => { q.defer(addFile, path); });
+
+        q.awaitAll(err => {
+            if (err) throw new Error('*** Error reading files:', err);
+            cb(shasum.digest('hex'));
+        });
+    };
+
+    this.hashProfile = (cb) => {
+        this.hashOfFiles(path.resolve(this.PROFILES_PATH, this.profile + '.lua'), cb);
+    };
+
+    this.hashString = (str) => {
+        return crypto.createHash('sha1').update(str).digest('hex');
+    };
+
+    return this;
+};
diff --git a/features/support/hash.rb b/features/support/hash.rb
deleted file mode 100644
index 6980b66..0000000
--- a/features/support/hash.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-require 'digest/sha1'
-
-bin_extract_hash = nil
-profile_hashes = nil
-
-def hash_of_files paths
-  paths = [paths] unless paths.is_a? Array
-  hash = Digest::SHA1.new
-  for path in paths do
-    open(path,'rb') do |io|
-      while !io.eof
-        buf = io.readpartial 1024
-        hash.update buf
-      end
-    end
-  end
-  return hash.hexdigest
-end
-
-
-def profile_hash
-  profile_hashes ||= {}
-  profile_hashes[@profile] ||= hash_of_files "#{PROFILES_PATH}/#{@profile}.lua"
-end
-
-def osm_hash
-  @osm_hash ||= Digest::SHA1.hexdigest osm_str
-end
-
-def lua_lib_hash
-  @lua_lib_hash ||= hash_of_files Dir.glob("../profiles/lib/*.lua")
-end
-
-def bin_extract_hash
-  @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}"
-end
-
-def bin_routed_hash
-  @bin_routed_hash ||= hash_of_files "#{BIN_PATH}/osrm-routed#{EXE}"
-end
-
-# 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.js b/features/support/hooks.js
new file mode 100644
index 0000000..f8c7a2f
--- /dev/null
+++ b/features/support/hooks.js
@@ -0,0 +1,37 @@
+var util = require('util');
+
+module.exports = function () {
+    this.BeforeFeatures((features, callback) => {
+        this.pid = null;
+        this.initializeEnv(() => {
+            this.initializeOptions(callback);
+        });
+    });
+
+    this.Before((scenario, callback) => {
+        this.scenarioTitle = scenario.getName();
+
+        this.loadMethod = this.DEFAULT_LOAD_METHOD;
+        this.queryParams = {};
+        var d = new Date();
+        this.scenarioTime = util.format('%d-%d-%dT%s:%s:%sZ', d.getFullYear(), d.getMonth()+1, d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds());
+        this.resetData();
+        this.hasLoggedPreprocessInfo = false;
+        this.hasLoggedScenarioInfo = false;
+        this.setGridSize(this.DEFAULT_GRID_SIZE);
+        this.setOrigin(this.DEFAULT_ORIGIN);
+        callback();
+    });
+
+    this.After((scenario, callback) => {
+        this.setExtractArgs('');
+        this.setContractArgs('');
+        if (this.loadMethod === 'directly' && !!this.OSRMLoader.loader) this.OSRMLoader.shutdown(callback);
+        else callback();
+    });
+
+    this.Around('@stress', (scenario, callback) => {
+        // TODO implement stress timeout? Around support is being dropped in cucumber-js anyway
+        callback();
+    });
+};
diff --git a/features/support/hooks.rb b/features/support/hooks.rb
deleted file mode 100644
index 6af9a8f..0000000
--- a/features/support/hooks.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-
-STRESS_TIMEOUT = 300
-
-
-Before do |scenario|
-
-  # fetch scenario and feature name, so we can use it in log files if needed
-  case scenario
-    when Cucumber::RunningTestCase::Scenario
-      @feature_name = scenario.feature.name
-      @scenario_title = scenario.name
-    when Cucumber::RunningTestCase::ExampleRow
-      @feature_name = scenario.scenario_outline.feature.name
-      @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|
-  Timeout.timeout(STRESS_TIMEOUT) do
-    block.call
-  end
-end
-
-After do
-end
diff --git a/features/support/http.js b/features/support/http.js
new file mode 100644
index 0000000..5da59c4
--- /dev/null
+++ b/features/support/http.js
@@ -0,0 +1,51 @@
+var Timeout = require('node-timeout');
+var request = require('request');
+
+module.exports = function () {
+    this.paramsToString = (params) => {
+        var paramString = '';
+        if (params.coordinates !== undefined) {
+            // FIXME this disables passing the output if its a default
+            // Remove after #2173 is fixed.
+            var outputString = (params.output && params.output !== 'json') ? ('.' + params.output) : '';
+            paramString = params.coordinates.join(';') + outputString;
+            delete params.coordinates;
+            delete params.output;
+        }
+        if (Object.keys(params).length) {
+            paramString += '?' + Object.keys(params).map(k => k + '=' + params[k]).join('&');
+        }
+
+        return paramString;
+    };
+
+    this.sendRequest = (baseUri, parameters, callback) => {
+        var limit = Timeout(this.OSRM_TIMEOUT, { err: { statusCode: 408 } });
+
+        var runRequest = (cb) => {
+            var params = this.paramsToString(parameters);
+            this.query = baseUri + (params.length ? '/' + params : '');
+
+            request(this.query, (err, res, body) => {
+                if (err && err.code === 'ECONNREFUSED') {
+                    throw new Error('*** osrm-routed is not running.');
+                } else if (err && err.statusCode === 408) {
+                    throw new Error();
+                }
+
+                return cb(err, res, body);
+            });
+        };
+
+        runRequest(limit((err, res, body) => {
+            if (err) {
+                if (err.statusCode === 408)
+                    return callback(this.RoutedError('*** osrm-routed did not respond'));
+                else if (err.code === 'ECONNREFUSED')
+                    return callback(this.RoutedError('*** osrm-routed is not running'));
+            }
+            //console.log(body+"\n");
+            return callback(err, res, body);
+        }));
+    };
+};
diff --git a/features/support/http.rb b/features/support/http.rb
deleted file mode 100644
index 0b9fb9a..0000000
--- a/features/support/http.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require 'net/http'
-
-# Converts an array [["param","val1"], ["param","val2"]] into ?param=val1&param=val2
-def params_to_url params
-  kv_pairs = params.map { |kv| kv[0].to_s + "=" + kv[1].to_s }
-  url = kv_pairs.size > 0 ? ("?" + kv_pairs.join("&")) : ""
-  return url
-end
-
-# Converts an array [["param","val1"], ["param","val2"]] into ["param"=>["val1", "val2"]]
-def params_to_map params
-  result = {}
-  params.each do |pair|
-    if not result.has_key? pair[0]
-      result[pair[0]] = []
-    end
-    result[pair[0]] << [pair[1]]
-  end
-end
-
-def send_request base_uri, parameters
-  Timeout.timeout(OSRM_TIMEOUT) do
-    if @http_method.eql? "POST"
-      uri = URI.parse base_uri
-      @query = uri.to_s
-      response = Net::HTTP.post_form uri, (params_to_map parameters)
-    else
-      uri = URI.parse base_uri+(params_to_url parameters)
-      @query = uri.to_s
-      response = Net::HTTP.get_response uri
-    end
-  end
-rescue Errno::ECONNREFUSED => e
-  raise "*** osrm-routed is not running."
-rescue Timeout::Error
-  raise "*** osrm-routed did not respond."
-end
diff --git a/features/support/launch.js b/features/support/launch.js
new file mode 100644
index 0000000..ee335e3
--- /dev/null
+++ b/features/support/launch.js
@@ -0,0 +1,5 @@
+var launchClasses = require('./launch_classes');
+
+module.exports = function () {
+    this._OSRMLoader = () => new (launchClasses._OSRMLoader.bind(launchClasses._OSRMLoader, this))();
+};
diff --git a/features/support/launch.rb b/features/support/launch.rb
deleted file mode 100644
index d8d23ae..0000000
--- a/features/support/launch.rb
+++ /dev/null
@@ -1,137 +0,0 @@
-require 'socket'
-require 'open3'
-require 'json'
-
-# 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
-
-  class OSRMBaseLoader
-    @@pid = nil
-
-    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
-
-    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 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
-
-    def osrm_down
-      if @@pid
-        Process.kill TERMSIGNAL, @@pid
-        wait_for_shutdown
-        @@pid = nil
-      end
-    end
-
-    def kill
-      if @@pid
-        Process.kill 'KILL', @@pid
-      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
-        end
-      end
-    end
-
-    def wait_for_shutdown
-      while osrm_up?
-        sleep 0.01
-      end
-    end
-  end
-
-  # 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
-
-    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
-
-  # 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 --shared-memory=1 --port #{OSRM_PORT}",:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE)
-      Process.detach(@@pid)    # avoid zombie processes
-    end
-  end
-
-  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/launch_classes.js b/features/support/launch_classes.js
new file mode 100644
index 0000000..38f3b31
--- /dev/null
+++ b/features/support/launch_classes.js
@@ -0,0 +1,163 @@
+'use strict';
+
+var fs = require('fs');
+var net = require('net');
+var spawn = require('child_process').spawn;
+var util = require('util');
+var Timeout = require('node-timeout');
+
+var OSRMBaseLoader = class {
+    constructor (scope) {
+        this.scope = scope;
+    }
+
+    launch (callback) {
+        var limit = Timeout(this.scope.LAUNCH_TIMEOUT, { err: this.scope.RoutedError('Launching osrm-routed timed out.') });
+
+        var runLaunch = (cb) => {
+            this.osrmUp(() => {
+                this.waitForConnection(cb);
+            });
+        };
+
+        runLaunch(limit((e) => { if (e) callback(e); else callback(); }));
+    }
+
+    shutdown (callback) {
+        var limit = Timeout(this.scope.SHUTDOWN_TIMEOUT, { err: this.scope.RoutedError('Shutting down osrm-routed timed out.')});
+
+        var runShutdown = (cb) => {
+            this.osrmDown(cb);
+        };
+
+        runShutdown(limit((e) => { if (e) callback(e); else callback(); }));
+    }
+
+    osrmIsRunning () {
+        return !!this.scope.pid && this.child && !this.child.killed;
+    }
+
+    osrmDown (callback) {
+        if (this.scope.pid) {
+            process.kill(this.scope.pid, this.scope.TERMSIGNAL);
+            this.waitForShutdown(callback);
+            this.scope.pid = null;
+        } else callback(true);
+    }
+
+    waitForConnection (callback) {
+        net.connect({
+            port: this.scope.OSRM_PORT,
+            host: '127.0.0.1'
+        })
+            .on('connect', () => {
+                callback();
+            })
+            .on('error', (e) => {
+                setTimeout(() => {
+                    callback(e);
+                }, 100);
+            });
+    }
+
+    waitForShutdown (callback) {
+        var check = () => {
+            if (!this.osrmIsRunning()) return callback();
+        };
+        setTimeout(check, 100);
+    }
+};
+
+var OSRMDirectLoader = class extends OSRMBaseLoader {
+    constructor (scope) {
+        super(scope);
+    }
+
+    load (inputFile, callback) {
+        this.inputFile = inputFile;
+        this.shutdown(() => {
+            this.launch(callback);
+        });
+    }
+
+    osrmUp (callback) {
+        if (this.scope.pid) return callback();
+        var writeToLog = (data) => {
+            fs.appendFile(this.scope.OSRM_ROUTED_LOG_FILE, data, (err) => { if (err) throw err; });
+        };
+
+        var child = spawn(util.format('%s%s/osrm-routed', this.scope.LOAD_LIBRARIES, this.scope.BIN_PATH), [this.inputFile, util.format('-p%d', this.scope.OSRM_PORT)]);
+        this.scope.pid = child.pid;
+        child.stdout.on('data', writeToLog);
+        child.stderr.on('data', writeToLog);
+
+        callback();
+    }
+};
+
+var OSRMDatastoreLoader = class extends OSRMBaseLoader {
+    constructor (scope) {
+        super(scope);
+    }
+
+    load (inputFile, callback) {
+        this.inputFile = inputFile;
+        this.loadData((err) => {
+            if (err) return callback(err);
+            if (!this.scope.pid) return this.launch(callback);
+            else callback();
+        });
+    }
+
+    loadData (callback) {
+        this.scope.runBin('osrm-datastore', this.inputFile, (err) => {
+            if (err) return callback(this.scope.LaunchError(this.exitCode, 'datastore', err));
+            callback();
+        });
+    }
+
+    osrmUp (callback) {
+        if (this.scope.pid) return callback();
+        var writeToLog = (data) => {
+            fs.appendFile(this.scope.OSRM_ROUTED_LOG_FILE, data, (err) => { if (err) throw err; });
+        };
+
+        var child = spawn(util.format('%s%s/osrm-routed', this.scope.LOAD_LIBRARIES, this.scope.BIN_PATH), ['--shared-memory=1', util.format('-p%d', this.scope.OSRM_PORT)]);
+        this.child = child;
+        this.scope.pid = child.pid;
+        child.stdout.on('data', writeToLog);
+        child.stderr.on('data', writeToLog);
+
+        callback();
+    }
+};
+
+module.exports = {
+    _OSRMLoader: class {
+        constructor (scope) {
+            this.scope = scope;
+            this.loader = null;
+        }
+
+        load (inputFile, callback) {
+            var method = this.scope.loadMethod;
+            if (method === 'datastore') {
+                this.loader = new OSRMDatastoreLoader(this.scope);
+                this.loader.load(inputFile, callback);
+            } else if (method === 'directly') {
+                this.loader = new OSRMDirectLoader(this.scope);
+                this.loader.load(inputFile, callback);
+            } else {
+                throw new Error('*** Unknown load method ' + method);
+            }
+        }
+
+        shutdown (callback) {
+            this.loader.shutdown(callback);
+        }
+
+        up () {
+            return this.loader ? this.loader.osrmIsRunning() : false;
+        }
+    }
+};
diff --git a/features/support/log.js b/features/support/log.js
new file mode 100644
index 0000000..c428cb9
--- /dev/null
+++ b/features/support/log.js
@@ -0,0 +1,90 @@
+var fs = require('fs');
+
+module.exports = function () {
+    this.clearLogFiles = (callback) => {
+        // emptying existing files, rather than deleting and writing new ones makes it
+        // easier to use tail -f from the command line
+        fs.writeFile(this.OSRM_ROUTED_LOG_FILE, '', err => {
+            if (err) throw err;
+            fs.writeFile(this.PREPROCESS_LOG_FILE, '', err => {
+                if (err) throw err;
+                fs.writeFile(this.LOG_FILE, '', err => {
+                    if (err) throw err;
+                    callback();
+                });
+            });
+        });
+    };
+
+    var log = this.log = (s, type) => {
+        s = s || '';
+        type = type || null;
+        var file = type === 'preprocess' ? this.PREPROCESS_LOG_FILE : this.LOG_FILE;
+        fs.appendFile(file, s + '\n', err => {
+            if (err) throw err;
+        });
+    };
+
+    this.logScenarioFailInfo = () => {
+        if (this.hasLoggedScenarioInfo) return;
+
+        log('=========================================');
+        log('Failed scenario: ' + this.scenarioTitle);
+        log('Time: ' + this.scenarioTime);
+        log('Fingerprint osm stage: ' + this.osmData.fingerprintOSM);
+        log('Fingerprint extract stage: ' + this.fingerprintExtract);
+        log('Fingerprint contract stage: ' + this.fingerprintContract);
+        log('Fingerprint route stage: ' + this.fingerprintRoute);
+        log('Profile: ' + this.profile);
+        log();
+        log('```xml');               // so output can be posted directly to github comment fields
+        log(this.osmData.str.trim());
+        log('```');
+        log();
+        log();
+
+        this.hasLoggedScenarioInfo = true;
+    };
+
+    this.logFail = (expected, got, attempts) => {
+        this.logScenarioFailInfo();
+        log('== ');
+        log('Expected: ' + JSON.stringify(expected));
+        log('Got:      ' + JSON.stringify(got));
+        log();
+        ['route','forw','backw'].forEach((direction) => {
+            if (attempts[direction]) {
+                log('Direction: ' + direction);
+                log('Query: ' + attempts[direction].query);
+                log('Response: ' + attempts[direction].response.body);
+                log();
+            }
+        });
+    };
+
+    this.logPreprocessInfo = () => {
+        if (this.hasLoggedPreprocessInfo) return;
+        log('=========================================', 'preprocess');
+        log('Preprocessing data for scenario: ' + this.scenarioTitle, 'preprocess');
+        log('Time: ' + this.scenarioTime, 'preprocess');
+        log('', 'preprocess');
+        log('== OSM data:', 'preprocess');
+        log('```xml', 'preprocess');            // so output can be posted directly to github comment fields
+        log(this.osmData.str, 'preprocess');
+        log('```', 'preprocess');
+        log('', 'preprocess');
+        log('== Profile:', 'preprocess');
+        log(this.profile, 'preprocess');
+        log('', 'preprocess');
+        this.hasLoggedPreprocessInfo = true;
+    };
+
+    this.logPreprocess = (str) => {
+        this.logPreprocessInfo();
+        log(str, 'preprocess');
+    };
+
+    this.logPreprocessDone = () => {
+        log('Done with preprocessing at ' + new Date(), 'preprocess');
+    };
+};
diff --git a/features/support/log.rb b/features/support/log.rb
deleted file mode 100644
index 8e6f9c1..0000000
--- a/features/support/log.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-# logging
-
-PREPROCESS_LOG_FILE = 'preprocessing.log'
-LOG_FILE = 'fail.log'
-
-
-def clear_log_files
-  Dir.chdir TEST_FOLDER do
-    # emptying existing files, rather than deleting and writing new ones makes it 
-    # easier to use tail -f from the command line
-    `echo '' > #{OSRM_ROUTED_LOG_FILE}`
-    `echo '' > #{PREPROCESS_LOG_FILE}`
-    `echo '' > #{LOG_FILE}`
-  end
-end
-
-def log s='', type=nil
-  if type == :preprocess
-    file = PREPROCESS_LOG_FILE
-  else
-    file = LOG_FILE
-  end
-  File.open(file, 'a') {|f| f.write("#{s}\n") }
-end
-
-
-def log_scenario_fail_info
-  return if @has_logged_scenario_info
-  log "========================================="
-  log "Failed scenario: #{@scenario_title}"
-  log "Time: #{@scenario_time}"
-  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
-  log osm_str.strip
-  log '```'
-  log
-  log
-  @has_logged_scenario_info = true
-end
-
-def log_fail expected,got,attempts
-  return
-  log_scenario_fail_info
-  log "== "
-  log "Expected: #{expected}"
-  log "Got:      #{got}"
-  log
-  ['route','forw','backw'].each do |direction|
-    if attempts[direction]
-      attempts[direction]
-      log "Direction: #{direction}"
-      log "Query: #{attempts[direction][:query]}"
-      log "Response: #{attempts[direction][:response].body}"
-      log
-    end
-  end
-end
-
-
-def log_preprocess_info
-  return if @has_logged_preprocess_info
-  log "=========================================", :preprocess
-  log "Preprocessing data for scenario: #{@scenario_title}", :preprocess
-  log "Time: #{@scenario_time}", :preprocess
-  log '', :preprocess
-  log "== OSM data:", :preprocess
-  log '```xml', :preprocess #so output can be posted directly to github comment fields
-  log osm_str, :preprocess
-  log '```', :preprocess
-  log '', :preprocess
-  log "== Profile:", :preprocess
-  log @profile, :preprocess
-  log '', :preprocess
-  @has_logged_preprocess_info = true
-end
-
-def log_preprocess str
-  log_preprocess_info
-  log str, :preprocess
-end
-
-def log_preprocess_done
-end
diff --git a/features/support/osm_parser.rb b/features/support/osm_parser.rb
deleted file mode 100644
index 1da7c73..0000000
--- a/features/support/osm_parser.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require 'OSM/StreamParser'
-
-locations = nil
-
-class OSMTestParserCallbacks < OSM::Callbacks
-  locations = nil
-
-  def self.locations
-    if locations
-      locations
-    else
-      #parse the test file, so we can later reference nodes and ways by name in tests
-      locations = {}
-      file = 'test/data/test.osm'
-      callbacks = OSMTestParserCallbacks.new
-      parser = OSM::StreamParser.new(:filename => file, :callbacks => callbacks)
-      parser.parse
-      puts locations
-    end
-  end
-
-  def node(node)
-    locations[node.name] = [node.lat,node.lon]
-  end
-end
\ No newline at end of file
diff --git a/features/support/osmlib.rb b/features/support/osmlib.rb
deleted file mode 100644
index 6b03dfa..0000000
--- a/features/support/osmlib.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-#monkey-patch osmlib to fix a bug
-
-module OSM
-  class Way
-    def to_xml(xml)
-      xml.way(attributes) do
-        nodes.each do |node|
-          xml.nd(:ref => node)
-        end
-        tags.to_xml(xml)
-      end
-    end
-  end
-end
diff --git a/features/support/route.js b/features/support/route.js
new file mode 100644
index 0000000..7c208ff
--- /dev/null
+++ b/features/support/route.js
@@ -0,0 +1,166 @@
+var Timeout = require('node-timeout');
+var request = require('request');
+
+module.exports = function () {
+    this.requestPath = (service, params, callback) => {
+        var uri;
+        if (service == 'timestamp') {
+            uri = [this.HOST, service].join('/');
+        } else {
+            uri = [this.HOST, service, 'v1', this.profile].join('/');
+        }
+
+        return this.sendRequest(uri, params, callback);
+    };
+
+    this.requestUrl = (path, callback) => {
+        var uri = this.query = [this.HOST, path].join('/'),
+            limit = Timeout(this.OSRM_TIMEOUT, { err: { statusCode: 408 } });
+
+        function runRequest (cb) {
+            request(uri, cb);
+        }
+
+        runRequest(limit((err, res, body) => {
+            if (err) {
+                if (err.statusCode === 408) return callback(this.RoutedError('*** osrm-routed did not respond'));
+                else if (err.code === 'ECONNREFUSED')
+                    return callback(this.RoutedError('*** osrm-routed is not running'));
+            } else
+                return callback(err, res, body);
+        }));
+    };
+
+    // Overwrites the default values in defaults
+    // e.g. [[a, 1], [b, 2]], [[a, 5], [d, 10]] => [[a, 5], [b, 2], [d, 10]]
+    this.overwriteParams = (defaults, other) => {
+        var otherMap = {};
+        for (var key in other) otherMap[key] = other[key];
+        return Object.assign({}, defaults, otherMap);
+    };
+
+    var encodeWaypoints = (waypoints) => {
+        return waypoints.map(w => [w.lon, w.lat].map(this.ensureDecimal).join(','));
+    };
+
+    this.requestRoute = (waypoints, bearings, userParams, callback) => {
+        if (bearings.length && bearings.length !== waypoints.length) throw new Error('*** number of bearings does not equal the number of waypoints');
+
+        var defaults = {
+                output: 'json',
+                steps: 'true',
+                alternatives: 'false'
+            },
+            params = this.overwriteParams(defaults, userParams),
+            encodedWaypoints = encodeWaypoints(waypoints);
+
+        params.coordinates = encodedWaypoints;
+
+        if (bearings.length) {
+            params.bearings = bearings.map(b => {
+                var bs = b.split(',');
+                if (bs.length === 2) return b;
+                else return b += ',10';
+            }).join(';');
+        }
+
+        return this.requestPath('route', params, callback);
+    };
+
+    this.requestNearest = (node, userParams, callback) => {
+        var defaults = {
+                output: 'json'
+            },
+            params = this.overwriteParams(defaults, userParams);
+        params.coordinates = [[node.lon, node.lat].join(',')];
+
+        return this.requestPath('nearest', params, callback);
+    };
+
+    this.requestTable = (waypoints, userParams, callback) => {
+        var defaults = {
+                output: 'json'
+            },
+            params = this.overwriteParams(defaults, userParams);
+
+        params.coordinates = waypoints.map(w => [w.coord.lon, w.coord.lat].join(','));
+        var srcs = waypoints.map((w, i) => [w.type, i]).filter(w => w[0] === 'src').map(w => w[1]),
+            dsts = waypoints.map((w, i) => [w.type, i]).filter(w => w[0] === 'dst').map(w => w[1]);
+        if (srcs.length) params.sources = srcs.join(';');
+        if (dsts.length) params.destinations = dsts.join(';');
+
+        return this.requestPath('table', params, callback);
+    };
+
+    this.requestTrip = (waypoints, userParams, callback) => {
+        var defaults = {
+                output: 'json'
+            },
+            params = this.overwriteParams(defaults, userParams);
+
+        params.coordinates = encodeWaypoints(waypoints);
+
+        return this.requestPath('trip', params, callback);
+    };
+
+    this.requestMatching = (waypoints, timestamps, userParams, callback) => {
+        var defaults = {
+                output: 'json'
+            },
+            params = this.overwriteParams(defaults, userParams);
+
+        params.coordinates = encodeWaypoints(waypoints);
+
+        if (timestamps.length) {
+            params.timestamps = timestamps.join(';');
+        }
+
+        return this.requestPath('match', params, callback);
+    };
+
+    this.extractInstructionList = (instructions, keyFinder, postfix) => {
+        postfix = postfix || null;
+        if (instructions) {
+            return instructions.legs.reduce((m, v) => m.concat(v.steps), [])
+                .map(keyFinder)
+                .join(',');
+        }
+    };
+
+    this.wayList = (instructions) => {
+        return this.extractInstructionList(instructions, s => s.name);
+    };
+
+    this.bearingList = (instructions) => {
+        return this.extractInstructionList(instructions, s => s.maneuver.bearing_after);
+    };
+
+    this.turnList = (instructions) => {
+        return instructions.legs.reduce((m, v) => m.concat(v.steps), [])
+            .map(v => {
+                switch (v.maneuver.type) {
+                case 'depart':
+                case 'arrive':
+                    return v.maneuver.type;
+                case 'roundabout':
+                    return 'roundabout-exit-' + v.maneuver.exit;
+                // FIXME this is a little bit over-simplistic for merge/fork instructions
+                default:
+                    return v.maneuver.modifier;
+                }
+            })
+            .join(',');
+    };
+
+    this.modeList = (instructions) => {
+        return this.extractInstructionList(instructions, s => s.mode);
+    };
+
+    this.timeList = (instructions) => {
+        return this.extractInstructionList(instructions, s => s.duration + 's');
+    };
+
+    this.distanceList = (instructions) => {
+        return this.extractInstructionList(instructions, s => s.distance + 'm');
+    };
+};
diff --git a/features/support/route.rb b/features/support/route.rb
deleted file mode 100644
index 935c5be..0000000
--- a/features/support/route.rb
+++ /dev/null
@@ -1,181 +0,0 @@
-require 'net/http'
-
-HOST = "http://127.0.0.1:#{OSRM_PORT}"
-DESTINATION_REACHED = 15      #OSRM instruction code
-
-def request_path service, params
-  uri = "#{HOST}/" + service
-  response = send_request uri, params
-  return response
-end
-
-def request_url path
-  uri = URI.parse"#{HOST}/#{path}"
-  @query = uri.to_s
-  Timeout.timeout(OSRM_TIMEOUT) do
-    Net::HTTP.get_response uri
-  end
-rescue Errno::ECONNREFUSED => e
-  raise "*** osrm-routed is not running."
-rescue Timeout::Error
-  raise "*** osrm-routed did not respond."
-end
-
-# Overwriters the default values in defaults.
-# e.g. [[a, 1], [b, 2]], [[a, 5], [d, 10]] => [[a, 5], [b, 2], [d, 10]]
-def overwrite_params defaults, other
-  merged = []
-  defaults.each do |k,v|
-    idx = other.index { |p| p[0] == k }
-    if idx == nil then
-      merged << [k, v]
-    else
-      merged << [k, other[idx][1]]
-    end
-  end
-  other.each do |k,v|
-    if merged.index { |pair| pair[0] == k} == nil then
-      merged << [k, v]
-    end
-  end
-
-  return merged
-end
-
-def request_route waypoints, bearings, user_params
-  raise "*** number of bearings does not equal the number of waypoints" unless bearings.size == 0 || bearings.size == waypoints.size
-
-  defaults = [['output','json'], ['instructions',true], ['alt',false]]
-  params = overwrite_params defaults, user_params
-  encoded_waypoint = waypoints.map{ |w| ["loc","#{w.lat},#{w.lon}"] }
-  if bearings.size > 0
-    encoded_bearings = bearings.map { |b| ["b", b.to_s]}
-    parasm = params.concat encoded_waypoint.zip(encoded_bearings).flatten! 1
-  else
-    params = params.concat encoded_waypoint
-  end
-
-  return request_path "viaroute", params
-end
-
-def request_nearest node, user_params
-  defaults = [['output', 'json']]
-  params = overwrite_params defaults, user_params
-  params << ["loc", "#{node.lat},#{node.lon}"]
-
-  return request_path "nearest", params
-end
-
-def request_table waypoints, user_params
-  defaults = [['output', 'json']]
-  params = overwrite_params defaults, user_params
-  params = params.concat waypoints.map{ |w| [w[:type],"#{w[:coord].lat},#{w[:coord].lon}"] }
-
-  return request_path "table", params
-end
-
-def request_trip waypoints, user_params
-  defaults = [['output', 'json']]
-  params = overwrite_params defaults, user_params
-  params = params.concat waypoints.map{ |w| ["loc","#{w.lat},#{w.lon}"] }
-
-  return request_path "trip", params
-end
-
-def request_matching waypoints, timestamps, user_params
-  defaults = [['output', 'json']]
-  params = overwrite_params defaults, user_params
-  encoded_waypoint = waypoints.map{ |w| ["loc","#{w.lat},#{w.lon}"] }
-  if timestamps.size > 0
-    encoded_timestamps = timestamps.map { |t| ["t", t.to_s]}
-    parasm = params.concat encoded_waypoint.zip(encoded_timestamps).flatten! 1
-  else
-    params = params.concat encoded_waypoint
-  end
-
-  return request_path "match", params
-end
-
-def got_route? response
-  if response.code == "200" && !response.body.empty?
-    json = JSON.parse response.body
-    if json['status'] == 200
-      return way_list( json['route_instructions']).empty? == false
-    end
-  end
-  return false
-end
-
-def route_status response
-  if response.code == "200" && !response.body.empty?
-    json = JSON.parse response.body
-    return json['status']
-  else
-    "HTTP #{response.code}"
-  end
-end
-
-def extract_instruction_list instructions, index, postfix=nil
-  if instructions
-    instructions.reject { |r| r[0].to_s=="#{DESTINATION_REACHED}" }.
-    map { |r| r[index] }.
-    map { |r| (r=="" || r==nil) ? '""' : "#{r}#{postfix}" }.
-    join(',')
-  end
-end
-
-def way_list instructions
-  extract_instruction_list instructions, 1
-end
-
-def compass_list instructions
-  extract_instruction_list instructions, 6
-end
-
-def bearing_list instructions
-  extract_instruction_list instructions, 7
-end
-
-def turn_list instructions
-  if instructions
-    types = {
-      0 => :none,
-      1 => :straight,
-      2 => :slight_right,
-      3 => :right,
-      4 => :sharp_right,
-      5 => :u_turn,
-      6 => :sharp_left,
-      7 => :left,
-      8 => :slight_left,
-      9 => :via,
-      10 => :head,
-      11 => :enter_roundabout,
-      12 => :leave_roundabout,
-      13 => :stay_roundabout,
-      14 => :start_end_of_street,
-      15 => :destination,
-      16 => :enter_contraflow,
-      17 => :leave_contraflow
-    }
-    # replace instructions codes with strings
-    # "11-3" (enter roundabout and leave a 3rd exit) gets converted to "enter_roundabout-3"
-    instructions.map do |r|
-      r[0].to_s.gsub(/^\d*/) do |match|
-        types[match.to_i].to_s
-      end
-    end.join(',')
-  end
-end
-
-def mode_list instructions
-  extract_instruction_list instructions, 8
-end
-
-def time_list instructions
-  extract_instruction_list instructions, 4, "s"
-end
-
-def distance_list instructions
-  extract_instruction_list instructions, 2, "m"
-end
diff --git a/features/support/run.js b/features/support/run.js
new file mode 100644
index 0000000..cede245
--- /dev/null
+++ b/features/support/run.js
@@ -0,0 +1,40 @@
+var fs = require('fs');
+var util = require('util');
+var exec = require('child_process').exec;
+
+module.exports = function () {
+    this.runBin = (bin, options, callback) => {
+        var opts = options.slice();
+
+        if (opts.match('{osm_base}')) {
+            if (!this.osmData.osmFile) throw new Error('*** {osm_base} is missing');
+            opts = opts.replace('{osm_base}', this.osmData.osmFile);
+        }
+
+        if (opts.match('{extracted_base}')) {
+            if (!this.osmData.extractedFile) throw new Error('*** {extracted_base} is missing');
+            opts = opts.replace('{extracted_base}', this.osmData.extractedFile);
+        }
+
+        if (opts.match('{contracted_base}')) {
+            if (!this.osmData.contractedFile) throw new Error('*** {contracted_base} is missing');
+            opts = opts.replace('{contracted_base}', this.osmData.contractedFile);
+        }
+
+        if (opts.match('{profile}')) {
+            opts = opts.replace('{profile}', [this.PROFILES_PATH, this.profile + '.lua'].join('/'));
+        }
+
+        var cmd = util.format('%s%s%s/%s%s%s %s 2>%s', this.QQ, this.LOAD_LIBRARIES, this.BIN_PATH, bin, this.EXE, this.QQ, opts, this.ERROR_LOG_FILE);
+        process.chdir(this.TEST_FOLDER);
+        exec(cmd, (err, stdout, stderr) => {
+            this.stdout = stdout.toString();
+            fs.readFile(this.ERROR_LOG_FILE, (e, data) => {
+                this.stderr = data ? data.toString() : '';
+                this.exitCode = err && err.code || 0;
+                process.chdir('../');
+                callback(err, stdout, stderr);
+            });
+        });
+    };
+};
diff --git a/features/support/run.rb b/features/support/run.rb
deleted file mode 100644
index 42dc597..0000000
--- a/features/support/run.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-def run_bin bin, options
-  Dir.chdir TEST_FOLDER do
-    opt = options.dup
-
-    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
-
-    cmd = "#{QQ}#{BIN_PATH}/#{bin}#{EXE}#{QQ} #{opt} 2>error.log"
-    @stdout = `#{cmd}`
-    @stderr = File.read 'error.log'
-    @exit_code = $?.exitstatus
-  end
-end
\ No newline at end of file
diff --git a/features/support/shared_steps.js b/features/support/shared_steps.js
new file mode 100644
index 0000000..5751492
--- /dev/null
+++ b/features/support/shared_steps.js
@@ -0,0 +1,202 @@
+var util = require('util');
+var assert = require('assert');
+
+module.exports = function () {
+    this.ShouldGetAResponse = () => {
+        assert.equal(this.response.statusCode, 200);
+        assert.ok(this.response.body);
+        assert.ok(this.response.body.length);
+    };
+
+    this.ShouldBeValidJSON = (callback) => {
+        try {
+            this.json = JSON.parse(this.response.body);
+            callback();
+        } catch (e) {
+            callback(e);
+        }
+    };
+
+    this.ShouldBeWellFormed = () => {
+        assert.equal(typeof this.json.status, 'number');
+    };
+
+    this.WhenIRouteIShouldGet = (table, callback) => {
+        this.reprocessAndLoadData(() => {
+            var headers = new Set(table.raw()[0]);
+
+            var requestRow = (row, ri, cb) => {
+                var got;
+
+                var afterRequest = (err, res, body) => {
+                    if (err) return cb(err);
+                    if (body && body.length) {
+                        var instructions, bearings, turns, modes, times, distances;
+
+                        var json = JSON.parse(body);
+
+                        var hasRoute = json.code === 'ok';
+
+                        if (hasRoute) {
+                            instructions = this.wayList(json.routes[0]);
+                            bearings = this.bearingList(json.routes[0]);
+                            turns = this.turnList(json.routes[0]);
+                            modes = this.modeList(json.routes[0]);
+                            times = this.timeList(json.routes[0]);
+                            distances = this.distanceList(json.routes[0]);
+                        }
+
+                        if (headers.has('status')) {
+                            got.status = res.statusCode.toString();
+                        }
+
+                        if (headers.has('message')) {
+                            got.message = json.message || '';
+                        }
+
+                        if (headers.has('#')) {
+                            // comment column
+                            got['#'] = row['#'];
+                        }
+
+                        if (headers.has('start')) {
+                            got.start = instructions ? json.route_summary.start_point : null;
+                        }
+
+                        if (headers.has('end')) {
+                            got.end = instructions ? json.route_summary.end_point : null;
+                        }
+
+                        if (headers.has('geometry')) {
+                            got.geometry = json.routes[0].geometry;
+                        }
+
+                        if (headers.has('route')) {
+                            got.route = (instructions || '').trim();
+
+                            if (headers.has('alternative')) {
+                                // TODO examine more than first alternative?
+                                got.alternative ='';
+                                if (json.routes && json.routes.length > 1)
+                                    got.alternative = this.wayList(json.routes[1]);
+                            }
+
+                            var distance = hasRoute && json.routes[0].distance,
+                                time = hasRoute && json.routes[0].duration;
+
+                            if (headers.has('distance')) {
+                                if (row.distance.length) {
+                                    if (!row.distance.match(/\d+m/))
+                                        throw new Error('*** Distance must be specified in meters. (ex: 250m)');
+                                    got.distance = instructions ? util.format('%dm', distance) : '';
+                                } else {
+                                    got.distance = '';
+                                }
+                            }
+
+                            if (headers.has('time')) {
+                                if (!row.time.match(/\d+s/))
+                                    throw new Error('*** Time must be specied in seconds. (ex: 60s)');
+                                got.time = instructions ? util.format('%ds', time) : '';
+                            }
+
+                            if (headers.has('speed')) {
+                                if (row.speed !== '' && instructions) {
+                                    if (!row.speed.match(/\d+ km\/h/))
+                                        throw new Error('*** Speed must be specied in km/h. (ex: 50 km/h)');
+                                    var speed = time > 0 ? Math.round(3.6*distance/time) : null;
+                                    got.speed = util.format('%d km/h', speed);
+                                } else {
+                                    got.speed = '';
+                                }
+                            }
+
+                            var putValue = (key, value) => {
+                                if (headers.has(key)) got[key] = instructions ? value : '';
+                            };
+
+                            putValue('bearing', bearings);
+                            putValue('turns', turns);
+                            putValue('modes', modes);
+                            putValue('times', times);
+                            putValue('distances', distances);
+                        }
+
+                        var ok = true;
+
+                        for (var key in row) {
+                            if (this.FuzzyMatch.match(got[key], row[key])) {
+                                got[key] = row[key];
+                            } else {
+                                ok = false;
+                            }
+                        }
+
+                        if (!ok) {
+                            this.logFail(row, got, { route: { query: this.query, response: res }});
+                        }
+
+                        cb(null, got);
+                    } else {
+                        cb(new Error('request failed to return valid body'));
+                    }
+                };
+
+                if (headers.has('request')) {
+                    got = { request: row.request };
+                    this.requestUrl(row.request, afterRequest);
+                } else {
+                    var defaultParams = this.queryParams;
+                    var userParams = [];
+                    got = {};
+                    for (var k in row) {
+                        var match = k.match(/param:(.*)/);
+                        if (match) {
+                            if (row[k] === '(nil)') {
+                                userParams.push([match[1], null]);
+                            } else if (row[k]) {
+                                userParams.push([match[1], row[k]]);
+                            }
+                            got[k] = row[k];
+                        }
+                    }
+
+                    var params = this.overwriteParams(defaultParams, userParams),
+                        waypoints = [],
+                        bearings = [];
+
+                    if (row.bearings) {
+                        got.bearings = row.bearings;
+                        bearings = row.bearings.split(' ').filter(b => !!b);
+                    }
+
+                    if (row.from && row.to) {
+                        var fromNode = this.findNodeByName(row.from);
+                        if (!fromNode) throw new Error(util.format('*** unknown from-node "%s"'), row.from);
+                        waypoints.push(fromNode);
+
+                        var toNode = this.findNodeByName(row.to);
+                        if (!toNode) throw new Error(util.format('*** unknown to-node "%s"'), row.to);
+                        waypoints.push(toNode);
+
+                        got.from = row.from;
+                        got.to = row.to;
+                        this.requestRoute(waypoints, bearings, params, afterRequest);
+                    } else if (row.waypoints) {
+                        row.waypoints.split(',').forEach((n) => {
+                            var node = this.findNodeByName(n.trim());
+                            if (!node) throw new Error('*** unknown waypoint node "%s"', n.trim());
+                            waypoints.push(node);
+                        });
+                        got.waypoints = row.waypoints;
+                        this.requestRoute(waypoints, bearings, params, afterRequest);
+                    } else {
+                        throw new Error('*** no waypoints');
+                    }
+                }
+            };
+
+            this.processRowsAndDiff(table, requestRow, callback);
+        });
+    };
+};
diff --git a/features/support/shortcuts.rb b/features/support/shortcuts.rb
deleted file mode 100644
index 20bc3c0..0000000
--- a/features/support/shortcuts.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-def shortcuts_hash
-  @shortcuts_hash ||= {}
-end
diff --git a/features/support/table_patch.js b/features/support/table_patch.js
new file mode 100644
index 0000000..16ffebb
--- /dev/null
+++ b/features/support/table_patch.js
@@ -0,0 +1,11 @@
+var DifferentError = require('./exception_classes').TableDiffError;
+
+module.exports = function () {
+    this.diffTables = (expected, actual, options, callback) => {
+        // this is a temp workaround while waiting for https://github.com/cucumber/cucumber-js/issues/534
+
+        var error = new DifferentError(expected, actual);
+
+        return callback(error.string);
+    };
+};
diff --git a/features/testbot/64bit.feature b/features/testbot/64bit.feature
index d2d0c8a..83ca884 100644
--- a/features/testbot/64bit.feature
+++ b/features/testbot/64bit.feature
@@ -19,5 +19,5 @@ Feature: Support 64bit node IDs
             | cdec  |
 
         When I route I should get
-            | from | to | route | turns            |
-            | x    | y  | abc   | head,destination |
+            | from | to | route   | turns         |
+            | x    | y  | abc,abc | depart,arrive |
diff --git a/features/testbot/alternative.feature b/features/testbot/alternative.feature
index d6ca030..4031631 100644
--- a/features/testbot/alternative.feature
+++ b/features/testbot/alternative.feature
@@ -6,7 +6,7 @@ Feature: Alternative route
 
         And the node map
             |   | b | c | d |   |   |
-            | a |   |   |   |   | z |
+            | a |   | k |   |   | z |
             |   | g | h | i | j |   |
 
         And the ways
@@ -20,19 +20,21 @@ Feature: Alternative route
             | hi    |
             | ij    |
             | jz    |
+            | ck    |
+            | kh    |
 
     Scenario: Enabled alternative
         Given the query options
-            | alt | true |
+            | alternatives | true |
 
         When I route I should get
-            | from | to | route       | alternative    |
-            | a    | z  | ab,bc,cd,dz | ag,gh,hi,ij,jz |
+            | from | to | route          | alternative       |
+            | a    | z  | ab,bc,cd,dz,dz | ag,gh,hi,ij,jz,jz |
 
     Scenario: Disabled alternative
         Given the query options
-            | alt | false |
+            | alternatives | false |
 
         When I route I should get
-            | from | to | route       | alternative |
-            | a    | z  | ab,bc,cd,dz |             |
+            | from | to | route          | alternative |
+            | a    | z  | ab,bc,cd,dz,dz |             |
diff --git a/features/testbot/alternative_loop.feature b/features/testbot/alternative_loop.feature
new file mode 100644
index 0000000..159a399
--- /dev/null
+++ b/features/testbot/alternative_loop.feature
@@ -0,0 +1,29 @@
+ at routing @testbot @alternative
+Feature: Alternative route
+
+    Background:
+        Given the profile "testbot"
+
+    Scenario: Alternative Loop Paths
+        Given the node map
+            | a | 2 | 1 | b |
+            | 7 |   |   | 4 |
+            | 8 |   |   | 3 |
+            | c | 5 | 6 | d |
+
+        And the ways
+            | nodes | oneway |
+            | ab    | yes    |
+            | bd    | yes    |
+            | dc    | yes    |
+            | ca    | yes    |
+
+        And the query options
+            | alternatives | true |
+
+        When I route I should get
+            | from | to | route             | alternative |
+            | 1    | 2  | ab,bd,dc,ca,ab,ab |             |
+            | 3    | 4  | bd,dc,ca,ab,bd,bd |             |
+            | 5    | 6  | dc,ca,ab,bd,dc,dc |             |
+            | 7    | 8  | ca,ab,bd,dc,ca,ca |             |
diff --git a/features/testbot/bad.feature b/features/testbot/bad.feature
index d7e3c95..18ee5f8 100644
--- a/features/testbot/bad.feature
+++ b/features/testbot/bad.feature
@@ -11,7 +11,7 @@ Feature: Handle bad data in a graceful manner
         Given the ways
             | nodes |
 
-        When the data has been prepared
+        When the data has been contracted
         Then "osrm-extract" should return code 1
 
     Scenario: Only dead-end oneways
@@ -23,8 +23,8 @@ Feature: Handle bad data in a graceful manner
             | abcde | yes    |
 
         When I route I should get
-            | from | to | route |
-            | b    | d  | abcde |
+            | from | to | route       |
+            | b    | d  | abcde,abcde |
 
     @todo
     Scenario: Start/end point at the same location
@@ -78,7 +78,7 @@ Feature: Handle bad data in a graceful manner
         # | b    | c  | cd    |
         # | a    | d  | cd    |
         # | c    | d  | cd    |
-            | d    | e  | de    |
+            | d    | e  | de,de |
         # | k    | l  | kl    |
         # | l    | m  | lm    |
         # | o    | l  | lm    |
diff --git a/features/testbot/basic.feature b/features/testbot/basic.feature
index 599b062..c2f969d 100644
--- a/features/testbot/basic.feature
+++ b/features/testbot/basic.feature
@@ -14,9 +14,9 @@ Feature: Basic Routing
             | ab    |
 
         When I route I should get
-            | from | to | route |
-            | a    | b  | ab    |
-            | b    | a  | ab    |
+            | from | to | route    |
+            | a    | b  | ab,ab    |
+            | b    | a  | ab,ab    |
 
     Scenario: Routing in between two nodes of way
         Given the node map
@@ -27,9 +27,9 @@ Feature: Basic Routing
             | abcd  |
 
         When I route I should get
-            | from | to | route |
-            | 1    | 2  | abcd  |
-            | 2    | 1  | abcd  |
+            | from | to | route      |
+            | 1    | 2  | abcd,abcd  |
+            | 2    | 1  | abcd,abcd  |
 
     Scenario: Routing between the middle nodes of way
         Given the node map
@@ -40,19 +40,19 @@ Feature: Basic Routing
             | abcdef |
 
         When I route I should get
-            | from | to | route  |
-            | b    | c  | abcdef |
-            | b    | d  | abcdef |
-            | b    | e  | abcdef |
-            | c    | b  | abcdef |
-            | c    | d  | abcdef |
-            | c    | e  | abcdef |
-            | d    | b  | abcdef |
-            | d    | c  | abcdef |
-            | d    | e  | abcdef |
-            | e    | b  | abcdef |
-            | e    | c  | abcdef |
-            | e    | d  | abcdef |
+            | from | to | route         |
+            | b    | c  | abcdef,abcdef |
+            | b    | d  | abcdef,abcdef |
+            | b    | e  | abcdef,abcdef |
+            | c    | b  | abcdef,abcdef |
+            | c    | d  | abcdef,abcdef |
+            | c    | e  | abcdef,abcdef |
+            | d    | b  | abcdef,abcdef |
+            | d    | c  | abcdef,abcdef |
+            | d    | e  | abcdef,abcdef |
+            | e    | b  | abcdef,abcdef |
+            | e    | c  | abcdef,abcdef |
+            | e    | d  | abcdef,abcdef |
 
     Scenario: Two ways connected in a straight line
         Given the node map
@@ -64,13 +64,13 @@ Feature: Basic Routing
             | bc    |
 
         When I route I should get
-            | from | to | route |
-            | a    | c  | ab,bc |
-            | c    | a  | bc,ab |
-            | a    | b  | ab    |
-            | b    | a  | ab    |
-            | b    | c  | bc    |
-            | c    | b  | bc    |
+            | from | to | route    |
+            | a    | c  | ab,bc,bc |
+            | c    | a  | bc,ab,ab |
+            | a    | b  | ab,ab    |
+            | b    | a  | ab,ab    |
+            | b    | c  | bc,bc    |
+            | c    | b  | bc,bc    |
 
     Scenario: 2 unconnected parallel ways
         Given the node map
@@ -83,33 +83,33 @@ Feature: Basic Routing
             | def   |
 
         When I route I should get
-            | from | to | route |
-            | a    | b  | abc   |
-            | b    | a  | abc   |
-            | b    | c  | abc   |
-            | c    | b  | abc   |
-            | d    | e  | def   |
-            | e    | d  | def   |
-            | e    | f  | def   |
-            | f    | e  | def   |
-            | a    | d  |       |
-            | d    | a  |       |
-            | b    | d  |       |
-            | d    | b  |       |
-            | c    | d  |       |
-            | d    | c  |       |
-            | a    | e  |       |
-            | e    | a  |       |
-            | b    | e  |       |
-            | e    | b  |       |
-            | c    | e  |       |
-            | e    | c  |       |
-            | a    | f  |       |
-            | f    | a  |       |
-            | b    | f  |       |
-            | f    | b  |       |
-            | c    | f  |       |
-            | f    | c  |       |
+            | from | to | route   |
+            | a    | b  | abc,abc |
+            | b    | a  | abc,abc |
+            | b    | c  | abc,abc |
+            | c    | b  | abc,abc |
+            | d    | e  | def,def |
+            | e    | d  | def,def |
+            | e    | f  | def,def |
+            | f    | e  | def,def |
+            | a    | d  |         |
+            | d    | a  |         |
+            | b    | d  |         |
+            | d    | b  |         |
+            | c    | d  |         |
+            | d    | c  |         |
+            | a    | e  |         |
+            | e    | a  |         |
+            | b    | e  |         |
+            | e    | b  |         |
+            | c    | e  |         |
+            | e    | c  |         |
+            | a    | f  |         |
+            | f    | a  |         |
+            | b    | f  |         |
+            | f    | b  |         |
+            | c    | f  |         |
+            | f    | c  |         |
 
     Scenario: 3 ways connected in a triangle
         Given the node map
@@ -124,13 +124,13 @@ Feature: Basic Routing
             | ca    |
 
         When I route I should get
-            | from | to | route |
-            | a    | b  | ab    |
-            | a    | c  | ca    |
-            | b    | c  | bc    |
-            | b    | a  | ab    |
-            | c    | a  | ca    |
-            | c    | b  | bc    |
+            | from | to | route  |
+            | a    | b  | ab,ab  |
+            | a    | c  | ca,ca  |
+            | b    | c  | bc,bc  |
+            | b    | a  | ab,ab  |
+            | c    | a  | ca,ca  |
+            | c    | b  | bc,bc  |
 
     Scenario: 3 connected triangles
         Given a grid size of 100 meters
@@ -157,12 +157,12 @@ Feature: Basic Routing
 
         When I route I should get
             | from | to | route |
-            | a    | b  | ab    |
-            | a    | c  | ca    |
-            | b    | c  | bc    |
-            | b    | a  | ab    |
-            | c    | a  | ca    |
-            | c    | b  | bc    |
+            | a    | b  | ab,ab |
+            | a    | c  | ca,ca |
+            | b    | c  | bc,bc |
+            | b    | a  | ab,ab |
+            | c    | a  | ca,ca |
+            | c    | b  | bc,bc |
 
     Scenario: To ways connected at a 45 degree angle
         Given the node map
@@ -176,13 +176,13 @@ Feature: Basic Routing
             | cde   |
 
         When I route I should get
-            | from | to | route   |
-            | b    | d  | abc,cde |
-            | a    | e  | abc,cde |
-            | a    | c  | abc     |
-            | c    | a  | abc     |
-            | c    | e  | cde     |
-            | e    | c  | cde     |
+            | from | to | route       |
+            | b    | d  | abc,cde,cde |
+            | a    | e  | abc,cde,cde |
+            | a    | c  | abc,abc     |
+            | c    | a  | abc,abc     |
+            | c    | e  | cde,cde     |
+            | e    | c  | cde,cde     |
 
     Scenario: Grid city center
         Given the node map
@@ -203,11 +203,11 @@ Feature: Basic Routing
             | dhlp  |
 
         When I route I should get
-            | from | to | route |
-            | f    | g  | efgh  |
-            | g    | f  | efgh  |
-            | f    | j  | bfjn  |
-            | j    | f  | bfjn  |
+            | from | to | route     |
+            | f    | g  | efgh,efgh |
+            | g    | f  | efgh,efgh |
+            | f    | j  | bfjn,bfjn |
+            | j    | f  | bfjn,bfjn |
 
     Scenario: Grid city periphery
         Given the node map
@@ -228,11 +228,11 @@ Feature: Basic Routing
             | dhlp  |
 
         When I route I should get
-            | from | to | route |
-            | a    | d  | abcd  |
-            | d    | a  | abcd  |
-            | a    | m  | aeim  |
-            | m    | a  | aeim  |
+            | from | to | route      |
+            | a    | d  | abcd,abcd  |
+            | d    | a  | abcd,abcd  |
+            | a    | m  | aeim,aeim  |
+            | m    | a  | aeim,aeim  |
     
     Scenario: Testbot - Triangle challenge
         Given the node map
@@ -249,5 +249,5 @@ Feature: Basic Routing
 
         When I route I should get
             | from | to | route |
-            | d    | c  | de,ce |
-            | e    | d  | de    |
+            | d    | c  | de,ce,ce |
+            | e    | d  | de,de    |
diff --git a/features/testbot/bearing.feature b/features/testbot/bearing.feature
index 9b3dc4e..76a2819 100644
--- a/features/testbot/bearing.feature
+++ b/features/testbot/bearing.feature
@@ -14,8 +14,8 @@ Feature: Compass bearing
             | ab    |
 
         When I route I should get
-            | from | to | route | compass | bearing |
-            | a    | b  | ab    | NW      | 315     |
+            | from | to | route    | bearing   |
+            | a    | b  | ab,ab    | 315,0     |
 
     Scenario: Bearing when going west
         Given the node map
@@ -26,8 +26,8 @@ Feature: Compass bearing
             | ab    |
 
         When I route I should get
-            | from | to | route | compass | bearing |
-            | a    | b  | ab    | W       | 270     |
+            | from | to | route    | bearing |
+            | a    | b  | ab,ab    | 270,0   |
 
     Scenario: Bearing af 45 degree intervals
         Given the node map
@@ -47,15 +47,15 @@ Feature: Compass bearing
             | xh    |
 
         When I route I should get
-            | from | to | route | compass | bearing |
-            | x    | a  | xa    | N       | 0       |
-            | x    | b  | xb    | NW      | 315     |
-            | x    | c  | xc    | W       | 270     |
-            | x    | d  | xd    | SW      | 225     |
-            | x    | e  | xe    | S       | 180     |
-            | x    | f  | xf    | SE      | 135     |
-            | x    | g  | xg    | E       | 90      |
-            | x    | h  | xh    | NE      | 45      |
+            | from | to | route    | bearing |
+            | x    | a  | xa,xa    | 0,0     |
+            | x    | b  | xb,xb    | 315,0   |
+            | x    | c  | xc,xc    | 270,0   |
+            | x    | d  | xd,xd    | 225,0   |
+            | x    | e  | xe,xe    | 180,0   |
+            | x    | f  | xf,xf    | 135,0   |
+            | x    | g  | xg,xg    | 90,0    |
+            | x    | h  | xh,xh    | 45,0    |
 
     Scenario: Bearing in a roundabout
         Given the node map
@@ -76,9 +76,9 @@ Feature: Compass bearing
             | ha    | yes    |
 
         When I route I should get
-            | from | to | route                | compass          | bearing                 |
-            | c    | b  | cd,de,ef,fg,gh,ha,ab | W,SW,S,SE,E,NE,N | 270,225,180,135,90,45,0 |
-            | g    | f  | gh,ha,ab,bc,cd,de,ef | E,NE,N,NW,W,SW,S | 90,45,0,315,270,225,180 |
+            | from | to | route                   | bearing                   |
+            | c    | b  | cd,de,ef,fg,gh,ha,ab,ab | 270,225,180,135,90,45,0,0 |
+            | g    | f  | gh,ha,ab,bc,cd,de,ef,ef | 90,45,0,315,270,225,180,0 |
 
     Scenario: Bearing should stay constant when zig-zagging
         Given the node map
@@ -96,8 +96,8 @@ Feature: Compass bearing
             | gh    |
 
         When I route I should get
-            | from | to | route                | compass          | bearing             |
-            | a    | h  | ab,bc,cd,de,ef,fg,gh | N,SE,N,SE,N,SE,N | 0,135,0,135,0,135,0 |
+            | from | to | route                   | bearing               |
+            | a    | h  | ab,bc,cd,de,ef,fg,gh,gh | 0,135,0,135,0,135,0,0 |
 
     Scenario: Bearings on an east-west way.
         Given the node map
@@ -108,37 +108,37 @@ Feature: Compass bearing
             | abcdef |
 
         When I route I should get
-            | from | to | route  | compass | bearing |
-            | a    | b  | abcdef | E       | 90      |
-            | a    | c  | abcdef | E       | 90      |
-            | a    | d  | abcdef | E       | 90      |
-            | a    | e  | abcdef | E       | 90      |
-            | a    | f  | abcdef | E       | 90      |
-            | b    | a  | abcdef | W       | 270     |
-            | b    | c  | abcdef | E       | 90      |
-            | b    | d  | abcdef | E       | 90      |
-            | b    | e  | abcdef | E       | 90      |
-            | b    | f  | abcdef | E       | 90      |
-            | c    | a  | abcdef | W       | 270     |
-            | c    | b  | abcdef | W       | 270     |
-            | c    | d  | abcdef | E       | 90      |
-            | c    | e  | abcdef | E       | 90      |
-            | c    | f  | abcdef | E       | 90      |
-            | d    | a  | abcdef | W       | 270     |
-            | d    | b  | abcdef | W       | 270     |
-            | d    | c  | abcdef | W       | 270     |
-            | d    | e  | abcdef | E       | 90      |
-            | d    | f  | abcdef | E       | 90      |
-            | e    | a  | abcdef | W       | 270     |
-            | e    | b  | abcdef | W       | 270     |
-            | e    | c  | abcdef | W       | 270     |
-            | e    | d  | abcdef | W       | 270     |
-            | e    | f  | abcdef | E       | 90      |
-            | f    | a  | abcdef | W       | 270     |
-            | f    | b  | abcdef | W       | 270     |
-            | f    | c  | abcdef | W       | 270     |
-            | f    | d  | abcdef | W       | 270     |
-            | f    | e  | abcdef | W       | 270     |
+            | from | to | route         | bearing |
+            | a    | b  | abcdef,abcdef | 90,0    |
+            | a    | c  | abcdef,abcdef | 90,0    |
+            | a    | d  | abcdef,abcdef | 90,0    |
+            | a    | e  | abcdef,abcdef | 90,0    |
+            | a    | f  | abcdef,abcdef | 90,0    |
+            | b    | a  | abcdef,abcdef | 270,0   |
+            | b    | c  | abcdef,abcdef | 90,0    |
+            | b    | d  | abcdef,abcdef | 90,0    |
+            | b    | e  | abcdef,abcdef | 90,0    |
+            | b    | f  | abcdef,abcdef | 90,0    |
+            | c    | a  | abcdef,abcdef | 270,0   |
+            | c    | b  | abcdef,abcdef | 270,0   |
+            | c    | d  | abcdef,abcdef | 90,0    |
+            | c    | e  | abcdef,abcdef | 90,0    |
+            | c    | f  | abcdef,abcdef | 90,0    |
+            | d    | a  | abcdef,abcdef | 270,0   |
+            | d    | b  | abcdef,abcdef | 270,0   |
+            | d    | c  | abcdef,abcdef | 270,0   |
+            | d    | e  | abcdef,abcdef | 90,0    |
+            | d    | f  | abcdef,abcdef | 90,0    |
+            | e    | a  | abcdef,abcdef | 270,0   |
+            | e    | b  | abcdef,abcdef | 270,0   |
+            | e    | c  | abcdef,abcdef | 270,0   |
+            | e    | d  | abcdef,abcdef | 270,0   |
+            | e    | f  | abcdef,abcdef | 90,0    |
+            | f    | a  | abcdef,abcdef | 270,0   |
+            | f    | b  | abcdef,abcdef | 270,0   |
+            | f    | c  | abcdef,abcdef | 270,0   |
+            | f    | d  | abcdef,abcdef | 270,0   |
+            | f    | e  | abcdef,abcdef | 270,0   |
 
     Scenario: Bearings at high latitudes
     # The coordinas below was calculated using http://www.movable-type.co.uk/scripts/latlong.html,
@@ -161,19 +161,19 @@ Feature: Compass bearing
             | bd    |
 
         When I route I should get
-            | from | to | route | compass | bearing |
-            | a    | b  | ab    | N       | 0       |
-            | b    | c  | bc    | E       | 90      |
-            | c    | d  | cd    | S       | 180     |
-            | d    | a  | da    | W       | 270     |
-            | b    | a  | ab    | S       | 180     |
-            | c    | b  | bc    | W       | 270     |
-            | d    | c  | cd    | N       | 0       |
-            | a    | d  | da    | E       | 90      |
-            | a    | c  | ac    | NE      | 45      |
-            | c    | a  | ac    | SW      | 225     |
-            | b    | d  | bd    | SE      | 135     |
-            | d    | b  | bd    | NW      | 315     |
+            | from | to | route | bearing |
+            | a    | b  | ab,ab | 0,0     |
+            | b    | c  | bc,bc | 90,0    |
+            | c    | d  | cd,cd | 180,0   |
+            | d    | a  | da,da | 270,0   |
+            | b    | a  | ab,ab | 180,0   |
+            | c    | b  | bc,bc | 270,0   |
+            | d    | c  | cd,cd | 0,0     |
+            | a    | d  | da,da | 90,0    |
+            | a    | c  | ac,ac | 45,0    |
+            | c    | a  | ac,ac | 225,0   |
+            | b    | d  | bd,bd | 135,0   |
+            | d    | b  | bd,bd | 315,0   |
 
     Scenario: Bearings at high negative latitudes
     # The coordinas below was calculated using http://www.movable-type.co.uk/scripts/latlong.html,
@@ -196,16 +196,16 @@ Feature: Compass bearing
             | bd    |
 
         When I route I should get
-            | from | to | route | compass | bearing |
-            | a    | b  | ab    | S       | 180     |
-            | b    | c  | bc    | E       | 90      |
-            | c    | d  | cd    | N       | 0       |
-            | d    | a  | da    | W       | 270     |
-            | b    | a  | ab    | N       | 0       |
-            | c    | b  | bc    | W       | 270     |
-            | d    | c  | cd    | S       | 180     |
-            | a    | d  | da    | E       | 90      |
-            | a    | c  | ac    | SE      | 135     |
-            | c    | a  | ac    | NW      | 315     |
-            | b    | d  | bd    | NE      | 45      |
-            | d    | b  | bd    | SW      | 225     |
+            | from | to | route  | bearing |
+            | a    | b  | ab,ab  | 180,0   |
+            | b    | c  | bc,bc  | 90,0    |
+            | c    | d  | cd,cd  | 0,0     |
+            | d    | a  | da,da  | 270,0   |
+            | b    | a  | ab,ab  | 0,0     |
+            | c    | b  | bc,bc  | 270,0   |
+            | d    | c  | cd,cd  | 180,0   |
+            | a    | d  | da,da  | 90,0    |
+            | a    | c  | ac,ac  | 135,0   |
+            | c    | a  | ac,ac  | 315,0   |
+            | b    | d  | bd,bd  | 45,0    |
+            | d    | b  | bd,bd  | 225,0   |
diff --git a/features/testbot/bearing_param.feature b/features/testbot/bearing_param.feature
index 1efa817..ea60856 100644
--- a/features/testbot/bearing_param.feature
+++ b/features/testbot/bearing_param.feature
@@ -15,11 +15,11 @@ Feature: Bearing parameter
 
         When I route I should get
             | from | to | bearings  | route | bearing |
-            | b    | c  | 90 90     | ad    | 90      |
+            | b    | c  | 90 90     | ad,ad | 90,0    |
             | b    | c  | 180 90    |       |         |
-            | b    | c  | 80 100    | ad    | 90      |
+            | b    | c  | 80 100    | ad,ad | 90,0    |
             | b    | c  | 79 100    |       |         |
-            | b    | c  | 79,11 100 | ad    | 90      |
+            | b    | c  | 79,11 100 | ad,ad | 90,0    |
 
     Scenario: Testbot - Intial bearing in simple case
         Given the node map
@@ -35,10 +35,10 @@ Feature: Bearing parameter
         When I route I should get
             | from | to | bearings | route | bearing |
             | 0    | c  | 0 0      |       |         |
-            | 0    | c  | 45 45    | bc    | 45 ~3%   |
+            | 0    | c  | 45 45    | bc,bc | 45 ~3%  |
             | 0    | c  | 85 85    |       |         |
             | 0    | c  | 95 95    |       |         |
-            | 0    | c  | 135 135  | ac    | 135 ~1%  |
+            | 0    | c  | 135 135  | ac,ac | 135 ~1% |
             | 0    | c  | 180 180  |       |         |
 
     Scenario: Testbot - Initial bearing on split way
@@ -55,19 +55,19 @@ Feature: Bearing parameter
 
         When I route I should get
             | from | to | bearings | route       | bearing       |
-            | 0    | b  | 10 10    | bc          | 0             |
-            | 0    | b  | 90 90    | ab          | 90            |
+            | 0    | b  | 10 10    | bc,bc       | 0,0            |
+            | 0    | b  | 90 90    | ab,ab       | 90,0           |
             # The returned bearing is wrong here, it's based on the snapped
             # coordinates, not the acutal edge bearing.  This should be
-            # fixed one day, but it's only a problem when we snap too vias
+            # fixed one day, but it's only a problem when we snap two vias
             # to the same point - DP
             #| 0    | b  | 170 170  | da          | 180           |
             #| 0    | b  | 189 189  | da          | 180           |
-            | 0    | 1  | 90 270   | ab,bc,cd    | 90,0,270      |
-            | 1    | d  | 10 10    | bc          | 0             |
-            | 1    | d  | 90 90    | ab,bc,cd,da | 90,0,270,180  |
-            | 1    | 0  | 189 189  | da          | 180           |
-            | 1    | d  | 270 270  | cd          | 270           |
+            | 0    | 1  | 90 270   | ab,bc,cd,cd    | 90,0,270,0      |
+            | 1    | d  | 10 10    | bc,bc          | 0,0             |
+            | 1    | d  | 90 90    | ab,bc,cd,da,da | 90,0,270,180,0  |
+            | 1    | 0  | 189 189  | da,da       | 180,0           |
+            | 1    | d  | 270 270  | cd,cd       | 270,0           |
             | 1    | d  | 349 349  |             |               |
 
     Scenario: Testbot - Initial bearing in all direction
@@ -100,12 +100,12 @@ Feature: Bearing parameter
             | ha    | yes    |
 
         When I route I should get
-            | from | to | bearings | route                      | bearing                     |
-            | 0    | q  | 0 90     | ia,ab,bc,cd,de,ef,fg,gh,ha | 0,90,180,180,270,270,0,0,90 |
-            | 0    | a  | 45 90    | jb,bc,cd,de,ef,fg,gh,ha    | 45,180,180,270,270,0,0,90   |
-            | 0    | q  | 90 90    | kc,cd,de,ef,fg,gh,ha       | 90,180,270,270,0,0,90       |
-            | 0    | a  | 135 90   | ld,de,ef,fg,gh,ha          | 135,270,270,0,0,90          |
-            | 0    | a  | 180 90   | me,ef,fg,gh,ha             | 180,270,0,0,90              |
-            | 0    | a  | 225 90   | nf,fg,gh,ha                | 225,0,0,90                  |
-            | 0    | a  | 270 90   | og,gh,ha                   | 270,0,90                    |
-            | 0    | a  | 315 90   | ph,ha                      | 315,90                      |
+            | from | to | bearings | route                         | bearing                       |
+            | 0    | q  | 0 90     | ia,ab,bc,cd,de,ef,fg,gh,ha,ha | 0,90,180,180,270,270,0,0,90,0 |
+            | 0    | a  | 45 90    | jb,bc,cd,de,ef,fg,gh,ha,ha    | 45,180,180,270,270,0,0,90,0   |
+            | 0    | q  | 90 90    | kc,cd,de,ef,fg,gh,ha,ha       | 90,180,270,270,0,0,90,0       |
+            | 0    | a  | 135 90   | ld,de,ef,fg,gh,ha,ha          | 135,270,270,0,0,90,0          |
+            | 0    | a  | 180 90   | me,ef,fg,gh,ha,ha             | 180,270,0,0,90,0              |
+            | 0    | a  | 225 90   | nf,fg,gh,ha,ha                | 225,0,0,90,0                  |
+            | 0    | a  | 270 90   | og,gh,ha,ha                   | 270,0,90,0                    |
+            | 0    | a  | 315 90   | ph,ha,ha                      | 315,90,0                      |
diff --git a/features/testbot/compression.feature b/features/testbot/compression.feature
index 4c0121d..79823ce 100644
--- a/features/testbot/compression.feature
+++ b/features/testbot/compression.feature
@@ -17,6 +17,6 @@ Feature: Geometry Compression
             | fg     |
 
         When I route I should get
-            | from | to | route   | distance | speed   |
-            | b    | e  | abcdef  | 589m     | 36 km/h |
-            | e    | b  | abcdef  | 589m     | 36 km/h |
+            | from | to | route         | distance | speed   |
+            | b    | e  | abcdef,abcdef | 589m     | 36 km/h |
+            | e    | b  | abcdef,abcdef | 589m     | 36 km/h |
diff --git a/features/testbot/datastore.feature b/features/testbot/datastore.feature
index 568ae7a..70a754b 100644
--- a/features/testbot/datastore.feature
+++ b/features/testbot/datastore.feature
@@ -14,8 +14,8 @@ Feature: Temporary tests related to osrm-datastore
 
         When I route I should get
             | from | to | route |
-            | a    | b  | ab    |
-            | b    | a  | ab    |
+            | a    | b  | ab,ab |
+            | b    | a  | ab,ab |
 
     Scenario: Scenaria xy
         Given the node map
@@ -27,5 +27,5 @@ Feature: Temporary tests related to osrm-datastore
 
         When I route I should get
             | from | to | route |
-            | x    | y  | xy    |
-            | y    | x  | xy    |
+            | x    | y  | xy,xy |
+            | y    | x  | xy,xy |
diff --git a/features/testbot/distance.feature b/features/testbot/distance.feature
index 55b5f64..b8e571f 100644
--- a/features/testbot/distance.feature
+++ b/features/testbot/distance.feature
@@ -15,7 +15,7 @@ Feature: Distance calculation
 
         When I route I should get
             | from | to | route | distance  |
-            | a    | b  | ab    | 100m +- 2 |
+            | a    | b  | ab,ab | 100m +- 2 |
 
     Scenario: Distance should equal sum of segments, leftwinded
         Given the node map
@@ -28,8 +28,8 @@ Feature: Distance calculation
             | abcde |
 
         When I route I should get
-            | from | to | route | distance |
-            | a    | d  | abcde | 300m +-2 |
+            | from | to | route       | distance |
+            | a    | d  | abcde,abcde | 300m +-2 |
 
     Scenario: Distance should equal sum of segments, rightwinded
         Given the node map
@@ -42,8 +42,8 @@ Feature: Distance calculation
             | abcde |
 
         When I route I should get
-            | from | to | route | distance |
-            | a    | d  | abcde | 300m +-2 |
+            | from | to | route       | distance |
+            | a    | d  | abcde,abcde | 300m +-2 |
 
     Scenario: 10m distances
         Given a grid size of 10 meters
@@ -56,13 +56,13 @@ Feature: Distance calculation
             | abc   |
 
         When I route I should get
-            | from | to | route | distance |
-            | a    | b  | abc   | 10m +-2  |
-            | b    | a  | abc   | 10m +-2  |
-            | b    | c  | abc   | 10m +-2  |
-            | c    | b  | abc   | 10m +-2  |
-            | a    | c  | abc   | 20m +-4  |
-            | c    | a  | abc   | 20m +-4  |
+            | from | to | route   | distance |
+            | a    | b  | abc,abc | 10m +-2  |
+            | b    | a  | abc,abc | 10m +-2  |
+            | b    | c  | abc,abc | 10m +-2  |
+            | c    | b  | abc,abc | 10m +-2  |
+            | a    | c  | abc,abc | 20m +-4  |
+            | c    | a  | abc,abc | 20m +-4  |
 
     Scenario: 100m distances
         Given a grid size of 100 meters
@@ -75,13 +75,13 @@ Feature: Distance calculation
             | abc   |
 
         When I route I should get
-            | from | to | route | distance |
-            | a    | b  | abc   | 100m +-2 |
-            | b    | a  | abc   | 100m +-2 |
-            | b    | c  | abc   | 100m +-2 |
-            | c    | b  | abc   | 100m +-2 |
-            | a    | c  | abc   | 200m +-4 |
-            | c    | a  | abc   | 200m +-4 |
+            | from | to | route   | distance |
+            | a    | b  | abc,abc | 100m +-2 |
+            | b    | a  | abc,abc | 100m +-2 |
+            | b    | c  | abc,abc | 100m +-2 |
+            | c    | b  | abc,abc | 100m +-2 |
+            | a    | c  | abc,abc | 200m +-4 |
+            | c    | a  | abc,abc | 200m +-4 |
 
     Scenario: 1km distance
         Given a grid size of 1000 meters
@@ -94,13 +94,13 @@ Feature: Distance calculation
             | abc   |
 
         When I route I should get
-            | from | to | route | distance  |
-            | a    | b  | abc   | 1000m +-2 |
-            | b    | a  | abc   | 1000m +-2 |
-            | b    | c  | abc   | 1000m +-2 |
-            | c    | b  | abc   | 1000m +-2 |
-            | a    | c  | abc   | 2000m +-4 |
-            | c    | a  | abc   | 2000m +-4 |
+            | from | to | route   | distance  |
+            | a    | b  | abc,abc | 1000m +-2 |
+            | b    | a  | abc,abc | 1000m +-2 |
+            | b    | c  | abc,abc | 1000m +-2 |
+            | c    | b  | abc,abc | 1000m +-2 |
+            | a    | c  | abc,abc | 2000m +-4 |
+            | c    | a  | abc,abc | 2000m +-4 |
 
     Scenario: Distance of a winding south-north path
         Given a grid size of 10 meters
@@ -115,14 +115,14 @@ Feature: Distance calculation
             | abcdefgh |
 
         When I route I should get
-            | from | to | route    | distance |
-            | a    | b  | abcdefgh | 10m +-2  |
-            | a    | c  | abcdefgh | 20m +-4  |
-            | a    | d  | abcdefgh | 30m +-6  |
-            | a    | e  | abcdefgh | 40m +-8  |
-            | a    | f  | abcdefgh | 50m +-10 |
-            | a    | g  | abcdefgh | 60m +-12 |
-            | a    | h  | abcdefgh | 70m +-14 |
+            | from | to | route             | distance |
+            | a    | b  | abcdefgh,abcdefgh | 10m +-2  |
+            | a    | c  | abcdefgh,abcdefgh | 20m +-4  |
+            | a    | d  | abcdefgh,abcdefgh | 30m +-6  |
+            | a    | e  | abcdefgh,abcdefgh | 40m +-8  |
+            | a    | f  | abcdefgh,abcdefgh | 50m +-10 |
+            | a    | g  | abcdefgh,abcdefgh | 60m +-12 |
+            | a    | h  | abcdefgh,abcdefgh | 70m +-14 |
 
     Scenario: Distance of a winding east-west path
         Given a grid size of 10 meters
@@ -135,14 +135,14 @@ Feature: Distance calculation
             | abcdefgh |
 
         When I route I should get
-            | from | to | route    | distance |
-            | a    | b  | abcdefgh | 10m +-2  |
-            | a    | c  | abcdefgh | 20m +-4  |
-            | a    | d  | abcdefgh | 30m +-6  |
-            | a    | e  | abcdefgh | 40m +-8  |
-            | a    | f  | abcdefgh | 50m +-10 |
-            | a    | g  | abcdefgh | 60m +-12 |
-            | a    | h  | abcdefgh | 70m +-14 |
+            | from | to | route             | distance |
+            | a    | b  | abcdefgh,abcdefgh | 10m +-2  |
+            | a    | c  | abcdefgh,abcdefgh | 20m +-4  |
+            | a    | d  | abcdefgh,abcdefgh | 30m +-6  |
+            | a    | e  | abcdefgh,abcdefgh | 40m +-8  |
+            | a    | f  | abcdefgh,abcdefgh | 50m +-10 |
+            | a    | g  | abcdefgh,abcdefgh | 60m +-12 |
+            | a    | h  | abcdefgh,abcdefgh | 70m +-14 |
 
     Scenario: Geometric distances
         Given a grid size of 100 meters
@@ -184,30 +184,30 @@ Feature: Distance calculation
 
         When I route I should get
             | from | to | route | distance  |
-            | 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 |
+            | x    | a  | xa,xa | 300m +-2 |
+            | x    | b  | xb,xb | 316m +-2 |
+            | x    | c  | xc,xc | 360m +-2 |
+            | x    | d  | xd,xd | 424m +-2 |
+            | x    | e  | xe,xe | 360m +-2 |
+            | x    | f  | xf,xf | 316m +-2 |
+            | x    | g  | xg,xg | 300m +-2 |
+            | x    | h  | xh,xh | 316m +-2 |
+            | x    | i  | xi,xi | 360m +-2 |
+            | x    | j  | xj,xj | 424m +-2 |
+            | x    | k  | xk,xk | 360m +-2 |
+            | x    | l  | xl,xl | 316m +-2 |
+            | x    | m  | xm,xm | 300m +-2 |
+            | x    | n  | xn,xn | 316m +-2 |
+            | x    | o  | xo,xo | 360m +-2 |
+            | x    | p  | xp,xp | 424m +-2 |
+            | x    | q  | xq,xq | 360m +-2 |
+            | x    | r  | xr,xr | 316m +-2 |
+            | x    | s  | xs,xs | 300m +-2 |
+            | x    | t  | xt,xt | 316m +-2 |
+            | x    | u  | xu,xu | 360m +-2 |
+            | x    | v  | xv,xv | 424m +-2 |
+            | x    | w  | xw,xw | 360m +-2 |
+            | x    | y  | xy,xy | 316m +-2 |
 
     @maze
     Scenario: Distance of a maze of short segments
@@ -224,5 +224,5 @@ Feature: Distance calculation
             | abcdefghijklmnopqrst |
 
         When I route I should get
-            | from | to | route                | distance |
-            | a    | t  | abcdefghijklmnopqrst | 133m +-2 |
+            | from | to | route                                     | distance |
+            | a    | t  | abcdefghijklmnopqrst,abcdefghijklmnopqrst | 133m +-2 |
diff --git a/features/testbot/distance_matrix.feature b/features/testbot/distance_matrix.feature
index 4910126..4afa307 100644
--- a/features/testbot/distance_matrix.feature
+++ b/features/testbot/distance_matrix.feature
@@ -16,9 +16,9 @@ Feature: Basic Distance Matrix
             | ab    |
 
         When I request a travel time matrix I should get
-            |   | a   | b   |
-            | a | 0   | 100 |
-            | b | 100 | 0   |
+            |   | a  | b  |
+            | a | 0  | 10 |
+            | b | 10 | 0  |
 
     Scenario: Testbot - Travel time matrix with different way speeds
         Given the node map
@@ -29,13 +29,13 @@ Feature: Basic Distance Matrix
             | 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   |
+            |   | a  | b  | c  | d  |
+            | a | 0  | 10 | 30 | 60 |
+            | b | 10 | 0  | 20 | 50 |
+            | c | 30 | 20 | 0  | 30 |
+            | d | 60 | 50 | 30 | 0  |
 
     Scenario: Testbot - Travel time matrix with fuzzy match
         Given the node map
@@ -47,9 +47,9 @@ Feature: Basic Distance Matrix
 
         When I request a travel time matrix I should get
             |   | a       | b        |
-            | a | 0       | 95 +- 10 |
-            | b | 95 ~10% | 0        |
-    
+            | a | 0       | 9 +- 2   |
+            | b | 9  ~15% | 0        |
+
     Scenario: Testbot - Travel time matrix of small grid
         Given the node map
             | a | b | c |
@@ -64,11 +64,11 @@ Feature: Basic Distance Matrix
             | 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   |
+            |   | a  | b  | e  | f  |
+            | a | 0  | 10 | 20 | 30 |
+            | b | 10 | 0  | 10 | 20 |
+            | e | 20 | 10 | 0  | 10 |
+            | f | 30 | 20 | 10 | 0  |
 
     Scenario: Testbot - Travel time matrix of network with unroutable parts
         Given the node map
@@ -79,10 +79,10 @@ Feature: Basic Distance Matrix
             | ab    | yes    |
 
         When I request a travel time matrix I should get
-            |   | a  | b   |
-            | a | 0  | 100 |
-            | b |    | 0   |
-    
+            |   | a | b  |
+            | a | 0 | 10 |
+            | b |   | 0  |
+
     Scenario: Testbot - Travel time matrix of network with oneways
         Given the node map
             | x | a | b | y |
@@ -95,11 +95,11 @@ Feature: Basic Distance Matrix
             | 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   |
+            |   | x  | y   | d  | e  |
+            | x | 0  | 30  | 40 | 30 |
+            | y | 50 | 0   | 30 | 20 |
+            | d | 20 | 30  | 0  | 30 |
+            | e | 30 | 40  | 10 | 0  |
 
     Scenario: Testbot - Travel time matrix and with only one source
         Given the node map
@@ -115,8 +115,8 @@ Feature: Basic Distance Matrix
             | cf    |
 
         When I request a travel time matrix I should get
-            |   | a   | b   | e   | f   |
-            | a | 0   | 100 | 200 | 300 |
+            |   | a | b  | e  | f  |
+            | a | 0 | 10 | 20 | 30 |
 
      Scenario: Testbot - Travel time 3x2 matrix
         Given the node map
@@ -132,11 +132,11 @@ Feature: Basic Distance Matrix
             | cf    |
 
         When I request a travel time matrix I should get
-            |   | b   | e   | f   |
-            | a | 100 | 200 | 300 |
-            | b | 0   | 100 | 200 |
+            |   | b  | e  | f  |
+            | a | 10 | 20 | 30 |
+            | b | 0  | 10 | 20 |
 
-    Scenario: Testbog - All coordinates are from same small component
+    Scenario: Testbot - All coordinates are from same small component
         Given a grid size of 300 meters
         Given the extract extra arguments "--small-component-size 4"
         Given the node map
@@ -152,11 +152,11 @@ Feature: Basic Distance Matrix
             | fg    |
 
         When I request a travel time matrix I should get
-            |   | f   | g   |
-            | f | 0   | 300 |
-            | g | 300 |  0  |
+            |   | f  | g  |
+            | f | 0  | 30 |
+            | g | 30 |  0 |
 
-    Scenario: Testbog - Coordinates are from different small component and snap to big CC
+    Scenario: Testbot - Coordinates are from different small component and snap to big CC
         Given a grid size of 300 meters
         Given the extract extra arguments "--small-component-size 4"
         Given the node map
@@ -173,9 +173,27 @@ Feature: Basic Distance Matrix
             | hi    |
 
         When I request a travel time matrix I should get
-            |   | f   | g   | h   | i   |
-            | f | 0   | 300 | 0   | 300 |
-            | g | 300 |  0  | 300 | 0   |
-            | h | 0   | 300 | 0   | 300 |
-            | i | 300 |  0  | 300 | 0   |
+            |   | f  | g  | h  | i  |
+            | f | 0  | 30 | 0  | 30 |
+            | g | 30 |  0 | 30 | 0  |
+            | h | 0  | 30 | 0  | 30 |
+            | i | 30 |  0 | 30 | 0  |
+
+    Scenario: Testbot - Travel time matrix with loops
+        Given the node map
+            | a | 1 | 2 | b |
+            | d | 4 | 3 | c |
 
+        And the ways
+            | nodes | oneway |
+            | ab    | yes |
+            | bc    | yes |
+            | cd    | yes |
+            | da    | yes |
+
+        When I request a travel time matrix I should get
+            |   | 1      | 2      | 3      | 4  |
+            | 1 | 0      | 10 +-1 | 40 +-1 | 50 +-1 |
+            | 2 | 70 +-1 | 0      | 30 +-1 | 40 +-1 |
+            | 3 | 40 +-1 | 50 +-1 | 0      | 10 +-1 |
+            | 4 | 30 +-1 | 40 +-1 | 70 +-1 | 0  |
diff --git a/features/testbot/duration.feature b/features/testbot/duration.feature
index d5c6e46..bb158db 100644
--- a/features/testbot/duration.feature
+++ b/features/testbot/duration.feature
@@ -20,11 +20,11 @@ Feature: Durations
 
         When I route I should get
             | from | to | route | distance | time       |
-            | a    | b  | ab    | 100m +-1 | 60s +-1    |
-            | b    | c  | bc    | 200m +-1 | 600s +-1   |
-            | c    | d  | cd    | 300m +-1 | 3600s +-1  |
-            | d    | e  | de    | 141m +-2 | 36000s +-1 |
-            | e    | f  | ef    | 224m +-2 | 3723s +-1  |
+            | a    | b  | ab,ab | 100m +-1 | 60s +-1    |
+            | b    | c  | bc,bc | 200m +-1 | 600s +-1   |
+            | c    | d  | cd,cd | 300m +-1 | 3600s +-1  |
+            | d    | e  | de,de | 141m +-2 | 36000s +-1 |
+            | e    | f  | ef,ef | 224m +-2 | 3723s +-1  |
 
     @todo
     Scenario: Partial duration of ways
@@ -36,7 +36,7 @@ Feature: Durations
             | abc   | primary | 0:01     |
 
         When I route I should get
-            | from | to | route | distance | time    |
-            | a    | c  | abc   | 300m +-1 | 60s +-1 |
-            | a    | b  | ab    | 100m +-1 | 20s +-1 |
-            | b    | c  | bc    | 200m +-1 | 40s +-1 |
+            | from | to | route   | distance | time    |
+            | a    | c  | abc,abc | 300m +-1 | 60s +-1 |
+            | a    | b  | ab,ab   | 100m +-1 | 20s +-1 |
+            | b    | c  | bc,bc   | 200m +-1 | 40s +-1 |
diff --git a/features/testbot/example.feature b/features/testbot/example.feature
index c2aa1e9..075a22e 100644
--- a/features/testbot/example.feature
+++ b/features/testbot/example.feature
@@ -20,18 +20,18 @@ Feature: Testbot - Walkthrough
             | de    | primary |        |
 
         When I route I should get
-            | from | to | route     |
-            | a    | b  | abc       |
-            | a    | c  | abc       |
-            | a    | d  | abc,cd    |
-            | a    | e  | abc,ce    |
-            | b    | a  | abc       |
-            | b    | c  | abc       |
-            | b    | d  | abc,cd    |
-            | b    | e  | abc,ce    |
-            | d    | a  | de,ce,abc |
-            | d    | b  | de,ce,abc |
-            | d    | e  | de        |
-            | e    | a  | ce,abc    |
-            | e    | b  | ce,abc    |
-            | e    | c  | ce        |
+            | from | to | route         |
+            | a    | b  | abc,abc       |
+            | a    | c  | abc,abc       |
+            | a    | d  | abc,cd,cd     |
+            | a    | e  | abc,ce,ce     |
+            | b    | a  | abc,abc       |
+            | b    | c  | abc,abc       |
+            | b    | d  | abc,cd,cd     |
+            | b    | e  | abc,ce,ce     |
+            | d    | a  | de,ce,abc,abc |
+            | d    | b  | de,ce,abc,abc |
+            | d    | e  | de,de         |
+            | e    | a  | ce,abc,abc    |
+            | e    | b  | ce,abc,abc    |
+            | e    | c  | ce,ce         |
diff --git a/features/testbot/fastest.feature b/features/testbot/fastest.feature
index 8c24a53..5576c73 100644
--- a/features/testbot/fastest.feature
+++ b/features/testbot/fastest.feature
@@ -18,9 +18,9 @@ Feature: Choosing fastest route
             | asb   | primary |
 
         When I route I should get
-            | from | to | route     |
-            | x    | y  | xa,atb,by |
-            | y    | x  | by,atb,xa |
+            | from | to | route        |
+            | x    | y  | xa,atb,by,by |
+            | y    | x  | by,atb,xa,xa |
 
     Scenario: Pick the fastest route, even when it's longer
         Given the node map
@@ -33,6 +33,6 @@ Feature: Choosing fastest route
             | asb   | secondary |
 
         When I route I should get
-            | from | to | route |
-            | a    | b  | apb   |
-            | b    | a  | apb   |
+            | from | to | route   |
+            | a    | b  | apb,apb |
+            | b    | a  | apb,apb |
diff --git a/features/testbot/ferry.feature b/features/testbot/ferry.feature
index 21cefcb..6dd896b 100644
--- a/features/testbot/ferry.feature
+++ b/features/testbot/ferry.feature
@@ -32,11 +32,11 @@ Feature: Testbot - Handle ferry routes
 
         When I route I should get
             | from | to | route | time        |
-            | b    | c  | bc    | 60s +-1     |
-            | f    | g  | fg    | 600s +-1    |
-            | j    | k  | jk    | 3600s +-1   |
-            | n    | o  | no    | 86400s +-1  |
-            | r    | s  | rs    | 345600s +-1 |
+            | b    | c  | bc,bc | 60s +-1     |
+            | f    | g  | fg,fg | 600s +-1    |
+            | j    | k  | jk,jk | 3600s +-1   |
+            | n    | o  | no,no | 86400s +-1  |
+            | r    | s  | rs,rs | 345600s +-1 |
 
     @todo
     Scenario: Testbot - Week long ferry routes
@@ -59,9 +59,9 @@ Feature: Testbot - Handle ferry routes
 
         When I route I should get
             | from | to | route | time        |
-            | b    | c  | bc    | 86400s +-1  |
-            | f    | g  | fg    | 604800s +-1 |
-            | j    | k  | jk    | 259200s +-1 |
+            | b    | c  | bc,bc | 86400s +-1  |
+            | f    | g  | fg,fg | 604800s +-1 |
+            | j    | k  | jk,jk | 259200s +-1 |
 
     Scenario: Testbot - Ferry duration, multiple nodes
         Given the node map
@@ -76,8 +76,8 @@ Feature: Testbot - Handle ferry routes
 
         When I route I should get
             | from | to | route | time      |
-            | a    | d  | ad    | 3600s +-1 |
-            | d    | a  | ad    | 3600s +-1 |
+            | a    | d  | ad,ad | 3600s +-1 |
+            | d    | a  | ad,ad | 3600s +-1 |
 
     @todo
     Scenario: Testbot - Ferry duration, individual parts, fast
@@ -95,11 +95,11 @@ Feature: Testbot - Handle ferry routes
             | abcd  |         | ferry | 0:06     |
 
         When I route I should get
-            | from | to | route | time     |
-            | a    | d  | abcd  | 360s +-1 |
-            | a    | b  | abcd  | 60s +-1  |
-            | b    | c  | abcd  | 120s +-1 |
-            | c    | d  | abcd  | 180s +-1 |
+            | from | to | route     | time     |
+            | a    | d  | abcd,abcd | 360s +-1 |
+            | a    | b  | abcd,abcd | 60s +-1  |
+            | b    | c  | abcd,abcd | 120s +-1 |
+            | c    | d  | abcd,abcd | 180s +-1 |
 
     @todo
     Scenario: Testbot - Ferry duration, individual parts, slow
@@ -116,11 +116,11 @@ Feature: Testbot - Handle ferry routes
             | abcd  |         | ferry | 1:00     |
 
         When I route I should get
-            | from | to | route | time      |
-            | a    | d  | abcd  | 3600s ~1% |
-            | a    | b  | abcd  | 600s ~1%  |
-            | b    | c  | abcd  | 1200s ~1% |
-            | c    | d  | abcd  | 1800s ~1% |
+            | from | to | route     | time      |
+            | a    | d  | abcd,abcd | 3600s ~1% |
+            | a    | b  | abcd,abcd | 600s ~1%  |
+            | b    | c  | abcd,abcd | 1200s ~1% |
+            | c    | d  | abcd,abcd | 1800s ~1% |
 
     Scenario: Testbot - Ferry duration, connected routes
         Given the node map
@@ -135,9 +135,9 @@ Feature: Testbot - Handle ferry routes
             | defg  |         | ferry | 0:30     |
 
         When I route I should get
-            | from | to | route     | time      |
-            | a    | g  | abcd,defg | 3600s +-1 |
-            | g    | a  | defg,abcd | 3600s +-1 |
+            | from | to | route          | time      |
+            | a    | g  | abcd,defg,defg | 3600s +-1 |
+            | g    | a  | defg,abcd,abcd | 3600s +-1 |
 
     Scenario: Testbot - Prefer road when faster than ferry
         Given the node map
@@ -154,9 +154,9 @@ Feature: Testbot - Handle ferry routes
             | defg  |         | ferry | 0:01     |
 
         When I route I should get
-            | from | to | route    | time      |
-            | a    | g  | xa,xy,yg | 60s +-25% |
-            | g    | a  | yg,xy,xa | 60s +-25% |
+            | from | to | route       | time      |
+            | a    | g  | xa,xy,yg,yg | 60s +-25% |
+            | g    | a  | yg,xy,xa,xa | 60s +-25% |
 
     Scenario: Testbot - Long winding ferry route
         Given the node map
@@ -170,9 +170,9 @@ Feature: Testbot - Handle ferry routes
             | abcdefg |         | ferry | 6:30     |
 
         When I route I should get
-            | from | to | route   | time       |
-            | a    | g  | abcdefg | 23400s +-2 |
-            | g    | a  | abcdefg | 23400s +-2 |
+            | from | to | route           | time       |
+            | a    | g  | abcdefg,abcdefg | 23400s +-2 |
+            | g    | a  | abcdefg,abcdefg | 23400s +-2 |
 
     @todo
     Scenario: Testbot - Ferry duration formats
@@ -194,12 +194,12 @@ Feature: Testbot - Handle ferry routes
 
         When I route I should get
             | from | to | route | time          |
-            | a    | b  | ab    | 60s +-1       |
-            | c    | d  | cd    | 60s +-1       |
-            | e    | f  | ef    | 3600s +-1     |
-            | g    | h  | gh    | 3600s +-1     |
-            | i    | j  | ij    | 8400s +-1     |
-            | k    | l  | kl    | 36000s +-1    |
-            | m    | n  | mn    | 360000s +-1   |
-            | o    | p  | mn    | 3600000s +-1  |
-            | q    | r  | mn    | 36000000s +-1 |
+            | a    | b  | ab,ab | 60s +-1       |
+            | c    | d  | cd,cd | 60s +-1       |
+            | e    | f  | ef,ef | 3600s +-1     |
+            | g    | h  | gh,gh | 3600s +-1     |
+            | i    | j  | ij,ij | 8400s +-1     |
+            | k    | l  | kl,kl | 36000s +-1    |
+            | m    | n  | mn,mn | 360000s +-1   |
+            | o    | p  | mn,mn | 3600000s +-1  |
+            | q    | r  | mn,mn | 36000000s +-1 |
diff --git a/features/testbot/fixed.feature b/features/testbot/fixed.feature
index 0edf25c..dc09eaa 100644
--- a/features/testbot/fixed.feature
+++ b/features/testbot/fixed.feature
@@ -22,5 +22,5 @@ Feature: Fixed bugs, kept to check for regressions
             | cdec  |
 
         When I route I should get
-            | from | to | route | turns            |
-            | x    | y  | abc   | head,destination |
+            | from | to | route   |
+            | x    | y  | abc,abc |
diff --git a/features/testbot/geometry.feature b/features/testbot/geometry.feature
index 8b38c06..24f3d23 100644
--- a/features/testbot/geometry.feature
+++ b/features/testbot/geometry.feature
@@ -21,10 +21,8 @@ Feature: Retrieve geometry
             | cd    |
 
         When I route I should get
-            | from | to | route | geometry                             |
-            | a    | c  | ab,bc | _c`\|@_upzA_c`\|@_c`\|@_c`\|@_c`\|@  |
-            | b    | d  | bc,cd | _gayB_yqwC_c`\|@_c`\|@_c`\|@_c`\|@   |
+            | from | to | route    | geometry         |
+            | a    | c  | ab,bc,bc | _ibE_~cH_seK_seK |
+            | b    | d  | bc,cd,cd | _seK_hgN_seK_seK |
 
 # Mind the \ before the pipes
-# polycodec.rb decode2 '_c`|@_upzA_c`|@_c`|@_c`|@_c`|@' [[1.0, 1.5], [2.0, 2.5], [3.0, 3.5]]
-# polycodec.rb decode2 '_gayB_yqwC_c`|@_c`|@_c`|@_c`|@' [[2.0, 2.5], [3.0, 3.5], [4.0, 4.5]]
diff --git a/features/testbot/graph.feature b/features/testbot/graph.feature
index adff998..f86b994 100644
--- a/features/testbot/graph.feature
+++ b/features/testbot/graph.feature
@@ -17,8 +17,8 @@ Feature: Basic Routing
             | dce   |
 
         When I route I should get
-            | from | to | route   |
-            | a    | e  | abc,dce |
+            | from | to | route       |
+            | a    | e  | abc,dce,dce |
 
     Scenario: Turn instructions on compressed road network geometry
         Given the node map
@@ -36,5 +36,5 @@ Feature: Basic Routing
             | fy     | last  |
 
         When I route I should get
-            | from | to | route            | turns                       |
-            | x    | y  | first,compr,last | head,right,left,destination |
+            | from | to | route                 | turns                    |
+            | x    | y  | first,compr,last,last | depart,right,left,arrive |
diff --git a/features/testbot/load.feature b/features/testbot/load.feature
index cf5e470..b29fdc7 100644
--- a/features/testbot/load.feature
+++ b/features/testbot/load.feature
@@ -17,8 +17,8 @@ Feature: Ways of loading data
 
         When I route I should get
             | from | to | route |
-            | a    | b  | ab    |
-            | b    | a  | ab    |
+            | a    | b  | ab,ab |
+            | b    | a  | ab,ab |
 
     Scenario: Load data directly - st
         Given data is loaded directly
@@ -31,10 +31,10 @@ Feature: Ways of loading data
 
         When I route I should get
             | from | to | route |
-            | s    | t  | st    |
-            | t    | s  | st    |
+            | s    | t  | st,st |
+            | t    | s  | st,st |
 
-    Scenario: Load data datstore - xy
+    Scenario: Load data datastore - xy
         Given data is loaded with datastore
         Given the node map
             | x | y |
@@ -45,8 +45,8 @@ Feature: Ways of loading data
 
         When I route I should get
             | from | to | route |
-            | x    | y  | xy    |
-            | y    | x  | xy    |
+            | x    | y  | xy,xy |
+            | y    | x  | xy,xy |
 
     Scenario: Load data directly - cd
         Given data is loaded directly
@@ -59,5 +59,5 @@ Feature: Ways of loading data
 
         When I route I should get
             | from | to | route |
-            | c    | d  | cd    |
-            | d    | c  | cd    |
+            | c    | d  | cd,cd |
+            | d    | c  | cd,cd |
diff --git a/features/testbot/loop.feature b/features/testbot/loop.feature
index c69e7a2..f035ab0 100644
--- a/features/testbot/loop.feature
+++ b/features/testbot/loop.feature
@@ -4,7 +4,7 @@ Feature: Avoid weird loops caused by rounding errors
     Background:
         Given the profile "testbot"
 
-    Scenario: Weired sidestreet loops
+    Scenario: Weird sidestreet loops
         Given the node map
             | a | 1 | b | 2 | c | 3 | d |
             |   |   |   |   |   |   |   |
@@ -18,10 +18,10 @@ Feature: Avoid weird loops caused by rounding errors
             | cg     |
 
        When I route I should get
-           | waypoints | route     | turns                |
-           | a,1,d     | abcd,abcd | head,via,destination |
-           | a,2,d     | abcd,abcd | head,via,destination |
-           | a,3,d     | abcd,abcd | head,via,destination |
+           | waypoints | route               |
+           | a,1,d     | abcd,abcd,abcd,abcd |
+           | a,2,d     | abcd,abcd,abcd,abcd |
+           | a,3,d     | abcd,abcd,abcd,abcd |
 
     Scenario: Avoid weird loops 1
         Given the node locations
@@ -47,8 +47,8 @@ Feature: Avoid weird loops caused by rounding errors
             | ie    |
 
         When I route I should get
-            | from | to | route | turns            |
-            | x    | y  | hfgd  | head,destination |
+            | from | to | route     |
+            | x    | y  | hfgd,hfgd |
 
     Scenario: Avoid weird loops 2
         Given the node locations
@@ -67,8 +67,8 @@ Feature: Avoid weird loops caused by rounding errors
             | cdec  |
 
         When I route I should get
-            | from | to | route | turns            |
-            | x    | y  | abc   | head,destination |
+            | from | to | route   |
+            | x    | y  | abc,abc |
 
     @412
     Scenario: Avoid weird loops 3
@@ -92,6 +92,6 @@ Feature: Avoid weird loops caused by rounding errors
             | cf    | primary     |
 
         When I route I should get
-            | 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 |
+            | waypoints | route                   |
+            | a,2,d     | ab,be,ef,ef,ef,cf,cd,cd |
+            | a,1,d     | ab,be,ef,ef,ef,cf,cd,cd |
diff --git a/features/testbot/matching.feature b/features/testbot/matching.feature
index 91bf928..bee3d9c 100644
--- a/features/testbot/matching.feature
+++ b/features/testbot/matching.feature
@@ -5,6 +5,23 @@ Feature: Basic Map Matching
         Given the profile "testbot"
         Given a grid size of 10 meters
 
+    Scenario: Testbot - Map matching with outlier that has no candidate
+        Given a grid size of 100 meters
+        Given the node map
+            | a | b | c | d |
+            |   |   |   |   |
+            |   |   |   |   |
+            |   |   |   |   |
+            |   |   | 1 |   |
+
+        And the ways
+            | nodes | oneway |
+            | abcd  | no     |
+
+        When I match I should get
+            | trace | timestamps | matchings |
+            | ab1d  | 0 1 2 3    | abcd      |
+
     Scenario: Testbot - Map matching with trace splitting
         Given the node map
             | a | b | c | d |
@@ -18,6 +35,20 @@ Feature: Basic Map Matching
             | trace | timestamps | matchings |
             | abcd  | 0 1 62 63  | ab,cd     |
 
+    Scenario: Testbot - Map matching with core factor
+        Given the contract extra arguments "--core 0.8"
+        Given the node map
+            | a | b | c | d |
+            |   |   | e |   |
+
+        And the ways
+            | nodes | oneway |
+            | abcd  | no     |
+
+        When I match I should get
+            | trace | timestamps | matchings |
+            | abcd  | 0 1 2 3    | abcd      |
+
     Scenario: Testbot - Map matching with small distortion
         Given the node map
             | a | b | c | d | e |
diff --git a/features/testbot/matching_turns.feature b/features/testbot/matching_turns.feature
deleted file mode 100644
index 8bca4a2..0000000
--- a/features/testbot/matching_turns.feature
+++ /dev/null
@@ -1,121 +0,0 @@
- at routing @turns @testbot
-Feature: Turn directions/codes
-
-    Background:
-        Given the profile "testbot"
-
-    Scenario: Turn directions
-        Given the query options
-            | instructions | true |
-        Given the node map
-            | o | p | a | b | c |
-            | n |   |   |   | d |
-            | m |   | x |   | e |
-            | l |   |   |   | f |
-            | k | j | i | h | g |
-
-        And the ways
-            | nodes |
-            | xa    |
-            | xb    |
-            | xc    |
-            | xd    |
-            | xe    |
-            | xf    |
-            | xg    |
-            | xh    |
-            | xi    |
-            | xj    |
-            | xk    |
-            | xl    |
-            | xm    |
-            | xn    |
-            | xo    |
-            | xp    |
-
-        When I match I should get
-            | trace | route | turns                         | matchings |
-            | im    | xi,xm | head,left,destination         | im        |
-            | io    | xi,xo | head,slight_left,destination  | io        |
-            | ia    | xi,xa | head,straight,destination     | ia        |
-            | ic    | xi,xc | head,slight_right,destination | ic        |
-            | ie    | xi,xe | head,right,destination        | ie        |
-            
-            | ko    | xk,xo | head,left,destination         | ko        |
-            | ka    | xk,xa | head,slight_left,destination  | ka        |
-            | kc    | xk,xc | head,straight,destination     | kc        |
-            | ke    | xk,xe | head,slight_right,destination | ke        |
-            | kg    | xk,xg | head,right,destination        | kg        |
-
-            | ma    | xm,xa | head,left,destination         | ma        |
-            | mc    | xm,xc | head,slight_left,destination  | mc        |
-            | me    | xm,xe | head,straight,destination     | me        |
-            | mg    | xm,xg | head,slight_right,destination | mg        |
-            | mi    | xm,xi | head,right,destination        | mi        |
-
-            | oc    | xo,xc | head,left,destination         | oc        |
-            | oe    | xo,xe | head,slight_left,destination  | oe        |
-            | og    | xo,xg | head,straight,destination     | og        |
-            | oi    | xo,xi | head,slight_right,destination | oi        |
-            | ok    | xo,xk | head,right,destination        | ok        |
-
-            | ae    | xa,xe | head,left,destination         | ae        |
-            | ag    | xa,xg | head,slight_left,destination  | ag        |
-            | ai    | xa,xi | head,straight,destination     | ai        |
-            | ak    | xa,xk | head,slight_right,destination | ak        |
-            | am    | xa,xm | head,right,destination        | am        |
-
-            | cg    | xc,xg | head,left,destination         | cg        |
-            | ci    | xc,xi | head,slight_left,destination  | ci        |
-            | ck    | xc,xk | head,straight,destination     | ck        |
-            | cm    | xc,xm | head,slight_right,destination | cm        |
-            | co    | xc,xo | head,right,destination        | co        |
-
-            | ei    | xe,xi | head,left,destination         | ei        |
-            | ek    | xe,xk | head,slight_left,destination  | ek        |
-            | em    | xe,xm | head,straight,destination     | em        |
-            | eo    | xe,xo | head,slight_right,destination | eo        |
-            | ea    | xe,xa | head,right,destination        | ea        |
-
-            | gk    | xg,xk | head,left,destination         | gk        |
-            | gm    | xg,xm | head,slight_left,destination  | gm        |
-            | go    | xg,xo | head,straight,destination     | go        |
-            | ga    | xg,xa | head,slight_right,destination | ga        |
-            | gc    | xg,xc | head,right,destination        | gc        |
-
-    Scenario: Turn directions
-        Given the query options
-            | instructions | true |
-        Given the node map
-            | o | p | a | b | c |
-            | n |   |   |   | d |
-            | m |   | x |   | e |
-            | l |   |   |   | f |
-            | k | j | i | h | g |
-
-        And the ways
-            | nodes |
-            | xa    |
-            | xb    |
-            | xc    |
-            | xd    |
-            | xe    |
-            | xf    |
-            | xg    |
-            | xh    |
-            | xi    |
-            | xj    |
-            | xk    |
-            | xl    |
-            | xm    |
-            | xn    |
-            | xo    |
-            | xp    |
-
-        When I match I should get
-            | trace | route | turns                         | matchings | duration |
-            | im    | xi,xm | head,left,destination         | im        | 80       |
-            | io    | xi,xo | head,slight_left,destination  | io        | 88       |
-            | ia    | xi,xa | head,straight,destination     | ia        | 80       |
-            | ic    | xi,xc | head,slight_right,destination | ic        | 88       |
-            | ie    | xi,xe | head,right,destination        | ie        | 60       |
diff --git a/features/testbot/mode.feature b/features/testbot/mode.feature
index ef8cd25..3f2463d 100644
--- a/features/testbot/mode.feature
+++ b/features/testbot/mode.feature
@@ -2,7 +2,7 @@
 Feature: Testbot - Travel mode
 
 # testbot modes:
-# 1 normal
+# 1 driving
 # 2 route
 # 3 river downstream
 # 4 river upstream
@@ -12,6 +12,7 @@ Feature: Testbot - Travel mode
     Background:
        Given the profile "testbot"
 
+    @mokob @2166
     Scenario: Testbot - Always announce mode change
         Given the node map
             | a | b | c | d |
@@ -23,9 +24,27 @@ Feature: Testbot - Travel mode
             | cd    | residential | foo  |
 
         When I route I should get
-            | from | to | route        | modes |
-            | a    | d  | foo,foo,foo  | 1,3,1 |
+            | from | to | route           | modes                                    |
+            | a    | d  | foo,foo,foo,foo | driving,river downstream,driving,driving |
+            | b    | d  | foo,foo,foo     | river downstream,driving,driving         |
 
+    @mokob @2166
+    Scenario: Testbot - Compressed Modes
+        Given the node map
+            | a | b | c | d | e | f | g |
+
+        And the ways
+            | nodes | highway     | name   |
+            | abc   | residential | road   |
+            | cde   | river       | liquid |
+            | efg   | residential | solid  |
+
+        When I route I should get
+            | from | to | route                    | modes                                    |
+            | a    | g  | road,liquid,solid,solid  | driving,river downstream,driving,driving |
+            | c    | g  | liquid,solid,solid       | river downstream,driving,driving         |
+
+    @mokob @2166
     Scenario: Testbot - Modes in each direction, different forward/backward speeds
         Given the node map
             |   | 0 | 1 |   |
@@ -36,15 +55,15 @@ Feature: Testbot - Travel mode
             | 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     |
+            | from | to | route | modes                             |
+            | a    | 0  | ab,ab | river downstream,river downstream |
+            | a    | b  | ab,ab | river downstream,river downstream |
+            | 0    | 1  | ab,ab | river downstream,river downstream |
+            | 0    | b  | ab,ab | river downstream,river downstream |
+            | b    | 1  | ab,ab | river upstream,river upstream     |
+            | b    | a  | ab,ab | river upstream,river upstream     |
+            | 1    | 0  | ab,ab | river upstream,river upstream     |
+            | 1    | a  | ab,ab | river upstream,river upstream     |
 
     Scenario: Testbot - Modes in each direction, same forward/backward speeds
         Given the node map
@@ -56,11 +75,11 @@ Feature: Testbot - Travel mode
             | 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 |
+            | from | to | route | modes                 | time    |
+            | 0    | 1  | ab,ab | steps down,steps down | 60s +-1 |
+            | 1    | 0  | ab,ab | steps up,steps up     | 60s +-1 |
 
-    @oneway
+    @oneway @mokob @2166
     Scenario: Testbot - Modes for oneway, different forward/backward speeds
         Given the node map
             | a | b |
@@ -70,9 +89,9 @@ Feature: Testbot - Travel mode
             | ab    | river   | yes    |
 
         When I route I should get
-            | from | to | route | modes |
-            | a    | b  | ab    | 3     |
-            | b    | a  |       |       |
+            | from | to | route | modes                             |
+            | a    | b  | ab,ab | river downstream,river downstream |
+            | b    | a  |       |                                   |
 
     @oneway
     Scenario: Testbot - Modes for oneway, same forward/backward speeds
@@ -84,11 +103,11 @@ Feature: Testbot - Travel mode
             | ab    | steps   | yes    |
 
         When I route I should get
-            | from | to | route | modes |
-            | a    | b  | ab    | 5     |
-            | b    | a  |       |       |
+            | from | to | route | modes                 |
+            | a    | b  | ab,ab | steps down,steps down |
+            | b    | a  |       |                       |
 
-    @oneway
+    @oneway @mokob @2166
     Scenario: Testbot - Modes for reverse oneway, different forward/backward speeds
         Given the node map
             | a | b |
@@ -98,9 +117,9 @@ Feature: Testbot - Travel mode
             | ab    | river   | -1     |
 
         When I route I should get
-            | from | to | route | modes |
-            | a    | b  |       |       |
-            | b    | a  | ab    | 4     |
+            | from | to | route | modes                         |
+            | a    | b  |       |                               |
+            | b    | a  | ab,ab | river upstream,river upstream |
 
     @oneway
     Scenario: Testbot - Modes for reverse oneway, same forward/backward speeds
@@ -112,11 +131,11 @@ Feature: Testbot - Travel mode
             | ab    | steps   | -1     |
 
         When I route I should get
-            | from | to | route | modes |
-            | a    | b  |       |       |
-            | b    | a  | ab    | 6     |
+            | from | to | route | modes             |
+            | a    | b  |       |                   |
+            | b    | a  | ab,ab | steps up,steps up |
 
-    @via
+    @via @mokob @2166
     Scenario: Testbot - Mode should be set at via points
         Given the node map
             | a | 1 | b |
@@ -126,10 +145,11 @@ Feature: Testbot - Travel mode
             | 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 |
+            | waypoints | route       | modes                                                               |
+            | a,1,b     | ab,ab,ab,ab | river downstream,river downstream,river downstream,river downstream |
+            | b,1,a     | ab,ab,ab,ab | river upstream,river upstream,river upstream,river upstream         |
 
+    @mokob @2166
     Scenario: Testbot - Starting at a tricky node
        Given the node map
             |  | a |  |   |   |
@@ -141,9 +161,10 @@ Feature: Testbot - Travel mode
             | bc    | primary |
 
        When I route I should get
-            | from | to | route | modes |
-            | b    | a  | ab    | 4     |
+            | from | to | route | modes                         |
+            | b    | a  | ab,ab | river upstream,river upstream |
 
+    @mokob @2166
     Scenario: Testbot - Mode changes on straight way without name change
        Given the node map
             | a | 1 | b | 2 | c |
@@ -154,11 +175,11 @@ Feature: Testbot - Travel mode
             | 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 |
+            | from | to | route                | modes                                     |
+            | a    | c  | Avenue,Avenue,Avenue | driving,river downstream,river downstream |
+            | c    | a  | Avenue,Avenue,Avenue | river upstream,driving,driving            |
+            | 1    | 2  | Avenue,Avenue,Avenue | driving,river downstream,river downstream |
+            | 2    | 1  | Avenue,Avenue,Avenue | river upstream,driving,driving            |
 
     Scenario: Testbot - Mode for routes
        Given the node map
@@ -174,15 +195,16 @@ Feature: Testbot - Travel mode
             | 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 |
-
+            | from | to | route             | modes                                         |
+            | a    | d  | ab,bc,cd,cd       | driving,route,driving,driving                 |
+            | d    | a  | cd,bc,ab,ab       | driving,route,driving,driving                 |
+            | c    | a  | bc,ab,ab          | route,driving,driving                         |
+            | d    | b  | cd,bc,bc          | driving,route,route                           |
+            | a    | c  | ab,bc,bc          | driving,route,route                           |
+            | b    | d  | bc,cd,cd          | route,driving,driving                         |
+            | a    | f  | ab,bc,cd,de,ef,ef | driving,route,driving,driving,driving,driving |
+
+    @mokob @2166
     Scenario: Testbot - Modes, triangle map
         Given the node map
             |   |   |   |   |   |   | d |
@@ -201,22 +223,23 @@ Feature: Testbot - Travel mode
             | 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   |
-
+            | from | to | route            | modes                                          |
+            | 0    | 1  | abc,ce,de,de     | driving,river downstream,driving,driving       |
+            | 1    | 0  | de,ce,abc,abc    | driving,river upstream,driving,driving         |
+            | 0    | 2  | abc,cd,cd        | driving,driving,driving                        |
+            | 2    | 0  | cd,de,ce,abc,abc | driving,driving,river upstream,driving,driving |
+            | 0    | 3  | abc,ce,ce        | driving,river downstream,river downstream      |
+            | 3    | 0  | ce,abc,abc       | river upstream,driving,driving                 |
+            | 4    | 3  | ce,ce            | river downstream,river downstream              |
+            | 3    | 4  | ce,ce            | river upstream,river upstream                  |
+            | 3    | 1  | ce,de,de         | river downstream,driving,driving               |
+            | 1    | 3  | de,ce,ce         | driving,river upstream,river upstream          |
+            | a    | e  | abc,ce,ce        | driving,river downstream,river downstream      |
+            | e    | a  | ce,abc,abc       | river upstream,driving,driving                 |
+            | a    | d  | abc,cd,cd        | driving,driving,driving                        |
+            | d    | a  | de,ce,abc,abc    | driving,river upstream,driving,driving         |
+
+    @mokob @2166
     Scenario: Testbot - River in the middle
         Given the node map
             | a | b | c |   |   |
@@ -230,12 +253,12 @@ Feature: Testbot - Travel mode
             | efg   | primary |
 
         When I route I should get
-            | 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   |
+            | from | to | route           | modes                                    |
+            | a    | g  | abc,cde,efg,efg | driving,river downstream,driving,driving |
+            | b    | f  | abc,cde,efg,efg | driving,river downstream,driving,driving |
+            | e    | c  | cde,cde         | river upstream,river upstream            |
+            | e    | b  | cde,abc,abc     | river upstream,driving,driving           |
+            | e    | a  | cde,abc,abc     | river upstream,driving,driving           |
+            | c    | e  | cde,cde         | river downstream,river downstream        |
+            | c    | f  | cde,efg,efg     | river downstream,driving,driving         |
+            | c    | g  | cde,efg,efg     | river downstream,driving,driving         |
diff --git a/features/testbot/oneway.feature b/features/testbot/oneway.feature
index 766bf8b..6e2326d 100644
--- a/features/testbot/oneway.feature
+++ b/features/testbot/oneway.feature
@@ -29,23 +29,23 @@ Feature: Testbot - oneways
             | xe    | yes    |
 
         When I route I should get
-            | from | to | route                |
-            | a    | b  | ab                   |
-            | b    | c  | bc                   |
-            | c    | d  | cd                   |
-            | d    | e  | de                   |
-            | e    | f  | ef                   |
-            | f    | g  | fg                   |
-            | g    | h  | gh                   |
-            | h    | a  | ha                   |
-            | b    | a  | bc,cd,de,ef,fg,gh,ha |
-            | c    | b  | cd,de,ef,fg,gh,ha,ab |
-            | d    | c  | de,ef,fg,gh,ha,ab,bc |
-            | e    | d  | ef,fg,gh,ha,ab,bc,cd |
-            | f    | e  | fg,gh,ha,ab,bc,cd,de |
-            | 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 |
+            | from | to | route                   |
+            | a    | b  | ab,ab                   |
+            | b    | c  | bc,bc                   |
+            | c    | d  | cd,cd                   |
+            | d    | e  | de,de                   |
+            | e    | f  | ef,ef                   |
+            | f    | g  | fg,fg                   |
+            | g    | h  | gh,gh                   |
+            | h    | a  | ha,ha                   |
+            | b    | a  | bc,cd,de,ef,fg,gh,ha,ha |
+            | c    | b  | cd,de,ef,fg,gh,ha,ab,ab |
+            | d    | c  | de,ef,fg,gh,ha,ab,bc,bc |
+            | e    | d  | ef,fg,gh,ha,ab,bc,cd,cd |
+            | f    | e  | fg,gh,ha,ab,bc,cd,de,de |
+            | g    | f  | gh,ha,ab,bc,cd,de,ef,ef |
+            | h    | g  | ha,ab,bc,cd,de,ef,fg,fg |
+            | a    | h  | ab,bc,cd,de,ef,fg,gh,gh |
 
     Scenario: Testbot - Simple oneway
         Then routability should be
@@ -70,9 +70,9 @@ Feature: Testbot - oneways
             | da    |        | no   |
 
         When I route I should get
-            | from | to | route    |
-            | a    | b  | ab       |
-            | b    | a  | bc,cd,da |
+            | from | to | route       |
+            | a    | b  | ab,ab       |
+            | b    | a  | bc,cd,da,da |
 
     Scenario: Testbot - Handle various oneway tag values
         Then routability should be
@@ -98,5 +98,5 @@ Feature: Testbot - oneways
 
 
         When I route I should get
-            | from | to | route |
-            | a    | c  | ab,bc |
+            | from | to | route    |
+            | a    | c  | ab,bc,bc |
diff --git a/features/testbot/opposite.feature b/features/testbot/opposite.feature
index c19755c..de11e5e 100644
--- a/features/testbot/opposite.feature
+++ b/features/testbot/opposite.feature
@@ -13,6 +13,6 @@ Feature: Separate settings for forward/backward direction
             | abcd  | river   |
 
         When I route I should get
-            | from | to | route | distance  | speed        |
-            | a    | d  | abcd  | 300 +- 1m | 36 km/h      |
-            | d    | a  | abcd  | 300 +- 1m | 16 km/h +- 1 |
+            | from | to | route     | distance  | speed        |
+            | a    | d  | abcd,abcd | 300 +- 1m | 36 km/h      |
+            | d    | a  | abcd,abcd | 300 +- 1m | 16 km/h +- 1 |
diff --git a/features/testbot/origin.feature b/features/testbot/origin.feature
index b5b1945..e56e94d 100644
--- a/features/testbot/origin.feature
+++ b/features/testbot/origin.feature
@@ -17,9 +17,9 @@ Feature: Routing close to the [0,0] origin
             | abcd  | yes    |
 
         When I route I should get
-            | from | to | route | distance |
-            | b    | c  | abcd  | 100m +-1 |
-            | c    | b  |       |          |
+            | from | to | route     | distance |
+            | b    | c  | abcd,abcd | 100m +-1 |
+            | c    | b  |           |          |
 
     Scenario: North-south oneways close to the origin
         Given the node locations
@@ -34,9 +34,9 @@ Feature: Routing close to the [0,0] origin
             | abcd  | yes    |
 
         When I route I should get
-            | from | to | route | distance |
-            | b    | c  | abcd  | 100m +-1 |
-            | c    | b  |       |          |
+            | from | to | route     | distance |
+            | b    | c  | abcd,abcd | 100m +-1 |
+            | c    | b  |           |          |
 
     Scenario: East-west oneways crossing the origin
         Given the node locations
@@ -52,9 +52,9 @@ Feature: Routing close to the [0,0] origin
             | abcde | yes    |
 
         When I route I should get
-            | from | to | route | distance |
-            | b    | d  | abcde | 200m +-2 |
-            | d    | b  |       |          |
+            | from | to | route       | distance |
+            | b    | d  | abcde,abcde | 200m +-2 |
+            | d    | b  |             |          |
 
     Scenario: North-south oneways crossing the origin
         Given the node locations
@@ -70,6 +70,6 @@ Feature: Routing close to the [0,0] origin
             | abcde | yes    |
 
         When I route I should get
-            | from | to | route | distance |
-            | b    | d  | abcde | 200m +-2 |
-            | d    | b  |       |          |
+            | from | to | route       | distance |
+            | b    | d  | abcde,abcde | 200m +-2 |
+            | d    | b  |             |          |
diff --git a/features/testbot/penalty.feature b/features/testbot/penalty.feature
index e4f3cb6..8d86a17 100644
--- a/features/testbot/penalty.feature
+++ b/features/testbot/penalty.feature
@@ -20,9 +20,9 @@ Feature: Penalties
             | def   |
 
         When I route I should get
-            | from | to | route | time    | distance |
-            | a    | c  | abc   | 20s +-1 | 200m +-1 |
-            | d    | f  | def   | 27s +-1 | 200m +-1 |
+            | from | to | route   | time    | distance |
+            | a    | c  | abc,abc | 20s +-1 | 200m +-1 |
+            | d    | f  | def,def | 27s +-1 | 200m +-1 |
 
     Scenario: Signal penalty should not depend on way type
         Given the node map
@@ -43,10 +43,10 @@ Feature: Penalties
             | ghi   | tertiary  |
 
         When I route I should get
-            | from | to | route | time    |
-            | a    | c  | abc   | 27s +-1 |
-            | d    | f  | def   | 47s +-1 |
-            | g    | i  | ghi   | 67s +-1 |
+            | from | to | route   | time    |
+            | a    | c  | abc,abc | 27s +-1 |
+            | d    | f  | def,def | 47s +-1 |
+            | g    | i  | ghi,ghi | 67s +-1 |
 
     Scenario: Passing multiple traffic signals should incur a accumulated delay
         Given the node map
@@ -63,8 +63,8 @@ Feature: Penalties
             | abcde |
 
         When I route I should get
-            | from | to | route | time    |
-            | a    | e  | abcde | 61s +-1 |
+            | from | to | route       | time    |
+            | a    | e  | abcde,abcde | 61s +-1 |
 
         @todo
         Scenario: Signal penalty should not depend on way type
@@ -86,13 +86,13 @@ Feature: Penalties
                 | ghi   | tertiary  |
 
             When I route I should get
-                | from | to | route | time    |
-                | a    | b  | abc   | 10s +-1 |
-                | a    | c  | abc   | 27s +-1 |
-                | d    | e  | def   | 20s +-1 |
-                | d    | f  | def   | 47s +-1 |
-                | g    | h  | ghi   | 30s +-1 |
-                | g    | i  | ghi   | 67s +-1 |
+                | from | to | route   | time    |
+                | a    | b  | abc,abc | 10s +-1 |
+                | a    | c  | abc,abc | 27s +-1 |
+                | d    | e  | def,def | 20s +-1 |
+                | d    | f  | def,def | 47s +-1 |
+                | g    | h  | ghi,ghi | 30s +-1 |
+                | g    | i  | ghi,ghi | 67s +-1 |
 
         Scenario: Passing multiple traffic signals should incur a accumulated delay
             Given the node map
@@ -109,8 +109,8 @@ Feature: Penalties
                 | abcde |
 
             When I route I should get
-                | from | to | route | time    |
-                | a    | e  | abcde | 61s +-1 |
+                | from | to | route       | time    |
+                | a    | e  | abcde,abcde | 61s +-1 |
 
     @todo
     Scenario: Starting or ending at a traffic signal should not incur a delay
@@ -144,9 +144,9 @@ Feature: Penalties
             | abcd  | primary |
 
         When I route I should get
-            | from | to | route | time    |
-            | b    | c  | abcd  | 10s +-1 |
-            | c    | b  | abcd  | 10s +-1 |
+            | from | to | route     | time    |
+            | b    | c  | abcd,abcd | 10s +-1 |
+            | c    | b  | abcd,abcd | 10s +-1 |
 
     Scenario: Prefer faster route without traffic signals
         Given a grid size of 50 meters
@@ -164,5 +164,5 @@ Feature: Penalties
             | adc   | primary |
 
         When I route I should get
-            | from | to | route |
-            | a    | c  | adc   |
+            | from | to | route   |
+            | a    | c  | adc,adc |
diff --git a/features/testbot/planetary.feature b/features/testbot/planetary.feature
index 19925fe..1fff4bd 100644
--- a/features/testbot/planetary.feature
+++ b/features/testbot/planetary.feature
@@ -13,7 +13,7 @@ Feature: Distance calculation
 
         When I route I should get
             | from | to | route | distance       |
-            | a    | b  | ab    | 8905559m ~0.1% |
+            | a    | b  | ab,ab | 8905559m ~0.1% |
 
     Scenario: Approximated Longitudinal distances at latitude 45
         Given the node locations
@@ -27,7 +27,7 @@ Feature: Distance calculation
 
         When I route I should get
             | from | to | route | distance       |
-            | c    | d  | cd    | 6028844m ~4.5% |
+            | c    | d  | cd,cd | 6028844m ~4.5% |
 
     Scenario: Approximated Longitudinal distances at latitude 80
         Given the node locations
@@ -41,7 +41,7 @@ Feature: Distance calculation
 
         When I route I should get
             | from | to | route | distance       |
-            | c    | d  | cd    | 1431469m ~9.5% |
+            | c    | d  | cd,cd | 1431469m ~9.5% |
 
     Scenario: Approximated Latitudinal distances at longitude 0
         Given the node locations
@@ -55,7 +55,7 @@ Feature: Distance calculation
 
         When I route I should get
             | from | to | route | distance       |
-            | a    | b  | ab    | 8905559m ~0.1% |
+            | a    | b  | ab,ab | 8905559m ~0.1% |
 
     Scenario: Approximated Latitudinal distances at longitude 45
         Given the node locations
@@ -69,7 +69,7 @@ Feature: Distance calculation
 
         When I route I should get
             | from | to | route | distance       |
-            | a    | b  | ab    | 8905559m ~0.1% |
+            | a    | b  | ab,ab | 8905559m ~0.1% |
 
     Scenario: Approximated Latitudinal distances at longitude 80
         Given the node locations
@@ -83,4 +83,4 @@ Feature: Distance calculation
 
         When I route I should get
             | from | to | route | distance       |
-            | a    | b  | ab    | 8905559m ~0.1% |
+            | a    | b  | ab,ab | 8905559m ~0.1% |
diff --git a/features/testbot/post.feature b/features/testbot/post.feature
deleted file mode 100644
index ac53177..0000000
--- a/features/testbot/post.feature
+++ /dev/null
@@ -1,83 +0,0 @@
- at post @testbot
-Feature: POST request
-
-    Background:
-        Given the profile "testbot"
-        And the HTTP method "POST"
-
-    Scenario: Testbot - viaroute POST request
-        Given the node locations
-            | node | lat       | lon      |
-            | a    | 55.68740  | 12.52430 |
-            | b    | 55.68745  | 12.52409 |
-            | c    | 55.68711  | 12.52383 |
-            | x    | -55.68740 | 12.52430 |
-            | y    | -55.68745 | 12.52409 |
-            | z    | -55.68711 | 12.52383 |
-
-        And the ways
-            | nodes |
-            | ab    |
-            | bc    |
-            | xy    |
-            | yz    |
-            
-        When I route I should get
-            | from | to | route | turns                  |
-            | a    | c  | ab,bc | head,left,destination  |
-            | c    | a  | bc,ab | head,right,destination |
-            | x    | z  | xy,yz | head,right,destination |
-            | z    | x  | yz,xy | head,left,destination  |
-
-    Scenario: Testbot - match POST request
-        Given a grid size of 10 meters
-        Given the node map
-            | a | b | c | d |
-            | e | f | g | h |
-
-        And the ways
-            | nodes | oneway |
-            | abcd  | yes    |
-            | hgfe  | yes    |
-
-        When I match I should get
-            | trace | matchings |
-            | dcba  | hgfe      |
-            
-    Scenario: Testbot - table POST request
-        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   |
-
-    Scenario: Testbot - nearest POST request
-        Given the node locations
-            | node | lat     | lon  |
-            | a    | -85     | -180 |
-            | b    | -85     | -160 |
-            | c    | -85     | -140 |
-            | x    | -84.999 | -180 |
-            | y    | -84.999 | -160 |
-            | z    | -84.999 | -140 |
-
-        And the ways
-            | nodes |
-            | abc   |
-
-        When I request nearest I should get
-            | in | out |
-            | x  | a   |
-            | y  | b   |
-            | z  | c   |
diff --git a/features/testbot/projection.feature b/features/testbot/projection.feature
index d7a0b89..ad4a32b 100644
--- a/features/testbot/projection.feature
+++ b/features/testbot/projection.feature
@@ -23,16 +23,16 @@ Feature: Projection to nearest point on road
 
     Scenario: Projection onto way at high latitudes, 1km distance
         When I route I should get
-            | from | to | route | compass | bearing | distance  |
-            | b    | a  | abc   | SW      | 225     | 1000m +-7 |
-            | b    | c  | abc   | NE      | 45      | 1000m +-7 |
-            | a    | d  | abc   | NE      | 45      | 1000m +-7 |
-            | d    | a  | abc   | SW      | 225     | 1000m +-7 |
-            | c    | d  | abc   | SW      | 225     | 1000m +-8 |
-            | d    | c  | abc   | NE      | 45  +-5 | 1000m +-8 |
+            | from | to | route   | bearing   | distance   |
+            | b    | a  | abc,abc | 225,0 +-1 | 1000m +- 7 |
+            | b    | c  | abc,abc | 45,0  +-1 | 1000m +- 7 |
+            | a    | d  | abc,abc | 45,0  +-1 | 1000m +- 7 |
+            | d    | a  | abc,abc | 225,0 +-1 | 1000m +- 7 |
+            | c    | d  | abc,abc | 225,0 +-1 | 1000m +- 8 |
+            | d    | c  | abc,abc | 45 +-1    | 1000m +- 8 |
 
     Scenario: Projection onto way at high latitudes, no distance
         When I route I should get
-            | from | to | route | distance |
-            | d    | b  | abc   | 0m  +-5  |
-            | b    | d  | abc   | 0m  +-5  |
+            | from | to | route     | distance |
+            | d    | b  | abc,abc   | 0m  +-5  |
+            | b    | d  | abc,abc   | 0m  +-5  |
diff --git a/features/testbot/protobuffer.feature b/features/testbot/protobuffer.feature
deleted file mode 100644
index e32de26..0000000
--- a/features/testbot/protobuffer.feature
+++ /dev/null
@@ -1,156 +0,0 @@
- 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
-# The scenarios in this file test the ability to import .pbf files,
-# including nodes, way, restictions, and a various special situations.
-
-    Background:
-        Given the profile "testbot"
-        And the import format "pbf"
-
-    Scenario: Testbot - Protobuffer import, nodes and ways
-        Given the node map
-            |   |   |   | d |
-            | a | b | c |   |
-            |   |   |   | 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 |
-            | d    | c  | de,ce |
-            | e    | d  | de    |
-
-
-    Scenario: Testbot - Protobuffer import, turn restiction relations
-        Given the node map
-            |   | n |   |
-            | w | j | e |
-            |   | s |   |
-
-        And the ways
-            | nodes | oneway |
-            | sj    | yes    |
-            | nj    | -1     |
-            | wj    | -1     |
-            | ej    | -1     |
-
-        And the relations
-            | type        | way:from | way:to | node:via | restriction  |
-            | restriction | sj       | wj     | j        | no_left_turn |
-
-        When I route I should get
-            | from | to | route |
-            | s    | w  |       |
-            | s    | n  | sj,nj |
-            | s    | e  | sj,ej |
-
-
-    Scenario: Testbot - Protobuffer import, distances at longitude 45
-        Given the node locations
-            | node | lat | lon |
-            | a    | 80  | 45  |
-            | b    | 0   | 45  |
-
-        And the ways
-            | nodes |
-            | ab    |
-
-        When I route I should get
-            | from | to | route | distance       |
-            | a    | b  | ab    | 8905559m ~0.1% |
-
-    Scenario: Testbot - Protobuffer import, distances at longitude 80
-        Given the node locations
-            | node | lat | lon |
-            | a    | 80  | 80  |
-            | b    | 0   | 80  |
-
-        And the ways
-            | nodes |
-            | ab    |
-
-        When I route I should get
-            | from | to | route | distance       |
-            | a    | b  | ab    | 8905559m ~0.1% |
-
-    Scenario: Testbot - Protobuffer import, empty dataset
-        Given the node map
-            |  |
-
-        Given the ways
-            | nodes |
-
-        When the data has been prepared
-        Then "osrm-extract" should return code 1
-
-
-    Scenario: Testbot - Protobuffer import, streetnames with UTF characters
-        Given the node map
-            | a | b | c | d |
-
-        And the ways
-            | nodes | name                   |
-            | ab    | Scandinavian København |
-            | bc    | Japanese 東京            |
-            | cd    | Cyrillic Москва        |
-
-        When I route I should get
-            | from | to | route                  |
-            | a    | b  | Scandinavian København |
-            | b    | c  | Japanese 東京            |
-            | c    | d  | Cyrillic Москва        |
-
-    Scenario: Testbot - Protobuffer import, bearing af 45 degree intervals
-        Given the node map
-            | b | a | h |
-            | c | x | g |
-            | d | e | f |
-
-        And the ways
-            | nodes |
-            | xa    |
-            | xb    |
-            | xc    |
-            | xd    |
-            | xe    |
-            | xf    |
-            | xg    |
-            | xh    |
-
-        When I route I should get
-            | from | to | route | compass | bearing |
-            | x    | a  | xa    | N       | 0       |
-            | x    | b  | xb    | NW      | 315     |
-            | x    | c  | xc    | W       | 270     |
-            | x    | d  | xd    | SW      | 225     |
-            | x    | e  | xe    | S       | 180     |
-            | x    | f  | xf    | SE      | 135     |
-            | x    | g  | xg    | E       | 90      |
-            | x    | h  | xh    | NE      | 45      |
-
-
-    Scenario: Testbot - Protobuffer import, rraffic signals should incur a delay
-        Given the node map
-            | a | b | c |
-            | d | e | f |
-
-        And the nodes
-            | node | highway         |
-            | e    | traffic_signals |
-
-        And the ways
-            | nodes |
-            | abc   |
-            | def   |
-
-        When I route I should get
-            | from | to | route | time    | distance |
-            | a    | c  | abc   | 20s +-1 | 200m +-1 |
-            | d    | f  | def   | 27s +-1 | 200m +-1 |
diff --git a/features/testbot/roundabout.feature b/features/testbot/roundabout.feature
index 570b14b..90f2fc0 100644
--- a/features/testbot/roundabout.feature
+++ b/features/testbot/roundabout.feature
@@ -21,19 +21,19 @@ Feature: Roundabout Instructions
             | abcda | roundabout |
 
         When I route I should get
-            | from | to | route | turns                               |
-            | s    | t  | sa,tb | head,enter_roundabout-1,destination |
-            | s    | u  | sa,uc | head,enter_roundabout-2,destination |
-            | s    | v  | sa,vd | head,enter_roundabout-3,destination |
-            | t    | u  | tb,uc | head,enter_roundabout-1,destination |
-            | t    | v  | tb,vd | head,enter_roundabout-2,destination |
-            | t    | s  | tb,sa | head,enter_roundabout-3,destination |
-            | u    | v  | uc,vd | head,enter_roundabout-1,destination |
-            | u    | s  | uc,sa | head,enter_roundabout-2,destination |
-            | u    | t  | uc,tb | head,enter_roundabout-3,destination |
-            | v    | s  | vd,sa | head,enter_roundabout-1,destination |
-            | v    | t  | vd,tb | head,enter_roundabout-2,destination |
-            | v    | u  | vd,uc | head,enter_roundabout-3,destination |
+            | from | to | route    | turns                            |
+            | s    | t  | sa,tb,tb | depart,roundabout-exit-1,arrive |
+            | s    | u  | sa,uc,uc | depart,roundabout-exit-2,arrive |
+            | s    | v  | sa,vd,vd | depart,roundabout-exit-3,arrive |
+            | t    | u  | tb,uc,uc | depart,roundabout-exit-1,arrive |
+            | t    | v  | tb,vd,vd | depart,roundabout-exit-2,arrive |
+            | t    | s  | tb,sa,sa | depart,roundabout-exit-3,arrive |
+            | u    | v  | uc,vd,vd | depart,roundabout-exit-1,arrive |
+            | u    | s  | uc,sa,sa | depart,roundabout-exit-2,arrive |
+            | u    | t  | uc,tb,tb | depart,roundabout-exit-3,arrive |
+            | v    | s  | vd,sa,sa | depart,roundabout-exit-1,arrive |
+            | v    | t  | vd,tb,tb | depart,roundabout-exit-2,arrive |
+            | v    | u  | vd,uc,uc | depart,roundabout-exit-3,arrive |
 
     Scenario: Testbot - Roundabout with oneway links
         Given the node map
@@ -57,20 +57,20 @@ Feature: Roundabout Instructions
             | abcdefgha | roundabout |        |
 
         When I route I should get
-            | from | to | route | turns                               |
-            | j    | k  | jb,ck | head,enter_roundabout-1,destination |
-            | j    | m  | jb,em | head,enter_roundabout-2,destination |
-            | j    | o  | jb,go | head,enter_roundabout-3,destination |
-            | j    | i  | jb,ai | head,enter_roundabout-4,destination |
-            | l    | m  | ld,em | head,enter_roundabout-1,destination |
-            | l    | o  | ld,go | head,enter_roundabout-2,destination |
-            | l    | i  | ld,ai | head,enter_roundabout-3,destination |
-            | l    | k  | ld,ck | head,enter_roundabout-4,destination |
-            | n    | o  | nf,go | head,enter_roundabout-1,destination |
-            | n    | i  | nf,ai | head,enter_roundabout-2,destination |
-            | n    | k  | nf,ck | head,enter_roundabout-3,destination |
-            | n    | m  | nf,em | head,enter_roundabout-4,destination |
-            | p    | i  | ph,ai | head,enter_roundabout-1,destination |
-            | p    | k  | ph,ck | head,enter_roundabout-2,destination |
-            | p    | m  | ph,em | head,enter_roundabout-3,destination |
-            | p    | o  | ph,go | head,enter_roundabout-4,destination |
+            | from | to | route    | turns                            |
+            | j    | k  | jb,ck,ck | depart,roundabout-exit-1,arrive |
+            | j    | m  | jb,em,em | depart,roundabout-exit-2,arrive |
+            | j    | o  | jb,go,go | depart,roundabout-exit-3,arrive |
+            | j    | i  | jb,ai,ai | depart,roundabout-exit-4,arrive |
+            | l    | m  | ld,em,em | depart,roundabout-exit-1,arrive |
+            | l    | o  | ld,go,go | depart,roundabout-exit-2,arrive |
+            | l    | i  | ld,ai,ai | depart,roundabout-exit-3,arrive |
+            | l    | k  | ld,ck,ck | depart,roundabout-exit-4,arrive |
+            | n    | o  | nf,go,go | depart,roundabout-exit-1,arrive |
+            | n    | i  | nf,ai,ai | depart,roundabout-exit-2,arrive |
+            | n    | k  | nf,ck,ck | depart,roundabout-exit-3,arrive |
+            | n    | m  | nf,em,em | depart,roundabout-exit-4,arrive |
+            | p    | i  | ph,ai,ai | depart,roundabout-exit-1,arrive |
+            | p    | k  | ph,ck,ck | depart,roundabout-exit-2,arrive |
+            | p    | m  | ph,em,em | depart,roundabout-exit-3,arrive |
+            | p    | o  | ph,go,go | depart,roundabout-exit-4,arrive |
diff --git a/features/testbot/snap.feature b/features/testbot/snap.feature
index 9b7bcbd..80c44bb 100644
--- a/features/testbot/snap.feature
+++ b/features/testbot/snap.feature
@@ -21,14 +21,14 @@ Feature: Snap start/end point to the nearest way
 
         When I route I should get
             | from | to | route |
-            | 1    | c  | nc    |
-            | 2    | c  | nc    |
-            | 3    | c  | ec    |
-            | 4    | c  | ec    |
-            | 5    | c  | sc    |
-            | 6    | c  | sc    |
-            | 7    | c  | wc    |
-            | 8    | c  | wc    |
+            | 1    | c  | nc,nc |
+            | 2    | c  | nc,nc |
+            | 3    | c  | ec,ec |
+            | 4    | c  | ec,ec |
+            | 5    | c  | sc,sc |
+            | 6    | c  | sc,sc |
+            | 7    | c  | wc,wc |
+            | 8    | c  | wc,wc |
 
     Scenario: Snap to nearest edge of a square
         Given the node map
@@ -43,11 +43,11 @@ Feature: Snap start/end point to the nearest way
             | adb   |
 
         When I route I should get
-            | from | to | route |
-            | 1    | b  | adb   |
-            | 2    | b  | adb   |
-            | 6    | b  | aub   |
-            | 7    | b  | aub   |
+            | from | to | route   |
+            | 1    | b  | adb,adb |
+            | 2    | b  | adb,adb |
+            | 6    | b  | aub,aub |
+            | 7    | b  | aub,aub |
 
     Scenario: Snap to edge right under start/end point
         Given the node map
@@ -64,17 +64,17 @@ Feature: Snap start/end point to the nearest way
             | jkla  |
 
         When I route I should get
-            | from | to | route     |
-            | a    | b  | abcd      |
-            | a    | c  | abcd      |
-            | a    | d  | abcd      |
-            | a    | e  | abcd,defg |
-            | a    | f  | abcd,defg |
-            | a    | h  | jkla,ghij |
-            | a    | i  | jkla,ghij |
-            | a    | j  | jkla      |
-            | a    | k  | jkla      |
-            | a    | l  | jkla      |
+            | from | to | route          |
+            | a    | b  | abcd,abcd      |
+            | a    | c  | abcd,abcd      |
+            | a    | d  | abcd,abcd      |
+            | a    | e  | abcd,defg,defg |
+            | a    | f  | abcd,defg,defg |
+            | a    | h  | jkla,ghij,ghij |
+            | a    | i  | jkla,ghij,ghij |
+            | a    | j  | jkla,jkla      |
+            | a    | k  | jkla,jkla      |
+            | a    | l  | jkla,jkla      |
 
     Scenario: Snapping in viaroute
         Given the extract extra arguments "--small-component-size 4"
@@ -92,9 +92,9 @@ Feature: Snap start/end point to the nearest way
 
         When I route I should get
             | from | to | route |
-            | a    | b  | ab    |
-            | a    | d  | cd    |
-            | c    | d  | cd    |
+            | a    | b  | ab,ab |
+            | a    | d  | cd,cd |
+            | c    | d  | cd,cd |
 
     Scenario: Snap to correct way at large scales
         Given a grid size of 1000 meters
@@ -111,12 +111,12 @@ Feature: Snap start/end point to the nearest way
 
         When I route I should get
             | from | to | route |
-            | x    | a  | xa    |
-            | x    | b  | xb    |
-            | x    | c  | xc    |
-            | a    | x  | xa    |
-            | b    | x  | xb    |
-            | c    | x  | xc    |
+            | x    | a  | xa,xa |
+            | x    | b  | xb,xb |
+            | x    | c  | xc,xc |
+            | a    | x  | xa,xa |
+            | b    | x  | xb,xb |
+            | c    | x  | xc,xc |
 
     Scenario: Find edges within 100m, and the same from 1km
         Given a grid size of 100 meters
@@ -152,19 +152,19 @@ Feature: Snap start/end point to the nearest way
 
         When I route I should get
             | from | to | route |
-            | x    | 1  | xa    |
-            | x    | 2  | xb    |
-            | x    | 3  | xc    |
-            | x    | 4  | xd    |
-            | x    | 5  | xe    |
-            | x    | 6  | xf    |
-            | x    | 7  | xg    |
-            | x    | 8  | xh    |
-            | x    | i  | xa    |
-            | x    | j  | xb    |
-            | x    | k  | xc    |
-            | x    | l  | xd    |
-            | x    | m  | xe    |
-            | x    | n  | xf    |
-            | x    | o  | xg    |
-            | x    | p  | xh    |
+            | x    | 1  | xa,xa |
+            | x    | 2  | xb,xb |
+            | x    | 3  | xc,xc |
+            | x    | 4  | xd,xd |
+            | x    | 5  | xe,xe |
+            | x    | 6  | xf,xf |
+            | x    | 7  | xg,xg |
+            | x    | 8  | xh,xh |
+            | x    | i  | xa,xa |
+            | x    | j  | xb,xb |
+            | x    | k  | xc,xc |
+            | x    | l  | xd,xd |
+            | x    | m  | xe,xe |
+            | x    | n  | xf,xf |
+            | x    | o  | xg,xg |
+            | x    | p  | xh,xh |
diff --git a/features/testbot/speed.feature b/features/testbot/speed.feature
index 2eb3724..0416419 100644
--- a/features/testbot/speed.feature
+++ b/features/testbot/speed.feature
@@ -26,6 +26,6 @@ Feature: Testbot - speeds
             | ab    | river   |
 
         When I route I should get
-            | from | to | route | speed        | time | distance |
-            | a    | b  | ab    | 36 km/h      | 10s  | 100m     |
-            | b    | a  | ab    | 16 km/h +- 1 | 23s  | 100m     |
+            | from | to | route | speed        | time    | distance  |
+            | a    | b  | ab,ab | 36 km/h      | 10s +-1 | 100m +- 1 |
+            | b    | a  | ab,ab | 16 km/h +- 1 | 23s +-1 | 100m +- 1 |
diff --git a/features/testbot/status.feature b/features/testbot/status.feature
index 86d8259..41ad18b 100644
--- a/features/testbot/status.feature
+++ b/features/testbot/status.feature
@@ -14,8 +14,8 @@ Feature: Status messages
 
         When I route I should get
             | from | to | route | status | message                    |
-            | a    | b  | ab    | 200    | Found route between points |
-            | b    | a  | ab    | 200    | Found route between points |
+            | a    | b  | ab,ab | 200    |                            |
+            | b    | a  | ab,ab | 200    |                            |
 
     Scenario: No route found
         Given the node map
@@ -30,38 +30,38 @@ Feature: Status messages
 
         When I route I should get
             | from | to | route | status | message                          |
-            | a    | b  | ab    | 200    | Found route between points       |
-            | c    | d  | cd    | 200    | Found route between points       |
-            | a    | c  |       | 207    | Impossible route between points  |
-            | b    | d  |       | 207    | Impossible route between points  |
+            | a    | b  | ab,ab | 200    |                                  |
+            | c    | d  | cd,cd | 200    |                                  |
+            | a    | c  |       | 400    | Impossible route between points  |
+            | b    | d  |       | 400    | Impossible route between points  |
 
     Scenario: Malformed requests
         Given the node locations
             | node | lat  | lon  |
             | a    | 1.00 | 1.00 |
-            | b    | 1.01 | 1.00 |
+            | b    | 2.00 | 1.00 |
 
         And the ways
             | nodes |
             | ab    |
 
         When I route I should get
-            | request                     | status | message                                     |
-            | viaroute?loc=1,1&loc=1.01,1 | 200    | Found route between points                  |
-            | nonsense                    | 400    | Service not found                           |
-            | nonsense?loc=1,1&loc=1.01,1 | 400    | Service not found                           |
-            |                             | 400    | Query string malformed close to position 0  |
-            | /                           | 400    | Query string malformed close to position 0  |
-            | ?                           | 400    | Query string malformed close to position 0  |
-            | viaroute?loc=               | 400    | Query string malformed close to position 9  |
-            | viaroute?loc=1              | 400    | Query string malformed close to position 9  |
-            | viaroute?loc=1,1            | 400    | Invalid coordinates                         |
-            | viaroute?loc=1,1,1          | 400    | Query string malformed close to position 17 |
-            | viaroute?loc=x              | 400    | Query string malformed close to position 9  |
-            | viaroute?loc=x,y            | 400    | Query string malformed close to position 9  |
-            | viaroute?loc=1,1&loc=       | 400    | Query string malformed close to position 17 |
-            | viaroute?loc=1,1&loc=1      | 400    | Query string malformed close to position 17 |
-            | viaroute?loc=1,1&loc=1,1    | 200    | Found route between points                  |
-            | viaroute?loc=1,1&loc=1,1,1  | 400    | Query string malformed close to position 25 |
-            | viaroute?loc=1,1&loc=x      | 400    | Query string malformed close to position 17 |
-            | viaroute?loc=1,1&loc=x,y    | 400    | Query string malformed close to position 17 |
+            | request                     | status | message                                         |
+            | route/v1/driving/1,1;1,2    | 200    |                                                 |
+            | nonsense                    | 400    | URL string malformed close to position 0: "/no" |
+            | nonsense/v1/driving/1,1;1,2 | 400    | Service nonsense not found!                     |
+            |                             | 400    | URL string malformed close to position 0: "/"   |
+            | /                           | 400    | URL string malformed close to position 0: "//"  |
+            | ?                           | 400    | URL string malformed close to position 0: "/?"  |
+            | route/v1/driving            | 400    | URL string malformed close to position 0: "/ro" |
+            | route/v1/driving/           | 400    | URL string malformed close to position 0: "/ro" |
+            | route/v1/driving/1          | 400    | Query string malformed close to position 0      |
+            | route/v1/driving/1,1        | 400    | Number of coordinates needs to be at least two. |
+            | route/v1/driving/1,1,1      | 400    | Query string malformed close to position 3      |
+            | route/v1/driving/x          | 400    | Query string malformed close to position 0      |
+            | route/v1/driving/x,y        | 400    | Query string malformed close to position 0      |
+            | route/v1/driving/1,1;       | 400    | Query string malformed close to position 3      |
+            | route/v1/driving/1,1;1      | 400    | Query string malformed close to position 3      |
+            | route/v1/driving/1,1;1,1,1  | 400    | Query string malformed close to position 7      |
+            | route/v1/driving/1,1;x      | 400    | Query string malformed close to position 3      |
+            | route/v1/driving/1,1;x,y    | 400    | Query string malformed close to position 3      |
diff --git a/features/testbot/time.feature b/features/testbot/time.feature
index c838796..834b13b 100644
--- a/features/testbot/time.feature
+++ b/features/testbot/time.feature
@@ -27,15 +27,15 @@ Feature: Estimation of travel time
             | xh    | primary |
 
         When I route I should get
-            | from | to | route | time   |
-            | x    | a  | xa    | 1s +-1 |
-            | x    | b  | xb    | 1s +-1 |
-            | x    | c  | xc    | 1s +-1 |
-            | x    | d  | xd    | 1s +-1 |
-            | x    | e  | xe    | 1s +-1 |
-            | x    | f  | xf    | 1s +-1 |
-            | x    | g  | xg    | 1s +-1 |
-            | x    | h  | xh    | 1s +-1 |
+            | from | to | route    | time   |
+            | x    | a  | xa,xa    | 1s +-1 |
+            | x    | b  | xb,xb    | 1s +-1 |
+            | x    | c  | xc,xc    | 1s +-1 |
+            | x    | d  | xd,xd    | 1s +-1 |
+            | x    | e  | xe,xe    | 1s +-1 |
+            | x    | f  | xf,xf    | 1s +-1 |
+            | x    | g  | xg,xg    | 1s +-1 |
+            | x    | h  | xh,xh    | 1s +-1 |
 
     Scenario: Basic travel time, 100m scale
         Given a grid size of 100 meters
@@ -56,15 +56,15 @@ Feature: Estimation of travel time
             | xh    | primary |
 
         When I route I should get
-            | from | to | route | time    |
-            | x    | a  | xa    | 10s +-1 |
-            | x    | b  | xb    | 14s +-1 |
-            | x    | c  | xc    | 10s +-1 |
-            | x    | d  | xd    | 14s +-1 |
-            | x    | e  | xe    | 10s +-1 |
-            | x    | f  | xf    | 14s +-1 |
-            | x    | g  | xg    | 10s +-1 |
-            | x    | h  | xh    | 14s +-1 |
+            | from | to | route    | time    |
+            | x    | a  | xa,xa    | 10s +-1 |
+            | x    | b  | xb,xb    | 14s +-1 |
+            | x    | c  | xc,xc    | 10s +-1 |
+            | x    | d  | xd,xd    | 14s +-1 |
+            | x    | e  | xe,xe    | 10s +-1 |
+            | x    | f  | xf,xf    | 14s +-1 |
+            | x    | g  | xg,xg    | 10s +-1 |
+            | x    | h  | xh,xh    | 14s +-1 |
 
     Scenario: Basic travel time, 1km scale
         Given a grid size of 1000 meters
@@ -85,15 +85,15 @@ Feature: Estimation of travel time
             | xh    | primary |
 
         When I route I should get
-            | from | to | route | time     |
-            | x    | a  | xa    | 100s +-1 |
-            | x    | b  | xb    | 141s +-1 |
-            | x    | c  | xc    | 100s +-1 |
-            | x    | d  | xd    | 141s +-1 |
-            | x    | e  | xe    | 100s +-1 |
-            | x    | f  | xf    | 141s +-1 |
-            | x    | g  | xg    | 100s +-1 |
-            | x    | h  | xh    | 141s +-1 |
+            | from | to | route    | time     |
+            | x    | a  | xa,xa    | 100s +-1 |
+            | x    | b  | xb,xb    | 141s +-1 |
+            | x    | c  | xc,xc    | 100s +-1 |
+            | x    | d  | xd,xd    | 141s +-1 |
+            | x    | e  | xe,xe    | 100s +-1 |
+            | x    | f  | xf,xf    | 141s +-1 |
+            | x    | g  | xg,xg    | 100s +-1 |
+            | x    | h  | xh,xh    | 141s +-1 |
 
     Scenario: Basic travel time, 10km scale
         Given a grid size of 10000 meters
@@ -114,15 +114,15 @@ Feature: Estimation of travel time
             | xh    | primary |
 
         When I route I should get
-            | from | to | route | time      |
-            | x    | a  | xa    | 1000s +-1 |
-            | x    | b  | xb    | 1414s +-1 |
-            | x    | c  | xc    | 1000s +-1 |
-            | x    | d  | xd    | 1414s +-1 |
-            | x    | e  | xe    | 1000s +-1 |
-            | x    | f  | xf    | 1414s +-1 |
-            | x    | g  | xg    | 1000s +-1 |
-            | x    | h  | xh    | 1414s +-1 |
+            | from | to | route    | time      |
+            | x    | a  | xa,xa    | 1000s +-1 |
+            | x    | b  | xb,xb    | 1414s +-1 |
+            | x    | c  | xc,xc    | 1000s +-1 |
+            | x    | d  | xd,xd    | 1414s +-1 |
+            | x    | e  | xe,xe    | 1000s +-1 |
+            | x    | f  | xf,xf    | 1414s +-1 |
+            | x    | g  | xg,xg    | 1000s +-1 |
+            | x    | h  | xh,xh    | 1414s +-1 |
 
     Scenario: Time of travel depending on way type
         Given the node map
@@ -138,10 +138,10 @@ Feature: Estimation of travel time
             | ace   | something |
 
         When I route I should get
-            | from | to | route | time    |
-            | a    | b  | ab    | 10s +-1 |
-            | c    | d  | cd    | 20s +-1 |
-            | e    | f  | ef    | 30s +-1 |
+            | from | to | route    | time    |
+            | a    | b  | ab,ab    | 10s +-1 |
+            | c    | d  | cd,cd    | 20s +-1 |
+            | e    | f  | ef,ef    | 30s +-1 |
 
     Scenario: Time of travel on a series of ways
         Given the node map
@@ -155,10 +155,10 @@ Feature: Estimation of travel time
             | cd    | primary |
 
         When I route I should get
-            | from | to | route    | time    |
-            | a    | b  | ab       | 10s +-1 |
-            | a    | c  | ab,bc    | 20s +-1 |
-            | a    | d  | ab,bc,cd | 30s +-1 |
+            | from | to | route       | time    |
+            | a    | b  | ab,ab       | 10s +-1 |
+            | a    | c  | ab,bc,bc    | 20s +-1 |
+            | a    | d  | ab,bc,cd,cd | 30s +-1 |
 
     Scenario: Time of travel on a winding way
         Given the node map
@@ -171,10 +171,10 @@ Feature: Estimation of travel time
             | abcdefghi | primary |
 
         When I route I should get
-            | from | to | route     | time    |
-            | a    | b  | abcdefghi | 10s +-1 |
-            | a    | e  | abcdefghi | 40s +-1 |
-            | a    | i  | abcdefghi | 80s +-1 |
+            | from | to | route               | time    |
+            | a    | b  | abcdefghi,abcdefghi | 10s +-1 |
+            | a    | e  | abcdefghi,abcdefghi | 40s +-1 |
+            | a    | i  | abcdefghi,abcdefghi | 80s +-1 |
 
     Scenario: Time of travel on combination of road types
         Given the node map
@@ -188,11 +188,11 @@ Feature: Estimation of travel time
             | cde   | tertiary |
 
         When I route I should get
-            | from | to | route   | time    |
-            | b    | c  | abc     | 10s +-1 |
-            | c    | e  | cde     | 60s +-1 |
-            | b    | d  | abc,cde | 40s +-1 |
-            | a    | e  | abc,cde | 80s +-1 |
+            | from | to | route       | time    |
+            | b    | c  | abc,abc     | 10s +-1 |
+            | c    | e  | cde,cde     | 60s +-1 |
+            | b    | d  | abc,cde,cde | 40s +-1 |
+            | a    | e  | abc,cde,cde | 80s +-1 |
 
     Scenario: Time of travel on part of a way
         Given the node map
@@ -206,13 +206,13 @@ Feature: Estimation of travel time
             | ab    | primary |
 
         When I route I should get
-            | from | to | route | time    |
-            | 1    | 2  | ab    | 10s +-1 |
-            | 1    | 3  | ab    | 20s +-1 |
-            | 1    | 4  | ab    | 30s +-1 |
-            | 4    | 3  | ab    | 10s +-1 |
-            | 4    | 2  | ab    | 20s +-1 |
-            | 4    | 1  | ab    | 30s +-1 |
+            | from | to | route    | time    |
+            | 1    | 2  | ab,ab    | 10s +-1 |
+            | 1    | 3  | ab,ab    | 20s +-1 |
+            | 1    | 4  | ab,ab    | 30s +-1 |
+            | 4    | 3  | ab,ab    | 10s +-1 |
+            | 4    | 2  | ab,ab    | 20s +-1 |
+            | 4    | 1  | ab,ab    | 30s +-1 |
 
     Scenario: Total travel time should match sum of times of individual ways
         Given a grid size of 1000 meters
@@ -228,10 +228,10 @@ Feature: Estimation of travel time
             | cd    | primary |
 
         When I route I should get
-            | from | to | route    | distances             | distance  | times              | time     |
-            | a    | b  | ab       | 1000m +-1             | 1000m +-1 | 100s +-1           | 100s +-1 |
-            | b    | c  | bc       | 2000m +-1             | 2000m +-1 | 200s +-1           | 200s +-1 |
-            | c    | d  | cd       | 3000m +-1             | 3000m +-1 | 300s +-1           | 300s +-1 |
-            | a    | c  | ab,bc    | 1000m,2000m +-1       | 3000m +-1 | 100s,200s +-1      | 300s +-1 |
-            | b    | d  | bc,cd    | 2000m,3000m +-1       | 5000m +-1 | 200s,300s +-1      | 500s +-1 |
-            | a    | d  | ab,bc,cd | 1000m,2000m,3000m +-1 | 6000m +-1 | 100s,200s,300s +-1 | 600s +-1 |
+            | from | to | route       | distances             | distance  | times              | time     |
+            | a    | b  | ab,ab       | 1000m +-1             | 1000m +-1 | 100s +-1           | 100s +-1 |
+            | b    | c  | bc,bc       | 2000m +-1             | 2000m +-1 | 200s +-1           | 200s +-1 |
+            | c    | d  | cd,cd       | 3000m +-1             | 3000m +-1 | 300s +-1           | 300s +-1 |
+            | a    | c  | ab,bc,bc    | 1000m,2000m +-1       | 3000m +-1 | 100s,200s +-1      | 300s +-1 |
+            | b    | d  | bc,cd,cd    | 2000m,3000m +-1       | 5000m +-1 | 200s,300s +-1      | 500s +-1 |
+            | a    | d  | ab,bc,cd,cd | 1000m,2000m,3000m +-1 | 6000m +-1 | 100s,200s,300s +-1 | 600s +-1 |
diff --git a/features/testbot/trip.feature b/features/testbot/trip.feature
index c9f944b..5f33763 100644
--- a/features/testbot/trip.feature
+++ b/features/testbot/trip.feature
@@ -82,5 +82,20 @@ Feature: Basic trip planning
             | waypoints                       | trips              |
             | a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p | cbalkjihgfedc,ponm |
 
+    # Test single node in each component #1850
+    Scenario: Testbot - Trip planning with less than 10 nodes
+        Given the node map
+            | a | 1 | b |
+            |   |   |   |
+            | c | 2 | d |
+
+        And the ways
+            | nodes |
+            | ab    |
+            | cd    |
+
+        When I plan a trip I should get
+            | waypoints | trips |
+            | 1,2       |       |
 
 
diff --git a/features/testbot/turn_angles.feature b/features/testbot/turn_angles.feature
new file mode 100644
index 0000000..115fd23
--- /dev/null
+++ b/features/testbot/turn_angles.feature
@@ -0,0 +1,74 @@
+ at routing @testbot @via
+Feature: Via points
+
+    Background:
+        Given the profile "testbot"
+
+        And a grid size of 4 meters
+
+    Scenario: Basic Right Turn
+        Given the node map
+            | a | b | c | d | e | f | g |
+            |   |   |   |   |   | h |   |
+            |   |   |   |   |   | i |   |
+            |   |   |   |   |   | j |   |
+            |   |   |   |   |   | k |   |
+
+        And the ways
+            | nodes   | oneway |
+            | abcdefg | yes    |
+            | ehijk   | yes    |
+
+        When I route I should get
+            | from | to | route               | distance  | turns               |
+            | a    | k  | abcdefg,ehijk,ehijk |  34m +-1  | depart,right,arrive |
+
+    Scenario: Slight Turn
+        Given the node map
+            | a | b | c | d | e | f | g |   |
+            |   |   |   |   |   | h | i |   |
+            |   |   |   |   |   |   |   | j |
+            |   |   |   |   |   |   |   | k |
+
+        And the ways
+            | nodes   | oneway |
+            | abcdefg | yes    |
+            | ehijk   | yes    |
+
+        When I route I should get
+            | from | to | route               | distance  | turns                      |
+            | a    | k  | abcdefg,ehijk,ehijk |  35m +-1  | depart,slight right,arrive |
+
+    Scenario: Nearly Slight Turn
+        Given the node map
+            | a | b | c | d | e | f | g |   |
+            |   |   |   |   |   | h |   |   |
+            |   |   |   |   |   |   | i |   |
+            |   |   |   |   |   |   |   | j |
+            |   |   |   |   |   |   |   | k |
+
+        And the ways
+            | nodes   | oneway |
+            | abcdefg | yes    |
+            | ehijk   | yes    |
+
+        When I route I should get
+            | from | to | route               | distance  | turns                      |
+            | a    | k  | abcdefg,ehijk,ehijk |  37m +-1  | depart,right,arrive        |
+
+    Scenario: Nearly Slight Turn (Variation)
+        Given the node map
+            | a | b | c | d | e | f | g |   |
+            |   |   |   |   |   | h |   |   |
+            |   |   |   |   |   |   | i |   |
+            |   |   |   |   |   |   | j |   |
+            |   |   |   |   |   |   |   | k |
+
+        And the ways
+            | nodes   | oneway |
+            | abcdefg | yes    |
+            | ehijk   | yes    |
+
+        When I route I should get
+            | from | to | route               | distance  | turns                      |
+            | a    | k  | abcdefg,ehijk,ehijk |  37m +-1  | depart,right,arrive        |
diff --git a/features/testbot/turns.feature b/features/testbot/turns.feature
index 6eba4f9..c80bdf7 100644
--- a/features/testbot/turns.feature
+++ b/features/testbot/turns.feature
@@ -14,88 +14,80 @@ Feature: Turn directions/codes
 
         And the ways
             | nodes |
-            | xa    |
-            | xb    |
-            | xc    |
-            | xd    |
-            | xe    |
-            | xf    |
-            | xg    |
-            | xh    |
             | xi    |
-            | xj    |
             | xk    |
-            | xl    |
             | xm    |
-            | xn    |
             | xo    |
-            | xp    |
+            | xa    |
+            | xc    |
+            | xe    |
+            | xg    |
 
         When I route I should get
-            | from | to | route | turns                         |
-            | i    | k  | xi,xk | head,sharp_left,destination   |
-            | i    | m  | xi,xm | head,left,destination         |
-            | i    | o  | xi,xo | head,slight_left,destination  |
-            | i    | a  | xi,xa | head,straight,destination     |
-            | i    | c  | xi,xc | head,slight_right,destination |
-            | i    | e  | xi,xe | head,right,destination        |
-            | i    | g  | xi,xg | head,sharp_right,destination  |
+            | from | to | route    | turns                      |
+            | i    | k  | xi,xk,xk | depart,sharp left,arrive   |
+            | i    | m  | xi,xm,xm | depart,left,arrive         |
+            | i    | o  | xi,xo,xo | depart,slight left,arrive  |
+            | i    | a  | xi,xa,xa | depart,straight,arrive     |
+            | i    | c  | xi,xc,xc | depart,slight right,arrive |
+            | i    | e  | xi,xe,xe | depart,right,arrive        |
+            | i    | g  | xi,xg,xg | depart,sharp right,arrive  |
 
-            | k | m | xk,xm | head,sharp_left,destination   |
-            | k | o | xk,xo | head,left,destination         |
-            | k | a | xk,xa | head,slight_left,destination  |
-            | k | c | xk,xc | head,straight,destination     |
-            | k | e | xk,xe | head,slight_right,destination |
-            | k | g | xk,xg | head,right,destination        |
-            | k | i | xk,xi | head,sharp_right,destination  |
+            | k | m | xk,xm,xm | depart,sharp left,arrive   |
+            | k | o | xk,xo,xo | depart,left,arrive         |
+            | k | a | xk,xa,xa | depart,slight left,arrive  |
+            | k | c | xk,xc,xc | depart,straight,arrive     |
+            | k | e | xk,xe,xe | depart,slight right,arrive |
+            | k | g | xk,xg,xg | depart,right,arrive        |
+            | k | i | xk,xi,xi | depart,sharp right,arrive  |
 
-            | m | o | xm,xo | head,sharp_left,destination   |
-            | m | a | xm,xa | head,left,destination         |
-            | m | c | xm,xc | head,slight_left,destination  |
-            | m | e | xm,xe | head,straight,destination     |
-            | m | g | xm,xg | head,slight_right,destination |
-            | m | i | xm,xi | head,right,destination        |
-            | m | k | xm,xk | head,sharp_right,destination  |
+            | m | o | xm,xo,xo | depart,sharp left,arrive   |
+            | m | a | xm,xa,xa | depart,left,arrive         |
+            | m | c | xm,xc,xc | depart,slight left,arrive  |
+            | m | e | xm,xe,xe | depart,straight,arrive     |
+            | m | g | xm,xg,xg | depart,slight right,arrive |
+            | m | i | xm,xi,xi | depart,right,arrive        |
+            | m | k | xm,xk,xk | depart,sharp right,arrive  |
 
-            | o | a | xo,xa | head,sharp_left,destination   |
-            | o | c | xo,xc | head,left,destination         |
-            | o | e | xo,xe | head,slight_left,destination  |
-            | o | g | xo,xg | head,straight,destination     |
-            | o | i | xo,xi | head,slight_right,destination |
-            | o | k | xo,xk | head,right,destination        |
-            | o | m | xo,xm | head,sharp_right,destination  |
+            | o | a | xo,xa,xa | depart,sharp left,arrive   |
+            | o | c | xo,xc,xc | depart,left,arrive         |
+            | o | e | xo,xe,xe | depart,slight left,arrive  |
+            | o | g | xo,xg,xg | depart,straight,arrive     |
+            | o | i | xo,xi,xi | depart,slight right,arrive |
+            | o | k | xo,xk,xk | depart,right,arrive        |
+            | o | m | xo,xm,xm | depart,sharp right,arrive  |
 
-            | a | c | xa,xc | head,sharp_left,destination   |
-            | a | e | xa,xe | head,left,destination         |
-            | a | g | xa,xg | head,slight_left,destination  |
-            | a | i | xa,xi | head,straight,destination     |
-            | a | k | xa,xk | head,slight_right,destination |
-            | a | m | xa,xm | head,right,destination        |
-            | a | o | xa,xo | head,sharp_right,destination  |
+            | a | c | xa,xc,xc | depart,sharp left,arrive   |
+            | a | e | xa,xe,xe | depart,left,arrive         |
+            | a | g | xa,xg,xg | depart,slight left,arrive  |
+            | a | i | xa,xi,xi | depart,straight,arrive     |
+            | a | k | xa,xk,xk | depart,slight right,arrive |
+            | a | m | xa,xm,xm | depart,right,arrive        |
+            | a | o | xa,xo,xo | depart,sharp right,arrive  |
 
-            | c | e | xc,xe | head,sharp_left,destination   |
-            | c | g | xc,xg | head,left,destination         |
-            | c | i | xc,xi | head,slight_left,destination  |
-            | c | k | xc,xk | head,straight,destination     |
-            | c | m | xc,xm | head,slight_right,destination |
-            | c | o | xc,xo | head,right,destination        |
-            | c | a | xc,xa | head,sharp_right,destination  |
+            | c | e | xc,xe,xe | depart,sharp left,arrive   |
+            | c | g | xc,xg,xg | depart,left,arrive         |
+            | c | i | xc,xi,xi | depart,slight left,arrive  |
+            | c | k | xc,xk,xk | depart,straight,arrive     |
+            | c | m | xc,xm,xm | depart,slight right,arrive |
+            | c | o | xc,xo,xo | depart,right,arrive        |
+            | c | a | xc,xa,xa | depart,sharp right,arrive  |
 
-            | e | g | xe,xg | head,sharp_left,destination   |
-            | e | i | xe,xi | head,left,destination         |
-            | e | k | xe,xk | head,slight_left,destination  |
-            | e | m | xe,xm | head,straight,destination     |
-            | e | o | xe,xo | head,slight_right,destination |
-            | e | a | xe,xa | head,right,destination        |
-            | e | c | xe,xc | head,sharp_right,destination  |
+            | e | g | xe,xg,xg | depart,sharp left,arrive   |
+            | e | i | xe,xi,xi | depart,left,arrive         |
+            | e | k | xe,xk,xk | depart,slight left,arrive  |
+            | e | m | xe,xm,xm | depart,straight,arrive     |
+            | e | o | xe,xo,xo | depart,slight right,arrive |
+            | e | a | xe,xa,xa | depart,right,arrive        |
+            | e | c | xe,xc,xc | depart,sharp right,arrive  |
 
-            | g | i | xg,xi | head,sharp_left,destination   |
-            | g | k | xg,xk | head,left,destination         |
-            | g | m | xg,xm | head,slight_left,destination  |
-            | g | o | xg,xo | head,straight,destination     |
-            | g | a | xg,xa | head,slight_right,destination |
-            | g | c | xg,xc | head,right,destination        |
-            | g | e | xg,xe | head,sharp_right,destination  |
+            | g | i | xg,xi,xi | depart,sharp left,arrive   |
+            | g | k | xg,xk,xk | depart,left,arrive         |
+            | g | m | xg,xm,xm | depart,slight left,arrive  |
+            | g | o | xg,xo,xo | depart,straight,arrive     |
+            | g | a | xg,xa,xa | depart,slight right,arrive |
+            | g | c | xg,xc,xc | depart,right,arrive        |
+            | g | e | xg,xe,xe | depart,sharp right,arrive  |
 
     Scenario: Turn instructions at high latitude
     # https://github.com/DennisOSRM/Project-OSRM/issues/532
@@ -116,8 +108,8 @@ Feature: Turn directions/codes
             | yz    |
 
         When I route I should get
-            | from | to | route | turns                  |
-            | a    | c  | ab,bc | head,left,destination  |
-            | c    | a  | bc,ab | head,right,destination |
-            | x    | z  | xy,yz | head,right,destination |
-            | z    | x  | yz,xy | head,left,destination  |
+            | from | to | route    | turns               |
+            | a    | c  | ab,bc,bc | depart,left,arrive  |
+            | c    | a  | bc,ab,ab | depart,right,arrive |
+            | x    | z  | xy,yz,yz | depart,right,arrive |
+            | z    | x  | yz,xy,xy | depart,left,arrive  |
diff --git a/features/testbot/utf.feature b/features/testbot/utf.feature
index d979e9f..b537163 100644
--- a/features/testbot/utf.feature
+++ b/features/testbot/utf.feature
@@ -15,7 +15,7 @@ Feature: Handling of UTF characters
             | cd    | Cyrillic Москва        |
 
         When I route I should get
-            | from | to | route                  |
-            | a    | b  | Scandinavian København |
-            | b    | c  | Japanese 東京            |
-            | c    | d  | Cyrillic Москва        |
+            | from | to | route                                         |
+            | a    | b  | Scandinavian København,Scandinavian København |
+            | b    | c  | Japanese 東京,Japanese 東京                    |
+            | c    | d  | Cyrillic Москва,Cyrillic Москва               |
diff --git a/features/testbot/uturn.feature b/features/testbot/uturn.feature
index 26c6818..f00f5fc 100644
--- a/features/testbot/uturn.feature
+++ b/features/testbot/uturn.feature
@@ -20,8 +20,8 @@ Feature: U-turns at via points
             | 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 |
+            | waypoints | route                   | turns                                                |
+            | a,e,c     | ab,be,be,ef,fg,dg,cd,cd | depart,right,arrive,depart,straight,left,left,arrive |
 
     Scenario: Query param to allow U-turns at all via points
         Given the node map
@@ -42,8 +42,8 @@ Feature: U-turns at via points
             | fg    |
 
         When I route I should get
-            | waypoints | route       |
-            | a,e,c     | ab,be,be,bc |
+            | waypoints | route             |
+            | a,e,c     | ab,be,be,be,bc,bc |
 
     @todo
     Scenario: Instructions at via points at u-turns
@@ -65,8 +65,8 @@ Feature: U-turns at via points
             | fg    |
 
         When I route I should get
-            | waypoints | route       | turns                              |
-            | a,e,c     | ab,be,be,bc | head,right,uturn,right,destination |
+            | waypoints | route          | turns                           |
+            | a,e,c     | ab,be,be,bc,bc | depart,right,uturn,right,arrive |
 
     Scenario: u-turn mixed with non-uturn vias
         Given the node map
@@ -88,6 +88,6 @@ Feature: U-turns at via points
             | fg    |
 
         When I route I should get
-            | waypoints | route                      |
-            | 1,2,3,4,5 | ab,be,be,bc,bc,cd,dg,dg,cd |
+            | waypoints | route                                        |
+            | 1,2,3,4,5 | ab,be,be,be,bc,bc,bc,be,ef,fg,dg,dg,dg,cd,cd |
 
diff --git a/features/testbot/via.feature b/features/testbot/via.feature
index a88b0f4..84b939b 100644
--- a/features/testbot/via.feature
+++ b/features/testbot/via.feature
@@ -13,9 +13,23 @@ Feature: Via points
             | abc   |
 
         When I route I should get
-            | waypoints | route   |
-            | a,b,c     | abc,abc |
-            | c,b,a     | abc,abc |
+            | waypoints | route           |
+            | a,b,c     | abc,abc,abc,abc |
+
+    Scenario: Simple via point with core factor
+        Given the contract extra arguments "--core 0.8"
+        Given the node map
+            | a | b | c |
+
+        And the ways
+            | nodes |
+            | abc   |
+
+        When I route I should get
+            | waypoints | route           |
+            | a,b,c     | abc,abc,abc,abc |
+            | c,b,a     | abc,abc,abc,abc |
+            | c,b,a     | abc,abc,abc,abc |
 
     Scenario: Via point at a dead end
         Given the node map
@@ -28,10 +42,11 @@ Feature: Via points
             | bd    |
 
         When I route I should get
-            | waypoints | route            |
-            | a,d,c     | abc,bd,bd,bd,abc |
-            | c,d,a     | abc,bd,bd,bd,abc |
+            | waypoints | route                |
+            | a,d,c     | abc,bd,bd,bd,abc,abc |
+            | c,d,a     | abc,bd,bd,bd,abc,abc |
 
+    @mokob
     Scenario: Multiple via points
         Given the node map
             | a |   |   |   | e | f | g |   |
@@ -48,9 +63,9 @@ Feature: Via points
             | dh    |
 
         When I route I should get
-            | waypoints | route                    |
-            | a,c,f     | ab,bcd,bcd,de,efg        |
-            | a,c,f,h   | ab,bcd,bcd,de,efg,efg,gh |
+            | waypoints | route                               |
+            | a,c,f     | ab,bcd,bcd,bcd,de,efg,efg           |
+            | a,c,f,h   | ab,bcd,bcd,bcd,de,efg,efg,efg,gh,gh |
 
 
     Scenario: Duplicate via point
@@ -65,8 +80,8 @@ Feature: Via points
             | ab    |
 
         When I route I should get
-            | waypoints | route | turns                |
-            | 1,1,4     | ab,ab | head,via,destination |
+            | waypoints | route       |
+            | 1,1,4     | ab,ab,ab,ab |
 
     Scenario: Via points on ring of oneways
     # xa it to avoid only having a single ring, which cna trigger edge cases
@@ -86,12 +101,12 @@ Feature: Via points
             | fa    | yes    |
 
         When I route I should get
-            | 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,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 |
+            | waypoints | route                                     | distance  |
+            | 1,3       | ab,bc,cd,cd                               |  400m +-1 |
+            | 3,1       | cd,de,ef,fa,ab,ab                         | 1000m +-1 |
+            | 1,2,3     | ab,bc,bc,bc,cd,cd                         |  400m +-1 |
+            | 1,3,2     | ab,bc,cd,cd,cd,de,ef,fa,ab,bc,bc          | 1600m +-1 |
+            | 3,2,1     | cd,de,ef,fa,ab,bc,bc,bc,cd,de,ef,fa,ab,ab | 2400m +-1 |
 
     Scenario: Via points on ring on the same oneway
     # xa it to avoid only having a single ring, which cna trigger edge cases
@@ -109,9 +124,95 @@ Feature: Via points
             | da    | yes    |
 
         When I route I should get
-            | waypoints | route                      | distance  | turns                                                            |
-            | 1,3       | ab                         | 200m +-1  | head,destination                                                 |
-            | 3,1       | ab,bc,cd,da,ab             | 800m +-1  | head,right,right,right,right,destination                         |
-            | 1,2,3     | ab,ab                      | 200m +-1  | head,via,destination                                             |
-            | 1,3,2     | ab,ab,bc,cd,da,ab          | 1100m +-1 | head,via,right,right,right,right,destination                     |
-            | 3,2,1     | ab,bc,cd,da,ab,ab,bc,cd,da,ab | 1800m     | head,right,right,right,right,via,right,right,right,right,destination |
+            | waypoints | route                               | distance  |
+            | 1,3       | ab,ab                               | 200m +-1  |
+            | 3,1       | ab,bc,cd,da,ab,ab                   | 800m +-1  |
+            | 1,2,3     | ab,ab,ab,ab                         | 200m +-1  |
+            | 1,3,2     | ab,ab,ab,bc,cd,da,ab,ab             | 1100m +-1 |
+            | 3,2,1     | ab,bc,cd,da,ab,ab,ab,bc,cd,da,ab,ab | 1800m +-1 |
+
+    # See issue #1896
+    Scenario: Via point at a dead end with oneway
+        Given the node map
+            | a | b | c |
+            |   | d |   |
+            |   | e |   |
+
+        And the ways
+            | nodes | oneway |
+            | abc   |  no    |
+            | bd    |  no    |
+            | de    |  yes   |
+
+        When I route I should get
+            | waypoints | route                |
+            | a,d,c     | abc,bd,bd,bd,abc,abc |
+            | c,d,a     | abc,bd,bd,bd,abc,abc |
+
+    # See issue #1896
+    Scenario: Via point at a dead end with barrier
+        Given the profile "car"
+        Given the node map
+            | a | b | c |
+            |   | 1 |   |
+            |   | d |   |
+            |   |   |   |
+            |   |   |   |
+            | f | e |   |
+
+        And the nodes
+            | node | barrier |
+            | d    | bollard |
+
+        And the ways
+            | nodes |
+            | abc   |
+            | bd    |
+            | afed  |
+
+        When I route I should get
+            | waypoints | route                   |
+            | a,1,c     | abc,bd,bd,bd,bd,abc,abc |
+            | c,1,a     | abc,bd,bd,bd,bd,abc,abc |
+
+    Scenario: Via points on ring on the same oneway, forces one of the vertices to be top node
+        Given the node map
+            | a | 1 | 2 | b |
+            | 8 |   |   | 3 |
+            | 7 |   |   | 4 |
+            | d | 6 | 5 | c |
+
+        And the ways
+            | nodes | oneway |
+            | ab    | yes    |
+            | bc    | yes    |
+            | cd    | yes    |
+            | da    | yes    |
+
+        When I route I should get
+            | waypoints | route                      | distance   |
+            | 2,1       | ab,bc,cd,da,ab,ab          | 1100m +-1  |
+            | 4,3       | bc,cd,da,ab,bc,bc          | 1100m +-1  |
+            | 6,5       | cd,da,ab,bc,cd,cd          | 1100m +-1  |
+            | 8,7       | da,ab,bc,cd,da,da          | 1100m +-1  |
+
+    Scenario: Multiple Via points on ring on the same oneway, forces one of the vertices to be top node
+        Given the node map
+            | a | 1 | 2 | 3 | b |
+            |   |   |   |   | 4 |
+            |   |   |   |   | 5 |
+            |   |   |   |   | 6 |
+            | d | 9 | 8 | 7 | c |
+
+        And the ways
+            | nodes | oneway |
+            | ab    | yes    |
+            | bc    | yes    |
+            | cd    | yes    |
+            | da    | yes    |
+
+        When I route I should get
+            | waypoints | route                               | distance     |
+            | 3,2,1     | ab,bc,cd,da,ab,ab,ab,bc,cd,da,ab,ab | 3000m +-1    |
+            | 6,5,4     | bc,cd,da,ab,bc,bc,bc,cd,da,ab,bc,bc | 3000m +-1    |
+            | 9,8,7     | cd,da,ab,bc,cd,cd,cd,da,ab,bc,cd,cd | 3000m +-1    |
diff --git a/features/timestamp/timestamp.feature b/features/timestamp/timestamp.feature
deleted file mode 100644
index 70ef91c..0000000
--- a/features/timestamp/timestamp.feature
+++ /dev/null
@@ -1,11 +0,0 @@
- at timestamp
-Feature: Timestamp
-
-    Scenario: Request timestamp
-        Given the node map
-            | a | b |
-        And the ways
-            | nodes |
-            | ab    |
-        When I request /timestamp
-        Then I should get a valid timestamp
diff --git a/include/contractor/contractor.hpp b/include/contractor/contractor.hpp
new file mode 100644
index 0000000..7cfc3dc
--- /dev/null
+++ b/include/contractor/contractor.hpp
@@ -0,0 +1,96 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+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 CONTRACTOR_CONTRACTOR_HPP
+#define CONTRACTOR_CONTRACTOR_HPP
+
+#include "contractor/contractor_config.hpp"
+#include "contractor/query_edge.hpp"
+#include "extractor/edge_based_edge.hpp"
+#include "extractor/edge_based_node.hpp"
+#include "util/typedefs.hpp"
+#include "util/deallocating_vector.hpp"
+
+#include <vector>
+#include <string>
+
+#include <cstddef>
+
+namespace osrm
+{
+namespace contractor
+{
+
+/// Base class of osrm-contract
+class Contractor
+{
+  public:
+    using EdgeData = QueryEdge::EdgeData;
+
+    explicit Contractor(const ContractorConfig &config_) : config{config_} {}
+
+    Contractor(const Contractor &) = delete;
+    Contractor &operator=(const Contractor &) = delete;
+
+    int Run();
+
+  protected:
+    void ContractGraph(const unsigned max_edge_id,
+                       util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
+                       util::DeallocatingVector<QueryEdge> &contracted_edge_list,
+                       std::vector<EdgeWeight> &&node_weights,
+                       std::vector<bool> &is_core_node,
+                       std::vector<float> &inout_node_levels) const;
+    void WriteCoreNodeMarker(std::vector<bool> &&is_core_node) const;
+    void WriteNodeLevels(std::vector<float> &&node_levels) const;
+    void ReadNodeLevels(std::vector<float> &contraction_order) const;
+    std::size_t
+    WriteContractedGraph(unsigned number_of_edge_based_nodes,
+                         const util::DeallocatingVector<QueryEdge> &contracted_edge_list);
+    void FindComponents(unsigned max_edge_id,
+                        const util::DeallocatingVector<extractor::EdgeBasedEdge> &edges,
+                        std::vector<extractor::EdgeBasedNode> &nodes) const;
+
+  private:
+    ContractorConfig config;
+
+    std::size_t
+    LoadEdgeExpandedGraph(const std::string &edge_based_graph_path,
+                          util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
+                          const std::string &edge_segment_lookup_path,
+                          const std::string &edge_penalty_path,
+                          const std::vector<std::string> &segment_speed_path,
+                          const std::string &nodes_filename,
+                          const std::string &geometry_filename,
+                          const std::string &datasource_names_filename,
+                          const std::string &datasource_indexes_filename,
+                          const std::string &rtree_leaf_filename);
+};
+}
+}
+
+#endif // PROCESSING_CHAIN_HPP
diff --git a/contractor/contractor_options.hpp b/include/contractor/contractor_config.hpp
similarity index 56%
rename from contractor/contractor_options.hpp
rename to include/contractor/contractor_config.hpp
index 5932b78..f557279 100644
--- a/contractor/contractor_options.hpp
+++ b/include/contractor/contractor_config.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -32,20 +32,33 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <string>
 
-enum class return_code : unsigned
+namespace osrm
+{
+namespace contractor
 {
-    ok,
-    fail,
-    exit
-};
 
 struct ContractorConfig
 {
-    ContractorConfig() noexcept : requested_num_threads(0) {}
+    ContractorConfig() : requested_num_threads(0) {}
+
+    // Infer the output names from the path of the .osrm file
+    void UseDefaultOutputNames()
+    {
+        level_output_path = osrm_input_path.string() + ".level";
+        core_output_path = osrm_input_path.string() + ".core";
+        graph_output_path = osrm_input_path.string() + ".hsgr";
+        edge_based_graph_path = osrm_input_path.string() + ".ebg";
+        edge_segment_lookup_path = osrm_input_path.string() + ".edge_segment_lookup";
+        edge_penalty_path = osrm_input_path.string() + ".edge_penalties";
+        node_based_graph_path = osrm_input_path.string() + ".nodes";
+        geometry_path = osrm_input_path.string() + ".geometry";
+        rtree_leaf_path = osrm_input_path.string() + ".fileIndex";
+        datasource_names_path = osrm_input_path.string() + ".datasource_names";
+        datasource_indexes_path = osrm_input_path.string() + ".datasource_indexes";
+    }
 
     boost::filesystem::path config_file_path;
     boost::filesystem::path osrm_input_path;
-    boost::filesystem::path profile_path;
 
     std::string level_output_path;
     std::string core_output_path;
@@ -54,28 +67,24 @@ struct ContractorConfig
 
     std::string edge_segment_lookup_path;
     std::string edge_penalty_path;
+    std::string node_based_graph_path;
+    std::string geometry_path;
+    std::string rtree_leaf_path;
     bool use_cached_priority;
 
     unsigned requested_num_threads;
 
-    //A percentage of vertices that will be contracted for the hierarchy.
-    //Offers a trade-off between preprocessing and query time.
-    //The remaining vertices form the core of the hierarchy 
+    // A percentage of vertices that will be contracted for the hierarchy.
+    // Offers a trade-off between preprocessing and query time.
+    // The remaining vertices form the core of the hierarchy
     //(e.g. 0.8 contracts 80 percent of the hierarchy, leaving a core of 20%)
     double core_factor;
 
-    std::string segment_speed_lookup_path;
-
-#ifdef DEBUG_GEOMETRY
-    std::string debug_geometry_path;
-#endif
-};
-
-struct ContractorOptions
-{
-    static return_code ParseArguments(int argc, char *argv[], ContractorConfig &extractor_config);
-
-    static void GenerateOutputFilesNames(ContractorConfig &extractor_config);
+    std::vector<std::string> segment_speed_lookup_paths;
+    std::string datasource_indexes_path;
+    std::string datasource_names_path;
 };
+}
+}
 
 #endif // EXTRACTOR_OPTIONS_HPP
diff --git a/algorithms/crc32_processor.hpp b/include/contractor/crc32_processor.hpp
similarity index 71%
rename from algorithms/crc32_processor.hpp
rename to include/contractor/crc32_processor.hpp
index a31b4ad..eaef76c 100644
--- a/algorithms/crc32_processor.hpp
+++ b/include/contractor/crc32_processor.hpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 ITERATOR_BASED_CRC32_H
 #define ITERATOR_BASED_CRC32_H
 
@@ -36,6 +9,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <iterator>
 
+namespace osrm
+{
+namespace contractor
+{
+
 class IteratorbasedCRC32
 {
   public:
@@ -141,5 +119,7 @@ struct RangebasedCRC32
   private:
     IteratorbasedCRC32 crc32;
 };
+}
+}
 
 #endif /* ITERATOR_BASED_CRC32_H */
diff --git a/contractor/contractor.hpp b/include/contractor/graph_contractor.hpp
similarity index 68%
rename from contractor/contractor.hpp
rename to include/contractor/graph_contractor.hpp
index 07a21dc..26be61d 100644
--- a/contractor/contractor.hpp
+++ b/include/contractor/graph_contractor.hpp
@@ -1,44 +1,17 @@
-/*
-
-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 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"
+#ifndef GRAPH_CONTRACTOR_HPP
+#define GRAPH_CONTRACTOR_HPP
+
+#include "util/binary_heap.hpp"
+#include "util/deallocating_vector.hpp"
+#include "util/dynamic_graph.hpp"
+#include "util/percent.hpp"
+#include "contractor/query_edge.hpp"
+#include "util/xor_fast_hash.hpp"
+#include "util/xor_fast_hash_storage.hpp"
+#include "util/integer_range.hpp"
+#include "util/simple_logger.hpp"
+#include "util/timing_util.hpp"
+#include "util/typedefs.hpp"
 
 #include <boost/assert.hpp>
 
@@ -53,9 +26,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <memory>
 #include <vector>
 
-class Contractor
+namespace osrm
+{
+namespace contractor
 {
 
+class GraphContractor
+{
   private:
     struct ContractorEdgeData
     {
@@ -86,18 +63,22 @@ class Contractor
 
     struct ContractorHeapData
     {
-        short hop;
-        bool target;
-        ContractorHeapData() : hop(0), target(false) {}
-        ContractorHeapData(short h, bool t) : hop(h), target(t) {}
+        ContractorHeapData() {}
+        ContractorHeapData(short hop_, bool target_) : hop(hop_), target(target_) {}
+
+        short hop = 0;
+        bool target = false;
     };
 
-    using ContractorGraph = DynamicGraph<ContractorEdgeData>;
-    //    using ContractorHeap = BinaryHeap<NodeID, NodeID, int, ContractorHeapData,
+    using ContractorGraph = util::DynamicGraph<ContractorEdgeData>;
+    //    using ContractorHeap = util::BinaryHeap<NodeID, NodeID, int, ContractorHeapData,
     //    ArrayStorage<NodeID, NodeID>
     //    >;
-    using ContractorHeap =
-        BinaryHeap<NodeID, NodeID, int, ContractorHeapData, XORFastHashStorage<NodeID, NodeID>>;
+    using ContractorHeap = util::BinaryHeap<NodeID,
+                                            NodeID,
+                                            int,
+                                            ContractorHeapData,
+                                            util::XORFastHashStorage<NodeID, NodeID>>;
     using ContractorEdge = ContractorGraph::InputEdge;
 
     struct ContractorThreadData
@@ -108,11 +89,7 @@ class Contractor
         explicit ContractorThreadData(NodeID nodes) : heap(nodes) {}
     };
 
-    struct NodePriorityData
-    {
-        int depth;
-        NodePriorityData() : depth(0) {}
-    };
+    using NodeDepth = int;
 
     struct ContractionStats
     {
@@ -157,16 +134,18 @@ class Contractor
     };
 
   public:
-    template <class ContainerT> Contractor(int nodes, ContainerT &input_edge_list)
-      : Contractor(nodes, input_edge_list, {}, {})
+    template <class ContainerT>
+    GraphContractor(int nodes, ContainerT &input_edge_list)
+        : GraphContractor(nodes, input_edge_list, {}, {})
     {
     }
 
     template <class ContainerT>
-    Contractor(int nodes,
-               ContainerT &input_edge_list,
-               std::vector<float> &&node_levels_)
-        : node_levels(std::move(node_levels_))
+    GraphContractor(int nodes,
+                    ContainerT &input_edge_list,
+                    std::vector<float> &&node_levels_,
+                    std::vector<EdgeWeight> &&node_weights_)
+        : node_levels(std::move(node_levels_)), node_weights(std::move(node_weights_))
     {
         std::vector<ContractorEdge> edges;
         edges.reserve(input_edge_list.size() * 2);
@@ -179,7 +158,7 @@ class Contractor
 #ifndef NDEBUG
             if (static_cast<unsigned int>(std::max(diter->weight, 1)) > 24 * 60 * 60 * 10)
             {
-                SimpleLogger().Write(logWARNING)
+                util::SimpleLogger().Write(logWARNING)
                     << "Edge weight large -> "
                     << static_cast<unsigned int>(std::max(diter->weight, 1)) << " : "
                     << static_cast<unsigned int>(diter->source) << " -> "
@@ -223,8 +202,7 @@ class Contractor
             forward_edge.data.shortcut = reverse_edge.data.shortcut = false;
             forward_edge.data.id = reverse_edge.data.id = id;
             forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1;
-            forward_edge.data.distance = reverse_edge.data.distance =
-                std::numeric_limits<int>::max();
+            forward_edge.data.distance = reverse_edge.data.distance = INVALID_EDGE_WEIGHT;
             // remove parallel edges
             while (i < edges.size() && edges[i].source == source && edges[i].target == target)
             {
@@ -243,7 +221,7 @@ class Contractor
             // 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())
+                if ((int)forward_edge.data.distance != INVALID_EDGE_WEIGHT)
                 {
                     forward_edge.data.backward = true;
                     edges[edge++] = forward_edge;
@@ -251,70 +229,47 @@ class Contractor
             }
             else
             { // insert seperate edges
-                if (((int)forward_edge.data.distance) != std::numeric_limits<int>::max())
+                if (((int)forward_edge.data.distance) != INVALID_EDGE_WEIGHT)
                 {
                     edges[edge++] = forward_edge;
                 }
-                if ((int)reverse_edge.data.distance != std::numeric_limits<int>::max())
+                if ((int)reverse_edge.data.distance != INVALID_EDGE_WEIGHT)
                 {
                     edges[edge++] = reverse_edge;
                 }
             }
         }
-        std::cout << "merged " << edges.size() - edge << " edges out of " << edges.size()
-                  << std::endl;
+        util::SimpleLogger().Write() << "merged " << edges.size() - edge << " edges out of "
+                                     << edges.size();
         edges.resize(edge);
         contractor_graph = std::make_shared<ContractorGraph>(nodes, edges);
         edges.clear();
         edges.shrink_to_fit();
 
         BOOST_ASSERT(0 == edges.capacity());
-        //        unsigned maxdegree = 0;
-        //        NodeID highestNode = 0;
-        //
-        //        for(unsigned i = 0; i < contractor_graph->GetNumberOfNodes(); ++i) {
-        //            unsigned degree = contractor_graph->EndEdges(i) -
-        //            contractor_graph->BeginEdges(i);
-        //            if(degree > maxdegree) {
-        //                maxdegree = degree;
-        //                highestNode = i;
-        //            }
-        //        }
-        //
-        //        SimpleLogger().Write() << "edges at node with id " << highestNode << " has degree
-        //        " << maxdegree;
-        //        for(unsigned i = contractor_graph->BeginEdges(highestNode); i <
-        //        contractor_graph->EndEdges(highestNode); ++i) {
-        //            SimpleLogger().Write() << " ->(" << highestNode << "," <<
-        //            contractor_graph->GetTarget(i)
-        //            << "); via: " << contractor_graph->GetEdgeData(i).via;
-        //        }
-
-        std::cout << "contractor finished initalization" << std::endl;
+        util::SimpleLogger().Write() << "contractor finished initalization";
     }
 
-    ~Contractor() {}
-
     void Run(double core_factor = 1.0)
     {
         // for the preperation we can use a big grain size, which is much faster (probably cache)
-        constexpr size_t InitGrainSize = 100000;
-        constexpr size_t PQGrainSize = 100000;
+        const constexpr size_t InitGrainSize = 100000;
+        const constexpr size_t PQGrainSize = 100000;
         // auto_partitioner will automatically increase the blocksize if we have
         // a lot of data. It is *important* for the last loop iterations
         // (which have a very small dataset) that it is devisible.
-        constexpr size_t IndependentGrainSize = 1;
-        constexpr size_t ContractGrainSize = 1;
-        constexpr size_t NeighboursGrainSize = 1;
-        constexpr size_t DeleteGrainSize = 1;
+        const constexpr size_t IndependentGrainSize = 1;
+        const constexpr size_t ContractGrainSize = 1;
+        const constexpr size_t NeighboursGrainSize = 1;
+        const constexpr size_t DeleteGrainSize = 1;
 
         const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
-        Percent p(number_of_nodes);
+        util::Percent p(number_of_nodes);
 
         ThreadDataContainer thread_data_list(number_of_nodes);
 
         NodeID number_of_contracted_nodes = 0;
-        std::vector<NodePriorityData> node_data;
+        std::vector<NodeDepth> node_depth;
         std::vector<float> node_priorities;
         is_core_node.resize(number_of_nodes, false);
 
@@ -338,20 +293,20 @@ class Contractor
         }
         else
         {
-            node_data.resize(number_of_nodes);
+            node_depth.resize(number_of_nodes, 0);
             node_priorities.resize(number_of_nodes);
             node_levels.resize(number_of_nodes);
 
             std::cout << "initializing elimination PQ ..." << std::flush;
             tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, PQGrainSize),
-                              [this, &node_priorities, &node_data, &thread_data_list](
-                                  const tbb::blocked_range<int> &range)
+                              [this, &node_priorities, &node_depth,
+                               &thread_data_list](const tbb::blocked_range<int> &range)
                               {
                                   ContractorThreadData *data = thread_data_list.getThreadData();
                                   for (int x = range.begin(), end = range.end(); x != end; ++x)
                                   {
                                       node_priorities[x] =
-                                          this->EvaluateNodePriority(data, &node_data[x], x);
+                                          this->EvaluateNodePriority(data, node_depth[x], x);
                                   }
                               });
             std::cout << "ok" << std::endl;
@@ -368,9 +323,10 @@ class Contractor
             if (!flushed_contractor && (number_of_contracted_nodes >
                                         static_cast<NodeID>(number_of_nodes * 0.65 * core_factor)))
             {
-                DeallocatingVector<ContractorEdge> new_edge_set; // this one is not explicitely
-                                                                 // cleared since it goes out of
-                                                                 // scope anywa
+                util::DeallocatingVector<ContractorEdge>
+                    new_edge_set; // this one is not explicitely
+                                  // cleared since it goes out of
+                                  // scope anywa
                 std::cout << " [flush " << number_of_contracted_nodes << " nodes] " << std::flush;
 
                 // Delete old heap data to free memory that we need for the coming operations
@@ -378,24 +334,27 @@ class Contractor
 
                 // Create new priority array
                 std::vector<float> new_node_priority(remaining_nodes.size());
+                std::vector<EdgeWeight> new_node_weights(remaining_nodes.size());
                 // this map gives the old IDs from the new ones, necessary to get a consistent graph
                 // at the end of contraction
                 orig_node_id_from_new_node_id_map.resize(remaining_nodes.size());
                 // this map gives the new IDs from the old ones, necessary to remap targets from the
                 // remaining graph
-                std::vector<NodeID> new_node_id_from_orig_id_map(number_of_nodes, UINT_MAX);
+                std::vector<NodeID> new_node_id_from_orig_id_map(number_of_nodes, SPECIAL_NODEID);
 
-                for (const auto new_node_id : osrm::irange<std::size_t>(0, remaining_nodes.size()))
+                for (const auto new_node_id : util::irange<std::size_t>(0, remaining_nodes.size()))
                 {
-                    auto& node = remaining_nodes[new_node_id];
+                    auto &node = remaining_nodes[new_node_id];
                     BOOST_ASSERT(node_priorities.size() > node.id);
                     new_node_priority[new_node_id] = node_priorities[node.id];
+                    BOOST_ASSERT(node_weights.size() > node.id);
+                    new_node_weights[new_node_id] = node_weights[node.id];
                 }
 
                 // build forward and backward renumbering map and remap ids in remaining_nodes
-                for (const auto new_node_id : osrm::irange<std::size_t>(0, remaining_nodes.size()))
+                for (const auto new_node_id : util::irange<std::size_t>(0, remaining_nodes.size()))
                 {
-                    auto& node = remaining_nodes[new_node_id];
+                    auto &node = remaining_nodes[new_node_id];
                     // create renumbering maps in both directions
                     orig_node_id_from_new_node_id_map[new_node_id] = node.id;
                     new_node_id_from_orig_id_map[node.id] = new_node_id;
@@ -403,7 +362,7 @@ class Contractor
                 }
                 // walk over all nodes
                 for (const auto source :
-                     osrm::irange<NodeID>(0, contractor_graph->GetNumberOfNodes()))
+                     util::irange<NodeID>(0, contractor_graph->GetNumberOfNodes()))
                 {
                     for (auto current_edge : contractor_graph->GetAdjacentEdgeRange(source))
                     {
@@ -417,15 +376,14 @@ class Contractor
                         else
                         {
                             // node is not yet contracted.
-                            // add (renumbered) outgoing edges to new DynamicGraph.
+                            // add (renumbered) outgoing edges to new util::DynamicGraph.
                             ContractorEdge new_edge = {new_node_id_from_orig_id_map[source],
-                                                       new_node_id_from_orig_id_map[target],
-                                                       data};
+                                                       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],
+                            BOOST_ASSERT_MSG(SPECIAL_NODEID != new_node_id_from_orig_id_map[source],
                                              "new source id not resolveable");
-                            BOOST_ASSERT_MSG(UINT_MAX != new_node_id_from_orig_id_map[target],
+                            BOOST_ASSERT_MSG(SPECIAL_NODEID != new_node_id_from_orig_id_map[target],
                                              "new target id not resolveable");
                             new_edge_set.push_back(new_edge);
                         }
@@ -439,8 +397,12 @@ class Contractor
                 // Replace old priorities array by new one
                 node_priorities.swap(new_node_priority);
                 // Delete old node_priorities vector
+                // Due to the scope, these should get cleared automatically? @daniel-j-h do you
+                // agree?
                 new_node_priority.clear();
                 new_node_priority.shrink_to_fit();
+
+                node_weights.swap(new_node_weights);
                 // old Graph is removed
                 contractor_graph.reset();
 
@@ -457,39 +419,44 @@ class Contractor
                 thread_data_list.number_of_nodes = contractor_graph->GetNumberOfNodes();
             }
 
-            tbb::parallel_for(tbb::blocked_range<std::size_t>(0, remaining_nodes.size(), IndependentGrainSize),
-                              [this, &node_priorities, &remaining_nodes, &thread_data_list](
-                                  const tbb::blocked_range<std::size_t> &range)
-                              {
-                                  ContractorThreadData *data = thread_data_list.getThreadData();
-                                  // determine independent node set
-                                  for (auto i = range.begin(), end = range.end(); i != end; ++i)
-                                  {
-                                      const NodeID node = remaining_nodes[i].id;
-                                      remaining_nodes[i].is_independent =
-                                          this->IsNodeIndependent(node_priorities, data, node);
-                                  }
-                              });
+            tbb::parallel_for(
+                tbb::blocked_range<std::size_t>(0, remaining_nodes.size(), IndependentGrainSize),
+                [this, &node_priorities, &remaining_nodes,
+                 &thread_data_list](const tbb::blocked_range<std::size_t> &range)
+                {
+                    ContractorThreadData *data = thread_data_list.getThreadData();
+                    // determine independent node set
+                    for (auto i = range.begin(), end = range.end(); i != end; ++i)
+                    {
+                        const NodeID node = remaining_nodes[i].id;
+                        remaining_nodes[i].is_independent =
+                            this->IsNodeIndependent(node_priorities, data, node);
+                    }
+                });
 
             // sort all remaining nodes to the beginning of the sequence
-            const auto begin_independent_nodes = stable_partition(remaining_nodes.begin(), remaining_nodes.end(),
-                                                [](RemainingNodeData node_data)
-                                                {
-                                                    return !node_data.is_independent;
-                                                });
-            auto begin_independent_nodes_idx = std::distance(remaining_nodes.begin(), begin_independent_nodes);
+            const auto begin_independent_nodes = stable_partition(
+                remaining_nodes.begin(), remaining_nodes.end(), [](RemainingNodeData node_data)
+                {
+                    return !node_data.is_independent;
+                });
+            auto begin_independent_nodes_idx =
+                std::distance(remaining_nodes.begin(), begin_independent_nodes);
             auto end_independent_nodes_idx = remaining_nodes.size();
 
             if (!use_cached_node_priorities)
             {
                 // write out contraction level
                 tbb::parallel_for(
-                    tbb::blocked_range<std::size_t>(begin_independent_nodes_idx, end_independent_nodes_idx, ContractGrainSize),
-                    [this, remaining_nodes, flushed_contractor, current_level](const tbb::blocked_range<std::size_t> &range)
+                    tbb::blocked_range<std::size_t>(begin_independent_nodes_idx,
+                                                    end_independent_nodes_idx, ContractGrainSize),
+                    [this, remaining_nodes, flushed_contractor,
+                     current_level](const tbb::blocked_range<std::size_t> &range)
                     {
                         if (flushed_contractor)
                         {
-                            for (int position = range.begin(), end = range.end(); position != end; ++position)
+                            for (int position = range.begin(), end = range.end(); position != end;
+                                 ++position)
                             {
                                 const NodeID x = remaining_nodes[position].id;
                                 node_levels[orig_node_id_from_new_node_id_map[x]] = current_level;
@@ -497,7 +464,8 @@ class Contractor
                         }
                         else
                         {
-                            for (int position = range.begin(), end = range.end(); position != end; ++position)
+                            for (int position = range.begin(), end = range.end(); position != end;
+                                 ++position)
                             {
                                 const NodeID x = remaining_nodes[position].id;
                                 node_levels[x] = current_level;
@@ -507,24 +475,29 @@ class Contractor
             }
 
             // contract independent nodes
-            tbb::parallel_for(
-                tbb::blocked_range<std::size_t>(begin_independent_nodes_idx, end_independent_nodes_idx, ContractGrainSize),
-                [this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<std::size_t> &range)
-                {
-                    ContractorThreadData *data = thread_data_list.getThreadData();
-                    for (int position = range.begin(), end = range.end(); position != end; ++position)
-                    {
-                        const NodeID x = remaining_nodes[position].id;
-                        this->ContractNode<false>(data, x);
-                    }
-                });
+            tbb::parallel_for(tbb::blocked_range<std::size_t>(begin_independent_nodes_idx,
+                                                              end_independent_nodes_idx,
+                                                              ContractGrainSize),
+                              [this, &remaining_nodes,
+                               &thread_data_list](const tbb::blocked_range<std::size_t> &range)
+                              {
+                                  ContractorThreadData *data = thread_data_list.getThreadData();
+                                  for (int position = range.begin(), end = range.end();
+                                       position != end; ++position)
+                                  {
+                                      const NodeID x = remaining_nodes[position].id;
+                                      this->ContractNode<false>(data, x);
+                                  }
+                              });
 
             tbb::parallel_for(
-                tbb::blocked_range<int>(begin_independent_nodes_idx, end_independent_nodes_idx, DeleteGrainSize),
+                tbb::blocked_range<int>(begin_independent_nodes_idx, end_independent_nodes_idx,
+                                        DeleteGrainSize),
                 [this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int> &range)
                 {
                     ContractorThreadData *data = thread_data_list.getThreadData();
-                    for (int position = range.begin(), end = range.end(); position != end; ++position)
+                    for (int position = range.begin(), end = range.end(); position != end;
+                         ++position)
                     {
                         const NodeID x = remaining_nodes[position].id;
                         this->DeleteIncomingEdges(data, x);
@@ -569,15 +542,17 @@ class Contractor
             if (!use_cached_node_priorities)
             {
                 tbb::parallel_for(
-                    tbb::blocked_range<int>(begin_independent_nodes_idx, end_independent_nodes_idx, NeighboursGrainSize),
-                    [this, &node_priorities, &remaining_nodes, &node_data, &thread_data_list](
-                        const tbb::blocked_range<int> &range)
+                    tbb::blocked_range<int>(begin_independent_nodes_idx, end_independent_nodes_idx,
+                                            NeighboursGrainSize),
+                    [this, &node_priorities, &remaining_nodes, &node_depth,
+                     &thread_data_list](const tbb::blocked_range<int> &range)
                     {
                         ContractorThreadData *data = thread_data_list.getThreadData();
-                        for (int position = range.begin(), end = range.end(); position != end; ++position)
+                        for (int position = range.begin(), end = range.end(); position != end;
+                             ++position)
                         {
                             NodeID x = remaining_nodes[position].id;
-                            this->UpdateNodeNeighbours(node_priorities, node_data, data, x);
+                            this->UpdateNodeNeighbours(node_priorities, node_depth, data, x);
                         }
                     });
             }
@@ -585,30 +560,6 @@ class Contractor
             // remove contracted nodes from the pool
             number_of_contracted_nodes += end_independent_nodes_idx - begin_independent_nodes_idx;
             remaining_nodes.resize(begin_independent_nodes_idx);
-            //            unsigned maxdegree = 0;
-            //            unsigned avgdegree = 0;
-            //            unsigned mindegree = UINT_MAX;
-            //            unsigned quaddegree = 0;
-            //
-            //            for(unsigned i = 0; i < remaining_nodes.size(); ++i) {
-            //                unsigned degree = contractor_graph->EndEdges(remaining_nodes[i].id)
-            //                -
-            //                contractor_graph->BeginEdges(remaining_nodes[i].first);
-            //                if(degree > maxdegree)
-            //                    maxdegree = degree;
-            //                if(degree < mindegree)
-            //                    mindegree = degree;
-            //
-            //                avgdegree += degree;
-            //                quaddegree += (degree*degree);
-            //            }
-            //
-            //            avgdegree /= std::max((unsigned)1,(unsigned)remaining_nodes.size() );
-            //            quaddegree /= std::max((unsigned)1,(unsigned)remaining_nodes.size() );
-            //
-            //            SimpleLogger().Write() << "rest: " << remaining_nodes.size() << ", max: "
-            //            << maxdegree << ", min: " << mindegree << ", avg: " << avgdegree << ",
-            //            quad: " << quaddegree;
 
             p.printStatus(number_of_contracted_nodes);
             ++current_level;
@@ -616,32 +567,31 @@ class Contractor
 
         if (remaining_nodes.size() > 2)
         {
-              if (orig_node_id_from_new_node_id_map.size() > 0)
-              {
-                  tbb::parallel_for(
-                      tbb::blocked_range<int>(0, remaining_nodes.size(), InitGrainSize),
-                      [this, &remaining_nodes](const tbb::blocked_range<int> &range)
-                      {
-                          for (int x = range.begin(), end = range.end(); x != end; ++x)
-                          {
-                              const auto orig_id = remaining_nodes[x].id;
-                              is_core_node[orig_node_id_from_new_node_id_map[orig_id]] = true;
-                          }
-                      });
-              }
-              else
-              {
-                  tbb::parallel_for(
-                      tbb::blocked_range<int>(0, remaining_nodes.size(), InitGrainSize),
-                      [this, &remaining_nodes](const tbb::blocked_range<int> &range)
-                      {
-                          for (int x = range.begin(), end = range.end(); x != end; ++x)
-                          {
-                              const auto orig_id = remaining_nodes[x].id;
-                              is_core_node[orig_id] = true;
-                          }
-                      });
-              }
+            if (orig_node_id_from_new_node_id_map.size() > 0)
+            {
+                tbb::parallel_for(tbb::blocked_range<int>(0, remaining_nodes.size(), InitGrainSize),
+                                  [this, &remaining_nodes](const tbb::blocked_range<int> &range)
+                                  {
+                                      for (int x = range.begin(), end = range.end(); x != end; ++x)
+                                      {
+                                          const auto orig_id = remaining_nodes[x].id;
+                                          is_core_node[orig_node_id_from_new_node_id_map[orig_id]] =
+                                              true;
+                                      }
+                                  });
+            }
+            else
+            {
+                tbb::parallel_for(tbb::blocked_range<int>(0, remaining_nodes.size(), InitGrainSize),
+                                  [this, &remaining_nodes](const tbb::blocked_range<int> &range)
+                                  {
+                                      for (int x = range.begin(), end = range.end(); x != end; ++x)
+                                      {
+                                          const auto orig_id = remaining_nodes[x].id;
+                                          is_core_node[orig_id] = true;
+                                      }
+                                  });
+            }
         }
         else
         {
@@ -650,8 +600,9 @@ class Contractor
             is_core_node.clear();
         }
 
-        SimpleLogger().Write() << "[core] " << remaining_nodes.size() << " nodes "
-                               << contractor_graph->GetNumberOfEdges() << " edges." << std::endl;
+        util::SimpleLogger().Write() << "[core] " << remaining_nodes.size() << " nodes "
+                                     << contractor_graph->GetNumberOfEdges() << " edges."
+                                     << std::endl;
 
         thread_data_list.data.clear();
     }
@@ -666,15 +617,15 @@ class Contractor
         out_node_levels.swap(node_levels);
     }
 
-    template <class Edge> inline void GetEdges(DeallocatingVector<Edge> &edges)
+    template <class Edge> inline void GetEdges(util::DeallocatingVector<Edge> &edges)
     {
-        Percent p(contractor_graph->GetNumberOfNodes());
-        SimpleLogger().Write() << "Getting edges of minimized graph";
+        util::Percent p(contractor_graph->GetNumberOfNodes());
+        util::SimpleLogger().Write() << "Getting edges of minimized graph";
         const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
         if (contractor_graph->GetNumberOfNodes())
         {
             Edge new_edge;
-            for (const auto node : osrm::irange(0u, number_of_nodes))
+            for (const auto node : util::irange(0u, number_of_nodes))
             {
                 p.printStatus(node);
                 for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
@@ -691,8 +642,8 @@ class Contractor
                         new_edge.source = node;
                         new_edge.target = target;
                     }
-                    BOOST_ASSERT_MSG(UINT_MAX != new_edge.source, "Source id invalid");
-                    BOOST_ASSERT_MSG(UINT_MAX != new_edge.target, "Target id invalid");
+                    BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.source, "Source id invalid");
+                    BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.target, "Target id invalid");
                     new_edge.data.distance = data.distance;
                     new_edge.data.shortcut = data.shortcut;
                     if (!data.is_original_via_node_ID && !orig_node_id_from_new_node_id_map.empty())
@@ -723,23 +674,55 @@ class Contractor
     }
 
   private:
+    inline void RelaxNode(const NodeID node,
+                          const NodeID forbidden_node,
+                          const int distance,
+                          ContractorHeap &heap)
+    {
+        const short current_hop = heap.GetData(node).hop + 1;
+        for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
+        {
+            const ContractorEdgeData &data = contractor_graph->GetEdgeData(edge);
+            if (!data.forward)
+            {
+                continue;
+            }
+            const NodeID to = contractor_graph->GetTarget(edge);
+            if (forbidden_node == to)
+            {
+                continue;
+            }
+            const int to_distance = distance + data.distance;
+
+            // New Node discovered -> Add to Heap + Node Info Storage
+            if (!heap.WasInserted(to))
+            {
+                heap.Insert(to, to_distance, ContractorHeapData{current_hop, false});
+            }
+            // Found a shorter Path -> Update distance
+            else if (to_distance < heap.GetKey(to))
+            {
+                heap.DecreaseKey(to, to_distance);
+                heap.GetData(to).hop = current_hop;
+            }
+        }
+    }
+
     inline void Dijkstra(const int max_distance,
                          const unsigned number_of_targets,
                          const int maxNodes,
-                         ContractorThreadData *const data,
+                         ContractorThreadData &data,
                          const NodeID middleNode)
     {
 
-        ContractorHeap &heap = data->heap;
+        ContractorHeap &heap = data.heap;
 
         int nodes = 0;
         unsigned number_of_targets_found = 0;
         while (!heap.Empty())
         {
             const NodeID node = heap.DeleteMin();
-            const int distance = heap.GetKey(node);
-            const short current_hop = heap.GetData(node).hop + 1;
-
+            const auto distance = heap.GetKey(node);
             if (++nodes > maxNodes)
             {
                 return;
@@ -759,38 +742,12 @@ class Contractor
                 }
             }
 
-            // iterate over all edges of node
-            for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
-            {
-                const ContractorEdgeData &data = contractor_graph->GetEdgeData(edge);
-                if (!data.forward)
-                {
-                    continue;
-                }
-                const NodeID to = contractor_graph->GetTarget(edge);
-                if (middleNode == to)
-                {
-                    continue;
-                }
-                const int to_distance = distance + data.distance;
-
-                // New Node discovered -> Add to Heap + Node Info Storage
-                if (!heap.WasInserted(to))
-                {
-                    heap.Insert(to, to_distance, ContractorHeapData(current_hop, false));
-                }
-                // Found a shorter Path -> Update distance
-                else if (to_distance < heap.GetKey(to))
-                {
-                    heap.DecreaseKey(to, to_distance);
-                    heap.GetData(to).hop = current_hop;
-                }
-            }
+            RelaxNode(node, middleNode, distance, heap);
         }
     }
 
     inline float EvaluateNodePriority(ContractorThreadData *const data,
-                                      NodePriorityData *const node_data,
+                                      const NodeDepth node_depth,
                                       const NodeID node)
     {
         ContractionStats stats;
@@ -802,14 +759,14 @@ class Contractor
         float result;
         if (0 == (stats.edges_deleted_count * stats.original_edges_deleted_count))
         {
-            result = 1.f * node_data->depth;
+            result = 1.f * node_depth;
         }
         else
         {
             result = 2.f * (((float)stats.edges_added_count) / stats.edges_deleted_count) +
                      4.f * (((float)stats.original_edges_added_count) /
                             stats.original_edges_deleted_count) +
-                     1.f * node_data->depth;
+                     1.f * node_depth;
         }
         BOOST_ASSERT(result >= 0);
         return result;
@@ -820,13 +777,21 @@ class Contractor
     ContractNode(ContractorThreadData *data, const NodeID node, ContractionStats *stats = nullptr)
     {
         ContractorHeap &heap = data->heap;
-        int inserted_edges_size = data->inserted_edges.size();
+        std::size_t inserted_edges_size = data->inserted_edges.size();
         std::vector<ContractorEdge> &inserted_edges = data->inserted_edges;
+        const constexpr bool SHORTCUT_ARC = true;
+        const constexpr bool FORWARD_DIRECTION_ENABLED = true;
+        const constexpr bool FORWARD_DIRECTION_DISABLED = false;
+        const constexpr bool REVERSE_DIRECTION_ENABLED = true;
+        const constexpr bool REVERSE_DIRECTION_DISABLED = false;
 
         for (auto in_edge : contractor_graph->GetAdjacentEdgeRange(node))
         {
             const ContractorEdgeData &in_data = contractor_graph->GetEdgeData(in_edge);
             const NodeID source = contractor_graph->GetTarget(in_edge);
+            if (source == node)
+                continue;
+
             if (RUNSIMULATION)
             {
                 BOOST_ASSERT(stats != nullptr);
@@ -839,7 +804,7 @@ class Contractor
             }
 
             heap.Clear();
-            heap.Insert(source, 0, ContractorHeapData());
+            heap.Insert(source, 0, ContractorHeapData{});
             int max_distance = 0;
             unsigned number_of_targets = 0;
 
@@ -851,22 +816,64 @@ class Contractor
                     continue;
                 }
                 const NodeID target = contractor_graph->GetTarget(out_edge);
-                const int path_distance = in_data.distance + out_data.distance;
+                if (node == target)
+                    continue;
+
+                const EdgeWeight path_distance = in_data.distance + out_data.distance;
+                if (target == source)
+                {
+                    if (path_distance < node_weights[node])
+                    {
+                        if (RUNSIMULATION)
+                        {
+                            // make sure to prune better, but keep inserting this loop if it should
+                            // still be the best
+                            // CAREFUL: This only works due to the independent node-setting. This
+                            // guarantees that source is not connected to another node that is
+                            // contracted
+                            node_weights[source] = path_distance + 1;
+                            BOOST_ASSERT(stats != nullptr);
+                            stats->edges_added_count += 2;
+                            stats->original_edges_added_count +=
+                                2 * (out_data.originalEdges + in_data.originalEdges);
+                        }
+                        else
+                        {
+                            // CAREFUL: This only works due to the independent node-setting. This
+                            // guarantees that source is not connected to another node that is
+                            // contracted
+                            node_weights[source] = path_distance; // make sure to prune better
+                            inserted_edges.emplace_back(
+                                source, target, path_distance,
+                                out_data.originalEdges + in_data.originalEdges, node, SHORTCUT_ARC,
+                                FORWARD_DIRECTION_ENABLED, REVERSE_DIRECTION_DISABLED);
+
+                            inserted_edges.emplace_back(
+                                target, source, path_distance,
+                                out_data.originalEdges + in_data.originalEdges, node, SHORTCUT_ARC,
+                                FORWARD_DIRECTION_DISABLED, REVERSE_DIRECTION_ENABLED);
+                        }
+                    }
+                    continue;
+                }
                 max_distance = std::max(max_distance, path_distance);
                 if (!heap.WasInserted(target))
                 {
-                    heap.Insert(target, INT_MAX, ContractorHeapData(0, true));
+                    heap.Insert(target, INVALID_EDGE_WEIGHT, ContractorHeapData{0, true});
                     ++number_of_targets;
                 }
             }
 
             if (RUNSIMULATION)
             {
-                Dijkstra(max_distance, number_of_targets, 1000, data, node);
+                const int constexpr SIMULATION_SEARCH_SPACE_SIZE = 1000;
+                Dijkstra(max_distance, number_of_targets, SIMULATION_SEARCH_SPACE_SIZE, *data,
+                         node);
             }
             else
             {
-                Dijkstra(max_distance, number_of_targets, 2000, data, node);
+                const int constexpr FULL_SEARCH_SPACE_SIZE = 2000;
+                Dijkstra(max_distance, number_of_targets, FULL_SEARCH_SPACE_SIZE, *data, node);
             }
             for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
             {
@@ -876,6 +883,8 @@ class Contractor
                     continue;
                 }
                 const NodeID target = contractor_graph->GetTarget(out_edge);
+                if (target == node)
+                    continue;
                 const int path_distance = in_data.distance + out_data.distance;
                 const int distance = heap.GetKey(target);
                 if (path_distance < distance)
@@ -891,22 +900,26 @@ class Contractor
                     {
                         inserted_edges.emplace_back(source, target, path_distance,
                                                     out_data.originalEdges + in_data.originalEdges,
-                                                    node, true, true, false);
+                                                    node, SHORTCUT_ARC, FORWARD_DIRECTION_ENABLED,
+                                                    REVERSE_DIRECTION_DISABLED);
 
                         inserted_edges.emplace_back(target, source, path_distance,
                                                     out_data.originalEdges + in_data.originalEdges,
-                                                    node, true, false, true);
+                                                    node, SHORTCUT_ARC, FORWARD_DIRECTION_DISABLED,
+                                                    REVERSE_DIRECTION_ENABLED);
                     }
                 }
             }
         }
+        // Check For One-Way Streets to decide on the creation of self-loops
+
         if (!RUNSIMULATION)
         {
-            int iend = inserted_edges.size();
-            for (int i = inserted_edges_size; i < iend; ++i)
+            std::size_t iend = inserted_edges.size();
+            for (std::size_t i = inserted_edges_size; i < iend; ++i)
             {
                 bool found = false;
-                for (int other = i + 1; other < iend; ++other)
+                for (std::size_t other = i + 1; other < iend; ++other)
                 {
                     if (inserted_edges[other].source != inserted_edges[i].source)
                     {
@@ -957,14 +970,14 @@ class Contractor
         std::sort(neighbours.begin(), neighbours.end());
         neighbours.resize(std::unique(neighbours.begin(), neighbours.end()) - neighbours.begin());
 
-        for (const auto i : osrm::irange<std::size_t>(0, neighbours.size()))
+        for (const auto i : util::irange<std::size_t>(0, neighbours.size()))
         {
             contractor_graph->DeleteEdgesTo(neighbours[i], node);
         }
     }
 
     inline bool UpdateNodeNeighbours(std::vector<float> &priorities,
-                                     std::vector<NodePriorityData> &node_data,
+                                     std::vector<NodeDepth> &node_depth,
                                      ContractorThreadData *const data,
                                      const NodeID node)
     {
@@ -980,7 +993,7 @@ class Contractor
                 continue;
             }
             neighbours.push_back(u);
-            node_data[u].depth = (std::max)(node_data[node].depth + 1, node_data[u].depth);
+            node_depth[u] = std::max(node_depth[node] + 1, node_depth[u]);
         }
         // eliminate duplicate entries ( forward + backward edges )
         std::sort(neighbours.begin(), neighbours.end());
@@ -989,7 +1002,7 @@ class Contractor
         // re-evaluate priorities of neighboring nodes
         for (const NodeID u : neighbours)
         {
-            priorities[u] = EvaluateNodePriority(data, &(node_data)[u], u);
+            priorities[u] = EvaluateNodePriority(data, node_depth[u], u);
         }
         return true;
     }
@@ -1076,8 +1089,17 @@ class Contractor
     stxxl::vector<QueryEdge> external_edge_list;
     std::vector<NodeID> orig_node_id_from_new_node_id_map;
     std::vector<float> node_levels;
+
+    // A list of weights for every node in the graph.
+    // The weight represents the cost for a u-turn on the segment in the base-graph in addition to
+    // its traversal.
+    // During contraction, self-loops are checked against this node weight to ensure that necessary
+    // self-loops are added.
+    std::vector<EdgeWeight> node_weights;
     std::vector<bool> is_core_node;
-    XORFastHash fast_hash;
+    util::XORFastHash<> fast_hash;
 };
+}
+}
 
 #endif // CONTRACTOR_HPP
diff --git a/data_structures/query_edge.hpp b/include/contractor/query_edge.hpp
similarity index 50%
rename from data_structures/query_edge.hpp
rename to include/contractor/query_edge.hpp
index 1c4af03..a3265b8 100644
--- a/data_structures/query_edge.hpp
+++ b/include/contractor/query_edge.hpp
@@ -1,37 +1,15 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 QUERYEDGE_HPP
 #define QUERYEDGE_HPP
 
-#include "../typedefs.h"
+#include "util/typedefs.hpp"
 
 #include <tuple>
 
+namespace osrm
+{
+namespace contractor
+{
+
 struct QueryEdge
 {
     NodeID source;
@@ -75,5 +53,7 @@ struct QueryEdge
                 data.id == right.data.id);
     }
 };
+}
+}
 
 #endif // QUERYEDGE_HPP
diff --git a/include/engine/api/base_api.hpp b/include/engine/api/base_api.hpp
new file mode 100644
index 0000000..8cac72b
--- /dev/null
+++ b/include/engine/api/base_api.hpp
@@ -0,0 +1,64 @@
+#ifndef ENGINE_API_BASE_API_HPP
+#define ENGINE_API_BASE_API_HPP
+
+#include "engine/api/base_parameters.hpp"
+#include "engine/datafacade/datafacade_base.hpp"
+
+#include "engine/api/json_factory.hpp"
+#include "engine/hint.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/range/algorithm/transform.hpp>
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+class BaseAPI
+{
+  public:
+    BaseAPI(const datafacade::BaseDataFacade &facade_, const BaseParameters &parameters_)
+        : facade(facade_), parameters(parameters_)
+    {
+    }
+
+    util::json::Array MakeWaypoints(const std::vector<PhantomNodes> &segment_end_coordinates) const
+    {
+        BOOST_ASSERT(parameters.coordinates.size() > 0);
+        BOOST_ASSERT(parameters.coordinates.size() == segment_end_coordinates.size() + 1);
+
+        util::json::Array waypoints;
+        waypoints.values.resize(parameters.coordinates.size());
+        waypoints.values[0] = MakeWaypoint(segment_end_coordinates.front().source_phantom);
+
+        auto out_iter = std::next(waypoints.values.begin());
+        boost::range::transform(segment_end_coordinates, out_iter,
+                                [this](const PhantomNodes &phantom_pair)
+                                {
+                                    return MakeWaypoint(phantom_pair.target_phantom);
+                                });
+        return waypoints;
+    }
+
+    // FIXME gcc 4.8 doesn't support for lambdas to call protected member functions
+    //  protected:
+    util::json::Object MakeWaypoint(const PhantomNode &phantom) const
+    {
+        return json::makeWaypoint(phantom.location, facade.GetNameForID(phantom.name_id),
+                                  Hint{phantom, facade.GetCheckSum()});
+    }
+
+    const datafacade::BaseDataFacade &facade;
+    const BaseParameters ¶meters;
+};
+
+} // ns api
+} // ns engine
+} // ns osrm
+
+#endif
diff --git a/include/engine/api/base_parameters.hpp b/include/engine/api/base_parameters.hpp
new file mode 100644
index 0000000..63239b7
--- /dev/null
+++ b/include/engine/api/base_parameters.hpp
@@ -0,0 +1,90 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+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 ENGINE_API_BASE_PARAMETERS_HPP
+#define ENGINE_API_BASE_PARAMETERS_HPP
+
+#include "engine/hint.hpp"
+#include "engine/bearing.hpp"
+#include "util/coordinate.hpp"
+
+#include <boost/optional.hpp>
+
+#include <vector>
+#include <algorithm>
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+/**
+ * General parameters for OSRM service queries.
+ *
+ * Holds member attributes:
+ *  - coordinates: for specifying location(s) to services
+ *  - hints: hint for the service to derive the position(s) in the road network more efficiently,
+ *           optional per coordinate
+ *  - radiuses: limits the search for segments in the road network to given radius(es) in meter,
+ *              optional per coordinate
+ *  - bearings: limits the search for segments in the road network to given bearing(s) in degree
+ *              towards true north in clockwise direction, optional per coordinate
+ *
+ * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters,
+ *      NearestParameters, TripParameters, MatchParameters and TileParameters
+ */
+struct BaseParameters
+{
+    std::vector<util::Coordinate> coordinates;
+    std::vector<boost::optional<Hint>> hints;
+    std::vector<boost::optional<double>> radiuses;
+    std::vector<boost::optional<Bearing>> bearings;
+
+    // FIXME add validation for invalid bearing values
+    bool IsValid() const
+    {
+        return (hints.empty() || hints.size() == coordinates.size()) &&
+               (bearings.empty() || bearings.size() == coordinates.size()) &&
+               (radiuses.empty() || radiuses.size() == coordinates.size()) &&
+               std::all_of(bearings.begin(), bearings.end(),
+                           [](const boost::optional<Bearing> bearing_and_range)
+                           {
+                               if (bearing_and_range)
+                               {
+                                   return bearing_and_range->IsValid();
+                               }
+                               return true;
+                           });
+    }
+};
+}
+}
+}
+
+#endif // ROUTE_PARAMETERS_HPP
diff --git a/include/engine/api/json_factory.hpp b/include/engine/api/json_factory.hpp
new file mode 100644
index 0000000..49e81f2
--- /dev/null
+++ b/include/engine/api/json_factory.hpp
@@ -0,0 +1,81 @@
+#ifndef ENGINE_RESPONSE_OBJECTS_HPP_
+#define ENGINE_RESPONSE_OBJECTS_HPP_
+
+#include "extractor/guidance/turn_instruction.hpp"
+#include "extractor/travel_mode.hpp"
+#include "engine/polyline_compressor.hpp"
+#include "engine/guidance/route_step.hpp"
+#include "engine/guidance/step_maneuver.hpp"
+#include "engine/guidance/route_leg.hpp"
+#include "engine/guidance/route.hpp"
+#include "engine/guidance/leg_geometry.hpp"
+#include "util/coordinate.hpp"
+#include "util/json_container.hpp"
+
+#include <boost/optional.hpp>
+
+#include <string>
+#include <algorithm>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+
+struct Hint;
+
+namespace api
+{
+namespace json
+{
+namespace detail
+{
+
+std::string instructionTypeToString(extractor::guidance::TurnType type);
+std::string instructionModifierToString(extractor::guidance::DirectionModifier modifier);
+
+util::json::Array coordinateToLonLat(const util::Coordinate coordinate);
+
+std::string modeToString(const extractor::TravelMode mode);
+
+} // namespace detail
+
+template <typename ForwardIter> util::json::String makePolyline(ForwardIter begin, ForwardIter end)
+{
+    return {encodePolyline(begin, end)};
+}
+
+template <typename ForwardIter>
+util::json::Object makeGeoJSONLineString(ForwardIter begin, ForwardIter end)
+{
+    util::json::Object geojson;
+    geojson.values["type"] = "LineString";
+    util::json::Array coordinates;
+    std::transform(begin, end, std::back_inserter(coordinates.values), &detail::coordinateToLonLat);
+    geojson.values["coordinates"] = std::move(coordinates);
+    return geojson;
+}
+
+util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver);
+
+util::json::Object makeRouteStep(guidance::RouteStep step,
+                                 boost::optional<util::json::Value> geometry);
+
+util::json::Object makeRoute(const guidance::Route &route,
+                             util::json::Array legs,
+                             boost::optional<util::json::Value> geometry);
+
+util::json::Object
+makeWaypoint(const util::Coordinate location, std::string name, const Hint &hint);
+
+util::json::Object makeRouteLeg(guidance::RouteLeg leg, util::json::Array steps);
+
+util::json::Array makeRouteLegs(std::vector<guidance::RouteLeg> legs,
+                                std::vector<util::json::Value> step_geometries);
+}
+}
+} // namespace engine
+} // namespace osrm
+
+#endif // ENGINE_GUIDANCE_API_RESPONSE_GENERATOR_HPP_
diff --git a/include/engine/api/match_api.hpp b/include/engine/api/match_api.hpp
new file mode 100644
index 0000000..7ce4fa2
--- /dev/null
+++ b/include/engine/api/match_api.hpp
@@ -0,0 +1,119 @@
+#ifndef ENGINE_API_MATCH_HPP
+#define ENGINE_API_MATCH_HPP
+
+#include "engine/api/route_api.hpp"
+#include "engine/api/match_parameters.hpp"
+
+#include "engine/datafacade/datafacade_base.hpp"
+
+#include "engine/internal_route_result.hpp"
+#include "engine/map_matching/sub_matching.hpp"
+
+#include "util/integer_range.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+class MatchAPI final : public RouteAPI
+{
+  public:
+    MatchAPI(const datafacade::BaseDataFacade &facade_, const MatchParameters &parameters_)
+        : RouteAPI(facade_, parameters_), parameters(parameters_)
+    {
+    }
+
+    void MakeResponse(const std::vector<map_matching::SubMatching> &sub_matchings,
+                      const std::vector<InternalRouteResult> &sub_routes,
+                      util::json::Object &response) const
+    {
+        auto number_of_routes = sub_matchings.size();
+        util::json::Array routes;
+        routes.values.reserve(number_of_routes);
+        BOOST_ASSERT(sub_matchings.size() == sub_routes.size());
+        for (auto index : util::irange<std::size_t>(0UL, sub_matchings.size()))
+        {
+            auto route = MakeRoute(sub_routes[index].segment_end_coordinates,
+                                   sub_routes[index].unpacked_path_segments,
+                                   sub_routes[index].source_traversed_in_reverse,
+                                   sub_routes[index].target_traversed_in_reverse);
+            route.values["confidence"] = sub_matchings[index].confidence;
+            routes.values.push_back(std::move(route));
+        }
+        response.values["tracepoints"] = MakeTracepoints(sub_matchings);
+        response.values["matchings"] = std::move(routes);
+        response.values["code"] = "ok";
+    }
+
+    // FIXME gcc 4.8 doesn't support for lambdas to call protected member functions
+    //  protected:
+
+    // FIXME this logic is a little backwards. We should change the output format of the
+    // map_matching
+    // routing algorithm to be easier to consume here.
+    util::json::Array
+    MakeTracepoints(const std::vector<map_matching::SubMatching> &sub_matchings) const
+    {
+        util::json::Array waypoints;
+        waypoints.values.reserve(parameters.coordinates.size());
+
+        struct MatchingIndex
+        {
+            MatchingIndex() = default;
+            MatchingIndex(unsigned sub_matching_index_, unsigned point_index_)
+                : sub_matching_index(sub_matching_index_), point_index(point_index_)
+            {
+            }
+
+            unsigned sub_matching_index = std::numeric_limits<unsigned>::max();
+            unsigned point_index = std::numeric_limits<unsigned>::max();
+
+            bool NotMatched()
+            {
+                return sub_matching_index == std::numeric_limits<unsigned>::max() &&
+                       point_index == std::numeric_limits<unsigned>::max();
+            }
+        };
+
+        std::vector<MatchingIndex> trace_idx_to_matching_idx(parameters.coordinates.size());
+        for (auto sub_matching_index :
+             util::irange(0u, static_cast<unsigned>(sub_matchings.size())))
+        {
+            for (auto point_index : util::irange(
+                     0u, static_cast<unsigned>(sub_matchings[sub_matching_index].indices.size())))
+            {
+                trace_idx_to_matching_idx[sub_matchings[sub_matching_index].indices[point_index]] =
+                    MatchingIndex{sub_matching_index, point_index};
+            }
+        }
+
+        for (auto trace_index : util::irange(0UL, parameters.coordinates.size()))
+        {
+            auto matching_index = trace_idx_to_matching_idx[trace_index];
+            if (matching_index.NotMatched())
+            {
+                waypoints.values.push_back(util::json::Null());
+                continue;
+            }
+            const auto &phantom =
+                sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index];
+            auto waypoint = BaseAPI::MakeWaypoint(phantom);
+            waypoint.values["matchings_index"] = matching_index.sub_matching_index;
+            waypoint.values["waypoint_index"] = matching_index.point_index;
+            waypoints.values.push_back(std::move(waypoint));
+        }
+
+        return waypoints;
+    }
+
+    const MatchParameters ¶meters;
+};
+
+} // ns api
+} // ns engine
+} // ns osrm
+
+#endif
diff --git a/util/json_logger.hpp b/include/engine/api/match_parameters.hpp
similarity index 51%
rename from util/json_logger.hpp
rename to include/engine/api/match_parameters.hpp
index 8726f78..0cb4741 100644
--- a/util/json_logger.hpp
+++ b/include/engine/api/match_parameters.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,67 +25,55 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef JSON_LOGGER_HPP
-#define JSON_LOGGER_HPP
+#ifndef ENGINE_API_MATCH_PARAMETERS_HPP
+#define ENGINE_API_MATCH_PARAMETERS_HPP
 
-#include <osrm/json_container.hpp>
+#include "engine/api/route_parameters.hpp"
 
-#include <boost/thread/tss.hpp>
-
-#include <string>
-#include <unordered_map>
+#include <vector>
 
 namespace osrm
 {
-namespace json
+namespace engine
 {
-
-// Used to append additional debugging information to the JSON response in a
-// thread safe manner.
-class Logger
+namespace api
 {
-    using MapT = std::unordered_map<std::string, osrm::json::Value>;
 
-  public:
-    static Logger* get()
+/**
+ * Parameters specific to the OSRM Match service.
+ *
+ * Holds member attributes:
+ *  - timestamps: timestamp(s) for the corresponding input coordinate(s)
+ *
+ * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters,
+ *      NearestParameters, TripParameters, MatchParameters and TileParameters
+ */
+struct MatchParameters : public RouteParameters
+{
+    MatchParameters()
+        : RouteParameters(false,
+                          false,
+                          RouteParameters::GeometriesType::Polyline,
+                          RouteParameters::OverviewType::Simplified,
+                          {})
     {
-        static Logger logger;
-
-        bool return_logger = true;
-#ifdef NDEBUG
-        return_logger = false;
-#endif
-#ifdef ENABLE_JSON_LOGGING
-        return_logger = true;
-#endif
-
-        if (return_logger)
-        {
-            return &logger;
-        }
-
-        return nullptr;
     }
 
-    void initialize(const std::string& name)
+    template <typename... Args>
+    MatchParameters(std::vector<unsigned> timestamps_, Args... args_)
+        : RouteParameters{std::forward<Args>(args_)...}, timestamps{std::move(timestamps_)}
     {
-        if (!map.get())
-        {
-            map.reset(new MapT());
-        }
-        (*map)[name] = Object();
     }
 
-    void render(const std::string& name, Object& obj) const
+    std::vector<unsigned> timestamps;
+    bool IsValid() const
     {
-        obj.values["debug"] = map->at(name);
+        return RouteParameters::IsValid() &&
+               (timestamps.empty() || timestamps.size() == coordinates.size());
     }
-
-    boost::thread_specific_ptr<MapT> map;
 };
-
-
+}
 }
 }
 
-#endif /* JSON_LOGGER_HPP */
+#endif
diff --git a/include/engine/api/nearest_api.hpp b/include/engine/api/nearest_api.hpp
new file mode 100644
index 0000000..ab3747e
--- /dev/null
+++ b/include/engine/api/nearest_api.hpp
@@ -0,0 +1,57 @@
+#ifndef ENGINE_API_NEAREST_API_HPP
+#define ENGINE_API_NEAREST_API_HPP
+
+#include "engine/api/base_api.hpp"
+#include "engine/api/nearest_parameters.hpp"
+
+#include "engine/api/json_factory.hpp"
+#include "engine/phantom_node.hpp"
+
+#include <boost/assert.hpp>
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+class NearestAPI final : public BaseAPI
+{
+  public:
+    NearestAPI(const datafacade::BaseDataFacade &facade_, const NearestParameters &parameters_)
+        : BaseAPI(facade_, parameters_), parameters(parameters_)
+    {
+    }
+
+    void MakeResponse(const std::vector<std::vector<PhantomNodeWithDistance>> &phantom_nodes,
+                      util::json::Object &response) const
+    {
+        BOOST_ASSERT(phantom_nodes.size() == 1);
+        BOOST_ASSERT(parameters.coordinates.size() == 1);
+
+        util::json::Array waypoints;
+        waypoints.values.resize(phantom_nodes.front().size());
+        std::transform(phantom_nodes.front().begin(), phantom_nodes.front().end(),
+                       waypoints.values.begin(),
+                       [this](const PhantomNodeWithDistance &phantom_with_distance)
+                       {
+                           auto waypoint = MakeWaypoint(phantom_with_distance.phantom_node);
+                           waypoint.values["distance"] = phantom_with_distance.distance;
+                           return waypoint;
+                       });
+
+        response.values["code"] = "ok";
+        response.values["waypoints"] = std::move(waypoints);
+    }
+
+    const NearestParameters ¶meters;
+};
+
+} // ns api
+} // ns engine
+} // ns osrm
+
+#endif
diff --git a/util/osrm_exception.hpp b/include/engine/api/nearest_parameters.hpp
similarity index 62%
rename from util/osrm_exception.hpp
rename to include/engine/api/nearest_parameters.hpp
index 369433f..6a6dad7 100644
--- a/util/osrm_exception.hpp
+++ b/include/engine/api/nearest_parameters.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,28 +25,35 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef OSRM_EXCEPTION_HPP
-#define OSRM_EXCEPTION_HPP
+#ifndef ENGINE_API_NEAREST_PARAMETERS_HPP
+#define ENGINE_API_NEAREST_PARAMETERS_HPP
 
-#include <exception>
-#include <string>
-#include <utility>
+#include "engine/api/base_parameters.hpp"
 
 namespace osrm
 {
-class exception final : public std::exception
+namespace engine
 {
-  public:
-    explicit exception(const char *message) : message(message) {}
-    explicit exception(std::string message) : message(std::move(message)) {}
-
-  private:
-    // 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 override { return message.c_str(); }
-    const std::string message;
+namespace api
+{
+
+/**
+ * Parameters specific to the OSRM Nearest service.
+ *
+ * Holds member attributes:
+ *  - number of results: number of nearest segments that should be returned
+ *
+ * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters,
+ *      NearestParameters, TripParameters, MatchParameters and TileParameters
+ */
+struct NearestParameters : public BaseParameters
+{
+    unsigned number_of_results = 1;
+
+    bool IsValid() const { return BaseParameters::IsValid() && number_of_results >= 1; }
 };
 }
-#endif /* OSRM_EXCEPTION_HPP */
+}
+}
+
+#endif // ENGINE_API_NEAREST_PARAMETERS_HPP
diff --git a/include/engine/api/route_api.hpp b/include/engine/api/route_api.hpp
new file mode 100644
index 0000000..e3b9ff8
--- /dev/null
+++ b/include/engine/api/route_api.hpp
@@ -0,0 +1,190 @@
+#ifndef ENGINE_API_ROUTE_HPP
+#define ENGINE_API_ROUTE_HPP
+
+#include "engine/api/base_api.hpp"
+#include "engine/api/route_parameters.hpp"
+#include "engine/api/json_factory.hpp"
+
+#include "engine/datafacade/datafacade_base.hpp"
+
+#include "engine/guidance/assemble_leg.hpp"
+#include "engine/guidance/assemble_route.hpp"
+#include "engine/guidance/assemble_geometry.hpp"
+#include "engine/guidance/assemble_overview.hpp"
+#include "engine/guidance/assemble_steps.hpp"
+#include "engine/guidance/post_processing.hpp"
+
+#include "engine/internal_route_result.hpp"
+
+#include "util/coordinate.hpp"
+#include "util/integer_range.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+class RouteAPI : public BaseAPI
+{
+  public:
+    RouteAPI(const datafacade::BaseDataFacade &facade_, const RouteParameters &parameters_)
+        : BaseAPI(facade_, parameters_), parameters(parameters_)
+    {
+    }
+
+    void MakeResponse(const InternalRouteResult &raw_route, util::json::Object &response) const
+    {
+        auto number_of_routes = raw_route.has_alternative() ? 2UL : 1UL;
+        util::json::Array routes;
+        routes.values.resize(number_of_routes);
+        routes.values[0] =
+            MakeRoute(raw_route.segment_end_coordinates, raw_route.unpacked_path_segments,
+                      raw_route.source_traversed_in_reverse, raw_route.target_traversed_in_reverse);
+        if (raw_route.has_alternative())
+        {
+            std::vector<std::vector<PathData>> wrapped_leg(1);
+            wrapped_leg.front() = std::move(raw_route.unpacked_alternative);
+            routes.values[1] = MakeRoute(raw_route.segment_end_coordinates, wrapped_leg,
+                                         raw_route.alt_source_traversed_in_reverse,
+                                         raw_route.alt_target_traversed_in_reverse);
+        }
+        response.values["waypoints"] = BaseAPI::MakeWaypoints(raw_route.segment_end_coordinates);
+        response.values["routes"] = std::move(routes);
+        response.values["code"] = "ok";
+    }
+
+    // FIXME gcc 4.8 doesn't support for lambdas to call protected member functions
+    //  protected:
+    template <typename ForwardIter>
+    util::json::Value MakeGeometry(ForwardIter begin, ForwardIter end) const
+    {
+        if (parameters.geometries == RouteParameters::GeometriesType::Polyline)
+        {
+            return json::makePolyline(begin, end);
+        }
+
+        BOOST_ASSERT(parameters.geometries == RouteParameters::GeometriesType::GeoJSON);
+        return json::makeGeoJSONLineString(begin, end);
+    }
+
+    util::json::Object MakeRoute(const std::vector<PhantomNodes> &segment_end_coordinates,
+                                 const std::vector<std::vector<PathData>> &unpacked_path_segments,
+                                 const std::vector<bool> &source_traversed_in_reverse,
+                                 const std::vector<bool> &target_traversed_in_reverse) const
+    {
+        std::vector<guidance::RouteLeg> legs;
+        std::vector<guidance::LegGeometry> leg_geometries;
+        auto number_of_legs = segment_end_coordinates.size();
+        legs.reserve(number_of_legs);
+        leg_geometries.reserve(number_of_legs);
+
+        for (auto idx : util::irange(0UL, number_of_legs))
+        {
+            const auto &phantoms = segment_end_coordinates[idx];
+            const auto &path_data = unpacked_path_segments[idx];
+
+            const bool reversed_source = source_traversed_in_reverse[idx];
+            const bool reversed_target = target_traversed_in_reverse[idx];
+
+            auto leg_geometry = guidance::assembleGeometry(
+                BaseAPI::facade, path_data, phantoms.source_phantom, phantoms.target_phantom);
+            auto leg = guidance::assembleLeg(BaseAPI::facade, path_data, leg_geometry,
+                                             phantoms.source_phantom, phantoms.target_phantom, reversed_target);
+
+            if (parameters.steps)
+            {
+                auto steps = guidance::assembleSteps(
+                    BaseAPI::facade, path_data, leg_geometry, phantoms.source_phantom,
+                    phantoms.target_phantom, reversed_source, reversed_target);
+
+                /* Perform step-based post-processing.
+                 *
+                 * Using post-processing on basis of route-steps for a single leg at a time
+                 * comes at the cost that we cannot count the correct exit for roundabouts.
+                 * We can only emit the exit nr/intersections up to/starting at a part of the leg.
+                 * If a roundabout is not terminated in a leg, we will end up with a
+                 *enter-roundabout
+                 * and exit-roundabout-nr where the exit nr is out of sync with the previous enter.
+                 *
+                 *         | S |
+                 *         *   *
+                 *  ----*        * ----
+                 *                  T
+                 *  ----*        * ----
+                 *       V *   *
+                 *         |   |
+                 *         |   |
+                 *
+                 * Coming from S via V to T, we end up with the legs S->V and V->T. V-T will say to
+                 *take
+                 * the second exit, even though counting from S it would be the third.
+                 * For S, we only emit `roundabout` without an exit number, showing that we enter a
+                 *roundabout
+                 * to find a via point.
+                 * The same exit will be emitted, though, if we should start routing at S, making
+                 * the overall response consistent.
+                 */
+
+                guidance::trimShortSegments(steps, leg_geometry);
+                leg.steps = guidance::postProcess(std::move(steps));
+                leg.steps = guidance::assignRelativeLocations(std::move(leg.steps), leg_geometry,
+                                                              phantoms.source_phantom,
+                                                              phantoms.target_phantom);
+                leg_geometry = guidance::resyncGeometry(std::move(leg_geometry), leg.steps);
+            }
+
+            leg_geometries.push_back(std::move(leg_geometry));
+            legs.push_back(std::move(leg));
+        }
+
+        auto route = guidance::assembleRoute(legs);
+        boost::optional<util::json::Value> json_overview;
+        if (parameters.overview != RouteParameters::OverviewType::False)
+        {
+            const auto use_simplification =
+                parameters.overview == RouteParameters::OverviewType::Simplified;
+            BOOST_ASSERT(use_simplification ||
+                         parameters.overview == RouteParameters::OverviewType::Full);
+
+            auto overview = guidance::assembleOverview(leg_geometries, use_simplification);
+            json_overview = MakeGeometry(overview.begin(), overview.end());
+        }
+
+        std::vector<util::json::Value> step_geometries;
+        for (const auto idx : util::irange(0UL, legs.size()))
+        {
+            auto &leg_geometry = leg_geometries[idx];
+            std::transform(
+                legs[idx].steps.begin(), legs[idx].steps.end(), std::back_inserter(step_geometries),
+                [this, &leg_geometry](const guidance::RouteStep &step)
+                {
+                    if (parameters.geometries == RouteParameters::GeometriesType::Polyline)
+                    {
+                        return static_cast<util::json::Value>(
+                            json::makePolyline(leg_geometry.locations.begin() + step.geometry_begin,
+                                               leg_geometry.locations.begin() + step.geometry_end));
+                    }
+                    BOOST_ASSERT(parameters.geometries == RouteParameters::GeometriesType::GeoJSON);
+                    return static_cast<util::json::Value>(json::makeGeoJSONLineString(
+                        leg_geometry.locations.begin() + step.geometry_begin,
+                        leg_geometry.locations.begin() + step.geometry_end));
+                });
+        }
+
+        return json::makeRoute(route,
+                               json::makeRouteLegs(std::move(legs), std::move(step_geometries)),
+                               std::move(json_overview));
+    }
+
+    const RouteParameters ¶meters;
+};
+
+} // ns api
+} // ns engine
+} // ns osrm
+
+#endif
diff --git a/include/engine/api/route_parameters.hpp b/include/engine/api/route_parameters.hpp
new file mode 100644
index 0000000..b8704fc
--- /dev/null
+++ b/include/engine/api/route_parameters.hpp
@@ -0,0 +1,96 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+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 ENGINE_API_ROUTE_PARAMETERS_HPP
+#define ENGINE_API_ROUTE_PARAMETERS_HPP
+
+#include "engine/api/base_parameters.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+/**
+ * Parameters specific to the OSRM Route service.
+ *
+ * Holds member attributes:
+ *  - steps: return route step for each route leg
+ *  - alternatives: tries to find alternative routes
+ *  - geometries: route geometry encoded in Polyline or GeoJSON
+ *  - overview: adds overview geometry either Full, Simplified (according to highest zoom level) or
+ *              False (not at all)
+ *  - uturns: enable or disable uturns (disabled by default)
+ *
+ * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters,
+ *      NearestParameters, TripParameters, MatchParameters and TileParameters
+ */
+struct RouteParameters : public BaseParameters
+{
+    enum class GeometriesType
+    {
+        Polyline,
+        GeoJSON
+    };
+    enum class OverviewType
+    {
+        Simplified,
+        Full,
+        False
+    };
+
+    RouteParameters() = default;
+
+    template <typename... Args>
+    RouteParameters(const bool steps_,
+                    const bool alternatives_,
+                    const GeometriesType geometries_,
+                    const OverviewType overview_,
+                    const boost::optional<bool> uturns_,
+                    Args... args_)
+        : BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternatives{alternatives_},
+          geometries{geometries_}, overview{overview_}, uturns{uturns_}
+    {
+    }
+
+    bool steps = true;
+    bool alternatives = true;
+    GeometriesType geometries = GeometriesType::Polyline;
+    OverviewType overview = OverviewType::Simplified;
+    boost::optional<bool> uturns;
+
+    bool IsValid() const { return coordinates.size() >= 2 && BaseParameters::IsValid(); }
+};
+}
+}
+}
+
+#endif
diff --git a/include/engine/api/table_api.hpp b/include/engine/api/table_api.hpp
new file mode 100644
index 0000000..ac683c9
--- /dev/null
+++ b/include/engine/api/table_api.hpp
@@ -0,0 +1,133 @@
+#ifndef ENGINE_API_TABLE_HPP
+#define ENGINE_API_TABLE_HPP
+
+#include "engine/api/base_api.hpp"
+#include "engine/api/table_parameters.hpp"
+#include "engine/api/json_factory.hpp"
+
+#include "engine/datafacade/datafacade_base.hpp"
+
+#include "engine/guidance/assemble_leg.hpp"
+#include "engine/guidance/assemble_route.hpp"
+#include "engine/guidance/assemble_geometry.hpp"
+#include "engine/guidance/assemble_overview.hpp"
+#include "engine/guidance/assemble_steps.hpp"
+
+#include "engine/internal_route_result.hpp"
+
+#include "util/integer_range.hpp"
+
+#include <boost/range/algorithm/transform.hpp>
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+class TableAPI final : public BaseAPI
+{
+  public:
+    TableAPI(const datafacade::BaseDataFacade &facade_, const TableParameters &parameters_)
+        : BaseAPI(facade_, parameters_), parameters(parameters_)
+    {
+    }
+
+    virtual void MakeResponse(const std::vector<EdgeWeight> &durations,
+                              const std::vector<PhantomNode> &phantoms,
+                              util::json::Object &response) const
+    {
+        auto number_of_sources = parameters.sources.size();
+        auto number_of_destinations = parameters.destinations.size();
+        ;
+
+        // symmetric case
+        if (parameters.sources.empty())
+        {
+            response.values["sources"] = MakeWaypoints(phantoms);
+            number_of_sources = phantoms.size();
+        }
+        else
+        {
+            response.values["sources"] = MakeWaypoints(phantoms, parameters.sources);
+        }
+
+        if (parameters.destinations.empty())
+        {
+            response.values["destinations"] = MakeWaypoints(phantoms);
+            number_of_destinations = phantoms.size();
+        }
+        else
+        {
+            response.values["destinations"] = MakeWaypoints(phantoms, parameters.destinations);
+        }
+
+        response.values["durations"] =
+            MakeTable(durations, number_of_sources, number_of_destinations);
+        response.values["code"] = "ok";
+    }
+
+    // FIXME gcc 4.8 doesn't support for lambdas to call protected member functions
+    //  protected:
+    virtual util::json::Array MakeWaypoints(const std::vector<PhantomNode> &phantoms) const
+    {
+        util::json::Array json_waypoints;
+        json_waypoints.values.reserve(phantoms.size());
+        BOOST_ASSERT(phantoms.size() == parameters.coordinates.size());
+
+        boost::range::transform(phantoms, std::back_inserter(json_waypoints.values),
+                                [this](const PhantomNode &phantom)
+                                {
+                                    return BaseAPI::MakeWaypoint(phantom);
+                                });
+        return json_waypoints;
+    }
+
+    virtual util::json::Array MakeWaypoints(const std::vector<PhantomNode> &phantoms,
+                                            const std::vector<std::size_t> &indices) const
+    {
+        util::json::Array json_waypoints;
+        json_waypoints.values.reserve(indices.size());
+        boost::range::transform(indices, std::back_inserter(json_waypoints.values),
+                                [this, phantoms](const std::size_t idx)
+                                {
+                                    BOOST_ASSERT(idx < phantoms.size());
+                                    return BaseAPI::MakeWaypoint(phantoms[idx]);
+                                });
+        return json_waypoints;
+    }
+
+    virtual util::json::Array MakeTable(const std::vector<EdgeWeight> &values,
+                                        std::size_t number_of_rows,
+                                        std::size_t number_of_columns) const
+    {
+        util::json::Array json_table;
+        for (const auto row : util::irange<std::size_t>(0, number_of_rows))
+        {
+            util::json::Array json_row;
+            auto row_begin_iterator = values.begin() + (row * number_of_columns);
+            auto row_end_iterator = values.begin() + ((row + 1) * number_of_columns);
+            json_row.values.resize(number_of_columns);
+            std::transform(row_begin_iterator, row_end_iterator, json_row.values.begin(),
+                           [](const EdgeWeight duration)
+                           {
+                               if (duration == INVALID_EDGE_WEIGHT)
+                               {
+                                   return util::json::Value(util::json::Null());
+                               }
+                               return util::json::Value(util::json::Number(duration / 10.));
+                           });
+            json_table.values.push_back(std::move(json_row));
+        }
+        return json_table;
+    }
+
+    const TableParameters ¶meters;
+};
+
+} // ns api
+} // ns engine
+} // ns osrm
+
+#endif
diff --git a/include/engine/api/table_parameters.hpp b/include/engine/api/table_parameters.hpp
new file mode 100644
index 0000000..d4d3fd3
--- /dev/null
+++ b/include/engine/api/table_parameters.hpp
@@ -0,0 +1,110 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+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 ENGINE_API_TABLE_PARAMETERS_HPP
+#define ENGINE_API_TABLE_PARAMETERS_HPP
+
+#include "engine/api/base_parameters.hpp"
+
+#include <cstddef>
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+/**
+ * Parameters specific to the OSRM Table service.
+ *
+ * Holds member attributes:
+ *  - sources: indices into coordinates indicating sources for the Table service, no sources means
+ *             use all coordinates as sources
+ *  - destinations: indices into coordinates indicating destinations for the Table service, no
+ *                  destinations means use all coordinates as destinations
+ *
+ * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters,
+ *      NearestParameters, TripParameters, MatchParameters and TileParameters
+ */
+struct TableParameters : public BaseParameters
+{
+    std::vector<std::size_t> sources;
+    std::vector<std::size_t> destinations;
+
+    TableParameters() = default;
+    template <typename... Args>
+    TableParameters(std::vector<std::size_t> sources_,
+                    std::vector<std::size_t> destinations_,
+                    Args... args_)
+        : BaseParameters{std::forward<Args>(args_)...}, sources{std::move(sources_)},
+          destinations{std::move(destinations_)}
+    {
+    }
+
+    bool IsValid() const
+    {
+        if (!BaseParameters::IsValid())
+            return false;
+
+        // Distance Table makes only sense with 2+ coodinates
+        if (coordinates.size() < 2)
+            return false;
+
+        // 1/ The user is able to specify duplicates in srcs and dsts, in that case it's her fault
+
+        // 2/ len(srcs) and len(dsts) smaller or equal to len(locations)
+        if (sources.size() > coordinates.size())
+            return false;
+
+        if (destinations.size() > coordinates.size())
+            return false;
+
+        // 3/ 0 <= index < len(locations)
+        const auto not_in_range = [this](const std::size_t x)
+        {
+            return x >= coordinates.size();
+        };
+
+        if (std::any_of(begin(sources), end(sources), not_in_range))
+            return false;
+
+        if (std::any_of(begin(destinations), end(destinations), not_in_range))
+            return false;
+
+        return true;
+    }
+};
+}
+}
+}
+
+#endif // ENGINE_API_TABLE_PARAMETERS_HPP
diff --git a/algorithms/trip_tabu_search.hpp b/include/engine/api/tile_parameters.hpp
similarity index 50%
rename from algorithms/trip_tabu_search.hpp
rename to include/engine/api/tile_parameters.hpp
index 32f50fc..34c949a 100644
--- a/algorithms/trip_tabu_search.hpp
+++ b/include/engine/api/tile_parameters.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,40 +25,52 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef TRIP_BRUTE_FORCE_HPP
-#define TRIP_BRUTE_FORCE_HPP
+#ifndef ENGINE_API_TILE_PARAMETERS_HPP
+#define ENGINE_API_TILE_PARAMETERS_HPP
 
-#include "../data_structures/search_engine.hpp"
-#include "../util/simple_logger.hpp"
-
-#include <osrm/json_container.hpp>
-
-#include <cstdlib>
-#include <algorithm>
-#include <string>
-#include <vector>
-#include <limits>
+#include <cmath>
 
 namespace osrm
 {
-namespace trip
+namespace engine
 {
-
-// todo: yet to be implemented
-void TabuSearchTrip(std::vector<unsigned> &location,
-                    const PhantomNodeArray &phantom_node_vector,
-                    const std::vector<EdgeWeight> &dist_table,
-                    InternalRouteResult &min_route,
-                    std::vector<int> &min_loc_permutation)
+namespace api
 {
-}
 
-void TabuSearchTrip(const PhantomNodeArray &phantom_node_vector,
-                    const std::vector<EdgeWeight> &dist_table,
-                    InternalRouteResult &min_route,
-                    std::vector<int> &min_loc_permutation)
+/**
+ * Parameters specific to the OSRM Tile service.
+ *
+ * Holds member attributes:
+ *  - x: the x location for the tile
+ *  - y: the y location for the tile
+ *  - z: the zoom level for the tile
+ *
+ * The parameters x,y and z have to conform to the Slippy Map Tilenames specification:
+ *  - https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Zoom_levels
+ *  - https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#X_and_Y
+ *
+ * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters,
+ *      NearestParameters, TripParameters, MatchParameters and TileParameters
+ */
+struct TileParameters final
 {
+    unsigned x;
+    unsigned y;
+    unsigned z;
+
+    bool IsValid() const
+    {
+        // https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Zoom_levels
+        // https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#X_and_Y
+        const auto valid_x = x <= static_cast<unsigned>(std::pow(2., z)) - 1;
+        const auto valid_y = y <= static_cast<unsigned>(std::pow(2., z)) - 1;
+        const auto valid_z = z < 20;
+
+        return valid_x && valid_y && valid_z;
+    };
+};
 }
 }
 }
-#endif // TRIP_BRUTE_FORCE_HPP
\ No newline at end of file
+
+#endif
diff --git a/include/engine/api/trip_api.hpp b/include/engine/api/trip_api.hpp
new file mode 100644
index 0000000..aea7676
--- /dev/null
+++ b/include/engine/api/trip_api.hpp
@@ -0,0 +1,111 @@
+#ifndef ENGINE_API_TRIP_HPP
+#define ENGINE_API_TRIP_HPP
+
+#include "engine/api/route_api.hpp"
+#include "engine/api/trip_parameters.hpp"
+
+#include "engine/datafacade/datafacade_base.hpp"
+
+#include "engine/internal_route_result.hpp"
+
+#include "util/integer_range.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+class TripAPI final : public RouteAPI
+{
+  public:
+    TripAPI(const datafacade::BaseDataFacade &facade_, const TripParameters &parameters_)
+        : RouteAPI(facade_, parameters_), parameters(parameters_)
+    {
+    }
+
+    void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
+                      const std::vector<InternalRouteResult> &sub_routes,
+                      const std::vector<PhantomNode> &phantoms,
+                      util::json::Object &response) const
+    {
+        auto number_of_routes = sub_trips.size();
+        util::json::Array routes;
+        routes.values.reserve(number_of_routes);
+        BOOST_ASSERT(sub_trips.size() == sub_routes.size());
+        for (auto index : util::irange<std::size_t>(0UL, sub_trips.size()))
+        {
+            auto route = MakeRoute(sub_routes[index].segment_end_coordinates,
+                                   sub_routes[index].unpacked_path_segments,
+                                   sub_routes[index].source_traversed_in_reverse,
+                                   sub_routes[index].target_traversed_in_reverse);
+            routes.values.push_back(std::move(route));
+        }
+        response.values["waypoints"] = MakeWaypoints(sub_trips, phantoms);
+        response.values["trips"] = std::move(routes);
+        response.values["code"] = "ok";
+    }
+
+    // FIXME gcc 4.8 doesn't support for lambdas to call protected member functions
+    //  protected:
+
+    // FIXME this logic is a little backwards. We should change the output format of the
+    // trip plugin routing algorithm to be easier to consume here.
+    util::json::Array MakeWaypoints(const std::vector<std::vector<NodeID>> &sub_trips,
+                                    const std::vector<PhantomNode> &phantoms) const
+    {
+        util::json::Array waypoints;
+        waypoints.values.reserve(parameters.coordinates.size());
+
+        struct TripIndex
+        {
+            TripIndex() = default;
+            TripIndex(unsigned sub_trip_index_, unsigned point_index_)
+                : sub_trip_index(sub_trip_index_), point_index(point_index_)
+            {
+            }
+
+            unsigned sub_trip_index = std::numeric_limits<unsigned>::max();
+            unsigned point_index = std::numeric_limits<unsigned>::max();
+
+            bool NotUsed()
+            {
+                return sub_trip_index == std::numeric_limits<unsigned>::max() &&
+                       point_index == std::numeric_limits<unsigned>::max();
+            }
+        };
+
+        std::vector<TripIndex> input_idx_to_trip_idx(parameters.coordinates.size());
+        for (auto sub_trip_index : util::irange(0u, static_cast<unsigned>(sub_trips.size())))
+        {
+            for (auto point_index :
+                 util::irange(0u, static_cast<unsigned>(sub_trips[sub_trip_index].size())))
+            {
+                input_idx_to_trip_idx[sub_trips[sub_trip_index][point_index]] =
+                    TripIndex{sub_trip_index, point_index};
+            }
+        }
+
+        for (auto input_index : util::irange(0UL, parameters.coordinates.size()))
+        {
+            auto trip_index = input_idx_to_trip_idx[input_index];
+            BOOST_ASSERT(!trip_index.NotUsed());
+
+            auto waypoint = BaseAPI::MakeWaypoint(phantoms[input_index]);
+            waypoint.values["trips_index"] = trip_index.sub_trip_index;
+            waypoint.values["waypoint_index"] = trip_index.point_index;
+            waypoints.values.push_back(std::move(waypoint));
+        }
+
+        return waypoints;
+    }
+
+    const TripParameters ¶meters;
+};
+
+} // ns api
+} // ns engine
+} // ns osrm
+
+#endif
diff --git a/algorithms/polyline_formatter.hpp b/include/engine/api/trip_parameters.hpp
similarity index 69%
rename from algorithms/polyline_formatter.hpp
rename to include/engine/api/trip_parameters.hpp
index 68cc702..53c9f42 100644
--- a/algorithms/polyline_formatter.hpp
+++ b/include/engine/api/trip_parameters.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2014, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,21 +25,32 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef POLYLINE_FORMATTER_HPP
-#define POLYLINE_FORMATTER_HPP
+#ifndef ENGINE_API_TRIP_PARAMETERS_HPP
+#define ENGINE_API_TRIP_PARAMETERS_HPP
 
-struct SegmentInformation;
+#include "engine/api/route_parameters.hpp"
 
-#include <osrm/json_container.hpp>
-
-#include <string>
 #include <vector>
 
-struct PolylineFormatter
+namespace osrm
+{
+namespace engine
+{
+namespace api
 {
-    osrm::json::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
 
-    osrm::json::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
+/**
+ * Parameters specific to the OSRM Trip service.
+ *
+ * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters,
+ *      NearestParameters, TripParameters, MatchParameters and TileParameters
+ */
+struct TripParameters : public RouteParameters
+{
+    // bool IsValid() const; Falls back to base class
 };
+}
+}
+}
 
-#endif /* POLYLINE_FORMATTER_HPP */
+#endif
diff --git a/include/engine/base64.hpp b/include/engine/base64.hpp
new file mode 100644
index 0000000..6482961
--- /dev/null
+++ b/include/engine/base64.hpp
@@ -0,0 +1,141 @@
+#ifndef OSRM_BASE64_HPP
+#define OSRM_BASE64_HPP
+
+#include <string>
+#include <vector>
+#include <iterator>
+#include <type_traits>
+
+#include <cstddef>
+#include <climits>
+
+#include <boost/archive/iterators/binary_from_base64.hpp>
+#include <boost/archive/iterators/base64_from_binary.hpp>
+#include <boost/archive/iterators/transform_width.hpp>
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/range/algorithm/copy.hpp>
+
+// RFC 4648 "The Base16, Base32, and Base64 Data Encodings"
+// See: https://tools.ietf.org/html/rfc4648
+
+namespace detail
+{
+// The C++ standard guarantees none of this by default, but we need it in the following.
+static_assert(CHAR_BIT == 8u, "we assume a byte holds 8 bits");
+static_assert(sizeof(char) == 1u, "we assume a char is one byte large");
+
+using Base64FromBinary = boost::archive::iterators::base64_from_binary<
+    boost::archive::iterators::transform_width<const char *, // sequence of chars
+                                               6,            // get view of 6 bit
+                                               8             // from sequence of 8 bit
+                                               >>;
+
+using BinaryFromBase64 = boost::archive::iterators::transform_width<
+    boost::archive::iterators::binary_from_base64<std::string::const_iterator>,
+    8, // get a view of 8 bit
+    6  // from a sequence of 6 bit
+    >;
+} // ns detail
+
+namespace osrm
+{
+namespace engine
+{
+
+// Encoding Implementation
+
+// Encodes a chunk of memory to Base64.
+inline std::string encodeBase64(const unsigned char *first, std::size_t size)
+{
+    std::vector<unsigned char> bytes{first, first + size};
+    BOOST_ASSERT(!bytes.empty());
+
+    std::size_t bytes_to_pad{0};
+
+    while (bytes.size() % 3 != 0)
+    {
+        bytes_to_pad += 1;
+        bytes.push_back(0);
+    }
+
+    BOOST_ASSERT(bytes_to_pad == 0 || bytes_to_pad == 1 || bytes_to_pad == 2);
+    BOOST_ASSERT_MSG(0 == bytes.size() % 3, "base64 input data size is not a multiple of 3");
+
+    std::string encoded{detail::Base64FromBinary{bytes.data()},
+                        detail::Base64FromBinary{bytes.data() + (bytes.size() - bytes_to_pad)}};
+
+    return encoded.append(bytes_to_pad, '=');
+}
+
+// C++11 standard 3.9.1/1: Plain char, signed char, and unsigned char are three distinct types
+
+// Overload for signed char catches (not only but also) C-string literals.
+inline std::string encodeBase64(const signed char *first, std::size_t size)
+{
+    return encodeBase64(reinterpret_cast<const unsigned char *>(first), size);
+}
+
+// Overload for char catches (not only but also) C-string literals.
+inline std::string encodeBase64(const char *first, std::size_t size)
+{
+    return encodeBase64(reinterpret_cast<const unsigned char *>(first), size);
+}
+
+// Convenience specialization, encoding from string instead of byte-dumping it.
+inline std::string encodeBase64(const std::string &x) { return encodeBase64(x.data(), x.size()); }
+
+// Encode any sufficiently trivial object to Base64.
+template <typename T> std::string encodeBase64Bytewise(const T &x)
+{
+#if not defined __GNUC__ or __GNUC__ > 4
+    static_assert(std::is_trivially_copyable<T>::value, "requires a trivially copyable type");
+#endif
+
+    return encodeBase64(reinterpret_cast<const unsigned char *>(&x), sizeof(T));
+}
+
+// Decoding Implementation
+
+// Decodes into a chunk of memory that is at least as large as the input.
+template <typename OutputIter> void decodeBase64(const std::string &encoded, OutputIter out)
+{
+    auto unpadded = encoded;
+
+    const auto num_padded = std::count(begin(encoded), end(encoded), '=');
+    std::replace(begin(unpadded), end(unpadded), '=', 'A'); // A_64 == \0
+
+    std::string decoded{detail::BinaryFromBase64{begin(unpadded)},
+                        detail::BinaryFromBase64{begin(unpadded) + unpadded.length()}};
+
+    decoded.erase(end(decoded) - num_padded, end(decoded));
+    std::copy(begin(decoded), end(decoded), out);
+}
+
+// Convenience specialization, filling string instead of byte-dumping into it.
+inline std::string decodeBase64(const std::string &encoded)
+{
+    std::string rv;
+
+    decodeBase64(encoded, std::back_inserter(rv));
+
+    return rv;
+}
+
+// Decodes from Base 64 to any sufficiently trivial object.
+template <typename T> T decodeBase64Bytewise(const std::string &encoded)
+{
+#if not defined __GNUC__ or __GNUC__ > 4
+    static_assert(std::is_trivially_copyable<T>::value, "requires a trivially copyable type");
+#endif
+
+    T x;
+
+    decodeBase64(encoded, reinterpret_cast<unsigned char *>(&x));
+
+    return x;
+}
+
+} // ns engine
+} // ns osrm
+
+#endif /* OSRM_BASE64_HPP */
diff --git a/util/range_algorithms.hpp b/include/engine/bearing.hpp
similarity index 72%
rename from util/range_algorithms.hpp
rename to include/engine/bearing.hpp
index 4d01d29..3b99962 100644
--- a/util/range_algorithms.hpp
+++ b/include/engine/bearing.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,25 +25,28 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef RANGE_ALGORITHMS_HPP
-#define RANGE_ALGORITHMS_HPP
-
-#include <algorithm>
+#ifndef OSRM_ENGINE_BEARING_HPP
+#define OSRM_ENGINE_BEARING_HPP
 
 namespace osrm
 {
+namespace engine
+{
 
-template <class Container>
-auto max_element(const Container &c) -> decltype(std::max_element(c.begin(), c.end()))
+struct Bearing
 {
-    return std::max_element(c.begin(), c.end());
-}
+    short bearing;
+    short range;
 
-template <class Container>
-auto max_element(const Container &c) -> decltype(std::max_element(c.cbegin(), c.cend()))
+    bool IsValid() const { return bearing >= 0 && bearing <= 360 && range >= 0 && range <= 180; }
+};
+
+inline bool operator==(const Bearing lhs, const Bearing rhs)
 {
-    return std::max_element(c.cbegin(), c.cend());
+    return lhs.bearing == rhs.bearing && lhs.range == rhs.range;
+}
+inline bool operator!=(const Bearing lhs, const Bearing rhs) { return !(lhs == rhs); }
 }
 }
 
-#endif // RANGE_ALGORITHMS_HPP
+#endif
diff --git a/include/engine/datafacade/datafacade_base.hpp b/include/engine/datafacade/datafacade_base.hpp
new file mode 100644
index 0000000..f4cb0c4
--- /dev/null
+++ b/include/engine/datafacade/datafacade_base.hpp
@@ -0,0 +1,153 @@
+#ifndef DATAFACADE_BASE_HPP
+#define DATAFACADE_BASE_HPP
+
+// Exposes all data access interfaces to the algorithms via base class ptr
+
+#include "extractor/edge_based_node.hpp"
+#include "extractor/external_memory_node.hpp"
+#include "contractor/query_edge.hpp"
+#include "engine/phantom_node.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+#include "util/integer_range.hpp"
+#include "util/exception.hpp"
+#include "util/string_util.hpp"
+#include "util/typedefs.hpp"
+
+#include "osrm/coordinate.hpp"
+
+#include <cstddef>
+
+#include <vector>
+#include <utility>
+#include <string>
+
+namespace osrm
+{
+namespace engine
+{
+namespace datafacade
+{
+
+using EdgeRange = util::range<EdgeID>;
+
+class BaseDataFacade
+{
+  public:
+    using EdgeData = contractor::QueryEdge::EdgeData;
+    using RTreeLeaf = extractor::EdgeBasedNode;
+    BaseDataFacade() {}
+    virtual ~BaseDataFacade() {}
+
+    // search graph access
+    virtual unsigned GetNumberOfNodes() const = 0;
+
+    virtual unsigned GetNumberOfEdges() const = 0;
+
+    virtual unsigned GetOutDegree(const NodeID n) const = 0;
+
+    virtual NodeID GetTarget(const EdgeID e) const = 0;
+
+    virtual const EdgeData &GetEdgeData(const EdgeID e) const = 0;
+
+    virtual EdgeID BeginEdges(const NodeID n) const = 0;
+
+    virtual EdgeID EndEdges(const NodeID n) const = 0;
+
+    virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0;
+
+    // searches for a specific edge
+    virtual EdgeID FindEdge(const NodeID from, const NodeID to) const = 0;
+
+    virtual EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const = 0;
+
+    virtual EdgeID
+    FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const = 0;
+
+    // node and edge information access
+    virtual util::Coordinate GetCoordinateOfNode(const unsigned id) const = 0;
+
+    virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const = 0;
+
+    virtual void GetUncompressedGeometry(const EdgeID id,
+                                         std::vector<NodeID> &result_nodes) const = 0;
+
+    // Gets the weight values for each segment in an uncompressed geometry.
+    // Should always be 1 shorter than GetUncompressedGeometry
+    virtual void GetUncompressedWeights(const EdgeID id,
+                                        std::vector<EdgeWeight> &result_weights) const = 0;
+
+    // Returns the data source ids that were used to supply the edge
+    // weights.  Will return an empty array when only the base profile is used.
+    virtual void GetUncompressedDatasources(const EdgeID id,
+                                            std::vector<uint8_t> &data_sources) const = 0;
+
+    // Gets the name of a datasource
+    virtual std::string GetDatasourceName(const uint8_t datasource_name_id) const = 0;
+
+    virtual extractor::guidance::TurnInstruction
+    GetTurnInstructionForEdgeID(const unsigned id) const = 0;
+
+    virtual extractor::TravelMode GetTravelModeForEdgeID(const unsigned id) const = 0;
+
+    virtual std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate south_west,
+                                                 const util::Coordinate north_east) = 0;
+
+    virtual std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
+                               const float max_distance,
+                               const int bearing,
+                               const int bearing_range) = 0;
+    virtual std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
+                               const float max_distance) = 0;
+
+    virtual std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate input_coordinate,
+                        const unsigned max_results,
+                        const double max_distance,
+                        const int bearing,
+                        const int bearing_range) = 0;
+    virtual std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate input_coordinate,
+                        const unsigned max_results,
+                        const int bearing,
+                        const int bearing_range) = 0;
+    virtual std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate input_coordinate, const unsigned max_results) = 0;
+    virtual std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate input_coordinate,
+                        const unsigned max_results,
+                        const double max_distance) = 0;
+
+    virtual std::pair<PhantomNode, PhantomNode>
+    NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate) = 0;
+    virtual std::pair<PhantomNode, PhantomNode>
+    NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+                                                      const double max_distance) = 0;
+    virtual std::pair<PhantomNode, PhantomNode>
+    NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+                                                      const double max_distance,
+                                                      const int bearing,
+                                                      const int bearing_range) = 0;
+    virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
+        const util::Coordinate input_coordinate, const int bearing, const int bearing_range) = 0;
+
+    virtual unsigned GetCheckSum() const = 0;
+
+    virtual bool IsCoreNode(const NodeID id) const = 0;
+
+    virtual unsigned GetNameIndexFromEdgeID(const unsigned id) const = 0;
+
+    virtual std::string GetNameForID(const unsigned name_id) const = 0;
+
+    virtual std::size_t GetCoreSize() const = 0;
+
+    virtual std::string GetTimestamp() const = 0;
+
+    virtual bool GetUTurnsDefault() const = 0;
+};
+}
+}
+}
+
+#endif // DATAFACADE_BASE_HPP
diff --git a/include/engine/datafacade/internal_datafacade.hpp b/include/engine/datafacade/internal_datafacade.hpp
new file mode 100644
index 0000000..302af30
--- /dev/null
+++ b/include/engine/datafacade/internal_datafacade.hpp
@@ -0,0 +1,658 @@
+#ifndef INTERNAL_DATAFACADE_HPP
+#define INTERNAL_DATAFACADE_HPP
+
+// implements all data storage when shared memory is _NOT_ used
+
+#include "engine/datafacade/datafacade_base.hpp"
+
+#include "extractor/guidance/turn_instruction.hpp"
+
+#include "engine/geospatial_query.hpp"
+#include "extractor/original_edge_data.hpp"
+#include "extractor/profile_properties.hpp"
+#include "extractor/query_node.hpp"
+#include "contractor/query_edge.hpp"
+#include "util/shared_memory_vector_wrapper.hpp"
+#include "util/static_graph.hpp"
+#include "util/static_rtree.hpp"
+#include "util/range_table.hpp"
+#include "util/graph_loader.hpp"
+#include "util/simple_logger.hpp"
+#include "util/rectangle.hpp"
+#include "extractor/compressed_edge_container.hpp"
+
+#include "osrm/coordinate.hpp"
+
+#include <cstddef>
+#include <cstdlib>
+
+#include <algorithm>
+#include <fstream>
+#include <ios>
+#include <limits>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/thread/tss.hpp>
+
+namespace osrm
+{
+namespace engine
+{
+namespace datafacade
+{
+
+class InternalDataFacade final : public BaseDataFacade
+{
+
+  private:
+    using super = BaseDataFacade;
+    using QueryGraph = util::StaticGraph<typename super::EdgeData>;
+    using InputEdge = typename QueryGraph::InputEdge;
+    using RTreeLeaf = typename super::RTreeLeaf;
+    using InternalRTree =
+        util::StaticRTree<RTreeLeaf, util::ShM<util::Coordinate, false>::vector, false>;
+    using InternalGeospatialQuery = GeospatialQuery<InternalRTree, BaseDataFacade>;
+
+    InternalDataFacade() {}
+
+    unsigned m_check_sum;
+    unsigned m_number_of_nodes;
+    std::unique_ptr<QueryGraph> m_query_graph;
+    std::string m_timestamp;
+
+    std::shared_ptr<util::ShM<util::Coordinate, false>::vector> m_coordinate_list;
+    util::ShM<NodeID, false>::vector m_via_node_list;
+    util::ShM<unsigned, false>::vector m_name_ID_list;
+    util::ShM<extractor::guidance::TurnInstruction, false>::vector m_turn_instruction_list;
+    util::ShM<extractor::TravelMode, false>::vector m_travel_mode_list;
+    util::ShM<char, false>::vector m_names_char_list;
+    util::ShM<unsigned, false>::vector m_geometry_indices;
+    util::ShM<extractor::CompressedEdgeContainer::CompressedEdge, false>::vector m_geometry_list;
+    util::ShM<bool, false>::vector m_is_core_node;
+    util::ShM<unsigned, false>::vector m_segment_weights;
+    util::ShM<uint8_t, false>::vector m_datasource_list;
+    util::ShM<std::string, false>::vector m_datasource_names;
+    extractor::ProfileProperties m_profile_properties;
+
+    boost::thread_specific_ptr<InternalRTree> m_static_rtree;
+    boost::thread_specific_ptr<InternalGeospatialQuery> m_geospatial_query;
+    boost::filesystem::path ram_index_path;
+    boost::filesystem::path file_index_path;
+    util::RangeTable<16, false> m_name_table;
+
+    void LoadProfileProperties(const boost::filesystem::path &properties_path)
+    {
+        boost::filesystem::ifstream in_stream(properties_path);
+        if (!in_stream)
+        {
+            throw util::exception("Could not open " + properties_path.string() + " for reading.");
+        }
+
+        in_stream.read(reinterpret_cast<char*>(&m_profile_properties), sizeof(m_profile_properties));
+    }
+
+    void LoadTimestamp(const boost::filesystem::path &timestamp_path)
+    {
+        util::SimpleLogger().Write() << "Loading Timestamp";
+        boost::filesystem::ifstream timestamp_stream(timestamp_path);
+        if (!timestamp_stream)
+        {
+            throw util::exception("Could not open " + timestamp_path.string() + " for reading.");
+        }
+        getline(timestamp_stream, m_timestamp);
+    }
+
+    void LoadGraph(const boost::filesystem::path &hsgr_path)
+    {
+        typename util::ShM<typename QueryGraph::NodeArrayEntry, false>::vector node_list;
+        typename util::ShM<typename QueryGraph::EdgeArrayEntry, false>::vector edge_list;
+
+        util::SimpleLogger().Write() << "loading graph from " << hsgr_path.string();
+
+        m_number_of_nodes = readHSGRFromStream(hsgr_path, node_list, edge_list, &m_check_sum);
+
+        BOOST_ASSERT_MSG(0 != node_list.size(), "node list empty");
+        // BOOST_ASSERT_MSG(0 != edge_list.size(), "edge list empty");
+        util::SimpleLogger().Write() << "loaded " << node_list.size() << " nodes and "
+                                     << edge_list.size() << " edges";
+        m_query_graph = std::unique_ptr<QueryGraph>(new 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");
+        util::SimpleLogger().Write() << "Data checksum is " << m_check_sum;
+    }
+
+    void LoadNodeAndEdgeInformation(const boost::filesystem::path &nodes_file,
+                                    const boost::filesystem::path &edges_file)
+    {
+        boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
+
+        extractor::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<util::Coordinate>>(number_of_coordinates);
+        for (unsigned i = 0; i < number_of_coordinates; ++i)
+        {
+            nodes_input_stream.read((char *)&current_node, sizeof(extractor::QueryNode));
+            m_coordinate_list->at(i) = util::Coordinate(current_node.lon, current_node.lat);
+            BOOST_ASSERT(m_coordinate_list->at(i).IsValid());
+        }
+
+        boost::filesystem::ifstream edges_input_stream(edges_file, std::ios::binary);
+        unsigned number_of_edges = 0;
+        edges_input_stream.read((char *)&number_of_edges, sizeof(unsigned));
+        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_travel_mode_list.resize(number_of_edges);
+
+        extractor::OriginalEdgeData current_edge_data;
+        for (unsigned i = 0; i < number_of_edges; ++i)
+        {
+            edges_input_stream.read((char *)&(current_edge_data),
+                                    sizeof(extractor::OriginalEdgeData));
+            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_travel_mode_list[i] = current_edge_data.travel_mode;
+        }
+    }
+
+    void LoadCoreInformation(const boost::filesystem::path &core_data_file)
+    {
+        std::ifstream core_stream(core_data_file.string().c_str(), std::ios::binary);
+        unsigned number_of_markers;
+        core_stream.read((char *)&number_of_markers, sizeof(unsigned));
+
+        std::vector<char> unpacked_core_markers(number_of_markers);
+        core_stream.read((char *)unpacked_core_markers.data(), sizeof(char) * number_of_markers);
+
+        // in this case we have nothing to do
+        if (number_of_markers <= 0)
+        {
+            return;
+        }
+
+        m_is_core_node.resize(number_of_markers);
+        for (auto i = 0u; i < number_of_markers; ++i)
+        {
+            BOOST_ASSERT(unpacked_core_markers[i] == 0 || unpacked_core_markers[i] == 1);
+            m_is_core_node[i] = unpacked_core_markers[i] == 1;
+        }
+    }
+
+    void LoadGeometries(const boost::filesystem::path &geometry_file)
+    {
+        std::ifstream geometry_stream(geometry_file.string().c_str(), std::ios::binary);
+        unsigned number_of_indices = 0;
+        unsigned number_of_compressed_geometries = 0;
+
+        geometry_stream.read((char *)&number_of_indices, sizeof(unsigned));
+
+        m_geometry_indices.resize(number_of_indices);
+        if (number_of_indices > 0)
+        {
+            geometry_stream.read((char *)&(m_geometry_indices[0]),
+                                 number_of_indices * sizeof(unsigned));
+        }
+
+        geometry_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
+
+        BOOST_ASSERT(m_geometry_indices.back() == number_of_compressed_geometries);
+        m_geometry_list.resize(number_of_compressed_geometries);
+
+        if (number_of_compressed_geometries > 0)
+        {
+            geometry_stream.read((char *)&(m_geometry_list[0]),
+                                 number_of_compressed_geometries *
+                                     sizeof(extractor::CompressedEdgeContainer::CompressedEdge));
+        }
+    }
+
+    void LoadDatasourceInfo(const boost::filesystem::path &datasource_names_file,
+                            const boost::filesystem::path &datasource_indexes_file)
+    {
+        boost::filesystem::ifstream datasources_stream(datasource_indexes_file, std::ios::binary);
+        if (!datasources_stream)
+        {
+            throw util::exception("Could not open " + datasource_indexes_file.string() + " for reading!");
+        }
+        BOOST_ASSERT(datasources_stream);
+
+        std::size_t number_of_datasources = 0;
+        datasources_stream.read(reinterpret_cast<char *>(&number_of_datasources),
+                                sizeof(std::size_t));
+        if (number_of_datasources > 0)
+        {
+            m_datasource_list.resize(number_of_datasources);
+            datasources_stream.read(reinterpret_cast<char *>(&(m_datasource_list[0])),
+                                    number_of_datasources * sizeof(uint8_t));
+        }
+
+        boost::filesystem::ifstream datasourcenames_stream(datasource_names_file, std::ios::binary);
+        if (!datasourcenames_stream)
+        {
+            throw util::exception("Could not open " + datasource_names_file.string() + " for reading!");
+        }
+        BOOST_ASSERT(datasourcenames_stream);
+        std::string name;
+        while (std::getline(datasourcenames_stream, name))
+        {
+            m_datasource_names.push_back(std::move(name));
+        }
+    }
+
+    void LoadRTree()
+    {
+        BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
+
+        m_static_rtree.reset(new InternalRTree(ram_index_path, file_index_path, m_coordinate_list));
+        m_geospatial_query.reset(
+            new InternalGeospatialQuery(*m_static_rtree, m_coordinate_list, *this));
+    }
+
+    void LoadStreetNames(const boost::filesystem::path &names_file)
+    {
+        boost::filesystem::ifstream name_stream(names_file, std::ios::binary);
+
+        name_stream >> m_name_table;
+
+        unsigned number_of_chars = 0;
+        name_stream.read((char *)&number_of_chars, sizeof(unsigned));
+        BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
+        m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element
+        name_stream.read((char *)&m_names_char_list[0], number_of_chars * sizeof(char));
+        if (0 == m_names_char_list.size())
+        {
+            util::SimpleLogger().Write(logWARNING) << "list of street names is empty";
+        }
+    }
+
+  public:
+    virtual ~InternalDataFacade()
+    {
+        m_static_rtree.reset();
+        m_geospatial_query.reset();
+    }
+
+    explicit InternalDataFacade(const storage::StorageConfig& config)
+    {
+        ram_index_path = config.ram_index_path;
+        file_index_path = config.file_index_path;
+
+        util::SimpleLogger().Write() << "loading graph data";
+        LoadGraph(config.hsgr_data_path);
+
+        util::SimpleLogger().Write() << "loading edge information";
+        LoadNodeAndEdgeInformation(config.nodes_data_path, config.edges_data_path);
+
+        util::SimpleLogger().Write() << "loading core information";
+        LoadCoreInformation(config.core_data_path);
+
+        util::SimpleLogger().Write() << "loading geometries";
+        LoadGeometries(config.geometries_path);
+
+        util::SimpleLogger().Write() << "loading datasource info";
+        LoadDatasourceInfo(config.datasource_names_path,
+                           config.datasource_indexes_path);
+
+        util::SimpleLogger().Write() << "loading timestamp";
+        LoadTimestamp(config.timestamp_path);
+
+        util::SimpleLogger().Write() << "loading profile properties";
+        LoadProfileProperties(config.properties_path);
+
+        util::SimpleLogger().Write() << "loading street names";
+        LoadStreetNames(config.names_data_path);
+    }
+
+    // search graph access
+    unsigned GetNumberOfNodes() const override final { return m_query_graph->GetNumberOfNodes(); }
+
+    unsigned GetNumberOfEdges() const override final { return m_query_graph->GetNumberOfEdges(); }
+
+    unsigned GetOutDegree(const NodeID n) const override final
+    {
+        return m_query_graph->GetOutDegree(n);
+    }
+
+    NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); }
+
+    EdgeData &GetEdgeData(const EdgeID e) const override final
+    {
+        return m_query_graph->GetEdgeData(e);
+    }
+
+    EdgeID BeginEdges(const NodeID n) const override final { return m_query_graph->BeginEdges(n); }
+
+    EdgeID EndEdges(const NodeID n) const override final { return m_query_graph->EndEdges(n); }
+
+    EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
+    {
+        return m_query_graph->GetAdjacentEdgeRange(node);
+    }
+
+    // searches for a specific edge
+    EdgeID FindEdge(const NodeID from, const NodeID to) const override final
+    {
+        return m_query_graph->FindEdge(from, to);
+    }
+
+    EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const override final
+    {
+        return m_query_graph->FindEdgeInEitherDirection(from, to);
+    }
+
+    EdgeID
+    FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const override final
+    {
+        return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
+    }
+
+    // node and edge information access
+    util::Coordinate GetCoordinateOfNode(const unsigned id) const override final
+    {
+        return m_coordinate_list->at(id);
+    }
+
+    extractor::guidance::TurnInstruction
+    GetTurnInstructionForEdgeID(const unsigned id) const override final
+    {
+        return m_turn_instruction_list.at(id);
+    }
+
+    extractor::TravelMode GetTravelModeForEdgeID(const unsigned id) const override final
+    {
+        return m_travel_mode_list.at(id);
+    }
+
+    std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate south_west,
+                                         const util::Coordinate north_east) override final
+    {
+        if (!m_static_rtree.get())
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+        const util::RectangleInt2D bbox{south_west.lon, north_east.lon, south_west.lat,
+                                        north_east.lat};
+        return m_geospatial_query->Search(bbox);
+    }
+
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
+                               const float max_distance) override final
+    {
+        if (!m_static_rtree.get())
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance);
+    }
+
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
+                               const float max_distance,
+                               const int bearing,
+                               const int bearing_range) override final
+    {
+        if (!m_static_rtree.get())
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance,
+                                                              bearing, bearing_range);
+    }
+
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate input_coordinate,
+                        const unsigned max_results) override final
+    {
+        if (!m_static_rtree.get())
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results);
+    }
+
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate input_coordinate,
+                        const unsigned max_results,
+                        const double max_distance) override final
+    {
+        if (!m_static_rtree.get())
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, max_distance);
+    }
+
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate input_coordinate,
+                        const unsigned max_results,
+                        const int bearing,
+                        const int bearing_range) override final
+    {
+        if (!m_static_rtree.get())
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, bearing,
+                                                       bearing_range);
+    }
+
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate input_coordinate,
+                        const unsigned max_results,
+                        const double max_distance,
+                        const int bearing,
+                        const int bearing_range) override final
+    {
+        if (!m_static_rtree.get())
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, max_distance,
+                                                       bearing, bearing_range);
+    }
+
+    std::pair<PhantomNode, PhantomNode>
+    NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+                                                      const double max_distance) override final
+    {
+        if (!m_static_rtree.get())
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
+            input_coordinate, max_distance);
+    }
+
+    std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
+        const util::Coordinate input_coordinate) override final
+    {
+        if (!m_static_rtree.get())
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
+            input_coordinate);
+    }
+
+    std::pair<PhantomNode, PhantomNode>
+    NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+                                                      const double max_distance,
+                                                      const int bearing,
+                                                      const int bearing_range) override final
+    {
+        if (!m_static_rtree.get())
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
+            input_coordinate, max_distance, bearing, bearing_range);
+    }
+
+    std::pair<PhantomNode, PhantomNode>
+    NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+                                                      const int bearing,
+                                                      const int bearing_range) override final
+    {
+        if (!m_static_rtree.get())
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
+            input_coordinate, bearing, bearing_range);
+    }
+
+    unsigned GetCheckSum() const override final { return m_check_sum; }
+
+    unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
+    {
+        return m_name_ID_list.at(id);
+    }
+
+    std::string GetNameForID(const unsigned name_id) const override final
+    {
+        if (std::numeric_limits<unsigned>::max() == name_id)
+        {
+            return "";
+        }
+        auto range = m_name_table.GetRange(name_id);
+
+        std::string result;
+        result.reserve(range.size());
+        if (range.begin() != range.end())
+        {
+            result.resize(range.back() - range.front() + 1);
+            std::copy(m_names_char_list.begin() + range.front(),
+                      m_names_char_list.begin() + range.back() + 1, result.begin());
+        }
+        return result;
+    }
+
+    virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const override final
+    {
+        return m_via_node_list.at(id);
+    }
+
+    virtual std::size_t GetCoreSize() const override final { return m_is_core_node.size(); }
+
+    virtual bool IsCoreNode(const NodeID id) const override final
+    {
+        if (m_is_core_node.size() > 0)
+        {
+            return m_is_core_node[id];
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+    virtual void GetUncompressedGeometry(const EdgeID id,
+                                         std::vector<NodeID> &result_nodes) const override final
+    {
+        const unsigned begin = m_geometry_indices.at(id);
+        const unsigned end = m_geometry_indices.at(id + 1);
+
+        result_nodes.clear();
+        result_nodes.reserve(end - begin);
+        std::for_each(m_geometry_list.begin() + begin, m_geometry_list.begin() + end,
+                      [&](const osrm::extractor::CompressedEdgeContainer::CompressedEdge &edge)
+                      {
+                          result_nodes.emplace_back(edge.node_id);
+                      });
+    }
+
+    virtual void
+    GetUncompressedWeights(const EdgeID id,
+                           std::vector<EdgeWeight> &result_weights) const override final
+    {
+        const unsigned begin = m_geometry_indices.at(id);
+        const unsigned end = m_geometry_indices.at(id + 1);
+
+        result_weights.clear();
+        result_weights.reserve(end - begin);
+        std::for_each(m_geometry_list.begin() + begin, m_geometry_list.begin() + end,
+                      [&](const osrm::extractor::CompressedEdgeContainer::CompressedEdge &edge)
+                      {
+                          result_weights.emplace_back(edge.weight);
+                      });
+    }
+
+    // Returns the data source ids that were used to supply the edge
+    // weights.
+    virtual void
+    GetUncompressedDatasources(const EdgeID id,
+                               std::vector<uint8_t> &result_datasources) const override final
+    {
+        const unsigned begin = m_geometry_indices.at(id);
+        const unsigned end = m_geometry_indices.at(id + 1);
+
+        result_datasources.clear();
+        result_datasources.reserve(end - begin);
+
+        // If there was no datasource info, return an array of 0's.
+        if (m_datasource_list.empty())
+        {
+            for (unsigned i = 0; i < end - begin; ++i)
+            {
+                result_datasources.push_back(0);
+            }
+        }
+        else
+        {
+            std::for_each(m_datasource_list.begin() + begin, m_datasource_list.begin() + end,
+                          [&](const uint8_t &datasource_id)
+                          {
+                              result_datasources.push_back(datasource_id);
+                          });
+        }
+    }
+
+    virtual std::string GetDatasourceName(const uint8_t datasource_name_id) const override final
+    {
+        BOOST_ASSERT(m_datasource_names.size() >= 1);
+        BOOST_ASSERT(m_datasource_names.size() > datasource_name_id);
+        return m_datasource_names[datasource_name_id];
+    }
+
+    std::string GetTimestamp() const override final { return m_timestamp; }
+
+    bool GetUTurnsDefault() const override final { return m_profile_properties.allow_u_turn_at_via; }
+};
+}
+}
+}
+
+#endif // INTERNAL_DATAFACADE_HPP
diff --git a/include/engine/datafacade/shared_datafacade.hpp b/include/engine/datafacade/shared_datafacade.hpp
new file mode 100644
index 0000000..dbb14bb
--- /dev/null
+++ b/include/engine/datafacade/shared_datafacade.hpp
@@ -0,0 +1,717 @@
+#ifndef SHARED_DATAFACADE_HPP
+#define SHARED_DATAFACADE_HPP
+
+// implements all data storage when shared memory _IS_ used
+
+#include "engine/datafacade/datafacade_base.hpp"
+#include "storage/shared_datatype.hpp"
+#include "storage/shared_memory.hpp"
+
+#include "extractor/guidance/turn_instruction.hpp"
+#include "extractor/profile_properties.hpp"
+
+#include "engine/geospatial_query.hpp"
+#include "util/range_table.hpp"
+#include "util/static_graph.hpp"
+#include "util/static_rtree.hpp"
+#include "util/make_unique.hpp"
+#include "util/simple_logger.hpp"
+#include "util/rectangle.hpp"
+
+#include <cstddef>
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/thread/tss.hpp>
+#include <boost/thread/shared_mutex.hpp>
+#include <boost/thread/lock_guard.hpp>
+
+namespace osrm
+{
+namespace engine
+{
+namespace datafacade
+{
+
+class SharedDataFacade final : public BaseDataFacade
+{
+
+  private:
+    using super = BaseDataFacade;
+    using QueryGraph = util::StaticGraph<EdgeData, true>;
+    using GraphNode = typename QueryGraph::NodeArrayEntry;
+    using GraphEdge = typename QueryGraph::EdgeArrayEntry;
+    using NameIndexBlock = typename util::RangeTable<16, true>::BlockT;
+    using InputEdge = typename QueryGraph::InputEdge;
+    using RTreeLeaf = typename super::RTreeLeaf;
+    using SharedRTree =
+        util::StaticRTree<RTreeLeaf, util::ShM<util::Coordinate, true>::vector, true>;
+    using SharedGeospatialQuery = GeospatialQuery<SharedRTree, BaseDataFacade>;
+    using TimeStampedRTreePair = std::pair<unsigned, std::shared_ptr<SharedRTree>>;
+    using RTreeNode = typename SharedRTree::TreeNode;
+
+    storage::SharedDataLayout *data_layout;
+    char *shared_memory;
+    storage::SharedDataTimestamp *data_timestamp_ptr;
+
+    storage::SharedDataType CURRENT_LAYOUT;
+    storage::SharedDataType CURRENT_DATA;
+    unsigned CURRENT_TIMESTAMP;
+
+    unsigned m_check_sum;
+    std::unique_ptr<QueryGraph> m_query_graph;
+    std::unique_ptr<storage::SharedMemory> m_layout_memory;
+    std::unique_ptr<storage::SharedMemory> m_large_memory;
+    std::string m_timestamp;
+    extractor::ProfileProperties* m_profile_properties;
+
+    std::shared_ptr<util::ShM<util::Coordinate, true>::vector> m_coordinate_list;
+    util::ShM<NodeID, true>::vector m_via_node_list;
+    util::ShM<unsigned, true>::vector m_name_ID_list;
+    util::ShM<extractor::guidance::TurnInstruction, true>::vector m_turn_instruction_list;
+    util::ShM<extractor::TravelMode, true>::vector m_travel_mode_list;
+    util::ShM<char, true>::vector m_names_char_list;
+    util::ShM<unsigned, true>::vector m_name_begin_indices;
+    util::ShM<unsigned, true>::vector m_geometry_indices;
+    util::ShM<extractor::CompressedEdgeContainer::CompressedEdge, true>::vector m_geometry_list;
+    util::ShM<bool, true>::vector m_is_core_node;
+    util::ShM<uint8_t, true>::vector m_datasource_list;
+
+    util::ShM<char, true>::vector m_datasource_name_data;
+    util::ShM<std::size_t, true>::vector m_datasource_name_offsets;
+    util::ShM<std::size_t, true>::vector m_datasource_name_lengths;
+
+    boost::thread_specific_ptr<std::pair<unsigned, std::shared_ptr<SharedRTree>>> m_static_rtree;
+    boost::thread_specific_ptr<SharedGeospatialQuery> m_geospatial_query;
+    boost::filesystem::path file_index_path;
+
+    std::shared_ptr<util::RangeTable<16, true>> m_name_table;
+
+    void LoadChecksum()
+    {
+        m_check_sum = *data_layout->GetBlockPtr<unsigned>(shared_memory,
+                                                          storage::SharedDataLayout::HSGR_CHECKSUM);
+        util::SimpleLogger().Write() << "set checksum: " << m_check_sum;
+    }
+
+    void LoadProfileProperties()
+    {
+        m_profile_properties =
+            data_layout->GetBlockPtr<extractor::ProfileProperties>(shared_memory, storage::SharedDataLayout::PROPERTIES);
+    }
+
+    void LoadTimestamp()
+    {
+        auto timestamp_ptr =
+            data_layout->GetBlockPtr<char>(shared_memory, storage::SharedDataLayout::TIMESTAMP);
+        m_timestamp.resize(data_layout->GetBlockSize(storage::SharedDataLayout::TIMESTAMP));
+        std::copy(timestamp_ptr,
+                  timestamp_ptr + data_layout->GetBlockSize(storage::SharedDataLayout::TIMESTAMP),
+                  m_timestamp.begin());
+    }
+
+    void LoadRTree()
+    {
+        BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
+
+        auto tree_ptr = data_layout->GetBlockPtr<RTreeNode>(
+            shared_memory, storage::SharedDataLayout::R_SEARCH_TREE);
+        m_static_rtree.reset(new TimeStampedRTreePair(
+            CURRENT_TIMESTAMP,
+            util::make_unique<SharedRTree>(
+                tree_ptr, data_layout->num_entries[storage::SharedDataLayout::R_SEARCH_TREE],
+                file_index_path, m_coordinate_list)));
+        m_geospatial_query.reset(
+            new SharedGeospatialQuery(*m_static_rtree->second, m_coordinate_list, *this));
+    }
+
+    void LoadGraph()
+    {
+        auto graph_nodes_ptr = data_layout->GetBlockPtr<GraphNode>(
+            shared_memory, storage::SharedDataLayout::GRAPH_NODE_LIST);
+
+        auto graph_edges_ptr = data_layout->GetBlockPtr<GraphEdge>(
+            shared_memory, storage::SharedDataLayout::GRAPH_EDGE_LIST);
+
+        typename util::ShM<GraphNode, true>::vector node_list(
+            graph_nodes_ptr, data_layout->num_entries[storage::SharedDataLayout::GRAPH_NODE_LIST]);
+        typename util::ShM<GraphEdge, true>::vector edge_list(
+            graph_edges_ptr, data_layout->num_entries[storage::SharedDataLayout::GRAPH_EDGE_LIST]);
+        m_query_graph.reset(new QueryGraph(node_list, edge_list));
+    }
+
+    void LoadNodeAndEdgeInformation()
+    {
+        auto coordinate_list_ptr = data_layout->GetBlockPtr<util::Coordinate>(
+            shared_memory, storage::SharedDataLayout::COORDINATE_LIST);
+        m_coordinate_list = util::make_unique<util::ShM<util::Coordinate, true>::vector>(
+            coordinate_list_ptr,
+            data_layout->num_entries[storage::SharedDataLayout::COORDINATE_LIST]);
+
+        auto travel_mode_list_ptr = data_layout->GetBlockPtr<extractor::TravelMode>(
+            shared_memory, storage::SharedDataLayout::TRAVEL_MODE);
+        typename util::ShM<extractor::TravelMode, true>::vector travel_mode_list(
+            travel_mode_list_ptr, data_layout->num_entries[storage::SharedDataLayout::TRAVEL_MODE]);
+        m_travel_mode_list = std::move(travel_mode_list);
+
+        auto turn_instruction_list_ptr =
+            data_layout->GetBlockPtr<extractor::guidance::TurnInstruction>(
+                shared_memory, storage::SharedDataLayout::TURN_INSTRUCTION);
+        typename util::ShM<extractor::guidance::TurnInstruction, true>::vector
+            turn_instruction_list(
+                turn_instruction_list_ptr,
+                data_layout->num_entries[storage::SharedDataLayout::TURN_INSTRUCTION]);
+        m_turn_instruction_list = std::move(turn_instruction_list);
+
+        auto name_id_list_ptr = data_layout->GetBlockPtr<unsigned>(
+            shared_memory, storage::SharedDataLayout::NAME_ID_LIST);
+        typename util::ShM<unsigned, true>::vector name_id_list(
+            name_id_list_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_ID_LIST]);
+        m_name_ID_list = std::move(name_id_list);
+    }
+
+    void LoadViaNodeList()
+    {
+        auto via_node_list_ptr = data_layout->GetBlockPtr<NodeID>(
+            shared_memory, storage::SharedDataLayout::VIA_NODE_LIST);
+        typename util::ShM<NodeID, true>::vector via_node_list(
+            via_node_list_ptr, data_layout->num_entries[storage::SharedDataLayout::VIA_NODE_LIST]);
+        m_via_node_list = std::move(via_node_list);
+    }
+
+    void LoadNames()
+    {
+        auto offsets_ptr = data_layout->GetBlockPtr<unsigned>(
+            shared_memory, storage::SharedDataLayout::NAME_OFFSETS);
+        auto blocks_ptr = data_layout->GetBlockPtr<NameIndexBlock>(
+            shared_memory, storage::SharedDataLayout::NAME_BLOCKS);
+        typename util::ShM<unsigned, true>::vector name_offsets(
+            offsets_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_OFFSETS]);
+        typename util::ShM<NameIndexBlock, true>::vector name_blocks(
+            blocks_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_BLOCKS]);
+
+        auto names_list_ptr = data_layout->GetBlockPtr<char>(
+            shared_memory, storage::SharedDataLayout::NAME_CHAR_LIST);
+        typename util::ShM<char, true>::vector names_char_list(
+            names_list_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_CHAR_LIST]);
+        m_name_table = util::make_unique<util::RangeTable<16, true>>(
+            name_offsets, name_blocks, static_cast<unsigned>(names_char_list.size()));
+
+        m_names_char_list = std::move(names_char_list);
+    }
+
+    void LoadCoreInformation()
+    {
+        if (data_layout->num_entries[storage::SharedDataLayout::CORE_MARKER] <= 0)
+        {
+            return;
+        }
+
+        auto core_marker_ptr = data_layout->GetBlockPtr<unsigned>(
+            shared_memory, storage::SharedDataLayout::CORE_MARKER);
+        typename util::ShM<bool, true>::vector is_core_node(
+            core_marker_ptr, data_layout->num_entries[storage::SharedDataLayout::CORE_MARKER]);
+        m_is_core_node = std::move(is_core_node);
+    }
+
+    void LoadGeometries()
+    {
+        auto geometries_index_ptr = data_layout->GetBlockPtr<unsigned>(
+            shared_memory, storage::SharedDataLayout::GEOMETRIES_INDEX);
+        typename util::ShM<unsigned, true>::vector geometry_begin_indices(
+            geometries_index_ptr,
+            data_layout->num_entries[storage::SharedDataLayout::GEOMETRIES_INDEX]);
+        m_geometry_indices = std::move(geometry_begin_indices);
+
+        auto geometries_list_ptr =
+            data_layout->GetBlockPtr<extractor::CompressedEdgeContainer::CompressedEdge>(
+                shared_memory, storage::SharedDataLayout::GEOMETRIES_LIST);
+        typename util::ShM<extractor::CompressedEdgeContainer::CompressedEdge, true>::vector
+            geometry_list(geometries_list_ptr,
+                          data_layout->num_entries[storage::SharedDataLayout::GEOMETRIES_LIST]);
+        m_geometry_list = std::move(geometry_list);
+
+        auto datasources_list_ptr = data_layout->GetBlockPtr<uint8_t>(
+            shared_memory, storage::SharedDataLayout::DATASOURCES_LIST);
+        typename util::ShM<uint8_t, true>::vector datasources_list(
+            datasources_list_ptr,
+            data_layout->num_entries[storage::SharedDataLayout::DATASOURCES_LIST]);
+        m_datasource_list = std::move(datasources_list);
+
+        auto datasource_name_data_ptr = data_layout->GetBlockPtr<char>(
+            shared_memory, storage::SharedDataLayout::DATASOURCE_NAME_DATA);
+        typename util::ShM<char, true>::vector datasource_name_data(
+            datasource_name_data_ptr,
+            data_layout->num_entries[storage::SharedDataLayout::DATASOURCE_NAME_DATA]);
+        m_datasource_name_data = std::move(datasource_name_data);
+
+        auto datasource_name_offsets_ptr = data_layout->GetBlockPtr<std::size_t>(
+            shared_memory, storage::SharedDataLayout::DATASOURCE_NAME_OFFSETS);
+        typename util::ShM<std::size_t, true>::vector datasource_name_offsets(
+            datasource_name_offsets_ptr,
+            data_layout->num_entries[storage::SharedDataLayout::DATASOURCE_NAME_OFFSETS]);
+        m_datasource_name_offsets = std::move(datasource_name_offsets);
+
+        auto datasource_name_lengths_ptr = data_layout->GetBlockPtr<std::size_t>(
+            shared_memory, storage::SharedDataLayout::DATASOURCE_NAME_LENGTHS);
+        typename util::ShM<std::size_t, true>::vector datasource_name_lengths(
+            datasource_name_lengths_ptr,
+            data_layout->num_entries[storage::SharedDataLayout::DATASOURCE_NAME_LENGTHS]);
+        m_datasource_name_lengths = std::move(datasource_name_lengths);
+    }
+
+  public:
+    virtual ~SharedDataFacade() {}
+
+    boost::shared_mutex data_mutex;
+
+    SharedDataFacade()
+    {
+        if (!storage::SharedMemory::RegionExists(storage::CURRENT_REGIONS))
+        {
+            throw util::exception(
+                "No shared memory blocks found, have you forgotten to run osrm-datastore?");
+        }
+        data_timestamp_ptr = static_cast<storage::SharedDataTimestamp *>(
+            storage::makeSharedMemory(storage::CURRENT_REGIONS,
+                                      sizeof(storage::SharedDataTimestamp), false, false)
+                ->Ptr());
+        CURRENT_LAYOUT = storage::LAYOUT_NONE;
+        CURRENT_DATA = storage::DATA_NONE;
+        CURRENT_TIMESTAMP = 0;
+
+        // load data
+        CheckAndReloadFacade();
+    }
+
+    void CheckAndReloadFacade()
+    {
+        if (CURRENT_LAYOUT != data_timestamp_ptr->layout ||
+            CURRENT_DATA != data_timestamp_ptr->data ||
+            CURRENT_TIMESTAMP != data_timestamp_ptr->timestamp)
+        {
+            // Get exclusive lock
+            util::SimpleLogger().Write(logDEBUG) << "Updates available, getting exclusive lock";
+            const boost::lock_guard<boost::shared_mutex> lock(data_mutex);
+
+            if (CURRENT_LAYOUT != data_timestamp_ptr->layout ||
+                CURRENT_DATA != data_timestamp_ptr->data)
+            {
+                // release the previous shared memory segments
+                storage::SharedMemory::Remove(CURRENT_LAYOUT);
+                storage::SharedMemory::Remove(CURRENT_DATA);
+
+                CURRENT_LAYOUT = data_timestamp_ptr->layout;
+                CURRENT_DATA = data_timestamp_ptr->data;
+                CURRENT_TIMESTAMP = 0; // Force trigger a reload
+
+                util::SimpleLogger().Write(logDEBUG)
+                    << "Current layout was different to new layout, swapping";
+            }
+            else
+            {
+                util::SimpleLogger().Write(logDEBUG)
+                    << "Current layout was same to new layout, not swapping";
+            }
+
+            if (CURRENT_TIMESTAMP != data_timestamp_ptr->timestamp)
+            {
+                CURRENT_TIMESTAMP = data_timestamp_ptr->timestamp;
+
+                util::SimpleLogger().Write(logDEBUG) << "Performing data reload";
+                m_layout_memory.reset(storage::makeSharedMemory(CURRENT_LAYOUT));
+
+                data_layout = static_cast<storage::SharedDataLayout *>(m_layout_memory->Ptr());
+
+                m_large_memory.reset(storage::makeSharedMemory(CURRENT_DATA));
+                shared_memory = (char *)(m_large_memory->Ptr());
+
+                const auto file_index_ptr = data_layout->GetBlockPtr<char>(
+                    shared_memory, storage::SharedDataLayout::FILE_INDEX_PATH);
+                file_index_path = boost::filesystem::path(file_index_ptr);
+                if (!boost::filesystem::exists(file_index_path))
+                {
+                    util::SimpleLogger().Write(logDEBUG) << "Leaf file name "
+                                                         << file_index_path.string();
+                    throw util::exception("Could not load leaf index file. "
+                                          "Is any data loaded into shared memory?");
+                }
+
+                LoadGraph();
+                LoadChecksum();
+                LoadNodeAndEdgeInformation();
+                LoadGeometries();
+                LoadTimestamp();
+                LoadViaNodeList();
+                LoadNames();
+                LoadCoreInformation();
+                LoadProfileProperties();
+
+                util::SimpleLogger().Write() << "number of geometries: "
+                                             << m_coordinate_list->size();
+                for (unsigned i = 0; i < m_coordinate_list->size(); ++i)
+                {
+                    if (!GetCoordinateOfNode(i).IsValid())
+                    {
+                        util::SimpleLogger().Write() << "coordinate " << i << " not valid";
+                    }
+                }
+            }
+            util::SimpleLogger().Write(logDEBUG) << "Releasing exclusive lock";
+        }
+    }
+
+    // search graph access
+    unsigned GetNumberOfNodes() const override final { return m_query_graph->GetNumberOfNodes(); }
+
+    unsigned GetNumberOfEdges() const override final { return m_query_graph->GetNumberOfEdges(); }
+
+    unsigned GetOutDegree(const NodeID n) const override final
+    {
+        return m_query_graph->GetOutDegree(n);
+    }
+
+    NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); }
+
+    EdgeData &GetEdgeData(const EdgeID e) const override final
+    {
+        return m_query_graph->GetEdgeData(e);
+    }
+
+    EdgeID BeginEdges(const NodeID n) const override final { return m_query_graph->BeginEdges(n); }
+
+    EdgeID EndEdges(const NodeID n) const override final { return m_query_graph->EndEdges(n); }
+
+    EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
+    {
+        return m_query_graph->GetAdjacentEdgeRange(node);
+    }
+
+    // searches for a specific edge
+    EdgeID FindEdge(const NodeID from, const NodeID to) const override final
+    {
+        return m_query_graph->FindEdge(from, to);
+    }
+
+    EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const override final
+    {
+        return m_query_graph->FindEdgeInEitherDirection(from, to);
+    }
+
+    EdgeID
+    FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const override final
+    {
+        return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
+    }
+
+    // node and edge information access
+    util::Coordinate GetCoordinateOfNode(const NodeID id) const override final
+    {
+        return m_coordinate_list->at(id);
+    }
+
+    virtual void GetUncompressedGeometry(const EdgeID id,
+                                         std::vector<NodeID> &result_nodes) const override final
+    {
+        const unsigned begin = m_geometry_indices.at(id);
+        const unsigned end = m_geometry_indices.at(id + 1);
+
+        result_nodes.clear();
+        result_nodes.reserve(end - begin);
+        std::for_each(m_geometry_list.begin() + begin, m_geometry_list.begin() + end,
+                      [&](const osrm::extractor::CompressedEdgeContainer::CompressedEdge &edge)
+                      {
+                          result_nodes.emplace_back(edge.node_id);
+                      });
+    }
+
+    virtual void
+    GetUncompressedWeights(const EdgeID id,
+                           std::vector<EdgeWeight> &result_weights) const override final
+    {
+        const unsigned begin = m_geometry_indices.at(id);
+        const unsigned end = m_geometry_indices.at(id + 1);
+
+        result_weights.clear();
+        result_weights.reserve(end - begin);
+        std::for_each(m_geometry_list.begin() + begin, m_geometry_list.begin() + end,
+                      [&](const osrm::extractor::CompressedEdgeContainer::CompressedEdge &edge)
+                      {
+                          result_weights.emplace_back(edge.weight);
+                      });
+    }
+
+    virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const override final
+    {
+        return m_via_node_list.at(id);
+    }
+
+    extractor::guidance::TurnInstruction
+    GetTurnInstructionForEdgeID(const unsigned id) const override final
+    {
+        return m_turn_instruction_list.at(id);
+    }
+
+    extractor::TravelMode GetTravelModeForEdgeID(const unsigned id) const override final
+    {
+        return m_travel_mode_list.at(id);
+    }
+
+    std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate south_west,
+                                         const util::Coordinate north_east) override final
+    {
+        if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+        const util::RectangleInt2D bbox{south_west.lon, north_east.lon, south_west.lat,
+                                        north_east.lat};
+        return m_geospatial_query->Search(bbox);
+    }
+
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
+                               const float max_distance) override final
+    {
+        if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance);
+    }
+
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
+                               const float max_distance,
+                               const int bearing,
+                               const int bearing_range) override final
+    {
+        if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance,
+                                                              bearing, bearing_range);
+    }
+
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate input_coordinate,
+                        const unsigned max_results) override final
+    {
+        if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results);
+    }
+
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate input_coordinate,
+                        const unsigned max_results,
+                        const double max_distance) override final
+    {
+        if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, max_distance);
+    }
+
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate input_coordinate,
+                        const unsigned max_results,
+                        const int bearing,
+                        const int bearing_range) override final
+    {
+        if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, bearing,
+                                                       bearing_range);
+    }
+
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate input_coordinate,
+                        const unsigned max_results,
+                        const double max_distance,
+                        const int bearing,
+                        const int bearing_range) override final
+    {
+        if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, max_distance,
+                                                       bearing, bearing_range);
+    }
+
+    std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
+        const util::Coordinate input_coordinate) override final
+    {
+        if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
+            input_coordinate);
+    }
+
+    std::pair<PhantomNode, PhantomNode>
+    NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+                                                      const double max_distance) override final
+    {
+        if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
+            input_coordinate, max_distance);
+    }
+
+    std::pair<PhantomNode, PhantomNode>
+    NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+                                                      const double max_distance,
+                                                      const int bearing,
+                                                      const int bearing_range) override final
+    {
+        if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
+            input_coordinate, max_distance, bearing, bearing_range);
+    }
+
+    std::pair<PhantomNode, PhantomNode>
+    NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+                                                      const int bearing,
+                                                      const int bearing_range) override final
+    {
+        if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+        {
+            LoadRTree();
+            BOOST_ASSERT(m_geospatial_query.get());
+        }
+
+        return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
+            input_coordinate, bearing, bearing_range);
+    }
+
+    unsigned GetCheckSum() const override final { return m_check_sum; }
+
+    unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
+    {
+        return m_name_ID_list.at(id);
+    }
+
+    std::string GetNameForID(const unsigned name_id) const override final
+    {
+        if (std::numeric_limits<unsigned>::max() == name_id)
+        {
+            return "";
+        }
+        auto range = m_name_table->GetRange(name_id);
+
+        std::string result;
+        result.reserve(range.size());
+        if (range.begin() != range.end())
+        {
+            result.resize(range.back() - range.front() + 1);
+            std::copy(m_names_char_list.begin() + range.front(),
+                      m_names_char_list.begin() + range.back() + 1, result.begin());
+        }
+        return result;
+    }
+
+    bool IsCoreNode(const NodeID id) const override final
+    {
+        if (m_is_core_node.size() > 0)
+        {
+            return m_is_core_node.at(id);
+        }
+
+        return false;
+    }
+
+    virtual std::size_t GetCoreSize() const override final { return m_is_core_node.size(); }
+
+    // Returns the data source ids that were used to supply the edge
+    // weights.
+    virtual void
+    GetUncompressedDatasources(const EdgeID id,
+                               std::vector<uint8_t> &result_datasources) const override final
+    {
+        const unsigned begin = m_geometry_indices.at(id);
+        const unsigned end = m_geometry_indices.at(id + 1);
+
+        result_datasources.clear();
+        result_datasources.reserve(end - begin);
+
+        // If there was no datasource info, return an array of 0's.
+        if (m_datasource_list.empty())
+        {
+            for (unsigned i = 0; i < end - begin; ++i)
+            {
+                result_datasources.push_back(0);
+            }
+        }
+        else
+        {
+            std::for_each(m_datasource_list.begin() + begin, m_datasource_list.begin() + end,
+                          [&](const uint8_t &datasource_id)
+                          {
+                              result_datasources.push_back(datasource_id);
+                          });
+        }
+    }
+
+    virtual std::string GetDatasourceName(const uint8_t datasource_name_id) const override final
+    {
+        BOOST_ASSERT(m_datasource_name_offsets.size() >= 1);
+        BOOST_ASSERT(m_datasource_name_offsets.size() > datasource_name_id);
+
+        std::string result;
+        result.reserve(m_datasource_name_lengths[datasource_name_id]);
+        std::copy(m_datasource_name_data.begin() + m_datasource_name_offsets[datasource_name_id],
+                  m_datasource_name_data.begin() + m_datasource_name_offsets[datasource_name_id] +
+                      m_datasource_name_lengths[datasource_name_id],
+                  std::back_inserter(result));
+
+        return result;
+    }
+
+    std::string GetTimestamp() const override final { return m_timestamp; }
+
+    bool GetUTurnsDefault() const override final { return m_profile_properties->allow_u_turn_at_via; }
+};
+}
+}
+}
+
+#endif // SHARED_DATAFACADE_HPP
diff --git a/include/engine/douglas_peucker.hpp b/include/engine/douglas_peucker.hpp
new file mode 100644
index 0000000..468c6c7
--- /dev/null
+++ b/include/engine/douglas_peucker.hpp
@@ -0,0 +1,60 @@
+#ifndef DOUGLAS_PEUCKER_HPP_
+#define DOUGLAS_PEUCKER_HPP_
+
+#include "util/coordinate.hpp"
+
+#include <vector>
+#include <iterator>
+
+namespace osrm
+{
+namespace engine
+{
+namespace detail
+{
+const constexpr int DOUGLAS_PEUCKER_THRESHOLDS[19] = {
+    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
+};
+
+const constexpr auto DOUGLAS_PEUCKER_THRESHOLDS_SIZE =
+    sizeof(DOUGLAS_PEUCKER_THRESHOLDS) / sizeof(*DOUGLAS_PEUCKER_THRESHOLDS);
+} // ns detail
+
+// These functions compute the bitvector of indicating generalized input
+// points according to the (Ramer-)Douglas-Peucker algorithm.
+//
+// Input is vector of pairs. Each pair consists of the point information and a
+// bit indicating if the points is present in the generalization.
+// Note: points may also be pre-selected*/
+std::vector<util::Coordinate> douglasPeucker(std::vector<util::Coordinate>::const_iterator begin,
+                                             std::vector<util::Coordinate>::const_iterator end,
+                                             const unsigned zoom_level);
+
+// Convenience range-based function
+inline std::vector<util::Coordinate> douglasPeucker(const std::vector<util::Coordinate> &geometry,
+                                                    const unsigned zoom_level)
+{
+    return douglasPeucker(begin(geometry), end(geometry), zoom_level);
+}
+}
+}
+
+#endif /* DOUGLAS_PEUCKER_HPP_ */
diff --git a/include/engine/engine.hpp b/include/engine/engine.hpp
new file mode 100644
index 0000000..027320b
--- /dev/null
+++ b/include/engine/engine.hpp
@@ -0,0 +1,88 @@
+#ifndef ENGINE_HPP
+#define ENGINE_HPP
+
+#include "engine/status.hpp"
+#include "storage/shared_barriers.hpp"
+#include "util/json_container.hpp"
+
+#include <memory>
+#include <unordered_map>
+#include <string>
+
+namespace osrm
+{
+
+namespace util
+{
+namespace json
+{
+struct Object;
+}
+}
+
+// Fwd decls
+namespace engine
+{
+struct EngineConfig;
+namespace api
+{
+struct RouteParameters;
+struct TableParameters;
+struct NearestParameters;
+struct TripParameters;
+struct MatchParameters;
+struct TileParameters;
+}
+namespace plugins
+{
+class ViaRoutePlugin;
+class TablePlugin;
+class NearestPlugin;
+class TripPlugin;
+class MatchPlugin;
+class TilePlugin;
+}
+// End fwd decls
+
+namespace datafacade
+{
+class BaseDataFacade;
+}
+
+class Engine final
+{
+  public:
+    // Needs to be public
+    struct EngineLock;
+
+    explicit Engine(EngineConfig &config);
+
+    Engine(Engine &&) noexcept;
+    Engine &operator=(Engine &&) noexcept;
+
+    // Impl. in cpp since for unique_ptr of incomplete types
+    ~Engine();
+
+    Status Route(const api::RouteParameters &parameters, util::json::Object &result);
+    Status Table(const api::TableParameters &parameters, util::json::Object &result);
+    Status Nearest(const api::NearestParameters &parameters, util::json::Object &result);
+    Status Trip(const api::TripParameters &parameters, util::json::Object &result);
+    Status Match(const api::MatchParameters &parameters, util::json::Object &result);
+    Status Tile(const api::TileParameters &parameters, std::string &result);
+
+  private:
+    std::unique_ptr<EngineLock> lock;
+
+    std::unique_ptr<plugins::ViaRoutePlugin> route_plugin;
+    std::unique_ptr<plugins::TablePlugin> table_plugin;
+    std::unique_ptr<plugins::NearestPlugin> nearest_plugin;
+    std::unique_ptr<plugins::TripPlugin> trip_plugin;
+    std::unique_ptr<plugins::MatchPlugin> match_plugin;
+    std::unique_ptr<plugins::TilePlugin> tile_plugin;
+
+    std::unique_ptr<datafacade::BaseDataFacade> query_data_facade;
+};
+}
+}
+
+#endif // OSRM_IMPL_HPP
diff --git a/include/osrm/libosrm_config.hpp b/include/engine/engine_config.hpp
similarity index 68%
rename from include/osrm/libosrm_config.hpp
rename to include/engine/engine_config.hpp
index 677450a..eb62719 100644
--- a/include/osrm/libosrm_config.hpp
+++ b/include/engine/engine_config.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,22 +25,49 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef LIBOSRM_CONFIG_HPP
-#define LIBOSRM_CONFIG_HPP
+#ifndef ENGINE_CONFIG_HPP
+#define ENGINE_CONFIG_HPP
+
+#include "storage/storage_config.hpp"
 
 #include <boost/filesystem/path.hpp>
 
-#include <unordered_map>
 #include <string>
 
-struct LibOSRMConfig
+namespace osrm
+{
+
+namespace engine
 {
-    std::unordered_map<std::string, boost::filesystem::path> server_paths;
+
+/**
+ * Configures an OSRM instance.
+ *
+ * You can customize the storage OSRM uses for auxiliary files specifying a storage config.
+ *
+ * You can further set service constraints.
+ * These are the maximum number of allowed locations (-1 for unlimited) for the services:
+ *  - Trip
+ *  - Route
+ *  - Table
+ *  - Match
+ *
+ * In addition, shared memory can be used for datasets loaded with osrm-datastore.
+ *
+ * \see OSRM, StorageConfig
+ */
+struct EngineConfig final
+{
+    bool IsValid() const;
+
+    storage::StorageConfig storage_config;
     int max_locations_trip = -1;
     int max_locations_viaroute = -1;
     int max_locations_distance_table = -1;
     int max_locations_map_matching = -1;
     bool use_shared_memory = true;
 };
+}
+}
 
 #endif // SERVER_CONFIG_HPP
diff --git a/include/engine/geospatial_query.hpp b/include/engine/geospatial_query.hpp
new file mode 100644
index 0000000..e880139
--- /dev/null
+++ b/include/engine/geospatial_query.hpp
@@ -0,0 +1,467 @@
+#ifndef GEOSPATIAL_QUERY_HPP
+#define GEOSPATIAL_QUERY_HPP
+
+#include "util/coordinate_calculation.hpp"
+#include "util/typedefs.hpp"
+#include "engine/phantom_node.hpp"
+#include "util/bearing.hpp"
+#include "util/rectangle.hpp"
+
+#include "osrm/coordinate.hpp"
+
+#include <algorithm>
+#include <cmath>
+#include <memory>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+
+// Implements complex queries on top of an RTree and builds PhantomNodes from it.
+//
+// Only holds a weak reference on the RTree!
+template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
+{
+    using EdgeData = typename RTreeT::EdgeData;
+    using CoordinateList = typename RTreeT::CoordinateList;
+    using CandidateSegment = typename RTreeT::CandidateSegment;
+
+  public:
+    GeospatialQuery(RTreeT &rtree_,
+                    std::shared_ptr<CoordinateList> coordinates_,
+                    DataFacadeT &datafacade_)
+        : rtree(rtree_), coordinates(std::move(coordinates_)), datafacade(datafacade_)
+    {
+    }
+
+    std::vector<EdgeData> Search(const util::RectangleInt2D &bbox)
+    {
+        return rtree.SearchInBox(bbox);
+    }
+
+    // Returns nearest PhantomNodes in the given bearing range within max_distance.
+    // Does not filter by small/big component!
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodesInRange(const util::Coordinate input_coordinate, const double max_distance)
+    {
+        auto results =
+            rtree.Nearest(input_coordinate,
+                          [](const CandidateSegment &)
+                          {
+                              return std::make_pair(true, true);
+                          },
+                          [this, max_distance, input_coordinate](const std::size_t,
+                                                                 const CandidateSegment &segment)
+                          {
+                              return checkSegmentDistance(input_coordinate, segment, max_distance);
+                          });
+
+        return MakePhantomNodes(input_coordinate, results);
+    }
+
+    // Returns nearest PhantomNodes in the given bearing range within max_distance.
+    // Does not filter by small/big component!
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
+                               const double max_distance,
+                               const int bearing,
+                               const int bearing_range)
+    {
+        auto results = rtree.Nearest(
+            input_coordinate,
+            [this, bearing, bearing_range, max_distance](const CandidateSegment &segment)
+            {
+                return checkSegmentBearing(segment, bearing, bearing_range);
+            },
+            [this, max_distance, input_coordinate](const std::size_t,
+                                                   const CandidateSegment &segment)
+            {
+                return checkSegmentDistance(input_coordinate, segment, max_distance);
+            });
+
+        return MakePhantomNodes(input_coordinate, results);
+    }
+
+    // Returns max_results nearest PhantomNodes in the given bearing range.
+    // Does not filter by small/big component!
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate input_coordinate,
+                        const unsigned max_results,
+                        const int bearing,
+                        const int bearing_range)
+    {
+        auto results =
+            rtree.Nearest(input_coordinate,
+                          [this, bearing, bearing_range](const CandidateSegment &segment)
+                          {
+                              return checkSegmentBearing(segment, bearing, bearing_range);
+                          },
+                          [max_results](const std::size_t num_results, const CandidateSegment &)
+                          {
+                              return num_results >= max_results;
+                          });
+
+        return MakePhantomNodes(input_coordinate, results);
+    }
+
+    // Returns max_results nearest PhantomNodes in the given bearing range within the maximum
+    // distance.
+    // Does not filter by small/big component!
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate input_coordinate,
+                        const unsigned max_results,
+                        const double max_distance,
+                        const int bearing,
+                        const int bearing_range)
+    {
+        auto results =
+            rtree.Nearest(input_coordinate,
+                          [this, bearing, bearing_range](const CandidateSegment &segment)
+                          {
+                              return checkSegmentBearing(segment, bearing, bearing_range);
+                          },
+                          [this, max_distance, max_results, input_coordinate](
+                              const std::size_t num_results, const CandidateSegment &segment)
+                          {
+                              return num_results >= max_results ||
+                                     checkSegmentDistance(input_coordinate, segment, max_distance);
+                          });
+
+        return MakePhantomNodes(input_coordinate, results);
+    }
+
+    // Returns max_results nearest PhantomNodes.
+    // Does not filter by small/big component!
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate input_coordinate, const unsigned max_results)
+    {
+        auto results =
+            rtree.Nearest(input_coordinate,
+                          [](const CandidateSegment &)
+                          {
+                              return std::make_pair(true, true);
+                          },
+                          [max_results](const std::size_t num_results, const CandidateSegment &)
+                          {
+                              return num_results >= max_results;
+                          });
+
+        return MakePhantomNodes(input_coordinate, results);
+    }
+
+    // Returns max_results nearest PhantomNodes in the given max distance.
+    // Does not filter by small/big component!
+    std::vector<PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate input_coordinate,
+                        const unsigned max_results,
+                        const double max_distance)
+    {
+        auto results =
+            rtree.Nearest(input_coordinate,
+                          [](const CandidateSegment &)
+                          {
+                              return std::make_pair(true, true);
+                          },
+                          [this, max_distance, max_results, input_coordinate](
+                              const std::size_t num_results, const CandidateSegment &segment)
+                          {
+                              return num_results >= max_results ||
+                                     checkSegmentDistance(input_coordinate, segment, max_distance);
+                          });
+
+        return MakePhantomNodes(input_coordinate, results);
+    }
+
+    // Returns the nearest phantom node. If this phantom node is not from a big component
+    // a second phantom node is return that is the nearest coordinate in a big component.
+    std::pair<PhantomNode, PhantomNode>
+    NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+                                                      const double max_distance)
+    {
+        bool has_small_component = false;
+        bool has_big_component = false;
+        auto results = rtree.Nearest(
+            input_coordinate,
+            [&has_big_component, &has_small_component](const CandidateSegment &segment)
+            {
+                auto use_segment = (!has_small_component ||
+                                    (!has_big_component && !segment.data.component.is_tiny));
+                auto use_directions = std::make_pair(use_segment, use_segment);
+
+                has_big_component = has_big_component || !segment.data.component.is_tiny;
+                has_small_component = has_small_component || segment.data.component.is_tiny;
+
+                return use_directions;
+            },
+            [this, &has_big_component, max_distance,
+             input_coordinate](const std::size_t num_results, const CandidateSegment &segment)
+            {
+                return (num_results > 0 && has_big_component) ||
+                       checkSegmentDistance(input_coordinate, segment, max_distance);
+            });
+
+        if (results.size() == 0)
+        {
+            return std::make_pair(PhantomNode{}, PhantomNode{});
+        }
+
+        BOOST_ASSERT(results.size() == 1 || results.size() == 2);
+        return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
+                              MakePhantomNode(input_coordinate, results.back()).phantom_node);
+    }
+
+    // Returns the nearest phantom node. If this phantom node is not from a big component
+    // a second phantom node is return that is the nearest coordinate in a big component.
+    std::pair<PhantomNode, PhantomNode>
+    NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate)
+    {
+        bool has_small_component = false;
+        bool has_big_component = false;
+        auto results = rtree.Nearest(
+            input_coordinate,
+            [&has_big_component, &has_small_component](const CandidateSegment &segment)
+            {
+                auto use_segment = (!has_small_component ||
+                                    (!has_big_component && !segment.data.component.is_tiny));
+                auto use_directions = std::make_pair(use_segment, use_segment);
+
+                has_big_component = has_big_component || !segment.data.component.is_tiny;
+                has_small_component = has_small_component || segment.data.component.is_tiny;
+
+                return use_directions;
+            },
+            [&has_big_component](const std::size_t num_results, const CandidateSegment &)
+            {
+                return num_results > 0 && has_big_component;
+            });
+
+        if (results.size() == 0)
+        {
+            return std::make_pair(PhantomNode{}, PhantomNode{});
+        }
+
+        BOOST_ASSERT(results.size() == 1 || results.size() == 2);
+        return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
+                              MakePhantomNode(input_coordinate, results.back()).phantom_node);
+    }
+
+    // Returns the nearest phantom node. If this phantom node is not from a big component
+    // a second phantom node is return that is the nearest coordinate in a big component.
+    std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
+        const util::Coordinate input_coordinate, const int bearing, const int bearing_range)
+    {
+        bool has_small_component = false;
+        bool has_big_component = false;
+        auto results = rtree.Nearest(
+            input_coordinate,
+            [this, bearing, bearing_range, &has_big_component,
+             &has_small_component](const CandidateSegment &segment)
+            {
+                auto use_segment = (!has_small_component ||
+                                    (!has_big_component && !segment.data.component.is_tiny));
+                auto use_directions = std::make_pair(use_segment, use_segment);
+
+                if (use_segment)
+                {
+                    use_directions = checkSegmentBearing(segment, bearing, bearing_range);
+                    if (use_directions.first || use_directions.second)
+                    {
+                        has_big_component = has_big_component || !segment.data.component.is_tiny;
+                        has_small_component = has_small_component || segment.data.component.is_tiny;
+                    }
+                }
+
+                return use_directions;
+            },
+            [&has_big_component](const std::size_t num_results, const CandidateSegment &)
+            {
+                return num_results > 0 && has_big_component;
+            });
+
+        if (results.size() == 0)
+        {
+            return std::make_pair(PhantomNode{}, PhantomNode{});
+        }
+
+        BOOST_ASSERT(results.size() > 0);
+        return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
+                              MakePhantomNode(input_coordinate, results.back()).phantom_node);
+    }
+
+    // Returns the nearest phantom node. If this phantom node is not from a big component
+    // a second phantom node is return that is the nearest coordinate in a big component.
+    std::pair<PhantomNode, PhantomNode>
+    NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+                                                      const double max_distance,
+                                                      const int bearing,
+                                                      const int bearing_range)
+    {
+        bool has_small_component = false;
+        bool has_big_component = false;
+        auto results = rtree.Nearest(
+            input_coordinate,
+            [this, bearing, bearing_range, &has_big_component,
+             &has_small_component](const CandidateSegment &segment)
+            {
+                auto use_segment = (!has_small_component ||
+                                    (!has_big_component && !segment.data.component.is_tiny));
+                auto use_directions = std::make_pair(use_segment, use_segment);
+
+                if (use_segment)
+                {
+                    use_directions = checkSegmentBearing(segment, bearing, bearing_range);
+                    if (use_directions.first || use_directions.second)
+                    {
+                        has_big_component = has_big_component || !segment.data.component.is_tiny;
+                        has_small_component = has_small_component || segment.data.component.is_tiny;
+                    }
+                }
+
+                return use_directions;
+            },
+            [this, &has_big_component, max_distance,
+             input_coordinate](const std::size_t num_results, const CandidateSegment &segment)
+            {
+                return (num_results > 0 && has_big_component) ||
+                       checkSegmentDistance(input_coordinate, segment, max_distance);
+            });
+
+        if (results.size() == 0)
+        {
+            return std::make_pair(PhantomNode{}, PhantomNode{});
+        }
+
+        BOOST_ASSERT(results.size() > 0);
+        return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
+                              MakePhantomNode(input_coordinate, results.back()).phantom_node);
+    }
+
+  private:
+    std::vector<PhantomNodeWithDistance>
+    MakePhantomNodes(const util::Coordinate input_coordinate,
+                     const std::vector<EdgeData> &results) const
+    {
+        std::vector<PhantomNodeWithDistance> distance_and_phantoms(results.size());
+        std::transform(results.begin(), results.end(), distance_and_phantoms.begin(),
+                       [this, &input_coordinate](const EdgeData &data)
+                       {
+                           return MakePhantomNode(input_coordinate, data);
+                       });
+        return distance_and_phantoms;
+    }
+
+    PhantomNodeWithDistance MakePhantomNode(const util::Coordinate input_coordinate,
+                                            const EdgeData &data) const
+    {
+        util::Coordinate point_on_segment;
+        double ratio;
+        const auto current_perpendicular_distance =
+            util::coordinate_calculation::perpendicularDistance(
+                coordinates->at(data.u), coordinates->at(data.v), input_coordinate,
+                point_on_segment, ratio);
+
+        // Find the node-based-edge that this belongs to, and directly
+        // calculate the forward_weight, forward_offset, reverse_weight, reverse_offset
+
+        int forward_offset = 0, forward_weight = 0;
+        int reverse_offset = 0, reverse_weight = 0;
+
+        if (data.forward_packed_geometry_id != SPECIAL_EDGEID)
+        {
+            std::vector<EdgeWeight> forward_weight_vector;
+            datafacade.GetUncompressedWeights(data.forward_packed_geometry_id,
+                                              forward_weight_vector);
+            for (std::size_t i = 0; i < data.fwd_segment_position; i++)
+            {
+                forward_offset += forward_weight_vector[i];
+            }
+            forward_weight = forward_weight_vector[data.fwd_segment_position];
+        }
+
+        if (data.reverse_packed_geometry_id != SPECIAL_EDGEID)
+        {
+            std::vector<EdgeWeight> reverse_weight_vector;
+            datafacade.GetUncompressedWeights(data.reverse_packed_geometry_id,
+                                              reverse_weight_vector);
+
+            BOOST_ASSERT(data.fwd_segment_position < reverse_weight_vector.size());
+
+            for (std::size_t i = 0;
+                 i < reverse_weight_vector.size() - data.fwd_segment_position - 1; i++)
+            {
+                reverse_offset += reverse_weight_vector[i];
+            }
+            reverse_weight =
+                reverse_weight_vector[reverse_weight_vector.size() - data.fwd_segment_position - 1];
+        }
+
+        ratio = std::min(1.0, std::max(0.0, ratio));
+        if (data.forward_segment_id.id != SPECIAL_SEGMENTID)
+        {
+            forward_weight *= ratio;
+        }
+        if (data.reverse_segment_id.id != SPECIAL_SEGMENTID)
+        {
+            reverse_weight *= 1.0 - ratio;
+        }
+
+        auto transformed = PhantomNodeWithDistance{PhantomNode{data, forward_weight, forward_offset,
+                                                               reverse_weight, reverse_offset,
+                                                               point_on_segment, input_coordinate},
+                                                   current_perpendicular_distance};
+
+        return transformed;
+    }
+
+    bool checkSegmentDistance(const Coordinate input_coordinate,
+                              const CandidateSegment &segment,
+                              const double max_distance)
+    {
+        BOOST_ASSERT(segment.data.forward_segment_id.id != SPECIAL_SEGMENTID ||
+                     !segment.data.forward_segment_id.enabled);
+        BOOST_ASSERT(segment.data.reverse_segment_id.id != SPECIAL_SEGMENTID ||
+                     !segment.data.reverse_segment_id.enabled);
+
+        Coordinate wsg84_coordinate = util::coordinate_calculation::mercator::toWGS84(
+            segment.fixed_projected_coordinate);
+
+        return util::coordinate_calculation::haversineDistance(input_coordinate, wsg84_coordinate) > max_distance;
+    }
+
+    std::pair<bool, bool> checkSegmentBearing(const CandidateSegment &segment,
+                                              const int filter_bearing,
+                                              const int filter_bearing_range)
+    {
+        BOOST_ASSERT(segment.data.forward_segment_id.id != SPECIAL_SEGMENTID ||
+                     !segment.data.forward_segment_id.enabled);
+        BOOST_ASSERT(segment.data.reverse_segment_id.id != SPECIAL_SEGMENTID ||
+                     !segment.data.reverse_segment_id.enabled);
+
+        const double forward_edge_bearing = util::coordinate_calculation::bearing(
+            coordinates->at(segment.data.u), coordinates->at(segment.data.v));
+
+        const double backward_edge_bearing = (forward_edge_bearing + 180) > 360
+                                                 ? (forward_edge_bearing - 180)
+                                                 : (forward_edge_bearing + 180);
+
+        const bool forward_bearing_valid =
+            util::bearing::CheckInBounds(std::round(forward_edge_bearing), filter_bearing,
+                                         filter_bearing_range) &&
+            segment.data.forward_segment_id.enabled;
+        const bool backward_bearing_valid =
+            util::bearing::CheckInBounds(std::round(backward_edge_bearing), filter_bearing,
+                                         filter_bearing_range) &&
+            segment.data.reverse_segment_id.enabled;
+        return std::make_pair(forward_bearing_valid, backward_bearing_valid);
+    }
+
+    RTreeT &rtree;
+    const std::shared_ptr<CoordinateList> coordinates;
+    DataFacadeT &datafacade;
+};
+}
+}
+
+#endif
diff --git a/include/engine/guidance/assemble_geometry.hpp b/include/engine/guidance/assemble_geometry.hpp
new file mode 100644
index 0000000..4fd84cb
--- /dev/null
+++ b/include/engine/guidance/assemble_geometry.hpp
@@ -0,0 +1,81 @@
+#ifndef ENGINE_GUIDANCE_ASSEMBLE_GEOMETRY_HPP
+#define ENGINE_GUIDANCE_ASSEMBLE_GEOMETRY_HPP
+
+#include "engine/internal_route_result.hpp"
+#include "engine/phantom_node.hpp"
+#include "engine/guidance/route_step.hpp"
+#include "engine/guidance/leg_geometry.hpp"
+#include "engine/guidance/toolkit.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/coordinate.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+#include "extractor/travel_mode.hpp"
+
+#include <vector>
+#include <utility>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+// Extracts the geometry for each segment and calculates the traveled distance
+// Combines the geometry form the phantom node with the PathData
+// to the full route geometry.
+//
+// turn    0   1   2   3   4
+//         s...x...y...z...t
+//         |---|segment 0
+//             |---| segment 1
+//                 |---| segment 2
+//                     |---| segment 3
+template <typename DataFacadeT>
+LegGeometry assembleGeometry(const DataFacadeT &facade,
+                             const std::vector<PathData> &leg_data,
+                             const PhantomNode &source_node,
+                             const PhantomNode &target_node)
+{
+    LegGeometry geometry;
+
+    // segment 0 first and last
+    geometry.segment_offsets.push_back(0);
+    geometry.locations.push_back(source_node.location);
+
+    auto current_distance = 0.;
+    auto prev_coordinate = geometry.locations.front();
+    for (const auto &path_point : leg_data)
+    {
+        auto coordinate = facade.GetCoordinateOfNode(path_point.turn_via_node);
+        current_distance +=
+            util::coordinate_calculation::haversineDistance(prev_coordinate, coordinate);
+
+        // all changes to this check have to be matched with assemble_steps
+        if (path_point.turn_instruction.type != extractor::guidance::TurnType::NoTurn)
+        {
+            geometry.segment_distances.push_back(current_distance);
+            geometry.segment_offsets.push_back(geometry.locations.size());
+            current_distance = 0.;
+        }
+
+        prev_coordinate = coordinate;
+        geometry.locations.push_back(std::move(coordinate));
+    }
+    current_distance +=
+        util::coordinate_calculation::haversineDistance(prev_coordinate, target_node.location);
+    // segment leading to the target node
+    geometry.segment_distances.push_back(current_distance);
+    geometry.segment_offsets.push_back(geometry.locations.size());
+    geometry.locations.push_back(target_node.location);
+
+    BOOST_ASSERT(geometry.segment_distances.size() == geometry.segment_offsets.size() - 1);
+    BOOST_ASSERT(geometry.locations.size() > geometry.segment_distances.size());
+
+    return geometry;
+}
+}
+}
+}
+
+#endif
diff --git a/include/engine/guidance/assemble_leg.hpp b/include/engine/guidance/assemble_leg.hpp
new file mode 100644
index 0000000..bf34d74
--- /dev/null
+++ b/include/engine/guidance/assemble_leg.hpp
@@ -0,0 +1,169 @@
+#ifndef ENGINE_GUIDANCE_ASSEMBLE_LEG_HPP_
+#define ENGINE_GUIDANCE_ASSEMBLE_LEG_HPP_
+
+#include "engine/guidance/route_leg.hpp"
+#include "engine/guidance/route_step.hpp"
+#include "engine/guidance/leg_geometry.hpp"
+#include "engine/internal_route_result.hpp"
+
+#include <cstddef>
+#include <cstdint>
+
+#include <vector>
+#include <array>
+#include <string>
+#include <utility>
+#include <numeric>
+#include <algorithm>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+namespace detail
+{
+const constexpr std::size_t MAX_USED_SEGMENTS = 2;
+struct NamedSegment
+{
+    double duration;
+    std::uint32_t position;
+    std::uint32_t name_id;
+};
+
+template <std::size_t SegmentNumber>
+std::array<std::uint32_t, SegmentNumber> summarizeRoute(const std::vector<PathData> &route_data)
+{
+    // merges segments with same name id
+    const auto collapse_segments = [](std::vector<NamedSegment> &segments)
+    {
+        auto out = segments.begin();
+        auto end = segments.end();
+        for (auto in = segments.begin(); in != end; ++in)
+        {
+            if (in->name_id == out->name_id)
+            {
+                out->duration += in->duration;
+            }
+            else
+            {
+                ++out;
+                BOOST_ASSERT(out != end);
+                *out = *in;
+            }
+        }
+        return out;
+    };
+
+    std::vector<NamedSegment> segments(route_data.size());
+    std::uint32_t index = 0;
+    std::transform(
+        route_data.begin(), route_data.end(), segments.begin(), [&index](const PathData &point)
+        {
+            return NamedSegment{point.duration_until_turn / 10.0, index++, point.name_id};
+        });
+    // this makes sure that the segment with the lowest position comes first
+    std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs)
+              {
+                  return lhs.name_id < rhs.name_id ||
+                         (lhs.name_id == rhs.name_id && lhs.position < rhs.position);
+              });
+    auto new_end = collapse_segments(segments);
+    segments.resize(new_end - segments.begin());
+    // sort descending
+    std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs)
+              {
+                  return lhs.duration > rhs.duration;
+              });
+
+    // make sure the segments are sorted by position
+    segments.resize(std::min(segments.size(), SegmentNumber));
+    std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs)
+              {
+                  return lhs.position < rhs.position;
+              });
+
+    std::array<std::uint32_t, SegmentNumber> summary;
+    std::fill(summary.begin(), summary.end(), 0);
+    std::transform(segments.begin(), segments.end(), summary.begin(),
+                   [](const NamedSegment &segment)
+                   {
+                       return segment.name_id;
+                   });
+    return summary;
+}
+}
+
+template <typename DataFacadeT>
+RouteLeg assembleLeg(const DataFacadeT &facade,
+                     const std::vector<PathData> &route_data,
+                     const LegGeometry &leg_geometry,
+                     const PhantomNode &source_node,
+                     const PhantomNode &target_node,
+                     const bool target_traversed_in_reverse)
+{
+    const auto target_duration =
+        (target_traversed_in_reverse ? target_node.reverse_weight : target_node.forward_weight) /
+        10.;
+
+    auto distance = std::accumulate(leg_geometry.segment_distances.begin(),
+                                    leg_geometry.segment_distances.end(), 0.);
+    auto duration = std::accumulate(route_data.begin(), route_data.end(), 0.,
+                                    [](const double sum, const PathData &data)
+                                    {
+                                        return sum + data.duration_until_turn;
+                                    }) /
+                    10.;
+
+    //                 s
+    //                 |
+    // Given a route a---b---c  where there is a right turn at c.
+    //                       |
+    //                       d
+    //                       |--t
+    //                       e
+    // (a, b, c) gets compressed to (a,c)
+    // (c, d, e) gets compressed to (c,e)
+    // The duration of the turn (a,c) -> (c,e) will be the duration of (a,c) (e.g. the duration
+    // of (a,b,c)).
+    // The phantom node of s will contain:
+    // `forward_weight`: duration of (a,s)
+    // `forward_offset`: 0 (its the first segment)
+    // The phantom node of t will contain:
+    // `forward_weight`: duration of (d,t)
+    // `forward_offset`: duration of (c, d)
+    // path_data will have entries for (s,b), (b, c), (c, d) but (d, t) is only
+    // caputed by the phantom node. So we need to add the target duration here.
+    // On local segments, the target duration is already part of the duration, however.
+
+    duration = duration + target_duration;
+    if (route_data.empty())
+    {
+        duration -=
+            (target_traversed_in_reverse ? source_node.reverse_weight : source_node.forward_weight) / 10;
+    }
+    auto summary_array = detail::summarizeRoute<detail::MAX_USED_SEGMENTS>(route_data);
+
+    BOOST_ASSERT(detail::MAX_USED_SEGMENTS > 0);
+    BOOST_ASSERT(summary_array.begin() != summary_array.end());
+    std::string summary =
+        std::accumulate(std::next(summary_array.begin()), summary_array.end(),
+                        facade.GetNameForID(summary_array.front()),
+                        [&facade](std::string previous, const std::uint32_t name_id)
+                        {
+                            if (name_id != 0)
+                            {
+                                previous += ", " + facade.GetNameForID(name_id);
+                            }
+                            return previous;
+                        });
+
+    return RouteLeg{duration, distance, summary, {}};
+}
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
+
+#endif // ENGINE_GUIDANCE_SEGMENT_LIST_HPP_
diff --git a/include/engine/guidance/assemble_overview.hpp b/include/engine/guidance/assemble_overview.hpp
new file mode 100644
index 0000000..f801d6c
--- /dev/null
+++ b/include/engine/guidance/assemble_overview.hpp
@@ -0,0 +1,24 @@
+#ifndef ENGINE_GUIDANCE_ASSEMBLE_OVERVIEW_HPP
+#define ENGINE_GUIDANCE_ASSEMBLE_OVERVIEW_HPP
+
+#include "engine/guidance/leg_geometry.hpp"
+
+#include "util/coordinate.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+std::vector<util::Coordinate> assembleOverview(const std::vector<LegGeometry> &leg_geometries,
+                                               const bool use_simplification);
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
+
+#endif
diff --git a/include/engine/guidance/assemble_route.hpp b/include/engine/guidance/assemble_route.hpp
new file mode 100644
index 0000000..ff1c905
--- /dev/null
+++ b/include/engine/guidance/assemble_route.hpp
@@ -0,0 +1,22 @@
+#ifndef ENGINE_GUIDANCE_ASSEMBLE_ROUTE_HPP
+#define ENGINE_GUIDANCE_ASSEMBLE_ROUTE_HPP
+
+#include "engine/guidance/route_leg.hpp"
+#include "engine/guidance/route.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+Route assembleRoute(const std::vector<RouteLeg> &route_legs);
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
+
+#endif
diff --git a/include/engine/guidance/assemble_steps.hpp b/include/engine/guidance/assemble_steps.hpp
new file mode 100644
index 0000000..c6d19ee
--- /dev/null
+++ b/include/engine/guidance/assemble_steps.hpp
@@ -0,0 +1,157 @@
+#ifndef ENGINE_GUIDANCE_ASSEMBLE_STEPS_HPP_
+#define ENGINE_GUIDANCE_ASSEMBLE_STEPS_HPP_
+
+#include "engine/guidance/route_step.hpp"
+#include "engine/guidance/step_maneuver.hpp"
+#include "engine/guidance/leg_geometry.hpp"
+#include "engine/guidance/toolkit.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+#include "engine/internal_route_result.hpp"
+#include "engine/phantom_node.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/coordinate.hpp"
+#include "util/bearing.hpp"
+#include "extractor/travel_mode.hpp"
+
+#include <vector>
+#include <boost/optional.hpp>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+namespace detail
+{
+StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction,
+                                      const LegGeometry &leg_geometry,
+                                      const std::size_t segment_index);
+
+StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction,
+                                      const WaypointType waypoint_type,
+                                      const LegGeometry &leg_geometry);
+
+} // ns detail
+
+template <typename DataFacadeT>
+std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
+                                     const std::vector<PathData> &leg_data,
+                                     const LegGeometry &leg_geometry,
+                                     const PhantomNode &source_node,
+                                     const PhantomNode &target_node,
+                                     const bool source_traversed_in_reverse,
+                                     const bool target_traversed_in_reverse)
+{
+    const double constexpr ZERO_DURATION = 0., ZERO_DISTANCE = 0.;
+    const EdgeWeight source_duration =
+        source_traversed_in_reverse ? source_node.reverse_weight : source_node.forward_weight;
+    const auto source_mode = source_traversed_in_reverse ? source_node.backward_travel_mode
+                                                         : source_node.forward_travel_mode;
+
+    const EdgeWeight target_duration =
+        target_traversed_in_reverse ? target_node.reverse_weight : target_node.forward_weight;
+    const auto target_mode = target_traversed_in_reverse ? target_node.backward_travel_mode
+                                                         : target_node.forward_travel_mode;
+
+    const auto number_of_segments = leg_geometry.GetNumberOfSegments();
+
+    std::vector<RouteStep> steps;
+    steps.reserve(number_of_segments);
+
+    std::size_t segment_index = 0;
+    BOOST_ASSERT(leg_geometry.locations.size() >= 2);
+
+    if (leg_data.size() > 0)
+    {
+
+        StepManeuver maneuver = detail::stepManeuverFromGeometry(
+            extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Depart, leg_geometry);
+        maneuver.location = source_node.location;
+
+        // PathData saves the information we need of the segment _before_ the turn,
+        // but a RouteStep is with regard to the segment after the turn.
+        // We need to skip the first segment because it is already covered by the
+        // initial start of a route
+        int segment_duration = 0;
+        for (const auto &path_point : leg_data)
+        {
+            segment_duration += path_point.duration_until_turn;
+
+            // all changes to this check have to be matched with assemble_geometry
+            if (path_point.turn_instruction.type != extractor::guidance::TurnType::NoTurn)
+            {
+                BOOST_ASSERT(segment_duration >= 0);
+                const auto name = facade.GetNameForID(path_point.name_id);
+                const auto distance = leg_geometry.segment_distances[segment_index];
+                steps.push_back(RouteStep{path_point.name_id,
+                                          name,
+                                          segment_duration / 10.0,
+                                          distance,
+                                          path_point.travel_mode,
+                                          maneuver,
+                                          leg_geometry.FrontIndex(segment_index),
+                                          leg_geometry.BackIndex(segment_index) + 1});
+                maneuver = detail::stepManeuverFromGeometry(path_point.turn_instruction,
+                                                            leg_geometry, segment_index);
+                segment_index++;
+                segment_duration = 0;
+            }
+        }
+        const auto distance = leg_geometry.segment_distances[segment_index];
+        const int duration = segment_duration + target_duration;
+        BOOST_ASSERT(duration >= 0);
+        steps.push_back(RouteStep{target_node.name_id,
+                                  facade.GetNameForID(target_node.name_id),
+                                  duration / 10.,
+                                  distance,
+                                  target_mode,
+                                  maneuver,
+                                  leg_geometry.FrontIndex(segment_index),
+                                  leg_geometry.BackIndex(segment_index) + 1});
+    }
+    // In this case the source + target are on the same edge segment
+    else
+    {
+        BOOST_ASSERT(source_node.fwd_segment_position == target_node.fwd_segment_position);
+        //     s     t
+        // u-------------v
+        // |---| source_duration
+        // |---------| target_duration
+
+        StepManeuver maneuver = detail::stepManeuverFromGeometry(
+            extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Depart, leg_geometry);
+        int duration = target_duration - source_duration;
+        BOOST_ASSERT(duration >= 0);
+
+        steps.push_back(RouteStep{source_node.name_id,
+                                  facade.GetNameForID(source_node.name_id),
+                                  duration / 10.,
+                                  leg_geometry.segment_distances[segment_index],
+                                  source_mode,
+                                  std::move(maneuver),
+                                  leg_geometry.FrontIndex(segment_index),
+                                  leg_geometry.BackIndex(segment_index) + 1});
+    }
+
+    BOOST_ASSERT(segment_index == number_of_segments - 1);
+    // This step has length zero, the only reason we need it is the target location
+    auto final_maneuver = detail::stepManeuverFromGeometry(
+        extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Arrive, leg_geometry);
+    steps.push_back(RouteStep{target_node.name_id,
+                              facade.GetNameForID(target_node.name_id),
+                              ZERO_DURATION,
+                              ZERO_DISTANCE,
+                              target_mode,
+                              final_maneuver,
+                              leg_geometry.locations.size(),
+                              leg_geometry.locations.size()});
+
+    return steps;
+}
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
+
+#endif // ENGINE_GUIDANCE_SEGMENT_LIST_HPP_
diff --git a/include/engine/guidance/leg_geometry.hpp b/include/engine/guidance/leg_geometry.hpp
new file mode 100644
index 0000000..622e40f
--- /dev/null
+++ b/include/engine/guidance/leg_geometry.hpp
@@ -0,0 +1,54 @@
+#ifndef ENGINE_GUIDANCE_LEG_GEOMETRY_HPP
+#define ENGINE_GUIDANCE_LEG_GEOMETRY_HPP
+
+#include "util/coordinate.hpp"
+#include "util/integer_range.hpp"
+
+#include <boost/assert.hpp>
+
+#include <cstddef>
+
+#include <vector>
+#include <cstdlib>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+// locations 0---1---2-...-n-1---n
+// turns     s       x      y    t
+// segment   |   0   |  1   | 2  | sentinel
+// offsets       0      2    n-1     n
+struct LegGeometry
+{
+    std::vector<util::Coordinate> locations;
+    // segment_offset[i] .. segment_offset[i+1] (inclusive)
+    // contains the geometry of segment i
+    std::vector<std::size_t> segment_offsets;
+    // length of the segment in meters
+    std::vector<double> segment_distances;
+
+    std::size_t FrontIndex(std::size_t segment_index) const
+    {
+        return segment_offsets[segment_index];
+    }
+
+    std::size_t BackIndex(std::size_t segment_index) const
+    {
+        return segment_offsets[segment_index + 1];
+    }
+
+    std::size_t GetNumberOfSegments() const
+    {
+        BOOST_ASSERT(segment_offsets.size() > 0);
+        return segment_offsets.size() - 1;
+    }
+};
+}
+}
+}
+
+#endif
diff --git a/include/engine/guidance/post_processing.hpp b/include/engine/guidance/post_processing.hpp
new file mode 100644
index 0000000..32f6ee5
--- /dev/null
+++ b/include/engine/guidance/post_processing.hpp
@@ -0,0 +1,44 @@
+#ifndef ENGINE_GUIDANCE_POST_PROCESSING_HPP
+#define ENGINE_GUIDANCE_POST_PROCESSING_HPP
+
+#include "engine/phantom_node.hpp"
+#include "engine/guidance/route_step.hpp"
+#include "engine/guidance/leg_geometry.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+// passed as none-reference to modify in-place and move out again
+std::vector<RouteStep> postProcess(std::vector<RouteStep> steps);
+
+// trim initial/final segment of very short length.
+// This function uses in/out parameter passing to modify both steps and geometry in place.
+// We use this method since both steps and geometry are closely coupled logically but
+// are not coupled in the same way in the background. To avoid the additional overhead
+// of introducing intermediate structions, we resolve to the in/out scheme at this point.
+void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry);
+
+// assign relative locations to depart/arrive instructions
+std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
+                                               const LegGeometry &geometry,
+                                               const PhantomNode &source_node,
+                                               const PhantomNode &target_node);
+
+// postProcess will break the connection between the leg geometry
+// for which a segment is supposed to represent exactly the coordinates
+// between routing maneuvers and the route steps itself.
+// If required, we can get both in sync again using this function.
+// Move in LegGeometry for modification in place.
+LegGeometry resyncGeometry(LegGeometry leg_geometry, const std::vector<RouteStep> &steps);
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
+
+#endif // ENGINE_GUIDANCE_POST_PROCESSING_HPP
diff --git a/include/engine/guidance/route.hpp b/include/engine/guidance/route.hpp
new file mode 100644
index 0000000..bde2d5f
--- /dev/null
+++ b/include/engine/guidance/route.hpp
@@ -0,0 +1,20 @@
+#ifndef ROUTE_HPP
+#define ROUTE_HPP
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+struct Route
+{
+    double duration;
+    double distance;
+};
+}
+}
+}
+
+#endif
diff --git a/include/engine/guidance/route_leg.hpp b/include/engine/guidance/route_leg.hpp
new file mode 100644
index 0000000..5ecca4f
--- /dev/null
+++ b/include/engine/guidance/route_leg.hpp
@@ -0,0 +1,29 @@
+#ifndef ROUTE_LEG_HPP
+#define ROUTE_LEG_HPP
+
+#include "engine/guidance/route_step.hpp"
+
+#include <boost/optional.hpp>
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+struct RouteLeg
+{
+    double duration;
+    double distance;
+    std::string summary;
+    std::vector<RouteStep> steps;
+};
+}
+}
+}
+
+#endif
diff --git a/include/engine/guidance/route_step.hpp b/include/engine/guidance/route_step.hpp
new file mode 100644
index 0000000..1a53579
--- /dev/null
+++ b/include/engine/guidance/route_step.hpp
@@ -0,0 +1,40 @@
+#ifndef ROUTE_STEP_HPP
+#define ROUTE_STEP_HPP
+
+#include "extractor/travel_mode.hpp"
+#include "engine/guidance/step_maneuver.hpp"
+
+#include <cstddef>
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+// Given the following turn from a,b to b,c over b:
+//  a --> b --> c
+// this struct saves the information of the segment b,c.
+// Notable exceptions are Departure and Arrival steps.
+// Departue: s --> a --> b. Represents the segment s,a with location being s.
+// Arrive: a --> b --> t. The segment (b,t) is already covered by the previous segment.
+struct RouteStep
+{
+    unsigned name_id;
+    std::string name;
+    double duration;
+    double distance;
+    extractor::TravelMode mode;
+    StepManeuver maneuver;
+    // indices into the locations array stored the LegGeometry
+    std::size_t geometry_begin;
+    std::size_t geometry_end;
+};
+}
+}
+}
+
+#endif
diff --git a/include/engine/guidance/step_maneuver.hpp b/include/engine/guidance/step_maneuver.hpp
new file mode 100644
index 0000000..5ae70f9
--- /dev/null
+++ b/include/engine/guidance/step_maneuver.hpp
@@ -0,0 +1,45 @@
+#ifndef ENGINE_GUIDANCE_STEP_MANEUVER_HPP
+#define ENGINE_GUIDANCE_STEP_MANEUVER_HPP
+
+#include "util/coordinate.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+
+#include <cstdint>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+enum class WaypointType : std::uint8_t
+{
+    None,
+    Arrive,
+    Depart,
+};
+
+//A represenetation of intermediate intersections
+struct IntermediateIntersection
+{
+    double duration;
+    double distance;
+    util::Coordinate location;
+};
+
+struct StepManeuver
+{
+    util::Coordinate location;
+    double bearing_before;
+    double bearing_after;
+    extractor::guidance::TurnInstruction instruction;
+    WaypointType waypoint_type;
+    unsigned exit;
+    std::vector<IntermediateIntersection> intersections;
+};
+} // namespace guidance
+} // namespace engine
+} // namespace osrmn
+#endif
diff --git a/include/engine/guidance/toolkit.hpp b/include/engine/guidance/toolkit.hpp
new file mode 100644
index 0000000..e9cbcf5
--- /dev/null
+++ b/include/engine/guidance/toolkit.hpp
@@ -0,0 +1,63 @@
+#ifndef OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_
+#define OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_
+
+#include "extractor/guidance/turn_instruction.hpp"
+#include "util/bearing.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+// Silent Turn Instructions are not to be mentioned to the outside world but
+inline bool isSilent(const extractor::guidance::TurnInstruction instruction)
+{
+    return instruction.type == extractor::guidance::TurnType::NoTurn ||
+           instruction.type == extractor::guidance::TurnType::Suppressed ||
+           instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
+}
+
+inline bool entersRoundabout(const extractor::guidance::TurnInstruction instruction)
+{
+    return (instruction.type == extractor::guidance::TurnType::EnterRoundabout ||
+            instruction.type == extractor::guidance::TurnType::EnterRotary ||
+            instruction.type == extractor::guidance::TurnType::EnterRoundaboutAtExit ||
+            instruction.type == extractor::guidance::TurnType::EnterRotaryAtExit ||
+            instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
+            instruction.type == extractor::guidance::TurnType::EnterAndExitRotary);
+}
+
+inline bool leavesRoundabout(const extractor::guidance::TurnInstruction instruction)
+{
+    return (instruction.type == extractor::guidance::TurnType::ExitRoundabout ||
+            instruction.type == extractor::guidance::TurnType::ExitRotary ||
+            instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
+            instruction.type == extractor::guidance::TurnType::EnterAndExitRotary);
+}
+
+inline bool staysOnRoundabout(const extractor::guidance::TurnInstruction instruction)
+{
+    return instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
+}
+
+inline extractor::guidance::DirectionModifier angleToDirectionModifier(const double bearing)
+{
+    if (bearing < 135)
+    {
+        return extractor::guidance::DirectionModifier::Right;
+    }
+
+    if (bearing <= 225)
+    {
+        return extractor::guidance::DirectionModifier::Straight;
+    }
+    return extractor::guidance::DirectionModifier::Left;
+}
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
+
+#endif /* OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_ */
diff --git a/include/engine/hint.hpp b/include/engine/hint.hpp
new file mode 100644
index 0000000..0ecaff6
--- /dev/null
+++ b/include/engine/hint.hpp
@@ -0,0 +1,81 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+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 ENGINE_HINT_HPP
+#define ENGINE_HINT_HPP
+
+#include "engine/phantom_node.hpp"
+
+#include "util/coordinate.hpp"
+
+#include <string>
+#include <cstdint>
+#include <iosfwd>
+
+namespace osrm
+{
+namespace engine
+{
+
+// Fwd. decls.
+namespace datafacade
+{
+class BaseDataFacade;
+}
+
+// Is returned as a temporary identifier for snapped coodinates
+struct Hint
+{
+    PhantomNode phantom;
+    std::uint32_t data_checksum;
+
+    bool IsValid(const util::Coordinate new_input_coordinates,
+                 const datafacade::BaseDataFacade &facade) const;
+
+    std::string ToBase64() const;
+    static Hint FromBase64(const std::string &base64Hint);
+
+    friend bool operator==(const Hint &, const Hint &);
+    friend std::ostream &operator<<(std::ostream &, const Hint &);
+};
+
+#ifndef _MSC_VER
+static_assert(sizeof(Hint) == 60 + 4, "Hint is bigger than expected");
+constexpr std::size_t ENCODED_HINT_SIZE = 88;
+static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint),
+              "ENCODED_HINT_SIZE does not match size of Hint");
+#else
+// PhantomNode is bigger under windows because MSVC does not support bit packing
+static_assert(sizeof(Hint) == 64 + 4, "Hint is bigger than expected");
+constexpr std::size_t ENCODED_HINT_SIZE = 92;
+static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint),
+              "ENCODED_HINT_SIZE does not match size of Hint");
+#endif
+}
+}
+
+#endif
diff --git a/include/engine/internal_route_result.hpp b/include/engine/internal_route_result.hpp
new file mode 100644
index 0000000..d1666e1
--- /dev/null
+++ b/include/engine/internal_route_result.hpp
@@ -0,0 +1,63 @@
+#ifndef RAW_ROUTE_DATA_H
+#define RAW_ROUTE_DATA_H
+
+#include "engine/phantom_node.hpp"
+#include "extractor/travel_mode.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+#include "util/typedefs.hpp"
+
+#include "osrm/coordinate.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+
+const constexpr unsigned INVALID_EXIT_NR = 0;
+
+struct PathData
+{
+    // id of via node of the turn
+    NodeID turn_via_node;
+    // name of the street that leads to the turn
+    unsigned name_id;
+    // duration that is traveled on the segment until the turn is reached
+    EdgeWeight duration_until_turn;
+    // instruction to execute at the turn
+    extractor::guidance::TurnInstruction turn_instruction;
+    // travel mode of the street that leads to the turn
+    extractor::TravelMode travel_mode : 4;
+};
+
+struct InternalRouteResult
+{
+    std::vector<std::vector<PathData>> unpacked_path_segments;
+    std::vector<PathData> unpacked_alternative;
+    std::vector<PhantomNodes> segment_end_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;
+    int shortest_path_length;
+    int alternative_path_length;
+
+    bool is_valid() const { return INVALID_EDGE_WEIGHT != shortest_path_length; }
+
+    bool has_alternative() const { return INVALID_EDGE_WEIGHT != alternative_path_length; }
+
+    bool is_via_leg(const std::size_t leg) const
+    {
+        return (leg != unpacked_path_segments.size() - 1);
+    }
+
+    InternalRouteResult()
+        : shortest_path_length(INVALID_EDGE_WEIGHT), alternative_path_length(INVALID_EDGE_WEIGHT)
+    {
+    }
+};
+}
+}
+
+#endif // RAW_ROUTE_DATA_H
diff --git a/algorithms/bayes_classifier.hpp b/include/engine/map_matching/bayes_classifier.hpp
similarity index 63%
rename from algorithms/bayes_classifier.hpp
rename to include/engine/map_matching/bayes_classifier.hpp
index ea300c1..c77fa84 100644
--- a/algorithms/bayes_classifier.hpp
+++ b/include/engine/map_matching/bayes_classifier.hpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 BAYES_CLASSIFIER_HPP
 #define BAYES_CLASSIFIER_HPP
 
@@ -33,6 +6,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <vector>
 #include <utility>
 
+#include <boost/math/constants/constants.hpp>
+
+namespace osrm
+{
+namespace engine
+{
+namespace map_matching
+{
+
 struct NormalDistribution
 {
     NormalDistribution(const double mean, const double standard_deviation)
@@ -40,11 +22,13 @@ struct NormalDistribution
     {
     }
 
-    // FIXME implement log-probability version since its faster
+    // FIXME implement log-probability version since it's faster
     double density_function(const double val) const
     {
+        using namespace boost::math::constants;
+
         const double x = val - mean;
-        return 1.0 / (std::sqrt(2. * M_PI) * standard_deviation) *
+        return 1.0 / (std::sqrt(two_pi<double>()) * standard_deviation) *
                std::exp(-x * x / (standard_deviation * standard_deviation));
     }
 
@@ -59,7 +43,7 @@ struct LaplaceDistribution
     {
     }
 
-    // FIXME implement log-probability version since its faster
+    // FIXME implement log-probability version since it's faster
     double density_function(const double val) const
     {
         const double x = std::abs(val - location);
@@ -114,5 +98,8 @@ class BayesClassifier
     double positive_apriori_probability;
     double negative_apriori_probability;
 };
+}
+}
+}
 
 #endif // BAYES_CLASSIFIER_HPP
diff --git a/data_structures/hidden_markov_model.hpp b/include/engine/map_matching/hidden_markov_model.hpp
similarity index 50%
rename from data_structures/hidden_markov_model.hpp
rename to include/engine/map_matching/hidden_markov_model.hpp
index e3efcea..303a835 100644
--- a/data_structures/hidden_markov_model.hpp
+++ b/include/engine/map_matching/hidden_markov_model.hpp
@@ -1,36 +1,10 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 HIDDEN_MARKOV_MODEL
 #define HIDDEN_MARKOV_MODEL
 
-#include "../util/integer_range.hpp"
+#include "util/integer_range.hpp"
 
 #include <boost/assert.hpp>
+#include <boost/math/constants/constants.hpp>
 
 #include <cmath>
 
@@ -39,14 +13,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace osrm
 {
-namespace matching
+namespace engine
 {
-static const double log_2_pi = std::log(2. * M_PI);
+namespace map_matching
+{
+
+static const double log_2_pi = std::log(2. * boost::math::constants::pi<double>());
 static const double IMPOSSIBLE_LOG_PROB = -std::numeric_limits<double>::infinity();
 static const double MINIMAL_LOG_PROB = std::numeric_limits<double>::lowest();
 static const std::size_t INVALID_STATE = std::numeric_limits<std::size_t>::max();
-} // namespace matching
-} // namespace osrm
 
 // closures to precompute log -> only simple floating point operations
 struct EmissionLogProbability
@@ -60,8 +35,7 @@ struct EmissionLogProbability
 
     double operator()(const double distance) const
     {
-        return -0.5 * (osrm::matching::log_2_pi + (distance / sigma_z) * (distance / sigma_z)) -
-               log_sigma_z;
+        return -0.5 * (log_2_pi + (distance / sigma_z) * (distance / sigma_z)) - log_sigma_z;
     }
 };
 
@@ -78,35 +52,32 @@ template <class CandidateLists> struct HiddenMarkovModel
 {
     std::vector<std::vector<double>> viterbi;
     std::vector<std::vector<std::pair<unsigned, unsigned>>> parents;
-    std::vector<std::vector<float>> path_lengths;
+    std::vector<std::vector<float>> path_distances;
     std::vector<std::vector<bool>> pruned;
-    std::vector<std::vector<bool>> suspicious;
     std::vector<bool> breakage;
 
     const CandidateLists &candidates_list;
-    const EmissionLogProbability &emission_log_probability;
+    const std::vector<std::vector<double>> &emission_log_probabilities;
 
     HiddenMarkovModel(const CandidateLists &candidates_list,
-                      const EmissionLogProbability &emission_log_probability)
+                      const std::vector<std::vector<double>> &emission_log_probabilities)
         : breakage(candidates_list.size()), candidates_list(candidates_list),
-          emission_log_probability(emission_log_probability)
+          emission_log_probabilities(emission_log_probabilities)
     {
         viterbi.resize(candidates_list.size());
         parents.resize(candidates_list.size());
-        path_lengths.resize(candidates_list.size());
-        suspicious.resize(candidates_list.size());
+        path_distances.resize(candidates_list.size());
         pruned.resize(candidates_list.size());
         breakage.resize(candidates_list.size());
-        for (const auto i : osrm::irange<std::size_t>(0u, candidates_list.size()))
+        for (const auto i : util::irange<std::size_t>(0u, candidates_list.size()))
         {
-            const auto& num_candidates = candidates_list[i].size();
+            const auto &num_candidates = candidates_list[i].size();
             // add empty vectors
             if (num_candidates > 0)
             {
                 viterbi[i].resize(num_candidates);
                 parents[i].resize(num_candidates);
-                path_lengths[i].resize(num_candidates);
-                suspicious[i].resize(num_candidates);
+                path_distances[i].resize(num_candidates);
                 pruned[i].resize(num_candidates);
             }
         }
@@ -116,15 +87,14 @@ template <class CandidateLists> struct HiddenMarkovModel
 
     void clear(std::size_t initial_timestamp)
     {
-        BOOST_ASSERT(viterbi.size() == parents.size() && parents.size() == path_lengths.size() &&
-                     path_lengths.size() == pruned.size() && pruned.size() == breakage.size());
+        BOOST_ASSERT(viterbi.size() == parents.size() && parents.size() == path_distances.size() &&
+                     path_distances.size() == pruned.size() && pruned.size() == breakage.size());
 
-        for (const auto t : osrm::irange(initial_timestamp, viterbi.size()))
+        for (const auto t : util::irange(initial_timestamp, viterbi.size()))
         {
-            std::fill(viterbi[t].begin(), viterbi[t].end(), osrm::matching::IMPOSSIBLE_LOG_PROB);
+            std::fill(viterbi[t].begin(), viterbi[t].end(), IMPOSSIBLE_LOG_PROB);
             std::fill(parents[t].begin(), parents[t].end(), std::make_pair(0u, 0u));
-            std::fill(path_lengths[t].begin(), path_lengths[t].end(), 0);
-            std::fill(suspicious[t].begin(), suspicious[t].end(), true);
+            std::fill(path_distances[t].begin(), path_distances[t].end(), 0);
             std::fill(pruned[t].begin(), pruned[t].end(), true);
         }
         std::fill(breakage.begin() + initial_timestamp, breakage.end(), true);
@@ -137,14 +107,11 @@ template <class CandidateLists> struct HiddenMarkovModel
         {
             BOOST_ASSERT(initial_timestamp < num_points);
 
-            for (const auto s : osrm::irange<std::size_t>(0u, viterbi[initial_timestamp].size()))
+            for (const auto s : util::irange<std::size_t>(0u, viterbi[initial_timestamp].size()))
             {
-                viterbi[initial_timestamp][s] =
-                    emission_log_probability(candidates_list[initial_timestamp][s].distance);
+                viterbi[initial_timestamp][s] = emission_log_probabilities[initial_timestamp][s];
                 parents[initial_timestamp][s] = std::make_pair(initial_timestamp, s);
-                pruned[initial_timestamp][s] =
-                    viterbi[initial_timestamp][s] < osrm::matching::MINIMAL_LOG_PROB;
-                suspicious[initial_timestamp][s] = false;
+                pruned[initial_timestamp][s] = viterbi[initial_timestamp][s] < MINIMAL_LOG_PROB;
 
                 breakage[initial_timestamp] =
                     breakage[initial_timestamp] && pruned[initial_timestamp][s];
@@ -155,7 +122,7 @@ template <class CandidateLists> struct HiddenMarkovModel
 
         if (initial_timestamp >= num_points)
         {
-            return osrm::matching::INVALID_STATE;
+            return INVALID_STATE;
         }
 
         BOOST_ASSERT(initial_timestamp > 0);
@@ -166,5 +133,8 @@ template <class CandidateLists> struct HiddenMarkovModel
         return initial_timestamp;
     }
 };
+}
+}
+}
 
 #endif // HIDDEN_MARKOV_MODEL
diff --git a/include/engine/map_matching/matching_confidence.hpp b/include/engine/map_matching/matching_confidence.hpp
new file mode 100644
index 0000000..03613b0
--- /dev/null
+++ b/include/engine/map_matching/matching_confidence.hpp
@@ -0,0 +1,58 @@
+#ifndef ENGINE_MAP_MATCHING_CONFIDENCE_HPP
+#define ENGINE_MAP_MATCHING_CONFIDENCE_HPP
+
+#include "engine/map_matching/bayes_classifier.hpp"
+
+#include <cmath>
+
+namespace osrm
+{
+namespace engine
+{
+namespace map_matching
+{
+
+struct MatchingConfidence
+{
+  private:
+    using ClassifierT = BayesClassifier<LaplaceDistribution, LaplaceDistribution, double>;
+    using TraceClassification = ClassifierT::ClassificationT;
+
+  public:
+    MatchingConfidence()
+        : // the values were derived from fitting a laplace distribution
+          // to the values of manually classified traces
+          classifier(map_matching::LaplaceDistribution(0.005986, 0.016646),
+                     map_matching::LaplaceDistribution(0.054385, 0.458432),
+                     0.696774) // valid apriori probability
+    {
+    }
+
+    double operator()(const float trace_length, const float matched_length) const
+    {
+        const double distance_feature = -std::log(trace_length) + std::log(matched_length);
+
+        // matched to the same point
+        if (!std::isfinite(distance_feature))
+        {
+            return 0;
+        }
+
+        const auto label_with_confidence = classifier.classify(distance_feature);
+        if (label_with_confidence.first == ClassifierT::ClassLabel::POSITIVE)
+        {
+            return label_with_confidence.second;
+        }
+
+        BOOST_ASSERT(label_with_confidence.first == ClassifierT::ClassLabel::NEGATIVE);
+        return 1 - label_with_confidence.second;
+    }
+
+  private:
+    ClassifierT classifier;
+};
+}
+}
+}
+
+#endif
diff --git a/include/engine/map_matching/sub_matching.hpp b/include/engine/map_matching/sub_matching.hpp
new file mode 100644
index 0000000..22c1803
--- /dev/null
+++ b/include/engine/map_matching/sub_matching.hpp
@@ -0,0 +1,25 @@
+#ifndef MAP_MATCHING_SUB_MATCHING_HPP
+#define MAP_MATCHING_SUB_MATCHING_HPP
+
+#include "engine/phantom_node.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace map_matching
+{
+
+struct SubMatching
+{
+    std::vector<PhantomNode> nodes;
+    std::vector<unsigned> indices;
+    double confidence;
+};
+}
+}
+}
+
+#endif
diff --git a/include/engine/phantom_node.hpp b/include/engine/phantom_node.hpp
new file mode 100644
index 0000000..244276c
--- /dev/null
+++ b/include/engine/phantom_node.hpp
@@ -0,0 +1,214 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+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 "extractor/travel_mode.hpp"
+#include "util/typedefs.hpp"
+
+#include "util/coordinate.hpp"
+
+#include <boost/assert.hpp>
+
+#include <iostream>
+#include <utility>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+
+struct PhantomNode
+{
+    PhantomNode(SegmentID forward_segment_id,
+                SegmentID reverse_segment_id,
+                unsigned name_id,
+                int forward_weight,
+                int reverse_weight,
+                int forward_offset,
+                int reverse_offset,
+                unsigned forward_packed_geometry_id_,
+                unsigned reverse_packed_geometry_id_,
+                bool is_tiny_component,
+                unsigned component_id,
+                util::Coordinate location,
+                util::Coordinate input_location,
+                unsigned short fwd_segment_position,
+                extractor::TravelMode forward_travel_mode,
+                extractor::TravelMode backward_travel_mode)
+        : forward_segment_id(forward_segment_id), reverse_segment_id(reverse_segment_id),
+          name_id(name_id), forward_weight(forward_weight), reverse_weight(reverse_weight),
+          forward_offset(forward_offset), reverse_offset(reverse_offset),
+          forward_packed_geometry_id(forward_packed_geometry_id_),
+          reverse_packed_geometry_id(reverse_packed_geometry_id_),
+          component{component_id, is_tiny_component}, location(std::move(location)),
+          input_location(std::move(input_location)), fwd_segment_position(fwd_segment_position),
+          forward_travel_mode(forward_travel_mode), backward_travel_mode(backward_travel_mode)
+    {
+    }
+
+    PhantomNode()
+        : forward_segment_id{SPECIAL_SEGMENTID, false},
+          reverse_segment_id{SPECIAL_SEGMENTID, false},
+          name_id(std::numeric_limits<unsigned>::max()), forward_weight(INVALID_EDGE_WEIGHT),
+          reverse_weight(INVALID_EDGE_WEIGHT), forward_offset(0), reverse_offset(0),
+          forward_packed_geometry_id(SPECIAL_EDGEID), reverse_packed_geometry_id(SPECIAL_EDGEID),
+          component{INVALID_COMPONENTID, false}, fwd_segment_position(0),
+          forward_travel_mode(TRAVEL_MODE_INACCESSIBLE),
+          backward_travel_mode(TRAVEL_MODE_INACCESSIBLE)
+    {
+    }
+
+    int GetForwardWeightPlusOffset() const
+    {
+        BOOST_ASSERT(forward_segment_id.enabled);
+        return forward_offset + forward_weight;
+    }
+
+    int GetReverseWeightPlusOffset() const
+    {
+        BOOST_ASSERT(reverse_segment_id.enabled);
+        return reverse_offset + reverse_weight;
+    }
+
+    bool IsBidirected() const { return forward_segment_id.enabled && reverse_segment_id.enabled; }
+
+    bool IsValid(const unsigned number_of_nodes) const
+    {
+        return location.IsValid() && ((forward_segment_id.id < number_of_nodes) ||
+                                      (reverse_segment_id.id < number_of_nodes)) &&
+               ((forward_weight != INVALID_EDGE_WEIGHT) ||
+                (reverse_weight != INVALID_EDGE_WEIGHT)) &&
+               (component.id != INVALID_COMPONENTID) && (name_id != INVALID_NAMEID);
+    }
+
+    bool IsValid(const unsigned number_of_nodes, const util::Coordinate queried_coordinate) const
+    {
+        return queried_coordinate == input_location && IsValid(number_of_nodes);
+    }
+
+    bool IsValid() const { return location.IsValid() && (name_id != INVALID_NAMEID); }
+
+    bool operator==(const PhantomNode &other) const { return location == other.location; }
+
+    template <class OtherT>
+    explicit PhantomNode(const OtherT &other,
+                         int forward_weight_,
+                         int forward_offset_,
+                         int reverse_weight_,
+                         int reverse_offset_,
+                         const util::Coordinate location_,
+                         const util::Coordinate input_location_)
+        : forward_segment_id{other.forward_segment_id},
+          reverse_segment_id{other.reverse_segment_id}, name_id{other.name_id},
+          forward_weight{forward_weight_}, reverse_weight{reverse_weight_},
+          forward_offset{forward_offset_}, reverse_offset{reverse_offset_},
+          forward_packed_geometry_id{other.forward_packed_geometry_id},
+          reverse_packed_geometry_id{other.reverse_packed_geometry_id},
+          component{other.component.id, other.component.is_tiny}, location{location_},
+          input_location{input_location_}, fwd_segment_position{other.fwd_segment_position},
+          forward_travel_mode{other.forward_travel_mode},
+          backward_travel_mode{other.backward_travel_mode}
+    {
+    }
+
+    SegmentID forward_segment_id;
+    SegmentID reverse_segment_id;
+    unsigned name_id;
+    int forward_weight;
+    int reverse_weight;
+    int forward_offset;
+    int reverse_offset;
+    unsigned forward_packed_geometry_id;
+    unsigned reverse_packed_geometry_id;
+    struct ComponentType
+    {
+        uint32_t id : 31;
+        bool is_tiny : 1;
+    } component;
+// bit-fields are broken on Windows
+#ifndef _MSC_VER
+    static_assert(sizeof(ComponentType) == 4, "ComponentType needs to be 4 bytes big");
+#endif
+    util::Coordinate location;
+    util::Coordinate input_location;
+    unsigned short fwd_segment_position;
+    // note 4 bits would suffice for each,
+    // but the saved byte would be padding anyway
+    extractor::TravelMode forward_travel_mode;
+    extractor::TravelMode backward_travel_mode;
+};
+
+#ifndef _MSC_VER
+static_assert(sizeof(PhantomNode) == 60, "PhantomNode has more padding then expected");
+#else
+static_assert(sizeof(PhantomNode) == 64, "PhantomNode has more padding then expected");
+#endif
+
+using PhantomNodePair = std::pair<PhantomNode, PhantomNode>;
+
+struct PhantomNodeWithDistance
+{
+    PhantomNode phantom_node;
+    double distance;
+};
+
+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_segment_id.id << ", "
+        << "node2: " << pn.reverse_segment_id.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 << ", "
+        << "fwd_geom: " << pn.forward_packed_geometry_id << ", "
+        << "rev_geom: " << pn.reverse_packed_geometry_id << ", "
+        << "comp: " << pn.component.is_tiny << " / " << pn.component.id << ", "
+        << "pos: " << pn.fwd_segment_position << ", "
+        << "loc: " << pn.location;
+    return out;
+}
+}
+}
+
+#endif // PHANTOM_NODES_H
diff --git a/include/engine/plugins/match.hpp b/include/engine/plugins/match.hpp
new file mode 100644
index 0000000..57f556a
--- /dev/null
+++ b/include/engine/plugins/match.hpp
@@ -0,0 +1,48 @@
+#ifndef MATCH_HPP
+#define MATCH_HPP
+
+#include "engine/plugins/plugin_base.hpp"
+#include "engine/api/match_parameters.hpp"
+
+#include "engine/map_matching/bayes_classifier.hpp"
+#include "engine/routing_algorithms/map_matching.hpp"
+#include "engine/routing_algorithms/shortest_path.hpp"
+#include "util/json_util.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+class MatchPlugin : public BasePlugin
+{
+  public:
+    using SubMatching = map_matching::SubMatching;
+    using SubMatchingList = routing_algorithms::SubMatchingList;
+    using CandidateLists = routing_algorithms::CandidateLists;
+    static const constexpr double DEFAULT_GPS_PRECISION = 5;
+    static const constexpr double RADIUS_MULTIPLIER = 3;
+
+    MatchPlugin(datafacade::BaseDataFacade &facade_, const int max_locations_map_matching)
+        : BasePlugin(facade_), map_matching(&facade_, heaps, DEFAULT_GPS_PRECISION),
+          shortest_path(&facade_, heaps), max_locations_map_matching(max_locations_map_matching)
+    {
+    }
+
+    Status HandleRequest(const api::MatchParameters &parameters, util::json::Object &json_result);
+
+  private:
+    SearchEngineData heaps;
+    routing_algorithms::MapMatching<datafacade::BaseDataFacade> map_matching;
+    routing_algorithms::ShortestPathRouting<datafacade::BaseDataFacade> shortest_path;
+    int max_locations_map_matching;
+};
+}
+}
+}
+
+#endif // MATCH_HPP
diff --git a/include/engine/plugins/nearest.hpp b/include/engine/plugins/nearest.hpp
new file mode 100644
index 0000000..103b789
--- /dev/null
+++ b/include/engine/plugins/nearest.hpp
@@ -0,0 +1,26 @@
+#ifndef NEAREST_HPP
+#define NEAREST_HPP
+
+#include "engine/plugins/plugin_base.hpp"
+#include "engine/api/nearest_parameters.hpp"
+#include "osrm/json_container.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+class NearestPlugin final : public BasePlugin
+{
+  public:
+    explicit NearestPlugin(datafacade::BaseDataFacade &facade);
+
+    Status HandleRequest(const api::NearestParameters &params, util::json::Object &result);
+};
+}
+}
+}
+
+#endif /* NEAREST_HPP */
diff --git a/include/engine/plugins/plugin_base.hpp b/include/engine/plugins/plugin_base.hpp
new file mode 100644
index 0000000..aec9dd0
--- /dev/null
+++ b/include/engine/plugins/plugin_base.hpp
@@ -0,0 +1,284 @@
+#ifndef BASE_PLUGIN_HPP
+#define BASE_PLUGIN_HPP
+
+#include "engine/datafacade/datafacade_base.hpp"
+#include "engine/api/base_parameters.hpp"
+#include "engine/phantom_node.hpp"
+#include "engine/status.hpp"
+
+#include "util/coordinate.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/json_container.hpp"
+#include "util/integer_range.hpp"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+class BasePlugin
+{
+  protected:
+    datafacade::BaseDataFacade &facade;
+    BasePlugin(datafacade::BaseDataFacade &facade_) : facade(facade_) {}
+
+    bool CheckAllCoordinates(const std::vector<util::Coordinate> &coordinates)
+    {
+        return !std::any_of(std::begin(coordinates), std::end(coordinates),
+                            [](const util::Coordinate coordinate)
+                            {
+                                return !coordinate.IsValid();
+                            });
+    }
+
+    Status Error(const std::string &code,
+                 const std::string &message,
+                 util::json::Object &json_result) const
+    {
+        json_result.values["code"] = code;
+        json_result.values["message"] = message;
+        return Status::Error;
+    }
+
+    // Decides whether to use the phantom node from a big or small component if both are found.
+    // Returns true if all phantom nodes are in the same component after snapping.
+    std::vector<PhantomNode>
+    SnapPhantomNodes(const std::vector<PhantomNodePair> &phantom_node_pair_list) const
+    {
+        const auto check_component_id_is_tiny =
+            [](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
+        {
+            return phantom_pair.first.component.is_tiny;
+        };
+
+        // are all phantoms from a tiny cc?
+        const auto check_all_in_same_component =
+            [](const std::vector<std::pair<PhantomNode, PhantomNode>> &nodes)
+        {
+            const auto component_id = nodes.front().first.component.id;
+
+            return std::all_of(std::begin(nodes), std::end(nodes),
+                               [component_id](const PhantomNodePair &phantom_pair)
+                               {
+                                   return component_id == phantom_pair.first.component.id;
+                               });
+        };
+
+        const auto fallback_to_big_component =
+            [](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
+        {
+            if (phantom_pair.first.component.is_tiny && phantom_pair.second.IsValid() &&
+                !phantom_pair.second.component.is_tiny)
+            {
+                return phantom_pair.second;
+            }
+            return phantom_pair.first;
+        };
+
+        const auto use_closed_phantom = [](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
+        {
+            return phantom_pair.first;
+        };
+
+        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);
+        auto all_in_same_component = check_all_in_same_component(phantom_node_pair_list);
+
+        std::vector<PhantomNode> snapped_phantoms;
+        snapped_phantoms.reserve(phantom_node_pair_list.size());
+
+        // The only case we don't snap to the big component if all phantoms are in the same small
+        // component
+        if (every_phantom_is_in_tiny_cc && all_in_same_component)
+        {
+            std::transform(phantom_node_pair_list.begin(), phantom_node_pair_list.end(),
+                           std::back_inserter(snapped_phantoms), use_closed_phantom);
+        }
+        else
+        {
+            std::transform(phantom_node_pair_list.begin(), phantom_node_pair_list.end(),
+                           std::back_inserter(snapped_phantoms), fallback_to_big_component);
+        }
+
+        return snapped_phantoms;
+    }
+
+    // Falls back to default_radius for non-set radii
+    std::vector<std::vector<PhantomNodeWithDistance>>
+    GetPhantomNodesInRange(const api::BaseParameters &parameters,
+                           const std::vector<double> radiuses) const
+    {
+        std::vector<std::vector<PhantomNodeWithDistance>> phantom_nodes(
+            parameters.coordinates.size());
+        BOOST_ASSERT(radiuses.size() == parameters.coordinates.size());
+
+        const bool use_hints = !parameters.hints.empty();
+        const bool use_bearings = !parameters.bearings.empty();
+
+        for (const auto i : util::irange<std::size_t>(0, parameters.coordinates.size()))
+        {
+            if (use_hints && parameters.hints[i] &&
+                parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
+            {
+                phantom_nodes[i].push_back(PhantomNodeWithDistance{
+                    parameters.hints[i]->phantom,
+                    util::coordinate_calculation::haversineDistance(
+                        parameters.coordinates[i], parameters.hints[i]->phantom.location),
+                });
+                continue;
+            }
+            if (use_bearings && parameters.bearings[i])
+            {
+                phantom_nodes[i] = facade.NearestPhantomNodesInRange(
+                    parameters.coordinates[i], radiuses[i], parameters.bearings[i]->bearing,
+                    parameters.bearings[i]->range);
+            }
+            else
+            {
+                phantom_nodes[i] =
+                    facade.NearestPhantomNodesInRange(parameters.coordinates[i], radiuses[i]);
+            }
+        }
+
+        return phantom_nodes;
+    }
+
+    std::vector<std::vector<PhantomNodeWithDistance>>
+    GetPhantomNodes(const api::BaseParameters &parameters, unsigned number_of_results)
+    {
+        std::vector<std::vector<PhantomNodeWithDistance>> phantom_nodes(
+            parameters.coordinates.size());
+
+        const bool use_hints = !parameters.hints.empty();
+        const bool use_bearings = !parameters.bearings.empty();
+        const bool use_radiuses = !parameters.radiuses.empty();
+
+        BOOST_ASSERT(parameters.IsValid());
+        for (const auto i : util::irange<std::size_t>(0, parameters.coordinates.size()))
+        {
+            if (use_hints && parameters.hints[i] &&
+                parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
+            {
+                phantom_nodes[i].push_back(PhantomNodeWithDistance{
+                    parameters.hints[i]->phantom,
+                    util::coordinate_calculation::haversineDistance(
+                        parameters.coordinates[i], parameters.hints[i]->phantom.location),
+                });
+                continue;
+            }
+
+            if (use_bearings && parameters.bearings[i])
+            {
+                if (use_radiuses && parameters.radiuses[i])
+                {
+                    phantom_nodes[i] = facade.NearestPhantomNodes(
+                        parameters.coordinates[i], number_of_results, *parameters.radiuses[i],
+                        parameters.bearings[i]->bearing, parameters.bearings[i]->range);
+                }
+                else
+                {
+                    phantom_nodes[i] = facade.NearestPhantomNodes(
+                        parameters.coordinates[i], number_of_results,
+                        parameters.bearings[i]->bearing, parameters.bearings[i]->range);
+                }
+            }
+            else
+            {
+                if (use_radiuses && parameters.radiuses[i])
+                {
+                    phantom_nodes[i] = facade.NearestPhantomNodes(
+                        parameters.coordinates[i], number_of_results, *parameters.radiuses[i]);
+                }
+                else
+                {
+                    phantom_nodes[i] =
+                        facade.NearestPhantomNodes(parameters.coordinates[i], number_of_results);
+                }
+            }
+
+            // we didn't find a fitting node, return error
+            if (phantom_nodes[i].empty())
+            {
+                break;
+            }
+        }
+        return phantom_nodes;
+    }
+
+    std::vector<PhantomNodePair> GetPhantomNodes(const api::BaseParameters &parameters)
+    {
+        std::vector<PhantomNodePair> phantom_node_pairs(parameters.coordinates.size());
+
+        const bool use_hints = !parameters.hints.empty();
+        const bool use_bearings = !parameters.bearings.empty();
+        const bool use_radiuses = !parameters.radiuses.empty();
+
+        BOOST_ASSERT(parameters.IsValid());
+        for (const auto i : util::irange<std::size_t>(0, parameters.coordinates.size()))
+        {
+            if (use_hints && parameters.hints[i] &&
+                parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
+            {
+                phantom_node_pairs[i].first = parameters.hints[i]->phantom;
+                // we don't set the second one - it will be marked as invalid
+                continue;
+            }
+
+            if (use_bearings && parameters.bearings[i])
+            {
+                if (use_radiuses && parameters.radiuses[i])
+                {
+                    phantom_node_pairs[i] =
+                        facade.NearestPhantomNodeWithAlternativeFromBigComponent(
+                            parameters.coordinates[i], *parameters.radiuses[i],
+                            parameters.bearings[i]->bearing, parameters.bearings[i]->range);
+                }
+                else
+                {
+                    phantom_node_pairs[i] =
+                        facade.NearestPhantomNodeWithAlternativeFromBigComponent(
+                            parameters.coordinates[i], parameters.bearings[i]->bearing,
+                            parameters.bearings[i]->range);
+                }
+            }
+            else
+            {
+                if (use_radiuses && parameters.radiuses[i])
+                {
+                    phantom_node_pairs[i] =
+                        facade.NearestPhantomNodeWithAlternativeFromBigComponent(
+                            parameters.coordinates[i], *parameters.radiuses[i]);
+                }
+                else
+                {
+                    phantom_node_pairs[i] =
+                        facade.NearestPhantomNodeWithAlternativeFromBigComponent(
+                            parameters.coordinates[i]);
+                }
+            }
+
+            // we didn't find a fitting node, return error
+            if (!phantom_node_pairs[i].first.IsValid(facade.GetNumberOfNodes()))
+            {
+                // TODO document why?
+                phantom_node_pairs.pop_back();
+                break;
+            }
+            BOOST_ASSERT(phantom_node_pairs[i].first.IsValid(facade.GetNumberOfNodes()));
+            BOOST_ASSERT(phantom_node_pairs[i].second.IsValid(facade.GetNumberOfNodes()));
+        }
+        return phantom_node_pairs;
+    }
+};
+}
+}
+}
+
+#endif /* BASE_PLUGIN_HPP */
diff --git a/include/engine/plugins/table.hpp b/include/engine/plugins/table.hpp
new file mode 100644
index 0000000..09f9761
--- /dev/null
+++ b/include/engine/plugins/table.hpp
@@ -0,0 +1,35 @@
+#ifndef TABLE_HPP
+#define TABLE_HPP
+
+#include "engine/plugins/plugin_base.hpp"
+
+#include "engine/api/table_parameters.hpp"
+#include "engine/routing_algorithms/many_to_many.hpp"
+#include "engine/search_engine_data.hpp"
+#include "util/json_container.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+class TablePlugin final : public BasePlugin
+{
+  public:
+    explicit TablePlugin(datafacade::BaseDataFacade &facade,
+                         const int max_locations_distance_table);
+
+    Status HandleRequest(const api::TableParameters &params, util::json::Object &result);
+
+  private:
+    SearchEngineData heaps;
+    routing_algorithms::ManyToManyRouting<datafacade::BaseDataFacade> distance_table;
+    int max_locations_distance_table;
+};
+}
+}
+}
+
+#endif // TABLE_HPP
diff --git a/include/engine/plugins/tile.hpp b/include/engine/plugins/tile.hpp
new file mode 100644
index 0000000..77ba357
--- /dev/null
+++ b/include/engine/plugins/tile.hpp
@@ -0,0 +1,35 @@
+#ifndef TILEPLUGIN_HPP
+#define TILEPLUGIN_HPP
+
+#include "engine/plugins/plugin_base.hpp"
+#include "engine/api/tile_parameters.hpp"
+
+#include <string>
+
+/*
+ * This plugin generates Mapbox Vector tiles that show the internal
+ * routing geometry and speed values on all road segments.
+ * You can use this along with a vector-tile viewer, like Mapbox GL,
+ * to display maps that show the exact road network that
+ * OSRM is routing.  This is very useful for debugging routing
+ * errors
+ */
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+class TilePlugin final : public BasePlugin
+{
+  public:
+    TilePlugin(datafacade::BaseDataFacade &facade) : BasePlugin(facade) {}
+
+    Status HandleRequest(const api::TileParameters &parameters, std::string &pbf_buffer);
+};
+}
+}
+}
+
+#endif /* TILEPLUGIN_HPP */
diff --git a/include/engine/plugins/trip.hpp b/include/engine/plugins/trip.hpp
new file mode 100644
index 0000000..cf36884
--- /dev/null
+++ b/include/engine/plugins/trip.hpp
@@ -0,0 +1,54 @@
+#ifndef TRIP_HPP
+#define TRIP_HPP
+
+#include "engine/plugins/plugin_base.hpp"
+
+#include "engine/api/trip_parameters.hpp"
+#include "engine/routing_algorithms/shortest_path.hpp"
+#include "engine/routing_algorithms/many_to_many.hpp"
+
+#include "osrm/json_container.hpp"
+
+#include <boost/assert.hpp>
+
+#include <cstdlib>
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+#include <iterator>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+class TripPlugin final : public BasePlugin
+{
+  private:
+    SearchEngineData heaps;
+    routing_algorithms::ShortestPathRouting<datafacade::BaseDataFacade> shortest_path;
+    routing_algorithms::ManyToManyRouting<datafacade::BaseDataFacade> duration_table;
+    int max_locations_trip;
+
+    InternalRouteResult ComputeRoute(const std::vector<PhantomNode> &phantom_node_list,
+                                     const api::TripParameters &parameters,
+                                     const std::vector<NodeID> &trip);
+
+  public:
+    explicit TripPlugin(datafacade::BaseDataFacade &facade_, const int max_locations_trip_)
+        : BasePlugin(facade_), shortest_path(&facade_, heaps), duration_table(&facade_, heaps),
+          max_locations_trip(max_locations_trip_)
+    {
+    }
+
+    Status HandleRequest(const api::TripParameters &parameters, util::json::Object &json_result);
+};
+}
+}
+}
+
+#endif // TRIP_HPP
diff --git a/include/engine/plugins/viaroute.hpp b/include/engine/plugins/viaroute.hpp
new file mode 100644
index 0000000..f73dcc6
--- /dev/null
+++ b/include/engine/plugins/viaroute.hpp
@@ -0,0 +1,47 @@
+#ifndef VIA_ROUTE_HPP
+#define VIA_ROUTE_HPP
+
+#include "engine/datafacade/datafacade_base.hpp"
+#include "engine/plugins/plugin_base.hpp"
+#include "engine/api/route_api.hpp"
+
+#include "engine/search_engine_data.hpp"
+#include "engine/routing_algorithms/shortest_path.hpp"
+#include "engine/routing_algorithms/alternative_path.hpp"
+#include "engine/routing_algorithms/direct_shortest_path.hpp"
+#include "util/json_container.hpp"
+
+#include <cstdlib>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+class ViaRoutePlugin final : public BasePlugin
+{
+  private:
+    SearchEngineData heaps;
+    routing_algorithms::ShortestPathRouting<datafacade::BaseDataFacade> shortest_path;
+    routing_algorithms::AlternativeRouting<datafacade::BaseDataFacade> alternative_path;
+    routing_algorithms::DirectShortestPathRouting<datafacade::BaseDataFacade> direct_shortest_path;
+    int max_locations_viaroute;
+
+  public:
+    explicit ViaRoutePlugin(datafacade::BaseDataFacade &facade, int max_locations_viaroute);
+
+    Status HandleRequest(const api::RouteParameters &route_parameters,
+                         util::json::Object &json_result);
+};
+}
+}
+}
+
+#endif // VIA_ROUTE_HPP
diff --git a/include/engine/polyline_compressor.hpp b/include/engine/polyline_compressor.hpp
new file mode 100644
index 0000000..4ecf941
--- /dev/null
+++ b/include/engine/polyline_compressor.hpp
@@ -0,0 +1,31 @@
+#ifndef POLYLINECOMPRESSOR_H_
+#define POLYLINECOMPRESSOR_H_
+
+#include "util/coordinate.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace detail
+{
+constexpr double POLYLINE_PRECISION = 1e5;
+constexpr double COORDINATE_TO_POLYLINE = POLYLINE_PRECISION / COORDINATE_PRECISION;
+constexpr double POLYLINE_TO_COORDINATE = COORDINATE_PRECISION / POLYLINE_PRECISION;
+}
+
+using CoordVectorForwardIter = std::vector<util::Coordinate>::const_iterator;
+// Encodes geometry into polyline format.
+// See: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
+std::string encodePolyline(CoordVectorForwardIter begin, CoordVectorForwardIter end);
+
+// Decodes geometry from polyline format
+// See: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
+std::vector<util::Coordinate> decodePolyline(const std::string &polyline);
+}
+}
+
+#endif /* POLYLINECOMPRESSOR_H_ */
diff --git a/routing_algorithms/alternative_path.hpp b/include/engine/routing_algorithms/alternative_path.hpp
similarity index 86%
rename from routing_algorithms/alternative_path.hpp
rename to include/engine/routing_algorithms/alternative_path.hpp
index 59b772e..8dcc123 100644
--- a/routing_algorithms/alternative_path.hpp
+++ b/include/engine/routing_algorithms/alternative_path.hpp
@@ -1,45 +1,26 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 ALTERNATIVE_PATH_ROUTING_HPP
 #define ALTERNATIVE_PATH_ROUTING_HPP
 
-#include "routing_base.hpp"
-#include "../data_structures/search_engine_data.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/container.hpp"
+#include "engine/routing_algorithms/routing_base.hpp"
+#include "engine/search_engine_data.hpp"
+#include "util/integer_range.hpp"
 
 #include <boost/assert.hpp>
 
+#include <algorithm>
+#include <iterator>
 #include <unordered_map>
 #include <unordered_set>
 
 #include <vector>
 
+namespace osrm
+{
+namespace engine
+{
+namespace routing_algorithms
+{
+
 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.
@@ -103,45 +84,37 @@ class AlternativeRouting final
         int upper_bound_to_shortest_path_distance = INVALID_EDGE_WEIGHT;
         NodeID middle_node = SPECIAL_NODEID;
         const EdgeWeight min_edge_offset =
-            std::min(-phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
-                     -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
+            std::min(phantom_node_pair.source_phantom.forward_segment_id.enabled ? -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset() : 0,
+                     phantom_node_pair.source_phantom.reverse_segment_id.enabled ? -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset() : 0);
 
-        if (phantom_node_pair.source_phantom.forward_node_id != SPECIAL_NODEID)
+        if (phantom_node_pair.source_phantom.forward_segment_id.enabled)
         {
-            // SimpleLogger().Write(logDEBUG) << "fwd-a insert: " <<
-            // phantom_node_pair.source_phantom.forward_node_id << ", w: " <<
-            // -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset();
-            forward_heap1.Insert(phantom_node_pair.source_phantom.forward_node_id,
+            BOOST_ASSERT(phantom_node_pair.source_phantom.forward_segment_id.id != SPECIAL_SEGMENTID);
+            forward_heap1.Insert(phantom_node_pair.source_phantom.forward_segment_id.id,
                                  -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
-                                 phantom_node_pair.source_phantom.forward_node_id);
+                                 phantom_node_pair.source_phantom.forward_segment_id.id);
         }
-        if (phantom_node_pair.source_phantom.reverse_node_id != SPECIAL_NODEID)
+        if (phantom_node_pair.source_phantom.reverse_segment_id.enabled)
         {
-            //     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,
+            BOOST_ASSERT(phantom_node_pair.source_phantom.reverse_segment_id.id != SPECIAL_SEGMENTID);
+            forward_heap1.Insert(phantom_node_pair.source_phantom.reverse_segment_id.id,
                                  -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
-                                 phantom_node_pair.source_phantom.reverse_node_id);
+                                 phantom_node_pair.source_phantom.reverse_segment_id.id);
         }
 
-        if (phantom_node_pair.target_phantom.forward_node_id != SPECIAL_NODEID)
+        if (phantom_node_pair.target_phantom.forward_segment_id.enabled)
         {
-            // SimpleLogger().Write(logDEBUG) << "rev-a insert: " <<
-            // phantom_node_pair.target_phantom.forward_node_id << ", w: " <<
-            // phantom_node_pair.target_phantom.GetForwardWeightPlusOffset();
-            reverse_heap1.Insert(phantom_node_pair.target_phantom.forward_node_id,
+            BOOST_ASSERT(phantom_node_pair.target_phantom.forward_segment_id.id != SPECIAL_SEGMENTID);
+            reverse_heap1.Insert(phantom_node_pair.target_phantom.forward_segment_id.id,
                                  phantom_node_pair.target_phantom.GetForwardWeightPlusOffset(),
-                                 phantom_node_pair.target_phantom.forward_node_id);
+                                 phantom_node_pair.target_phantom.forward_segment_id.id);
         }
-        if (phantom_node_pair.target_phantom.reverse_node_id != SPECIAL_NODEID)
+        if (phantom_node_pair.target_phantom.reverse_segment_id.enabled)
         {
-            // SimpleLogger().Write(logDEBUG) << "rev-b insert: " <<
-            // phantom_node_pair.target_phantom.reverse_node_id << ", w: " <<
-            // phantom_node_pair.target_phantom.GetReverseWeightPlusOffset();
-            reverse_heap1.Insert(phantom_node_pair.target_phantom.reverse_node_id,
+            BOOST_ASSERT(phantom_node_pair.target_phantom.reverse_segment_id.id != SPECIAL_SEGMENTID);
+            reverse_heap1.Insert(phantom_node_pair.target_phantom.reverse_segment_id.id,
                                  phantom_node_pair.target_phantom.GetReverseWeightPlusOffset(),
-                                 phantom_node_pair.target_phantom.reverse_node_id);
+                                 phantom_node_pair.target_phantom.reverse_segment_id.id);
         }
 
         // search from s and t till new_min/(1+epsilon) > length_of_shortest_path
@@ -168,13 +141,32 @@ class AlternativeRouting final
             return;
         }
 
-        osrm::sort_unique_resize(via_node_candidate_list);
+        std::sort(begin(via_node_candidate_list), end(via_node_candidate_list));
+        auto unique_end = std::unique(begin(via_node_candidate_list), end(via_node_candidate_list));
+        via_node_candidate_list.resize(unique_end - begin(via_node_candidate_list));
 
         std::vector<NodeID> packed_forward_path;
         std::vector<NodeID> packed_reverse_path;
 
-        super::RetrievePackedPathFromSingleHeap(forward_heap1, middle_node, packed_forward_path);
-        super::RetrievePackedPathFromSingleHeap(reverse_heap1, middle_node, packed_reverse_path);
+        const bool path_is_a_loop =
+            upper_bound_to_shortest_path_distance !=
+            forward_heap1.GetKey(middle_node) + reverse_heap1.GetKey(middle_node);
+        if (path_is_a_loop)
+        {
+            // Self Loop
+            BOOST_ASSERT(forward_heap1.GetData(middle_node).parent == middle_node &&
+                         reverse_heap1.GetData(middle_node).parent == middle_node);
+            packed_forward_path.push_back(middle_node);
+            packed_forward_path.push_back(middle_node);
+        }
+        else
+        {
+
+            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() +
@@ -231,16 +223,18 @@ class AlternativeRouting final
             }
         }
 
-        // SimpleLogger().Write(logDEBUG) << "fwd_search_space size: " <<
+        // util::SimpleLogger().Write(logDEBUG) << "fwd_search_space size: " <<
         // forward_search_space.size() << ", marked " << approximated_forward_sharing.size() << "
         // nodes";
-        // SimpleLogger().Write(logDEBUG) << "rev_search_space size: " <<
+        // util::SimpleLogger().Write(logDEBUG) << "rev_search_space size: " <<
         // reverse_search_space.size() << ", marked " << approximated_reverse_sharing.size() << "
         // nodes";
 
         std::vector<NodeID> preselected_node_list;
         for (const NodeID node : via_node_candidate_list)
         {
+            if (node == middle_node)
+                continue;
             const auto fwd_iterator = approximated_forward_sharing.find(node);
             const int fwd_sharing =
                 (fwd_iterator != approximated_forward_sharing.end()) ? fwd_iterator->second : 0;
@@ -267,10 +261,13 @@ class AlternativeRouting final
         }
 
         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);
-        packed_shortest_path.insert(packed_shortest_path.end(), packed_reverse_path.begin(),
-                                    packed_reverse_path.end());
+        if (!path_is_a_loop)
+        {
+            std::reverse(packed_shortest_path.begin(), packed_shortest_path.end());
+            packed_shortest_path.emplace_back(middle_node);
+            packed_shortest_path.insert(packed_shortest_path.end(), packed_reverse_path.begin(),
+                                        packed_reverse_path.end());
+        }
         std::vector<RankedCandidateNode> ranked_candidates_list;
 
         // prioritizing via nodes for deep inspection
@@ -311,9 +308,9 @@ class AlternativeRouting final
             BOOST_ASSERT(!packed_shortest_path.empty());
             raw_route_data.unpacked_path_segments.resize(1);
             raw_route_data.source_traversed_in_reverse.push_back(
-                (packed_shortest_path.front() != phantom_node_pair.source_phantom.forward_node_id));
+                (packed_shortest_path.front() != phantom_node_pair.source_phantom.forward_segment_id.id));
             raw_route_data.target_traversed_in_reverse.push_back(
-                (packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_node_id));
+                (packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_segment_id.id));
 
             super::UnpackPath(
                 // -- packed input
@@ -333,9 +330,9 @@ class AlternativeRouting final
                                         s_v_middle, 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));
+                packed_alternate_path.front() != phantom_node_pair.source_phantom.forward_segment_id.id));
             raw_route_data.alt_target_traversed_in_reverse.push_back(
-                (packed_alternate_path.back() != phantom_node_pair.target_phantom.forward_node_id));
+                (packed_alternate_path.back() != phantom_node_pair.target_phantom.forward_segment_id.id));
 
             // unpack the alternate path
             super::UnpackPath(packed_alternate_path.begin(), packed_alternate_path.end(),
@@ -399,10 +396,13 @@ class AlternativeRouting final
         int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT;
         new_reverse_heap.Insert(via_node, 0, via_node);
         // compute path <s,..,v> by reusing forward search from s
+        const bool constexpr STALLING_ENABLED = true;
+        const bool constexpr DO_NOT_FORCE_LOOPS = false;
         while (!new_reverse_heap.Empty())
         {
             super::RoutingStep(new_reverse_heap, existing_forward_heap, s_v_middle,
-                               upper_bound_s_v_path_length, min_edge_offset, false);
+                               upper_bound_s_v_path_length, min_edge_offset, false,
+                               STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
         }
         // compute path <v,..,t> by reusing backward search from node t
         NodeID v_t_middle = SPECIAL_NODEID;
@@ -411,7 +411,8 @@ class AlternativeRouting final
         while (!new_forward_heap.Empty())
         {
             super::RoutingStep(new_forward_heap, existing_reverse_heap, v_t_middle,
-                               upper_bound_of_v_t_path_length, min_edge_offset, true);
+                               upper_bound_of_v_t_path_length, min_edge_offset, true,
+                               STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
         }
         *real_length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;
 
@@ -430,7 +431,7 @@ class AlternativeRouting final
         // First partially unpack s-->v until paths deviate, note length of common path.
         const int64_t s_v_min_path_size =
             static_cast<int64_t>(std::min(packed_s_v_path.size(), packed_shortest_path.size())) - 1;
-        for (const int64_t current_node : osrm::irange<int64_t>(0, s_v_min_path_size))
+        for (const int64_t current_node : util::irange<int64_t>(0, s_v_min_path_size))
         {
             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])
@@ -546,7 +547,7 @@ class AlternativeRouting final
     //     //compute forward sharing
     //     while( (packed_alternate_path[aindex] == packed_shortest_path[aindex]) &&
     //     (packed_alternate_path[aindex+1] == packed_shortest_path[aindex+1]) ) {
-    //         //            SimpleLogger().Write() << "retrieving edge (" <<
+    //         //            util::SimpleLogger().Write() << "retrieving edge (" <<
     //         packed_alternate_path[aindex] << "," << packed_alternate_path[aindex+1] << ")";
     //         EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_alternate_path[aindex],
     //         packed_alternate_path[aindex+1]);
@@ -584,7 +585,8 @@ class AlternativeRouting final
         const NodeID node = forward_heap.DeleteMin();
         const int distance = forward_heap.GetKey(node);
         // const NodeID parentnode = forward_heap.GetData(node).parent;
-        // SimpleLogger().Write() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled edge ("
+        // util::SimpleLogger().Write() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled
+        // edge ("
         // << parentnode << "," << node << "), dist: " << distance;
 
         const int scaled_distance =
@@ -608,12 +610,26 @@ class AlternativeRouting final
                 {
                     *middle_node = node;
                     *upper_bound_to_shortest_path_distance = new_distance;
-                    //     SimpleLogger().Write() << "accepted middle_node " << *middle_node << " at
+                    //     util::SimpleLogger().Write() << "accepted middle_node " << *middle_node
+                    //     << " at
                     //     distance " << new_distance;
                     // } else {
-                    //     SimpleLogger().Write() << "discarded middle_node " << *middle_node << "
+                    //     util::SimpleLogger().Write() << "discarded middle_node " << *middle_node
+                    //     << "
                     //     at distance " << new_distance;
                 }
+                else
+                {
+                    // check whether there is a loop present at the node
+                    const auto loop_distance = super::GetLoopWeight(node);
+                    const int new_distance_with_loop = new_distance + loop_distance;
+                    if (loop_distance != INVALID_EDGE_WEIGHT &&
+                        new_distance_with_loop <= *upper_bound_to_shortest_path_distance)
+                    {
+                        *middle_node = node;
+                        *upper_bound_to_shortest_path_distance = loop_distance;
+                    }
+                }
             }
         }
 
@@ -669,10 +685,13 @@ class AlternativeRouting final
         int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT;
         // compute path <s,..,v> by reusing forward search from s
         new_reverse_heap.Insert(candidate.node, 0, candidate.node);
+        const bool constexpr STALLING_ENABLED = true;
+        const bool constexpr DO_NOT_FORCE_LOOPS = false;
         while (new_reverse_heap.Size() > 0)
         {
             super::RoutingStep(new_reverse_heap, existing_forward_heap, *s_v_middle,
-                               upper_bound_s_v_path_length, min_edge_offset, false);
+                               upper_bound_s_v_path_length, min_edge_offset, false,
+                               STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
         }
 
         if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_length)
@@ -687,7 +706,8 @@ class AlternativeRouting final
         while (new_forward_heap.Size() > 0)
         {
             super::RoutingStep(new_forward_heap, existing_reverse_heap, *v_t_middle,
-                               upper_bound_of_v_t_path_length, min_edge_offset, true);
+                               upper_bound_of_v_t_path_length, min_edge_offset, true,
+                               STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
         }
 
         if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_length)
@@ -855,16 +875,21 @@ class AlternativeRouting final
             if (!forward_heap3.Empty())
             {
                 super::RoutingStep(forward_heap3, reverse_heap3, middle, upper_bound,
-                                   min_edge_offset, true);
+                                   min_edge_offset, true, STALLING_ENABLED, DO_NOT_FORCE_LOOPS,
+                                   DO_NOT_FORCE_LOOPS);
             }
             if (!reverse_heap3.Empty())
             {
                 super::RoutingStep(reverse_heap3, forward_heap3, middle, upper_bound,
-                                   min_edge_offset, false);
+                                   min_edge_offset, false, STALLING_ENABLED, DO_NOT_FORCE_LOOPS,
+                                   DO_NOT_FORCE_LOOPS);
             }
         }
         return (upper_bound <= t_test_path_length);
     }
 };
+}
+}
+}
 
 #endif /* ALTERNATIVE_PATH_ROUTING_HPP */
diff --git a/routing_algorithms/direct_shortest_path.hpp b/include/engine/routing_algorithms/direct_shortest_path.hpp
similarity index 54%
rename from routing_algorithms/direct_shortest_path.hpp
rename to include/engine/routing_algorithms/direct_shortest_path.hpp
index 2237d68..970949e 100644
--- a/routing_algorithms/direct_shortest_path.hpp
+++ b/include/engine/routing_algorithms/direct_shortest_path.hpp
@@ -1,41 +1,21 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 DIRECT_SHORTEST_PATH_HPP
 #define DIRECT_SHORTEST_PATH_HPP
 
 #include <boost/assert.hpp>
 #include <iterator>
 
-#include "routing_base.hpp"
-#include "../data_structures/search_engine_data.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/timing_util.hpp"
-#include "../typedefs.h"
+#include "engine/routing_algorithms/routing_base.hpp"
+#include "engine/search_engine_data.hpp"
+#include "util/integer_range.hpp"
+#include "util/timing_util.hpp"
+#include "util/typedefs.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+namespace routing_algorithms
+{
 
 /// This is a striped down version of the general shortest path algorithm.
 /// The general algorithm always computes two queries for each leg. This is only
@@ -60,17 +40,15 @@ class DirectShortestPathRouting final
     ~DirectShortestPathRouting() {}
 
     void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
-                    const std::vector<bool> &uturn_indicators,
                     InternalRouteResult &raw_route_data) const
     {
-        (void)uturn_indicators; // unused
-
         // Get distance to next pair of target nodes.
         BOOST_ASSERT_MSG(1 == phantom_nodes_vector.size(),
-                                         "Direct Shortest Path Query only accepts a single source and target pair. Multiple ones have been specified.");
-        const auto& phantom_node_pair = phantom_nodes_vector.front();
-        const auto& source_phantom = phantom_node_pair.source_phantom;
-        const auto& target_phantom = phantom_node_pair.target_phantom;
+                         "Direct Shortest Path Query only accepts a single source and target pair. "
+                         "Multiple ones have been specified.");
+        const auto &phantom_node_pair = phantom_nodes_vector.front();
+        const auto &source_phantom = phantom_node_pair.source_phantom;
+        const auto &target_phantom = phantom_node_pair.target_phantom;
 
         engine_working_data.InitializeOrClearFirstThreadLocalStorage(
             super::facade->GetNumberOfNodes());
@@ -79,39 +57,42 @@ class DirectShortestPathRouting final
         forward_heap.Clear();
         reverse_heap.Clear();
 
-        BOOST_ASSERT(source_phantom.is_valid());
-        BOOST_ASSERT(target_phantom.is_valid());
+        BOOST_ASSERT(source_phantom.IsValid());
+        BOOST_ASSERT(target_phantom.IsValid());
 
-        if (source_phantom.forward_node_id != SPECIAL_NODEID)
+        if (source_phantom.forward_segment_id.enabled)
         {
-            forward_heap.Insert(source_phantom.forward_node_id,
+            forward_heap.Insert(source_phantom.forward_segment_id.id,
                                 -source_phantom.GetForwardWeightPlusOffset(),
-                                source_phantom.forward_node_id);
+                                source_phantom.forward_segment_id.id);
         }
-        if (source_phantom.reverse_node_id != SPECIAL_NODEID)
+        if (source_phantom.reverse_segment_id.enabled)
         {
-            forward_heap.Insert(source_phantom.reverse_node_id,
+            forward_heap.Insert(source_phantom.reverse_segment_id.id,
                                 -source_phantom.GetReverseWeightPlusOffset(),
-                                source_phantom.reverse_node_id);
+                                source_phantom.reverse_segment_id.id);
         }
 
-        if (target_phantom.forward_node_id != SPECIAL_NODEID)
+        if (target_phantom.forward_segment_id.enabled)
         {
-            reverse_heap.Insert(target_phantom.forward_node_id,
+            reverse_heap.Insert(target_phantom.forward_segment_id.id,
                                 target_phantom.GetForwardWeightPlusOffset(),
-                                target_phantom.forward_node_id);
+                                target_phantom.forward_segment_id.id);
         }
 
-        if (target_phantom.reverse_node_id != SPECIAL_NODEID)
+        if (target_phantom.reverse_segment_id.enabled)
         {
-            reverse_heap.Insert(target_phantom.reverse_node_id,
+            reverse_heap.Insert(target_phantom.reverse_segment_id.id,
                                 target_phantom.GetReverseWeightPlusOffset(),
-                                target_phantom.reverse_node_id);
+                                target_phantom.reverse_segment_id.id);
         }
 
         int distance = INVALID_EDGE_WEIGHT;
         std::vector<NodeID> packed_leg;
 
+        const bool constexpr DO_NOT_FORCE_LOOPS =
+            false; // prevents forcing of loops, since offsets are set correctly
+
         if (super::facade->GetCoreSize() > 0)
         {
             engine_working_data.InitializeOrClearSecondThreadLocalStorage(
@@ -121,13 +102,13 @@ class DirectShortestPathRouting final
             forward_core_heap.Clear();
             reverse_core_heap.Clear();
 
-
             super::SearchWithCore(forward_heap, reverse_heap, forward_core_heap, reverse_core_heap,
-                                  distance, packed_leg);
+                                  distance, packed_leg, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
         }
         else
         {
-            super::Search(forward_heap, reverse_heap, distance, packed_leg);
+            super::Search(forward_heap, reverse_heap, distance, packed_leg, DO_NOT_FORCE_LOOPS,
+                          DO_NOT_FORCE_LOOPS);
         }
 
         // No path found for both target nodes?
@@ -143,13 +124,16 @@ class DirectShortestPathRouting final
         raw_route_data.shortest_path_length = distance;
         raw_route_data.unpacked_path_segments.resize(1);
         raw_route_data.source_traversed_in_reverse.push_back(
-            (packed_leg.front() != phantom_node_pair.source_phantom.forward_node_id));
+            (packed_leg.front() != phantom_node_pair.source_phantom.forward_segment_id.id));
         raw_route_data.target_traversed_in_reverse.push_back(
-            (packed_leg.back() != phantom_node_pair.target_phantom.forward_node_id));
-
-        super::UnpackPath(packed_leg.begin(), packed_leg.end(), phantom_node_pair, raw_route_data.unpacked_path_segments.front());
+            (packed_leg.back() != phantom_node_pair.target_phantom.forward_segment_id.id));
 
+        super::UnpackPath(packed_leg.begin(), packed_leg.end(), phantom_node_pair,
+                          raw_route_data.unpacked_path_segments.front());
     }
 };
+}
+}
+}
 
 #endif /* DIRECT_SHORTEST_PATH_HPP */
diff --git a/routing_algorithms/many_to_many.hpp b/include/engine/routing_algorithms/many_to_many.hpp
similarity index 59%
rename from routing_algorithms/many_to_many.hpp
rename to include/engine/routing_algorithms/many_to_many.hpp
index c5dfb7c..e09a91d 100644
--- a/routing_algorithms/many_to_many.hpp
+++ b/include/engine/routing_algorithms/many_to_many.hpp
@@ -1,36 +1,9 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 MANY_TO_MANY_ROUTING_HPP
 #define MANY_TO_MANY_ROUTING_HPP
 
-#include "routing_base.hpp"
-#include "../data_structures/search_engine_data.hpp"
-#include "../typedefs.h"
+#include "engine/routing_algorithms/routing_base.hpp"
+#include "engine/search_engine_data.hpp"
+#include "util/typedefs.hpp"
 
 #include <boost/assert.hpp>
 
@@ -39,6 +12,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <unordered_map>
 #include <vector>
 
+namespace osrm
+{
+namespace engine
+{
+namespace routing_algorithms
+{
+
 template <class DataFacadeT>
 class ManyToManyRouting final
     : public BasicRoutingInterface<DataFacadeT, ManyToManyRouting<DataFacadeT>>
@@ -56,6 +36,8 @@ class ManyToManyRouting final
         {
         }
     };
+
+    // FIXME This should be replaced by an std::unordered_multimap, though this needs benchmarking
     using SearchSpaceWithBuckets = std::unordered_map<NodeID, std::vector<NodeBucket>>;
 
   public:
@@ -64,16 +46,17 @@ class ManyToManyRouting final
     {
     }
 
-    ~ManyToManyRouting() {}
-
-    std::shared_ptr<std::vector<EdgeWeight>>
-    operator()(const std::vector<PhantomNode> &phantom_sources_array, const std::vector<PhantomNode> &phantom_targets_array) const
+    std::vector<EdgeWeight> operator()(const std::vector<PhantomNode> &phantom_nodes,
+                                       const std::vector<std::size_t> &source_indices,
+                                       const std::vector<std::size_t> &target_indices) const
     {
-        const auto number_of_sources = phantom_sources_array.size();
-        const auto number_of_targets = phantom_targets_array.size();
-        std::shared_ptr<std::vector<EdgeWeight>> result_table =
-            std::make_shared<std::vector<EdgeWeight>>(number_of_targets * number_of_sources,
-                                                      std::numeric_limits<EdgeWeight>::max());
+        const auto number_of_sources =
+            source_indices.empty() ? phantom_nodes.size() : source_indices.size();
+        const auto number_of_targets =
+            target_indices.empty() ? phantom_nodes.size() : target_indices.size();
+        const auto number_of_entries = number_of_sources * number_of_targets;
+        std::vector<EdgeWeight> result_table(number_of_entries,
+                                             std::numeric_limits<EdgeWeight>::max());
 
         engine_working_data.InitializeOrClearFirstThreadLocalStorage(
             super::facade->GetNumberOfNodes());
@@ -82,71 +65,102 @@ class ManyToManyRouting final
 
         SearchSpaceWithBuckets search_space_with_buckets;
 
-        unsigned target_id = 0;
-        for (const auto &phantom : phantom_targets_array)
+        unsigned column_idx = 0;
+        const auto search_target_phantom = [&](const PhantomNode &phantom)
         {
             query_heap.Clear();
             // insert target(s) at distance 0
 
-            if (SPECIAL_NODEID != phantom.forward_node_id)
+            if (phantom.forward_segment_id.enabled)
             {
-                query_heap.Insert(phantom.forward_node_id,
+                query_heap.Insert(phantom.forward_segment_id.id,
                                   phantom.GetForwardWeightPlusOffset(),
-                                  phantom.forward_node_id);
+                                  phantom.forward_segment_id.id);
             }
-            if (SPECIAL_NODEID != phantom.reverse_node_id)
+            if (phantom.reverse_segment_id.enabled)
             {
-                query_heap.Insert(phantom.reverse_node_id,
+                query_heap.Insert(phantom.reverse_segment_id.id,
                                   phantom.GetReverseWeightPlusOffset(),
-                                  phantom.reverse_node_id);
+                                  phantom.reverse_segment_id.id);
             }
 
             // explore search space
             while (!query_heap.Empty())
             {
-                BackwardRoutingStep(target_id, query_heap, search_space_with_buckets);
+                BackwardRoutingStep(column_idx, query_heap, search_space_with_buckets);
             }
-            ++target_id;
-        }
+            ++column_idx;
+        };
 
         // for each source do forward search
-        unsigned source_id = 0;
-        for (const auto &phantom : phantom_sources_array)
+        unsigned row_idx = 0;
+        const auto search_source_phantom = [&](const PhantomNode &phantom)
         {
             query_heap.Clear();
             // insert target(s) at distance 0
 
-            if (SPECIAL_NODEID != phantom.forward_node_id)
+            if (phantom.forward_segment_id.enabled)
             {
-                query_heap.Insert(phantom.forward_node_id,
-                                 -phantom.GetForwardWeightPlusOffset(),
-                                  phantom.forward_node_id);
+                query_heap.Insert(phantom.forward_segment_id.id,
+                                  -phantom.GetForwardWeightPlusOffset(),
+                                  phantom.forward_segment_id.id);
             }
-            if (SPECIAL_NODEID != phantom.reverse_node_id)
+            if (phantom.reverse_segment_id.enabled)
             {
-                query_heap.Insert(phantom.reverse_node_id,
-                                 -phantom.GetReverseWeightPlusOffset(),
-                                  phantom.reverse_node_id);
+                query_heap.Insert(phantom.reverse_segment_id.id,
+                                  -phantom.GetReverseWeightPlusOffset(),
+                                  phantom.reverse_segment_id.id);
             }
 
             // explore search space
             while (!query_heap.Empty())
             {
-                ForwardRoutingStep(source_id, number_of_targets, query_heap,
+                ForwardRoutingStep(row_idx, number_of_targets, query_heap,
                                    search_space_with_buckets, result_table);
             }
+            ++row_idx;
+        };
 
-            ++source_id;
+        if (target_indices.empty())
+        {
+            for (const auto &phantom : phantom_nodes)
+            {
+                search_target_phantom(phantom);
+            }
         }
-        // BOOST_ASSERT(source_id == target_id);
+        else
+        {
+            for (const auto index : target_indices)
+            {
+                const auto &phantom = phantom_nodes[index];
+                search_target_phantom(phantom);
+            }
+        }
+
+        if (source_indices.empty())
+        {
+            for (const auto &phantom : phantom_nodes)
+            {
+                search_source_phantom(phantom);
+            }
+        }
+        else
+        {
+            for (const auto index : source_indices)
+            {
+                const auto &phantom = phantom_nodes[index];
+                search_source_phantom(phantom);
+            }
+        }
+
         return result_table;
     }
 
-    void ForwardRoutingStep(const unsigned source_id,
+    void ForwardRoutingStep(const unsigned row_idx,
                             const unsigned number_of_targets,
                             QueryHeap &query_heap,
                             const SearchSpaceWithBuckets &search_space_with_buckets,
-                            std::shared_ptr<std::vector<EdgeWeight>> result_table) const
+                            std::vector<EdgeWeight> &result_table) const
     {
         const NodeID node = query_heap.DeleteMin();
         const int source_distance = query_heap.GetKey(node);
@@ -160,16 +174,23 @@ class ManyToManyRouting final
             for (const NodeBucket &current_bucket : bucket_list)
             {
                 // get target id from bucket entry
-                const unsigned target_id = current_bucket.target_id;
+                const unsigned column_idx = current_bucket.target_id;
                 const int target_distance = current_bucket.distance;
-                const EdgeWeight current_distance =
-                    (*result_table)[source_id * number_of_targets + target_id];
+                auto &current_distance = result_table[row_idx * number_of_targets + column_idx];
                 // check if new distance is better
                 const EdgeWeight new_distance = source_distance + target_distance;
-                if (new_distance >= 0 && new_distance < current_distance)
+                if (new_distance < 0)
+                {
+                    const EdgeWeight loop_weight = super::GetLoopWeight(node);
+                    const int new_distance_with_loop = new_distance + loop_weight;
+                    if (loop_weight != INVALID_EDGE_WEIGHT && new_distance_with_loop >= 0)
+                    {
+                        current_distance = std::min(current_distance, new_distance_with_loop);
+                    }
+                }
+                else if (new_distance < current_distance)
                 {
-                    (*result_table)[source_id * number_of_targets + target_id] =
-                        (source_distance + target_distance);
+                    result_table[row_idx * number_of_targets + column_idx] = new_distance;
                 }
             }
         }
@@ -180,7 +201,7 @@ class ManyToManyRouting final
         RelaxOutgoingEdges<true>(node, source_distance, query_heap);
     }
 
-    void BackwardRoutingStep(const unsigned target_id,
+    void BackwardRoutingStep(const unsigned column_idx,
                              QueryHeap &query_heap,
                              SearchSpaceWithBuckets &search_space_with_buckets) const
     {
@@ -188,7 +209,7 @@ class ManyToManyRouting final
         const int target_distance = query_heap.GetKey(node);
 
         // store settled nodes in search space bucket
-        search_space_with_buckets[node].emplace_back(target_id, target_distance);
+        search_space_with_buckets[node].emplace_back(column_idx, target_distance);
 
         if (StallAtNode<false>(node, target_distance, query_heap))
         {
@@ -256,4 +277,8 @@ class ManyToManyRouting final
         return false;
     }
 };
+}
+}
+}
+
 #endif
diff --git a/routing_algorithms/map_matching.hpp b/include/engine/routing_algorithms/map_matching.hpp
similarity index 55%
rename from routing_algorithms/map_matching.hpp
rename to include/engine/routing_algorithms/map_matching.hpp
index 430682d..7d8b04e 100644
--- a/routing_algorithms/map_matching.hpp
+++ b/include/engine/routing_algorithms/map_matching.hpp
@@ -1,39 +1,15 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 MAP_MATCHING_HPP
 #define MAP_MATCHING_HPP
 
-#include "routing_base.hpp"
+#include "engine/routing_algorithms/routing_base.hpp"
 
-#include "../algorithms/coordinate_calculation.hpp"
-#include "../data_structures/hidden_markov_model.hpp"
-#include "../util/json_logger.hpp"
-#include "../util/matching_debug_info.hpp"
+#include "engine/map_matching/hidden_markov_model.hpp"
+#include "engine/map_matching/sub_matching.hpp"
+#include "engine/map_matching/matching_confidence.hpp"
+
+#include "util/coordinate_calculation.hpp"
+#include "util/json_logger.hpp"
+#include "util/for_each_pair.hpp"
 
 #include <cstddef>
 
@@ -46,28 +22,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace osrm
 {
-namespace matching
+namespace engine
 {
-
-struct SubMatching
+namespace routing_algorithms
 {
-    std::vector<PhantomNode> nodes;
-    std::vector<unsigned> indices;
-    double length;
-    double confidence;
-};
 
 using CandidateList = std::vector<PhantomNodeWithDistance>;
 using CandidateLists = std::vector<CandidateList>;
-using HMM = HiddenMarkovModel<CandidateLists>;
-using SubMatchingList = std::vector<SubMatching>;
+using HMM = map_matching::HiddenMarkovModel<CandidateLists>;
+using SubMatchingList = std::vector<map_matching::SubMatching>;
 
 constexpr static const unsigned MAX_BROKEN_STATES = 10;
-
 constexpr static const double MAX_SPEED = 180 / 3.6; // 180km -> m/s
-constexpr static const unsigned SUSPICIOUS_DISTANCE_DELTA = 100;
-}
-}
+static const constexpr double MATCHING_BETA = 10;
+constexpr static const double MAX_DISTANCE_DELTA = 2000.;
 
 // implements a hidden markov model map matching algorithm
 template <class DataFacadeT>
@@ -76,8 +44,11 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
     using super = BasicRoutingInterface<DataFacadeT, MapMatching<DataFacadeT>>;
     using QueryHeap = SearchEngineData::QueryHeap;
     SearchEngineData &engine_working_data;
+    map_matching::EmissionLogProbability default_emission_log_probability;
+    map_matching::TransitionLogProbability transition_log_probability;
+    map_matching::MatchingConfidence confidence;
 
-    unsigned GetMedianSampleTime(const std::vector<unsigned>& timestamps) const
+    unsigned GetMedianSampleTime(const std::vector<unsigned> &timestamps) const
     {
         BOOST_ASSERT(timestamps.size() > 1);
 
@@ -87,30 +58,36 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
 
         // don't use first element of sample_times -> will not be a difference.
         auto first_elem = std::next(sample_times.begin());
-        auto median = first_elem + std::distance(first_elem, sample_times.end())/2;
+        auto median = first_elem + std::distance(first_elem, sample_times.end()) / 2;
         std::nth_element(first_elem, median, sample_times.end());
         return *median;
     }
 
   public:
-    MapMatching(DataFacadeT *facade, SearchEngineData &engine_working_data)
-        : super(facade), engine_working_data(engine_working_data)
+    MapMatching(DataFacadeT *facade,
+                SearchEngineData &engine_working_data,
+                const double default_gps_precision)
+        : super(facade), engine_working_data(engine_working_data),
+          default_emission_log_probability(default_gps_precision),
+          transition_log_probability(MATCHING_BETA)
     {
     }
 
-    void operator()(const osrm::matching::CandidateLists &candidates_list,
-                    const std::vector<FixedPointCoordinate> &trace_coordinates,
-                    const std::vector<unsigned> &trace_timestamps,
-                    const double matching_beta,
-                    const double gps_precision,
-                    osrm::matching::SubMatchingList &sub_matchings) const
+    SubMatchingList
+    operator()(const CandidateLists &candidates_list,
+               const std::vector<util::Coordinate> &trace_coordinates,
+               const std::vector<unsigned> &trace_timestamps,
+               const std::vector<boost::optional<double>> &trace_gps_precision) const
     {
+        SubMatchingList sub_matchings;
+
         BOOST_ASSERT(candidates_list.size() == trace_coordinates.size());
         BOOST_ASSERT(candidates_list.size() > 1);
 
         const bool use_timestamps = trace_timestamps.size() > 1;
 
-        const auto median_sample_time = [&]() {
+        const auto median_sample_time = [&]
+        {
             if (use_timestamps)
             {
                 return std::max(1u, GetMedianSampleTime(trace_timestamps));
@@ -120,40 +97,81 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
                 return 1u;
             }
         }();
-        const auto max_broken_time = median_sample_time * osrm::matching::MAX_BROKEN_STATES;
-        const auto max_distance_delta = [&]() {
+        const auto max_broken_time = median_sample_time * MAX_BROKEN_STATES;
+        const auto max_distance_delta = [&]
+        {
             if (use_timestamps)
             {
-                return median_sample_time * osrm::matching::MAX_SPEED;
+                return median_sample_time * MAX_SPEED;
             }
             else
             {
-                return std::numeric_limits<double>::max();
+                return MAX_DISTANCE_DELTA;
             }
         }();
 
-        // TODO replace default values with table lookup based on sampling frequency
-        EmissionLogProbability emission_log_probability(gps_precision);
-        TransitionLogProbability transition_log_probability(matching_beta);
+        std::vector<std::vector<double>> emission_log_probabilities(trace_coordinates.size());
+        if (trace_gps_precision.empty())
+        {
+            for (auto t = 0UL; t < candidates_list.size(); ++t)
+            {
+                emission_log_probabilities[t].resize(candidates_list[t].size());
+                std::transform(candidates_list[t].begin(), candidates_list[t].end(),
+                               emission_log_probabilities[t].begin(),
+                               [this](const PhantomNodeWithDistance &candidate)
+                               {
+                                   return default_emission_log_probability(candidate.distance);
+                               });
+            }
+        }
+        else
+        {
+            for (auto t = 0UL; t < candidates_list.size(); ++t)
+            {
+                emission_log_probabilities[t].resize(candidates_list[t].size());
+                if (trace_gps_precision[t])
+                {
+                    map_matching::EmissionLogProbability emission_log_probability(
+                        *trace_gps_precision[t]);
+                    std::transform(
+                        candidates_list[t].begin(), candidates_list[t].end(),
+                        emission_log_probabilities[t].begin(),
+                        [&emission_log_probability](const PhantomNodeWithDistance &candidate)
+                        {
+                            return emission_log_probability(candidate.distance);
+                        });
+                }
+                else
+                {
+                    std::transform(candidates_list[t].begin(), candidates_list[t].end(),
+                                   emission_log_probabilities[t].begin(),
+                                   [this](const PhantomNodeWithDistance &candidate)
+                                   {
+                                       return default_emission_log_probability(candidate.distance);
+                                   });
+                }
+            }
+        }
 
-        osrm::matching::HMM model(candidates_list, emission_log_probability);
+        HMM model(candidates_list, emission_log_probabilities);
 
         std::size_t initial_timestamp = model.initialize(0);
-        if (initial_timestamp == osrm::matching::INVALID_STATE)
+        if (initial_timestamp == map_matching::INVALID_STATE)
         {
-            return;
+            return sub_matchings;
         }
 
-        MatchingDebugInfo matching_debug(osrm::json::Logger::get());
-        matching_debug.initialize(candidates_list);
-
         engine_working_data.InitializeOrClearFirstThreadLocalStorage(
             super::facade->GetNumberOfNodes());
+        engine_working_data.InitializeOrClearSecondThreadLocalStorage(
+            super::facade->GetNumberOfNodes());
 
         QueryHeap &forward_heap = *(engine_working_data.forward_heap_1);
         QueryHeap &reverse_heap = *(engine_working_data.reverse_heap_1);
+        QueryHeap &forward_core_heap = *(engine_working_data.forward_heap_2);
+        QueryHeap &reverse_core_heap = *(engine_working_data.reverse_heap_2);
 
-        std::size_t breakage_begin = osrm::matching::INVALID_STATE;
+        std::size_t breakage_begin = map_matching::INVALID_STATE;
         std::vector<std::size_t> split_points;
         std::vector<std::size_t> prev_unbroken_timestamps;
         prev_unbroken_timestamps.reserve(candidates_list.size());
@@ -173,17 +191,17 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
             }
             else
             {
-                trace_split = trace_split || (t - prev_unbroken_timestamps.back() >
-                                              osrm::matching::MAX_BROKEN_STATES);
+                trace_split =
+                    trace_split || (t - prev_unbroken_timestamps.back() > MAX_BROKEN_STATES);
             }
 
             if (trace_split)
             {
                 std::size_t split_index = t;
-                if (breakage_begin != osrm::matching::INVALID_STATE)
+                if (breakage_begin != map_matching::INVALID_STATE)
                 {
                     split_index = breakage_begin;
-                    breakage_begin = osrm::matching::INVALID_STATE;
+                    breakage_begin = map_matching::INVALID_STATE;
                 }
                 split_points.push_back(split_index);
 
@@ -191,7 +209,7 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
                 model.clear(split_index);
                 std::size_t new_start = model.initialize(split_index);
                 // no new start was found -> stop viterbi calculation
-                if (new_start == osrm::matching::INVALID_STATE)
+                if (new_start == map_matching::INVALID_STATE)
                 {
                     break;
                 }
@@ -214,28 +232,28 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
 
             auto &current_viterbi = model.viterbi[t];
             auto &current_pruned = model.pruned[t];
-            auto &current_suspicious = model.suspicious[t];
             auto &current_parents = model.parents[t];
-            auto &current_lengths = model.path_lengths[t];
+            auto &current_lengths = model.path_distances[t];
             const auto &current_timestamps_list = candidates_list[t];
             const auto &current_coordinate = trace_coordinates[t];
 
-            const auto haversine_distance = coordinate_calculation::haversine_distance(prev_coordinate, current_coordinate);
+            const auto haversine_distance = util::coordinate_calculation::haversineDistance(
+                prev_coordinate, current_coordinate);
+            // assumes minumum of 0.1 m/s
+            const int duration_uppder_bound =
+                ((haversine_distance + max_distance_delta) * 0.25) * 10;
 
             // compute d_t for this timestamp and the next one
-            for (const auto s : osrm::irange<std::size_t>(0u, prev_viterbi.size()))
+            for (const auto s : util::irange<std::size_t>(0u, prev_viterbi.size()))
             {
                 if (prev_pruned[s])
                 {
                     continue;
                 }
 
-                for (const auto s_prime : osrm::irange<std::size_t>(0u, current_viterbi.size()))
+                for (const auto s_prime : util::irange<std::size_t>(0u, current_viterbi.size()))
                 {
-                    // how likely is candidate s_prime at time t to be emitted?
-                    // FIXME this can be pre-computed
-                    const double emission_pr =
-                        emission_log_probability(candidates_list[t][s_prime].distance);
+                    const double emission_pr = emission_log_probabilities[t][s_prime];
                     double new_value = prev_viterbi[s] + emission_pr;
                     if (current_viterbi[s_prime] > new_value)
                     {
@@ -245,11 +263,25 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
                     forward_heap.Clear();
                     reverse_heap.Clear();
 
-                    // get distance diff between loc1/2 and locs/s_prime
-                    const auto network_distance = super::get_network_distance(
-                        forward_heap, reverse_heap, prev_unbroken_timestamps_list[s].phantom_node,
-                        current_timestamps_list[s_prime].phantom_node);
+                    double network_distance;
+                    if (super::facade->GetCoreSize() > 0)
+                    {
+                        forward_core_heap.Clear();
+                        reverse_core_heap.Clear();
+                        network_distance = super::GetNetworkDistanceWithCore(
+                            forward_heap, reverse_heap, forward_core_heap, reverse_core_heap,
+                            prev_unbroken_timestamps_list[s].phantom_node,
+                            current_timestamps_list[s_prime].phantom_node, duration_uppder_bound);
+                    }
+                    else
+                    {
+                        network_distance = super::GetNetworkDistance(
+                            forward_heap, reverse_heap,
+                            prev_unbroken_timestamps_list[s].phantom_node,
+                            current_timestamps_list[s_prime].phantom_node);
+                    }
 
+                    // get distance diff between loc1/2 and locs/s_prime
                     const auto d_t = std::abs(network_distance - haversine_distance);
 
                     // very low probability transition -> prune
@@ -261,17 +293,12 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
                     const double transition_pr = transition_log_probability(d_t);
                     new_value += transition_pr;
 
-                    matching_debug.add_transition_info(prev_unbroken_timestamp, t, s, s_prime,
-                                                       prev_viterbi[s], emission_pr, transition_pr,
-                                                       network_distance, haversine_distance);
-
                     if (new_value > current_viterbi[s_prime])
                     {
                         current_viterbi[s_prime] = new_value;
                         current_parents[s_prime] = std::make_pair(prev_unbroken_timestamp, s);
                         current_lengths[s_prime] = network_distance;
                         current_pruned[s_prime] = false;
-                        current_suspicious[s_prime] = d_t > osrm::matching::SUSPICIOUS_DISTANCE_DELTA;
                         model.breakage[t] = false;
                     }
                 }
@@ -295,8 +322,6 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
             }
         }
 
-        matching_debug.set_viterbi(model.viterbi, model.pruned, model.suspicious);
-
         if (!prev_unbroken_timestamps.empty())
         {
             split_points.push_back(prev_unbroken_timestamps.back() + 1);
@@ -305,7 +330,7 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
         std::size_t sub_matching_begin = initial_timestamp;
         for (const auto sub_matching_end : split_points)
         {
-            osrm::matching::SubMatching matching;
+            map_matching::SubMatching matching;
 
             std::size_t parent_timestamp_index = sub_matching_end - 1;
             while (parent_timestamp_index >= sub_matching_begin &&
@@ -313,8 +338,7 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
             {
                 --parent_timestamp_index;
             }
-            while (sub_matching_begin < sub_matching_end &&
-                   model.breakage[sub_matching_begin])
+            while (sub_matching_begin < sub_matching_end && model.breakage[sub_matching_begin])
             {
                 ++sub_matching_begin;
             }
@@ -359,27 +383,41 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
                 continue;
             }
 
-            matching.length = 0.0f;
-            matching.nodes.resize(reconstructed_indices.size());
-            matching.indices.resize(reconstructed_indices.size());
-            for (const auto i : osrm::irange<std::size_t>(0u, reconstructed_indices.size()))
+            auto matching_distance = 0.0;
+            auto trace_distance = 0.0;
+            matching.nodes.reserve(reconstructed_indices.size());
+            matching.indices.reserve(reconstructed_indices.size());
+            for (const auto idx : reconstructed_indices)
             {
-                const auto timestamp_index = reconstructed_indices[i].first;
-                const auto location_index = reconstructed_indices[i].second;
-
-                matching.indices[i] = timestamp_index;
-                matching.nodes[i] = candidates_list[timestamp_index][location_index].phantom_node;
-                matching.length += model.path_lengths[timestamp_index][location_index];
+                const auto timestamp_index = idx.first;
+                const auto location_index = idx.second;
 
-                matching_debug.add_chosen(timestamp_index, location_index);
+                matching.indices.push_back(timestamp_index);
+                matching.nodes.push_back(
+                    candidates_list[timestamp_index][location_index].phantom_node);
+                matching_distance += model.path_distances[timestamp_index][location_index];
             }
+            util::for_each_pair(
+                reconstructed_indices, [&trace_distance, &trace_coordinates](
+                                           const std::pair<std::size_t, std::size_t> &prev,
+                                           const std::pair<std::size_t, std::size_t> &curr)
+                {
+                    trace_distance += util::coordinate_calculation::haversineDistance(
+                        trace_coordinates[prev.first], trace_coordinates[curr.first]);
+                });
+
+            matching.confidence = confidence(trace_distance, matching_distance);
 
             sub_matchings.push_back(matching);
             sub_matching_begin = sub_matching_end;
         }
-        matching_debug.add_breakage(model.breakage);
+
+        return sub_matchings;
     }
 };
+}
+}
+}
 
 //[1] "Hidden Markov Map Matching Through Noise and Sparseness"; P. Newson and J. Krumm; 2009; ACM
 // GIS
diff --git a/include/engine/routing_algorithms/routing_base.hpp b/include/engine/routing_algorithms/routing_base.hpp
new file mode 100644
index 0000000..0a9b1f2
--- /dev/null
+++ b/include/engine/routing_algorithms/routing_base.hpp
@@ -0,0 +1,906 @@
+#ifndef ROUTING_BASE_HPP
+#define ROUTING_BASE_HPP
+
+#include "util/coordinate_calculation.hpp"
+#include "engine/internal_route_result.hpp"
+#include "engine/search_engine_data.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+#include "util/typedefs.hpp"
+
+#include <boost/assert.hpp>
+
+#include <cstddef>
+#include <cstdint>
+
+#include <algorithm>
+#include <iterator>
+#include <utility>
+#include <vector>
+#include <stack>
+#include <numeric>
+
+namespace osrm
+{
+namespace engine
+{
+
+namespace routing_algorithms
+{
+
+template <class DataFacadeT, class Derived> class BasicRoutingInterface
+{
+  private:
+    using EdgeData = typename DataFacadeT::EdgeData;
+
+  protected:
+    DataFacadeT *facade;
+
+  public:
+    explicit BasicRoutingInterface(DataFacadeT *facade) : facade(facade) {}
+    ~BasicRoutingInterface() {}
+
+    BasicRoutingInterface(const BasicRoutingInterface &) = delete;
+    BasicRoutingInterface &operator=(const BasicRoutingInterface &) = delete;
+
+    /*
+    min_edge_offset is needed in case we use multiple
+    nodes as start/target nodes with different (even negative) offsets.
+    In that case the termination criterion is not correct
+    anymore.
+
+    Example:
+    forward heap: a(-100), b(0),
+    reverse heap: c(0), d(100)
+
+    a --- d
+      \ /
+      / \
+    b --- c
+
+    This is equivalent to running a bi-directional Dijkstra on the following graph:
+
+        a --- d
+       /  \ /  \
+      y    x    z
+       \  / \  /
+        b --- c
+
+    The graph is constructed by inserting nodes y and z that are connected to the initial nodes
+    using edges (y, a) with weight -100, (y, b) with weight 0 and,
+    (d, z) with weight 100, (c, z) with weight 0 corresponding.
+    Since we are dealing with a graph that contains _negative_ edges,
+    we need to add an offset to the termination criterion.
+    */
+    void RoutingStep(SearchEngineData::QueryHeap &forward_heap,
+                     SearchEngineData::QueryHeap &reverse_heap,
+                     NodeID &middle_node_id,
+                     std::int32_t &upper_bound,
+                     std::int32_t min_edge_offset,
+                     const bool forward_direction,
+                     const bool stalling,
+                     const bool force_loop_forward,
+                     const bool force_loop_reverse) const
+    {
+        const NodeID node = forward_heap.DeleteMin();
+        const std::int32_t distance = forward_heap.GetKey(node);
+
+        if (reverse_heap.WasInserted(node))
+        {
+            const std::int32_t new_distance = reverse_heap.GetKey(node) + distance;
+            if (new_distance < upper_bound)
+            {
+                // if loops are forced, they are so at the source
+                if (new_distance >= 0 &&
+                    (!force_loop_forward || forward_heap.GetData(node).parent != node) &&
+                    (!force_loop_reverse || reverse_heap.GetData(node).parent != node))
+                {
+                    middle_node_id = node;
+                    upper_bound = new_distance;
+                }
+                else
+                {
+                    // check whether there is a loop present at the node
+                    for (const auto edge : facade->GetAdjacentEdgeRange(node))
+                    {
+                        const EdgeData &data = facade->GetEdgeData(edge);
+                        bool forward_directionFlag =
+                            (forward_direction ? data.forward : data.backward);
+                        if (forward_directionFlag)
+                        {
+                            const NodeID to = facade->GetTarget(edge);
+                            if (to == node)
+                            {
+                                const EdgeWeight edge_weight = data.distance;
+                                const std::int32_t loop_distance = new_distance + edge_weight;
+                                if (loop_distance >= 0 && loop_distance < upper_bound)
+                                {
+                                    middle_node_id = node;
+                                    upper_bound = loop_distance;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // make sure we don't terminate too early if we initialize the distance
+        // for the nodes in the forward heap with the forward/reverse offset
+        BOOST_ASSERT(min_edge_offset <= 0);
+        if (distance + min_edge_offset > upper_bound)
+        {
+            forward_heap.DeleteAll();
+            return;
+        }
+
+        // Stalling
+        if (stalling)
+        {
+            for (const auto edge : facade->GetAdjacentEdgeRange(node))
+            {
+                const EdgeData &data = facade->GetEdgeData(edge);
+                const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
+                if (reverse_flag)
+                {
+                    const NodeID to = facade->GetTarget(edge);
+                    const EdgeWeight edge_weight = data.distance;
+
+                    BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
+
+                    if (forward_heap.WasInserted(to))
+                    {
+                        if (forward_heap.GetKey(to) + edge_weight < distance)
+                        {
+                            return;
+                        }
+                    }
+                }
+            }
+        }
+
+        for (const auto edge : facade->GetAdjacentEdgeRange(node))
+        {
+            const EdgeData &data = facade->GetEdgeData(edge);
+            bool forward_directionFlag = (forward_direction ? data.forward : data.backward);
+            if (forward_directionFlag)
+            {
+
+                const NodeID to = facade->GetTarget(edge);
+                const EdgeWeight edge_weight = data.distance;
+
+                BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
+                const int to_distance = distance + edge_weight;
+
+                // New Node discovered -> Add to Heap + Node Info Storage
+                if (!forward_heap.WasInserted(to))
+                {
+                    forward_heap.Insert(to, to_distance, node);
+                }
+                // Found a shorter Path -> Update distance
+                else if (to_distance < forward_heap.GetKey(to))
+                {
+                    // new parent
+                    forward_heap.GetData(to).parent = node;
+                    forward_heap.DecreaseKey(to, to_distance);
+                }
+            }
+        }
+    }
+
+    inline EdgeWeight GetLoopWeight(NodeID node) const
+    {
+        EdgeWeight loop_weight = INVALID_EDGE_WEIGHT;
+        for (auto edge : facade->GetAdjacentEdgeRange(node))
+        {
+            const auto &data = facade->GetEdgeData(edge);
+            if (data.forward)
+            {
+                const NodeID to = facade->GetTarget(edge);
+                if (to == node)
+                {
+                    loop_weight = std::min(loop_weight, data.distance);
+                }
+            }
+        }
+        return loop_weight;
+    }
+
+    template <typename RandomIter>
+    void UnpackPath(RandomIter packed_path_begin,
+                    RandomIter packed_path_end,
+                    const PhantomNodes &phantom_node_pair,
+                    std::vector<PathData> &unpacked_path) const
+    {
+        const bool start_traversed_in_reverse =
+            (*packed_path_begin != phantom_node_pair.source_phantom.forward_segment_id.id);
+        const bool target_traversed_in_reverse =
+            (*std::prev(packed_path_end) != phantom_node_pair.target_phantom.forward_segment_id.id);
+
+        BOOST_ASSERT(std::distance(packed_path_begin, packed_path_end) > 0);
+        std::stack<std::pair<NodeID, NodeID>> recursion_stack;
+
+        // We have to push the path in reverse order onto the stack because it's LIFO.
+        for (auto current = std::prev(packed_path_end); current != packed_path_begin;
+             current = std::prev(current))
+        {
+            recursion_stack.emplace(*std::prev(current), *current);
+        }
+
+        std::pair<NodeID, NodeID> edge;
+        while (!recursion_stack.empty())
+        {
+            // edge.first         edge.second
+            //     *------------------>*
+            //            edge_id
+            edge = recursion_stack.top();
+            recursion_stack.pop();
+
+            // Contraction might introduce double edges by inserting shortcuts
+            // this searching for the smallest upwards edge found by the forward search
+            EdgeID smaller_edge_id = SPECIAL_EDGEID;
+            EdgeWeight edge_weight = std::numeric_limits<EdgeWeight>::max();
+            for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
+            {
+                const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
+                if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
+                    facade->GetEdgeData(edge_id).forward)
+                {
+                    smaller_edge_id = edge_id;
+                    edge_weight = weight;
+                }
+            }
+
+            // edge.first         edge.second
+            //     *<------------------*
+            //            edge_id
+            // if we don't find a forward edge, this edge must have been an downwards edge
+            // found by the reverse search.
+            if (SPECIAL_EDGEID == smaller_edge_id)
+            {
+                for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
+                {
+                    const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
+                    if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
+                        facade->GetEdgeData(edge_id).backward)
+                    {
+                        smaller_edge_id = edge_id;
+                        edge_weight = weight;
+                    }
+                }
+            }
+            BOOST_ASSERT_MSG(edge_weight != INVALID_EDGE_WEIGHT, "edge id invalid");
+
+            const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
+            if (ed.shortcut)
+            { // unpack
+                const NodeID middle_node_id = ed.id;
+                // again, we need to this in reversed order
+                recursion_stack.emplace(middle_node_id, edge.second);
+                recursion_stack.emplace(edge.first, middle_node_id);
+            }
+            else
+            {
+                BOOST_ASSERT_MSG(!ed.shortcut, "original edge flagged as shortcut");
+                unsigned name_index = facade->GetNameIndexFromEdgeID(ed.id);
+                const auto turn_instruction = facade->GetTurnInstructionForEdgeID(ed.id);
+                const extractor::TravelMode travel_mode =
+                    (unpacked_path.empty() && start_traversed_in_reverse)
+                        ? phantom_node_pair.source_phantom.backward_travel_mode
+                        : facade->GetTravelModeForEdgeID(ed.id);
+
+                std::vector<NodeID> id_vector;
+                facade->GetUncompressedGeometry(facade->GetGeometryIndexForEdgeID(ed.id),
+                                                id_vector);
+                BOOST_ASSERT(id_vector.size() > 0);
+
+                std::vector<EdgeWeight> weight_vector;
+                facade->GetUncompressedWeights(facade->GetGeometryIndexForEdgeID(ed.id),
+                                               weight_vector);
+                BOOST_ASSERT(weight_vector.size() > 0);
+
+                auto total_weight = std::accumulate(weight_vector.begin(), weight_vector.end(), 0);
+
+                BOOST_ASSERT(weight_vector.size() == id_vector.size());
+                // ed.distance should be total_weight + penalties (turn, stop, etc)
+                BOOST_ASSERT(ed.distance >= total_weight);
+                const bool is_first_segment = unpacked_path.empty();
+
+                const std::size_t start_index =
+                    (is_first_segment
+                         ? ((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 std::size_t end_index = id_vector.size();
+
+                BOOST_ASSERT(start_index >= 0);
+                BOOST_ASSERT(start_index < end_index);
+                for (std::size_t i = start_index; i < end_index; ++i)
+                {
+                    unpacked_path.push_back(
+                        PathData{id_vector[i],
+                                 name_index,
+                                 weight_vector[i],
+                                 extractor::guidance::TurnInstruction::NO_TURN(),
+                                 travel_mode});
+                }
+                BOOST_ASSERT(unpacked_path.size() > 0);
+                unpacked_path.back().turn_instruction = turn_instruction;
+                unpacked_path.back().duration_until_turn += (ed.distance - total_weight);
+            }
+        }
+        std::size_t start_index = 0, end_index = 0;
+        std::vector<unsigned> id_vector;
+        std::vector<EdgeWeight> weight_vector;
+        const bool is_local_path = (phantom_node_pair.source_phantom.forward_packed_geometry_id ==
+                                    phantom_node_pair.target_phantom.forward_packed_geometry_id) &&
+                                   unpacked_path.empty();
+
+        if (target_traversed_in_reverse)
+        {
+            facade->GetUncompressedGeometry(
+                phantom_node_pair.target_phantom.reverse_packed_geometry_id, id_vector);
+
+            facade->GetUncompressedWeights(
+                phantom_node_pair.target_phantom.reverse_packed_geometry_id, weight_vector);
+
+            if (is_local_path)
+            {
+                start_index =
+                    id_vector.size() - phantom_node_pair.source_phantom.fwd_segment_position - 1;
+            }
+            end_index = id_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position - 1;
+        }
+        else
+        {
+            if (is_local_path)
+            {
+                start_index = phantom_node_pair.source_phantom.fwd_segment_position;
+            }
+            end_index = phantom_node_pair.target_phantom.fwd_segment_position;
+            facade->GetUncompressedGeometry(
+                phantom_node_pair.target_phantom.forward_packed_geometry_id, id_vector);
+
+            facade->GetUncompressedWeights(
+                phantom_node_pair.target_phantom.forward_packed_geometry_id, weight_vector);
+        }
+
+        // Given the following compressed geometry:
+        // U---v---w---x---y---Z
+        //    s           t
+        // s: fwd_segment 0
+        // t: fwd_segment 3
+        // -> (U, v), (v, w), (w, x)
+        // note that (x, t) is _not_ included but needs to be added later.
+        BOOST_ASSERT(start_index <= end_index);
+        for (std::size_t i = start_index; i != end_index; ++i)
+        {
+            BOOST_ASSERT(i < id_vector.size());
+            BOOST_ASSERT(phantom_node_pair.target_phantom.forward_travel_mode > 0);
+            unpacked_path.push_back(
+                PathData{id_vector[i],
+                         phantom_node_pair.target_phantom.name_id,
+                         weight_vector[i],
+                         extractor::guidance::TurnInstruction::NO_TURN(),
+                         target_traversed_in_reverse
+                             ? phantom_node_pair.target_phantom.backward_travel_mode
+                             : phantom_node_pair.target_phantom.forward_travel_mode});
+        }
+
+        if (unpacked_path.size() > 0)
+        {
+            const auto source_weight = start_traversed_in_reverse
+                                           ? phantom_node_pair.source_phantom.reverse_weight
+                                           : phantom_node_pair.source_phantom.forward_weight;
+            // The above code will create segments for (v, w), (w,x), (x, y) and (y, Z).
+            // However the first segment duration needs to be adjusted to the fact that the source
+            // phantom is in the middle of the segment. We do this by subtracting v--s from the
+            // duration.
+            BOOST_ASSERT(unpacked_path.front().duration_until_turn >= source_weight);
+            unpacked_path.front().duration_until_turn -= source_weight;
+        }
+
+        // there is no equivalent to a node-based node in an edge-expanded graph.
+        // two equivalent routes may start (or end) at different node-based edges
+        // as they are added with the offset how much "distance" on the edge
+        // has already been traversed. Depending on offset one needs to remove
+        // the last node.
+        if (unpacked_path.size() > 1)
+        {
+            const std::size_t last_index = unpacked_path.size() - 1;
+            const std::size_t second_to_last_index = last_index - 1;
+
+            if (unpacked_path[last_index].turn_via_node ==
+                unpacked_path[second_to_last_index].turn_via_node)
+            {
+                unpacked_path.pop_back();
+            }
+            BOOST_ASSERT(!unpacked_path.empty());
+        }
+    }
+
+    void UnpackEdge(const NodeID s, const NodeID t, std::vector<NodeID> &unpacked_path) const
+    {
+        std::stack<std::pair<NodeID, NodeID>> recursion_stack;
+        recursion_stack.emplace(s, t);
+
+        std::pair<NodeID, NodeID> edge;
+        while (!recursion_stack.empty())
+        {
+            edge = recursion_stack.top();
+            recursion_stack.pop();
+
+            EdgeID smaller_edge_id = SPECIAL_EDGEID;
+            EdgeWeight edge_weight = std::numeric_limits<EdgeWeight>::max();
+            for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
+            {
+                const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
+                if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
+                    facade->GetEdgeData(edge_id).forward)
+                {
+                    smaller_edge_id = edge_id;
+                    edge_weight = weight;
+                }
+            }
+
+            if (SPECIAL_EDGEID == smaller_edge_id)
+            {
+                for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
+                {
+                    const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
+                    if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
+                        facade->GetEdgeData(edge_id).backward)
+                    {
+                        smaller_edge_id = edge_id;
+                        edge_weight = weight;
+                    }
+                }
+            }
+            BOOST_ASSERT_MSG(edge_weight != std::numeric_limits<EdgeWeight>::max(),
+                             "edge weight invalid");
+
+            const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
+            if (ed.shortcut)
+            { // unpack
+                const NodeID middle_node_id = ed.id;
+                // again, we need to this in reversed order
+                recursion_stack.emplace(middle_node_id, edge.second);
+                recursion_stack.emplace(edge.first, middle_node_id);
+            }
+            else
+            {
+                BOOST_ASSERT_MSG(!ed.shortcut, "edge must be shortcut");
+                unpacked_path.emplace_back(edge.first);
+            }
+        }
+        unpacked_path.emplace_back(t);
+    }
+
+    void RetrievePackedPathFromHeap(const SearchEngineData::QueryHeap &forward_heap,
+                                    const SearchEngineData::QueryHeap &reverse_heap,
+                                    const NodeID middle_node_id,
+                                    std::vector<NodeID> &packed_path) const
+    {
+        RetrievePackedPathFromSingleHeap(forward_heap, middle_node_id, packed_path);
+        std::reverse(packed_path.begin(), packed_path.end());
+        packed_path.emplace_back(middle_node_id);
+        RetrievePackedPathFromSingleHeap(reverse_heap, middle_node_id, packed_path);
+    }
+
+    void RetrievePackedPathFromSingleHeap(const SearchEngineData::QueryHeap &search_heap,
+                                          const NodeID middle_node_id,
+                                          std::vector<NodeID> &packed_path) const
+    {
+        NodeID current_node_id = middle_node_id;
+        while (current_node_id != search_heap.GetData(current_node_id).parent)
+        {
+            current_node_id = search_heap.GetData(current_node_id).parent;
+            packed_path.emplace_back(current_node_id);
+        }
+    }
+
+    // assumes that heaps are already setup correctly.
+    // ATTENTION: This only works if no additional offset is supplied next to the Phantom Node
+    // Offsets.
+    // In case additional offsets are supplied, you might have to force a loop first.
+    // A forced loop might be necessary, if source and target are on the same segment.
+    // If this is the case and the offsets of the respective direction are larger for the source
+    // than the target
+    // then a force loop is required (e.g. source_phantom.forward_segment_id ==
+    // target_phantom.forward_segment_id
+    // && source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
+    // requires
+    // a force loop, if the heaps have been initialized with positive offsets.
+    void Search(SearchEngineData::QueryHeap &forward_heap,
+                SearchEngineData::QueryHeap &reverse_heap,
+                std::int32_t &distance,
+                std::vector<NodeID> &packed_leg,
+                const bool force_loop_forward,
+                const bool force_loop_reverse,
+                const int duration_upper_bound = INVALID_EDGE_WEIGHT) const
+    {
+        NodeID middle = SPECIAL_NODEID;
+        distance = duration_upper_bound;
+
+        // get offset to account for offsets on phantom nodes on compressed edges
+        const auto min_edge_offset = std::min(0, forward_heap.MinKey());
+        BOOST_ASSERT(min_edge_offset <= 0);
+        // we only every insert negative offsets for nodes in the forward heap
+        BOOST_ASSERT(reverse_heap.MinKey() >= 0);
+
+        // run two-Target Dijkstra routing step.
+        const constexpr bool STALLING_ENABLED = true;
+        while (0 < (forward_heap.Size() + reverse_heap.Size()))
+        {
+            if (!forward_heap.Empty())
+            {
+                RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset, true,
+                            STALLING_ENABLED, force_loop_forward, force_loop_reverse);
+            }
+            if (!reverse_heap.Empty())
+            {
+                RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset, false,
+                            STALLING_ENABLED, force_loop_reverse, force_loop_forward);
+            }
+        }
+
+        // No path found for both target nodes?
+        if (duration_upper_bound <= distance || SPECIAL_NODEID == middle)
+        {
+            distance = INVALID_EDGE_WEIGHT;
+            return;
+        }
+
+        // Was a paths over one of the forward/reverse nodes not found?
+        BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance),
+                         "no path found");
+
+        // make sure to correctly unpack loops
+        if (distance != forward_heap.GetKey(middle) + reverse_heap.GetKey(middle))
+        {
+            // self loop
+            BOOST_ASSERT(forward_heap.GetData(middle).parent == middle &&
+                         reverse_heap.GetData(middle).parent == middle);
+            packed_leg.push_back(middle);
+            packed_leg.push_back(middle);
+        }
+        else
+        {
+            RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
+        }
+    }
+
+    // assumes that heaps are already setup correctly.
+    // A forced loop might be necessary, if source and target are on the same segment.
+    // If this is the case and the offsets of the respective direction are larger for the source
+    // than the target
+    // then a force loop is required (e.g. source_phantom.forward_segment_id ==
+    // target_phantom.forward_segment_id
+    // && source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
+    // requires
+    // a force loop, if the heaps have been initialized with positive offsets.
+    void SearchWithCore(SearchEngineData::QueryHeap &forward_heap,
+                        SearchEngineData::QueryHeap &reverse_heap,
+                        SearchEngineData::QueryHeap &forward_core_heap,
+                        SearchEngineData::QueryHeap &reverse_core_heap,
+                        int &distance,
+                        std::vector<NodeID> &packed_leg,
+                        const bool force_loop_forward,
+                        const bool force_loop_reverse,
+                        int duration_upper_bound = INVALID_EDGE_WEIGHT) const
+    {
+        NodeID middle = SPECIAL_NODEID;
+        distance = duration_upper_bound;
+
+        std::vector<std::pair<NodeID, EdgeWeight>> forward_entry_points;
+        std::vector<std::pair<NodeID, EdgeWeight>> reverse_entry_points;
+
+        // get offset to account for offsets on phantom nodes on compressed edges
+        const auto min_edge_offset = std::min(0, forward_heap.MinKey());
+        // we only every insert negative offsets for nodes in the forward heap
+        BOOST_ASSERT(reverse_heap.MinKey() >= 0);
+
+        const constexpr bool STALLING_ENABLED = true;
+        // run two-Target Dijkstra routing step.
+        while (0 < (forward_heap.Size() + reverse_heap.Size()))
+        {
+            if (!forward_heap.Empty())
+            {
+                if (facade->IsCoreNode(forward_heap.Min()))
+                {
+                    const NodeID node = forward_heap.DeleteMin();
+                    const int key = forward_heap.GetKey(node);
+                    forward_entry_points.emplace_back(node, key);
+                }
+                else
+                {
+                    RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset, true,
+                                STALLING_ENABLED, force_loop_forward, force_loop_reverse);
+                }
+            }
+            if (!reverse_heap.Empty())
+            {
+                if (facade->IsCoreNode(reverse_heap.Min()))
+                {
+                    const NodeID node = reverse_heap.DeleteMin();
+                    const int key = reverse_heap.GetKey(node);
+                    reverse_entry_points.emplace_back(node, key);
+                }
+                else
+                {
+                    RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset,
+                                false, STALLING_ENABLED, force_loop_reverse, force_loop_forward);
+                }
+            }
+        }
+        // TODO check if unordered_set might be faster
+        // sort by id and increasing by distance
+        auto entry_point_comparator =
+            [](const std::pair<NodeID, EdgeWeight> &lhs, const std::pair<NodeID, EdgeWeight> &rhs)
+        {
+            return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second < rhs.second);
+        };
+        std::sort(forward_entry_points.begin(), forward_entry_points.end(), entry_point_comparator);
+        std::sort(reverse_entry_points.begin(), reverse_entry_points.end(), entry_point_comparator);
+
+        NodeID last_id = SPECIAL_NODEID;
+        forward_core_heap.Clear();
+        reverse_core_heap.Clear();
+        for (const auto &p : forward_entry_points)
+        {
+            if (p.first == last_id)
+            {
+                continue;
+            }
+            forward_core_heap.Insert(p.first, p.second, p.first);
+            last_id = p.first;
+        }
+        last_id = SPECIAL_NODEID;
+        for (const auto &p : reverse_entry_points)
+        {
+            if (p.first == last_id)
+            {
+                continue;
+            }
+            reverse_core_heap.Insert(p.first, p.second, p.first);
+            last_id = p.first;
+        }
+
+        // get offset to account for offsets on phantom nodes on compressed edges
+        int min_core_edge_offset = 0;
+        if (forward_core_heap.Size() > 0)
+        {
+            min_core_edge_offset = std::min(min_core_edge_offset, forward_core_heap.MinKey());
+        }
+        if (reverse_core_heap.Size() > 0 && reverse_core_heap.MinKey() < 0)
+        {
+            min_core_edge_offset = std::min(min_core_edge_offset, reverse_core_heap.MinKey());
+        }
+        BOOST_ASSERT(min_core_edge_offset <= 0);
+
+        // run two-target Dijkstra routing step on core with termination criterion
+        const constexpr bool STALLING_DISABLED = false;
+        while (0 < forward_core_heap.Size() && 0 < reverse_core_heap.Size() &&
+               distance > (forward_core_heap.MinKey() + reverse_core_heap.MinKey()))
+        {
+            RoutingStep(forward_core_heap, reverse_core_heap, middle, distance,
+                        min_core_edge_offset, true, STALLING_DISABLED, force_loop_forward,
+                        force_loop_reverse);
+
+            RoutingStep(reverse_core_heap, forward_core_heap, middle, distance,
+                        min_core_edge_offset, false, STALLING_DISABLED, force_loop_reverse,
+                        force_loop_forward);
+        }
+
+        // No path found for both target nodes?
+        if (duration_upper_bound <= distance || SPECIAL_NODEID == middle)
+        {
+            distance = INVALID_EDGE_WEIGHT;
+            return;
+        }
+
+        // Was a paths over one of the forward/reverse nodes not found?
+        BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance),
+                         "no path found");
+
+        // we need to unpack sub path from core heaps
+        if (facade->IsCoreNode(middle))
+        {
+            if (distance != forward_core_heap.GetKey(middle) + reverse_core_heap.GetKey(middle))
+            {
+                // self loop
+                BOOST_ASSERT(forward_core_heap.GetData(middle).parent == middle &&
+                             reverse_core_heap.GetData(middle).parent == middle);
+                packed_leg.push_back(middle);
+                packed_leg.push_back(middle);
+            }
+            else
+            {
+                std::vector<NodeID> packed_core_leg;
+                RetrievePackedPathFromHeap(forward_core_heap, reverse_core_heap, middle,
+                                           packed_core_leg);
+                BOOST_ASSERT(packed_core_leg.size() > 0);
+                RetrievePackedPathFromSingleHeap(forward_heap, packed_core_leg.front(), packed_leg);
+                std::reverse(packed_leg.begin(), packed_leg.end());
+                packed_leg.insert(packed_leg.end(), packed_core_leg.begin(), packed_core_leg.end());
+                RetrievePackedPathFromSingleHeap(reverse_heap, packed_core_leg.back(), packed_leg);
+            }
+        }
+        else
+        {
+            if (distance != forward_heap.GetKey(middle) + reverse_heap.GetKey(middle))
+            {
+                // self loop
+                BOOST_ASSERT(forward_heap.GetData(middle).parent == middle &&
+                             reverse_heap.GetData(middle).parent == middle);
+                packed_leg.push_back(middle);
+                packed_leg.push_back(middle);
+            }
+            else
+            {
+                RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
+            }
+        }
+    }
+
+    bool NeedsLoopForward(const PhantomNode &source_phantom,
+                          const PhantomNode &target_phantom) const
+    {
+        return source_phantom.forward_segment_id.enabled &&
+               target_phantom.forward_segment_id.enabled &&
+               source_phantom.forward_segment_id.id == target_phantom.forward_segment_id.id &&
+               source_phantom.GetForwardWeightPlusOffset() >
+                   target_phantom.GetForwardWeightPlusOffset();
+    }
+
+    bool NeedsLoopBackwards(const PhantomNode &source_phantom,
+                            const PhantomNode &target_phantom) const
+    {
+        return source_phantom.reverse_segment_id.enabled &&
+               target_phantom.reverse_segment_id.enabled &&
+               source_phantom.reverse_segment_id.id == target_phantom.reverse_segment_id.id &&
+               source_phantom.GetReverseWeightPlusOffset() >
+                   target_phantom.GetReverseWeightPlusOffset();
+    }
+
+    double GetPathDistance(const std::vector<NodeID> &packed_path,
+                           const PhantomNode &source_phantom,
+                           const PhantomNode &target_phantom) const
+    {
+        std::vector<PathData> unpacked_path;
+        PhantomNodes nodes;
+        nodes.source_phantom = source_phantom;
+        nodes.target_phantom = target_phantom;
+        UnpackPath(packed_path.begin(), packed_path.end(), nodes, unpacked_path);
+
+        util::Coordinate previous_coordinate = source_phantom.location;
+        util::Coordinate current_coordinate;
+        double distance = 0;
+        for (const auto &p : unpacked_path)
+        {
+            current_coordinate = facade->GetCoordinateOfNode(p.turn_via_node);
+            distance += util::coordinate_calculation::haversineDistance(previous_coordinate,
+                                                                        current_coordinate);
+            previous_coordinate = current_coordinate;
+        }
+        distance += util::coordinate_calculation::haversineDistance(previous_coordinate,
+                                                                    target_phantom.location);
+        return distance;
+    }
+
+    // Requires the heaps for be empty
+    // If heaps should be adjusted to be initialized outside of this function,
+    // the addition of force_loop parameters might be required
+    double GetNetworkDistanceWithCore(SearchEngineData::QueryHeap &forward_heap,
+                                      SearchEngineData::QueryHeap &reverse_heap,
+                                      SearchEngineData::QueryHeap &forward_core_heap,
+                                      SearchEngineData::QueryHeap &reverse_core_heap,
+                                      const PhantomNode &source_phantom,
+                                      const PhantomNode &target_phantom,
+                                      int duration_upper_bound = INVALID_EDGE_WEIGHT) const
+    {
+        BOOST_ASSERT(forward_heap.Empty());
+        BOOST_ASSERT(reverse_heap.Empty());
+
+        if (source_phantom.forward_segment_id.enabled)
+        {
+            forward_heap.Insert(source_phantom.forward_segment_id.id,
+                                -source_phantom.GetForwardWeightPlusOffset(),
+                                source_phantom.forward_segment_id.id);
+        }
+        if (source_phantom.reverse_segment_id.enabled)
+        {
+            forward_heap.Insert(source_phantom.reverse_segment_id.id,
+                                -source_phantom.GetReverseWeightPlusOffset(),
+                                source_phantom.reverse_segment_id.id);
+        }
+
+        if (target_phantom.forward_segment_id.enabled)
+        {
+            reverse_heap.Insert(target_phantom.forward_segment_id.id,
+                                target_phantom.GetForwardWeightPlusOffset(),
+                                target_phantom.forward_segment_id.id);
+        }
+        if (target_phantom.reverse_segment_id.enabled)
+        {
+            reverse_heap.Insert(target_phantom.reverse_segment_id.id,
+                                target_phantom.GetReverseWeightPlusOffset(),
+                                target_phantom.reverse_segment_id.id);
+        }
+
+        const bool constexpr DO_NOT_FORCE_LOOPS =
+            false; // prevents forcing of loops, since offsets are set correctly
+
+        int duration = INVALID_EDGE_WEIGHT;
+        std::vector<NodeID> packed_path;
+        SearchWithCore(forward_heap, reverse_heap, forward_core_heap, reverse_core_heap, duration,
+                       packed_path, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS, duration_upper_bound);
+
+        double distance = std::numeric_limits<double>::max();
+        if (duration != INVALID_EDGE_WEIGHT)
+        {
+            return GetPathDistance(packed_path, source_phantom, target_phantom);
+        }
+        return distance;
+    }
+
+    // Requires the heaps for be empty
+    // If heaps should be adjusted to be initialized outside of this function,
+    // the addition of force_loop parameters might be required
+    double GetNetworkDistance(SearchEngineData::QueryHeap &forward_heap,
+                              SearchEngineData::QueryHeap &reverse_heap,
+                              const PhantomNode &source_phantom,
+                              const PhantomNode &target_phantom,
+                              int duration_upper_bound = INVALID_EDGE_WEIGHT) const
+    {
+        BOOST_ASSERT(forward_heap.Empty());
+        BOOST_ASSERT(reverse_heap.Empty());
+
+        if (source_phantom.forward_segment_id.enabled)
+        {
+            forward_heap.Insert(source_phantom.forward_segment_id.id,
+                                -source_phantom.GetForwardWeightPlusOffset(),
+                                source_phantom.forward_segment_id.id);
+        }
+        if (source_phantom.reverse_segment_id.enabled)
+        {
+            forward_heap.Insert(source_phantom.reverse_segment_id.id,
+                                -source_phantom.GetReverseWeightPlusOffset(),
+                                source_phantom.reverse_segment_id.id);
+        }
+
+        if (target_phantom.forward_segment_id.enabled)
+        {
+            reverse_heap.Insert(target_phantom.forward_segment_id.id,
+                                target_phantom.GetForwardWeightPlusOffset(),
+                                target_phantom.forward_segment_id.id);
+        }
+        if (target_phantom.reverse_segment_id.enabled)
+        {
+            reverse_heap.Insert(target_phantom.reverse_segment_id.id,
+                                target_phantom.GetReverseWeightPlusOffset(),
+                                target_phantom.reverse_segment_id.id);
+        }
+
+        const bool constexpr DO_NOT_FORCE_LOOPS =
+            false; // prevents forcing of loops, since offsets are set correctly
+
+        int duration = INVALID_EDGE_WEIGHT;
+        std::vector<NodeID> packed_path;
+        Search(forward_heap, reverse_heap, duration, packed_path, DO_NOT_FORCE_LOOPS,
+               DO_NOT_FORCE_LOOPS, duration_upper_bound);
+
+        if (duration == INVALID_EDGE_WEIGHT)
+        {
+            return std::numeric_limits<double>::max();
+        }
+
+        return GetPathDistance(packed_path, source_phantom, target_phantom);
+    }
+};
+}
+}
+}
+
+#endif // ROUTING_BASE_HPP
diff --git a/routing_algorithms/shortest_path.hpp b/include/engine/routing_algorithms/shortest_path.hpp
similarity index 58%
rename from routing_algorithms/shortest_path.hpp
rename to include/engine/routing_algorithms/shortest_path.hpp
index 601e394..9720931 100644
--- a/routing_algorithms/shortest_path.hpp
+++ b/include/engine/routing_algorithms/shortest_path.hpp
@@ -1,41 +1,22 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 SHORTEST_PATH_HPP
 #define SHORTEST_PATH_HPP
 
-#include "../typedefs.h"
+#include "util/typedefs.hpp"
 
-#include "routing_base.hpp"
+#include "engine/routing_algorithms/routing_base.hpp"
 
-#include "../data_structures/search_engine_data.hpp"
-#include "../util/integer_range.hpp"
+#include "engine/search_engine_data.hpp"
+#include "util/integer_range.hpp"
 
 #include <boost/assert.hpp>
+#include <boost/optional.hpp>
+
+namespace osrm
+{
+namespace engine
+{
+namespace routing_algorithms
+{
 
 template <class DataFacadeT>
 class ShortestPathRouting final
@@ -44,6 +25,7 @@ class ShortestPathRouting final
     using super = BasicRoutingInterface<DataFacadeT, ShortestPathRouting<DataFacadeT>>;
     using QueryHeap = SearchEngineData::QueryHeap;
     SearchEngineData &engine_working_data;
+    const static constexpr bool DO_NOT_FORCE_LOOP = false;
 
   public:
     ShortestPathRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
@@ -57,6 +39,8 @@ class ShortestPathRouting final
     // searches source forward/reverse -> target forward/reverse
     void SearchWithUTurn(QueryHeap &forward_heap,
                          QueryHeap &reverse_heap,
+                         QueryHeap &forward_core_heap,
+                         QueryHeap &reverse_core_heap,
                          const bool search_from_forward_node,
                          const bool search_from_reverse_node,
                          const bool search_to_forward_node,
@@ -72,136 +56,57 @@ class ShortestPathRouting final
         reverse_heap.Clear();
         if (search_from_forward_node)
         {
-            forward_heap.Insert(source_phantom.forward_node_id,
+            forward_heap.Insert(source_phantom.forward_segment_id.id,
                                 total_distance_to_forward -
                                     source_phantom.GetForwardWeightPlusOffset(),
-                                source_phantom.forward_node_id);
+                                source_phantom.forward_segment_id.id);
         }
         if (search_from_reverse_node)
         {
-            forward_heap.Insert(source_phantom.reverse_node_id,
+            forward_heap.Insert(source_phantom.reverse_segment_id.id,
                                 total_distance_to_reverse -
                                     source_phantom.GetReverseWeightPlusOffset(),
-                                source_phantom.reverse_node_id);
+                                source_phantom.reverse_segment_id.id);
         }
         if (search_to_forward_node)
         {
-            reverse_heap.Insert(target_phantom.forward_node_id,
+            reverse_heap.Insert(target_phantom.forward_segment_id.id,
                                 target_phantom.GetForwardWeightPlusOffset(),
-                                target_phantom.forward_node_id);
+                                target_phantom.forward_segment_id.id);
         }
         if (search_to_reverse_node)
         {
-            reverse_heap.Insert(target_phantom.reverse_node_id,
+            reverse_heap.Insert(target_phantom.reverse_segment_id.id,
                                 target_phantom.GetReverseWeightPlusOffset(),
-                                target_phantom.reverse_node_id);
+                                target_phantom.reverse_segment_id.id);
         }
+
         BOOST_ASSERT(forward_heap.Size() > 0);
         BOOST_ASSERT(reverse_heap.Size() > 0);
-        super::Search(forward_heap, reverse_heap, new_total_distance, leg_packed_path);
-    }
 
-    // If source and target are reverse on a oneway we need to find a path
-    // that connects the two. This is _not_ the shortest path in our model,
-    // as source and target are on the same edge based node.
-    // We force a detour by inserting "virtaul vias", which means we search a path
-    // from all nodes that are connected by outgoing edges to all nodes that are connected by
-    // incoming edges.
-    // ------^
-    // |     ^source
-    // |     ^
-    // |     ^target
-    // ------^
-    void SearchLoop(QueryHeap &forward_heap,
-                QueryHeap &reverse_heap,
-                const bool search_forward_node,
-                const bool search_reverse_node,
-                const PhantomNode &source_phantom,
-                const PhantomNode &target_phantom,
-                const int total_distance_to_forward,
-                const int total_distance_to_reverse,
-                int &new_total_distance_to_forward,
-                int &new_total_distance_to_reverse,
-                std::vector<NodeID> &leg_packed_path_forward,
-                std::vector<NodeID> &leg_packed_path_reverse) const
-    {
-        BOOST_ASSERT(source_phantom.forward_node_id == target_phantom.forward_node_id);
-        BOOST_ASSERT(source_phantom.reverse_node_id == target_phantom.reverse_node_id);
-
-        if (search_forward_node)
+        // this is only relevent if source and target are on the same compressed edge
+        auto is_oneway_source = !(search_from_forward_node && search_from_reverse_node);
+        auto is_oneway_target = !(search_to_forward_node && search_to_reverse_node);
+        // we only enable loops here if we can't search from forward to backward node
+        auto needs_loop_forwad =
+            is_oneway_source && super::NeedsLoopForward(source_phantom, target_phantom);
+        auto needs_loop_backwards =
+            is_oneway_target && super::NeedsLoopBackwards(source_phantom, target_phantom);
+        if (super::facade->GetCoreSize() > 0)
         {
-            forward_heap.Clear();
-            reverse_heap.Clear();
-
-            auto node_id = source_phantom.forward_node_id;
-
-            for (const auto edge : super::facade->GetAdjacentEdgeRange(node_id))
-            {
-                const auto& data = super::facade->GetEdgeData(edge);
-                if (data.forward)
-                {
-                    auto target = super::facade->GetTarget(edge);
-                    auto offset = total_distance_to_forward + data.distance - source_phantom.GetForwardWeightPlusOffset();
-                    forward_heap.Insert(target, offset, target);
-                }
-
-                if (data.backward)
-                {
-                    auto target = super::facade->GetTarget(edge);
-                    auto offset = data.distance + target_phantom.GetForwardWeightPlusOffset();
-                    reverse_heap.Insert(target, offset, target);
-                }
-            }
-
-            BOOST_ASSERT(forward_heap.Size() > 0);
-            BOOST_ASSERT(reverse_heap.Size() > 0);
-            super::Search(forward_heap, reverse_heap, new_total_distance_to_forward,
-                          leg_packed_path_forward);
-
-            // insert node to both endpoints to close the leg
-            leg_packed_path_forward.push_back(node_id);
-            std::reverse(leg_packed_path_forward.begin(), leg_packed_path_forward.end());
-            leg_packed_path_forward.push_back(node_id);
-            std::reverse(leg_packed_path_forward.begin(), leg_packed_path_forward.end());
+            forward_core_heap.Clear();
+            reverse_core_heap.Clear();
+            BOOST_ASSERT(forward_core_heap.Size() == 0);
+            BOOST_ASSERT(reverse_core_heap.Size() == 0);
+            super::SearchWithCore(forward_heap, reverse_heap, forward_core_heap, reverse_core_heap,
+                                  new_total_distance, leg_packed_path, needs_loop_forwad,
+                                  needs_loop_backwards);
         }
-
-        if (search_reverse_node)
+        else
         {
-            forward_heap.Clear();
-            reverse_heap.Clear();
-
-            auto node_id = source_phantom.reverse_node_id;
-
-            for (const auto edge : super::facade->GetAdjacentEdgeRange(node_id))
-            {
-                const auto& data = super::facade->GetEdgeData(edge);
-                if (data.forward)
-                {
-                    auto target = super::facade->GetTarget(edge);
-                    auto offset = total_distance_to_reverse + data.distance - source_phantom.GetReverseWeightPlusOffset();
-                    forward_heap.Insert(target, offset, target);
-                }
-
-                if (data.backward)
-                {
-                    auto target = super::facade->GetTarget(edge);
-                    auto offset = data.distance + target_phantom.GetReverseWeightPlusOffset();
-                    reverse_heap.Insert(target, offset, target);
-                }
-            }
-
-            BOOST_ASSERT(forward_heap.Size() > 0);
-            BOOST_ASSERT(reverse_heap.Size() > 0);
-            super::Search(forward_heap, reverse_heap, new_total_distance_to_reverse,
-                          leg_packed_path_reverse);
-
-            // insert node to both endpoints to close the leg
-            leg_packed_path_reverse.push_back(node_id);
-            std::reverse(leg_packed_path_reverse.begin(), leg_packed_path_reverse.end());
-            leg_packed_path_reverse.push_back(node_id);
-            std::reverse(leg_packed_path_reverse.begin(), leg_packed_path_reverse.end());
+            super::Search(forward_heap, reverse_heap, new_total_distance, leg_packed_path,
+                          needs_loop_forwad, needs_loop_backwards);
         }
-
     }
 
     // searches shortest path between:
@@ -209,6 +114,8 @@ class ShortestPathRouting final
     // source forward/reverse -> target reverse
     void Search(QueryHeap &forward_heap,
                 QueryHeap &reverse_heap,
+                QueryHeap &forward_core_heap,
+                QueryHeap &reverse_core_heap,
                 const bool search_from_forward_node,
                 const bool search_from_reverse_node,
                 const bool search_to_forward_node,
@@ -226,55 +133,87 @@ class ShortestPathRouting final
         {
             forward_heap.Clear();
             reverse_heap.Clear();
-            reverse_heap.Insert(target_phantom.forward_node_id,
+            reverse_heap.Insert(target_phantom.forward_segment_id.id,
                                 target_phantom.GetForwardWeightPlusOffset(),
-                                target_phantom.forward_node_id);
+                                target_phantom.forward_segment_id.id);
 
             if (search_from_forward_node)
             {
-                forward_heap.Insert(source_phantom.forward_node_id,
+                forward_heap.Insert(source_phantom.forward_segment_id.id,
                                     total_distance_to_forward -
                                         source_phantom.GetForwardWeightPlusOffset(),
-                                    source_phantom.forward_node_id);
+                                    source_phantom.forward_segment_id.id);
             }
             if (search_from_reverse_node)
             {
-                forward_heap.Insert(source_phantom.reverse_node_id,
+                forward_heap.Insert(source_phantom.reverse_segment_id.id,
                                     total_distance_to_reverse -
                                         source_phantom.GetReverseWeightPlusOffset(),
-                                    source_phantom.reverse_node_id);
+                                    source_phantom.reverse_segment_id.id);
             }
             BOOST_ASSERT(forward_heap.Size() > 0);
             BOOST_ASSERT(reverse_heap.Size() > 0);
-            super::Search(forward_heap, reverse_heap, new_total_distance_to_forward,
-                          leg_packed_path_forward);
+
+            if (super::facade->GetCoreSize() > 0)
+            {
+                forward_core_heap.Clear();
+                reverse_core_heap.Clear();
+                BOOST_ASSERT(forward_core_heap.Size() == 0);
+                BOOST_ASSERT(reverse_core_heap.Size() == 0);
+                super::SearchWithCore(
+                    forward_heap, reverse_heap, forward_core_heap, reverse_core_heap,
+                    new_total_distance_to_forward, leg_packed_path_forward,
+                    super::NeedsLoopForward(source_phantom, target_phantom), DO_NOT_FORCE_LOOP);
+            }
+            else
+            {
+                super::Search(forward_heap, reverse_heap, new_total_distance_to_forward,
+                              leg_packed_path_forward,
+                              super::NeedsLoopForward(source_phantom, target_phantom),
+                              DO_NOT_FORCE_LOOP);
+            }
         }
 
         if (search_to_reverse_node)
         {
             forward_heap.Clear();
             reverse_heap.Clear();
-            reverse_heap.Insert(target_phantom.reverse_node_id,
+            reverse_heap.Insert(target_phantom.reverse_segment_id.id,
                                 target_phantom.GetReverseWeightPlusOffset(),
-                                target_phantom.reverse_node_id);
+                                target_phantom.reverse_segment_id.id);
             if (search_from_forward_node)
             {
-                forward_heap.Insert(source_phantom.forward_node_id,
+                forward_heap.Insert(source_phantom.forward_segment_id.id,
                                     total_distance_to_forward -
                                         source_phantom.GetForwardWeightPlusOffset(),
-                                    source_phantom.forward_node_id);
+                                    source_phantom.forward_segment_id.id);
             }
             if (search_from_reverse_node)
             {
-                forward_heap.Insert(source_phantom.reverse_node_id,
+                forward_heap.Insert(source_phantom.reverse_segment_id.id,
                                     total_distance_to_reverse -
                                         source_phantom.GetReverseWeightPlusOffset(),
-                                    source_phantom.reverse_node_id);
+                                    source_phantom.reverse_segment_id.id);
             }
             BOOST_ASSERT(forward_heap.Size() > 0);
             BOOST_ASSERT(reverse_heap.Size() > 0);
-            super::Search(forward_heap, reverse_heap, new_total_distance_to_reverse,
-                          leg_packed_path_reverse);
+            if (super::facade->GetCoreSize() > 0)
+            {
+                forward_core_heap.Clear();
+                reverse_core_heap.Clear();
+                BOOST_ASSERT(forward_core_heap.Size() == 0);
+                BOOST_ASSERT(reverse_core_heap.Size() == 0);
+                super::SearchWithCore(forward_heap, reverse_heap, forward_core_heap,
+                                      reverse_core_heap, new_total_distance_to_reverse,
+                                      leg_packed_path_reverse, DO_NOT_FORCE_LOOP,
+                                      super::NeedsLoopBackwards(source_phantom, target_phantom));
+            }
+            else
+            {
+                super::Search(forward_heap, reverse_heap, new_total_distance_to_reverse,
+                              leg_packed_path_reverse, DO_NOT_FORCE_LOOP,
+                              super::NeedsLoopBackwards(source_phantom, target_phantom));
+            }
         }
     }
 
@@ -288,7 +227,7 @@ class ShortestPathRouting final
 
         raw_route_data.shortest_path_length = shortest_path_length;
 
-        for (const auto current_leg : osrm::irange<std::size_t>(0, packed_leg_begin.size() - 1))
+        for (const auto current_leg : util::irange<std::size_t>(0, packed_leg_begin.size() - 1))
         {
             auto leg_begin = total_packed_path.begin() + packed_leg_begin[current_leg];
             auto leg_end = total_packed_path.begin() + packed_leg_begin[current_leg + 1];
@@ -297,28 +236,36 @@ class ShortestPathRouting final
                               raw_route_data.unpacked_path_segments[current_leg]);
 
             raw_route_data.source_traversed_in_reverse.push_back(
-                (*leg_begin != phantom_nodes_vector[current_leg].source_phantom.forward_node_id));
+                (*leg_begin !=
+                 phantom_nodes_vector[current_leg].source_phantom.forward_segment_id.id));
             raw_route_data.target_traversed_in_reverse.push_back(
                 (*std::prev(leg_end) !=
-                 phantom_nodes_vector[current_leg].target_phantom.forward_node_id));
+                 phantom_nodes_vector[current_leg].target_phantom.forward_segment_id.id));
         }
     }
 
     void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
-                    const std::vector<bool> &uturn_indicators,
+                    const boost::optional<bool> uturns,
                     InternalRouteResult &raw_route_data) const
     {
-        BOOST_ASSERT(uturn_indicators.size() == phantom_nodes_vector.size() + 1);
+        const bool allow_u_turn_at_via = uturns ? *uturns : super::facade->GetUTurnsDefault();
+
         engine_working_data.InitializeOrClearFirstThreadLocalStorage(
             super::facade->GetNumberOfNodes());
+        engine_working_data.InitializeOrClearSecondThreadLocalStorage(
+            super::facade->GetNumberOfNodes());
 
         QueryHeap &forward_heap = *(engine_working_data.forward_heap_1);
         QueryHeap &reverse_heap = *(engine_working_data.reverse_heap_1);
+        QueryHeap &forward_core_heap = *(engine_working_data.forward_heap_2);
+        QueryHeap &reverse_core_heap = *(engine_working_data.reverse_heap_2);
 
         int total_distance_to_forward = 0;
         int total_distance_to_reverse = 0;
-        bool search_from_forward_node = phantom_nodes_vector.front().source_phantom.forward_node_id != SPECIAL_NODEID;
-        bool search_from_reverse_node = phantom_nodes_vector.front().source_phantom.reverse_node_id != SPECIAL_NODEID;
+        bool search_from_forward_node =
+            phantom_nodes_vector.front().source_phantom.forward_segment_id.enabled;
+        bool search_from_reverse_node =
+            phantom_nodes_vector.front().source_phantom.reverse_segment_id.enabled;
 
         std::vector<NodeID> prev_packed_leg_to_forward;
         std::vector<NodeID> prev_packed_leg_to_reverse;
@@ -342,47 +289,34 @@ class ShortestPathRouting final
             const auto &source_phantom = phantom_node_pair.source_phantom;
             const auto &target_phantom = phantom_node_pair.target_phantom;
 
+            bool search_to_forward_node = target_phantom.forward_segment_id.enabled;
+            bool search_to_reverse_node = target_phantom.reverse_segment_id.enabled;
 
-            BOOST_ASSERT(current_leg + 1 < uturn_indicators.size());
-            const bool allow_u_turn_at_via = uturn_indicators[current_leg + 1];
-
-            bool search_to_forward_node = target_phantom.forward_node_id != SPECIAL_NODEID;
-            bool search_to_reverse_node = target_phantom.reverse_node_id != SPECIAL_NODEID;
-
-            BOOST_ASSERT(!search_from_forward_node || source_phantom.forward_node_id != SPECIAL_NODEID);
-            BOOST_ASSERT(!search_from_reverse_node || source_phantom.reverse_node_id != SPECIAL_NODEID);
-
-            if (source_phantom.forward_node_id == target_phantom.forward_node_id &&
-                source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
-            {
-                search_to_forward_node = search_from_reverse_node;
-            }
-            if (source_phantom.reverse_node_id == target_phantom.reverse_node_id &&
-                source_phantom.GetReverseWeightPlusOffset() > target_phantom.GetReverseWeightPlusOffset())
-            {
-                search_to_reverse_node = search_from_forward_node;
-            }
+            BOOST_ASSERT(!search_from_forward_node || source_phantom.forward_segment_id.enabled);
+            BOOST_ASSERT(!search_from_reverse_node || source_phantom.reverse_segment_id.enabled);
 
             BOOST_ASSERT(search_from_forward_node || search_from_reverse_node);
 
-            if(search_to_reverse_node || search_to_forward_node)
+            if (search_to_reverse_node || search_to_forward_node)
             {
                 if (allow_u_turn_at_via)
                 {
-                    SearchWithUTurn(forward_heap, reverse_heap, search_from_forward_node,
+                    SearchWithUTurn(forward_heap, reverse_heap, forward_core_heap,
+                                    reverse_core_heap, search_from_forward_node,
                                     search_from_reverse_node, search_to_forward_node,
                                     search_to_reverse_node, source_phantom, target_phantom,
                                     total_distance_to_forward, total_distance_to_reverse,
                                     new_total_distance_to_forward, packed_leg_to_forward);
-                    // if only the reverse node is valid (e.g. when using the match plugin) we actually need to move
-                    if (target_phantom.forward_node_id == SPECIAL_NODEID)
+                    // if only the reverse node is valid (e.g. when using the match plugin) we
+                    // actually need to move
+                    if (target_phantom.forward_segment_id.enabled)
                     {
-                        BOOST_ASSERT(target_phantom.reverse_node_id != SPECIAL_NODEID);
+                        BOOST_ASSERT(target_phantom.reverse_segment_id.enabled);
                         new_total_distance_to_reverse = new_total_distance_to_forward;
                         packed_leg_to_reverse = std::move(packed_leg_to_forward);
                         new_total_distance_to_forward = INVALID_EDGE_WEIGHT;
                     }
-                    else if (target_phantom.reverse_node_id != SPECIAL_NODEID)
+                    else if (target_phantom.reverse_segment_id.enabled)
                     {
                         new_total_distance_to_reverse = new_total_distance_to_forward;
                         packed_leg_to_reverse = packed_leg_to_forward;
@@ -390,24 +324,14 @@ class ShortestPathRouting final
                 }
                 else
                 {
-                    Search(forward_heap, reverse_heap, search_from_forward_node,
-                           search_from_reverse_node, search_to_forward_node, search_to_reverse_node,
-                           source_phantom, target_phantom, total_distance_to_forward,
-                           total_distance_to_reverse, new_total_distance_to_forward,
-                           new_total_distance_to_reverse, packed_leg_to_forward, packed_leg_to_reverse);
+                    Search(forward_heap, reverse_heap, forward_core_heap, reverse_core_heap,
+                           search_from_forward_node, search_from_reverse_node,
+                           search_to_forward_node, search_to_reverse_node, source_phantom,
+                           target_phantom, total_distance_to_forward, total_distance_to_reverse,
+                           new_total_distance_to_forward, new_total_distance_to_reverse,
+                           packed_leg_to_forward, packed_leg_to_reverse);
                 }
             }
-            else
-            {
-                search_to_forward_node = target_phantom.forward_node_id != SPECIAL_NODEID;
-                search_to_reverse_node = target_phantom.reverse_node_id != SPECIAL_NODEID;
-                BOOST_ASSERT(search_from_reverse_node == search_to_reverse_node);
-                BOOST_ASSERT(search_from_forward_node == search_to_forward_node);
-                SearchLoop(forward_heap, reverse_heap, search_from_forward_node,
-                       search_from_reverse_node, source_phantom, target_phantom, total_distance_to_forward,
-                       total_distance_to_reverse, new_total_distance_to_forward,
-                       new_total_distance_to_reverse, packed_leg_to_forward, packed_leg_to_reverse);
-            }
 
             // No path found for both target nodes?
             if ((INVALID_EDGE_WEIGHT == new_total_distance_to_forward) &&
@@ -423,16 +347,16 @@ class ShortestPathRouting final
             {
                 bool forward_to_forward =
                     (new_total_distance_to_forward != INVALID_EDGE_WEIGHT) &&
-                    packed_leg_to_forward.front() == source_phantom.forward_node_id;
+                    packed_leg_to_forward.front() == source_phantom.forward_segment_id.id;
                 bool reverse_to_forward =
                     (new_total_distance_to_forward != INVALID_EDGE_WEIGHT) &&
-                    packed_leg_to_forward.front() == source_phantom.reverse_node_id;
+                    packed_leg_to_forward.front() == source_phantom.reverse_segment_id.id;
                 bool forward_to_reverse =
                     (new_total_distance_to_reverse != INVALID_EDGE_WEIGHT) &&
-                    packed_leg_to_reverse.front() == source_phantom.forward_node_id;
+                    packed_leg_to_reverse.front() == source_phantom.forward_segment_id.id;
                 bool reverse_to_reverse =
                     (new_total_distance_to_reverse != INVALID_EDGE_WEIGHT) &&
-                    packed_leg_to_reverse.front() == source_phantom.reverse_node_id;
+                    packed_leg_to_reverse.front() == source_phantom.reverse_segment_id.id;
 
                 BOOST_ASSERT(!forward_to_forward || !reverse_to_forward);
                 BOOST_ASSERT(!forward_to_reverse || !reverse_to_reverse);
@@ -467,7 +391,7 @@ class ShortestPathRouting final
 
             if (new_total_distance_to_forward != INVALID_EDGE_WEIGHT)
             {
-                BOOST_ASSERT(target_phantom.forward_node_id != SPECIAL_NODEID);
+                BOOST_ASSERT(target_phantom.forward_segment_id.enabled);
 
                 packed_leg_to_forward_begin.push_back(total_packed_path_to_forward.size());
                 total_packed_path_to_forward.insert(total_packed_path_to_forward.end(),
@@ -484,7 +408,7 @@ class ShortestPathRouting final
 
             if (new_total_distance_to_reverse != INVALID_EDGE_WEIGHT)
             {
-                BOOST_ASSERT(target_phantom.reverse_node_id != SPECIAL_NODEID);
+                BOOST_ASSERT(target_phantom.reverse_segment_id.enabled);
 
                 packed_leg_to_reverse_begin.push_back(total_packed_path_to_reverse.size());
                 total_packed_path_to_reverse.insert(total_packed_path_to_reverse.end(),
@@ -532,5 +456,8 @@ class ShortestPathRouting final
         }
     }
 };
+}
+}
+}
 
 #endif /* SHORTEST_PATH_HPP */
diff --git a/include/engine/search_engine_data.hpp b/include/engine/search_engine_data.hpp
new file mode 100644
index 0000000..3112a78
--- /dev/null
+++ b/include/engine/search_engine_data.hpp
@@ -0,0 +1,42 @@
+#ifndef SEARCH_ENGINE_DATA_HPP
+#define SEARCH_ENGINE_DATA_HPP
+
+#include <boost/thread/tss.hpp>
+
+#include "util/typedefs.hpp"
+#include "util/binary_heap.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+
+struct HeapData
+{
+    NodeID parent;
+    /* explicit */ HeapData(NodeID p) : parent(p) {}
+};
+
+struct SearchEngineData
+{
+    using QueryHeap =
+        util::BinaryHeap<NodeID, NodeID, int, HeapData, util::UnorderedMapStorage<NodeID, int>>;
+    using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
+
+    static SearchEngineHeapPtr forward_heap_1;
+    static SearchEngineHeapPtr reverse_heap_1;
+    static SearchEngineHeapPtr forward_heap_2;
+    static SearchEngineHeapPtr reverse_heap_2;
+    static SearchEngineHeapPtr forward_heap_3;
+    static SearchEngineHeapPtr reverse_heap_3;
+
+    void InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes);
+
+    void InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes);
+
+    void InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes);
+};
+}
+}
+
+#endif // SEARCH_ENGINE_DATA_HPP
diff --git a/server/http/compression_type.hpp b/include/engine/status.hpp
similarity index 83%
rename from server/http/compression_type.hpp
rename to include/engine/status.hpp
index f0dc692..4a0fc9a 100644
--- a/server/http/compression_type.hpp
+++ b/include/engine/status.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,18 +25,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef COMPRESSION_TYPE_HPP
-#define COMPRESSION_TYPE_HPP
+#ifndef ENGINE_STATUS_HPP
+#define ENGINE_STATUS_HPP
 
-namespace http
+namespace osrm
+{
+namespace engine
 {
 
-enum compression_type
+/**
+ * Status for indicating query success or failure.
+ * \see OSRM
+ */
+enum class Status
 {
-    no_compression,
-    gzip_rfc1952,
-    deflate_rfc1951
+    Ok,
+    Error
 };
 }
+}
 
-#endif // COMPRESSION_TYPE_HPP
+#endif
diff --git a/algorithms/trip_brute_force.hpp b/include/engine/trip/trip_brute_force.hpp
similarity index 57%
rename from algorithms/trip_brute_force.hpp
rename to include/engine/trip/trip_brute_force.hpp
index 601971c..b8fe8ec 100644
--- a/algorithms/trip_brute_force.hpp
+++ b/include/engine/trip/trip_brute_force.hpp
@@ -1,38 +1,11 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 TRIP_BRUTE_FORCE_HPP
 #define TRIP_BRUTE_FORCE_HPP
 
-#include "../data_structures/search_engine.hpp"
-#include "../util/dist_table_wrapper.hpp"
-#include "../util/simple_logger.hpp"
+#include "util/typedefs.hpp"
+#include "util/dist_table_wrapper.hpp"
+#include "util/simple_logger.hpp"
 
-#include <osrm/json_container.hpp>
+#include "osrm/json_container.hpp"
 
 #include <cstdlib>
 #include <algorithm>
@@ -43,11 +16,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace osrm
 {
+namespace engine
+{
 namespace trip
 {
 
 // computes the distance of a given permutation
-EdgeWeight ReturnDistance(const DistTableWrapper<EdgeWeight> &dist_table,
+EdgeWeight ReturnDistance(const util::DistTableWrapper<EdgeWeight> &dist_table,
                           const std::vector<NodeID> &location_order,
                           const EdgeWeight min_route_dist,
                           const std::size_t component_size)
@@ -71,7 +46,7 @@ template <typename NodeIDIterator>
 std::vector<NodeID> BruteForceTrip(const NodeIDIterator start,
                                    const NodeIDIterator end,
                                    const std::size_t number_of_locations,
-                                   const DistTableWrapper<EdgeWeight> &dist_table)
+                                   const util::DistTableWrapper<EdgeWeight> &dist_table)
 {
     (void)number_of_locations; // unused
 
@@ -102,7 +77,8 @@ std::vector<NodeID> BruteForceTrip(const NodeIDIterator start,
 
     return route;
 }
+}
+}
+}
 
-} // end namespace trip
-} // end namespace osrm
 #endif // TRIP_BRUTE_FORCE_HPP
diff --git a/algorithms/trip_farthest_insertion.hpp b/include/engine/trip/trip_farthest_insertion.hpp
similarity index 80%
rename from algorithms/trip_farthest_insertion.hpp
rename to include/engine/trip/trip_farthest_insertion.hpp
index 91f0aa4..c062e72 100644
--- a/algorithms/trip_farthest_insertion.hpp
+++ b/include/engine/trip/trip_farthest_insertion.hpp
@@ -1,37 +1,11 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 TRIP_FARTHEST_INSERTION_HPP
 #define TRIP_FARTHEST_INSERTION_HPP
 
-#include "../data_structures/search_engine.hpp"
-#include "../util/dist_table_wrapper.hpp"
+#include "util/typedefs.hpp"
+#include "util/dist_table_wrapper.hpp"
+#include "util/typedefs.hpp"
 
-#include <osrm/json_container.hpp>
+#include "osrm/json_container.hpp"
 #include <boost/assert.hpp>
 
 #include <cstdlib>
@@ -42,6 +16,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace osrm
 {
+namespace engine
+{
 namespace trip
 {
 
@@ -50,7 +26,7 @@ namespace trip
 using NodeIDIter = std::vector<NodeID>::iterator;
 std::pair<EdgeWeight, NodeIDIter>
 GetShortestRoundTrip(const NodeID new_loc,
-                     const DistTableWrapper<EdgeWeight> &dist_table,
+                     const util::DistTableWrapper<EdgeWeight> &dist_table,
                      const std::size_t number_of_locations,
                      std::vector<NodeID> &route)
 {
@@ -103,7 +79,7 @@ std::vector<NodeID> FindRoute(const std::size_t &number_of_locations,
                               const std::size_t &component_size,
                               const NodeIDIterator &start,
                               const NodeIDIterator &end,
-                              const DistTableWrapper<EdgeWeight> &dist_table,
+                              const util::DistTableWrapper<EdgeWeight> &dist_table,
                               const NodeID &start1,
                               const NodeID &start2)
 {
@@ -165,7 +141,7 @@ template <typename NodeIDIterator>
 std::vector<NodeID> FarthestInsertionTrip(const NodeIDIterator &start,
                                           const NodeIDIterator &end,
                                           const std::size_t number_of_locations,
-                                          const DistTableWrapper<EdgeWeight> &dist_table)
+                                          const util::DistTableWrapper<EdgeWeight> &dist_table)
 {
     //////////////////////////////////////////////////////////////////////////////////////////////////
     // START FARTHEST INSERTION HERE
@@ -177,6 +153,13 @@ std::vector<NodeID> FarthestInsertionTrip(const NodeIDIterator &start,
     // 5. DONE!
     //////////////////////////////////////////////////////////////////////////////////////////////////
 
+
+    // Guard against division-by-zero in the code path below.
+    BOOST_ASSERT(number_of_locations > 0);
+
+    // Guard against dist_table being empty therefore max_element returning the end iterator.
+    BOOST_ASSERT(dist_table.size() > 0);
+
     const auto component_size = std::distance(start, end);
     BOOST_ASSERT(component_size >= 0);
 
@@ -194,12 +177,16 @@ std::vector<NodeID> FarthestInsertionTrip(const NodeIDIterator &start,
     }
     else
     {
-        auto max_dist = 0;
+        auto max_dist = std::numeric_limits<EdgeWeight>::min();
+
         for (auto x = start; x != end; ++x)
         {
             for (auto y = start; y != end; ++y)
             {
                 const auto xy_dist = dist_table(*x, *y);
+                // SCC decomposition done correctly?
+                BOOST_ASSERT(xy_dist != INVALID_EDGE_WEIGHT);
+
                 if (xy_dist > max_dist)
                 {
                     max_dist = xy_dist;
@@ -209,14 +196,15 @@ std::vector<NodeID> FarthestInsertionTrip(const NodeIDIterator &start,
             }
         }
     }
+
     BOOST_ASSERT(max_from >= 0);
     BOOST_ASSERT(max_to >= 0);
     BOOST_ASSERT_MSG(static_cast<std::size_t>(max_from) < number_of_locations, "start node");
     BOOST_ASSERT_MSG(static_cast<std::size_t>(max_to) < number_of_locations, "start node");
     return FindRoute(number_of_locations, component_size, start, end, dist_table, max_from, max_to);
 }
-
-} // end namespace trip
-} // end namespace osrm
+}
+}
+}
 
 #endif // TRIP_FARTHEST_INSERTION_HPP
diff --git a/algorithms/trip_nearest_neighbour.hpp b/include/engine/trip/trip_nearest_neighbour.hpp
similarity index 64%
rename from algorithms/trip_nearest_neighbour.hpp
rename to include/engine/trip/trip_nearest_neighbour.hpp
index 0ae1792..df70bc4 100644
--- a/algorithms/trip_nearest_neighbour.hpp
+++ b/include/engine/trip/trip_nearest_neighbour.hpp
@@ -1,38 +1,11 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 TRIP_NEAREST_NEIGHBOUR_HPP
 #define TRIP_NEAREST_NEIGHBOUR_HPP
 
-#include "../data_structures/search_engine.hpp"
-#include "../util/simple_logger.hpp"
-#include "../util/dist_table_wrapper.hpp"
+#include "util/typedefs.hpp"
+#include "util/simple_logger.hpp"
+#include "util/dist_table_wrapper.hpp"
 
-#include <osrm/json_container.hpp>
+#include "osrm/json_container.hpp"
 
 #include <cstdlib>
 #include <algorithm>
@@ -42,13 +15,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace osrm
 {
+namespace engine
+{
 namespace trip
 {
+
 template <typename NodeIDIterator>
 std::vector<NodeID> NearestNeighbourTrip(const NodeIDIterator &start,
                                          const NodeIDIterator &end,
                                          const std::size_t number_of_locations,
-                                         const DistTableWrapper<EdgeWeight> &dist_table)
+                                         const util::DistTableWrapper<EdgeWeight> &dist_table)
 {
     //////////////////////////////////////////////////////////////////////////////////////////////////
     // START GREEDY NEAREST NEIGHBOUR HERE
@@ -116,7 +92,8 @@ std::vector<NodeID> NearestNeighbourTrip(const NodeIDIterator &start,
     }
     return route;
 }
+}
+}
+}
 
-} // end namespace trip
-} // end namespace osrm
-#endif // TRIP_NEAREST_NEIGHBOUR_HPP
\ No newline at end of file
+#endif // TRIP_NEAREST_NEIGHBOUR_HPP
diff --git a/include/engine/trip/trip_tabu_search.hpp b/include/engine/trip/trip_tabu_search.hpp
new file mode 100644
index 0000000..24ff745
--- /dev/null
+++ b/include/engine/trip/trip_tabu_search.hpp
@@ -0,0 +1,41 @@
+#ifndef TRIP_BRUTE_FORCE_HPP
+#define TRIP_BRUTE_FORCE_HPP
+
+#include "engine/search_engine.hpp"
+#include "util/simple_logger.hpp"
+
+#include "osrm/json_container.hpp"
+
+#include <cstdlib>
+#include <algorithm>
+#include <string>
+#include <vector>
+#include <limits>
+
+namespace osrm
+{
+namespace engine
+{
+namespace trip
+{
+
+// todo: yet to be implemented
+void TabuSearchTrip(std::vector<unsigned> &location,
+                    const PhantomNodeArray &phantom_node_vector,
+                    const std::vector<EdgeWeight> &dist_table,
+                    InternalRouteResult &min_route,
+                    std::vector<int> &min_loc_permutation)
+{
+}
+
+void TabuSearchTrip(const PhantomNodeArray &phantom_node_vector,
+                    const std::vector<EdgeWeight> &dist_table,
+                    InternalRouteResult &min_route,
+                    std::vector<int> &min_loc_permutation)
+{
+}
+}
+}
+}
+
+#endif // TRIP_BRUTE_FORCE_HPP
diff --git a/include/extractor/compressed_edge_container.hpp b/include/extractor/compressed_edge_container.hpp
new file mode 100644
index 0000000..662c18e
--- /dev/null
+++ b/include/extractor/compressed_edge_container.hpp
@@ -0,0 +1,57 @@
+#ifndef GEOMETRY_COMPRESSOR_HPP_
+#define GEOMETRY_COMPRESSOR_HPP_
+
+#include "util/typedefs.hpp"
+
+#include <unordered_map>
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace extractor
+{
+
+class CompressedEdgeContainer
+{
+  public:
+    struct CompressedEdge
+    {
+      public:
+        NodeID node_id;    // refers to an internal node-based-node
+        EdgeWeight weight; // the weight of the edge leading to this node
+    };
+    using EdgeBucket = std::vector<CompressedEdge>;
+
+    CompressedEdgeContainer();
+    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);
+
+    void
+    AddUncompressedEdge(const EdgeID edgei_id, const NodeID target_node, const EdgeWeight weight);
+
+    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 EdgeBucket &GetBucketReference(const EdgeID edge_id) const;
+    NodeID GetFirstEdgeTargetID(const EdgeID edge_id) const;
+    NodeID GetLastEdgeSourceID(const EdgeID edge_id) const;
+
+  private:
+    int free_list_maximum = 0;
+
+    void IncreaseFreeList();
+    std::vector<EdgeBucket> m_compressed_geometries;
+    std::vector<unsigned> m_free_list;
+    std::unordered_map<EdgeID, unsigned> m_edge_id_to_list_index_map;
+};
+}
+}
+
+#endif // GEOMETRY_COMPRESSOR_HPP_
diff --git a/include/extractor/edge_based_edge.hpp b/include/extractor/edge_based_edge.hpp
new file mode 100644
index 0000000..e4e5ef3
--- /dev/null
+++ b/include/extractor/edge_based_edge.hpp
@@ -0,0 +1,80 @@
+#ifndef EDGE_BASED_EDGE_HPP
+#define EDGE_BASED_EDGE_HPP
+
+#include "extractor/travel_mode.hpp"
+#include "util/typedefs.hpp"
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct EdgeBasedEdge
+{
+  public:
+    EdgeBasedEdge();
+
+    template <class EdgeT> explicit EdgeBasedEdge(const EdgeT &other);
+
+    EdgeBasedEdge(const NodeID source,
+                  const NodeID target,
+                  const NodeID edge_id,
+                  const EdgeWeight weight,
+                  const bool forward,
+                  const bool backward);
+
+    bool operator<(const EdgeBasedEdge &other) const;
+
+    NodeID source;
+    NodeID target;
+    NodeID edge_id;
+    EdgeWeight weight : 30;
+    bool forward : 1;
+    bool backward : 1;
+};
+
+// Impl.
+
+inline EdgeBasedEdge::EdgeBasedEdge()
+    : source(0), target(0), edge_id(0), weight(0), forward(false), backward(false)
+{
+}
+
+template <class EdgeT>
+inline EdgeBasedEdge::EdgeBasedEdge(const EdgeT &other)
+    : source(other.source), target(other.target), edge_id(other.data.via),
+      weight(other.data.distance), forward(other.data.forward), backward(other.data.backward)
+{
+}
+
+inline EdgeBasedEdge::EdgeBasedEdge(const NodeID source,
+                                    const NodeID target,
+                                    const NodeID edge_id,
+                                    const EdgeWeight weight,
+                                    const bool forward,
+                                    const bool backward)
+    : source(source), target(target), edge_id(edge_id), weight(weight), forward(forward),
+      backward(backward)
+{
+}
+
+inline bool EdgeBasedEdge::operator<(const EdgeBasedEdge &other) const
+{
+    if (source == other.source)
+    {
+        if (target == other.target)
+        {
+            if (weight == other.weight)
+            {
+                return forward && backward && ((!other.forward) || (!other.backward));
+            }
+            return weight < other.weight;
+        }
+        return target < other.target;
+    }
+    return source < other.source;
+}
+} // ns extractor
+} // ns osrm
+
+#endif /* EDGE_BASED_EDGE_HPP */
diff --git a/include/extractor/edge_based_graph_factory.hpp b/include/extractor/edge_based_graph_factory.hpp
new file mode 100644
index 0000000..1aff390
--- /dev/null
+++ b/include/extractor/edge_based_graph_factory.hpp
@@ -0,0 +1,134 @@
+//  This class constructs the edge-expanded routing graph
+
+#ifndef EDGE_BASED_GRAPH_FACTORY_HPP_
+#define EDGE_BASED_GRAPH_FACTORY_HPP_
+
+#include "extractor/edge_based_edge.hpp"
+#include "extractor/profile_properties.hpp"
+#include "extractor/restriction_map.hpp"
+#include "extractor/compressed_edge_container.hpp"
+#include "extractor/edge_based_node.hpp"
+#include "extractor/original_edge_data.hpp"
+#include "extractor/query_node.hpp"
+#include "extractor/guidance/turn_analysis.hpp"
+
+#include "extractor/guidance/turn_instruction.hpp"
+
+#include "util/node_based_graph.hpp"
+#include "util/typedefs.hpp"
+#include "util/deallocating_vector.hpp"
+#include "util/name_table.hpp"
+
+#include <algorithm>
+#include <cstdint>
+#include <cstddef>
+#include <iosfwd>
+#include <memory>
+#include <queue>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+#include <string>
+
+#include <boost/filesystem/fstream.hpp>
+
+struct lua_State;
+
+namespace osrm
+{
+namespace extractor
+{
+
+class EdgeBasedGraphFactory
+{
+  public:
+    EdgeBasedGraphFactory(const EdgeBasedGraphFactory &) = delete;
+    EdgeBasedGraphFactory &operator=(const EdgeBasedGraphFactory &) = delete;
+
+    explicit EdgeBasedGraphFactory(std::shared_ptr<util::NodeBasedDynamicGraph> node_based_graph,
+                                   const CompressedEdgeContainer &compressed_edge_container,
+                                   const std::unordered_set<NodeID> &barrier_nodes,
+                                   const std::unordered_set<NodeID> &traffic_lights,
+                                   std::shared_ptr<const RestrictionMap> restriction_map,
+                                   const std::vector<QueryNode> &node_info_list,
+                                   ProfileProperties profile_properties,
+                                   const util::NameTable &name_table);
+
+    void Run(const std::string &original_edge_data_filename,
+             lua_State *lua_state,
+             const std::string &edge_segment_lookup_filename,
+             const std::string &edge_penalty_filename,
+             const bool generate_edge_lookup);
+
+    // The following get access functions destroy the content in the factory
+    void GetEdgeBasedEdges(util::DeallocatingVector<EdgeBasedEdge> &edges);
+    void GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes);
+    void GetStartPointMarkers(std::vector<bool> &node_is_startpoint);
+    void GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights);
+
+    unsigned GetHighestEdgeID();
+
+    // Basic analysis of a turn (u --(e1)-- v --(e2)-- w)
+    // with known angle.
+    // Handles special cases like u-turns and roundabouts
+    // For basic turns, the turn based on the angle-classification is returned
+    guidance::TurnInstruction AnalyzeTurn(const NodeID u,
+                                          const EdgeID e1,
+                                          const NodeID v,
+                                          const EdgeID e2,
+                                          const NodeID w,
+                                          const double angle) const;
+
+    std::int32_t GetTurnPenalty(double angle, lua_State *lua_state) const;
+
+  private:
+    using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
+
+    //! maps index from m_edge_based_node_list to ture/false if the node is an entry point to the
+    //! graph
+    std::vector<bool> m_edge_based_node_is_startpoint;
+
+    //! node weights that indicate the length of the segment (node based) represented by the
+    //! edge-based node
+    std::vector<EdgeWeight> m_edge_based_node_weights;
+
+    //! list of edge based nodes (compressed segments)
+    std::vector<EdgeBasedNode> m_edge_based_node_list;
+    util::DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
+    unsigned m_max_edge_id;
+
+    const std::vector<QueryNode> &m_node_info_list;
+    std::shared_ptr<util::NodeBasedDynamicGraph> m_node_based_graph;
+    std::shared_ptr<RestrictionMap const> m_restriction_map;
+
+    const std::unordered_set<NodeID> &m_barrier_nodes;
+    const std::unordered_set<NodeID> &m_traffic_lights;
+    const CompressedEdgeContainer &m_compressed_edge_container;
+
+    ProfileProperties profile_properties;
+
+    const util::NameTable &name_table;
+
+    void CompressGeometry();
+    unsigned RenumberEdges();
+    void GenerateEdgeExpandedNodes();
+    void GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
+                                   lua_State *lua_state,
+                                   const std::string &edge_segment_lookup_filename,
+                                   const std::string &edge_fixed_penalties_filename,
+                                   const bool generate_edge_lookup);
+
+    void InsertEdgeBasedNode(const NodeID u, const NodeID v);
+
+    void FlushVectorToStream(std::ofstream &edge_data_file,
+                             std::vector<OriginalEdgeData> &original_edge_data_vector) const;
+
+    std::size_t restricted_turns_counter;
+    std::size_t skipped_uturns_counter;
+    std::size_t skipped_barrier_turns_counter;
+};
+} // namespace extractor
+} // namespace osrm
+
+#endif /* EDGE_BASED_GRAPH_FACTORY_HPP_ */
diff --git a/include/extractor/edge_based_node.hpp b/include/extractor/edge_based_node.hpp
new file mode 100644
index 0000000..699e9e7
--- /dev/null
+++ b/include/extractor/edge_based_node.hpp
@@ -0,0 +1,76 @@
+#ifndef EDGE_BASED_NODE_HPP
+#define EDGE_BASED_NODE_HPP
+
+#include "extractor/travel_mode.hpp"
+#include "util/typedefs.hpp"
+
+#include <boost/assert.hpp>
+
+#include "osrm/coordinate.hpp"
+
+#include <limits>
+
+namespace osrm
+{
+namespace extractor
+{
+
+/// This is what util::StaticRTree serialized and stores on disk
+/// It is generated in EdgeBasedGraphFactory.
+struct EdgeBasedNode
+{
+    EdgeBasedNode()
+        : forward_segment_id{SPECIAL_SEGMENTID, false},
+          reverse_segment_id{SPECIAL_SEGMENTID, false}, u(SPECIAL_NODEID),
+          v(SPECIAL_NODEID), name_id(0), forward_packed_geometry_id(SPECIAL_EDGEID),
+          reverse_packed_geometry_id(SPECIAL_EDGEID), component{INVALID_COMPONENTID, false},
+          fwd_segment_position(std::numeric_limits<unsigned short>::max()),
+          forward_travel_mode(TRAVEL_MODE_INACCESSIBLE),
+          backward_travel_mode(TRAVEL_MODE_INACCESSIBLE)
+    {
+    }
+
+    explicit EdgeBasedNode(const SegmentID forward_segment_id_,
+                           const SegmentID reverse_segment_id_,
+                           NodeID u,
+                           NodeID v,
+                           unsigned name_id,
+                           unsigned forward_geometry_id_,
+                           unsigned reverse_geometry_id_,
+                           bool is_tiny_component,
+                           unsigned component_id,
+                           unsigned short fwd_segment_position,
+                           TravelMode forward_travel_mode,
+                           TravelMode backward_travel_mode)
+        : forward_segment_id(forward_segment_id_),
+          reverse_segment_id(reverse_segment_id_), u(u), v(v), name_id(name_id),
+          forward_packed_geometry_id(forward_geometry_id_),
+          reverse_packed_geometry_id(reverse_geometry_id_),
+          component{component_id, is_tiny_component}, fwd_segment_position(fwd_segment_position),
+          forward_travel_mode(forward_travel_mode), backward_travel_mode(backward_travel_mode)
+    {
+        BOOST_ASSERT(forward_segment_id.enabled ||
+                     reverse_segment_id.enabled);
+    }
+
+    SegmentID forward_segment_id; // needed for edge-expanded graph
+    SegmentID reverse_segment_id; // needed for edge-expanded graph
+    NodeID u;                     // indices into the coordinates array
+    NodeID v;                     // indices into the coordinates array
+    unsigned name_id;             // id of the edge name
+
+    unsigned forward_packed_geometry_id;
+    unsigned reverse_packed_geometry_id;
+    struct
+    {
+        unsigned id : 31;
+        bool is_tiny : 1;
+    } component;
+    unsigned short fwd_segment_position; // segment id in a compressed geometry
+    TravelMode forward_travel_mode : 4;
+    TravelMode backward_travel_mode : 4;
+};
+}
+}
+
+#endif // EDGE_BASED_NODE_HPP
diff --git a/include/extractor/external_memory_node.hpp b/include/extractor/external_memory_node.hpp
new file mode 100644
index 0000000..d26f7d3
--- /dev/null
+++ b/include/extractor/external_memory_node.hpp
@@ -0,0 +1,56 @@
+#ifndef EXTERNAL_MEMORY_NODE_HPP_
+#define EXTERNAL_MEMORY_NODE_HPP_
+
+#include "extractor/query_node.hpp"
+
+#include "util/typedefs.hpp"
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct ExternalMemoryNode : QueryNode
+{
+    ExternalMemoryNode(const util::FixedLongitude lon_,
+                       const util::FixedLatitude lat_,
+                       OSMNodeID node_id_,
+                       bool barrier_,
+                       bool traffic_lights_)
+        : QueryNode(lon_, lat_, node_id_), barrier(barrier_), traffic_lights(traffic_lights_)
+    {
+    }
+
+    ExternalMemoryNode() : barrier(false), traffic_lights(false) {}
+
+    static ExternalMemoryNode min_value()
+    {
+        return ExternalMemoryNode(util::FixedLongitude(0), util::FixedLatitude(0), MIN_OSM_NODEID,
+                                  false, false);
+    }
+
+    static ExternalMemoryNode max_value()
+    {
+        return ExternalMemoryNode(util::FixedLongitude(std::numeric_limits<int>::max()),
+                                  util::FixedLatitude(std::numeric_limits<int>::max()),
+                                  MAX_OSM_NODEID, false, false);
+    }
+
+    bool barrier;
+    bool traffic_lights;
+};
+
+struct ExternalMemoryNodeSTXXLCompare
+{
+    using value_type = ExternalMemoryNode;
+    value_type max_value() { return value_type::max_value(); }
+    value_type min_value() { return value_type::min_value(); }
+    bool operator()(const value_type &left, const value_type &right) const
+    {
+        return left.node_id < right.node_id;
+    }
+};
+}
+}
+
+#endif /* EXTERNAL_MEMORY_NODE_HPP_ */
diff --git a/extractor/extraction_containers.hpp b/include/extractor/extraction_containers.hpp
similarity index 51%
rename from extractor/extraction_containers.hpp
rename to include/extractor/extraction_containers.hpp
index 541ad35..848e457 100644
--- a/extractor/extraction_containers.hpp
+++ b/include/extractor/extraction_containers.hpp
@@ -1,42 +1,20 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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_CONTAINERS_HPP
 #define EXTRACTION_CONTAINERS_HPP
 
-#include "internal_extractor_edge.hpp"
-#include "first_and_last_segment_of_way.hpp"
-#include "scripting_environment.hpp"
-#include "../data_structures/external_memory_node.hpp"
-#include "../data_structures/restriction.hpp"
+#include "extractor/internal_extractor_edge.hpp"
+#include "extractor/first_and_last_segment_of_way.hpp"
+#include "extractor/scripting_environment.hpp"
+#include "extractor/external_memory_node.hpp"
+#include "extractor/restriction.hpp"
 
 #include <stxxl/vector>
 #include <unordered_map>
 
+namespace osrm
+{
+namespace extractor
+{
+
 /**
  * Uses external memory containers from stxxl to store all the data that
  * is collected by the extractor callbacks.
@@ -56,10 +34,11 @@ class ExtractionContainers
     void PrepareRestrictions();
     void PrepareEdges(lua_State *segment_state);
 
-    void WriteNodes(std::ofstream& file_out_stream) const;
-    void WriteRestrictions(const std::string& restrictions_file_name) const;
-    void WriteEdges(std::ofstream& file_out_stream) const;
-    void WriteNames(const std::string& names_file_name) const;
+    void WriteNodes(std::ofstream &file_out_stream) const;
+    void WriteRestrictions(const std::string &restrictions_file_name) const;
+    void WriteEdges(std::ofstream &file_out_stream) const;
+    void WriteNames(const std::string &names_file_name) const;
+
   public:
     using STXXLNodeIDVector = stxxl::vector<OSMNodeID>;
     using STXXLNodeVector = stxxl::vector<ExternalMemoryNode>;
@@ -86,5 +65,7 @@ class ExtractionContainers
                      const std::string &names_file_name,
                      lua_State *segment_state);
 };
+}
+}
 
 #endif /* EXTRACTION_CONTAINERS_HPP */
diff --git a/extractor/extraction_helper_functions.hpp b/include/extractor/extraction_helper_functions.hpp
similarity index 53%
rename from extractor/extraction_helper_functions.hpp
rename to include/extractor/extraction_helper_functions.hpp
index 69ab456..cbd5a64 100644
--- a/extractor/extraction_helper_functions.hpp
+++ b/include/extractor/extraction_helper_functions.hpp
@@ -1,35 +1,8 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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_HELPER_FUNCTIONS_HPP
 #define EXTRACTION_HELPER_FUNCTIONS_HPP
 
-#include "../util/cast.hpp"
-#include "../util/iso_8601_duration_parser.hpp"
+#include "util/cast.hpp"
+#include "util/iso_8601_duration_parser.hpp"
 
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string_regex.hpp>
@@ -39,7 +12,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <limits>
 #include <string>
 
-bool simple_duration_is_valid(const std::string &s)
+namespace osrm
+{
+namespace extractor
+{
+
+inline bool simple_duration_is_valid(const std::string &s)
 {
     boost::regex simple_format(
         "((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",
@@ -54,10 +32,10 @@ bool simple_duration_is_valid(const std::string &s)
     return false;
 }
 
-bool iso_8601_duration_is_valid(const std::string &s)
+inline bool iso_8601_duration_is_valid(const std::string &s)
 {
-    iso_8601_grammar<std::string::const_iterator> iso_parser;
-    const bool result = qi::parse(s.begin(), s.end(), iso_parser);
+    util::iso_8601_grammar<std::string::const_iterator> iso_parser;
+    const bool result = boost::spirit::qi::parse(s.begin(), s.end(), iso_parser);
 
     // check if the was an error with the request
     if (result && (0 != iso_parser.get_duration()))
@@ -67,12 +45,12 @@ bool iso_8601_duration_is_valid(const std::string &s)
     return false;
 }
 
-bool durationIsValid(const std::string &s)
+inline bool durationIsValid(const std::string &s)
 {
     return simple_duration_is_valid(s) || iso_8601_duration_is_valid(s);
 }
 
-unsigned parseDuration(const std::string &s)
+inline unsigned parseDuration(const std::string &s)
 {
     if (simple_duration_is_valid(s))
     {
@@ -108,13 +86,15 @@ unsigned parseDuration(const std::string &s)
     }
     else if (iso_8601_duration_is_valid(s))
     {
-        iso_8601_grammar<std::string::const_iterator> iso_parser;
-        qi::parse(s.begin(), s.end(), iso_parser);
+        util::iso_8601_grammar<std::string::const_iterator> iso_parser;
+        boost::spirit::qi::parse(s.begin(), s.end(), iso_parser);
 
         return iso_parser.get_duration();
     }
 
     return std::numeric_limits<unsigned>::max();
 }
+}
+}
 
 #endif // EXTRACTION_HELPER_FUNCTIONS_HPP
diff --git a/include/extractor/extraction_node.hpp b/include/extractor/extraction_node.hpp
new file mode 100644
index 0000000..e82f298
--- /dev/null
+++ b/include/extractor/extraction_node.hpp
@@ -0,0 +1,19 @@
+#ifndef EXTRACTION_NODE_HPP
+#define EXTRACTION_NODE_HPP
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct ExtractionNode
+{
+    ExtractionNode() : traffic_lights(false), barrier(false) {}
+    void clear() { traffic_lights = barrier = false; }
+    bool traffic_lights;
+    bool barrier;
+};
+}
+}
+
+#endif // EXTRACTION_NODE_HPP
diff --git a/include/extractor/extraction_way.hpp b/include/extractor/extraction_way.hpp
new file mode 100644
index 0000000..f82787d
--- /dev/null
+++ b/include/extractor/extraction_way.hpp
@@ -0,0 +1,58 @@
+#ifndef EXTRACTION_WAY_HPP
+#define EXTRACTION_WAY_HPP
+
+#include "extractor/travel_mode.hpp"
+#include "util/typedefs.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace extractor
+{
+
+/**
+ * This struct is the direct result of the call to ```way_function```
+ * in the lua based profile.
+ *
+ * It is split into multiple edge segments in the ExtractorCallback.
+ */
+struct ExtractionWay
+{
+    ExtractionWay() { clear(); }
+
+    void clear()
+    {
+        forward_speed = -1;
+        backward_speed = -1;
+        duration = -1;
+        roundabout = false;
+        is_startpoint = true;
+        is_access_restricted = false;
+        name.clear();
+        forward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
+        backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
+    }
+
+    // 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 is_startpoint;
+    TravelMode forward_travel_mode : 4;
+    TravelMode backward_travel_mode : 4;
+};
+}
+}
+
+#endif // EXTRACTION_WAY_HPP
diff --git a/extractor/extractor.hpp b/include/extractor/extractor.hpp
similarity index 65%
rename from extractor/extractor.hpp
rename to include/extractor/extractor.hpp
index c147f19..1b61513 100644
--- a/extractor/extractor.hpp
+++ b/include/extractor/extractor.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -28,39 +28,56 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef EXTRACTOR_HPP
 #define EXTRACTOR_HPP
 
-#include "extractor_options.hpp"
-#include "edge_based_graph_factory.hpp"
-#include "../algorithms/graph_compressor.hpp"
+#include "extractor/edge_based_edge.hpp"
+#include "extractor/extractor_config.hpp"
+#include "extractor/edge_based_graph_factory.hpp"
+#include "extractor/graph_compressor.hpp"
 
-class extractor
+#include "util/typedefs.hpp"
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct ProfileProperties;
+
+class Extractor
 {
   public:
-    extractor(ExtractorConfig extractor_config) : config(std::move(extractor_config)) {}
+    Extractor(ExtractorConfig extractor_config) : config(std::move(extractor_config)) {}
     int run();
 
   private:
     ExtractorConfig config;
-    void SetupScriptingEnvironment(lua_State *myLuaState, SpeedProfileProperties &speed_profile);
+
     std::pair<std::size_t, std::size_t>
-    BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map,
+    BuildEdgeExpandedGraph(lua_State* lua_state,
+                           const ProfileProperties& profile_properties,
+                           std::vector<QueryNode> &internal_to_external_node_map,
                            std::vector<EdgeBasedNode> &node_based_edge_list,
                            std::vector<bool> &node_is_startpoint,
-                           DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list);
+                           std::vector<EdgeWeight> &edge_based_node_weights,
+                           util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list);
+    void WriteProfileProperties(const std::string& output_path, const ProfileProperties& properties) const;
     void WriteNodeMapping(const std::vector<QueryNode> &internal_to_external_node_map);
     void FindComponents(unsigned max_edge_id,
-                        const DeallocatingVector<EdgeBasedEdge> &edges,
+                        const util::DeallocatingVector<EdgeBasedEdge> &edges,
                         std::vector<EdgeBasedNode> &nodes) const;
     void BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
                     std::vector<bool> node_is_startpoint,
                     const std::vector<QueryNode> &internal_to_external_node_map);
     std::shared_ptr<RestrictionMap> LoadRestrictionMap();
-    std::shared_ptr<NodeBasedDynamicGraph>
+    std::shared_ptr<util::NodeBasedDynamicGraph>
     LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
                        std::unordered_set<NodeID> &traffic_lights,
                        std::vector<QueryNode> &internal_to_external_node_map);
 
-    void WriteEdgeBasedGraph(std::string const &output_file_filename,
-                             size_t const max_edge_id,
-                             DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list);
+    void WriteEdgeBasedGraph(const std::string &output_file_filename,
+                             const size_t max_edge_id,
+                             util::DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list);
 };
+}
+}
+
 #endif /* EXTRACTOR_HPP */
diff --git a/extractor/extractor_callbacks.hpp b/include/extractor/extractor_callbacks.hpp
similarity index 51%
rename from extractor/extractor_callbacks.hpp
rename to include/extractor/extractor_callbacks.hpp
index 0026b6f..db4e870 100644
--- a/extractor/extractor_callbacks.hpp
+++ b/include/extractor/extractor_callbacks.hpp
@@ -1,50 +1,28 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 EXTRACTOR_CALLBACKS_HPP
 #define EXTRACTOR_CALLBACKS_HPP
 
-#include "../typedefs.h"
+#include "util/typedefs.hpp"
 #include <boost/optional/optional_fwd.hpp>
 
 #include <string>
 #include <unordered_map>
 
-struct ExternalMemoryNode;
-class ExtractionContainers;
-struct InputRestrictionContainer;
-struct ExtractionNode;
-struct ExtractionWay;
 namespace osmium
 {
 class Node;
 class Way;
 }
 
+namespace osrm
+{
+namespace extractor
+{
+
+class ExtractionContainers;
+struct InputRestrictionContainer;
+struct ExtractionNode;
+struct ExtractionWay;
+
 /**
  * This class is uses by the extractor with the results of the
  * osmium based parsing and the customization through the lua profile.
@@ -60,10 +38,11 @@ class ExtractorCallbacks
     ExtractionContainers &external_memory;
 
   public:
-    ExtractorCallbacks() = delete;
-    ExtractorCallbacks(const ExtractorCallbacks &) = delete;
     explicit ExtractorCallbacks(ExtractionContainers &extraction_containers);
 
+    ExtractorCallbacks(const ExtractorCallbacks &) = delete;
+    ExtractorCallbacks &operator=(const ExtractorCallbacks &) = delete;
+
     // warning: caller needs to take care of synchronization!
     void ProcessNode(const osmium::Node &current_node, const ExtractionNode &result_node);
 
@@ -73,5 +52,7 @@ class ExtractorCallbacks
     // warning: caller needs to take care of synchronization!
     void ProcessWay(const osmium::Way &current_way, const ExtractionWay &result_way);
 };
+}
+}
 
 #endif /* EXTRACTOR_CALLBACKS_HPP */
diff --git a/extractor/extractor_options.hpp b/include/extractor/extractor_config.hpp
similarity index 56%
rename from extractor/extractor_options.hpp
rename to include/extractor/extractor_config.hpp
index 00d6f84..80196db 100644
--- a/extractor/extractor_options.hpp
+++ b/include/extractor/extractor_config.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,23 +25,55 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef EXTRACTOR_OPTIONS_HPP
-#define EXTRACTOR_OPTIONS_HPP
+#ifndef EXTRACTOR_CONFIG_HPP
+#define EXTRACTOR_CONFIG_HPP
 
 #include <boost/filesystem/path.hpp>
 
 #include <string>
+#include <array>
 
-enum class return_code : unsigned
+namespace osrm
+{
+namespace extractor
 {
-    ok,
-    fail,
-    exit
-};
 
 struct ExtractorConfig
 {
     ExtractorConfig() noexcept : requested_num_threads(0) {}
+    void UseDefaultOutputNames()
+    {
+        std::string basepath = input_path.string();
+
+        auto pos = std::string::npos;
+        std::array<std::string, 5> known_extensions{
+            {".osm.bz2", ".osm.pbf", ".osm.xml", ".pbf", ".osm"}};
+        for (auto ext : known_extensions)
+        {
+            pos = basepath.find(ext);
+            if (pos != std::string::npos)
+            {
+                basepath.replace(pos, ext.size(), "");
+                break;
+            }
+        }
+
+        output_file_name = basepath + ".osrm";
+        restriction_file_name = basepath + ".osrm.restrictions";
+        names_file_name = basepath + ".osrm.names";
+        timestamp_file_name = basepath + ".osrm.timestamp";
+        geometry_output_path = basepath + ".osrm.geometry";
+        node_output_path = basepath + ".osrm.nodes";
+        edge_output_path = basepath + ".osrm.edges";
+        edge_graph_output_path = basepath + ".osrm.ebg";
+        rtree_nodes_output_path = basepath + ".osrm.ramIndex";
+        rtree_leafs_output_path = basepath + ".osrm.fileIndex";
+        edge_segment_lookup_path = basepath + ".osrm.edge_segment_lookup";
+        edge_penalty_path = basepath + ".osrm.edge_penalties";
+        edge_based_node_weights_output_path = basepath + ".osrm.enw";
+        profile_properties_output_path = basepath + ".osrm.properties";
+    }
+
     boost::filesystem::path config_file_path;
     boost::filesystem::path input_path;
     boost::filesystem::path profile_path;
@@ -53,9 +85,11 @@ struct ExtractorConfig
     std::string geometry_output_path;
     std::string edge_output_path;
     std::string edge_graph_output_path;
+    std::string edge_based_node_weights_output_path;
     std::string node_output_path;
     std::string rtree_nodes_output_path;
     std::string rtree_leafs_output_path;
+    std::string profile_properties_output_path;
 
     unsigned requested_num_threads;
     unsigned small_component_size;
@@ -63,16 +97,8 @@ struct ExtractorConfig
     bool generate_edge_lookup;
     std::string edge_penalty_path;
     std::string edge_segment_lookup_path;
-#ifdef DEBUG_GEOMETRY
-    std::string debug_turns_path;
-#endif
-};
-
-struct ExtractorOptions
-{
-    static return_code ParseArguments(int argc, char *argv[], ExtractorConfig &extractor_config);
-
-    static void GenerateOutputFilesNames(ExtractorConfig &extractor_config);
 };
+}
+}
 
-#endif // EXTRACTOR_OPTIONS_HPP
+#endif // EXTRACTOR_CONFIG_HPP
diff --git a/include/extractor/first_and_last_segment_of_way.hpp b/include/extractor/first_and_last_segment_of_way.hpp
new file mode 100644
index 0000000..37d0e40
--- /dev/null
+++ b/include/extractor/first_and_last_segment_of_way.hpp
@@ -0,0 +1,60 @@
+#ifndef FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
+#define FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
+
+#include "extractor/external_memory_node.hpp"
+#include "util/typedefs.hpp"
+
+#include <limits>
+#include <string>
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct FirstAndLastSegmentOfWay
+{
+    OSMWayID way_id;
+    OSMNodeID first_segment_source_id;
+    OSMNodeID first_segment_target_id;
+    OSMNodeID last_segment_source_id;
+    OSMNodeID last_segment_target_id;
+
+    FirstAndLastSegmentOfWay()
+        : way_id(SPECIAL_OSM_WAYID), first_segment_source_id(SPECIAL_OSM_NODEID),
+          first_segment_target_id(SPECIAL_OSM_NODEID), last_segment_source_id(SPECIAL_OSM_NODEID),
+          last_segment_target_id(SPECIAL_OSM_NODEID)
+    {
+    }
+
+    FirstAndLastSegmentOfWay(OSMWayID w, OSMNodeID fs, OSMNodeID ft, OSMNodeID ls, OSMNodeID lt)
+        : way_id(std::move(w)), first_segment_source_id(std::move(fs)),
+          first_segment_target_id(std::move(ft)), last_segment_source_id(std::move(ls)),
+          last_segment_target_id(std::move(lt))
+    {
+    }
+
+    static FirstAndLastSegmentOfWay min_value()
+    {
+        return {MIN_OSM_WAYID, MIN_OSM_NODEID, MIN_OSM_NODEID, MIN_OSM_NODEID, MIN_OSM_NODEID};
+    }
+    static FirstAndLastSegmentOfWay max_value()
+    {
+        return {MAX_OSM_WAYID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID};
+    }
+};
+
+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/include/extractor/graph_compressor.hpp b/include/extractor/graph_compressor.hpp
new file mode 100644
index 0000000..78f3eaa
--- /dev/null
+++ b/include/extractor/graph_compressor.hpp
@@ -0,0 +1,38 @@
+#ifndef GEOMETRY_COMPRESSOR_HPP
+#define GEOMETRY_COMPRESSOR_HPP
+
+#include "util/typedefs.hpp"
+
+#include "util/node_based_graph.hpp"
+
+#include <memory>
+#include <unordered_set>
+
+namespace osrm
+{
+namespace extractor
+{
+
+class CompressedEdgeContainer;
+class RestrictionMap;
+
+class GraphCompressor
+{
+    using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
+
+  public:
+    void Compress(const std::unordered_set<NodeID> &barrier_nodes,
+                  const std::unordered_set<NodeID> &traffic_lights,
+                  RestrictionMap &restriction_map,
+                  util::NodeBasedDynamicGraph &graph,
+                  CompressedEdgeContainer &geometry_compressor);
+
+  private:
+    void PrintStatistics(unsigned original_number_of_nodes,
+                         unsigned original_number_of_edges,
+                         const util::NodeBasedDynamicGraph &graph) const;
+};
+}
+}
+
+#endif
diff --git a/include/extractor/guidance/classification_data.hpp b/include/extractor/guidance/classification_data.hpp
new file mode 100644
index 0000000..53f54cf
--- /dev/null
+++ b/include/extractor/guidance/classification_data.hpp
@@ -0,0 +1,67 @@
+#ifndef OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_
+#define OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_
+
+#include <cstdint>
+
+#include <string>
+
+// Forward Declaration to allow usage of external osmium::Way
+namespace osmium
+{
+class Way;
+}
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+enum class FunctionalRoadClass : std::uint8_t
+{
+    UNKNOWN = 0,
+    MOTORWAY,
+    MOTORWAY_LINK,
+    TRUNK,
+    TRUNK_LINK,
+    PRIMARY,
+    PRIMARY_LINK,
+    SECONDARY,
+    SECONDARY_LINK,
+    TERTIARY,
+    TERTIARY_LINK,
+    UNCLASSIFIED,
+    RESIDENTIAL,
+    SERVICE,
+    LIVING_STREET,
+    LOW_PRIORITY_ROAD // a road simply included for connectivity. Should be avoided at all cost
+};
+
+FunctionalRoadClass functionalRoadClassFromTag(std::string const &tag);
+
+inline bool isRampClass(const FunctionalRoadClass road_class)
+{
+    // Primary Roads and down are usually too small to announce their links as ramps
+    return road_class == FunctionalRoadClass::MOTORWAY_LINK ||
+           road_class == FunctionalRoadClass::TRUNK_LINK;
+}
+
+// TODO augment this with all data required for guidance generation
+struct RoadClassificationData
+{
+    FunctionalRoadClass road_class = FunctionalRoadClass::UNKNOWN;
+
+    void augment(const osmium::Way &way);
+};
+
+inline bool operator==(const RoadClassificationData lhs, const RoadClassificationData rhs)
+{
+    return lhs.road_class == rhs.road_class;
+}
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif // OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_
diff --git a/include/extractor/guidance/discrete_angle.hpp b/include/extractor/guidance/discrete_angle.hpp
new file mode 100644
index 0000000..08509cb
--- /dev/null
+++ b/include/extractor/guidance/discrete_angle.hpp
@@ -0,0 +1,19 @@
+#ifndef OSRM_EXTRACTOR_GUIDANCE_DISCRETE_ANGLE
+#define OSRM_EXTRACTOR_GUIDANCE_DISCRETE_ANGLE
+
+#include <cstdint>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+using DiscreteAngle = std::uint8_t;
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif /* OSRM_EXTRACTOR_GUIDANCE_DISCRETE_ANGLE */
diff --git a/include/extractor/guidance/toolkit.hpp b/include/extractor/guidance/toolkit.hpp
new file mode 100644
index 0000000..45ca897
--- /dev/null
+++ b/include/extractor/guidance/toolkit.hpp
@@ -0,0 +1,404 @@
+#ifndef OSRM_GUIDANCE_TOOLKIT_HPP_
+#define OSRM_GUIDANCE_TOOLKIT_HPP_
+
+#include "util/bearing.hpp"
+#include "util/coordinate.hpp"
+#include "util/coordinate_calculation.hpp"
+
+#include "extractor/compressed_edge_container.hpp"
+#include "extractor/query_node.hpp"
+
+#include "extractor/guidance/discrete_angle.hpp"
+#include "extractor/guidance/classification_data.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+
+#include <algorithm>
+#include <map>
+#include <cmath>
+#include <cstdint>
+#include <string>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+namespace detail
+{
+const constexpr double DESIRED_SEGMENT_LENGTH = 10.0;
+const constexpr bool shiftable_ccw[] = {false, true, true, false, false, true, true, false};
+const constexpr bool shiftable_cw[] = {false, false, true, true, false, false, true, true};
+const constexpr std::uint8_t modifier_bounds[detail::num_direction_modifiers] = {
+    0, 36, 93, 121, 136, 163, 220, 255};
+const constexpr double discrete_angle_step_size = 360. / 256.;
+
+template <typename IteratorType>
+util::Coordinate
+getCoordinateFromCompressedRange(util::Coordinate current_coordinate,
+                                 const IteratorType compressed_geometry_begin,
+                                 const IteratorType compressed_geometry_end,
+                                 const util::Coordinate final_coordinate,
+                                 const std::vector<extractor::QueryNode> &query_nodes)
+{
+    const auto extractCoordinateFromNode = [](const extractor::QueryNode &node) -> util::Coordinate
+    {
+        return {node.lon, node.lat};
+    };
+    double distance_to_current_coordinate = 0;
+    double distance_to_next_coordinate = 0;
+
+    // get the length that is missing from the current segment to reach DESIRED_SEGMENT_LENGTH
+    const auto getFactor = [](const double first_distance, const double second_distance)
+    {
+        BOOST_ASSERT(first_distance < detail::DESIRED_SEGMENT_LENGTH);
+        double segment_length = second_distance - first_distance;
+        BOOST_ASSERT(segment_length > 0);
+        BOOST_ASSERT(second_distance >= detail::DESIRED_SEGMENT_LENGTH);
+        double missing_distance = detail::DESIRED_SEGMENT_LENGTH - first_distance;
+        return missing_distance / segment_length;
+    };
+
+    for (auto compressed_geometry_itr = compressed_geometry_begin;
+         compressed_geometry_itr != compressed_geometry_end; ++compressed_geometry_itr)
+    {
+        const auto next_coordinate =
+            extractCoordinateFromNode(query_nodes[compressed_geometry_itr->node_id]);
+        distance_to_next_coordinate =
+            distance_to_current_coordinate +
+            util::coordinate_calculation::haversineDistance(current_coordinate, next_coordinate);
+
+        // reached point where coordinates switch between
+        if (distance_to_next_coordinate >= detail::DESIRED_SEGMENT_LENGTH)
+            return util::coordinate_calculation::interpolateLinear(
+                getFactor(distance_to_current_coordinate, distance_to_next_coordinate),
+                current_coordinate, next_coordinate);
+
+        // prepare for next iteration
+        current_coordinate = next_coordinate;
+        distance_to_current_coordinate = distance_to_next_coordinate;
+    }
+
+    distance_to_next_coordinate =
+        distance_to_current_coordinate +
+        util::coordinate_calculation::haversineDistance(current_coordinate, final_coordinate);
+
+    // reached point where coordinates switch between
+    if (distance_to_next_coordinate >= detail::DESIRED_SEGMENT_LENGTH)
+        return util::coordinate_calculation::interpolateLinear(
+            getFactor(distance_to_current_coordinate, distance_to_next_coordinate),
+            current_coordinate, final_coordinate);
+    else
+        return final_coordinate;
+}
+} // namespace detail
+
+// Finds a (potentially inteprolated) coordinate that is DESIRED_SEGMENT_LENGTH away
+// from the start of an edge
+inline util::Coordinate
+getRepresentativeCoordinate(const NodeID from_node,
+                            const NodeID to_node,
+                            const EdgeID via_edge_id,
+                            const bool traverse_in_reverse,
+                            const extractor::CompressedEdgeContainer &compressed_geometries,
+                            const std::vector<extractor::QueryNode> &query_nodes)
+{
+    const auto extractCoordinateFromNode = [](const extractor::QueryNode &node) -> util::Coordinate
+    {
+        return {node.lon, node.lat};
+    };
+
+    // Uncompressed roads are simple, return the coordinate at the end
+    if (!compressed_geometries.HasEntryForID(via_edge_id))
+    {
+        return extractCoordinateFromNode(traverse_in_reverse ? query_nodes[from_node]
+                                                             : query_nodes[to_node]);
+    }
+    else
+    {
+        const auto &geometry = compressed_geometries.GetBucketReference(via_edge_id);
+
+        const auto base_node_id = (traverse_in_reverse) ? to_node : from_node;
+        const auto base_coordinate = extractCoordinateFromNode(query_nodes[base_node_id]);
+
+        const auto final_node = (traverse_in_reverse) ? from_node : to_node;
+        const auto final_coordinate = extractCoordinateFromNode(query_nodes[final_node]);
+
+        if (traverse_in_reverse)
+            return detail::getCoordinateFromCompressedRange(
+                base_coordinate, geometry.rbegin(), geometry.rend(), final_coordinate, query_nodes);
+        else
+            return detail::getCoordinateFromCompressedRange(
+                base_coordinate, geometry.begin(), geometry.end(), final_coordinate, query_nodes);
+    }
+}
+
+// shift an instruction around the degree circle in CCW order
+inline DirectionModifier forcedShiftCCW(const DirectionModifier modifier)
+{
+    return static_cast<DirectionModifier>((static_cast<std::uint32_t>(modifier) + 1) %
+                                          detail::num_direction_modifiers);
+}
+
+inline DirectionModifier shiftCCW(const DirectionModifier modifier)
+{
+    if (detail::shiftable_ccw[static_cast<int>(modifier)])
+        return forcedShiftCCW(modifier);
+    else
+        return modifier;
+}
+
+// shift an instruction around the degree circle in CW order
+inline DirectionModifier forcedShiftCW(const DirectionModifier modifier)
+{
+    return static_cast<DirectionModifier>(
+        (static_cast<std::uint32_t>(modifier) + detail::num_direction_modifiers - 1) %
+        detail::num_direction_modifiers);
+}
+
+inline DirectionModifier shiftCW(const DirectionModifier modifier)
+{
+    if (detail::shiftable_cw[static_cast<int>(modifier)])
+        return forcedShiftCW(modifier);
+    else
+        return modifier;
+}
+
+inline bool isBasic(const TurnType type)
+{
+    return type == TurnType::Turn || type == TurnType::EndOfRoad;
+}
+
+inline bool isUturn(const TurnInstruction instruction)
+{
+    return isBasic(instruction.type) && instruction.direction_modifier == DirectionModifier::UTurn;
+}
+
+inline bool resolve(TurnInstruction &to_resolve, const TurnInstruction neighbor, bool resolve_cw)
+{
+    const auto shifted_turn = resolve_cw ? shiftCW(to_resolve.direction_modifier)
+                                         : shiftCCW(to_resolve.direction_modifier);
+    if (shifted_turn == neighbor.direction_modifier ||
+        shifted_turn == to_resolve.direction_modifier)
+        return false;
+
+    to_resolve.direction_modifier = shifted_turn;
+    return true;
+}
+
+inline bool resolveTransitive(TurnInstruction &first,
+                              TurnInstruction &second,
+                              const TurnInstruction third,
+                              bool resolve_cw)
+{
+    if (resolve(second, third, resolve_cw))
+    {
+        first.direction_modifier =
+            resolve_cw ? shiftCW(first.direction_modifier) : shiftCCW(first.direction_modifier);
+        return true;
+    }
+    return false;
+}
+
+inline bool isSlightTurn(const TurnInstruction turn)
+{
+    return (isBasic(turn.type) || turn.type == TurnType::NoTurn) &&
+           (turn.direction_modifier == DirectionModifier::Straight ||
+            turn.direction_modifier == DirectionModifier::SlightRight ||
+            turn.direction_modifier == DirectionModifier::SlightLeft);
+}
+
+inline bool isSlightModifier(const DirectionModifier direction_modifier)
+{
+    return (direction_modifier == DirectionModifier::Straight ||
+            direction_modifier == DirectionModifier::SlightRight ||
+            direction_modifier == DirectionModifier::SlightLeft);
+}
+
+inline bool isSharpTurn(const TurnInstruction turn)
+{
+    return isBasic(turn.type) && (turn.direction_modifier == DirectionModifier::SharpLeft ||
+                                  turn.direction_modifier == DirectionModifier::SharpRight);
+}
+
+inline bool isStraight(const TurnInstruction turn)
+{
+    return (isBasic(turn.type) || turn.type == TurnType::NoTurn) &&
+           turn.direction_modifier == DirectionModifier::Straight;
+}
+
+inline bool isConflict(const TurnInstruction first, const TurnInstruction second)
+{
+    return (first.type == second.type && first.direction_modifier == second.direction_modifier) ||
+           (isStraight(first) && isStraight(second));
+}
+
+inline DiscreteAngle discretizeAngle(const double angle)
+{
+    BOOST_ASSERT(angle >= 0. && angle <= 360.);
+    return DiscreteAngle(static_cast<std::uint8_t>(angle / detail::discrete_angle_step_size));
+}
+
+inline double angleFromDiscreteAngle(const DiscreteAngle angle)
+{
+    return static_cast<double>(angle) * detail::discrete_angle_step_size;
+}
+
+inline double angularDeviation(const double angle, const double from)
+{
+    const double deviation = std::abs(angle - from);
+    return std::min(360 - deviation, deviation);
+}
+
+inline double getAngularPenalty(const double angle, DirectionModifier modifier)
+{
+    // these are not aligned with getTurnDirection but represent an ideal center
+    const double center[] = {0, 45, 90, 135, 180, 225, 270, 315};
+    return angularDeviation(center[static_cast<int>(modifier)], angle);
+}
+
+inline double getTurnConfidence(const double angle, TurnInstruction instruction)
+{
+
+    // special handling of U-Turns and Roundabout
+    if (!isBasic(instruction.type) || instruction.direction_modifier == DirectionModifier::UTurn)
+        return 1.0;
+
+    const double deviations[] = {0, 45, 50, 30, 20, 30, 50, 45};
+    const double difference = getAngularPenalty(angle, instruction.direction_modifier);
+    const double max_deviation = deviations[static_cast<int>(instruction.direction_modifier)];
+    return 1.0 - (difference / max_deviation) * (difference / max_deviation);
+}
+
+// Translates between angles and their human-friendly directional representation
+inline DirectionModifier getTurnDirection(const double angle)
+{
+    // An angle of zero is a u-turn
+    // 180 goes perfectly straight
+    // 0-180 are right turns
+    // 180-360 are left turns
+    if (angle > 0 && angle < 60)
+        return DirectionModifier::SharpRight;
+    if (angle >= 60 && angle < 140)
+        return DirectionModifier::Right;
+    if (angle >= 140 && angle < 170)
+        return DirectionModifier::SlightRight;
+    if (angle >= 165 && angle <= 195)
+        return DirectionModifier::Straight;
+    if (angle > 190 && angle <= 220)
+        return DirectionModifier::SlightLeft;
+    if (angle > 220 && angle <= 300)
+        return DirectionModifier::Left;
+    if (angle > 300 && angle < 360)
+        return DirectionModifier::SharpLeft;
+    return DirectionModifier::UTurn;
+}
+
+// swaps left <-> right modifier types
+inline DirectionModifier mirrorDirectionModifier(const DirectionModifier modifier)
+{
+    const constexpr DirectionModifier results[] = {DirectionModifier::UTurn,
+                                                   DirectionModifier::SharpLeft,
+                                                   DirectionModifier::Left,
+                                                   DirectionModifier::SlightLeft,
+                                                   DirectionModifier::Straight,
+                                                   DirectionModifier::SlightRight,
+                                                   DirectionModifier::Right,
+                                                   DirectionModifier::SharpRight};
+    return results[modifier];
+}
+
+inline bool canBeSuppressed(const TurnType type)
+{
+    if (type == TurnType::Turn)
+        return true;
+    return false;
+}
+
+inline bool isLowPriorityRoadClass(const FunctionalRoadClass road_class)
+{
+    return road_class == FunctionalRoadClass::LOW_PRIORITY_ROAD ||
+           road_class == FunctionalRoadClass::SERVICE;
+}
+
+inline bool isDistinct(const DirectionModifier first, const DirectionModifier second)
+{
+    if ((first + 1) % detail::num_direction_modifiers == second)
+        return false;
+
+    if ((second + 1) % detail::num_direction_modifiers == first)
+        return false;
+
+    return true;
+}
+
+inline bool requiresNameAnnounced(const std::string &from, const std::string &to)
+{
+    // FIXME, handle in profile to begin with?
+    // this uses the encoding of references in the profile, which is very BAD
+    // Input for this function should be a struct separating streetname, suffix (e.g. road,
+    // boulevard, North, West ...), and a list of references
+    std::string from_name;
+    std::string from_ref;
+    std::string to_name;
+    std::string to_ref;
+
+    // Split from the format "{name} ({ref})" -> name, ref
+    auto split = [](const std::string &name, std::string &out_name, std::string &out_ref)
+    {
+        const auto ref_begin = name.find_first_of('(');
+        if (ref_begin != std::string::npos)
+        {
+            out_name = name.substr(0, ref_begin);
+            out_ref = name.substr(ref_begin + 1, name.find_first_of(')') - 1);
+        }
+        else
+        {
+            out_name = name;
+        }
+    };
+
+    split(from, from_name, from_ref);
+    split(to, to_name, to_ref);
+
+    // check similarity of names
+    auto names_are_empty = from_name.empty() && to_name.empty();
+    auto names_are_equal = from_name == to_name;
+    auto name_is_removed = !from_name.empty() && to_name.empty();
+    // references are contained in one another
+    auto refs_are_empty = from_ref.empty() && to_ref.empty();
+    auto ref_is_contained =
+        !from_ref.empty() && !to_ref.empty() &&
+        (from_ref.find(to_ref) != std::string::npos || to_ref.find(from_ref) != std::string::npos);
+    auto ref_is_removed = !from_ref.empty() && to_ref.empty();
+
+    auto obvious_change = ref_is_contained || names_are_equal ||
+                          (names_are_empty && refs_are_empty) || name_is_removed || ref_is_removed;
+
+    return !obvious_change;
+}
+
+inline int getPriority( const FunctionalRoadClass road_class )
+{
+    //The road priorities indicate which roads can bee seen as more or less equal.
+    //They are used in Fork-Discovery. Possibly should be moved to profiles post v5?
+    //A fork can happen between road types that are at most 1 priority apart from each other
+    const constexpr int road_priority[] = {10, 0, 10, 2, 10, 4, 10, 6, 10, 8, 10, 11, 10, 12, 10, 14};
+    return road_priority[static_cast<int>(road_class)];
+}
+
+inline bool canBeSeenAsFork(const FunctionalRoadClass first, const FunctionalRoadClass second)
+{
+    // forks require similar road categories
+    // Based on the priorities assigned above, we can set forks only if the road priorities match closely.
+    // Potentially we could include features like number of lanes here and others?
+    // Should also be moved to profiles
+    return std::abs(getPriority(first) - getPriority(second)) <= 1;
+}
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif // OSRM_GUIDANCE_TOOLKIT_HPP_
diff --git a/include/extractor/guidance/turn_analysis.hpp b/include/extractor/guidance/turn_analysis.hpp
new file mode 100644
index 0000000..538fabc
--- /dev/null
+++ b/include/extractor/guidance/turn_analysis.hpp
@@ -0,0 +1,202 @@
+#ifndef OSRM_EXTRACTOR_TURN_ANALYSIS
+#define OSRM_EXTRACTOR_TURN_ANALYSIS
+
+#include "extractor/guidance/turn_classification.hpp"
+#include "extractor/guidance/toolkit.hpp"
+#include "extractor/restriction_map.hpp"
+#include "extractor/compressed_edge_container.hpp"
+
+#include "util/name_table.hpp"
+
+#include <cstdint>
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <utility>
+#include <unordered_set>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+// What is exposed to the outside
+struct TurnOperation final
+{
+    EdgeID eid;
+    double angle;
+    TurnInstruction instruction;
+};
+
+// For the turn analysis, we require a full list of all connected roads to determine the outcome.
+// Invalid turns can influence the perceived angles
+//
+// aaa(2)aa
+//          a - bbbbb
+// aaa(1)aa
+//
+// will not be perceived as a turn from (1) -> b, and as a U-turn from (1) -> (2).
+// In addition, they can influence whether a turn is obvious or not.
+struct ConnectedRoad final
+{
+    ConnectedRoad(const TurnOperation turn, const bool entry_allowed = false);
+
+    TurnOperation turn;
+    bool entry_allowed; // a turn may be relevant to good instructions, even if we cannot take
+                        // the road
+
+    std::string toString() const
+    {
+        std::string result = "[connection] ";
+        result += std::to_string(turn.eid);
+        result += " allows entry: ";
+        result += std::to_string(entry_allowed);
+        result += " angle: ";
+        result += std::to_string(turn.angle);
+        result += " instruction: ";
+        result += std::to_string(static_cast<std::int32_t>(turn.instruction.type)) + " " +
+                  std::to_string(static_cast<std::int32_t>(turn.instruction.direction_modifier));
+        return result;
+    }
+};
+
+class TurnAnalysis
+{
+
+  public:
+    TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
+                 const std::vector<QueryNode> &node_info_list,
+                 const RestrictionMap &restriction_map,
+                 const std::unordered_set<NodeID> &barrier_nodes,
+                 const CompressedEdgeContainer &compressed_edge_container,
+                 const util::NameTable &name_table);
+
+    // the entry into the turn analysis
+    std::vector<TurnOperation> getTurns(const NodeID from_node, const EdgeID via_eid) const;
+
+  private:
+    const util::NodeBasedDynamicGraph &node_based_graph;
+    const std::vector<QueryNode> &node_info_list;
+    const RestrictionMap &restriction_map;
+    const std::unordered_set<NodeID> &barrier_nodes;
+    const CompressedEdgeContainer &compressed_edge_container;
+    const util::NameTable &name_table;
+
+    // Check for restrictions/barriers and generate a list of valid and invalid turns present at
+    // the
+    // node reached
+    // from `from_node` via `via_eid`
+    // The resulting candidates have to be analysed for their actual instructions later on.
+    std::vector<ConnectedRoad> getConnectedRoads(const NodeID from_node,
+                                                 const EdgeID via_eid) const;
+
+    // Merge segregated roads to omit invalid turns in favor of treating segregated roads as
+    // one.
+    // This function combines roads the following way:
+    //
+    //     *                           *
+    //     *        is converted to    *
+    //   v   ^                         +
+    //   v   ^                         +
+    //
+    // The treatment results in a straight turn angle of 180º rather than a turn angle of approx
+    // 160
+    std::vector<ConnectedRoad> mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) const;
+
+    // TODO distinguish roundabouts and rotaries
+    // TODO handle bike/walk cases that allow crossing a roundabout!
+
+    // Processing of roundabouts
+    // Produces instructions to enter/exit a roundabout or to stay on it.
+    // Performs the distinction between roundabout and rotaries.
+    std::vector<ConnectedRoad> handleRoundabouts(const EdgeID via_edge,
+                                                 const bool on_roundabout,
+                                                 const bool can_exit_roundabout,
+                                                 std::vector<ConnectedRoad> intersection) const;
+
+    // Indicates a Junction containing a motoryway
+    bool isMotorwayJunction(const EdgeID via_edge,
+                            const std::vector<ConnectedRoad> &intersection) const;
+
+    // Decide whether a turn is a turn or a ramp access
+    TurnType findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const;
+
+    // Get the Instruction for an obvious turn
+    // Instruction will be a silent instruction
+    TurnInstruction getInstructionForObvious(const std::size_t number_of_candidates,
+                                             const EdgeID via_edge,
+                                             const ConnectedRoad &candidate) const;
+
+    // Helper Function that decides between NoTurn or NewName
+    TurnInstruction
+    noTurnOrNewName(const NodeID from, const EdgeID via_edge, const ConnectedRoad &candidate) const;
+
+    // Basic Turn Handling
+
+    // Dead end.
+    std::vector<ConnectedRoad> handleOneWayTurn(std::vector<ConnectedRoad> intersection) const;
+
+    // Mode Changes, new names...
+    std::vector<ConnectedRoad> handleTwoWayTurn(const EdgeID via_edge,
+                                                std::vector<ConnectedRoad> intersection) const;
+
+    // Forks, T intersections and similar
+    std::vector<ConnectedRoad> handleThreeWayTurn(const EdgeID via_edge,
+                                                  std::vector<ConnectedRoad> intersection) const;
+
+    // Handling of turns larger then degree three
+    std::vector<ConnectedRoad> handleComplexTurn(const EdgeID via_edge,
+                                                 std::vector<ConnectedRoad> intersection) const;
+
+    // Any Junction containing motorways
+    std::vector<ConnectedRoad> handleMotorwayJunction(
+        const EdgeID via_edge, std::vector<ConnectedRoad> intersection) const;
+
+    std::vector<ConnectedRoad> handleFromMotorway(const EdgeID via_edge,
+                                                  std::vector<ConnectedRoad> intersection) const;
+
+    std::vector<ConnectedRoad> handleMotorwayRamp(const EdgeID via_edge,
+                                                  std::vector<ConnectedRoad> intersection) const;
+
+    // Utility function, setting basic turn types. Prepares for normal turn handling.
+    std::vector<ConnectedRoad> setTurnTypes(const NodeID from,
+                                            const EdgeID via_edge,
+                                            std::vector<ConnectedRoad> intersection) const;
+
+    // Assignment of specific turn types
+    void assignFork(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const;
+    void assignFork(const EdgeID via_edge,
+                    ConnectedRoad &left,
+                    ConnectedRoad &center,
+                    ConnectedRoad &right) const;
+
+    void
+    handleDistinctConflict(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const;
+
+    // Type specific fallbacks
+    std::vector<ConnectedRoad>
+    fallbackTurnAssignmentMotorway(std::vector<ConnectedRoad> intersection) const;
+
+    // Classification
+    std::size_t findObviousTurn(const EdgeID via_edge,
+                                const std::vector<ConnectedRoad> &intersection) const;
+    std::pair<std::size_t, std::size_t>
+    findFork(const std::vector<ConnectedRoad> &intersection) const;
+
+    std::vector<ConnectedRoad> assignLeftTurns(const EdgeID via_edge,
+                                               std::vector<ConnectedRoad> intersection,
+                                               const std::size_t starting_at) const;
+    std::vector<ConnectedRoad> assignRightTurns(const EdgeID via_edge,
+                                                std::vector<ConnectedRoad> intersection,
+                                                const std::size_t up_to) const;
+
+}; // class TurnAnalysis
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif // OSRM_EXTRACTOR_TURN_ANALYSIS
diff --git a/include/extractor/guidance/turn_classification.hpp b/include/extractor/guidance/turn_classification.hpp
new file mode 100644
index 0000000..58f7666
--- /dev/null
+++ b/include/extractor/guidance/turn_classification.hpp
@@ -0,0 +1,123 @@
+#ifndef OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
+#define OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
+
+#include "extractor/guidance/toolkit.hpp"
+
+#include "util/typedefs.hpp"
+#include "util/coordinate.hpp"
+#include "util/node_based_graph.hpp"
+
+#include "extractor/compressed_edge_container.hpp"
+#include "extractor/query_node.hpp"
+
+#include <algorithm>
+#include <cstddef>
+#include <vector>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+struct TurnPossibility
+{
+    TurnPossibility(DiscreteAngle angle, EdgeID edge_id)
+        : angle(std::move(angle)), edge_id(std::move(edge_id))
+    {
+    }
+
+    TurnPossibility() : angle(0), edge_id(SPECIAL_EDGEID) {}
+
+    DiscreteAngle angle;
+    EdgeID edge_id;
+};
+
+struct CompareTurnPossibilities
+{
+    bool operator()(const std::vector<TurnPossibility> &left,
+                    const std::vector<TurnPossibility> &right) const
+    {
+        if (left.size() < right.size())
+            return true;
+        if (left.size() > right.size())
+            return false;
+        for (std::size_t i = 0; i < left.size(); ++i)
+        {
+            if ((((int)left[i].angle + 16) % 256) / 32 < (((int)right[i].angle + 16) % 256) / 32)
+                return true;
+            if ((((int)left[i].angle + 16) % 256) / 32 > (((int)right[i].angle + 16) % 256) / 32)
+                return false;
+        }
+        return false;
+    }
+};
+
+inline std::vector<TurnPossibility>
+classifyIntersection(NodeID nid,
+                     const util::NodeBasedDynamicGraph &graph,
+                     const extractor::CompressedEdgeContainer &compressed_geometries,
+                     const std::vector<extractor::QueryNode> &query_nodes)
+{
+
+    std::vector<TurnPossibility> turns;
+
+    if (graph.BeginEdges(nid) == graph.EndEdges(nid))
+        return std::vector<TurnPossibility>();
+
+    const EdgeID base_id = graph.BeginEdges(nid);
+    const auto base_coordinate = getRepresentativeCoordinate(nid, graph.GetTarget(base_id), base_id,
+                                                             graph.GetEdgeData(base_id).reversed,
+                                                             compressed_geometries, query_nodes);
+    const auto node_coordinate = util::Coordinate(query_nodes[nid].lon, query_nodes[nid].lat);
+
+    // generate a list of all turn angles between a base edge, the node and a current edge
+    for (const EdgeID eid : graph.GetAdjacentEdgeRange(nid))
+    {
+        const auto edge_coordinate = getRepresentativeCoordinate(
+            nid, graph.GetTarget(eid), eid, false, compressed_geometries, query_nodes);
+
+        double angle = util::coordinate_calculation::computeAngle(base_coordinate, node_coordinate,
+                                                                  edge_coordinate);
+        turns.emplace_back(discretizeAngle(angle), eid);
+    }
+
+    std::sort(turns.begin(), turns.end(),
+              [](const TurnPossibility left, const TurnPossibility right)
+              {
+                  return left.angle < right.angle;
+              });
+
+    turns.push_back(turns.front()); // sentinel
+    for (std::size_t turn_nr = 0; turn_nr + 1 < turns.size(); ++turn_nr)
+    {
+        turns[turn_nr].angle = (256 + static_cast<uint32_t>(turns[turn_nr + 1].angle) -
+                                static_cast<uint32_t>(turns[turn_nr].angle)) %
+                               256; // calculate the difference to the right
+    }
+    turns.pop_back(); // remove sentinel again
+
+    // find largest:
+    std::size_t best_id = 0;
+    DiscreteAngle largest_turn_angle = turns.front().angle;
+    for (std::size_t current_turn_id = 1; current_turn_id < turns.size(); ++current_turn_id)
+    {
+        if (turns[current_turn_id].angle > largest_turn_angle)
+        {
+            largest_turn_angle = turns[current_turn_id].angle;
+            best_id = current_turn_id;
+        }
+    }
+
+    // rotate all angles so the largest angle comes first
+    std::rotate(turns.begin(), turns.begin() + best_id, turns.end());
+
+    return turns;
+}
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif // OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
diff --git a/include/extractor/guidance/turn_instruction.hpp b/include/extractor/guidance/turn_instruction.hpp
new file mode 100644
index 0000000..da3da62
--- /dev/null
+++ b/include/extractor/guidance/turn_instruction.hpp
@@ -0,0 +1,127 @@
+#ifndef OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
+#define OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
+
+#include <cstdint>
+
+#include <boost/assert.hpp>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+namespace detail
+{
+// inclusive bounds for turn modifiers
+const constexpr uint8_t num_direction_modifiers = 8;
+} // detail
+
+// direction modifiers based on angle
+// Would be nice to have
+// enum class DirectionModifier : unsigned char
+enum DirectionModifier
+{
+    UTurn,
+    SharpRight,
+    Right,
+    SlightRight,
+    Straight,
+    SlightLeft,
+    Left,
+    SharpLeft
+};
+
+// enum class TurnType : unsigned char
+enum TurnType // at the moment we can support 32 turn types, without increasing memory consumption
+{
+    Invalid,                // no valid turn instruction
+    NoTurn,                 // end of segment without turn/middle of a segment
+    Suppressed,             // location that suppresses a turn
+    NewName,                // no turn, but name changes
+    Continue,               // remain on a street
+    Turn,                   // basic turn
+    FirstTurn,              // First of x turns
+    SecondTurn,             // Second of x turns
+    ThirdTurn,              // Third of x turns
+    FourthTurn,             // Fourth of x turns
+    Merge,                  // merge onto a street
+    Ramp,                   // special turn (highway ramp exits)
+    FirstRamp,              // first turn onto a ramp
+    SecondRamp,             // second turn onto a ramp
+    ThirdRamp,              // third turn onto a ramp
+    FourthRamp,             // fourth turn onto a ramp
+    Fork,                   // fork road splitting up
+    EndOfRoad,              // T intersection
+    EnterRoundabout,        // Entering a small Roundabout
+    EnterRoundaboutAtExit,  // Entering a small Roundabout at a countable exit
+    EnterAndExitRoundabout, // Touching a roundabout
+    ExitRoundabout,         // Exiting a small Roundabout
+    EnterRotary,            // Enter a rotary
+    EnterRotaryAtExit,      // Enter A Rotary at a countable exit
+    EnterAndExitRotary,     // Touching a rotary
+    ExitRotary,             // Exit a rotary
+    StayOnRoundabout,       // Continue on Either a small or a large Roundabout
+    Restriction,            // Cross a Barrier, requires barrier penalties instead of full block
+    Notification            // Travel Mode Changes`
+};
+
+// turn angle in 1.40625 degree -> 128 == 180 degree
+struct TurnInstruction
+{
+    TurnInstruction(const TurnType type = TurnType::Invalid,
+                    const DirectionModifier direction_modifier = DirectionModifier::Straight)
+        : type(type), direction_modifier(direction_modifier)
+    {
+    }
+
+    TurnType type : 5;
+    DirectionModifier direction_modifier : 3;
+
+    static TurnInstruction INVALID()
+    {
+        return TurnInstruction(TurnType::Invalid, DirectionModifier::UTurn);
+    }
+
+    static TurnInstruction NO_TURN()
+    {
+        return TurnInstruction(TurnType::NoTurn, DirectionModifier::UTurn);
+    }
+
+    static TurnInstruction REMAIN_ROUNDABOUT(const DirectionModifier modifier)
+    {
+        return TurnInstruction(TurnType::StayOnRoundabout, modifier);
+    }
+
+    static TurnInstruction ENTER_ROUNDABOUT(const DirectionModifier modifier)
+    {
+        return TurnInstruction(TurnType::EnterRoundabout, modifier);
+    }
+
+    static TurnInstruction EXIT_ROUNDABOUT(const DirectionModifier modifier)
+    {
+        return TurnInstruction(TurnType::ExitRoundabout, modifier);
+    }
+
+    static TurnInstruction SUPPRESSED(const DirectionModifier modifier)
+    {
+        return TurnInstruction{TurnType::Suppressed, modifier};
+    }
+};
+
+inline bool operator!=(const TurnInstruction lhs, const TurnInstruction rhs)
+{
+    return lhs.type != rhs.type || lhs.direction_modifier != rhs.direction_modifier;
+}
+
+inline bool operator==(const TurnInstruction lhs, const TurnInstruction rhs)
+{
+    return lhs.type == rhs.type && lhs.direction_modifier == rhs.direction_modifier;
+}
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif // OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
diff --git a/extractor/internal_extractor_edge.hpp b/include/extractor/internal_extractor_edge.hpp
similarity index 60%
rename from extractor/internal_extractor_edge.hpp
rename to include/extractor/internal_extractor_edge.hpp
index 0df6e8c..2ccdb2c 100644
--- a/extractor/internal_extractor_edge.hpp
+++ b/include/extractor/internal_extractor_edge.hpp
@@ -1,46 +1,26 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 INTERNAL_EXTRACTOR_EDGE_HPP
 #define INTERNAL_EXTRACTOR_EDGE_HPP
 
-#include "../typedefs.h"
-#include "../data_structures/travel_mode.hpp"
-#include "../data_structures/import_edge.hpp"
+#include "util/typedefs.hpp"
+#include "extractor/travel_mode.hpp"
+#include "extractor/node_based_edge.hpp"
 
 #include <boost/assert.hpp>
 
-#include <osrm/coordinate.hpp>
+#include "osrm/coordinate.hpp"
 #include <utility>
+#include "extractor/guidance/classification_data.hpp"
+
+namespace osrm
+{
+namespace extractor
+{
 
 struct InternalExtractorEdge
 {
     // specify the type of the weight data
-    enum class WeightType : char {
+    enum class WeightType : char
+    {
         INVALID,
         SPEED,
         EDGE_DURATION,
@@ -50,9 +30,7 @@ struct InternalExtractorEdge
     struct WeightData
     {
 
-        WeightData() : duration(0.0), type(WeightType::INVALID)
-        {
-        }
+        WeightData() : duration(0.0), type(WeightType::INVALID) {}
 
         union
         {
@@ -63,8 +41,18 @@ struct InternalExtractorEdge
     };
 
     explicit InternalExtractorEdge()
-        : result(MIN_OSM_NODEID, MIN_OSM_NODEID, 0, 0, false, false, false, false, true,
-                TRAVEL_MODE_INACCESSIBLE, false)
+        : result(MIN_OSM_NODEID,
+                 MIN_OSM_NODEID,
+                 0,
+                 0,
+                 false,
+                 false,
+                 false,
+                 false,
+                 true,
+                 TRAVEL_MODE_INACCESSIBLE,
+                 false,
+                 guidance::RoadClassificationData())
     {
     }
 
@@ -78,7 +66,8 @@ struct InternalExtractorEdge
                                    bool access_restricted,
                                    bool startpoint,
                                    TravelMode travel_mode,
-                                   bool is_split)
+                                   bool is_split,
+                                   guidance::RoadClassificationData road_classification)
         : result(OSMNodeID(source),
                  OSMNodeID(target),
                  name_id,
@@ -89,7 +78,8 @@ struct InternalExtractorEdge
                  access_restricted,
                  startpoint,
                  travel_mode,
-                 is_split),
+                 is_split,
+                 std::move(road_classification)),
           weight_data(std::move(weight_data))
     {
     }
@@ -99,19 +89,20 @@ struct InternalExtractorEdge
     // intermediate edge weight
     WeightData weight_data;
     // coordinate of the source node
-    FixedPointCoordinate source_coordinate;
-
+    util::Coordinate source_coordinate;
 
     // necessary static util functions for stxxl's sorting
     static InternalExtractorEdge min_osm_value()
     {
-        return InternalExtractorEdge(MIN_OSM_NODEID, MIN_OSM_NODEID, 0, WeightData(), false, false, false,
-                                     false, true, TRAVEL_MODE_INACCESSIBLE, false);
+        return InternalExtractorEdge(MIN_OSM_NODEID, MIN_OSM_NODEID, 0, WeightData(), false, false,
+                                     false, false, true, TRAVEL_MODE_INACCESSIBLE, false,
+                                     guidance::RoadClassificationData());
     }
     static InternalExtractorEdge max_osm_value()
     {
-        return InternalExtractorEdge(MAX_OSM_NODEID, MAX_OSM_NODEID, 0, WeightData(), false,
-                                     false, false, false, true, TRAVEL_MODE_INACCESSIBLE, false);
+        return InternalExtractorEdge(MAX_OSM_NODEID, MAX_OSM_NODEID, 0, WeightData(), false, false,
+                                     false, false, true, TRAVEL_MODE_INACCESSIBLE, false,
+                                     guidance::RoadClassificationData());
     }
 
     static InternalExtractorEdge min_internal_value()
@@ -128,7 +119,6 @@ struct InternalExtractorEdge
         v.result.target = std::numeric_limits<NodeID>::max();
         return v;
     }
-
 };
 
 struct CmpEdgeByInternalStartThenInternalTargetID
@@ -136,9 +126,9 @@ struct CmpEdgeByInternalStartThenInternalTargetID
     using value_type = InternalExtractorEdge;
     bool operator()(const InternalExtractorEdge &lhs, const InternalExtractorEdge &rhs) const
     {
-        return (lhs.result.source <  rhs.result.source) ||
-              ((lhs.result.source == rhs.result.source) &&
-               (lhs.result.target <  rhs.result.target));
+        return (lhs.result.source < rhs.result.source) ||
+               ((lhs.result.source == rhs.result.source) &&
+                (lhs.result.target < rhs.result.target));
     }
 
     value_type max_value() { return InternalExtractorEdge::max_internal_value(); }
@@ -168,5 +158,7 @@ struct CmpEdgeByOSMTargetID
     value_type max_value() { return InternalExtractorEdge::max_osm_value(); }
     value_type min_value() { return InternalExtractorEdge::min_osm_value(); }
 };
+}
+}
 
 #endif // INTERNAL_EXTRACTOR_EDGE_HPP
diff --git a/include/extractor/node_based_edge.hpp b/include/extractor/node_based_edge.hpp
new file mode 100644
index 0000000..47090e6
--- /dev/null
+++ b/include/extractor/node_based_edge.hpp
@@ -0,0 +1,143 @@
+#ifndef NODE_BASED_EDGE_HPP
+#define NODE_BASED_EDGE_HPP
+
+#include "extractor/travel_mode.hpp"
+#include "util/typedefs.hpp"
+
+#include "extractor/guidance/classification_data.hpp"
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct NodeBasedEdge
+{
+    NodeBasedEdge();
+
+    NodeBasedEdge(NodeID source,
+                  NodeID target,
+                  NodeID name_id,
+                  EdgeWeight weight,
+                  bool forward,
+                  bool backward,
+                  bool roundabout,
+                  bool access_restricted,
+                  bool startpoint,
+                  TravelMode travel_mode,
+                  bool is_split,
+                  guidance::RoadClassificationData road_classification);
+
+    bool operator<(const NodeBasedEdge &other) const;
+
+    NodeID source;
+    NodeID target;
+    NodeID name_id;
+    EdgeWeight weight;
+    bool forward : 1;
+    bool backward : 1;
+    bool roundabout : 1;
+    bool access_restricted : 1;
+    bool startpoint : 1;
+    bool is_split : 1;
+    TravelMode travel_mode : 4;
+    guidance::RoadClassificationData road_classification;
+};
+
+struct NodeBasedEdgeWithOSM : NodeBasedEdge
+{
+    NodeBasedEdgeWithOSM(OSMNodeID source,
+                         OSMNodeID target,
+                         NodeID name_id,
+                         EdgeWeight weight,
+                         bool forward,
+                         bool backward,
+                         bool roundabout,
+                         bool access_restricted,
+                         bool startpoint,
+                         TravelMode travel_mode,
+                         bool is_split,
+                         guidance::RoadClassificationData road_classification);
+
+    OSMNodeID osm_source_id;
+    OSMNodeID osm_target_id;
+};
+
+// Impl.
+
+inline NodeBasedEdge::NodeBasedEdge()
+    : source(SPECIAL_NODEID), target(SPECIAL_NODEID), name_id(0), weight(0), forward(false),
+      backward(false), roundabout(false), access_restricted(false), startpoint(true),
+      is_split(false), travel_mode(false)
+{
+}
+
+inline NodeBasedEdge::NodeBasedEdge(NodeID source,
+                                    NodeID target,
+                                    NodeID name_id,
+                                    EdgeWeight weight,
+                                    bool forward,
+                                    bool backward,
+                                    bool roundabout,
+                                    bool access_restricted,
+                                    bool startpoint,
+                                    TravelMode travel_mode,
+                                    bool is_split,
+                                    guidance::RoadClassificationData road_classification)
+    : source(source), target(target), name_id(name_id), weight(weight), forward(forward),
+      backward(backward), roundabout(roundabout), access_restricted(access_restricted),
+      startpoint(startpoint), is_split(is_split), travel_mode(travel_mode),
+      road_classification(std::move(road_classification))
+{
+}
+
+inline bool NodeBasedEdge::operator<(const NodeBasedEdge &other) const
+{
+    if (source == other.source)
+    {
+        if (target == other.target)
+        {
+            if (weight == other.weight)
+            {
+                return forward && backward && ((!other.forward) || (!other.backward));
+            }
+            return weight < other.weight;
+        }
+        return target < other.target;
+    }
+    return source < other.source;
+}
+
+inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(
+    OSMNodeID source,
+    OSMNodeID target,
+    NodeID name_id,
+    EdgeWeight weight,
+    bool forward,
+    bool backward,
+    bool roundabout,
+    bool access_restricted,
+    bool startpoint,
+    TravelMode travel_mode,
+    bool is_split,
+    guidance::RoadClassificationData road_classification)
+    : NodeBasedEdge(SPECIAL_NODEID,
+                    SPECIAL_NODEID,
+                    name_id,
+                    weight,
+                    forward,
+                    backward,
+                    roundabout,
+                    access_restricted,
+                    startpoint,
+                    travel_mode,
+                    is_split,
+                    std::move(road_classification)),
+      osm_source_id(std::move(source)), osm_target_id(std::move(target))
+{
+}
+
+} // ns extractor
+} // ns osrm
+
+#endif /* NODE_BASED_EDGE_HPP */
diff --git a/include/extractor/original_edge_data.hpp b/include/extractor/original_edge_data.hpp
new file mode 100644
index 0000000..17d234a
--- /dev/null
+++ b/include/extractor/original_edge_data.hpp
@@ -0,0 +1,42 @@
+#ifndef ORIGINAL_EDGE_DATA_HPP
+#define ORIGINAL_EDGE_DATA_HPP
+
+#include "extractor/travel_mode.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+#include "util/typedefs.hpp"
+
+#include <limits>
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct OriginalEdgeData
+{
+    explicit OriginalEdgeData(NodeID via_node,
+                              unsigned name_id,
+                              guidance::TurnInstruction turn_instruction,
+                              TravelMode travel_mode)
+        : via_node(via_node), name_id(name_id), turn_instruction(turn_instruction),
+          travel_mode(travel_mode)
+    {
+    }
+
+    OriginalEdgeData()
+        : via_node(std::numeric_limits<unsigned>::max()),
+          name_id(std::numeric_limits<unsigned>::max()),
+          turn_instruction(guidance::TurnInstruction::INVALID()),
+          travel_mode(TRAVEL_MODE_INACCESSIBLE)
+    {
+    }
+
+    NodeID via_node;
+    unsigned name_id;
+    guidance::TurnInstruction turn_instruction;
+    TravelMode travel_mode;
+};
+}
+}
+
+#endif // ORIGINAL_EDGE_DATA_HPP
diff --git a/include/extractor/profile_properties.hpp b/include/extractor/profile_properties.hpp
new file mode 100644
index 0000000..859034c
--- /dev/null
+++ b/include/extractor/profile_properties.hpp
@@ -0,0 +1,48 @@
+#ifndef PROFILE_PROPERTIES_HPP
+#define PROFILE_PROPERTIES_HPP
+
+#include <boost/numeric/conversion/cast.hpp>
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct ProfileProperties
+{
+    ProfileProperties()
+        : traffic_signal_penalty(0), u_turn_penalty(0), allow_u_turn_at_via(false), use_turn_restrictions(false)
+    {
+    }
+
+    double GetUturnPenalty() const
+    {
+        return u_turn_penalty / 10.;
+    }
+
+    void SetUturnPenalty(const double u_turn_penalty_)
+    {
+        u_turn_penalty = boost::numeric_cast<int>(u_turn_penalty_ * 10.);
+    }
+
+    double GetTrafficSignalPenalty() const
+    {
+        return traffic_signal_penalty / 10.;
+    }
+
+    void SetTrafficSignalPenalty(const double traffic_signal_penalty_)
+    {
+        traffic_signal_penalty = boost::numeric_cast<int>(traffic_signal_penalty_ * 10.);
+    }
+
+    //! penalty to cross a traffic light in deci-seconds
+    int traffic_signal_penalty;
+    //! penalty to do a uturn in deci-seconds
+    int u_turn_penalty;
+    bool allow_u_turn_at_via;
+    bool use_turn_restrictions;
+};
+}
+}
+
+#endif
diff --git a/include/extractor/query_node.hpp b/include/extractor/query_node.hpp
new file mode 100644
index 0000000..93c2d61
--- /dev/null
+++ b/include/extractor/query_node.hpp
@@ -0,0 +1,51 @@
+#ifndef QUERY_NODE_HPP
+#define QUERY_NODE_HPP
+
+#include "util/typedefs.hpp"
+
+#include "util/coordinate.hpp"
+
+#include <limits>
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct QueryNode
+{
+    using key_type = OSMNodeID; // type of NodeID
+    using value_type = int;     // type of lat,lons
+
+    explicit QueryNode(const util::FixedLongitude lon_,
+                       const util::FixedLatitude lat_,
+                       key_type node_id)
+        : lon(lon_), lat(lat_), node_id(std::move(node_id))
+    {
+    }
+    QueryNode()
+        : lon(std::numeric_limits<int>::max()), lat(std::numeric_limits<int>::max()),
+          node_id(SPECIAL_OSM_NODEID)
+    {
+    }
+
+    util::FixedLongitude lon;
+    util::FixedLatitude lat;
+    key_type node_id;
+
+    static QueryNode min_value()
+    {
+        return QueryNode(util::FixedLongitude(-180 * COORDINATE_PRECISION),
+                         util::FixedLatitude(-90 * COORDINATE_PRECISION), MIN_OSM_NODEID);
+    }
+
+    static QueryNode max_value()
+    {
+        return QueryNode(util::FixedLongitude(180 * COORDINATE_PRECISION),
+                         util::FixedLatitude(90 * COORDINATE_PRECISION), MAX_OSM_NODEID);
+    }
+};
+}
+}
+
+#endif // QUERY_NODE_HPP
diff --git a/data_structures/raster_source.hpp b/include/extractor/raster_source.hpp
similarity index 69%
rename from data_structures/raster_source.hpp
rename to include/extractor/raster_source.hpp
index 86c8596..4cc7e02 100644
--- a/data_structures/raster_source.hpp
+++ b/include/extractor/raster_source.hpp
@@ -1,34 +1,8 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 RASTER_SOURCE_HPP
 #define RASTER_SOURCE_HPP
 
-#include "../util/osrm_exception.hpp"
+#include "util/exception.hpp"
+#include "util/coordinate.hpp"
 
 #include <boost/filesystem.hpp>
 #include <boost/filesystem/fstream.hpp>
@@ -40,6 +14,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <unordered_map>
 #include <iterator>
 
+namespace osrm
+{
+namespace extractor
+{
+
 /**
     \brief Small wrapper around raster source queries to optionally provide results
     gracefully, depending on source bounds
@@ -64,10 +43,10 @@ class RasterGrid
         ydim = _ydim;
         _data.reserve(ydim * xdim);
 
-        boost::filesystem::ifstream stream(filepath);
+        boost::filesystem::ifstream stream(filepath, std::ios::binary);
         if (!stream)
         {
-            throw osrm::exception("Unable to open raster file.");
+            throw util::exception("Unable to open raster file.");
         }
 
         stream.seekg(0, std::ios_base::end);
@@ -92,13 +71,13 @@ class RasterGrid
         }
         catch (std::exception const &ex)
         {
-            throw osrm::exception(
+            throw util::exception(
                 std::string("Failed to read from raster source with exception: ") + ex.what());
         }
 
         if (!r || itr != end)
         {
-            throw osrm::exception("Failed to parse raster source correctly.");
+            throw util::exception("Failed to parse raster source correctly.");
         }
     }
 
@@ -163,13 +142,15 @@ class SourceContainer
                          std::size_t nrows,
                          std::size_t ncols);
 
-    RasterDatum getRasterDataFromSource(unsigned int source_id, int lon, int lat);
+    RasterDatum getRasterDataFromSource(unsigned int source_id, double lon, double lat);
 
-    RasterDatum getRasterInterpolateFromSource(unsigned int source_id, int lon, int lat);
+    RasterDatum getRasterInterpolateFromSource(unsigned int source_id, double lon, double lat);
 
   private:
     std::vector<RasterSource> LoadedSources;
     std::unordered_map<std::string, int> LoadedSourcePaths;
 };
+}
+}
 
 #endif /* RASTER_SOURCE_HPP */
diff --git a/data_structures/restriction.hpp b/include/extractor/restriction.hpp
similarity index 69%
rename from data_structures/restriction.hpp
rename to include/extractor/restriction.hpp
index ecab4f9..5916c85 100644
--- a/data_structures/restriction.hpp
+++ b/include/extractor/restriction.hpp
@@ -1,37 +1,15 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 RESTRICTION_HPP
 #define RESTRICTION_HPP
 
-#include "../typedefs.h"
+#include "util/typedefs.hpp"
 
 #include <limits>
 
+namespace osrm
+{
+namespace extractor
+{
+
 struct TurnRestriction
 {
     union WayOrNode
@@ -79,7 +57,7 @@ struct TurnRestriction
 
 /**
  * This is just a wrapper around TurnRestriction used in the extractor.
- * 
+ *
  * Could be merged with TurnRestriction. For now the type-destiction makes sense
  * as the format in which the restriction is presented in the extractor and in the
  * preprocessing is different. (see restriction_parser.cpp)
@@ -130,5 +108,7 @@ struct CmpRestrictionContainerByTo
     value_type max_value() const { return InputRestrictionContainer::max_value(); }
     value_type min_value() const { return InputRestrictionContainer::min_value(); }
 };
+}
+}
 
 #endif // RESTRICTION_HPP
diff --git a/data_structures/restriction_map.hpp b/include/extractor/restriction_map.hpp
similarity index 72%
rename from data_structures/restriction_map.hpp
rename to include/extractor/restriction_map.hpp
index dbca356..3e47867 100644
--- a/data_structures/restriction_map.hpp
+++ b/include/extractor/restriction_map.hpp
@@ -1,36 +1,10 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 RESTRICTION_MAP_HPP
 #define RESTRICTION_MAP_HPP
 
-#include "restriction.hpp"
-#include "../util/std_hash.hpp"
-#include "../typedefs.h"
+#include "extractor/edge_based_edge.hpp"
+#include "extractor/restriction.hpp"
+#include "util/std_hash.hpp"
+#include "util/typedefs.hpp"
 
 #include <boost/assert.hpp>
 
@@ -39,6 +13,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <unordered_set>
 #include <vector>
 
+namespace osrm
+{
+namespace extractor
+{
+
 struct RestrictionSource
 {
     NodeID start_node;
@@ -64,26 +43,32 @@ struct RestrictionTarget
         return (lhs.target_node == rhs.target_node && lhs.is_only == rhs.is_only);
     }
 };
+}
+}
 
 namespace std
 {
-template <> struct hash<RestrictionSource>
+template <> struct hash<osrm::extractor::RestrictionSource>
 {
-    size_t operator()(const RestrictionSource &r_source) const
+    size_t operator()(const osrm::extractor::RestrictionSource &r_source) const
     {
         return hash_val(r_source.start_node, r_source.via_node);
     }
 };
 
-template <> struct hash<RestrictionTarget>
+template <> struct hash<osrm::extractor::RestrictionTarget>
 {
-    size_t operator()(const RestrictionTarget &r_target) const
+    size_t operator()(const osrm::extractor::RestrictionTarget &r_target) const
     {
         return hash_val(r_target.target_node, r_target.is_only);
     }
 };
 }
 
+namespace osrm
+{
+namespace extractor
+{
 /**
     \brief Efficent look up if an edge is the start + via node of a TurnRestriction
     EdgeBasedEdgeFactory decides by it if edges are inserted or geometry is compressed
@@ -91,7 +76,7 @@ template <> struct hash<RestrictionTarget>
 class RestrictionMap
 {
   public:
-    RestrictionMap() : m_count(0) {};
+    RestrictionMap() : m_count(0){}
     RestrictionMap(const std::vector<TurnRestriction> &restriction_list);
 
     // Replace end v with w in each turn restriction containing u as via node
@@ -172,5 +157,7 @@ class RestrictionMap
     std::unordered_set<NodeID> m_restriction_start_nodes;
     std::unordered_set<NodeID> m_no_turn_via_node_set;
 };
+}
+}
 
 #endif // RESTRICTION_MAP_HPP
diff --git a/include/extractor/restriction_parser.hpp b/include/extractor/restriction_parser.hpp
new file mode 100644
index 0000000..d2be8c1
--- /dev/null
+++ b/include/extractor/restriction_parser.hpp
@@ -0,0 +1,58 @@
+#ifndef RESTRICTION_PARSER_HPP
+#define RESTRICTION_PARSER_HPP
+
+#include "extractor/restriction.hpp"
+
+#include <boost/optional/optional.hpp>
+
+#include <string>
+#include <vector>
+
+struct lua_State;
+namespace osmium
+{
+class Relation;
+}
+
+namespace osrm
+{
+namespace extractor
+{
+
+class ProfileProperties;
+
+/**
+ * Parses the relations that represents turn restrictions.
+ *
+ * Currently only restrictions where the via objects is a node are supported.
+ *  from   via   to
+ * ------->(x)-------->
+ *
+ * While this class does not directly invoke any lua code _per relation_ it does
+ * load configuration values from the profile, that are saved in variables.
+ * Namely ```use_turn_restrictions``` and ```get_exceptions```.
+ *
+ * The restriction is represented by the osm id of the from way, the osm id of the
+ * to way and the osm id of the via node. This representation must be post-processed
+ * in the extractor to work with the edge-based data-model of OSRM:
+ * Since the from and to way share the via-node a turn will have the following form:
+ * ...----(a)-----(via)------(b)----...
+ * So it can be represented by the tripe (a, via, b).
+ */
+class RestrictionParser
+{
+  public:
+    RestrictionParser(lua_State *lua_state, const ProfileProperties& properties);
+    boost::optional<InputRestrictionContainer> TryParse(const osmium::Relation &relation) const;
+
+  private:
+    void ReadRestrictionExceptions(lua_State *lua_state);
+    bool ShouldIgnoreRestriction(const std::string &except_tag_string) const;
+
+    std::vector<std::string> restriction_exceptions;
+    bool use_turn_restrictions;
+};
+}
+}
+
+#endif /* RESTRICTION_PARSER_HPP */
diff --git a/include/extractor/scripting_environment.hpp b/include/extractor/scripting_environment.hpp
new file mode 100644
index 0000000..5494c12
--- /dev/null
+++ b/include/extractor/scripting_environment.hpp
@@ -0,0 +1,54 @@
+#ifndef SCRIPTING_ENVIRONMENT_HPP
+#define SCRIPTING_ENVIRONMENT_HPP
+
+#include "extractor/profile_properties.hpp"
+#include "extractor/raster_source.hpp"
+
+#include "util/lua_util.hpp"
+
+#include <string>
+#include <memory>
+#include <mutex>
+#include <tbb/enumerable_thread_specific.h>
+
+struct lua_State;
+
+namespace osrm
+{
+namespace extractor
+{
+
+/**
+ * Creates a lua context and binds osmium way, node and relation objects and
+ * ExtractionWay and ExtractionNode to lua objects.
+ *
+ * Each thread has its own lua state which is implemented with thread specific
+ * storage from TBB.
+ */
+class ScriptingEnvironment
+{
+  public:
+    struct Context
+    {
+        ProfileProperties properties;
+        SourceContainer sources;
+        util::LuaState state;
+    };
+
+    explicit ScriptingEnvironment(const std::string &file_name);
+
+    ScriptingEnvironment(const ScriptingEnvironment &) = delete;
+    ScriptingEnvironment &operator=(const ScriptingEnvironment &) = delete;
+
+    Context &GetContex();
+
+  private:
+    void InitContext(Context &context);
+    std::mutex init_mutex;
+    std::string file_name;
+    tbb::enumerable_thread_specific<std::unique_ptr<Context>> script_contexts;
+};
+}
+}
+
+#endif /* SCRIPTING_ENVIRONMENT_HPP */
diff --git a/algorithms/tarjan_scc.hpp b/include/extractor/tarjan_scc.hpp
similarity index 74%
rename from algorithms/tarjan_scc.hpp
rename to include/extractor/tarjan_scc.hpp
index 5907732..874d3f6 100644
--- a/algorithms/tarjan_scc.hpp
+++ b/include/extractor/tarjan_scc.hpp
@@ -1,45 +1,18 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 TARJAN_SCC_HPP
 #define TARJAN_SCC_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 "util/typedefs.hpp"
+#include "util/deallocating_vector.hpp"
+#include "extractor/node_based_edge.hpp"
+#include "extractor/query_node.hpp"
+#include "util/percent.hpp"
 
-#include "../util/integer_range.hpp"
-#include "../util/simple_logger.hpp"
-#include "../util/std_hash.hpp"
-#include "../util/timing_util.hpp"
+#include "util/integer_range.hpp"
+#include "util/simple_logger.hpp"
+#include "util/std_hash.hpp"
+#include "util/timing_util.hpp"
 
-#include <osrm/coordinate.hpp>
+#include "osrm/coordinate.hpp"
 #include <boost/assert.hpp>
 #include <cstdint>
 
@@ -49,6 +22,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <stack>
 #include <vector>
 
+namespace osrm
+{
+namespace extractor
+{
+
 template <typename GraphT> class TarjanSCC
 {
     struct TarjanStackFrame
@@ -93,7 +71,7 @@ template <typename GraphT> class TarjanSCC
         unsigned component_index = 0, size_of_current_component = 0;
         unsigned index = 0;
         std::vector<bool> processing_node_before_recursion(max_node_id, true);
-        for (const NodeID node : osrm::irange(0u, max_node_id))
+        for (const NodeID node : util::irange(0u, max_node_id))
         {
             if (SPECIAL_NODEID == components_index[node])
             {
@@ -168,8 +146,8 @@ template <typename GraphT> class TarjanSCC
 
                         if (size_of_current_component > 1000)
                         {
-                            SimpleLogger().Write() << "large component [" << component_index
-                                                   << "]=" << size_of_current_component;
+                            util::SimpleLogger().Write() << "large component [" << component_index
+                                                         << "]=" << size_of_current_component;
                         }
 
                         ++component_index;
@@ -180,7 +158,7 @@ template <typename GraphT> class TarjanSCC
         }
 
         TIMER_STOP(SCC_RUN);
-        SimpleLogger().Write() << "SCC run took: " << TIMER_MSEC(SCC_RUN) / 1000. << "s";
+        util::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)
@@ -200,5 +178,7 @@ template <typename GraphT> class TarjanSCC
 
     unsigned get_component_id(const NodeID node) const { return components_index[node]; }
 };
+}
+}
 
 #endif /* TARJAN_SCC_HPP */
diff --git a/data_structures/travel_mode.hpp b/include/extractor/travel_mode.hpp
similarity index 54%
rename from data_structures/travel_mode.hpp
rename to include/extractor/travel_mode.hpp
index 2bbe463..7ec7bec 100644
--- a/data_structures/travel_mode.hpp
+++ b/include/extractor/travel_mode.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2014, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -28,10 +28,30 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef TRAVEL_MODE_HPP
 #define TRAVEL_MODE_HPP
 
-namespace
+namespace osrm
 {
+namespace extractor
+{
+
+// This is a char instead of a typed enum, so that we can
+// pack it into e.g. a "TravelMode mode : 4" packed bitfield
 using TravelMode = unsigned char;
-static const TravelMode TRAVEL_MODE_INACCESSIBLE = 0;
-static const TravelMode TRAVEL_MODE_DEFAULT = 1;
 }
+}
+
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_INACCESSIBLE = 0;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_DRIVING = 1;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_CYCLING = 2;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_WALKING = 3;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_FERRY = 4;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_TRAIN = 5;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_PUSHING_BIKE = 6;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_MOVABLE_BRIDGE = 7;
+// FIXME only for testbot.lua
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_STEPS_UP = 8;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_STEPS_DOWN = 9;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_RIVER_UP = 10;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_RIVER_DOWN = 11;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_ROUTE = 12;
+
 #endif /* TRAVEL_MODE_HPP */
diff --git a/data_structures/tribool.hpp b/include/osrm/bearing.hpp
similarity index 88%
copy from data_structures/tribool.hpp
copy to include/osrm/bearing.hpp
index 2d4b610..75ec110 100644
--- a/data_structures/tribool.hpp
+++ b/include/osrm/bearing.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,16 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef TRIBOOL_HPP
-#define TRIBOOL_HPP
+#ifndef OSRM_BEARING_HPP
+#define OSRM_BEARING_HPP
+
+#include "engine/bearing.hpp"
 
 namespace osrm
 {
-enum class tribool : char
-{
-    yes,
-    no,
-    indeterminate
-};
+  using engine::Bearing;
 }
-#endif // TRIBOOL_HPP
+
+#endif
diff --git a/include/osrm/coordinate.hpp b/include/osrm/coordinate.hpp
index 6318465..39b684d 100644
--- a/include/osrm/coordinate.hpp
+++ b/include/osrm/coordinate.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,47 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef COORDINATE_HPP_
-#define COORDINATE_HPP_
+#ifndef GLOBAL_COORDINATE_HPP
+#define GLOBAL_COORDINATE_HPP
 
-#include <iosfwd> //for std::ostream
-#include <string>
-#include <type_traits>
+#include "util/coordinate.hpp"
 
-namespace
+namespace osrm
 {
-constexpr static const float COORDINATE_PRECISION = 1000000.f;
+using util::Coordinate;
 }
 
-struct FixedPointCoordinate
-{
-    int lat;
-    int lon;
-
-    FixedPointCoordinate();
-    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");
-    }
-
-    bool is_valid() const;
-    bool operator==(const FixedPointCoordinate &other) const;
-
-    float bearing(const FixedPointCoordinate &other) const;
-    void output(std::ostream &out) const;
-};
-
-inline std::ostream &operator<<(std::ostream &out_stream, FixedPointCoordinate const &coordinate)
-{
-    coordinate.output(out_stream);
-    return out_stream;
-}
-
-#endif /* COORDINATE_HPP_ */
+#endif
diff --git a/unit_tests/algorithm_tests.cpp b/include/osrm/engine_config.hpp
similarity index 86%
rename from unit_tests/algorithm_tests.cpp
rename to include/osrm/engine_config.hpp
index 0a9f3fd..e48dceb 100644
--- a/unit_tests/algorithm_tests.cpp
+++ b/include/osrm/engine_config.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2014, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,10 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#define BOOST_TEST_MODULE algorithm tests
+#ifndef GLOBAL_ENGINE_CONFIG_HPP
+#define GLOBAL_ENGINE_CONFIG_HPP
 
-#include <boost/test/unit_test.hpp>
+#include "engine/engine_config.hpp"
 
-/*
- * This file will contain an automatically generated main function.
- */
+namespace osrm
+{
+using engine::EngineConfig;
+}
+
+#endif
diff --git a/include/osrm/json_container.hpp b/include/osrm/json_container.hpp
index 63accb8..7010cf4 100644
--- a/include/osrm/json_container.hpp
+++ b/include/osrm/json_container.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,72 +25,11 @@ 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
-
-#ifndef JSON_CONTAINER_HPP
-#define JSON_CONTAINER_HPP
-
-#include <variant/variant.hpp>
-
-#include <iostream>
-#include <vector>
-#include <string>
-#include <unordered_map>
-
+#ifndef GLOBAL_JSON_CONTAINER_HPP
+#define GLOBAL_JSON_CONTAINER_HPP
+#include "util/json_container.hpp"
 namespace osrm
 {
-namespace json
-{
-
-struct Object;
-struct Array;
-
-struct String
-{
-    String() {}
-    String(const char *value) : value(value) {}
-    String(std::string value) : value(std::move(value)) {}
-    std::string value;
-};
-
-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
-} // namespace osrm
-#endif // JSON_CONTAINER_HPP
+namespace json = osrm::util::json;
+}
+#endif
diff --git a/data_structures/tribool.hpp b/include/osrm/match_parameters.hpp
similarity index 86%
copy from data_structures/tribool.hpp
copy to include/osrm/match_parameters.hpp
index 2d4b610..36e7001 100644
--- a/data_structures/tribool.hpp
+++ b/include/osrm/match_parameters.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,16 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef TRIBOOL_HPP
-#define TRIBOOL_HPP
+#ifndef GLOBAL_MATCH_PARAMETERS_HPP
+#define GLOBAL_MATCH_PARAMETERS_HPP
+
+#include "engine/api/match_parameters.hpp"
 
 namespace osrm
 {
-enum class tribool : char
-{
-    yes,
-    no,
-    indeterminate
-};
+using engine::api::MatchParameters;
 }
-#endif // TRIBOOL_HPP
+
+#endif
diff --git a/data_structures/tribool.hpp b/include/osrm/nearest_parameters.hpp
similarity index 85%
copy from data_structures/tribool.hpp
copy to include/osrm/nearest_parameters.hpp
index 2d4b610..f19131c 100644
--- a/data_structures/tribool.hpp
+++ b/include/osrm/nearest_parameters.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,16 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef TRIBOOL_HPP
-#define TRIBOOL_HPP
+#ifndef GLOBAL_NEAREST_PARAMETERS_HPP
+#define GLOBAL_NEAREST_PARAMETERS_HPP
+
+#include "engine/api/nearest_parameters.hpp"
 
 namespace osrm
 {
-enum class tribool : char
-{
-    yes,
-    no,
-    indeterminate
-};
+using engine::api::NearestParameters;
 }
-#endif // TRIBOOL_HPP
+
+#endif
diff --git a/include/osrm/osrm.hpp b/include/osrm/osrm.hpp
index cbf14d3..1de8610 100644
--- a/include/osrm/osrm.hpp
+++ b/include/osrm/osrm.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -28,29 +28,111 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef OSRM_HPP
 #define OSRM_HPP
 
-#include <memory>
+#include "osrm/osrm_fwd.hpp"
+#include "osrm/status.hpp"
 
-struct LibOSRMConfig;
-struct RouteParameters;
+#include <memory>
+#include <string>
 
 namespace osrm
 {
-namespace json
-{
-struct Object;
-}
-}
+namespace json = util::json;
+using engine::EngineConfig;
+using engine::api::RouteParameters;
+using engine::api::TableParameters;
+using engine::api::NearestParameters;
+using engine::api::TripParameters;
+using engine::api::MatchParameters;
+using engine::api::TileParameters;
 
-class OSRM
+/**
+ * Represents a Open Source Routing Machine with access to its services.
+ *
+ * This represents an Open Source Routing Machine (OSRM) instance, with the services:
+ *
+ *  - Route: shortest path queries for coordinates
+ *  - Table: distance tables for coordinates
+ *  - Nearest: nearest street segment for coordinate
+ *  - Trip: shortest round trip between coordinates
+ *  - Match: snaps noisy coordinate traces to the road network
+ *  - Tile: vector tiles with internal graph representation
+ *
+ *  All services take service-specific parameters, fill a JSON object, and return a status code.
+ */
+class OSRM final
 {
-  private:
-    class OSRM_impl;
-    std::unique_ptr<OSRM_impl> OSRM_pimpl_;
-
   public:
-    OSRM(LibOSRMConfig &lib_config);
-    ~OSRM(); // needed because we need to define it with the implementation of OSRM_impl
-    int RunQuery(const RouteParameters &route_parameters, osrm::json::Object &json_result);
+    /**
+     * Constructs an OSRM instance with user-configurable settings.
+     *
+     * \param config The user-provided OSRM configuration.
+     * \see EngineConfig
+     */
+    explicit OSRM(EngineConfig &config);
+
+    ~OSRM();
+
+    // Moveable but not copyable
+    OSRM(OSRM &&) noexcept;
+    OSRM &operator=(OSRM &&) noexcept;
+
+    /**
+     * Shortest path queries for coordinates.
+     *
+     * \param parameters route query specific parameters
+     * \return Status indicating success for the query or failure
+     * \see Status, RouteParameters and json::Object
+     */
+    Status Route(const RouteParameters &parameters, json::Object &result);
+
+    /**
+     * Distance tables for coordinates.
+     *
+     * \param parameters table query specific parameters
+     * \return Status indicating success for the query or failure
+     * \see Status, TableParameters and json::Object
+     */
+    Status Table(const TableParameters &parameters, json::Object &result);
+
+    /**
+     * Nearest street segment for coordinate.
+     *
+     * \param parameters nearest query specific parameters
+     * \return Status indicating success for the query or failure
+     * \see Status, NearestParameters and json::Object
+     */
+    Status Nearest(const NearestParameters &parameters, json::Object &result);
+
+    /**
+     * Trip: shortest round trip between coordinates.
+     *
+     * \param parameters trip query specific parameters
+     * \return Status indicating success for the query or failure
+     * \see Status, TripParameters and json::Object
+     */
+    Status Trip(const TripParameters &parameters, json::Object &result);
+
+    /**
+     * Match: snaps noisy coordinate traces to the road network
+     *
+     * \param parameters match query specific parameters
+     * \return Status indicating success for the query or failure
+     * \see Status, MatchParameters and json::Object
+     */
+    Status Match(const MatchParameters &parameters, json::Object &result);
+
+    /**
+     * Tile: vector tiles with internal graph representation
+     *
+     * \param parameters tile query specific parameters
+     * \return Status indicating success for the query or failure
+     * \see Status, TileParameters and json::Object
+     */
+    Status Tile(const TileParameters &parameters, std::string &result);
+
+  private:
+    std::unique_ptr<engine::Engine> engine_;
 };
+}
 
 #endif // OSRM_HPP
diff --git a/util/floating_point.hpp b/include/osrm/osrm_fwd.hpp
similarity index 68%
rename from util/floating_point.hpp
rename to include/osrm/osrm_fwd.hpp
index 13f2d3b..f0f1f17 100644
--- a/util/floating_point.hpp
+++ b/include/osrm/osrm_fwd.hpp
@@ -1,5 +1,6 @@
 /*
-Copyright (c) 2013, Project OSRM contributors
+
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -24,21 +25,38 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef FLOATING_POINT_HPP
-#define FLOATING_POINT_HPP
-
-#include <cmath>
+#ifndef OSRM_FWD_HPP
+#define OSRM_FWD_HPP
 
-#include <limits>
-#include <type_traits>
+// OSRM API forward declarations for usage in interfaces. Exposes forward declarations for:
+// osrm::util::json::Object, osrm::engine::api::XParameters
 
 namespace osrm
 {
-template <typename FloatT> bool epsilon_compare(const FloatT number1, const FloatT number2)
+
+namespace util
+{
+namespace json
 {
-    static_assert(std::is_floating_point<FloatT>::value, "type must be floating point");
-    return (std::abs(number1 - number2) < std::numeric_limits<FloatT>::epsilon());
-}
-}
+struct Object;
+} // ns json
+} // ns util
 
-#endif // FLOATING_POINT_HPP
+namespace engine
+{
+namespace api
+{
+struct RouteParameters;
+struct TableParameters;
+struct NearestParameters;
+struct TripParameters;
+struct MatchParameters;
+struct TileParameters;
+} // ns api
+
+class Engine;
+struct EngineConfig;
+} // ns engine
+} // ns osrm
+
+#endif
diff --git a/include/osrm/route_parameters.hpp b/include/osrm/route_parameters.hpp
index 6d2dda7..6c0508c 100644
--- a/include/osrm/route_parameters.hpp
+++ b/include/osrm/route_parameters.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,92 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef ROUTE_PARAMETERS_HPP
-#define ROUTE_PARAMETERS_HPP
+#ifndef GLOBAL_ROUTE_PARAMETERS_HPP
+#define GLOBAL_ROUTE_PARAMETERS_HPP
 
-#include <osrm/coordinate.hpp>
+#include "engine/api/route_parameters.hpp"
 
-#include <boost/fusion/container/vector/vector_fwd.hpp>
-#include <boost/spirit/include/qi.hpp>
-
-#include <string>
-#include <vector>
-
-struct RouteParameters
+namespace osrm
 {
-    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 setClassify(const bool classify);
-
-    void setMatchingBeta(const double beta);
-
-    void setGPSPrecision(const double precision);
-
-    void setDeprecatedAPIFlag(const std::string &);
-
-    void setChecksum(const unsigned check_sum);
-
-    void setInstructionFlag(const bool flag);
-
-    void setService(const std::string &service);
-
-    void setOutputFormat(const std::string &format);
-
-    void setJSONpParameter(const std::string &parameter);
-
-    void addHint(const std::string &hint);
-
-    void addTimestamp(const unsigned timestamp);
-
-    void addBearing(const boost::fusion::vector<int, boost::optional<int>> &received_bearing, boost::spirit::qi::unused_type unused, bool& pass);
-
-    void setLanguage(const std::string &language);
-
-    void setGeometryFlag(const bool flag);
-
-    void setCompressionFlag(const bool flag);
-
-    void addCoordinate(const boost::fusion::vector<double, double> &received_coordinates);
-
-    void addDestination(const boost::fusion::vector<double, double> &received_coordinates);
-
-    void addSource(const boost::fusion::vector<double, double> &received_coordinates);
-
-    void getCoordinatesFromGeometry(const std::string &geometry_string);
-
-    short zoom_level;
-    bool print_instructions;
-    bool alternate_route;
-    bool geometry;
-    bool compression;
-    bool deprecatedAPI;
-    bool uturn_default;
-    bool classify;
-    double matching_beta;
-    double gps_precision;
-    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<unsigned> timestamps;
-    std::vector<std::pair<const int,const boost::optional<int>>> bearings;
-    std::vector<bool> uturns;
-    std::vector<FixedPointCoordinate> coordinates;
-    std::vector<bool> is_destination;
-    std::vector<bool> is_source;
-};
+using engine::api::RouteParameters;
+}
 
-#endif // ROUTE_PARAMETERS_HPP
+#endif
diff --git a/util/fingerprint.cpp b/include/osrm/status.hpp
similarity index 87%
rename from util/fingerprint.cpp
rename to include/osrm/status.hpp
index 8a705b0..8bb1f66 100644
--- a/util/fingerprint.cpp
+++ b/include/osrm/status.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,5 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#include "util/fingerprint.hpp"
-#include "util/fingerprint_impl.hpp"
+#ifndef OSRM_STATUS_HPP
+#define OSRM_STATUS_HPP
+
+#include "engine/status.hpp"
+
+namespace osrm
+{
+using engine::Status;
+}
+
+#endif
diff --git a/unit_tests/datastructure_tests.cpp b/include/osrm/storage_config.hpp
similarity index 85%
rename from unit_tests/datastructure_tests.cpp
rename to include/osrm/storage_config.hpp
index 850d619..353c75e 100644
--- a/unit_tests/datastructure_tests.cpp
+++ b/include/osrm/storage_config.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2014, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,10 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#define BOOST_TEST_MODULE datastructure tests
+#ifndef GLOBAL_STORAGE_CONFIG_HPP
+#define GLOBAL_STORAGE_CONFIG_HPP
 
-#include <boost/test/unit_test.hpp>
+#include "storage/storage_config.hpp"
 
-/*
- * This file will contain an automatically generated main function.
- */
+namespace osrm
+{
+using storage::StorageConfig;
+}
+
+#endif
diff --git a/include/osrm/strong_typedef.hpp b/include/osrm/strong_typedef.hpp
deleted file mode 100644
index c2364b0..0000000
--- a/include/osrm/strong_typedef.hpp
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef OSRM_STRONG_TYPEDEF_HPP
-#define OSRM_STRONG_TYPEDEF_HPP
-
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 <type_traits>
-#include <functional>
-
-/* Creates strongly typed wrappers around scalar types.
- * Useful for stopping accidental assignment of lats to lons,
- * etc.  Also clarifies what this random "int" value is
- * being used for.
- */
-#define OSRM_STRONG_TYPEDEF(From, To)                 \
-  class To final {                                      \
-    static_assert(std::is_arithmetic<From>(), "");      \
-    From x;                                             \
-                                                        \
-   public:                                              \
-    To() = default;                                     \
-    explicit To(const From x_) : x(x_) {}                     \
-    explicit operator From&() { return x; }             \
-    explicit operator const From&() const { return x; } \
-    bool operator <(const To &z_) const { return x < static_cast<const From>(z_) ; } \
-    bool operator >(const To &z_) const { return x > static_cast<const From>(z_) ; } \
-    bool operator <=(const To &z_) const { return x <= static_cast<const From>(z_) ; } \
-    bool operator >=(const To &z_) const { return x >= static_cast<const From>(z_) ; } \
-    bool operator ==(const To &z_) const { return x == static_cast<const From>(z_) ; } \
-    bool operator !=(const To &z_) const { return x != static_cast<const From>(z_) ; } \
-  };                                                    \
-  inline From To##_to_##From(To to) { return static_cast<From>(to); } \
-  namespace std { \
-  template <> \
-  struct hash<To> \
-  { \
-    std::size_t operator()(const To& k) const \
-    { \
-      return std::hash<From>()(static_cast<const From>(k)); \
-    } \
-  }; \
-  }
-
-#endif // OSRM_STRONG_TYPEDEF_HPP
diff --git a/data_structures/tribool.hpp b/include/osrm/table_parameters.hpp
similarity index 86%
copy from data_structures/tribool.hpp
copy to include/osrm/table_parameters.hpp
index 2d4b610..7bb16eb 100644
--- a/data_structures/tribool.hpp
+++ b/include/osrm/table_parameters.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,16 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef TRIBOOL_HPP
-#define TRIBOOL_HPP
+#ifndef GLOBAL_TABLE_PARAMETERS_HPP
+#define GLOBAL_TABLE_PARAMETERS_HPP
+
+#include "engine/api/table_parameters.hpp"
 
 namespace osrm
 {
-enum class tribool : char
-{
-    yes,
-    no,
-    indeterminate
-};
+using engine::api::TableParameters;
 }
-#endif // TRIBOOL_HPP
+
+#endif
diff --git a/data_structures/tribool.hpp b/include/osrm/tile_parameters.hpp
similarity index 86%
copy from data_structures/tribool.hpp
copy to include/osrm/tile_parameters.hpp
index 2d4b610..0672dea 100644
--- a/data_structures/tribool.hpp
+++ b/include/osrm/tile_parameters.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,16 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef TRIBOOL_HPP
-#define TRIBOOL_HPP
+#ifndef GLOBAL_TILE_PARAMETERS_HPP
+#define GLOBAL_TILE_PARAMETERS_HPP
+
+#include "engine/api/tile_parameters.hpp"
 
 namespace osrm
 {
-enum class tribool : char
-{
-    yes,
-    no,
-    indeterminate
-};
+using engine::api::TileParameters;
 }
-#endif // TRIBOOL_HPP
+
+#endif
diff --git a/data_structures/tribool.hpp b/include/osrm/trip_parameters.hpp
similarity index 86%
rename from data_structures/tribool.hpp
rename to include/osrm/trip_parameters.hpp
index 2d4b610..15a70c1 100644
--- a/data_structures/tribool.hpp
+++ b/include/osrm/trip_parameters.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -25,16 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef TRIBOOL_HPP
-#define TRIBOOL_HPP
+#ifndef GLOBAL_TRIP_PARAMETERS_HPP
+#define GLOBAL_TRIP_PARAMETERS_HPP
+
+#include "engine/api/trip_parameters.hpp"
 
 namespace osrm
 {
-enum class tribool : char
-{
-    yes,
-    no,
-    indeterminate
-};
+using engine::api::TripParameters;
 }
-#endif // TRIBOOL_HPP
+
+#endif
diff --git a/include/server/api/base_parameters_grammar.hpp b/include/server/api/base_parameters_grammar.hpp
new file mode 100644
index 0000000..2f9a95e
--- /dev/null
+++ b/include/server/api/base_parameters_grammar.hpp
@@ -0,0 +1,108 @@
+#ifndef SERVER_API_BASE_PARAMETERS_GRAMMAR_HPP
+#define SERVER_API_BASE_PARAMETERS_GRAMMAR_HPP
+
+#include "engine/api/base_parameters.hpp"
+
+#include "engine/polyline_compressor.hpp"
+#include "engine/hint.hpp"
+#include "engine/bearing.hpp"
+
+#include <boost/spirit/include/qi_lit.hpp>
+#include <boost/spirit/include/qi_char_.hpp>
+#include <boost/spirit/include/qi_int.hpp>
+#include <boost/spirit/include/qi_real.hpp>
+#include <boost/spirit/include/qi_grammar.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_optional.hpp>
+#include <boost/spirit/include/qi_attr_cast.hpp>
+#include <boost/spirit/include/qi_operator.hpp>
+#include <boost/spirit/include/qi_repeat.hpp>
+#include <boost/spirit/include/qi_as_string.hpp>
+
+#include <string>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace qi = boost::spirit::qi;
+struct BaseParametersGrammar : boost::spirit::qi::grammar<std::string::iterator>
+{
+    using Iterator = std::string::iterator;
+    using RadiusesT = std::vector<boost::optional<double>>;
+
+    BaseParametersGrammar(qi::rule<Iterator> &root_rule_, engine::api::BaseParameters &parameters_)
+        : BaseParametersGrammar::base_type(root_rule_), base_parameters(parameters_)
+    {
+        const auto add_bearing =
+            [this](boost::optional<boost::fusion::vector2<short, short>> bearing_range)
+        {
+            boost::optional<engine::Bearing> bearing;
+            if (bearing_range)
+            {
+                bearing = engine::Bearing{boost::fusion::at_c<0>(*bearing_range),
+                                          boost::fusion::at_c<1>(*bearing_range)};
+            }
+            base_parameters.bearings.push_back(std::move(bearing));
+        };
+        const auto set_radiuses = [this](RadiusesT &radiuses)
+        {
+            base_parameters.radiuses = std::move(radiuses);
+        };
+        const auto add_hint = [this](const std::string &hint_string)
+        {
+            if (hint_string.size() > 0)
+            {
+                base_parameters.hints.push_back(engine::Hint::FromBase64(hint_string));
+            }
+        };
+        const auto add_coordinate = [this](const boost::fusion::vector<double, double> &lonLat)
+        {
+            base_parameters.coordinates.emplace_back(util::Coordinate(
+                util::FixedLongitude(boost::fusion::at_c<0>(lonLat) * COORDINATE_PRECISION),
+                util::FixedLatitude(boost::fusion::at_c<1>(lonLat) * COORDINATE_PRECISION)));
+        };
+        const auto polyline_to_coordinates = [this](const std::string &polyline)
+        {
+            base_parameters.coordinates = engine::decodePolyline(polyline);
+        };
+
+        alpha_numeral = +qi::char_("a-zA-Z0-9");
+        polyline_chars = qi::char_("a-zA-Z0-9_.--[]{}@?|\\%~`^");
+        base64_char = qi::char_("a-zA-Z0-9--_");
+
+        radiuses_rule = qi::lit("radiuses=") >> -qi::double_ % ";";
+        hints_rule =
+            qi::lit("hints=") >>
+            qi::as_string[qi::repeat(engine::ENCODED_HINT_SIZE)[base64_char]][add_hint] % ";";
+        bearings_rule =
+            qi::lit("bearings=") >> (-(qi::short_ >> ',' >> qi::short_))[add_bearing] % ";";
+        polyline_rule = qi::as_string[qi::lit("polyline(") >> +polyline_chars >>
+                                      qi::lit(")")][polyline_to_coordinates];
+        location_rule = (qi::double_ >> qi::lit(',') >> qi::double_)[add_coordinate];
+        query_rule = (location_rule % ';') | polyline_rule;
+
+        base_rule = bearings_rule | radiuses_rule[set_radiuses] | hints_rule;
+    }
+
+  protected:
+    qi::rule<Iterator> base_rule;
+    qi::rule<Iterator> query_rule;
+
+  private:
+    engine::api::BaseParameters &base_parameters;
+    qi::rule<Iterator> bearings_rule;
+    qi::rule<Iterator> hints_rule;
+    qi::rule<Iterator> polyline_rule, location_rule;
+    qi::rule<Iterator, RadiusesT()> radiuses_rule;
+    qi::rule<Iterator, unsigned char()> base64_char;
+    qi::rule<Iterator, std::string()> alpha_numeral, polyline_chars;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/api/match_parameter_grammar.hpp b/include/server/api/match_parameter_grammar.hpp
new file mode 100644
index 0000000..7628e87
--- /dev/null
+++ b/include/server/api/match_parameter_grammar.hpp
@@ -0,0 +1,88 @@
+#ifndef MATCH_PARAMETERS_GRAMMAR_HPP
+#define MATCH_PARAMETERS_GRAMMAR_HPP
+
+#include "engine/api/match_parameters.hpp"
+
+#include "server/api/base_parameters_grammar.hpp"
+
+#include <boost/spirit/include/qi_lit.hpp>
+#include <boost/spirit/include/qi_uint.hpp>
+#include <boost/spirit/include/qi_bool.hpp>
+#include <boost/spirit/include/qi_grammar.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_optional.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace qi = boost::spirit::qi;
+
+struct MatchParametersGrammar final : public BaseParametersGrammar
+{
+    using Iterator = std::string::iterator;
+    using StepsT = bool;
+    using TimestampsT = std::vector<unsigned>;
+    using GeometriesT = engine::api::RouteParameters::GeometriesType;
+    using OverviewT = engine::api::RouteParameters::OverviewType;
+
+    MatchParametersGrammar() : BaseParametersGrammar(root_rule, parameters)
+    {
+        const auto set_geojson_type = [this]()
+        {
+            parameters.geometries = engine::api::RouteParameters::GeometriesType::GeoJSON;
+        };
+        const auto set_polyline_type = [this]()
+        {
+            parameters.geometries = engine::api::RouteParameters::GeometriesType::Polyline;
+        };
+
+        const auto set_simplified_type = [this]()
+        {
+            parameters.overview = engine::api::RouteParameters::OverviewType::Simplified;
+        };
+        const auto set_full_type = [this]()
+        {
+            parameters.overview = engine::api::RouteParameters::OverviewType::Full;
+        };
+        const auto set_false_type = [this]()
+        {
+            parameters.overview = engine::api::RouteParameters::OverviewType::False;
+        };
+        const auto set_steps = [this](const StepsT steps)
+        {
+            parameters.steps = steps;
+        };
+        const auto set_timestamps = [this](TimestampsT &timestamps)
+        {
+            parameters.timestamps = std::move(timestamps);
+        };
+
+        steps_rule = qi::lit("steps=") >> qi::bool_;
+        geometries_rule = qi::lit("geometries=geojson")[set_geojson_type] |
+                          qi::lit("geometries=polyline")[set_polyline_type];
+        overview_rule = qi::lit("overview=simplified")[set_simplified_type] |
+                        qi::lit("overview=full")[set_full_type] |
+                        qi::lit("overview=false")[set_false_type];
+        timestamps_rule = qi::lit("timestamps=") >> qi::uint_ % ";";
+        match_rule = steps_rule[set_steps] | geometries_rule | overview_rule |
+                     timestamps_rule[set_timestamps];
+        root_rule =
+            query_rule >> -qi::lit(".json") >> -(qi::lit("?") >> (match_rule | base_rule) % '&');
+    }
+
+    engine::api::MatchParameters parameters;
+
+  private:
+    qi::rule<Iterator> root_rule, match_rule, geometries_rule, overview_rule;
+    qi::rule<Iterator, TimestampsT()> timestamps_rule;
+    qi::rule<Iterator, StepsT()> steps_rule;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/api/nearest_parameter_grammar.hpp b/include/server/api/nearest_parameter_grammar.hpp
new file mode 100644
index 0000000..e51ccb5
--- /dev/null
+++ b/include/server/api/nearest_parameter_grammar.hpp
@@ -0,0 +1,48 @@
+#ifndef NEAREST_PARAMETERS_GRAMMAR_HPP
+#define NEAREST_PARAMETERS_GRAMMAR_HPP
+
+#include "engine/api/nearest_parameters.hpp"
+
+#include "server/api/base_parameters_grammar.hpp"
+
+#include <boost/spirit/include/qi_lit.hpp>
+#include <boost/spirit/include/qi_uint.hpp>
+#include <boost/spirit/include/qi_grammar.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_optional.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace qi = boost::spirit::qi;
+
+struct NearestParametersGrammar final : public BaseParametersGrammar
+{
+    using Iterator = std::string::iterator;
+
+    NearestParametersGrammar() : BaseParametersGrammar(root_rule, parameters)
+    {
+        const auto set_number = [this](const unsigned number)
+        {
+            parameters.number_of_results = number;
+        };
+        nearest_rule = (qi::lit("number=") >> qi::uint_)[set_number];
+        root_rule =
+            query_rule >> -qi::lit(".json") >> -(qi::lit("?") >> (nearest_rule | base_rule) % '&');
+    }
+
+    engine::api::NearestParameters parameters;
+
+  private:
+    qi::rule<Iterator> root_rule;
+    qi::rule<Iterator> nearest_rule;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/api/parameters_parser.hpp b/include/server/api/parameters_parser.hpp
new file mode 100644
index 0000000..5af5888
--- /dev/null
+++ b/include/server/api/parameters_parser.hpp
@@ -0,0 +1,49 @@
+#ifndef SERVER_API_ROUTE_PARAMETERS_PARSER_HPP
+#define SERVER_API_ROUTE_PARAMETERS_PARSER_HPP
+
+#include "engine/api/base_parameters.hpp"
+#include "engine/api/tile_parameters.hpp"
+
+#include <boost/optional/optional.hpp>
+
+#include <type_traits>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+// Note: this file provides only the interface for the generic parseParameters function.
+// The actual implementations for each concrete parameter type live in the cpp file.
+
+namespace detail
+{
+template <typename T>
+using is_parameter_t =
+    std::integral_constant<bool,
+                           std::is_base_of<engine::api::BaseParameters, T>::value ||
+                               std::is_same<engine::api::TileParameters, T>::value>;
+} // ns detail
+
+// Starts parsing and iter and modifies it until iter == end or parsing failed
+template <typename ParameterT,
+          typename std::enable_if<detail::is_parameter_t<ParameterT>::value, int>::type = 0>
+boost::optional<ParameterT> parseParameters(std::string::iterator &iter, std::string::iterator end);
+
+// Copy on purpose because we need mutability
+template <typename ParameterT,
+          typename std::enable_if<detail::is_parameter_t<ParameterT>::value, int>::type = 0>
+boost::optional<ParameterT> parseParameters(std::string options_string)
+{
+    auto first = options_string.begin();
+    const auto last = options_string.end();
+    return parseParameters<ParameterT>(first, last);
+}
+
+} // ns api
+} // ns server
+} // ns osrm
+
+#endif
diff --git a/include/server/api/parsed_url.hpp b/include/server/api/parsed_url.hpp
new file mode 100644
index 0000000..224f4a6
--- /dev/null
+++ b/include/server/api/parsed_url.hpp
@@ -0,0 +1,27 @@
+#ifndef SERVER_API_PARSED_URL_HPP
+#define SERVER_API_PARSED_URL_HPP
+
+#include "util/coordinate.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+struct ParsedURL
+{
+    std::string service;
+    unsigned version;
+    std::string profile;
+    std::string query;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/api/route_parameters_grammar.hpp b/include/server/api/route_parameters_grammar.hpp
new file mode 100644
index 0000000..d85d435
--- /dev/null
+++ b/include/server/api/route_parameters_grammar.hpp
@@ -0,0 +1,96 @@
+#ifndef ROUTE_PARAMETERS_GRAMMAR_HPP
+#define ROUTE_PARAMETERS_GRAMMAR_HPP
+
+#include "engine/api/route_parameters.hpp"
+
+#include "server/api/base_parameters_grammar.hpp"
+
+#include <boost/spirit/include/qi_lit.hpp>
+#include <boost/spirit/include/qi_bool.hpp>
+#include <boost/spirit/include/qi_grammar.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_optional.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace qi = boost::spirit::qi;
+
+struct RouteParametersGrammar : public BaseParametersGrammar
+{
+    using Iterator = std::string::iterator;
+    using StepsT = bool;
+    using AlternativeT = bool;
+    using GeometriesT = engine::api::RouteParameters::GeometriesType;
+    using OverviewT = engine::api::RouteParameters::OverviewType;
+    using UturnsT = bool;
+
+    RouteParametersGrammar() : BaseParametersGrammar(root_rule, parameters)
+    {
+        const auto set_geojson_type = [this]()
+        {
+            parameters.geometries = engine::api::RouteParameters::GeometriesType::GeoJSON;
+        };
+        const auto set_polyline_type = [this]()
+        {
+            parameters.geometries = engine::api::RouteParameters::GeometriesType::Polyline;
+        };
+
+        const auto set_simplified_type = [this]()
+        {
+            parameters.overview = engine::api::RouteParameters::OverviewType::Simplified;
+        };
+        const auto set_full_type = [this]()
+        {
+            parameters.overview = engine::api::RouteParameters::OverviewType::Full;
+        };
+        const auto set_false_type = [this]()
+        {
+            parameters.overview = engine::api::RouteParameters::OverviewType::False;
+        };
+        const auto set_steps = [this](const StepsT steps)
+        {
+            parameters.steps = steps;
+        };
+        const auto set_alternatives = [this](const AlternativeT alternatives)
+        {
+            parameters.alternatives = alternatives;
+        };
+        const auto set_uturns = [this](UturnsT &uturns)
+        {
+            parameters.uturns = std::move(uturns);
+        };
+
+        alternatives_rule = qi::lit("alternatives=") >> qi::bool_;
+        steps_rule = qi::lit("steps=") >> qi::bool_;
+        geometries_rule = qi::lit("geometries=geojson")[set_geojson_type] |
+                          qi::lit("geometries=polyline")[set_polyline_type];
+        overview_rule = qi::lit("overview=simplified")[set_simplified_type] |
+                        qi::lit("overview=full")[set_full_type] |
+                        qi::lit("overview=false")[set_false_type];
+        uturns_rule = qi::lit("uturns=default") | (qi::lit("uturns=") >> qi::bool_)[set_uturns];
+        route_rule = steps_rule[set_steps] | alternatives_rule[set_alternatives] | geometries_rule |
+                     overview_rule | uturns_rule;
+
+        root_rule =
+            query_rule >> -qi::lit(".json") >> -(qi::lit("?") >> (route_rule | base_rule) % '&');
+    }
+
+    engine::api::RouteParameters parameters;
+
+  private:
+    qi::rule<Iterator> root_rule;
+    qi::rule<Iterator> route_rule, geometries_rule, overview_rule;
+    qi::rule<Iterator, UturnsT()> uturns_rule;
+    qi::rule<Iterator, StepsT()> steps_rule;
+    qi::rule<Iterator, AlternativeT()> alternatives_rule;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/api/table_parameter_grammar.hpp b/include/server/api/table_parameter_grammar.hpp
new file mode 100644
index 0000000..d5acb04
--- /dev/null
+++ b/include/server/api/table_parameter_grammar.hpp
@@ -0,0 +1,61 @@
+#ifndef TABLE_PARAMETERS_GRAMMAR_HPP
+#define TABLE_PARAMETERS_GRAMMAR_HPP
+
+#include "engine/api/table_parameters.hpp"
+
+#include "server/api/base_parameters_grammar.hpp"
+
+#include <boost/spirit/include/qi_lit.hpp>
+#include <boost/spirit/include/qi_uint.hpp>
+#include <boost/spirit/include/qi_grammar.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_optional.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace qi = boost::spirit::qi;
+
+struct TableParametersGrammar final : public BaseParametersGrammar
+{
+    using Iterator = std::string::iterator;
+    using SourcesT = std::vector<std::size_t>;
+    using DestinationsT = std::vector<std::size_t>;
+
+    TableParametersGrammar() : BaseParametersGrammar(root_rule, parameters)
+    {
+        const auto set_destiantions = [this](DestinationsT &dests)
+        {
+            parameters.destinations = std::move(dests);
+        };
+        const auto set_sources = [this](SourcesT &sources)
+        {
+            parameters.sources = std::move(sources);
+        };
+        destinations_rule = (qi::lit("destinations=") >> (qi::ulong_ % ";")[set_destiantions]) |
+                            qi::lit("destinations=all");
+        sources_rule =
+            (qi::lit("sources=") >> (qi::ulong_ % ";")[set_sources]) | qi::lit("sources=all");
+        table_rule = destinations_rule | sources_rule;
+
+        root_rule =
+            query_rule >> -qi::lit(".json") >> -(qi::lit("?") >> (table_rule | base_rule) % '&');
+    }
+
+    engine::api::TableParameters parameters;
+
+  private:
+    qi::rule<Iterator> root_rule;
+    qi::rule<Iterator> table_rule;
+    qi::rule<Iterator> sources_rule;
+    qi::rule<Iterator> destinations_rule;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/api/tile_parameter_grammar.hpp b/include/server/api/tile_parameter_grammar.hpp
new file mode 100644
index 0000000..2212b81
--- /dev/null
+++ b/include/server/api/tile_parameter_grammar.hpp
@@ -0,0 +1,59 @@
+#ifndef SERVER_API_TILE_PARAMETERS_GRAMMAR_HPP
+#define SERVER_API_TILE_PARAMETERS_GRAMMAR_HPP
+
+#include "engine/api/tile_parameters.hpp"
+
+#include "engine/polyline_compressor.hpp"
+#include "engine/hint.hpp"
+
+#include <boost/spirit/include/qi_lit.hpp>
+#include <boost/spirit/include/qi_uint.hpp>
+#include <boost/spirit/include/qi_grammar.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_operator.hpp>
+
+#include <string>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace qi = boost::spirit::qi;
+struct TileParametersGrammar final : boost::spirit::qi::grammar<std::string::iterator>
+{
+    using Iterator = std::string::iterator;
+
+    TileParametersGrammar() : TileParametersGrammar::base_type(root_rule)
+    {
+        const auto set_x = [this](const unsigned x_)
+        {
+            parameters.x = x_;
+        };
+        const auto set_y = [this](const unsigned y_)
+        {
+            parameters.y = y_;
+        };
+        const auto set_z = [this](const unsigned z_)
+        {
+            parameters.z = z_;
+        };
+
+        query_rule = qi::lit("tile(") >> qi::uint_[set_x] >> qi::lit(",") >> qi::uint_[set_y] >>
+                     qi::lit(",") >> qi::uint_[set_z] >> qi::lit(")");
+
+        root_rule = query_rule >> qi::lit(".mvt");
+    }
+    engine::api::TileParameters parameters;
+
+  private:
+    qi::rule<Iterator> root_rule;
+    qi::rule<Iterator> query_rule;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/api/trip_parameter_grammar.hpp b/include/server/api/trip_parameter_grammar.hpp
new file mode 100644
index 0000000..3165d99
--- /dev/null
+++ b/include/server/api/trip_parameter_grammar.hpp
@@ -0,0 +1,81 @@
+#ifndef TRIP_PARAMETERS_GRAMMAR_HPP
+#define TRIP_PARAMETERS_GRAMMAR_HPP
+
+#include "engine/api/trip_parameters.hpp"
+
+#include "server/api/base_parameters_grammar.hpp"
+
+#include <boost/spirit/include/qi_lit.hpp>
+#include <boost/spirit/include/qi_uint.hpp>
+#include <boost/spirit/include/qi_bool.hpp>
+#include <boost/spirit/include/qi_grammar.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_optional.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace qi = boost::spirit::qi;
+
+struct TripParametersGrammar final : public BaseParametersGrammar
+{
+    using Iterator = std::string::iterator;
+    using StepsT = bool;
+    using GeometriesT = engine::api::RouteParameters::GeometriesType;
+    using OverviewT = engine::api::RouteParameters::OverviewType;
+
+    TripParametersGrammar() : BaseParametersGrammar(root_rule, parameters)
+    {
+        const auto set_geojson_type = [this]()
+        {
+            parameters.geometries = engine::api::RouteParameters::GeometriesType::GeoJSON;
+        };
+        const auto set_polyline_type = [this]()
+        {
+            parameters.geometries = engine::api::RouteParameters::GeometriesType::Polyline;
+        };
+
+        const auto set_simplified_type = [this]()
+        {
+            parameters.overview = engine::api::RouteParameters::OverviewType::Simplified;
+        };
+        const auto set_full_type = [this]()
+        {
+            parameters.overview = engine::api::RouteParameters::OverviewType::Full;
+        };
+        const auto set_false_type = [this]()
+        {
+            parameters.overview = engine::api::RouteParameters::OverviewType::False;
+        };
+        const auto set_steps = [this](const StepsT steps)
+        {
+            parameters.steps = steps;
+        };
+
+        steps_rule = qi::lit("steps=") >> qi::bool_;
+        geometries_rule = qi::lit("geometries=geojson")[set_geojson_type] |
+                          qi::lit("geometries=polyline")[set_polyline_type];
+        overview_rule = qi::lit("overview=simplified")[set_simplified_type] |
+                        qi::lit("overview=full")[set_full_type] |
+                        qi::lit("overview=false")[set_false_type];
+        trip_rule = steps_rule[set_steps] | geometries_rule | overview_rule;
+
+        root_rule =
+            query_rule >> -qi::lit(".json") >> -(qi::lit("?") >> (trip_rule | base_rule) % '&');
+    }
+
+    engine::api::TripParameters parameters;
+
+  private:
+    qi::rule<Iterator> root_rule, trip_rule, geometries_rule, overview_rule;
+    qi::rule<Iterator, StepsT()> steps_rule;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/api/url_parser.hpp b/include/server/api/url_parser.hpp
new file mode 100644
index 0000000..0bac20f
--- /dev/null
+++ b/include/server/api/url_parser.hpp
@@ -0,0 +1,29 @@
+#ifndef SERVER_URL_PARSER_HPP
+#define SERVER_URL_PARSER_HPP
+
+#include "server/api/parsed_url.hpp"
+
+#include <boost/optional.hpp>
+
+#include <string>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+// Starts parsing and iter and modifies it until iter == end or parsing failed
+boost::optional<ParsedURL> parseURL(std::string::iterator &iter, std::string::iterator end);
+// copy on purpose because we need mutability
+inline boost::optional<ParsedURL> parseURL(std::string url_string)
+{
+    auto iter = url_string.begin();
+    return parseURL(iter, url_string.end());
+}
+}
+}
+}
+
+#endif
diff --git a/include/server/connection.hpp b/include/server/connection.hpp
new file mode 100644
index 0000000..0882159
--- /dev/null
+++ b/include/server/connection.hpp
@@ -0,0 +1,72 @@
+#ifndef CONNECTION_HPP
+#define CONNECTION_HPP
+
+#include "server/http/compression_type.hpp"
+#include "server/http/reply.hpp"
+#include "server/http/request.hpp"
+#include "server/request_parser.hpp"
+
+#include <boost/array.hpp>
+#include <boost/asio.hpp>
+#include <boost/config.hpp>
+#include <boost/version.hpp>
+
+#include <memory>
+#include <vector>
+
+// workaround for incomplete std::shared_ptr compatibility in old boost versions
+#if BOOST_VERSION < 105300 || defined BOOST_NO_CXX11_SMART_PTR
+
+namespace boost
+{
+template <class T> const T *get_pointer(std::shared_ptr<T> const &p) { return p.get(); }
+
+template <class T> T *get_pointer(std::shared_ptr<T> &p) { return p.get(); }
+} // namespace boost
+
+#endif
+
+namespace osrm
+{
+namespace server
+{
+
+class RequestHandler;
+
+/// Represents a single connection from a client.
+class Connection : public std::enable_shared_from_this<Connection>
+{
+  public:
+    explicit Connection(boost::asio::io_service &io_service, RequestHandler &handler);
+    Connection(const Connection &) = delete;
+    Connection &operator=(const Connection &) = delete;
+
+    boost::asio::ip::tcp::socket &socket();
+
+    /// Start the first asynchronous operation for the connection.
+    void start();
+
+  private:
+    void handle_read(const boost::system::error_code &e, std::size_t bytes_transferred);
+
+    /// Handle completion of a write operation.
+    void handle_write(const boost::system::error_code &e);
+
+    std::vector<char> compress_buffers(const std::vector<char> &uncompressed_data,
+                                       const http::compression_type compression_type);
+
+    boost::asio::io_service::strand strand;
+    boost::asio::ip::tcp::socket TCP_socket;
+    RequestHandler &request_handler;
+    RequestParser request_parser;
+    boost::array<char, 8192> incoming_data_buffer;
+    http::request current_request;
+    http::reply current_reply;
+    std::vector<char> compressed_output;
+    // Header compression_header;
+    std::vector<boost::asio::const_buffer> output_buffer;
+};
+}
+}
+
+#endif // CONNECTION_HPP
diff --git a/include/server/http/compression_type.hpp b/include/server/http/compression_type.hpp
new file mode 100644
index 0000000..7ff929c
--- /dev/null
+++ b/include/server/http/compression_type.hpp
@@ -0,0 +1,21 @@
+#ifndef COMPRESSION_TYPE_HPP
+#define COMPRESSION_TYPE_HPP
+
+namespace osrm
+{
+namespace server
+{
+namespace http
+{
+
+enum compression_type
+{
+    no_compression,
+    gzip_rfc1952,
+    deflate_rfc1951
+};
+}
+}
+}
+
+#endif // COMPRESSION_TYPE_HPP
diff --git a/include/server/http/header.hpp b/include/server/http/header.hpp
new file mode 100644
index 0000000..33cc4bb
--- /dev/null
+++ b/include/server/http/header.hpp
@@ -0,0 +1,34 @@
+#ifndef HEADER_HPP
+#define HEADER_HPP
+
+#include <string>
+#include <algorithm>
+
+namespace osrm
+{
+namespace server
+{
+namespace http
+{
+
+struct header
+{
+    // explicitly use default copy c'tor as adding move c'tor
+    header &operator=(const header &other) = default;
+    header(std::string name, std::string value) : name(std::move(name)), value(std::move(value)) {}
+    header(header &&other) : name(std::move(other.name)), value(std::move(other.value)) {}
+
+    void clear()
+    {
+        name.clear();
+        value.clear();
+    }
+
+    std::string name;
+    std::string value;
+};
+}
+}
+}
+
+#endif // HEADER_HPP
diff --git a/include/server/http/reply.hpp b/include/server/http/reply.hpp
new file mode 100644
index 0000000..8474a5c
--- /dev/null
+++ b/include/server/http/reply.hpp
@@ -0,0 +1,45 @@
+#ifndef REPLY_HPP
+#define REPLY_HPP
+
+#include "server/http/header.hpp"
+
+#include <boost/asio.hpp>
+
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace http
+{
+
+class reply
+{
+  public:
+    enum status_type
+    {
+        ok = 200,
+        bad_request = 400,
+        internal_server_error = 500
+    } status;
+
+    std::vector<header> headers;
+    std::vector<boost::asio::const_buffer> to_buffers();
+    std::vector<boost::asio::const_buffer> headers_to_buffers();
+    std::vector<char> content;
+    static reply stock_reply(const status_type status);
+    void set_size(const std::size_t size);
+    void set_uncompressed_size();
+
+    reply();
+
+  private:
+    std::string status_to_string(reply::status_type status);
+    boost::asio::const_buffer status_to_buffer(reply::status_type status);
+};
+}
+}
+}
+
+#endif // REPLY_HPP
diff --git a/include/server/http/request.hpp b/include/server/http/request.hpp
new file mode 100644
index 0000000..1b86253
--- /dev/null
+++ b/include/server/http/request.hpp
@@ -0,0 +1,26 @@
+#ifndef REQUEST_HPP
+#define REQUEST_HPP
+
+#include <boost/asio.hpp>
+
+#include <string>
+
+namespace osrm
+{
+namespace server
+{
+namespace http
+{
+
+struct request
+{
+    std::string uri;
+    std::string referrer;
+    std::string agent;
+    boost::asio::ip::address endpoint;
+};
+}
+}
+}
+
+#endif // REQUEST_HPP
diff --git a/include/server/request_handler.hpp b/include/server/request_handler.hpp
new file mode 100644
index 0000000..d76ba6d
--- /dev/null
+++ b/include/server/request_handler.hpp
@@ -0,0 +1,37 @@
+#ifndef REQUEST_HANDLER_HPP
+#define REQUEST_HANDLER_HPP
+
+#include "server/service_handler.hpp"
+
+#include <string>
+
+namespace osrm
+{
+namespace server
+{
+
+namespace http
+{
+class reply;
+struct request;
+}
+
+class RequestHandler
+{
+
+  public:
+    RequestHandler() = default;
+    RequestHandler(const RequestHandler &) = delete;
+    RequestHandler &operator=(const RequestHandler &) = delete;
+
+    void RegisterServiceHandler(std::unique_ptr<ServiceHandler> service_handler);
+
+    void HandleRequest(const http::request &current_request, http::reply &current_reply);
+
+  private:
+    std::unique_ptr<ServiceHandler> service_handler;
+};
+}
+}
+
+#endif // REQUEST_HANDLER_HPP
diff --git a/include/server/request_parser.hpp b/include/server/request_parser.hpp
new file mode 100644
index 0000000..3ac4c17
--- /dev/null
+++ b/include/server/request_parser.hpp
@@ -0,0 +1,76 @@
+#ifndef REQUEST_PARSER_HPP
+#define REQUEST_PARSER_HPP
+
+#include "server/http/compression_type.hpp"
+#include "server/http/header.hpp"
+
+#include <tuple>
+
+namespace osrm
+{
+namespace server
+{
+
+namespace http
+{
+struct request;
+}
+
+class RequestParser
+{
+  public:
+    RequestParser();
+
+    enum class RequestStatus : char
+    {
+        valid,
+        invalid,
+        indeterminate
+    };
+
+    std::tuple<RequestStatus, http::compression_type>
+    parse(http::request &current_request, char *begin, char *end);
+
+  private:
+    RequestStatus consume(http::request &current_request, const char input);
+
+    bool is_char(const int character) const;
+
+    bool is_CTL(const int character) const;
+
+    bool is_special(const int character) const;
+
+    bool is_digit(const int character) const;
+
+    enum class internal_state : unsigned char
+    {
+        method_start,
+        method,
+        uri_start,
+        uri,
+        http_version_h,
+        http_version_t_1,
+        http_version_t_2,
+        http_version_p,
+        http_version_slash,
+        http_version_major_start,
+        http_version_major,
+        http_version_minor_start,
+        http_version_minor,
+        expecting_newline_1,
+        header_line_start,
+        header_lws,
+        header_name,
+        space_before_header_value,
+        header_value,
+        expecting_newline_2,
+        expecting_newline_3
+    } state;
+
+    http::header current_header;
+    http::compression_type selected_compression;
+};
+}
+}
+
+#endif // REQUEST_PARSER_HPP
diff --git a/server/server.hpp b/include/server/server.hpp
similarity index 57%
rename from server/server.hpp
rename to include/server/server.hpp
index 80fae97..8813074 100644
--- a/server/server.hpp
+++ b/include/server/server.hpp
@@ -1,38 +1,12 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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_HPP
 #define SERVER_HPP
 
-#include "connection.hpp"
-#include "request_handler.hpp"
+#include "server/connection.hpp"
+#include "server/request_handler.hpp"
+#include "server/service_handler.hpp"
 
-#include "../util/integer_range.hpp"
-#include "../util/simple_logger.hpp"
+#include "util/integer_range.hpp"
+#include "util/simple_logger.hpp"
 
 #include <boost/asio.hpp>
 #include <boost/bind.hpp>
@@ -45,6 +19,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <vector>
 #include <string>
 
+namespace osrm
+{
+namespace server
+{
+
 class Server
 {
   public:
@@ -52,7 +31,8 @@ class Server
     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();
+        util::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);
@@ -60,7 +40,7 @@ class Server
 
     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(std::make_shared<http::Connection>(io_service, request_handler))
+          new_connection(std::make_shared<Connection>(io_service, request_handler))
     {
         const auto port_string = std::to_string(port);
 
@@ -72,6 +52,9 @@ class Server
         acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
         acceptor.bind(endpoint);
         acceptor.listen();
+
+        util::SimpleLogger().Write() << "Listening on: " << acceptor.local_endpoint();
+
         acceptor.async_accept(
             new_connection->socket(),
             boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
@@ -94,7 +77,10 @@ class Server
 
     void Stop() { io_service.stop(); }
 
-    RequestHandler &GetRequestHandlerPtr() { return request_handler; }
+    void RegisterServiceHandler(std::unique_ptr<ServiceHandler> service_handler_)
+    {
+        request_handler.RegisterServiceHandler(std::move(service_handler_));
+    }
 
   private:
     void HandleAccept(const boost::system::error_code &e)
@@ -102,7 +88,7 @@ class Server
         if (!e)
         {
             new_connection->start();
-            new_connection = std::make_shared<http::Connection>(io_service, request_handler);
+            new_connection = std::make_shared<Connection>(io_service, request_handler);
             acceptor.async_accept(
                 new_connection->socket(),
                 boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
@@ -112,8 +98,10 @@ class Server
     unsigned thread_pool_size;
     boost::asio::io_service io_service;
     boost::asio::ip::tcp::acceptor acceptor;
-    std::shared_ptr<http::Connection> new_connection;
+    std::shared_ptr<Connection> new_connection;
     RequestHandler request_handler;
 };
+}
+}
 
 #endif // SERVER_HPP
diff --git a/include/server/service/base_service.hpp b/include/server/service/base_service.hpp
new file mode 100644
index 0000000..36c82db
--- /dev/null
+++ b/include/server/service/base_service.hpp
@@ -0,0 +1,39 @@
+#ifndef SERVER_SERVICE_BASE_SERVICE_HPP
+#define SERVER_SERVICE_BASE_SERVICE_HPP
+
+#include "engine/status.hpp"
+#include "util/coordinate.hpp"
+#include "osrm/osrm.hpp"
+
+#include <variant/variant.hpp>
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+class BaseService
+{
+  public:
+    using ResultT = mapbox::util::variant<util::json::Object, std::string>;
+
+    BaseService(OSRM &routing_machine) : routing_machine(routing_machine) {}
+    virtual ~BaseService() = default;
+
+    virtual engine::Status RunQuery(std::string &query, ResultT &result) = 0;
+
+    virtual unsigned GetVersion() = 0;
+
+  protected:
+    OSRM &routing_machine;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/service/match_service.hpp b/include/server/service/match_service.hpp
new file mode 100644
index 0000000..23212c1
--- /dev/null
+++ b/include/server/service/match_service.hpp
@@ -0,0 +1,33 @@
+#ifndef SERVER_SERVICE_MATCH_SERVICE_HPP
+#define SERVER_SERVICE_MATCH_SERVICE_HPP
+
+#include "server/service/base_service.hpp"
+
+#include "engine/status.hpp"
+#include "util/coordinate.hpp"
+#include "osrm/osrm.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+class MatchService final : public BaseService
+{
+  public:
+    MatchService(OSRM &routing_machine) : BaseService(routing_machine) {}
+
+    engine::Status RunQuery(std::string &query, ResultT &result) final override;
+
+    unsigned GetVersion() final override { return 1; }
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/service/nearest_service.hpp b/include/server/service/nearest_service.hpp
new file mode 100644
index 0000000..222003c
--- /dev/null
+++ b/include/server/service/nearest_service.hpp
@@ -0,0 +1,33 @@
+#ifndef SERVER_SERVICE_NEAREST_SERVICE_HPP
+#define SERVER_SERVICE_NEAREST_SERVICE_HPP
+
+#include "server/service/base_service.hpp"
+
+#include "engine/status.hpp"
+#include "util/coordinate.hpp"
+#include "osrm/osrm.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+class NearestService final : public BaseService
+{
+  public:
+    NearestService(OSRM &routing_machine) : BaseService(routing_machine) {}
+
+    engine::Status RunQuery(std::string &query, ResultT &result) final override;
+
+    unsigned GetVersion() final override { return 1; }
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/service/route_service.hpp b/include/server/service/route_service.hpp
new file mode 100644
index 0000000..1115585
--- /dev/null
+++ b/include/server/service/route_service.hpp
@@ -0,0 +1,33 @@
+#ifndef SERVER_SERVICE_ROUTE_SERVICE_HPP
+#define SERVER_SERVICE_ROUTE_SERVICE_HPP
+
+#include "server/service/base_service.hpp"
+
+#include "engine/status.hpp"
+#include "util/coordinate.hpp"
+#include "osrm/osrm.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+class RouteService final : public BaseService
+{
+  public:
+    RouteService(OSRM &routing_machine) : BaseService(routing_machine) {}
+
+    engine::Status RunQuery(std::string &query, ResultT &result) final override;
+
+    unsigned GetVersion() final override { return 1; }
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/service/table_service.hpp b/include/server/service/table_service.hpp
new file mode 100644
index 0000000..61b9d84
--- /dev/null
+++ b/include/server/service/table_service.hpp
@@ -0,0 +1,33 @@
+#ifndef SERVER_SERVICE_TABLE_SERVICE_HPP
+#define SERVER_SERVICE_TABLE_SERVICE_HPP
+
+#include "server/service/base_service.hpp"
+
+#include "engine/status.hpp"
+#include "util/coordinate.hpp"
+#include "osrm/osrm.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+class TableService final : public BaseService
+{
+  public:
+    TableService(OSRM &routing_machine) : BaseService(routing_machine) {}
+
+    engine::Status RunQuery(std::string &query, ResultT &result) final override;
+
+    unsigned GetVersion() final override { return 1; }
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/service/tile_service.hpp b/include/server/service/tile_service.hpp
new file mode 100644
index 0000000..05365d4
--- /dev/null
+++ b/include/server/service/tile_service.hpp
@@ -0,0 +1,33 @@
+#ifndef SERVER_SERVICE_TILE_SERVICE_HPP
+#define SERVER_SERVICE_TILE_SERVICE_HPP
+
+#include "server/service/base_service.hpp"
+
+#include "engine/status.hpp"
+#include "util/coordinate.hpp"
+#include "osrm/osrm.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+class TileService final : public BaseService
+{
+  public:
+    TileService(OSRM &routing_machine) : BaseService(routing_machine) {}
+
+    engine::Status RunQuery(std::string &query, ResultT &result) final override;
+
+    unsigned GetVersion() final override { return 1; }
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/service/trip_service.hpp b/include/server/service/trip_service.hpp
new file mode 100644
index 0000000..7daeba6
--- /dev/null
+++ b/include/server/service/trip_service.hpp
@@ -0,0 +1,33 @@
+#ifndef SERVER_SERVICE_TRIP_SERVICE_HPP
+#define SERVER_SERVICE_TRIP_SERVICE_HPP
+
+#include "server/service/base_service.hpp"
+
+#include "engine/status.hpp"
+#include "util/coordinate.hpp"
+#include "osrm/osrm.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+class TripService final : public BaseService
+{
+  public:
+    TripService(OSRM &routing_machine) : BaseService(routing_machine) {}
+
+    engine::Status RunQuery(std::string &query, ResultT &result) final override;
+
+    unsigned GetVersion() final override { return 1; }
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/service/utils.hpp b/include/server/service/utils.hpp
new file mode 100644
index 0000000..e4fd7df
--- /dev/null
+++ b/include/server/service/utils.hpp
@@ -0,0 +1,29 @@
+#include <boost/format.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+const constexpr char PARAMETER_SIZE_MISMATCH_MSG[] =
+    "Number of elements in %1% size %2% does not match coordinate size %3%";
+
+template <typename ParamT>
+bool constrainParamSize(const char *msg_template,
+                        const char *name,
+                        const ParamT &param,
+                        const std::size_t target_size,
+                        std::string &help)
+{
+    if (param.size() > 0 && param.size() != target_size)
+    {
+        help = (boost::format(msg_template) % name % param.size() % target_size).str();
+        return true;
+    }
+    return false;
+}
+}
+}
+}
diff --git a/include/server/service_handler.hpp b/include/server/service_handler.hpp
new file mode 100644
index 0000000..cb9b037
--- /dev/null
+++ b/include/server/service_handler.hpp
@@ -0,0 +1,41 @@
+#ifndef SERVER_SERVICE_HANLDER_HPP
+#define SERVER_SERVICE_HANLDER_HPP
+
+#include "server/service/base_service.hpp"
+
+#include "osrm/osrm.hpp"
+
+#include <unordered_map>
+
+namespace osrm
+{
+namespace util
+{
+namespace json
+{
+struct Object;
+}
+}
+namespace server
+{
+namespace api
+{
+struct ParsedURL;
+}
+
+class ServiceHandler
+{
+  public:
+    ServiceHandler(osrm::EngineConfig &config);
+    using ResultT = service::BaseService::ResultT;
+
+    engine::Status RunQuery(api::ParsedURL parsed_url, ResultT &result);
+
+  private:
+    std::unordered_map<std::string, std::unique_ptr<service::BaseService>> service_map;
+    OSRM routing_machine;
+};
+}
+}
+
+#endif
diff --git a/include/storage/shared_barriers.hpp b/include/storage/shared_barriers.hpp
new file mode 100644
index 0000000..48d305c
--- /dev/null
+++ b/include/storage/shared_barriers.hpp
@@ -0,0 +1,39 @@
+#ifndef SHARED_BARRIERS_HPP
+#define SHARED_BARRIERS_HPP
+
+#include <boost/interprocess/sync/named_mutex.hpp>
+#include <boost/interprocess/sync/named_condition.hpp>
+
+namespace osrm
+{
+namespace storage
+{
+struct SharedBarriers
+{
+
+    SharedBarriers()
+        : pending_update_mutex(boost::interprocess::open_or_create, "pending_update"),
+          update_mutex(boost::interprocess::open_or_create, "update"),
+          query_mutex(boost::interprocess::open_or_create, "query"),
+          no_running_queries_condition(boost::interprocess::open_or_create, "no_running_queries"),
+          update_ongoing(false), number_of_queries(0)
+    {
+    }
+
+    // Mutex to protect access to the boolean variable
+    boost::interprocess::named_mutex pending_update_mutex;
+    boost::interprocess::named_mutex update_mutex;
+    boost::interprocess::named_mutex query_mutex;
+
+    // Condition that no update is running
+    boost::interprocess::named_condition no_running_queries_condition;
+
+    // Is there an ongoing update?
+    bool update_ongoing;
+    // Is there any query?
+    int number_of_queries;
+};
+}
+}
+
+#endif // SHARED_BARRIERS_HPP
diff --git a/include/storage/shared_datatype.hpp b/include/storage/shared_datatype.hpp
new file mode 100644
index 0000000..ec1033a
--- /dev/null
+++ b/include/storage/shared_datatype.hpp
@@ -0,0 +1,136 @@
+#ifndef SHARED_DATA_TYPE_HPP
+#define SHARED_DATA_TYPE_HPP
+
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+
+#include <cstdint>
+
+#include <array>
+
+namespace osrm
+{
+namespace storage
+{
+
+// Added at the start and end of each block as sanity check
+const constexpr char CANARY[] = "OSRM";
+
+struct SharedDataLayout
+{
+    enum BlockID
+    {
+        NAME_OFFSETS = 0,
+        NAME_BLOCKS,
+        NAME_CHAR_LIST,
+        NAME_ID_LIST,
+        VIA_NODE_LIST,
+        GRAPH_NODE_LIST,
+        GRAPH_EDGE_LIST,
+        COORDINATE_LIST,
+        TURN_INSTRUCTION,
+        TRAVEL_MODE,
+        R_SEARCH_TREE,
+        GEOMETRIES_INDEX,
+        GEOMETRIES_LIST,
+        HSGR_CHECKSUM,
+        TIMESTAMP,
+        FILE_INDEX_PATH,
+        CORE_MARKER,
+        DATASOURCES_LIST,
+        DATASOURCE_NAME_DATA,
+        DATASOURCE_NAME_OFFSETS,
+        DATASOURCE_NAME_LENGTHS,
+        PROPERTIES,
+        NUM_BLOCKS
+    };
+
+    std::array<uint64_t, NUM_BLOCKS> num_entries;
+    std::array<uint64_t, NUM_BLOCKS> entry_size;
+
+    SharedDataLayout() : num_entries(), entry_size() {}
+
+    template <typename T> inline void SetBlockSize(BlockID bid, uint64_t entries)
+    {
+        num_entries[bid] = entries;
+        entry_size[bid] = sizeof(T);
+    }
+
+    inline uint64_t GetBlockSize(BlockID bid) const
+    {
+        // special bit encoding
+        if (bid == CORE_MARKER)
+        {
+            return (num_entries[bid] / 32 + 1) * entry_size[bid];
+        }
+
+        return num_entries[bid] * entry_size[bid];
+    }
+
+    inline uint64_t GetSizeOfLayout() const
+    {
+        return GetBlockOffset(NUM_BLOCKS) + NUM_BLOCKS * 2 * sizeof(CANARY);
+    }
+
+    inline uint64_t GetBlockOffset(BlockID bid) const
+    {
+        uint64_t result = sizeof(CANARY);
+        for (auto i = 0; i < bid; i++)
+        {
+            result += GetBlockSize((BlockID)i) + 2 * sizeof(CANARY);
+        }
+        return result;
+    }
+
+    template <typename T, bool WRITE_CANARY = false>
+    inline T *GetBlockPtr(char *shared_memory, BlockID bid)
+    {
+        T *ptr = (T *)(shared_memory + GetBlockOffset(bid));
+        if (WRITE_CANARY)
+        {
+            char *start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
+            char *end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
+            std::copy(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
+            std::copy(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
+        }
+        else
+        {
+            char *start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
+            char *end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
+            bool start_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
+            bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
+            if (!start_canary_alive)
+            {
+                throw util::exception("Start canary of block corrupted.");
+            }
+            if (!end_canary_alive)
+            {
+                throw util::exception("End canary of block corrupted.");
+            }
+        }
+
+        return ptr;
+    }
+};
+
+enum SharedDataType
+{
+    CURRENT_REGIONS,
+    LAYOUT_1,
+    DATA_1,
+    LAYOUT_2,
+    DATA_2,
+    LAYOUT_NONE,
+    DATA_NONE
+};
+
+struct SharedDataTimestamp
+{
+    SharedDataType layout;
+    SharedDataType data;
+    unsigned timestamp;
+};
+}
+}
+
+#endif /* SHARED_DATA_TYPE_HPP */
diff --git a/data_structures/shared_memory_factory.hpp b/include/storage/shared_memory.hpp
similarity index 68%
rename from data_structures/shared_memory_factory.hpp
rename to include/storage/shared_memory.hpp
index 833b4aa..47238cf 100644
--- a/data_structures/shared_memory_factory.hpp
+++ b/include/storage/shared_memory.hpp
@@ -1,35 +1,8 @@
-/*
+#ifndef SHARED_MEMORY_HPP
+#define SHARED_MEMORY_HPP
 
-Copyright (c) 2015, Project OSRM contributors
-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 SHARED_MEMORY_FACTORY_HPP
-#define SHARED_MEMORY_FACTORY_HPP
-
-#include "../util/osrm_exception.hpp"
-#include "../util/simple_logger.hpp"
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
 
 #include <boost/filesystem.hpp>
 #include <boost/filesystem/fstream.hpp>
@@ -51,6 +24,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <algorithm>
 #include <exception>
 
+namespace osrm
+{
+namespace storage
+{
+
 struct OSRMLockFile
 {
     boost::filesystem::path operator()()
@@ -80,15 +58,18 @@ class SharedMemory
         }
 
         shm_remove() : m_shmid(INT_MIN), m_initialized(false) {}
+
         shm_remove(const shm_remove &) = delete;
+        shm_remove &operator=(const shm_remove &) = delete;
+
         ~shm_remove()
         {
             if (m_initialized)
             {
-                SimpleLogger().Write(logDEBUG) << "automatic memory deallocation";
+                util::SimpleLogger().Write(logDEBUG) << "automatic memory deallocation";
                 if (!boost::interprocess::xsi_shared_memory::remove(m_shmid))
                 {
-                    SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
+                    util::SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
                 }
             }
         }
@@ -97,7 +78,6 @@ class SharedMemory
   public:
     void *Ptr() const { return region.get_address(); }
 
-    SharedMemory() = delete;
     SharedMemory(const SharedMemory &) = delete;
     SharedMemory &operator=(const SharedMemory &) = delete;
 
@@ -131,14 +111,15 @@ class SharedMemory
             {
                 if (ENOMEM == errno)
                 {
-                    SimpleLogger().Write(logWARNING) << "could not lock shared memory to RAM";
+                    util::SimpleLogger().Write(logWARNING) << "could not lock shared memory to RAM";
                 }
             }
 #endif
             region = boost::interprocess::mapped_region(shm, boost::interprocess::read_write);
 
             remover.SetID(shm.get_shmid());
-            SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size << " bytes";
+            util::SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size
+                                                 << " bytes";
         }
     }
 
@@ -185,7 +166,7 @@ class SharedMemory
         bool ret = false;
         try
         {
-            SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
+            util::SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
             boost::interprocess::xsi_shared_memory xsi(boost::interprocess::open_only, key);
             ret = boost::interprocess::xsi_shared_memory::remove(xsi.get_shmid());
         }
@@ -214,8 +195,6 @@ class SharedMemory
     class shm_remove
     {
       private:
-        shm_remove(const shm_remove &) = delete;
-        shm_remove &operator=(const shm_remove &) = delete;
         char *m_shmid;
         bool m_initialized;
 
@@ -228,14 +207,17 @@ class SharedMemory
 
         shm_remove() : m_shmid("undefined"), m_initialized(false) {}
 
+        shm_remove(const shm_remove &) = delete;
+        shm_remove &operator=(const shm_remove &) = delete;
+
         ~shm_remove()
         {
             if (m_initialized)
             {
-                SimpleLogger().Write(logDEBUG) << "automatic memory deallocation";
+                util::SimpleLogger().Write(logDEBUG) << "automatic memory deallocation";
                 if (!boost::interprocess::shared_memory_object::remove(m_shmid))
                 {
-                    SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
+                    util::SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
                 }
             }
         }
@@ -272,7 +254,8 @@ class SharedMemory
             region = boost::interprocess::mapped_region(shm, boost::interprocess::read_write);
 
             remover.SetID(key);
-            SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size << " bytes";
+            util::SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size
+                                                 << " bytes";
         }
     }
 
@@ -322,7 +305,7 @@ class SharedMemory
         bool ret = false;
         try
         {
-            SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
+            util::SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
             ret = boost::interprocess::shared_memory_object::remove(key);
         }
         catch (const boost::interprocess::interprocess_exception &e)
@@ -342,45 +325,36 @@ class SharedMemory
 };
 #endif
 
-template <class LockFileT = OSRMLockFile> class SharedMemoryFactory_tmpl
+template <typename IdentifierT, typename LockFileT = OSRMLockFile>
+SharedMemory *makeSharedMemory(const IdentifierT &id,
+                               const uint64_t size = 0,
+                               bool read_write = false,
+                               bool remove_prev = true)
 {
-  public:
-    template <typename IdentifierT>
-    static SharedMemory *Get(const IdentifierT &id,
-                             const uint64_t size = 0,
-                             bool read_write = false,
-                             bool remove_prev = true)
+    try
     {
-        try
+        LockFileT lock_file;
+        if (!boost::filesystem::exists(lock_file()))
         {
-            LockFileT lock_file;
-            if (!boost::filesystem::exists(lock_file()))
+            if (0 == size)
             {
-                if (0 == size)
-                {
-                    throw osrm::exception("lock file does not exist, exiting");
-                }
-                else
-                {
-                    boost::filesystem::ofstream ofs(lock_file());
-                    ofs.close();
-                }
+                throw util::exception("lock file does not exist, exiting");
+            }
+            else
+            {
+                boost::filesystem::ofstream ofs(lock_file());
             }
-            return new SharedMemory(lock_file(), id, size, read_write, remove_prev);
-        }
-        catch (const boost::interprocess::interprocess_exception &e)
-        {
-            SimpleLogger().Write(logWARNING) << "caught exception: " << e.what() << ", code "
-                                             << e.get_error_code();
-            throw osrm::exception(e.what());
         }
+        return new SharedMemory(lock_file(), id, size, read_write, remove_prev);
     }
+    catch (const boost::interprocess::interprocess_exception &e)
+    {
+        util::SimpleLogger().Write(logWARNING) << "caught exception: " << e.what() << ", code "
+                                               << e.get_error_code();
+        throw util::exception(e.what());
+    }
+}
+}
+}
 
-    SharedMemoryFactory_tmpl() = delete;
-    SharedMemoryFactory_tmpl(const SharedMemoryFactory_tmpl &) = delete;
-    SharedMemoryFactory_tmpl &operator=(const SharedMemoryFactory_tmpl &) = delete;
-};
-
-using SharedMemoryFactory = SharedMemoryFactory_tmpl<>;
-
-#endif // SHARED_MEMORY_FACTORY_HPP
+#endif // SHARED_MEMORY_HPP
diff --git a/include/storage/storage.hpp b/include/storage/storage.hpp
new file mode 100644
index 0000000..31278aa
--- /dev/null
+++ b/include/storage/storage.hpp
@@ -0,0 +1,26 @@
+#ifndef STORAGE_HPP
+#define STORAGE_HPP
+
+#include "storage/storage_config.hpp"
+
+#include <boost/filesystem/path.hpp>
+
+#include <string>
+
+namespace osrm
+{
+namespace storage
+{
+class Storage
+{
+  public:
+    Storage(StorageConfig config);
+    int Run();
+
+  private:
+    StorageConfig config;
+};
+}
+}
+
+#endif
diff --git a/include/storage/storage_config.hpp b/include/storage/storage_config.hpp
new file mode 100644
index 0000000..e5e0e88
--- /dev/null
+++ b/include/storage/storage_config.hpp
@@ -0,0 +1,44 @@
+#ifndef STORAGE_CONFIG_HPP
+#define STORAGE_CONFIG_HPP
+
+#include <boost/filesystem/path.hpp>
+
+namespace osrm
+{
+namespace storage
+{
+
+/**
+ * Configures OSRM's file storage paths.
+ *
+ * \see OSRM, EngineConfig
+ */
+struct StorageConfig final
+{
+    StorageConfig() = default;
+
+    /**
+     * Constructs a storage configuration setting paths based on a base path.
+     *
+     * \param base The base path (e.g. france.pbf.osrm) to derive auxiliary file suffixes from.
+     */
+    StorageConfig(const boost::filesystem::path &base);
+    bool IsValid() const;
+
+    boost::filesystem::path ram_index_path;
+    boost::filesystem::path file_index_path;
+    boost::filesystem::path hsgr_data_path;
+    boost::filesystem::path nodes_data_path;
+    boost::filesystem::path edges_data_path;
+    boost::filesystem::path core_data_path;
+    boost::filesystem::path geometries_path;
+    boost::filesystem::path timestamp_path;
+    boost::filesystem::path datasource_names_path;
+    boost::filesystem::path datasource_indexes_path;
+    boost::filesystem::path names_data_path;
+    boost::filesystem::path properties_path;
+};
+}
+}
+
+#endif
diff --git a/include/util/assert.hpp b/include/util/assert.hpp
new file mode 100644
index 0000000..d9bfb95
--- /dev/null
+++ b/include/util/assert.hpp
@@ -0,0 +1,20 @@
+#ifndef OSRM_ASSERT_HPP
+#define OSRM_ASSERT_HPP
+
+#include <boost/assert.hpp>
+
+#include <stdexcept>
+
+namespace osrm
+{
+namespace util
+{
+// Assertion type to be thrown for stack unwinding
+struct assertionError final : std::logic_error
+{
+    assertionError(const char *msg) : std::logic_error{msg} {}
+};
+}
+}
+
+#endif
diff --git a/util/bearing.hpp b/include/util/bearing.hpp
similarity index 62%
rename from util/bearing.hpp
rename to include/util/bearing.hpp
index 5f3036a..f1ba624 100644
--- a/util/bearing.hpp
+++ b/include/util/bearing.hpp
@@ -1,36 +1,14 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 BEARING_HPP
 #define BEARING_HPP
 
 #include <boost/assert.hpp>
 #include <string>
 
+namespace osrm
+{
+namespace util
+{
+
 namespace bearing
 {
 inline std::string get(const double heading)
@@ -112,5 +90,7 @@ inline bool CheckInBounds(const int A, const int B, const int range)
     }
 }
 }
+}
+}
 
 #endif // BEARING_HPP
diff --git a/data_structures/binary_heap.hpp b/include/util/binary_heap.hpp
similarity index 83%
rename from data_structures/binary_heap.hpp
rename to include/util/binary_heap.hpp
index 85703f4..f3c01f6 100644
--- a/data_structures/binary_heap.hpp
+++ b/include/util/binary_heap.hpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 BINARY_HEAP_H
 #define BINARY_HEAP_H
 
@@ -37,6 +10,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <unordered_map>
 #include <vector>
 
+namespace osrm
+{
+namespace util
+{
+
 template <typename NodeID, typename Key> class ArrayStorage
 {
   public:
@@ -189,9 +167,10 @@ class BinaryHeap
         return inserted_nodes[heap[1].index].node;
     }
 
-    Weight MinKey() const {
-      BOOST_ASSERT(heap.size() > 1);
-      return heap[1].weight;
+    Weight MinKey() const
+    {
+        BOOST_ASSERT(heap.size() > 1);
+        return heap[1].weight;
     }
 
     NodeID DeleteMin()
@@ -311,5 +290,7 @@ class BinaryHeap
 #endif
     }
 };
+}
+}
 
 #endif // BINARY_HEAP_H
diff --git a/include/util/cast.hpp b/include/util/cast.hpp
new file mode 100644
index 0000000..e78f630
--- /dev/null
+++ b/include/util/cast.hpp
@@ -0,0 +1,49 @@
+#ifndef CAST_HPP
+#define CAST_HPP
+
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <type_traits>
+
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/trim.hpp>
+
+namespace osrm
+{
+namespace util
+{
+
+namespace cast
+{
+template <typename Enumeration>
+inline 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 T, int Precision = 6> inline std::string to_string_with_precision(const T x)
+{
+    static_assert(std::is_arithmetic<T>::value, "integral or floating point type required");
+
+    std::ostringstream out;
+    out << std::fixed << std::setprecision(Precision) << x;
+    auto rv = out.str();
+
+    // Javascript has no separation of float / int, digits without a '.' are integral typed
+    // X.Y.0 -> X.Y
+    // X.0 -> X
+    boost::trim_right_if(rv, boost::is_any_of("0"));
+    boost::trim_right_if(rv, boost::is_any_of("."));
+    // Note:
+    //  - assumes the locale to use '.' as digit separator
+    //  - this is not identical to:  trim_right_if(rv, is_any_of('0 .'))
+
+    return rv;
+}
+}
+}
+}
+
+#endif // CAST_HPP
diff --git a/include/util/container.hpp b/include/util/container.hpp
new file mode 100644
index 0000000..bd85e9c
--- /dev/null
+++ b/include/util/container.hpp
@@ -0,0 +1,20 @@
+#ifndef CONTAINER_HPP
+#define CONTAINER_HPP
+
+namespace osrm
+{
+namespace util
+{
+
+template <class Container> void append_to_container(Container &&) {}
+
+template <class Container, typename T, typename... Args>
+void append_to_container(Container &&container, T value, Args &&... args)
+{
+    container.emplace_back(value);
+    append_to_container(std::forward<Container>(container), std::forward<Args>(args)...);
+}
+}
+}
+
+#endif
diff --git a/include/util/coordinate.hpp b/include/util/coordinate.hpp
new file mode 100644
index 0000000..e249bb2
--- /dev/null
+++ b/include/util/coordinate.hpp
@@ -0,0 +1,187 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+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 COORDINATE_HPP_
+#define COORDINATE_HPP_
+
+#include "util/strong_typedef.hpp"
+
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <iosfwd> //for std::ostream
+#include <string>
+#include <type_traits>
+#include <cstddef>
+
+namespace osrm
+{
+
+constexpr const double COORDINATE_PRECISION = 1e6;
+
+namespace util
+{
+
+OSRM_STRONG_TYPEDEF(int32_t, FixedLatitude)
+OSRM_STRONG_TYPEDEF(int32_t, FixedLongitude)
+OSRM_STRONG_TYPEDEF(double, FloatLatitude)
+OSRM_STRONG_TYPEDEF(double, FloatLongitude)
+
+/**
+ * Converts a typed latitude from floating to fixed representation.
+ *
+ * \param floating typed latitude in floating representation.
+ * \return typed latitude in fixed representation
+ * \see Coordinate, toFloating
+ */
+inline FixedLatitude toFixed(const FloatLatitude floating)
+{
+    const auto latitude = static_cast<double>(floating);
+    const auto fixed = boost::numeric_cast<std::int32_t>(latitude * COORDINATE_PRECISION);
+    return FixedLatitude(fixed);
+}
+
+/**
+ * Converts a typed longitude from floating to fixed representation.
+ *
+ * \param floating typed longitude in floating representation.
+ * \return typed latitude in fixed representation
+ * \see Coordinate, toFloating
+ */
+inline FixedLongitude toFixed(const FloatLongitude floating)
+{
+    const auto longitude = static_cast<double>(floating);
+    const auto fixed = boost::numeric_cast<std::int32_t>(longitude * COORDINATE_PRECISION);
+    return FixedLongitude(fixed);
+}
+
+/**
+ * Converts a typed latitude from fixed to floating representation.
+ *
+ * \param fixed typed latitude in fixed representation.
+ * \return typed latitude in floating representation
+ * \see Coordinate, toFixed
+ */
+inline FloatLatitude toFloating(const FixedLatitude fixed)
+{
+    const auto latitude = static_cast<std::int32_t>(fixed);
+    const auto floating = boost::numeric_cast<double>(latitude / COORDINATE_PRECISION);
+    return FloatLatitude(floating);
+}
+
+/**
+ * Converts a typed longitude from fixed to floating representation.
+ *
+ * \param fixed typed longitude in fixed representation.
+ * \return typed longitude in floating representation
+ * \see Coordinate, toFixed
+ */
+inline FloatLongitude toFloating(const FixedLongitude fixed)
+{
+    const auto longitude = static_cast<std::int32_t>(fixed);
+    const auto floating = boost::numeric_cast<double>(longitude / COORDINATE_PRECISION);
+    return FloatLongitude(floating);
+}
+
+// fwd. decl.
+struct FloatCoordinate;
+
+/**
+ * Represents a coordinate based on longitude and latitude in fixed representation.
+ *
+ * To prevent accidental longitude and latitude flips, we provide typed longitude and latitude
+ * wrappers. You can cast these wrappers back to their underlying representation or convert them
+ * from one representation to the other.
+ *
+ * The two representation we provide are:
+ *  - Fixed point
+ *  - Floating point
+ *
+ * \see FloatCoordinate, toFixed, toFloating
+ */
+struct Coordinate
+{
+    FixedLongitude lon;
+    FixedLatitude lat;
+
+    Coordinate();
+    Coordinate(const FloatCoordinate &other);
+    Coordinate(const FixedLongitude lon_, const FixedLatitude lat_);
+    Coordinate(const FloatLongitude lon_, const FloatLatitude lat_);
+
+    template <class T> Coordinate(const T &coordinate) : lon(coordinate.lon), lat(coordinate.lat)
+    {
+        static_assert(!std::is_same<T, Coordinate>::value,
+                      "This constructor should not be used for Coordinates");
+        static_assert(std::is_same<decltype(lon), decltype(coordinate.lon)>::value,
+                      "coordinate types incompatible");
+        static_assert(std::is_same<decltype(lat), decltype(coordinate.lat)>::value,
+                      "coordinate types incompatible");
+    }
+
+    bool IsValid() const;
+    friend bool operator==(const Coordinate lhs, const Coordinate rhs);
+    friend bool operator!=(const Coordinate lhs, const Coordinate rhs);
+    friend std::ostream &operator<<(std::ostream &out, const Coordinate coordinate);
+};
+
+/**
+ * Represents a coordinate based on longitude and latitude in floating representation.
+ *
+ * To prevent accidental longitude and latitude flips, we provide typed longitude and latitude
+ * wrappers. You can cast these wrappers back to their underlying representation or convert them
+ * from one representation to the other.
+ *
+ * The two representation we provide are:
+ *  - Fixed point
+ *  - Floating point
+ *
+ * \see Coordinate, toFixed, toFloating
+ */
+struct FloatCoordinate
+{
+    FloatLongitude lon;
+    FloatLatitude lat;
+
+    FloatCoordinate();
+    FloatCoordinate(const FixedLongitude lon_, const FixedLatitude lat_);
+    FloatCoordinate(const FloatLongitude lon_, const FloatLatitude lat_);
+    FloatCoordinate(const Coordinate other);
+
+    bool IsValid() const;
+    friend bool operator==(const FloatCoordinate lhs, const FloatCoordinate rhs);
+    friend bool operator!=(const FloatCoordinate lhs, const FloatCoordinate rhs);
+    friend std::ostream &operator<<(std::ostream &out, const FloatCoordinate coordinate);
+};
+
+bool operator==(const Coordinate lhs, const Coordinate rhs);
+bool operator==(const FloatCoordinate lhs, const FloatCoordinate rhs);
+std::ostream &operator<<(std::ostream &out, const Coordinate coordinate);
+std::ostream &operator<<(std::ostream &out, const FloatCoordinate coordinate);
+}
+}
+
+#endif /* COORDINATE_HPP_ */
diff --git a/include/util/coordinate_calculation.hpp b/include/util/coordinate_calculation.hpp
new file mode 100644
index 0000000..806b538
--- /dev/null
+++ b/include/util/coordinate_calculation.hpp
@@ -0,0 +1,92 @@
+#ifndef COORDINATE_CALCULATION
+#define COORDINATE_CALCULATION
+
+#include "util/coordinate.hpp"
+
+#include <boost/math/constants/constants.hpp>
+
+#include <utility>
+
+namespace osrm
+{
+namespace util
+{
+namespace coordinate_calculation
+{
+
+const constexpr long double DEGREE_TO_RAD = 0.017453292519943295769236907684886;
+const constexpr long double RAD_TO_DEGREE = 1. / DEGREE_TO_RAD;
+// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
+// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
+const constexpr long double EARTH_RADIUS = 6372797.560856;
+// radius used by WGS84
+const constexpr double EARTH_RADIUS_WGS84 = 6378137.0;
+
+namespace detail
+{
+// earth circumference devided by 2
+const constexpr double MAXEXTENT = EARTH_RADIUS_WGS84 * boost::math::constants::pi<double>();
+// ^ math functions are not constexpr since they have side-effects (setting errno) :(
+const double MAX_LATITUDE = RAD_TO_DEGREE * (2.0 * std::atan(std::exp(180.0 * DEGREE_TO_RAD)) -
+                                             boost::math::constants::half_pi<double>());
+const constexpr double MAX_LONGITUDE = 180.0;
+}
+
+//! Takes the squared euclidean distance of the input coordinates. Does not return meters!
+double squaredEuclideanDistance(const FloatCoordinate &lhs, const FloatCoordinate &rhs);
+
+double haversineDistance(const Coordinate first_coordinate, const Coordinate second_coordinate);
+
+double greatCircleDistance(const Coordinate first_coordinate, const Coordinate second_coordinate);
+
+std::pair<double, FloatCoordinate>
+projectPointOnSegment(const FloatCoordinate &projected_xy_source,
+                      const FloatCoordinate &projected_xy_target,
+                      const FloatCoordinate &projected_xy_coordinate);
+
+double perpendicularDistance(const Coordinate segment_source,
+                             const Coordinate segment_target,
+                             const Coordinate query_location);
+
+double perpendicularDistance(const Coordinate segment_source,
+                             const Coordinate segment_target,
+                             const Coordinate query_location,
+                             Coordinate &nearest_location,
+                             double &ratio);
+
+Coordinate centroid(const Coordinate lhs, const Coordinate rhs);
+
+double bearing(const Coordinate first_coordinate, const Coordinate second_coordinate);
+
+// Get angle of line segment (A,C)->(C,B)
+double computeAngle(const Coordinate first, const Coordinate second, const Coordinate third);
+
+// factor in [0,1]. Returns point along the straight line between from and to. 0 returns from, 1
+// returns to
+Coordinate interpolateLinear(double factor, const Coordinate from, const Coordinate to);
+
+namespace mercator
+{
+// This is the global default tile size for all Mapbox Vector Tiles
+const constexpr double TILE_SIZE = 256.0;
+// Converts projected mercator degrees to PX
+const constexpr double DEGREE_TO_PX = detail::MAXEXTENT / 180.0;
+
+double degreeToPixel(FloatLatitude lat, unsigned zoom);
+double degreeToPixel(FloatLongitude lon, unsigned zoom);
+FloatLatitude yToLat(const double value);
+double latToY(const FloatLatitude latitude);
+
+FloatCoordinate fromWGS84(const FloatCoordinate &wgs84_coordinate);
+FloatCoordinate toWGS84(const FloatCoordinate &mercator_coordinate);
+
+void xyzToMercator(
+    const int x, const int y, const int z, double &minx, double &miny, double &maxx, double &maxy);
+void xyzToWGS84(
+    const int x, const int y, const int z, double &minx, double &miny, double &maxx, double &maxy);
+} // ns mercator
+} // ns coordinate_calculation
+} // ns util
+} // ns osrm
+
+#endif // COORDINATE_CALCULATION
diff --git a/data_structures/deallocating_vector.hpp b/include/util/deallocating_vector.hpp
similarity index 85%
rename from data_structures/deallocating_vector.hpp
rename to include/util/deallocating_vector.hpp
index 72cb081..c8883b2 100644
--- a/data_structures/deallocating_vector.hpp
+++ b/include/util/deallocating_vector.hpp
@@ -1,34 +1,7 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 DEALLOCATING_VECTOR_HPP
 #define DEALLOCATING_VECTOR_HPP
 
-#include "../util/integer_range.hpp"
+#include "util/integer_range.hpp"
 
 #include <boost/iterator/iterator_facade.hpp>
 
@@ -36,6 +9,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <utility>
 #include <vector>
 
+namespace osrm
+{
+namespace util
+{
+
 template <typename ElementT> struct ConstDeallocatingVectorIteratorState
 {
     ConstDeallocatingVectorIteratorState()
@@ -47,14 +25,15 @@ template <typename ElementT> struct ConstDeallocatingVectorIteratorState
     {
     }
     explicit ConstDeallocatingVectorIteratorState(const std::size_t idx,
-                                             const std::vector<ElementT *> *input_list)
+                                                  const std::vector<ElementT *> *input_list)
         : index(idx), bucket_list(input_list)
     {
     }
     std::size_t index;
     const std::vector<ElementT *> *bucket_list;
 
-    ConstDeallocatingVectorIteratorState &operator=(const ConstDeallocatingVectorIteratorState &other)
+    ConstDeallocatingVectorIteratorState &
+    operator=(const ConstDeallocatingVectorIteratorState &other)
     {
         index = other.index;
         bucket_list = other.bucket_list;
@@ -237,11 +216,10 @@ class DeallocatingVectorRemoveIterator
     }
 };
 
-template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK>
-class DeallocatingVector;
+template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK> class DeallocatingVector;
 
-template<typename T, std::size_t S>
-void swap(DeallocatingVector<T, S>& lhs, DeallocatingVector<T, S>& rhs);
+template <typename T, std::size_t S>
+void swap(DeallocatingVector<T, S> &lhs, DeallocatingVector<T, S> &rhs);
 
 template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK = 8388608 / sizeof(ElementT)>
 class DeallocatingVector
@@ -263,7 +241,8 @@ class DeallocatingVector
 
     ~DeallocatingVector() { clear(); }
 
-    friend void swap<>(DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK>& lhs, DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK>& rhs);
+    friend void swap<>(DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK> &lhs,
+                       DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK> &rhs);
 
     void swap(DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK> &other)
     {
@@ -327,8 +306,7 @@ class DeallocatingVector
         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()))
+            for (const auto bucket_index : irange(number_of_necessary_buckets, bucket_list.size()))
             {
                 if (nullptr != bucket_list[bucket_index])
                 {
@@ -394,10 +372,12 @@ class DeallocatingVector
     }
 };
 
-template<typename T, std::size_t S>
-void swap(DeallocatingVector<T, S>& lhs, DeallocatingVector<T, S>& rhs)
+template <typename T, std::size_t S>
+void swap(DeallocatingVector<T, S> &lhs, DeallocatingVector<T, S> &rhs)
 {
     lhs.swap(rhs);
 }
+}
+}
 
 #endif /* DEALLOCATING_VECTOR_HPP */
diff --git a/util/dist_table_wrapper.hpp b/include/util/dist_table_wrapper.hpp
similarity index 58%
rename from util/dist_table_wrapper.hpp
rename to include/util/dist_table_wrapper.hpp
index 15550fa..714bcef 100644
--- a/util/dist_table_wrapper.hpp
+++ b/include/util/dist_table_wrapper.hpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 DIST_TABLE_WRAPPER_H
 #define DIST_TABLE_WRAPPER_H
 
@@ -33,6 +6,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <boost/assert.hpp>
 #include <cstddef>
 
+namespace osrm
+{
+namespace util
+{
+
 // This Wrapper provides an easier access to a distance table that is given as an linear vector
 
 template <typename T> class DistTableWrapper
@@ -47,7 +25,7 @@ template <typename T> class DistTableWrapper
         BOOST_ASSERT_MSG(table.size() == 0, "table is empty");
         BOOST_ASSERT_MSG(number_of_nodes_ * number_of_nodes_ <= table_.size(),
                          "number_of_nodes_ is invalid");
-    };
+    }
 
     std::size_t GetNumberOfNodes() const { return number_of_nodes_; }
 
@@ -84,5 +62,7 @@ template <typename T> class DistTableWrapper
     std::vector<T> table_;
     const std::size_t number_of_nodes_;
 };
+}
+}
 
 #endif // DIST_TABLE_WRAPPER_H
diff --git a/data_structures/dynamic_graph.hpp b/include/util/dynamic_graph.hpp
similarity index 80%
rename from data_structures/dynamic_graph.hpp
rename to include/util/dynamic_graph.hpp
index 4f63c02..7df32a9 100644
--- a/data_structures/dynamic_graph.hpp
+++ b/include/util/dynamic_graph.hpp
@@ -1,36 +1,9 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 DYNAMICGRAPH_HPP
 #define DYNAMICGRAPH_HPP
 
-#include "deallocating_vector.hpp"
-#include "../util/integer_range.hpp"
-#include "../typedefs.h"
+#include "util/deallocating_vector.hpp"
+#include "util/integer_range.hpp"
+#include "util/typedefs.hpp"
 
 #include <boost/assert.hpp>
 
@@ -42,13 +15,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <tuple>
 #include <vector>
 
+namespace osrm
+{
+namespace util
+{
+
 template <typename EdgeDataT> class DynamicGraph
 {
   public:
     using EdgeData = EdgeDataT;
     using NodeIterator = unsigned;
     using EdgeIterator = unsigned;
-    using EdgeRange = osrm::range<EdgeIterator>;
+    using EdgeRange = range<EdgeIterator>;
 
     class InputEdge
     {
@@ -91,14 +69,15 @@ template <typename EdgeDataT> class DynamicGraph
     template <class ContainerT> DynamicGraph(const NodeIterator nodes, const ContainerT &graph)
     {
         // we need to cast here because DeallocatingVector does not have a valid const iterator
-        BOOST_ASSERT(std::is_sorted(const_cast<ContainerT&>(graph).begin(), const_cast<ContainerT&>(graph).end()));
+        BOOST_ASSERT(std::is_sorted(const_cast<ContainerT &>(graph).begin(),
+                                    const_cast<ContainerT &>(graph).end()));
 
         number_of_nodes = nodes;
         number_of_edges = static_cast<EdgeIterator>(graph.size());
         node_array.resize(number_of_nodes + 1);
         EdgeIterator edge = 0;
         EdgeIterator position = 0;
-        for (const auto node : osrm::irange(0u, number_of_nodes))
+        for (const auto node : irange(0u, number_of_nodes))
         {
             EdgeIterator last_edge = edge;
             while (edge < number_of_edges && graph[edge].source == node)
@@ -113,10 +92,10 @@ template <typename EdgeDataT> class DynamicGraph
         edge_list.reserve(static_cast<std::size_t>(edge_list.size() * 1.1));
         edge_list.resize(position);
         edge = 0;
-        for (const auto node : osrm::irange(0u, number_of_nodes))
+        for (const auto node : irange(0u, number_of_nodes))
         {
-            for (const auto i : osrm::irange(node_array[node].first_edge,
-                                             node_array[node].first_edge + node_array[node].edges))
+            for (const auto i : irange(node_array[node].first_edge,
+                                       node_array[node].first_edge + node_array[node].edges))
             {
                 edge_list[i].target = graph[edge].target;
                 BOOST_ASSERT(edge_list[i].target < number_of_nodes);
@@ -137,7 +116,7 @@ template <typename EdgeDataT> class DynamicGraph
     unsigned GetDirectedOutDegree(const NodeIterator n) const
     {
         unsigned degree = 0;
-        for (const auto edge : osrm::irange(BeginEdges(n), EndEdges(n)))
+        for (const auto edge : irange(BeginEdges(n), EndEdges(n)))
         {
             if (!GetEdgeData(edge).reversed)
             {
@@ -167,7 +146,7 @@ template <typename EdgeDataT> class DynamicGraph
 
     EdgeRange GetAdjacentEdgeRange(const NodeIterator node) const
     {
-        return osrm::irange(BeginEdges(node), EndEdges(node));
+        return irange(BeginEdges(node), EndEdges(node));
     }
 
     NodeIterator InsertNode()
@@ -201,12 +180,12 @@ template <typename EdgeDataT> class DynamicGraph
                     edge_list.reserve(requiredCapacity * 1.1);
                 }
                 edge_list.resize(edge_list.size() + newSize);
-                for (const auto i : osrm::irange(0u, node.edges))
+                for (const auto i : irange(0u, node.edges))
                 {
                     edge_list[newFirstEdge + i] = edge_list[node.first_edge + i];
                     makeDummy(node.first_edge + i);
                 }
-                for (const auto i : osrm::irange(node.edges + 1, newSize))
+                for (const auto i : irange(node.edges + 1, newSize))
                 {
                     makeDummy(newFirstEdge + i);
                 }
@@ -261,7 +240,7 @@ template <typename EdgeDataT> class DynamicGraph
     // searches for a specific edge
     EdgeIterator FindEdge(const NodeIterator from, const NodeIterator to) const
     {
-        for (const auto i : osrm::irange(BeginEdges(from), EndEdges(from)))
+        for (const auto i : irange(BeginEdges(from), EndEdges(from)))
         {
             if (to == edge_list[i].target)
             {
@@ -341,5 +320,7 @@ template <typename EdgeDataT> class DynamicGraph
     std::vector<Node> node_array;
     DeallocatingVector<Edge> edge_list;
 };
+}
+}
 
 #endif // DYNAMICGRAPH_HPP
diff --git a/include/util/exception.hpp b/include/util/exception.hpp
new file mode 100644
index 0000000..41efb0b
--- /dev/null
+++ b/include/util/exception.hpp
@@ -0,0 +1,30 @@
+#ifndef OSRM_EXCEPTION_HPP
+#define OSRM_EXCEPTION_HPP
+
+#include <exception>
+#include <string>
+#include <utility>
+
+namespace osrm
+{
+namespace util
+{
+
+class exception final : public std::exception
+{
+  public:
+    explicit exception(const char *message) : message(message) {}
+    explicit exception(std::string message) : message(std::move(message)) {}
+    const char *what() const noexcept override { return message.c_str(); }
+
+  private:
+    // 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 std::string message;
+};
+}
+}
+
+#endif /* OSRM_EXCEPTION_HPP */
diff --git a/include/util/fingerprint.hpp b/include/util/fingerprint.hpp
new file mode 100644
index 0000000..e8238c0
--- /dev/null
+++ b/include/util/fingerprint.hpp
@@ -0,0 +1,39 @@
+#ifndef FINGERPRINT_H
+#define FINGERPRINT_H
+
+#include <boost/uuid/uuid.hpp>
+#include <type_traits>
+
+namespace osrm
+{
+namespace util
+{
+
+// implements a singleton, i.e. there is one and only one conviguration object
+class FingerPrint
+{
+  public:
+    static FingerPrint GetValid();
+    const boost::uuids::uuid &GetFingerPrint() const;
+    bool IsMagicNumberOK(const FingerPrint &other) const;
+    bool TestGraphUtil(const FingerPrint &other) const;
+    bool TestContractor(const FingerPrint &other) const;
+    bool TestRTree(const FingerPrint &other) const;
+    bool TestQueryObjects(const FingerPrint &other) const;
+
+  private:
+    unsigned magic_number;
+    char md5_prepare[33];
+    char md5_tree[33];
+    char md5_graph[33];
+    char md5_objects[33];
+
+    // initialize to {6ba7b810-9dad-11d1-80b4-00c04fd430c8}
+    boost::uuids::uuid named_uuid;
+};
+
+static_assert(std::is_trivial<FingerPrint>::value, "FingerPrint needs to be trivial.");
+}
+}
+
+#endif /* FingerPrint_H */
diff --git a/util/fingerprint_impl.hpp.in b/include/util/fingerprint_impl.hpp.in
similarity index 58%
rename from util/fingerprint_impl.hpp.in
rename to include/util/fingerprint_impl.hpp.in
index 88e8436..7b31d6d 100644
--- a/util/fingerprint_impl.hpp.in
+++ b/include/util/fingerprint_impl.hpp.in
@@ -1,31 +1,4 @@
-/*
-
-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 "util/osrm_exception.hpp"
+#include "util/exception.hpp"
 
 #include <boost/uuid/name_generator.hpp>
 #include <boost/uuid/uuid_generators.hpp>
@@ -40,6 +13,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #cmakedefine MD5GRAPH "${MD5GRAPH}"
 #cmakedefine MD5OBJECTS "${MD5OBJECTS}"
 
+namespace osrm
+{
+namespace util
+{
+
 FingerPrint FingerPrint::GetValid()
 {
     FingerPrint fingerprint;
@@ -79,16 +57,16 @@ bool FingerPrint::TestGraphUtil(const FingerPrint &other) const
 {
     if (!IsMagicNumberOK(other))
     {
-        throw osrm::exception("hsgr input file misses magic number. Check or reprocess the file");
+        throw exception("hsgr input file misses magic number. Check or reprocess the file");
     }
     return std::equal(md5_graph, md5_graph + 32, other.md5_graph);
 }
 
-bool FingerPrint::TestPrepare(const FingerPrint &other) const
+bool FingerPrint::TestContractor(const FingerPrint &other) const
 {
     if (!IsMagicNumberOK(other))
     {
-        throw osrm::exception("osrm input file misses magic number. Check or reprocess the file");
+        throw exception("osrm input file misses magic number. Check or reprocess the file");
     }
     return std::equal(md5_prepare, md5_prepare + 32, other.md5_prepare);
 }
@@ -97,7 +75,7 @@ bool FingerPrint::TestRTree(const FingerPrint &other) const
 {
     if (!IsMagicNumberOK(other))
     {
-        throw osrm::exception("r-tree input file misses magic number. Check or reprocess the file");
+        throw exception("r-tree input file misses magic number. Check or reprocess the file");
     }
     return std::equal(md5_tree, md5_tree + 32, other.md5_tree);
 }
@@ -106,7 +84,10 @@ bool FingerPrint::TestQueryObjects(const FingerPrint &other) const
 {
     if (!IsMagicNumberOK(other))
     {
-        throw osrm::exception("missing magic number. Check or reprocess the file");
+        throw exception("missing magic number. Check or reprocess the file");
     }
     return std::equal(md5_objects, md5_objects + 32, other.md5_objects);
 }
+
+}
+}
diff --git a/include/util/for_each_pair.hpp b/include/util/for_each_pair.hpp
new file mode 100644
index 0000000..86fc75e
--- /dev/null
+++ b/include/util/for_each_pair.hpp
@@ -0,0 +1,45 @@
+#ifndef FOR_EACH_PAIR_HPP
+#define FOR_EACH_PAIR_HPP
+
+#include <numeric>
+#include <iterator>
+
+namespace osrm
+{
+namespace util
+{
+
+// TODO: check why this is not an option here:
+// std::adjacent_find(begin, end, [=](const auto& l, const auto& r){ return function(), false; });
+template <typename ForwardIterator, typename Function>
+Function for_each_pair(ForwardIterator begin, ForwardIterator end, Function function)
+{
+    if (begin == end)
+    {
+        return function;
+    }
+
+    auto next = begin;
+    next = std::next(next);
+
+    while (next != end)
+    {
+        function(*begin, *next);
+        begin = std::next(begin);
+        next = std::next(next);
+    }
+    return function;
+}
+
+template <class ContainerT, typename Function>
+Function for_each_pair(ContainerT &container, Function function)
+{
+    using std::begin;
+    using std::end;
+    return for_each_pair(begin(container), end(container), function);
+}
+
+} // namespace util
+} // namespace osrm
+
+#endif /* FOR_EACH_PAIR_HPP */
diff --git a/util/graph_loader.hpp b/include/util/graph_loader.hpp
similarity index 71%
rename from util/graph_loader.hpp
rename to include/util/graph_loader.hpp
index 6ddd0eb..b611e04 100644
--- a/util/graph_loader.hpp
+++ b/include/util/graph_loader.hpp
@@ -1,41 +1,14 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 GRAPH_LOADER_HPP
 #define GRAPH_LOADER_HPP
 
-#include "fingerprint.hpp"
-#include "osrm_exception.hpp"
-#include "simple_logger.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 "../typedefs.h"
+#include "util/fingerprint.hpp"
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+#include "extractor/external_memory_node.hpp"
+#include "extractor/node_based_edge.hpp"
+#include "extractor/query_node.hpp"
+#include "extractor/restriction.hpp"
+#include "util/typedefs.hpp"
 
 #include <boost/assert.hpp>
 #include <boost/filesystem.hpp>
@@ -49,19 +22,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <ios>
 #include <vector>
 
+namespace osrm
+{
+namespace util
+{
+
 /**
  * Reads the .restrictions file and loads it to a vector.
  * The since the restrictions reference nodes using their external node id,
  * we need to renumber it to the new internal id.
 */
 unsigned loadRestrictionsFromFile(std::istream &input_stream,
-                                  std::vector<TurnRestriction> &restriction_list)
+                                  std::vector<extractor::TurnRestriction> &restriction_list)
 {
     const FingerPrint fingerprint_valid = FingerPrint::GetValid();
     FingerPrint fingerprint_loaded;
     unsigned number_of_usable_restrictions = 0;
     input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
-    if (!fingerprint_loaded.TestPrepare(fingerprint_valid))
+    if (!fingerprint_loaded.TestContractor(fingerprint_valid))
     {
         SimpleLogger().Write(logWARNING) << ".restrictions was prepared with different build.\n"
                                             "Reprocess to get rid of this warning.";
@@ -72,7 +50,7 @@ unsigned loadRestrictionsFromFile(std::istream &input_stream,
     if (number_of_usable_restrictions > 0)
     {
         input_stream.read((char *)restriction_list.data(),
-                          number_of_usable_restrictions * sizeof(TurnRestriction));
+                          number_of_usable_restrictions * sizeof(extractor::TurnRestriction));
     }
 
     return number_of_usable_restrictions;
@@ -87,13 +65,13 @@ unsigned loadRestrictionsFromFile(std::istream &input_stream,
 NodeID loadNodesFromFile(std::istream &input_stream,
                          std::vector<NodeID> &barrier_node_list,
                          std::vector<NodeID> &traffic_light_node_list,
-                         std::vector<QueryNode> &node_array)
+                         std::vector<extractor::QueryNode> &node_array)
 {
     const FingerPrint fingerprint_valid = FingerPrint::GetValid();
     FingerPrint fingerprint_loaded;
     input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(FingerPrint));
 
-    if (!fingerprint_loaded.TestPrepare(fingerprint_valid))
+    if (!fingerprint_loaded.TestContractor(fingerprint_valid))
     {
         SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build.\n"
                                             "Reprocess to get rid of this warning.";
@@ -103,11 +81,12 @@ NodeID loadNodesFromFile(std::istream &input_stream,
     input_stream.read(reinterpret_cast<char *>(&n), sizeof(NodeID));
     SimpleLogger().Write() << "Importing n = " << n << " nodes ";
 
-    ExternalMemoryNode current_node;
+    extractor::ExternalMemoryNode current_node;
     for (NodeID i = 0; i < n; ++i)
     {
-        input_stream.read(reinterpret_cast<char *>(&current_node), sizeof(ExternalMemoryNode));
-        node_array.emplace_back(current_node.lat, current_node.lon, current_node.node_id);
+        input_stream.read(reinterpret_cast<char *>(&current_node),
+                          sizeof(extractor::ExternalMemoryNode));
+        node_array.emplace_back(current_node.lon, current_node.lat, current_node.node_id);
         if (current_node.barrier)
         {
             barrier_node_list.emplace_back(i);
@@ -128,21 +107,22 @@ NodeID loadNodesFromFile(std::istream &input_stream,
 /**
  * Reads a .osrm file and produces the edges.
  */
-NodeID loadEdgesFromFile(std::istream &input_stream, std::vector<NodeBasedEdge> &edge_list)
+NodeID loadEdgesFromFile(std::istream &input_stream,
+                         std::vector<extractor::NodeBasedEdge> &edge_list)
 {
     EdgeID m;
     input_stream.read(reinterpret_cast<char *>(&m), sizeof(unsigned));
     edge_list.resize(m);
     SimpleLogger().Write() << " and " << m << " edges ";
 
-    input_stream.read((char *)edge_list.data(), m * sizeof(NodeBasedEdge));
+    input_stream.read((char *)edge_list.data(), m * sizeof(extractor::NodeBasedEdge));
 
     BOOST_ASSERT(edge_list.size() > 0);
 
 #ifndef NDEBUG
     SimpleLogger().Write() << "Validating loaded edges...";
     tbb::parallel_sort(edge_list.begin(), edge_list.end(),
-                       [](const NodeBasedEdge &lhs, const NodeBasedEdge &rhs)
+                       [](const extractor::NodeBasedEdge &lhs, const extractor::NodeBasedEdge &rhs)
                        {
                            return (lhs.source < rhs.source) ||
                                   (lhs.source == rhs.source && lhs.target < rhs.target);
@@ -175,11 +155,11 @@ unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
 {
     if (!boost::filesystem::exists(hsgr_file))
     {
-        throw osrm::exception("hsgr file does not exist");
+        throw exception("hsgr file does not exist");
     }
     if (0 == boost::filesystem::file_size(hsgr_file))
     {
-        throw osrm::exception("hsgr file is empty");
+        throw exception("hsgr file is empty");
     }
 
     boost::filesystem::ifstream hsgr_input_stream(hsgr_file, std::ios::binary);
@@ -214,9 +194,10 @@ unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
         hsgr_input_stream.read(reinterpret_cast<char *>(&edge_list[0]),
                                number_of_edges * sizeof(EdgeT));
     }
-    hsgr_input_stream.close();
 
     return number_of_nodes;
 }
+}
+}
 
 #endif // GRAPH_LOADER_HPP
diff --git a/util/graph_utils.hpp b/include/util/graph_utils.hpp
similarity index 84%
rename from util/graph_utils.hpp
rename to include/util/graph_utils.hpp
index 9af8dbc..c2165c5 100644
--- a/util/graph_utils.hpp
+++ b/include/util/graph_utils.hpp
@@ -1,26 +1,31 @@
 #ifndef GRAPH_UTILS_HPP
 #define GRAPH_UTILS_HPP
 
-#include "../typedefs.h"
+#include "util/typedefs.hpp"
 
 #include <boost/assert.hpp>
 #include <vector>
 
+namespace osrm
+{
+namespace util
+{
+
 /// This function checks if the graph (consisting of directed edges) is undirected
-template<typename GraphT>
-bool isUndirectedGraph(const GraphT& graph)
+template <typename GraphT> bool isUndirectedGraph(const GraphT &graph)
 {
     for (auto source = 0u; source < graph.GetNumberOfNodes(); ++source)
     {
         for (auto edge = graph.BeginEdges(source); edge < graph.EndEdges(source); ++edge)
         {
-            const auto& data = graph.GetEdgeData(edge);
+            const auto &data = graph.GetEdgeData(edge);
 
             auto target = graph.GetTarget(edge);
             BOOST_ASSERT(target != SPECIAL_NODEID);
 
             bool found_reverse = false;
-            for (auto rev_edge = graph.BeginEdges(target); rev_edge < graph.EndEdges(target); ++rev_edge)
+            for (auto rev_edge = graph.BeginEdges(target); rev_edge < graph.EndEdges(target);
+                 ++rev_edge)
             {
                 auto rev_target = graph.GetTarget(rev_edge);
                 BOOST_ASSERT(rev_target != SPECIAL_NODEID);
@@ -44,7 +49,6 @@ bool isUndirectedGraph(const GraphT& graph)
     return true;
 }
 
-
 /// Since DynamicGraph assumes directed edges we have to make sure we transformed
 /// the compressed edge format into single directed edges. We do this to make sure
 /// every node also knows its incoming edges, not only its outgoing edges and use the reversed=true
@@ -60,13 +64,14 @@ bool isUndirectedGraph(const GraphT& graph)
 ///      (a <-- b gets reducted to b --> a)
 ///   2. a --> b will be transformed to a --> b and b <-- a
 ///   3. a <-> b will be transformed to a --> b and b --> a
-template<typename OutputEdgeT, typename InputEdgeT, typename FunctorT>
-std::vector<OutputEdgeT> directedEdgesFromCompressed(const std::vector<InputEdgeT>& input_edge_list, FunctorT copy_data)
+template <typename OutputEdgeT, typename InputEdgeT, typename FunctorT>
+std::vector<OutputEdgeT> directedEdgesFromCompressed(const std::vector<InputEdgeT> &input_edge_list,
+                                                     FunctorT copy_data)
 {
     std::vector<OutputEdgeT> output_edge_list;
 
     OutputEdgeT edge;
-    for (const auto& input_edge : input_edge_list)
+    for (const auto &input_edge : input_edge_list)
     {
         // edges that are not forward get converted by flipping the end points
         BOOST_ASSERT(input_edge.forward);
@@ -91,4 +96,7 @@ std::vector<OutputEdgeT> directedEdgesFromCompressed(const std::vector<InputEdge
 
     return output_edge_list;
 }
+}
+}
+
 #endif
diff --git a/include/util/hilbert_value.hpp b/include/util/hilbert_value.hpp
new file mode 100644
index 0000000..2acb6b4
--- /dev/null
+++ b/include/util/hilbert_value.hpp
@@ -0,0 +1,18 @@
+#ifndef HILBERT_VALUE_HPP
+#define HILBERT_VALUE_HPP
+
+#include "osrm/coordinate.hpp"
+
+#include <cstdint>
+
+namespace osrm
+{
+namespace util
+{
+
+// Computes a 64 bit value that corresponds to the hilbert space filling curve
+std::uint64_t hilbertCode(const Coordinate coordinate);
+}
+}
+
+#endif /* HILBERT_VALUE_HPP */
diff --git a/include/util/integer_range.hpp b/include/util/integer_range.hpp
new file mode 100644
index 0000000..29d428f
--- /dev/null
+++ b/include/util/integer_range.hpp
@@ -0,0 +1,58 @@
+#ifndef INTEGER_RANGE_HPP
+#define INTEGER_RANGE_HPP
+
+#include <boost/assert.hpp>
+
+#include <type_traits>
+
+#include <cstdint>
+
+namespace osrm
+{
+namespace util
+{
+
+// Warning: do not try to replace this with Boost's irange, as it is broken on Boost 1.55:
+//     auto r = boost::irange<unsigned int>(0, 15);
+//     std::cout << r.size() << std::endl;
+// results in -4294967281. Latest Boost versions fix this, but we still support older ones.
+
+template <typename Integer> class range
+{
+  private:
+    const Integer last;
+    Integer iter;
+
+  public:
+    range(Integer start, Integer end) noexcept : last(end), iter(start)
+    {
+        BOOST_ASSERT_MSG(start <= end, "backwards counting ranges not suppoted");
+        static_assert(std::is_integral<Integer>::value, "range type must be integral");
+    }
+
+    // Iterable functions
+    const range &begin() const noexcept { return *this; }
+    const range &end() const noexcept { return *this; }
+    Integer front() const noexcept { return iter; }
+    Integer back() const noexcept { return last - 1; }
+    std::size_t size() const noexcept { return static_cast<std::size_t>(last - iter); }
+
+    // Iterator functions
+    bool operator!=(const range &) const noexcept { return iter < last; }
+    void operator++() noexcept { ++iter; }
+    Integer operator*() const noexcept { return iter; }
+};
+
+// 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) noexcept
+{
+    return range<Integer>(first, last);
+}
+}
+}
+
+#endif // INTEGER_RANGE_HPP
diff --git a/include/util/io.hpp b/include/util/io.hpp
new file mode 100644
index 0000000..70ab64a
--- /dev/null
+++ b/include/util/io.hpp
@@ -0,0 +1,127 @@
+#ifndef OSRM_INCLUDE_UTIL_IO_HPP_
+#define OSRM_INCLUDE_UTIL_IO_HPP_
+
+#include "util/simple_logger.hpp"
+
+#include <boost/filesystem.hpp>
+
+#include <cstddef>
+#include <cstdint>
+
+#include <fstream>
+#include <bitset>
+#include <vector>
+
+#include "util/fingerprint.hpp"
+
+namespace osrm
+{
+namespace util
+{
+
+inline bool writeFingerprint(std::ostream &stream)
+{
+    const auto fingerprint = FingerPrint::GetValid();
+    stream.write(reinterpret_cast<const char *>(&fingerprint), sizeof(fingerprint));
+    return static_cast<bool>(stream);
+}
+
+inline bool readAndCheckFingerprint(std::istream &stream)
+{
+    FingerPrint fingerprint;
+    const auto valid = FingerPrint::GetValid();
+    stream.read(reinterpret_cast<char *>(&fingerprint), sizeof(fingerprint));
+    // compare the compilation state stored in the fingerprint
+    return static_cast<bool>(stream) && valid.IsMagicNumberOK(fingerprint) &&
+           valid.TestContractor(fingerprint) && valid.TestGraphUtil(fingerprint) &&
+           valid.TestRTree(fingerprint) && valid.TestQueryObjects(fingerprint);
+}
+
+template <typename simple_type>
+bool serializeVector(const std::string &filename, const std::vector<simple_type> &data)
+{
+    std::ofstream stream(filename, std::ios::binary);
+
+    writeFingerprint(stream);
+
+    std::uint64_t count = data.size();
+    stream.write(reinterpret_cast<const char *>(&count), sizeof(count));
+    if (!data.empty())
+        stream.write(reinterpret_cast<const char *>(&data[0]), sizeof(simple_type) * count);
+    return static_cast<bool>(stream);
+}
+
+template <typename simple_type>
+bool deserializeVector(const std::string &filename, std::vector<simple_type> &data)
+{
+    std::ifstream stream(filename, std::ios::binary);
+
+    if (!readAndCheckFingerprint(stream))
+        return false;
+
+    std::uint64_t count = 0;
+    stream.read(reinterpret_cast<char *>(&count), sizeof(count));
+    data.resize(count);
+    if (count)
+        stream.read(reinterpret_cast<char *>(&data[0]), sizeof(simple_type) * count);
+    return static_cast<bool>(stream);
+}
+
+inline bool serializeFlags(const boost::filesystem::path &path, const std::vector<bool> &flags)
+{
+    // TODO this should be replaced with a FILE-based write using error checking
+    std::ofstream flag_stream(path.string(), std::ios::binary);
+
+    writeFingerprint(flag_stream);
+
+    std::uint32_t number_of_bits = flags.size();
+    flag_stream.write(reinterpret_cast<const char *>(&number_of_bits), sizeof(number_of_bits));
+    // putting bits in ints
+    std::uint32_t chunk = 0;
+    std::size_t chunk_count = 0;
+    for (std::size_t bit_nr = 0; bit_nr < number_of_bits;)
+    {
+        std::bitset<32> chunk_bitset;
+        for (std::size_t chunk_bit = 0; chunk_bit < 32 && bit_nr < number_of_bits;
+             ++chunk_bit, ++bit_nr)
+            chunk_bitset[chunk_bit] = flags[bit_nr];
+
+        chunk = chunk_bitset.to_ulong();
+        ++chunk_count;
+        flag_stream.write(reinterpret_cast<const char *>(&chunk), sizeof(chunk));
+    }
+    SimpleLogger().Write() << "Wrote " << number_of_bits << " bits in " << chunk_count
+                           << " chunks (Flags).";
+    return static_cast<bool>(flag_stream);
+}
+
+inline bool deserializeFlags(const boost::filesystem::path &path, std::vector<bool> &flags)
+{
+    SimpleLogger().Write() << "Reading flags from " << path;
+    std::ifstream flag_stream(path.string(), std::ios::binary);
+
+    if (!readAndCheckFingerprint(flag_stream))
+        return false;
+
+    std::uint32_t number_of_bits;
+    flag_stream.read(reinterpret_cast<char *>(&number_of_bits), sizeof(number_of_bits));
+    flags.resize(number_of_bits);
+    // putting bits in ints
+    std::uint32_t chunks = (number_of_bits + 31) / 32;
+    std::size_t bit_position = 0;
+    std::uint32_t chunk;
+    for (std::size_t chunk_id = 0; chunk_id < chunks; ++chunk_id)
+    {
+        flag_stream.read(reinterpret_cast<char *>(&chunk), sizeof(chunk));
+        std::bitset<32> chunk_bits(chunk);
+        for (std::size_t bit = 0; bit < 32 && bit_position < number_of_bits; ++bit, ++bit_position)
+            flags[bit_position] = chunk_bits[bit];
+    }
+    SimpleLogger().Write() << "Read " << number_of_bits << " bits in " << chunks
+                           << " Chunks from disk.";
+    return static_cast<bool>(flag_stream);
+}
+} // namespace util
+} // namespace osrm
+
+#endif // OSRM_INCLUDE_UTIL_IO_HPP_
diff --git a/util/iso_8601_duration_parser.hpp b/include/util/iso_8601_duration_parser.hpp
similarity index 61%
rename from util/iso_8601_duration_parser.hpp
rename to include/util/iso_8601_duration_parser.hpp
index 3e558ce..91f9d2d 100644
--- a/util/iso_8601_duration_parser.hpp
+++ b/include/util/iso_8601_duration_parser.hpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 ISO_8601_DURATION_PARSER_HPP
 #define ISO_8601_DURATION_PARSER_HPP
 
@@ -32,6 +5,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <boost/spirit/include/qi.hpp>
 #include <boost/spirit/include/qi_action.hpp>
 
+namespace osrm
+{
+namespace util
+{
+
 namespace qi = boost::spirit::qi;
 
 template <typename Iterator> struct iso_8601_grammar : qi::grammar<Iterator>
@@ -98,5 +76,7 @@ template <typename Iterator> struct iso_8601_grammar : qi::grammar<Iterator>
         return temp;
     }
 };
+}
+}
 
 #endif // ISO_8601_DURATION_PARSER_HPP
diff --git a/include/osrm/json_container.hpp b/include/util/json_container.hpp
similarity index 59%
copy from include/osrm/json_container.hpp
copy to include/util/json_container.hpp
index 63accb8..9a383bb 100644
--- a/include/osrm/json_container.hpp
+++ b/include/util/json_container.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -33,46 +33,92 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <variant/variant.hpp>
 
-#include <iostream>
 #include <vector>
 #include <string>
+#include <utility>
 #include <unordered_map>
 
 namespace osrm
 {
+
+namespace util
+{
+
+/**
+ * JSON types representing OSRM responses.
+ *
+ * The json::Value type represents the basic sum-type, implemented as a variant.
+ *
+ * There are two ways for destructuring such types:
+ *  - Either provide a visitor and use the apply_visitor function or
+ *  - use the get function and explicitely specify the type
+ *
+ * See the following documentations on variants:
+ *  - https://github.com/mapbox/variant
+ *  - http://www.boost.org/doc/libs/1_55_0/doc/html/variant.html
+ *
+ * And take a look at the example we provide.
+ *
+ * \see OSRM
+ */
 namespace json
 {
 
+// fwd. decls.
 struct Object;
 struct Array;
 
+/**
+ * Typed string wrapper.
+ *
+ * Unwrap the type via its value member attribute.
+ */
 struct String
 {
-    String() {}
-    String(const char *value) : value(value) {}
-    String(std::string value) : value(std::move(value)) {}
+    String() = default;
+    String(const char *value_) : value{value_} {}
+    String(std::string value_) : value{std::move(value_)} {}
     std::string value;
 };
 
+/**
+ * Typed floating point number.
+ *
+ * Unwrap the type via its value member attribute.
+ */
 struct Number
 {
-    Number() {}
-    Number(double value) : value(static_cast<double>(value)) {}
+    Number() = default;
+    Number(double value_) : value{value_} {}
     double value;
 };
 
+/**
+ * Typed True.
+ */
 struct True
 {
 };
 
+/**
+ * Typed False.
+ */
 struct False
 {
 };
 
+/**
+ * Typed Null.
+ */
 struct Null
 {
 };
 
+/**
+ * Typed Value sum-type implemented as a variant able to represent tree-like JSON structures.
+ *
+ * Dispatch on its type by either by using apply_visitor or its get function.
+ */
 using Value = mapbox::util::variant<String,
                                     Number,
                                     mapbox::util::recursive_wrapper<Object>,
@@ -81,16 +127,28 @@ using Value = mapbox::util::variant<String,
                                     False,
                                     Null>;
 
+/**
+ * Typed Object.
+ *
+ * Unwrap the key-value pairs holding type via its values member attribute.
+ */
 struct Object
 {
     std::unordered_map<std::string, Value> values;
 };
 
+/**
+ * Typed Array.
+ *
+ * Unwrap the Value holding type via its values member attribute.
+ */
 struct Array
 {
     std::vector<Value> values;
 };
 
-} // namespace JSON
+} // namespace json
+} // namespace util
 } // namespace osrm
+
 #endif // JSON_CONTAINER_HPP
diff --git a/include/util/json_deep_compare.hpp b/include/util/json_deep_compare.hpp
new file mode 100644
index 0000000..32b0bde
--- /dev/null
+++ b/include/util/json_deep_compare.hpp
@@ -0,0 +1,158 @@
+#ifndef UTIL_JSON_DEEP_COMPARE_HPP
+#define UTIL_JSON_DEEP_COMPARE_HPP
+
+#include "util/json_container.hpp"
+#include "util/integer_range.hpp"
+
+#include <boost/assert.hpp>
+
+#include <algorithm>
+#include <functional>
+#include <set>
+
+namespace osrm
+{
+namespace util
+{
+namespace json
+{
+
+struct Comparator : mapbox::util::static_visitor<bool>
+{
+    Comparator(std::string &reason_, const std::string &lhs_path_, const std::string &rhs_path_)
+        : reason(reason_), lhs_path(lhs_path_), rhs_path(rhs_path_)
+    {
+    }
+
+    bool operator()(const String &lhs, const String &rhs) const {
+      bool is_same = lhs.value == rhs.value;
+      if (!is_same)
+      {
+        reason = lhs_path + " (= \"" + lhs.value + "\") != " + rhs_path + " (= \"" + rhs.value + "\")";
+      }
+      return is_same;
+    }
+
+    bool operator()(const Number &lhs, const Number &rhs) const {
+      bool is_same = lhs.value == rhs.value;
+      if (!is_same)
+      {
+        reason = lhs_path + " (= " + std::to_string(lhs.value) + ") != " + rhs_path + " (= " + std::to_string(rhs.value) + ")";
+      }
+      return is_same;
+    }
+
+    bool operator()(const Object &lhs, const Object &rhs) const
+    {
+        std::set<std::string> lhs_keys;
+        for (const auto &key_value : lhs.values)
+        {
+            lhs_keys.insert(key_value.first);
+        }
+
+        std::set<std::string> rhs_keys;
+        for (const auto &key_value : rhs.values)
+        {
+            rhs_keys.insert(key_value.first);
+        }
+
+        for (const auto &key : lhs_keys)
+        {
+            if (rhs_keys.find(key) == rhs_keys.end())
+            {
+                reason = rhs_path + " doesn't have key \"" + key + "\"";
+                return false;
+            }
+        }
+
+        for (const auto &key : rhs_keys)
+        {
+            if (lhs_keys.find(key) == lhs_keys.end())
+            {
+                reason = lhs_path + " doesn't have key \"" + key + "\"";
+                return false;
+            }
+        }
+
+        for (const auto &key : lhs_keys)
+        {
+            BOOST_ASSERT(rhs.values.find(key) != rhs.values.end());
+            BOOST_ASSERT(lhs.values.find(key) != lhs.values.end());
+
+            const auto &rhs_child = rhs.values.find(key)->second;
+            const auto &lhs_child = lhs.values.find(key)->second;
+            auto is_same = mapbox::util::apply_visitor(
+                Comparator(reason, lhs_path + "." + key, rhs_path + "." + key), lhs_child,
+                rhs_child);
+            if (!is_same)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    bool operator()(const Array &lhs, const Array &rhs) const
+    {
+        if (lhs.values.size() != rhs.values.size())
+        {
+            reason = lhs_path + ".length " + std::to_string(lhs.values.size()) + " != " + rhs_path +
+                     ".length " + std::to_string(rhs.values.size());
+            return false;
+        }
+
+        for (auto i = 0UL; i < lhs.values.size(); ++i)
+        {
+            auto is_same = mapbox::util::apply_visitor(
+                Comparator(reason, lhs_path + "[" + std::to_string(i) + "]",
+                           rhs_path + "[" + std::to_string(i) + "]"),
+                lhs.values[i], rhs.values[i]);
+            if (!is_same)
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    bool operator()(const True &, const True &) const { return true; }
+    bool operator()(const False &, const False &) const { return true; }
+    bool operator()(const Null &, const Null &) const { return true; }
+
+    bool operator()(const False &, const True &) const
+    {
+        reason = lhs_path + " is false but " + rhs_path + " is true";
+        return false;
+    }
+    bool operator()(const True &, const False &) const
+    {
+        reason = lhs_path + " is true but " + rhs_path + " is false";
+        return false;
+    }
+
+    template <typename T1,
+              typename T2,
+              typename = typename std::enable_if<!std::is_same<T1, T2>::value>::type>
+    bool operator()(const T1 &, const T2 &)
+    {
+        reason = lhs_path + " and " + rhs_path + " have different types";
+        return false;
+    }
+
+  private:
+    std::string &reason;
+    const std::string &lhs_path;
+    const std::string &rhs_path;
+};
+
+inline bool compare(const Value &reference, const Value &result, std::string &reason)
+{
+    return mapbox::util::apply_visitor(Comparator(reason, "reference", "result"), reference,
+                                       result);
+}
+}
+}
+}
+
+#endif
diff --git a/include/util/json_logger.hpp b/include/util/json_logger.hpp
new file mode 100644
index 0000000..aa72b54
--- /dev/null
+++ b/include/util/json_logger.hpp
@@ -0,0 +1,62 @@
+#ifndef JSON_LOGGER_HPP
+#define JSON_LOGGER_HPP
+
+#include "osrm/json_container.hpp"
+
+#include <boost/thread/tss.hpp>
+
+#include <string>
+#include <unordered_map>
+
+namespace osrm
+{
+namespace util
+{
+namespace json
+{
+
+// Used to append additional debugging information to the JSON response in a
+// thread safe manner.
+class Logger
+{
+    using MapT = std::unordered_map<std::string, Value>;
+
+  public:
+    static Logger *get()
+    {
+        static Logger logger;
+
+        bool return_logger = true;
+#ifdef NDEBUG
+        return_logger = false;
+#endif
+#ifdef ENABLE_JSON_LOGGING
+        return_logger = true;
+#endif
+
+        if (return_logger)
+        {
+            return &logger;
+        }
+
+        return nullptr;
+    }
+
+    void initialize(const std::string &name)
+    {
+        if (!map.get())
+        {
+            map.reset(new MapT());
+        }
+        (*map)[name] = Object();
+    }
+
+    void render(const std::string &name, Object &obj) const { obj.values["debug"] = map->at(name); }
+
+    boost::thread_specific_ptr<MapT> map;
+};
+}
+}
+}
+
+#endif /* JSON_LOGGER_HPP */
diff --git a/util/json_renderer.hpp b/include/util/json_renderer.hpp
similarity index 72%
rename from util/json_renderer.hpp
rename to include/util/json_renderer.hpp
index 09d7bb2..a1ac7a0 100644
--- a/util/json_renderer.hpp
+++ b/include/util/json_renderer.hpp
@@ -1,47 +1,27 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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.
-
-*/
-
 // based on
 // https://svn.apache.org/repos/asf/mesos/tags/release-0.9.0-incubating-RC0/src/common/json.hpp
 
 #ifndef JSON_RENDERER_HPP
 #define JSON_RENDERER_HPP
 
-#include "cast.hpp"
-#include "string_util.hpp"
+#include "util/cast.hpp"
+#include "util/string_util.hpp"
+
+#include "osrm/json_container.hpp"
 
-#include <osrm/json_container.hpp>
+#include <ostream>
+#include <vector>
+#include <iterator>
+#include <string>
 
 namespace osrm
 {
+namespace util
+{
 namespace json
 {
 
-struct Renderer : mapbox::util::static_visitor<>
+struct Renderer
 {
     explicit Renderer(std::ostream &_out) : out(_out) {}
 
@@ -97,7 +77,7 @@ struct Renderer : mapbox::util::static_visitor<>
     std::ostream &out;
 };
 
-struct ArrayRenderer : mapbox::util::static_visitor<>
+struct ArrayRenderer
 {
     explicit ArrayRenderer(std::vector<char> &_out) : out(_out) {}
 
@@ -183,5 +163,7 @@ inline void render(std::vector<char> &out, const Object &object)
 }
 
 } // namespace json
+} // namespace util
 } // namespace osrm
+
 #endif // JSON_RENDERER_HPP
diff --git a/include/util/json_util.hpp b/include/util/json_util.hpp
new file mode 100644
index 0000000..32a1bd7
--- /dev/null
+++ b/include/util/json_util.hpp
@@ -0,0 +1,58 @@
+#ifndef JSON_UTIL_HPP
+#define JSON_UTIL_HPP
+
+#include "osrm/json_container.hpp"
+#include "util/container.hpp"
+
+#include <cmath>
+#include <limits>
+
+namespace osrm
+{
+namespace util
+{
+namespace json
+{
+// Make sure we don't have inf and NaN values
+template <typename T> T clamp_float(T d)
+{
+    if (std::isnan(d) || std::numeric_limits<T>::infinity() == d)
+    {
+        return std::numeric_limits<T>::max();
+    }
+    if (-std::numeric_limits<T>::infinity() == d)
+    {
+        return std::numeric_limits<T>::lowest();
+    }
+
+    return d;
+}
+
+template <typename... Args> Array make_array(Args... args)
+{
+    Array a;
+    // TODO: check why a.values.emplace_back(args...); is not an option here
+    append_to_container(a.values, args...);
+    return a;
+}
+
+// Easy acces to object hierachies
+inline Value &get(Value &value) { return value; }
+
+template <typename... Keys> Value &get(Value &value, const char *key, Keys... keys)
+{
+    using recursive_object_t = mapbox::util::recursive_wrapper<Object>;
+    return get(value.get<recursive_object_t>().get().values[key], keys...);
+}
+
+template <typename... Keys> Value &get(Value &value, unsigned key, Keys... keys)
+{
+    using recursive_array_t = mapbox::util::recursive_wrapper<Array>;
+    return get(value.get<recursive_array_t>().get().values[key], keys...);
+}
+
+} // namespace json
+} // namespace util
+} // namespace osrm
+
+#endif // JSON_UTIL_HPP
diff --git a/include/util/lua_util.hpp b/include/util/lua_util.hpp
new file mode 100644
index 0000000..4d4fe17
--- /dev/null
+++ b/include/util/lua_util.hpp
@@ -0,0 +1,54 @@
+#ifndef LUA_UTIL_HPP
+#define LUA_UTIL_HPP
+
+extern "C" {
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+}
+
+#include <boost/filesystem/convenience.hpp>
+#include <luabind/luabind.hpp>
+
+#include <iostream>
+#include <string>
+
+namespace osrm
+{
+namespace util
+{
+
+struct LuaState
+{
+    LuaState() : handle{::luaL_newstate(), &::lua_close} { luaL_openlibs(*this); }
+
+    operator lua_State *() { return handle.get(); }
+    operator lua_State const *() const { return handle.get(); }
+
+    using handle_type = std::unique_ptr<lua_State, decltype(&::lua_close)>;
+    handle_type handle;
+};
+
+// Check if the lua function <name> is defined
+inline bool luaFunctionExists(lua_State *lua_state, const char *name)
+{
+    luabind::object globals_table = luabind::globals(lua_state);
+    luabind::object lua_function = globals_table[name];
+    return lua_function && (luabind::type(lua_function) == LUA_TFUNCTION);
+}
+
+// Add the folder contain the script to the lua load path, so script can easily require() other lua
+// scripts inside that folder, or subfolders.
+// See http://lua-users.org/wiki/PackagePath for details on the package.path syntax.
+inline void luaAddScriptFolderToLoadPath(lua_State *lua_state, const char *file_name)
+{
+    boost::filesystem::path profile_path = boost::filesystem::canonical(file_name);
+    std::string folder = profile_path.parent_path().string();
+    // TODO: This code is most probably not Windows safe since it uses UNIX'ish path delimiters
+    const std::string lua_code = "package.path = \"" + folder + "/?.lua;\" .. package.path";
+    luaL_dostring(lua_state, lua_code.c_str());
+}
+}
+}
+
+#endif // LUA_UTIL_HPP
diff --git a/util/make_unique.hpp b/include/util/make_unique.hpp
similarity index 51%
rename from util/make_unique.hpp
rename to include/util/make_unique.hpp
index 83e2301..74d4e3d 100644
--- a/util/make_unique.hpp
+++ b/include/util/make_unique.hpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-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 MAKE_UNIQUE_H_
 #define MAKE_UNIQUE_H_
 
@@ -34,6 +7,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace osrm
 {
+namespace util
+{
+
 // Implement make_unique according to N3656. Taken from libcxx's implementation
 
 /// \brief Constructs a `new T()` with the given args and returns a
@@ -70,4 +46,6 @@ make_unique(size_t n)
 template <class T, class... Args>
 typename std::enable_if<std::extent<T>::value != 0>::type make_unique(Args &&...) = delete;
 }
+}
+
 #endif // MAKE_UNIQUE_H_
diff --git a/include/util/matrix_graph_wrapper.hpp b/include/util/matrix_graph_wrapper.hpp
new file mode 100644
index 0000000..3b4ee5c
--- /dev/null
+++ b/include/util/matrix_graph_wrapper.hpp
@@ -0,0 +1,51 @@
+#ifndef MATRIX_GRAPH_WRAPPER_H
+#define MATRIX_GRAPH_WRAPPER_H
+
+#include <vector>
+#include <cstddef>
+#include <iterator>
+
+#include "util/typedefs.hpp"
+
+namespace osrm
+{
+namespace util
+{
+
+// This Wrapper provides all methods that are needed for extractor::TarjanSCC, when the graph is
+// given in a
+// matrix representation (e.g. as output from a distance table call)
+
+template <typename T> class MatrixGraphWrapper
+{
+  public:
+    MatrixGraphWrapper(std::vector<T> table, const std::size_t number_of_nodes)
+        : table_(std::move(table)), number_of_nodes_(number_of_nodes){}
+
+    std::size_t GetNumberOfNodes() const { return number_of_nodes_; }
+
+    std::vector<T> GetAdjacentEdgeRange(const NodeID node) const
+    {
+
+        std::vector<T> edges;
+        // find all valid adjacent edges and move to vector `edges`
+        for (std::size_t i = 0; i < number_of_nodes_; ++i)
+        {
+            if (*(std::begin(table_) + node * number_of_nodes_ + i) != INVALID_EDGE_WEIGHT)
+            {
+                edges.push_back(i);
+            }
+        }
+        return edges;
+    }
+
+    EdgeWeight GetTarget(const EdgeWeight edge) const { return edge; }
+
+  private:
+    const std::vector<T> table_;
+    const std::size_t number_of_nodes_;
+};
+}
+}
+
+#endif // MATRIX_GRAPH_WRAPPER_H
diff --git a/include/util/name_table.hpp b/include/util/name_table.hpp
new file mode 100644
index 0000000..2f1887a
--- /dev/null
+++ b/include/util/name_table.hpp
@@ -0,0 +1,31 @@
+#ifndef OSRM_UTIL_NAME_TABLE_HPP
+#define OSRM_UTIL_NAME_TABLE_HPP
+
+#include "util/shared_memory_vector_wrapper.hpp"
+#include "util/range_table.hpp"
+
+#include <string>
+
+namespace osrm
+{
+namespace util
+{
+
+// While this could, theoretically, hold any names in the fitting format,
+// the NameTable allows access to a part of the Datafacade to allow
+// processing based on name indices.
+class NameTable
+{
+  private:
+    // FIXME should this use shared memory
+    RangeTable<16, false> m_name_table;
+    ShM<char, false>::vector m_names_char_list;
+
+  public:
+    NameTable(const std::string &filename);
+    std::string GetNameForID(const unsigned name_id) const;
+};
+} // namespace util
+} // namespace osrm
+
+#endif // OSRM_UTIL_NAME_TABLE_HPP
diff --git a/include/util/node_based_graph.hpp b/include/util/node_based_graph.hpp
new file mode 100644
index 0000000..463fbb1
--- /dev/null
+++ b/include/util/node_based_graph.hpp
@@ -0,0 +1,95 @@
+#ifndef NODE_BASED_GRAPH_HPP
+#define NODE_BASED_GRAPH_HPP
+
+#include "util/dynamic_graph.hpp"
+#include "extractor/node_based_edge.hpp"
+#include "util/graph_utils.hpp"
+#include "extractor/guidance/classification_data.hpp"
+
+#include <tbb/parallel_sort.h>
+
+#include <memory>
+
+namespace osrm
+{
+namespace util
+{
+
+struct NodeBasedEdgeData
+{
+    NodeBasedEdgeData()
+        : distance(INVALID_EDGE_WEIGHT), edge_id(SPECIAL_NODEID),
+          name_id(std::numeric_limits<unsigned>::max()), access_restricted(false), reversed(false),
+          roundabout(false), travel_mode(TRAVEL_MODE_INACCESSIBLE)
+    {
+    }
+
+    NodeBasedEdgeData(int distance,
+                      unsigned edge_id,
+                      unsigned name_id,
+                      bool access_restricted,
+                      bool reversed,
+                      bool roundabout,
+                      bool startpoint,
+                      extractor::TravelMode travel_mode)
+        : distance(distance), edge_id(edge_id), name_id(name_id),
+          access_restricted(access_restricted), reversed(reversed), roundabout(roundabout),
+          startpoint(startpoint), travel_mode(travel_mode)
+    {
+    }
+
+    int distance;
+    unsigned edge_id;
+    unsigned name_id;
+    bool access_restricted : 1;
+    bool reversed : 1;
+    bool roundabout : 1;
+    bool startpoint : 1;
+    extractor::TravelMode travel_mode : 4;
+    extractor::guidance::RoadClassificationData road_classification;
+
+    bool IsCompatibleTo(const NodeBasedEdgeData &other) const
+    {
+        return (name_id == other.name_id) && (reversed == other.reversed) &&
+               (roundabout == other.roundabout) && (startpoint == other.startpoint) &&
+               (access_restricted == other.access_restricted) &&
+               (travel_mode == other.travel_mode) &&
+               (road_classification == other.road_classification);
+    }
+};
+
+using NodeBasedDynamicGraph = DynamicGraph<NodeBasedEdgeData>;
+
+/// Factory method to create NodeBasedDynamicGraph from NodeBasedEdges
+/// Since DynamicGraph expects directed edges, we need to insert
+/// two edges for undirected edges.
+inline std::shared_ptr<NodeBasedDynamicGraph>
+NodeBasedDynamicGraphFromEdges(std::size_t number_of_nodes,
+                               const std::vector<extractor::NodeBasedEdge> &input_edge_list)
+{
+    auto edges_list = directedEdgesFromCompressed<NodeBasedDynamicGraph::InputEdge>(
+        input_edge_list, [](NodeBasedDynamicGraph::InputEdge &output_edge,
+                            const extractor::NodeBasedEdge &input_edge)
+        {
+            output_edge.data.distance = static_cast<int>(input_edge.weight);
+            BOOST_ASSERT(output_edge.data.distance > 0);
+
+            output_edge.data.roundabout = input_edge.roundabout;
+            output_edge.data.name_id = input_edge.name_id;
+            output_edge.data.access_restricted = input_edge.access_restricted;
+            output_edge.data.travel_mode = input_edge.travel_mode;
+            output_edge.data.startpoint = input_edge.startpoint;
+            output_edge.data.road_classification = input_edge.road_classification;
+        });
+
+    tbb::parallel_sort(edges_list.begin(), edges_list.end());
+
+    auto graph = std::make_shared<NodeBasedDynamicGraph>(
+        static_cast<NodeBasedDynamicGraph::NodeIterator>(number_of_nodes), edges_list);
+
+    return graph;
+}
+}
+}
+
+#endif // NODE_BASED_GRAPH_HPP
diff --git a/data_structures/percent.hpp b/include/util/percent.hpp
similarity index 57%
rename from data_structures/percent.hpp
rename to include/util/percent.hpp
index 392417e..d34a77d 100644
--- a/data_structures/percent.hpp
+++ b/include/util/percent.hpp
@@ -1,36 +1,14 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 PERCENT_HPP
 #define PERCENT_HPP
 
 #include <iostream>
 #include <atomic>
 
+namespace osrm
+{
+namespace util
+{
+
 class Percent
 {
   public:
@@ -97,5 +75,7 @@ class Percent
         }
     }
 };
+}
+}
 
 #endif // PERCENT_HPP
diff --git a/data_structures/range_table.hpp b/include/util/range_table.hpp
similarity index 81%
rename from data_structures/range_table.hpp
rename to include/util/range_table.hpp
index e750c90..f012349 100644
--- a/data_structures/range_table.hpp
+++ b/include/util/range_table.hpp
@@ -1,39 +1,17 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 RANGE_TABLE_HPP
 #define RANGE_TABLE_HPP
 
-#include "../util/integer_range.hpp"
-#include "shared_memory_factory.hpp"
-#include "shared_memory_vector_wrapper.hpp"
+#include "util/integer_range.hpp"
+#include "util/shared_memory_vector_wrapper.hpp"
 
 #include <fstream>
 #include <array>
+#include <utility>
+
+namespace osrm
+{
+namespace util
+{
 /*
  * These pre-declarations are needed because parsing C++ is hard
  * and otherwise the compiler gets confused.
@@ -62,7 +40,7 @@ template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY> class RangeTable
     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>;
+    using RangeT = range<unsigned>;
 
     friend std::ostream &operator<<<>(std::ostream &out, const RangeTable &table);
     friend std::istream &operator>><>(std::istream &in, RangeTable &table);
@@ -75,13 +53,13 @@ template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY> class RangeTable
                         const unsigned sum_lengths)
         : sum_lengths(sum_lengths)
     {
-        block_offsets.swap(external_offsets);
-        diff_blocks.swap(external_blocks);
+        using std::swap;
+        swap(block_offsets, external_offsets);
+        swap(diff_blocks, external_blocks);
     }
 
     // construct table from length vector
-    template<typename VectorT>
-    explicit RangeTable(const VectorT &lengths)
+    template <typename VectorT> explicit RangeTable(const VectorT &lengths)
     {
         const unsigned number_of_blocks = [&lengths]()
         {
@@ -194,7 +172,7 @@ template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY> class RangeTable
         BOOST_ASSERT(begin_idx < sum_lengths && end_idx <= sum_lengths);
         BOOST_ASSERT(begin_idx <= end_idx);
 
-        return osrm::irange(begin_idx, end_idx);
+        return irange(begin_idx, end_idx);
     }
 
   private:
@@ -256,5 +234,7 @@ std::istream &operator>>(std::istream &in, RangeTable<BLOCK_SIZE, USE_SHARED_MEM
     in.read((char *)table.diff_blocks.data(), BLOCK_SIZE * number_of_blocks);
     return in;
 }
+}
+}
 
 #endif // RANGE_TABLE_HPP
diff --git a/include/util/rectangle.hpp b/include/util/rectangle.hpp
new file mode 100644
index 0000000..fd0f871
--- /dev/null
+++ b/include/util/rectangle.hpp
@@ -0,0 +1,182 @@
+#ifndef RECTANGLE_HPP
+#define RECTANGLE_HPP
+
+#include "util/coordinate_calculation.hpp"
+
+#include <boost/assert.hpp>
+
+#include "osrm/coordinate.hpp"
+
+#include <iomanip>
+#include <algorithm>
+#include <utility>
+#include <limits>
+
+#include <cstdint>
+
+namespace osrm
+{
+namespace util
+{
+
+// TODO: Make template type, add tests
+struct RectangleInt2D
+{
+    RectangleInt2D()
+        : min_lon(std::numeric_limits<std::int32_t>::max()),
+          max_lon(std::numeric_limits<std::int32_t>::min()),
+          min_lat(std::numeric_limits<std::int32_t>::max()),
+          max_lat(std::numeric_limits<std::int32_t>::min())
+    {
+    }
+
+    RectangleInt2D(FixedLongitude min_lon_,
+                   FixedLongitude max_lon_,
+                   FixedLatitude min_lat_,
+                   FixedLatitude max_lat_)
+        : min_lon(min_lon_), max_lon(max_lon_), min_lat(min_lat_), max_lat(max_lat_)
+    {
+    }
+
+    RectangleInt2D(FloatLongitude min_lon_,
+                   FloatLongitude max_lon_,
+                   FloatLatitude min_lat_,
+                   FloatLatitude max_lat_)
+        : min_lon(toFixed(min_lon_)), max_lon(toFixed(max_lon_)), min_lat(toFixed(min_lat_)),
+          max_lat(toFixed(max_lat_))
+    {
+    }
+
+    FixedLongitude min_lon, max_lon;
+    FixedLatitude min_lat, max_lat;
+
+    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_lon != FixedLongitude(std::numeric_limits<std::int32_t>::min()));
+        BOOST_ASSERT(min_lat != FixedLatitude(std::numeric_limits<std::int32_t>::min()));
+        BOOST_ASSERT(max_lon != FixedLongitude(std::numeric_limits<std::int32_t>::min()));
+        BOOST_ASSERT(max_lat != FixedLatitude(std::numeric_limits<std::int32_t>::min()));
+    }
+
+    Coordinate Centroid() const
+    {
+        Coordinate centroid;
+        // The coordinates of the midpoints are given by:
+        // x = (x1 + x2) /2 and y = (y1 + y2) /2.
+        centroid.lon = (min_lon + max_lon) / FixedLongitude(2);
+        centroid.lat = (min_lat + max_lat) / FixedLatitude(2);
+        return centroid;
+    }
+
+    bool Intersects(const RectangleInt2D &other) const
+    {
+        // Standard box intersection test - check if boxes *don't* overlap,
+        // and return the negative of that
+        return !(max_lon < other.min_lon || min_lon > other.max_lon || max_lat < other.min_lat ||
+                 min_lat > other.max_lat);
+    }
+
+    // This code assumes that we are operating in euclidean space!
+    // That means if you just put unprojected lat/lon in here you will
+    // get invalid results.
+    double GetMinSquaredDist(const Coordinate 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);
+
+        double min_dist = std::numeric_limits<double>::max();
+        switch (d)
+        {
+        case NORTH:
+            min_dist = coordinate_calculation::squaredEuclideanDistance(
+                location, Coordinate(location.lon, max_lat));
+            break;
+        case SOUTH:
+            min_dist = coordinate_calculation::squaredEuclideanDistance(
+                location, Coordinate(location.lon, min_lat));
+            break;
+        case WEST:
+            min_dist = coordinate_calculation::squaredEuclideanDistance(
+                location, Coordinate(min_lon, location.lat));
+            break;
+        case EAST:
+            min_dist = coordinate_calculation::squaredEuclideanDistance(
+                location, Coordinate(max_lon, location.lat));
+            break;
+        case NORTH_EAST:
+            min_dist =
+                coordinate_calculation::squaredEuclideanDistance(location, Coordinate(max_lon, max_lat));
+            break;
+        case NORTH_WEST:
+            min_dist =
+                coordinate_calculation::squaredEuclideanDistance(location, Coordinate(min_lon, max_lat));
+            break;
+        case SOUTH_EAST:
+            min_dist =
+                coordinate_calculation::squaredEuclideanDistance(location, Coordinate(max_lon, min_lat));
+            break;
+        case SOUTH_WEST:
+            min_dist =
+                coordinate_calculation::squaredEuclideanDistance(location, Coordinate(min_lon, min_lat));
+            break;
+        default:
+            break;
+        }
+
+        BOOST_ASSERT(min_dist < std::numeric_limits<double>::max());
+
+        return min_dist;
+    }
+
+    bool Contains(const Coordinate location) const
+    {
+        const bool lons_contained = (location.lon >= min_lon) && (location.lon <= max_lon);
+        const bool lats_contained = (location.lat >= min_lat) && (location.lat <= max_lat);
+        return lons_contained && lats_contained;
+    }
+
+    friend std::ostream &operator<<(std::ostream &out, const RectangleInt2D &rect);
+};
+inline std::ostream &operator<<(std::ostream &out, const RectangleInt2D &rect)
+{
+    out << std::setprecision(12) << "(" << toFloating(rect.min_lon) << ","
+        << toFloating(rect.max_lon) << "," << toFloating(rect.min_lat) << ","
+        << toFloating(rect.max_lat) << ")";
+    return out;
+}
+}
+}
+
+#endif
diff --git a/data_structures/shared_memory_vector_wrapper.hpp b/include/util/shared_memory_vector_wrapper.hpp
similarity index 61%
rename from data_structures/shared_memory_vector_wrapper.hpp
rename to include/util/shared_memory_vector_wrapper.hpp
index dc51cff..74f4a8e 100644
--- a/data_structures/shared_memory_vector_wrapper.hpp
+++ b/include/util/shared_memory_vector_wrapper.hpp
@@ -1,39 +1,20 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 SHARED_MEMORY_VECTOR_WRAPPER_HPP
 #define SHARED_MEMORY_VECTOR_WRAPPER_HPP
 
 #include <boost/assert.hpp>
 
+#include <cstddef>
+
 #include <algorithm>
 #include <iterator>
 #include <type_traits>
 #include <vector>
+#include <utility>
+
+namespace osrm
+{
+namespace util
+{
 
 template <typename DataT> class ShMemIterator : public std::iterator<std::input_iterator_tag, DataT>
 {
@@ -74,13 +55,6 @@ template <typename DataT> class SharedMemoryWrapper
 
     SharedMemoryWrapper(DataT *ptr, std::size_t size) : m_ptr(ptr), m_size(size) {}
 
-    void swap(SharedMemoryWrapper<DataT> &other)
-    {
-        // 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);
-    }
-
     DataT &at(const std::size_t index) { return m_ptr[index]; }
 
     const DataT &at(const std::size_t index) const { return m_ptr[index]; }
@@ -104,6 +78,9 @@ template <typename DataT> class SharedMemoryWrapper
         BOOST_ASSERT_MSG(index < m_size, "invalid size");
         return m_ptr[index];
     }
+
+    template <typename T>
+    friend void swap(SharedMemoryWrapper<T> &, SharedMemoryWrapper<T> &) noexcept;
 };
 
 template <> class SharedMemoryWrapper<bool>
@@ -117,18 +94,11 @@ template <> class SharedMemoryWrapper<bool>
 
     SharedMemoryWrapper(unsigned *ptr, std::size_t size) : m_ptr(ptr), m_size(size) {}
 
-    void swap(SharedMemoryWrapper<bool> &other)
-    {
-        // 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);
-    }
-
     bool at(const std::size_t index) const
     {
         const std::size_t bucket = index / 32;
         const unsigned offset = static_cast<unsigned>(index % 32);
-        return m_ptr[bucket] & (1 << offset);
+        return m_ptr[bucket] & (1u << offset);
     }
 
     std::size_t size() const { return m_size; }
@@ -140,15 +110,28 @@ template <> class SharedMemoryWrapper<bool>
         BOOST_ASSERT_MSG(index < m_size, "invalid size");
         const unsigned bucket = index / 32;
         const unsigned offset = index % 32;
-        return m_ptr[bucket] & (1 << offset);
+        return m_ptr[bucket] & (1u << offset);
     }
+
+    template <typename T>
+    friend void swap(SharedMemoryWrapper<T> &, SharedMemoryWrapper<T> &) noexcept;
 };
 
+// Both SharedMemoryWrapper<T> and the SharedMemoryWrapper<bool> specializations share this impl.
+template <typename DataT>
+void swap(SharedMemoryWrapper<DataT> &lhs, SharedMemoryWrapper<DataT> &rhs) noexcept
+{
+    std::swap(lhs.m_ptr, rhs.m_ptr);
+    std::swap(lhs.m_size, rhs.m_size);
+}
+
 template <typename DataT, bool UseSharedMemory> struct ShM
 {
     using vector = typename std::conditional<UseSharedMemory,
                                              SharedMemoryWrapper<DataT>,
                                              std::vector<DataT>>::type;
 };
+}
+}
 
 #endif // SHARED_MEMORY_VECTOR_WRAPPER_HPP
diff --git a/include/util/simple_logger.hpp b/include/util/simple_logger.hpp
new file mode 100644
index 0000000..f71f0ff
--- /dev/null
+++ b/include/util/simple_logger.hpp
@@ -0,0 +1,55 @@
+#ifndef SIMPLE_LOGGER_HPP
+#define SIMPLE_LOGGER_HPP
+
+#include <atomic>
+#include <mutex>
+#include <sstream>
+
+enum LogLevel
+{
+    logINFO,
+    logWARNING,
+    logDEBUG
+};
+
+namespace osrm
+{
+namespace util
+{
+
+class LogPolicy
+{
+  public:
+    void Unmute();
+
+    void Mute();
+
+    bool IsMute() const;
+
+    static LogPolicy &GetInstance();
+
+    LogPolicy(const LogPolicy &) = delete;
+    LogPolicy &operator=(const LogPolicy &) = delete;
+
+  private:
+    LogPolicy() : m_is_mute(true) {}
+    std::atomic<bool> m_is_mute;
+};
+
+class SimpleLogger
+{
+  public:
+    SimpleLogger();
+
+    virtual ~SimpleLogger();
+    std::mutex &get_mutex();
+    std::ostringstream &Write(LogLevel l = logINFO) noexcept;
+
+  private:
+    std::ostringstream os;
+    LogLevel level;
+};
+}
+}
+
+#endif /* SIMPLE_LOGGER_HPP */
diff --git a/data_structures/static_graph.hpp b/include/util/static_graph.hpp
similarity index 70%
rename from data_structures/static_graph.hpp
rename to include/util/static_graph.hpp
index 3b8f927..a4fa2d7 100644
--- a/data_structures/static_graph.hpp
+++ b/include/util/static_graph.hpp
@@ -1,37 +1,10 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 STATIC_GRAPH_HPP
 #define STATIC_GRAPH_HPP
 
-#include "percent.hpp"
-#include "shared_memory_vector_wrapper.hpp"
-#include "../util/integer_range.hpp"
-#include "../typedefs.h"
+#include "util/percent.hpp"
+#include "util/shared_memory_vector_wrapper.hpp"
+#include "util/integer_range.hpp"
+#include "util/typedefs.hpp"
 
 #include <boost/assert.hpp>
 
@@ -40,13 +13,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <utility>
 #include <vector>
 
+namespace osrm
+{
+namespace util
+{
+
 template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
 {
   public:
     using NodeIterator = NodeID;
     using EdgeIterator = NodeID;
     using EdgeData = EdgeDataT;
-    using EdgeRange = osrm::range<EdgeIterator>;
+    using EdgeRange = range<EdgeIterator>;
 
     class InputEdge
     {
@@ -84,20 +62,20 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
 
     EdgeRange GetAdjacentEdgeRange(const NodeID node) const
     {
-        return osrm::irange(BeginEdges(node), EndEdges(node));
+        return irange(BeginEdges(node), EndEdges(node));
     }
 
-    template<typename ContainerT>
-    StaticGraph(const int nodes, const ContainerT &graph)
+    template <typename ContainerT> StaticGraph(const int nodes, const ContainerT &graph)
     {
-        BOOST_ASSERT(std::is_sorted(const_cast<ContainerT&>(graph).begin(), const_cast<ContainerT&>(graph).end()));
+        BOOST_ASSERT(std::is_sorted(const_cast<ContainerT &>(graph).begin(),
+                                    const_cast<ContainerT &>(graph).end()));
 
         number_of_nodes = nodes;
         number_of_edges = static_cast<EdgeIterator>(graph.size());
         node_array.resize(number_of_nodes + 1);
         EdgeIterator edge = 0;
         EdgeIterator position = 0;
-        for (const auto node : osrm::irange(0u, number_of_nodes + 1))
+        for (const auto node : irange(0u, number_of_nodes + 1))
         {
             EdgeIterator last_edge = edge;
             while (edge < number_of_edges && graph[edge].source == node)
@@ -109,10 +87,10 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
         }
         edge_array.resize(position); //(edge)
         edge = 0;
-        for (const auto node : osrm::irange(0u, number_of_nodes))
+        for (const auto node : irange(0u, number_of_nodes))
         {
             EdgeIterator e = node_array[node + 1].first_edge;
-            for (const auto i : osrm::irange(node_array[node].first_edge, e))
+            for (const auto i : irange(node_array[node].first_edge, e))
             {
                 edge_array[i].target = graph[edge].target;
                 edge_array[i].data = graph[edge].data;
@@ -127,8 +105,9 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
         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);
+        using std::swap;
+        swap(node_array, nodes);
+        swap(edge_array, edges);
     }
 
     unsigned GetNumberOfNodes() const { return number_of_nodes; }
@@ -159,7 +138,7 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
     // searches for a specific edge
     EdgeIterator FindEdge(const NodeIterator from, const NodeIterator to) const
     {
-        for (const auto i : osrm::irange(BeginEdges(from), EndEdges(from)))
+        for (const auto i : irange(BeginEdges(from), EndEdges(from)))
         {
             if (to == edge_array[i].target)
             {
@@ -215,5 +194,7 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
     typename ShM<NodeArrayEntry, UseSharedMemory>::vector node_array;
     typename ShM<EdgeArrayEntry, UseSharedMemory>::vector edge_array;
 };
+}
+}
 
 #endif // STATIC_GRAPH_HPP
diff --git a/data_structures/static_rtree.hpp b/include/util/static_rtree.hpp
similarity index 53%
rename from data_structures/static_rtree.hpp
rename to include/util/static_rtree.hpp
index 6bc3678..6924d94 100644
--- a/data_structures/static_rtree.hpp
+++ b/include/util/static_rtree.hpp
@@ -1,46 +1,17 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 STATIC_RTREE_HPP
 #define STATIC_RTREE_HPP
 
-#include "deallocating_vector.hpp"
-#include "hilbert_value.hpp"
-#include "rectangle.hpp"
-#include "shared_memory_factory.hpp"
-#include "shared_memory_vector_wrapper.hpp"
+#include "util/deallocating_vector.hpp"
+#include "util/hilbert_value.hpp"
+#include "util/rectangle.hpp"
+#include "util/shared_memory_vector_wrapper.hpp"
 
-#include "../util/bearing.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/mercator.hpp"
-#include "../util/osrm_exception.hpp"
-#include "../typedefs.h"
+#include "util/bearing.hpp"
+#include "util/integer_range.hpp"
+#include "util/exception.hpp"
+#include "util/typedefs.hpp"
 
-#include <osrm/coordinate.hpp>
+#include "osrm/coordinate.hpp"
 
 #include <boost/assert.hpp>
 #include <boost/filesystem.hpp>
@@ -59,12 +30,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <string>
 #include <vector>
 
+namespace osrm
+{
+namespace util
+{
+
 // Static RTree for serving nearest neighbour queries
+// All coordinates are pojected first to Web Mercator before the bounding boxes
+// are computed, this means the internal distance metric doesn not represent meters!
 template <class EdgeDataT,
-          class CoordinateListT = std::vector<FixedPointCoordinate>,
+          class CoordinateListT = std::vector<Coordinate>,
           bool UseSharedMemory = false,
-          uint32_t BRANCHING_FACTOR = 64,
-          uint32_t LEAF_NODE_SIZE = 1024>
+          std::uint32_t BRANCHING_FACTOR = 64,
+          std::uint32_t LEAF_NODE_SIZE = 1024>
 class StaticRTree
 {
   public:
@@ -72,21 +50,33 @@ class StaticRTree
     using EdgeData = EdgeDataT;
     using CoordinateList = CoordinateListT;
 
-    static constexpr std::size_t MAX_CHECKED_ELEMENTS = 4 * LEAF_NODE_SIZE;
+    struct CandidateSegment
+    {
+        Coordinate fixed_projected_coordinate;
+        EdgeDataT data;
+    };
 
     struct TreeNode
     {
         TreeNode() : child_count(0), child_is_on_disk(false) {}
         Rectangle minimum_bounding_rectangle;
-        uint32_t child_count : 31;
+        std::uint32_t child_count : 31;
         bool child_is_on_disk : 1;
-        uint32_t children[BRANCHING_FACTOR];
+        std::uint32_t children[BRANCHING_FACTOR];
+    };
+
+    struct LeafNode
+    {
+        LeafNode() : object_count(0), objects() {}
+        uint32_t object_count;
+        std::array<EdgeDataT, LEAF_NODE_SIZE> objects;
     };
 
   private:
     struct WrappedInputElement
     {
-        explicit WrappedInputElement(const uint64_t _hilbert_value, const uint32_t _array_index)
+        explicit WrappedInputElement(const uint64_t _hilbert_value,
+                                     const std::uint32_t _array_index)
             : m_hilbert_value(_hilbert_value), m_array_index(_array_index)
         {
         }
@@ -94,7 +84,7 @@ class StaticRTree
         WrappedInputElement() : m_hilbert_value(0), m_array_index(UINT_MAX) {}
 
         uint64_t m_hilbert_value;
-        uint32_t m_array_index;
+        std::uint32_t m_array_index;
 
         inline bool operator<(const WrappedInputElement &other) const
         {
@@ -102,23 +92,16 @@ class StaticRTree
         }
     };
 
-    struct LeafNode
-    {
-        LeafNode() : object_count(0), objects() {}
-        uint32_t object_count;
-        std::array<EdgeDataT, LEAF_NODE_SIZE> objects;
-    };
-
-    using QueryNodeType = mapbox::util::variant<TreeNode, EdgeDataT>;
+    using QueryNodeType = mapbox::util::variant<TreeNode, CandidateSegment>;
     struct QueryCandidate
     {
         inline bool operator<(const QueryCandidate &other) const
         {
             // Attn: this is reversed order. std::pq is a max pq!
-            return other.min_dist < min_dist;
+            return other.squared_min_dist < squared_min_dist;
         }
 
-        float min_dist;
+        double squared_min_dist;
         QueryNodeType node;
     };
 
@@ -129,8 +112,8 @@ class StaticRTree
     boost::filesystem::ifstream leaves_stream;
 
   public:
-    StaticRTree() = delete;
     StaticRTree(const StaticRTree &) = delete;
+    StaticRTree &operator=(const StaticRTree &) = delete;
 
     template <typename CoordinateT>
     // Construct a packed Hilbert-R-Tree with Kamel-Faloutsos algorithm [1]
@@ -142,12 +125,10 @@ class StaticRTree
     {
         std::vector<WrappedInputElement> input_wrapper_vector(m_element_count);
 
-        HilbertCode get_hilbert_number;
-
         // generate auxiliary vector of hilbert-values
         tbb::parallel_for(
             tbb::blocked_range<uint64_t>(0, m_element_count),
-            [&input_data_vector, &input_wrapper_vector, &get_hilbert_number,
+            [&input_data_vector, &input_wrapper_vector,
              &coordinate_list](const tbb::blocked_range<uint64_t> &range)
             {
                 for (uint64_t element_counter = range.begin(), end = range.end();
@@ -159,16 +140,16 @@ class StaticRTree
                     EdgeDataT const &current_element = input_data_vector[element_counter];
 
                     // Get Hilbert-Value for centroid in mercartor projection
-                    FixedPointCoordinate current_centroid = EdgeDataT::Centroid(
-                        FixedPointCoordinate(coordinate_list.at(current_element.u).lat,
-                                             coordinate_list.at(current_element.u).lon),
-                        FixedPointCoordinate(coordinate_list.at(current_element.v).lat,
-                                             coordinate_list.at(current_element.v).lon));
-                    current_centroid.lat =
+                    BOOST_ASSERT(current_element.u < coordinate_list.size());
+                    BOOST_ASSERT(current_element.v < coordinate_list.size());
+
+                    Coordinate current_centroid = coordinate_calculation::centroid(
+                        coordinate_list[current_element.u], coordinate_list[current_element.v]);
+                    current_centroid.lat = FixedLatitude(
                         COORDINATE_PRECISION *
-                        mercator::lat2y(current_centroid.lat / COORDINATE_PRECISION);
+                        coordinate_calculation::mercator::latToY(toFloating(current_centroid.lat)));
 
-                    current_wrapper.m_hilbert_value = get_hilbert_number(current_centroid);
+                    current_wrapper.m_hilbert_value = hilbertCode(current_centroid);
                 }
             });
 
@@ -187,12 +168,12 @@ class StaticRTree
 
             LeafNode current_leaf;
             TreeNode current_node;
-            for (uint32_t current_element_index = 0; LEAF_NODE_SIZE > current_element_index;
+            for (std::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))
                 {
-                    uint32_t index_of_next_object =
+                    std::uint32_t index_of_next_object =
                         input_wrapper_vector[processed_objects_count + current_element_index]
                             .m_array_index;
                     current_leaf.objects[current_element_index] =
@@ -213,19 +194,16 @@ class StaticRTree
             processed_objects_count += current_leaf.object_count;
         }
 
-        // close leaf file
-        leaf_node_file.close();
-
-        uint32_t processing_level = 0;
+        std::uint32_t processing_level = 0;
         while (1 < tree_nodes_in_level.size())
         {
             std::vector<TreeNode> tree_nodes_in_next_level;
-            uint32_t processed_tree_nodes_in_level = 0;
+            std::uint32_t processed_tree_nodes_in_level = 0;
             while (processed_tree_nodes_in_level < tree_nodes_in_level.size())
             {
                 TreeNode parent_node;
                 // pack BRANCHING_FACTOR elements into tree_nodes each
-                for (uint32_t current_child_node_index = 0;
+                for (std::uint32_t current_child_node_index = 0;
                      BRANCHING_FACTOR > current_child_node_index; ++current_child_node_index)
                 {
                     if (processed_tree_nodes_in_level < tree_nodes_in_level.size())
@@ -255,17 +233,18 @@ class StaticRTree
         // reverse and renumber tree to have root at index 0
         std::reverse(m_search_tree.begin(), m_search_tree.end());
 
-        uint32_t search_tree_size = m_search_tree.size();
-        tbb::parallel_for(tbb::blocked_range<uint32_t>(0, search_tree_size),
-                          [this, &search_tree_size](const tbb::blocked_range<uint32_t> &range)
+        std::uint32_t search_tree_size = m_search_tree.size();
+        tbb::parallel_for(tbb::blocked_range<std::uint32_t>(0, search_tree_size),
+                          [this, &search_tree_size](const tbb::blocked_range<std::uint32_t> &range)
                           {
-                              for (uint32_t i = range.begin(), end = range.end(); i != end; ++i)
+                              for (std::uint32_t i = range.begin(), end = range.end(); i != end;
+                                   ++i)
                               {
                                   TreeNode &current_tree_node = this->m_search_tree[i];
-                                  for (uint32_t j = 0; j < current_tree_node.child_count; ++j)
+                                  for (std::uint32_t j = 0; j < current_tree_node.child_count; ++j)
                                   {
-                                      const uint32_t old_id = current_tree_node.children[j];
-                                      const uint32_t new_id = search_tree_size - old_id - 1;
+                                      const std::uint32_t old_id = current_tree_node.children[j];
+                                      const std::uint32_t new_id = search_tree_size - old_id - 1;
                                       current_tree_node.children[j] = new_id;
                                   }
                               }
@@ -274,12 +253,10 @@ class StaticRTree
         // open tree file
         boost::filesystem::ofstream tree_node_file(tree_node_filename, std::ios::binary);
 
-        uint32_t size_of_tree = m_search_tree.size();
+        std::uint32_t size_of_tree = m_search_tree.size();
         BOOST_ASSERT_MSG(0 < size_of_tree, "tree empty");
-        tree_node_file.write((char *)&size_of_tree, sizeof(uint32_t));
+        tree_node_file.write((char *)&size_of_tree, sizeof(std::uint32_t));
         tree_node_file.write((char *)&m_search_tree[0], sizeof(TreeNode) * size_of_tree);
-        // close tree node file.
-        tree_node_file.close();
     }
 
     explicit StaticRTree(const boost::filesystem::path &node_file,
@@ -292,31 +269,31 @@ class StaticRTree
 
         if (!boost::filesystem::exists(node_file))
         {
-            throw osrm::exception("ram index file does not exist");
+            throw exception("ram index file does not exist");
         }
         if (0 == boost::filesystem::file_size(node_file))
         {
-            throw osrm::exception("ram index file is empty");
+            throw exception("ram index file is empty");
         }
         boost::filesystem::ifstream tree_node_file(node_file, std::ios::binary);
 
-        uint32_t tree_size = 0;
-        tree_node_file.read((char *)&tree_size, sizeof(uint32_t));
+        std::uint32_t tree_size = 0;
+        tree_node_file.read((char *)&tree_size, sizeof(std::uint32_t));
 
         m_search_tree.resize(tree_size);
         if (tree_size > 0)
         {
             tree_node_file.read((char *)&m_search_tree[0], sizeof(TreeNode) * tree_size);
         }
-        tree_node_file.close();
+
         // open leaf node file and store thread specific pointer
         if (!boost::filesystem::exists(leaf_file))
         {
-            throw osrm::exception("mem index file does not exist");
+            throw exception("mem index file does not exist");
         }
         if (0 == boost::filesystem::file_size(leaf_file))
         {
-            throw osrm::exception("mem index file is empty");
+            throw exception("mem index file is empty");
         }
 
         leaves_stream.open(leaf_file, std::ios::binary);
@@ -333,27 +310,94 @@ class StaticRTree
         // open leaf node file and store thread specific pointer
         if (!boost::filesystem::exists(leaf_file))
         {
-            throw osrm::exception("mem index file does not exist");
+            throw exception("mem index file does not exist");
         }
         if (0 == boost::filesystem::file_size(leaf_file))
         {
-            throw osrm::exception("mem index file is empty");
+            throw exception("mem index file is empty");
         }
 
         leaves_stream.open(leaf_file, std::ios::binary);
         leaves_stream.read((char *)&m_element_count, sizeof(uint64_t));
     }
 
+    /* Returns all features inside the bounding box.
+       Rectangle needs to be projected!*/
+    std::vector<EdgeDataT> SearchInBox(const Rectangle &search_rectangle)
+    {
+        const Rectangle projected_rectangle{
+            search_rectangle.min_lon, search_rectangle.max_lon,
+            toFixed(FloatLatitude{coordinate_calculation::mercator::latToY(
+                toFloating(FixedLatitude(search_rectangle.min_lat)))}),
+            toFixed(FloatLatitude{coordinate_calculation::mercator::latToY(
+                toFloating(FixedLatitude(search_rectangle.max_lat)))})};
+        std::vector<EdgeDataT> results;
+
+        std::queue<TreeNode> traversal_queue;
+
+        traversal_queue.push(m_search_tree[0]);
+
+        while (!traversal_queue.empty())
+        {
+            auto const current_tree_node = traversal_queue.front();
+            traversal_queue.pop();
+
+            if (current_tree_node.child_is_on_disk)
+            {
+                LeafNode current_leaf_node;
+                LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
+
+                for (const auto i : irange(0u, current_leaf_node.object_count))
+                {
+                    const auto &current_edge = current_leaf_node.objects[i];
+
+                    // we don't need to project the coordinates here,
+                    // because we use the unprojected rectangle to test against
+                    const Rectangle bbox{std::min((*m_coordinate_list)[current_edge.u].lon,
+                                                  (*m_coordinate_list)[current_edge.v].lon),
+                                         std::max((*m_coordinate_list)[current_edge.u].lon,
+                                                  (*m_coordinate_list)[current_edge.v].lon),
+                                         std::min((*m_coordinate_list)[current_edge.u].lat,
+                                                  (*m_coordinate_list)[current_edge.v].lat),
+                                         std::max((*m_coordinate_list)[current_edge.u].lat,
+                                                  (*m_coordinate_list)[current_edge.v].lat)};
+
+                    // use the _unprojected_ input rectangle here
+                    if (bbox.Intersects(search_rectangle))
+                    {
+                        results.push_back(current_edge);
+                    }
+                }
+            }
+            else
+            {
+                // If it's a tree node, look at all children and add them
+                // to the search queue if their bounding boxes intersect
+                for (std::uint32_t i = 0; i < current_tree_node.child_count; ++i)
+                {
+                    const std::int32_t child_id = current_tree_node.children[i];
+                    const auto &child_tree_node = m_search_tree[child_id];
+                    const auto &child_rectangle = child_tree_node.minimum_bounding_rectangle;
+
+                    if (child_rectangle.Intersects(projected_rectangle))
+                    {
+                        traversal_queue.push(m_search_tree[child_id]);
+                    }
+                }
+            }
+        }
+        return results;
+    }
+
     // Override filter and terminator for the desired behaviour.
-    std::vector<EdgeDataT> Nearest(const FixedPointCoordinate &input_coordinate,
-                                const std::size_t max_results)
+    std::vector<EdgeDataT> Nearest(const Coordinate input_coordinate, const std::size_t max_results)
     {
         return Nearest(input_coordinate,
-                       [](const EdgeDataT &)
+                       [](const CandidateSegment &)
                        {
                            return std::make_pair(true, true);
                        },
-                       [max_results](const std::size_t num_results, const float)
+                       [max_results](const std::size_t num_results, const CandidateSegment &)
                        {
                            return num_results >= max_results;
                        });
@@ -361,28 +405,20 @@ class StaticRTree
 
     // Override filter and terminator for the desired behaviour.
     template <typename FilterT, typename TerminationT>
-    std::vector<EdgeDataT> Nearest(const FixedPointCoordinate &input_coordinate,
-                                const FilterT filter,
-                                const TerminationT terminate)
+    std::vector<EdgeDataT>
+    Nearest(const Coordinate input_coordinate, const FilterT filter, const TerminationT terminate)
     {
         std::vector<EdgeDataT> results;
-        std::pair<double, double> projected_coordinate = {
-            mercator::lat2y(input_coordinate.lat / COORDINATE_PRECISION),
-            input_coordinate.lon / COORDINATE_PRECISION};
+        auto projected_coordinate = coordinate_calculation::mercator::fromWGS84(input_coordinate);
+        Coordinate fixed_projected_coordinate{projected_coordinate};
 
         // initialize queue with root element
         std::priority_queue<QueryCandidate> traversal_queue;
-        traversal_queue.push(QueryCandidate {0.f, m_search_tree[0]});
+        traversal_queue.push(QueryCandidate{0.f, m_search_tree[0]});
 
         while (!traversal_queue.empty())
         {
-            const QueryCandidate current_query_node = traversal_queue.top();
-            if (terminate(results.size(), current_query_node.min_dist))
-            {
-                traversal_queue = std::priority_queue<QueryCandidate>{};
-                break;
-            }
-
+            QueryCandidate current_query_node = traversal_queue.top();
             traversal_queue.pop();
 
             if (current_query_node.node.template is<TreeNode>())
@@ -391,37 +427,34 @@ class StaticRTree
                     current_query_node.node.template get<TreeNode>();
                 if (current_tree_node.child_is_on_disk)
                 {
-                    ExploreLeafNode(current_tree_node.children[0], input_coordinate,
-                                    projected_coordinate, traversal_queue);
+                    ExploreLeafNode(current_tree_node.children[0], projected_coordinate,
+                                    traversal_queue);
                 }
                 else
                 {
-                    ExploreTreeNode(current_tree_node, input_coordinate, traversal_queue);
+                    ExploreTreeNode(current_tree_node, fixed_projected_coordinate, traversal_queue);
                 }
             }
             else
             {
                 // inspecting an actual road segment
-                const auto &current_segment = current_query_node.node.template get<EdgeDataT>();
-
+                auto &current_candidate = current_query_node.node.template get<CandidateSegment>();
+                if (terminate(results.size(), current_candidate))
+                {
+                    traversal_queue = std::priority_queue<QueryCandidate>{};
+                    break;
+                }
 
-                auto use_segment = filter(current_segment);
+                auto use_segment = filter(current_candidate);
                 if (!use_segment.first && !use_segment.second)
                 {
                     continue;
                 }
+                current_candidate.data.forward_segment_id.enabled &= use_segment.first;
+                current_candidate.data.reverse_segment_id.enabled &= use_segment.second;
 
                 // store phantom node in result vector
-                results.push_back(std::move(current_segment));
-
-                if (!use_segment.first)
-                {
-                    results.back().forward_edge_based_node_id = SPECIAL_NODEID;
-                }
-                else if (!use_segment.second)
-                {
-                    results.back().reverse_edge_based_node_id = SPECIAL_NODEID;
-                }
+                results.push_back(std::move(current_candidate.data));
             }
         }
 
@@ -431,44 +464,55 @@ class StaticRTree
   private:
     template <typename QueueT>
     void ExploreLeafNode(const std::uint32_t leaf_id,
-                         const FixedPointCoordinate &input_coordinate,
-                         const std::pair<double, double> &projected_coordinate,
+                         const FloatCoordinate &projected_input_coordinate,
                          QueueT &traversal_queue)
     {
         LeafNode current_leaf_node;
         LoadLeafFromDisk(leaf_id, current_leaf_node);
 
         // current object represents a block on disk
-        for (const auto i : osrm::irange(0u, current_leaf_node.object_count))
+        for (const auto i : irange(0u, current_leaf_node.object_count))
         {
             auto &current_edge = current_leaf_node.objects[i];
-            const float current_perpendicular_distance =
-                coordinate_calculation::perpendicular_distance_from_projected_coordinate(
-                    m_coordinate_list->at(current_edge.u), m_coordinate_list->at(current_edge.v),
-                    input_coordinate, projected_coordinate);
+            auto projected_u =
+                coordinate_calculation::mercator::fromWGS84((*m_coordinate_list)[current_edge.u]);
+            auto projected_v =
+                coordinate_calculation::mercator::fromWGS84((*m_coordinate_list)[current_edge.v]);
+
+            FloatCoordinate projected_nearest;
+            std::tie(std::ignore, projected_nearest) =
+                coordinate_calculation::projectPointOnSegment(projected_u, projected_v,
+                                                              projected_input_coordinate);
+
+            auto squared_distance = coordinate_calculation::squaredEuclideanDistance(
+                projected_input_coordinate, projected_nearest);
             // distance must be non-negative
-            BOOST_ASSERT(0.f <= current_perpendicular_distance);
+            BOOST_ASSERT(0. <= squared_distance);
 
-            traversal_queue.push(QueryCandidate {current_perpendicular_distance, std::move(current_edge)});
+            traversal_queue.push(
+                QueryCandidate{squared_distance, CandidateSegment{Coordinate{projected_nearest},
+                                                                  std::move(current_edge)}});
         }
     }
 
     template <class QueueT>
     void ExploreTreeNode(const TreeNode &parent,
-                         const FixedPointCoordinate &input_coordinate,
+                         const Coordinate fixed_projected_input_coordinate,
                          QueueT &traversal_queue)
     {
-        for (uint32_t i = 0; i < parent.child_count; ++i)
+        for (std::uint32_t i = 0; i < parent.child_count; ++i)
         {
-            const int32_t child_id = parent.children[i];
+            const std::int32_t child_id = parent.children[i];
             const auto &child_tree_node = m_search_tree[child_id];
             const auto &child_rectangle = child_tree_node.minimum_bounding_rectangle;
-            const float lower_bound_to_element = child_rectangle.GetMinDist(input_coordinate);
-            traversal_queue.push(QueryCandidate {lower_bound_to_element, m_search_tree[child_id]});
+            const auto squared_lower_bound_to_element =
+                child_rectangle.GetMinSquaredDist(fixed_projected_input_coordinate);
+            traversal_queue.push(
+                QueryCandidate{squared_lower_bound_to_element, m_search_tree[child_id]});
         }
     }
 
-    inline void LoadLeafFromDisk(const uint32_t leaf_id, LeafNode &result_node)
+    inline void LoadLeafFromDisk(const std::uint32_t leaf_id, LeafNode &result_node)
     {
         if (!leaves_stream.is_open())
         {
@@ -476,7 +520,7 @@ class StaticRTree
         }
         if (!leaves_stream.good())
         {
-          throw osrm::exception("Could not read from leaf file.");
+            throw exception("Could not read from leaf file.");
         }
         const uint64_t seek_pos = sizeof(uint64_t) + leaf_id * sizeof(LeafNode);
         leaves_stream.seekg(seek_pos);
@@ -488,29 +532,42 @@ class StaticRTree
     template <typename CoordinateT>
     void InitializeMBRectangle(Rectangle &rectangle,
                                const std::array<EdgeDataT, LEAF_NODE_SIZE> &objects,
-                               const uint32_t element_count,
+                               const std::uint32_t element_count,
                                const std::vector<CoordinateT> &coordinate_list)
     {
-        for (uint32_t i = 0; i < element_count; ++i)
+        for (std::uint32_t i = 0; i < element_count; ++i)
         {
+            BOOST_ASSERT(objects[i].u < coordinate_list.size());
+            BOOST_ASSERT(objects[i].v < coordinate_list.size());
+
+            Coordinate projected_u{coordinate_calculation::mercator::fromWGS84(
+                Coordinate{coordinate_list[objects[i].u]})};
+            Coordinate projected_v{coordinate_calculation::mercator::fromWGS84(
+                Coordinate{coordinate_list[objects[i].v]})};
+
+            BOOST_ASSERT(toFloating(projected_u.lon) <= FloatLongitude(180.));
+            BOOST_ASSERT(toFloating(projected_u.lon) >= FloatLongitude(-180.));
+            BOOST_ASSERT(toFloating(projected_u.lat) <= FloatLatitude(180.));
+            BOOST_ASSERT(toFloating(projected_u.lat) >= FloatLatitude(-180.));
+            BOOST_ASSERT(toFloating(projected_v.lon) <= FloatLongitude(180.));
+            BOOST_ASSERT(toFloating(projected_v.lon) >= FloatLongitude(-180.));
+            BOOST_ASSERT(toFloating(projected_v.lat) <= FloatLatitude(180.));
+            BOOST_ASSERT(toFloating(projected_v.lat) >= FloatLatitude(-180.));
+
             rectangle.min_lon =
-                std::min(rectangle.min_lon, std::min(coordinate_list.at(objects[i].u).lon,
-                                                     coordinate_list.at(objects[i].v).lon));
+                std::min(rectangle.min_lon, std::min(projected_u.lon, projected_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));
+                std::max(rectangle.max_lon, std::max(projected_u.lon, projected_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));
+                std::min(rectangle.min_lat, std::min(projected_u.lat, projected_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));
+                std::max(rectangle.max_lat, std::max(projected_u.lat, projected_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());
+        BOOST_ASSERT(rectangle.min_lon != FixedLongitude(std::numeric_limits<int>::min()));
+        BOOST_ASSERT(rectangle.min_lat != FixedLatitude(std::numeric_limits<int>::min()));
+        BOOST_ASSERT(rectangle.max_lon != FixedLongitude(std::numeric_limits<int>::min()));
+        BOOST_ASSERT(rectangle.max_lat != FixedLatitude(std::numeric_limits<int>::min()));
     }
 };
 
@@ -518,4 +575,7 @@ 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 // STATIC_RTREE_HPP
diff --git a/include/util/std_hash.hpp b/include/util/std_hash.hpp
new file mode 100644
index 0000000..b456ab1
--- /dev/null
+++ b/include/util/std_hash.hpp
@@ -0,0 +1,41 @@
+#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.
+
+template <typename T> void hash_combine(std::size_t &seed, const T &val)
+{
+    seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+}
+
+template <typename T> void hash_val(std::size_t &seed, const T &val) { hash_combine(seed, val); }
+
+template <typename T, typename... Types>
+void hash_val(std::size_t &seed, const T &val, const Types &... args)
+{
+    hash_combine(seed, val);
+    hash_val(seed, args...);
+}
+
+template <typename... Types> std::size_t hash_val(const Types &... args)
+{
+    std::size_t seed = 0;
+    hash_val(seed, args...);
+    return seed;
+}
+
+namespace std
+{
+template <typename T1, typename T2> struct hash<std::pair<T1, T2>>
+{
+    size_t operator()(const std::pair<T1, T2> &pair) const
+    {
+        return hash_val(pair.first, pair.second);
+    }
+};
+}
+
+#endif // STD_HASH_HPP
diff --git a/util/string_util.hpp b/include/util/string_util.hpp
similarity index 68%
rename from util/string_util.hpp
rename to include/util/string_util.hpp
index 8075e65..41c5f09 100644
--- a/util/string_util.hpp
+++ b/include/util/string_util.hpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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
 
@@ -34,10 +7,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <string>
 #include <vector>
 
+namespace osrm
+{
+namespace util
+{
+
 // 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)
+template <int length, int precision> char *printInt(char *buffer, int value)
 {
     static_assert(length > 0, "length must be positive");
     static_assert(precision > 0, "precision must be positive");
@@ -148,5 +126,7 @@ inline std::size_t URIDecode(const std::string &input, std::string &output)
 }
 
 inline std::size_t URIDecodeInPlace(std::string &URI) { return URIDecode(URI, URI); }
+}
+}
 
 #endif // STRING_UTIL_HPP
diff --git a/include/util/strong_typedef.hpp b/include/util/strong_typedef.hpp
new file mode 100644
index 0000000..eabcaa3
--- /dev/null
+++ b/include/util/strong_typedef.hpp
@@ -0,0 +1,84 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+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 STRONG_TYPEDEF_HPP
+#define STRONG_TYPEDEF_HPP
+
+#include <iostream>
+#include <type_traits>
+#include <functional>
+
+namespace osrm
+{
+
+/* Creates strongly typed wrappers around scalar types.
+ * Useful for stopping accidental assignment of lats to lons,
+ * etc.  Also clarifies what this random "int" value is
+ * being used for.
+ */
+#define OSRM_STRONG_TYPEDEF(From, To)                                                              \
+    class To final                                                                                 \
+    {                                                                                              \
+        static_assert(std::is_arithmetic<From>(), "");                                             \
+        From x;                                                                                    \
+        friend std::ostream &operator<<(std::ostream &stream, const To &inst);                     \
+                                                                                                   \
+      public:                                                                                      \
+        To() = default;                                                                            \
+        explicit To(const From x_) : x(x_) {}                                                      \
+        explicit operator From &() { return x; }                                                   \
+        explicit operator From() const { return x; }                                               \
+        To operator+(const To rhs_) const { return To(x + static_cast<const From>(rhs_)); }        \
+        To operator-(const To rhs_) const { return To(x - static_cast<const From>(rhs_)); }        \
+        To operator*(const To rhs_) const { return To(x * static_cast<const From>(rhs_)); }        \
+        To operator/(const To rhs_) const { return To(x / static_cast<const From>(rhs_)); }        \
+        bool operator<(const To z_) const { return x < static_cast<const From>(z_); }              \
+        bool operator>(const To z_) const { return x > static_cast<const From>(z_); }              \
+        bool operator<=(const To z_) const { return x <= static_cast<const From>(z_); }            \
+        bool operator>=(const To z_) const { return x >= static_cast<const From>(z_); }            \
+        bool operator==(const To z_) const { return x == static_cast<const From>(z_); }            \
+        bool operator!=(const To z_) const { return x != static_cast<const From>(z_); }            \
+    };                                                                                             \
+    inline std::ostream &operator<<(std::ostream &stream, const To &inst)                          \
+    {                                                                                              \
+        return stream << inst.x;                                                                   \
+    }
+
+#define OSRM_STRONG_TYPEDEF_HASHABLE(From, To)                                                     \
+    namespace std                                                                                  \
+    {                                                                                              \
+    template <> struct hash<To>                                                                    \
+    {                                                                                              \
+        std::size_t operator()(const To &k) const                                                  \
+        {                                                                                          \
+            return std::hash<From>()(static_cast<const From>(k));                                  \
+        }                                                                                          \
+    };                                                                                             \
+    }
+}
+
+#endif // OSRM_STRONG_TYPEDEF_HPP
diff --git a/util/timing_util.hpp b/include/util/timing_util.hpp
similarity index 68%
rename from util/timing_util.hpp
rename to include/util/timing_util.hpp
index c0c59c8..537f0dc 100644
--- a/util/timing_util.hpp
+++ b/include/util/timing_util.hpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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
 
@@ -34,6 +7,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <mutex>
 #include <unordered_map>
 
+namespace osrm
+{
+namespace util
+{
+
 struct GlobalTimer
 {
     GlobalTimer() : time(0) {}
@@ -86,5 +64,7 @@ class GlobalTimerFactory
      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/trigonometry_table.hpp b/include/util/trigonometry_table.hpp
similarity index 95%
rename from util/trigonometry_table.hpp
rename to include/util/trigonometry_table.hpp
index 234a94e..fe1d316 100644
--- a/util/trigonometry_table.hpp
+++ b/include/util/trigonometry_table.hpp
@@ -1,38 +1,18 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 TRIGONOMETRY_TABLE_HPP
 #define TRIGONOMETRY_TABLE_HPP
 
-#include "../typedefs.h"
+#include "util/typedefs.hpp"
 #include <cmath>
 
 #include <limits>
 
+#include <boost/math/constants/constants.hpp>
+
+namespace osrm
+{
+namespace util
+{
+
 constexpr unsigned short atan_table[4096] = {
     0x0000, 0x0014, 0x0028, 0x003d, 0x0051, 0x0065, 0x007a, 0x008e, 0x00a3, 0x00b7, 0x00cb, 0x00e0,
     0x00f4, 0x0108, 0x011d, 0x0131, 0x0146, 0x015a, 0x016e, 0x0183, 0x0197, 0x01ab, 0x01c0, 0x01d4,
@@ -378,19 +358,27 @@ constexpr unsigned short atan_table[4096] = {
     0xffe0, 0xffea, 0xfff4, 0xffff};
 
 // max value is pi/4
-constexpr double SCALING_FACTOR = 4. / M_PI * 0xFFFF;
+#ifdef _MSC_VER //TODO: remove as soon as boost allows C++14 features with Visual Studio
+const constexpr double SCALING_FACTOR = 4. / M_PI * 0xFFFF;
+#else
+const constexpr double SCALING_FACTOR = 4. / boost::math::constants::pi<double>() * 0xFFFF;
+#endif
+
 
 inline double atan2_lookup(double y, double x)
 {
+
+    using namespace boost::math::constants;
+
     if (std::abs(x) < std::numeric_limits<double>::epsilon())
     {
         if (y >= 0.)
         {
-            return M_PI / 2.;
+            return half_pi<double>();
         }
         else
         {
-            return -M_PI / 2.;
+            return -half_pi<double>();
         }
     }
 
@@ -421,28 +409,30 @@ inline double atan2_lookup(double y, double x)
     case 0:
         break;
     case 1:
-        angle = M_PI - angle;
+        angle = pi<double>() - angle;
         break;
     case 2:
         angle = -angle;
         break;
     case 3:
-        angle = -M_PI + angle;
+        angle = -pi<double>() + angle;
         break;
     case 4:
-        angle = M_PI / 2.0 - angle;
+        angle = half_pi<double>() - angle;
         break;
     case 5:
-        angle = M_PI / 2.0 + angle;
+        angle = half_pi<double>() + angle;
         break;
     case 6:
-        angle = -M_PI / 2.0 + angle;
+        angle = -half_pi<double>() + angle;
         break;
     case 7:
-        angle = -M_PI / 2.0 - angle;
+        angle = -half_pi<double>() - angle;
         break;
     }
     return angle;
 }
+}
+}
 
 #endif // TRIGONOMETRY_TABLE_HPP
diff --git a/typedefs.h b/include/util/typedefs.hpp
similarity index 80%
rename from typedefs.h
rename to include/util/typedefs.hpp
index dc77f39..b3404bc 100644
--- a/typedefs.h
+++ b/include/util/typedefs.hpp
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2016, Project OSRM contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
@@ -28,21 +28,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef TYPEDEFS_H
 #define TYPEDEFS_H
 
+#include "util/strong_typedef.hpp"
+
+#include <boost/assert.hpp>
+
 #include <limits>
-#include <osrm/strong_typedef.hpp>
 #include <cstddef>
 
-// 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
-#endif
-
 // OpenStreetMap node ids are higher than 2^32
 OSRM_STRONG_TYPEDEF(uint64_t, OSMNodeID)
+OSRM_STRONG_TYPEDEF_HASHABLE(uint64_t, OSMNodeID)
+
 OSRM_STRONG_TYPEDEF(uint32_t, OSMWayID)
+OSRM_STRONG_TYPEDEF_HASHABLE(uint32_t, OSMWayID)
 
 static const OSMNodeID SPECIAL_OSM_NODEID = OSMNodeID(std::numeric_limits<std::uint64_t>::max());
 static const OSMWayID SPECIAL_OSM_WAYID = OSMWayID(std::numeric_limits<std::uint32_t>::max());
@@ -60,9 +58,26 @@ using EdgeID = unsigned int;
 using EdgeWeight = int;
 
 static const NodeID SPECIAL_NODEID = std::numeric_limits<unsigned>::max();
+static const NodeID SPECIAL_SEGMENTID = std::numeric_limits<int>::max();
 static const EdgeID SPECIAL_EDGEID = std::numeric_limits<unsigned>::max();
 static const unsigned INVALID_NAMEID = std::numeric_limits<unsigned>::max();
 static const unsigned INVALID_COMPONENTID = 0;
 static const EdgeWeight INVALID_EDGE_WEIGHT = std::numeric_limits<int>::max();
 
+struct SegmentID
+{
+    SegmentID(const NodeID id_, const bool enabled_) : id{id_}, enabled{enabled_}
+    {
+        BOOST_ASSERT(!enabled || id != SPECIAL_SEGMENTID);
+    }
+
+    NodeID id : 31;
+    bool enabled : 1;
+};
+
+// bit-fields are broken on Windows
+#ifndef _MSC_VER
+static_assert(sizeof(SegmentID) == 4, "SegmentID needs to be 4 bytes big");
+#endif
+
 #endif /* TYPEDEFS_H */
diff --git a/include/util/version.hpp.in b/include/util/version.hpp.in
new file mode 100644
index 0000000..cb97dca
--- /dev/null
+++ b/include/util/version.hpp.in
@@ -0,0 +1,10 @@
+#ifndef VERSION_HPP
+#define VERSION_HPP
+
+#define OSRM_VERSION_MAJOR "@OSRM_VERSION_MAJOR@"
+#define OSRM_VERSION_MINOR "@OSRM_VERSION_MINOR@"
+#define OSRM_VERSION_PATCH "@OSRM_VERSION_PATCH@"
+
+#define OSRM_VERSION "v" OSRM_VERSION_MAJOR "." OSRM_VERSION_MINOR "." OSRM_VERSION_PATCH
+
+#endif // VERSION_HPP
diff --git a/include/util/viewport.hpp b/include/util/viewport.hpp
new file mode 100644
index 0000000..fd0ac73
--- /dev/null
+++ b/include/util/viewport.hpp
@@ -0,0 +1,51 @@
+#ifndef UTIL_VIEWPORT_HPP
+#define UTIL_VIEWPORT_HPP
+
+#include "util/coordinate.hpp"
+#include "util/coordinate_calculation.hpp"
+
+#include <boost/assert.hpp>
+
+#include <cmath>
+#include <tuple>
+
+// Port of https://github.com/mapbox/geo-viewport
+
+namespace osrm
+{
+namespace util
+{
+namespace viewport
+{
+
+namespace detail
+{
+static constexpr unsigned MAX_ZOOM = 18;
+static constexpr unsigned MIN_ZOOM = 1;
+// this is an upper bound to current display sizes
+static constexpr double VIEWPORT_WIDTH = 8 * coordinate_calculation::mercator::TILE_SIZE;
+static constexpr double VIEWPORT_HEIGHT = 5 * coordinate_calculation::mercator::TILE_SIZE;
+static double INV_LOG_2 = 1. / std::log(2);
+}
+
+unsigned getFittedZoom(util::Coordinate south_west, util::Coordinate north_east)
+{
+    const auto min_x = coordinate_calculation::mercator::degreeToPixel(toFloating(south_west.lon), detail::MAX_ZOOM);
+    const auto max_y = coordinate_calculation::mercator::degreeToPixel(toFloating(south_west.lat), detail::MAX_ZOOM);
+    const auto max_x = coordinate_calculation::mercator::degreeToPixel(toFloating(north_east.lon), detail::MAX_ZOOM);
+    const auto min_y = coordinate_calculation::mercator::degreeToPixel(toFloating(north_east.lat), detail::MAX_ZOOM);
+    const double width_ratio = (max_x - min_x) / detail::VIEWPORT_WIDTH;
+    const double height_ratio = (max_y - min_y) / detail::VIEWPORT_HEIGHT;
+    const auto zoom = detail::MAX_ZOOM - std::max(std::log(width_ratio), std::log(height_ratio)) * detail::INV_LOG_2;
+
+    if (std::isfinite(zoom))
+        return std::max<unsigned>(detail::MIN_ZOOM, zoom);
+    else
+      return detail::MIN_ZOOM;
+}
+
+}
+}
+}
+
+#endif
diff --git a/include/util/xor_fast_hash.hpp b/include/util/xor_fast_hash.hpp
new file mode 100644
index 0000000..6ad79d6
--- /dev/null
+++ b/include/util/xor_fast_hash.hpp
@@ -0,0 +1,71 @@
+#ifndef XOR_FAST_HASH_HPP
+#define XOR_FAST_HASH_HPP
+
+#include <boost/assert.hpp>
+
+#include <array>
+#include <algorithm>
+#include <iterator>
+#include <numeric>
+#include <random>
+#include <vector>
+
+#include <cstdint>
+
+namespace osrm
+{
+namespace util
+{
+
+/*
+    This is an implementation of Tabulation hashing, which has suprising properties like
+   universality.
+    The space requirement is 2*2^16 = 256 kb of memory, which fits into L2 cache.
+    Evaluation boils down to 10 or less assembly instruction on any recent X86 CPU:
+
+    1: movq    table2(%rip), %rdx
+    2: movl    %edi, %eax
+    3: movzwl  %di, %edi
+    4: shrl    $16, %eax
+    5: movzwl  %ax, %eax
+    6: movzbl  (%rdx,%rax), %eax
+    7: movq    table1(%rip), %rdx
+    8: xorb    (%rdx,%rdi), %al
+    9: movzbl  %al, %eax
+    10: ret
+
+*/
+template <std::size_t MaxNumElements = (1u << 16u)> class XORFastHash
+{
+    static_assert(MaxNumElements <= (1u << 16u), "only 65536 elements indexable with uint16_t");
+
+    std::array<std::uint16_t, MaxNumElements> table1;
+    std::array<std::uint16_t, MaxNumElements> table2;
+
+  public:
+    XORFastHash()
+    {
+        std::mt19937 generator; // impl. defined but deterministic default seed
+
+        std::iota(begin(table1), end(table1), 0u);
+        std::shuffle(begin(table1), end(table1), generator);
+
+        std::iota(begin(table2), end(table2), 0u);
+        std::shuffle(begin(table2), end(table2), generator);
+    }
+
+    inline std::uint16_t operator()(const std::uint32_t originalValue) const
+    {
+        std::uint16_t lsb = originalValue & 0xffffu;
+        std::uint16_t msb = originalValue >> 16u;
+
+        BOOST_ASSERT(lsb < table1.size());
+        BOOST_ASSERT(msb < table2.size());
+
+        return table1[lsb] ^ table2[msb];
+    }
+};
+}
+}
+
+#endif // XOR_FAST_HASH_HPP
diff --git a/include/util/xor_fast_hash_storage.hpp b/include/util/xor_fast_hash_storage.hpp
new file mode 100644
index 0000000..6d2d76b
--- /dev/null
+++ b/include/util/xor_fast_hash_storage.hpp
@@ -0,0 +1,84 @@
+#ifndef XOR_FAST_HASH_STORAGE_HPP
+#define XOR_FAST_HASH_STORAGE_HPP
+
+#include "util/xor_fast_hash.hpp"
+
+#include <limits>
+#include <vector>
+
+namespace osrm
+{
+namespace util
+{
+
+template <typename NodeID, typename Key, std::size_t MaxNumElements = (1u << 16u)>
+class XORFastHashStorage
+{
+  public:
+    struct HashCell
+    {
+        unsigned time;
+        NodeID id;
+        Key key;
+        HashCell()
+            : time(std::numeric_limits<unsigned>::max()), id(std::numeric_limits<unsigned>::max()),
+              key(std::numeric_limits<unsigned>::max())
+        {
+        }
+
+        HashCell(const HashCell &other) : time(other.key), id(other.id), key(other.time) {}
+        operator Key() const { return key; }
+        void operator=(const Key key_to_insert) { key = key_to_insert; }
+    };
+
+    explicit XORFastHashStorage(size_t) : positions(MaxNumElements), current_timestamp{0u} {}
+
+    HashCell &operator[](const NodeID node)
+    {
+        std::uint16_t position = fast_hasher(node);
+        while ((positions[position].time == current_timestamp) && (positions[position].id != node))
+        {
+            ++position %= MaxNumElements;
+        }
+
+        positions[position].time = current_timestamp;
+        positions[position].id = node;
+
+        BOOST_ASSERT(position < positions.size());
+
+        return positions[position];
+    }
+
+    // peek into table, get key for node, think of it as a read-only operator[]
+    Key peek_index(const NodeID node) const
+    {
+        std::uint16_t position = fast_hasher(node);
+        while ((positions[position].time == current_timestamp) && (positions[position].id != node))
+        {
+            ++position %= MaxNumElements;
+        }
+
+        BOOST_ASSERT(position < positions.size());
+
+        return positions[position].key;
+    }
+
+    void Clear()
+    {
+        ++current_timestamp;
+        if (std::numeric_limits<unsigned>::max() == current_timestamp)
+        {
+            positions.clear();
+            positions.resize(MaxNumElements);
+        }
+    }
+
+  private:
+    std::vector<HashCell> positions;
+    XORFastHash<MaxNumElements> fast_hasher;
+    unsigned current_timestamp;
+};
+}
+}
+
+#endif // XOR_FAST_HASH_STORAGE_HPP
diff --git a/library/osrm_impl.cpp b/library/osrm_impl.cpp
deleted file mode 100644
index 069ef95..0000000
--- a/library/osrm_impl.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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.
-
-*/
-
-namespace boost
-{
-namespace interprocess
-{
-class named_mutex;
-}
-}
-
-#include "osrm_impl.hpp"
-
-#include "../plugins/distance_table.hpp"
-#include "../plugins/hello_world.hpp"
-#include "../plugins/nearest.hpp"
-#include "../plugins/timestamp.hpp"
-#include "../plugins/trip.hpp"
-#include "../plugins/viaroute.hpp"
-#include "../plugins/match.hpp"
-#include "../server/data_structures/datafacade_base.hpp"
-#include "../server/data_structures/internal_datafacade.hpp"
-#include "../server/data_structures/shared_barriers.hpp"
-#include "../server/data_structures/shared_datafacade.hpp"
-#include "../util/make_unique.hpp"
-#include "../util/routed_options.hpp"
-#include "../util/simple_logger.hpp"
-
-#include <boost/assert.hpp>
-#include <boost/interprocess/sync/named_condition.hpp>
-#include <boost/interprocess/sync/scoped_lock.hpp>
-
-#include <osrm/route_parameters.hpp>
-#include <osrm/libosrm_config.hpp>
-#include <osrm/osrm.hpp>
-
-#include <algorithm>
-#include <fstream>
-#include <utility>
-#include <vector>
-
-OSRM::OSRM_impl::OSRM_impl(LibOSRMConfig& lib_config)
-{
-    if (lib_config.use_shared_memory)
-    {
-        barrier = osrm::make_unique<SharedBarriers>();
-        query_data_facade = new SharedDataFacade<QueryEdge::EdgeData>();
-    }
-    else
-    {
-        // populate base path
-        populate_base_path(lib_config.server_paths);
-        query_data_facade = new InternalDataFacade<QueryEdge::EdgeData>(lib_config.server_paths);
-    }
-
-    // The following plugins handle all requests.
-    RegisterPlugin(new DistanceTablePlugin<BaseDataFacade<QueryEdge::EdgeData>>(
-        query_data_facade, lib_config.max_locations_distance_table));
-    RegisterPlugin(new HelloWorldPlugin());
-    RegisterPlugin(new NearestPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
-    RegisterPlugin(new MapMatchingPlugin<BaseDataFacade<QueryEdge::EdgeData>>(
-        query_data_facade, lib_config.max_locations_map_matching));
-    RegisterPlugin(new TimestampPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
-    RegisterPlugin(new ViaRoutePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade,
-                lib_config.max_locations_viaroute));
-    RegisterPlugin(new RoundTripPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade,
-                lib_config.max_locations_trip));
-}
-
-void OSRM::OSRM_impl::RegisterPlugin(BasePlugin *raw_plugin_ptr)
-{
-    std::unique_ptr<BasePlugin> plugin_ptr(raw_plugin_ptr);
-    SimpleLogger().Write() << "loaded plugin: " << plugin_ptr->GetDescriptor();
-    plugin_map[plugin_ptr->GetDescriptor()] = std::move(plugin_ptr);
-}
-
-int OSRM::OSRM_impl::RunQuery(const RouteParameters &route_parameters, osrm::json::Object &json_result)
-{
-    const auto &plugin_iterator = plugin_map.find(route_parameters.service);
-
-    if (plugin_map.end() == plugin_iterator)
-    {
-        json_result.values["status_message"] = "Service not found";
-        return 400;
-    }
-
-    increase_concurrent_query_count();
-    BasePlugin::Status return_code;
-    if (barrier) {
-        // Get a shared data lock so that other threads won't update
-        // things while the query is running
-        boost::shared_lock<boost::shared_mutex> data_lock{
-            (static_cast<SharedDataFacade<QueryEdge::EdgeData> *>(query_data_facade))->data_mutex};
-        return_code = plugin_iterator->second->HandleRequest(route_parameters, json_result);
-    } else {
-        return_code = plugin_iterator->second->HandleRequest(route_parameters, json_result);
-    }
-    decrease_concurrent_query_count();
-    return static_cast<int>(return_code);
-}
-
-// decrease number of concurrent queries
-void OSRM::OSRM_impl::decrease_concurrent_query_count()
-{
-    if (!barrier)
-    {
-        return;
-    }
-    // lock query
-    boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
-        barrier->query_mutex);
-
-    // decrement query count
-    --(barrier->number_of_queries);
-    BOOST_ASSERT_MSG(0 <= barrier->number_of_queries, "invalid number of queries");
-
-    // notify all processes that were waiting for this condition
-    if (0 == barrier->number_of_queries)
-    {
-        barrier->no_running_queries_condition.notify_all();
-    }
-}
-
-// increase number of concurrent queries
-void OSRM::OSRM_impl::increase_concurrent_query_count()
-{
-    if (!barrier)
-    {
-        return;
-    }
-
-    // lock update pending
-    boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock(
-        barrier->pending_update_mutex);
-
-    // lock query
-    boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
-        barrier->query_mutex);
-
-    // unlock update pending
-    pending_lock.unlock();
-
-    // increment query count
-    ++(barrier->number_of_queries);
-
-    (static_cast<SharedDataFacade<QueryEdge::EdgeData> *>(query_data_facade))
-        ->CheckAndReloadFacade();
-}
-
-// proxy code for compilation firewall
-OSRM::OSRM(LibOSRMConfig &lib_config) : OSRM_pimpl_(osrm::make_unique<OSRM_impl>(lib_config)) {}
-
-// needed because unique_ptr needs the size of OSRM_impl for delete
-OSRM::~OSRM() {}
-
-int OSRM::RunQuery(const RouteParameters &route_parameters, osrm::json::Object &json_result)
-{
-    return OSRM_pimpl_->RunQuery(route_parameters, json_result);
-}
diff --git a/library/osrm_impl.hpp b/library/osrm_impl.hpp
deleted file mode 100644
index c223449..0000000
--- a/library/osrm_impl.hpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 OSRM_IMPL_HPP
-#define OSRM_IMPL_HPP
-
-class BasePlugin;
-struct RouteParameters;
-
-#include "../data_structures/query_edge.hpp"
-
-#include <osrm/json_container.hpp>
-#include <osrm/libosrm_config.hpp>
-#include <osrm/osrm.hpp>
-
-#include <memory>
-#include <unordered_map>
-#include <string>
-
-struct SharedBarriers;
-template <class EdgeDataT> class BaseDataFacade;
-
-class OSRM::OSRM_impl final
-{
-  private:
-    using PluginMap = std::unordered_map<std::string, std::unique_ptr<BasePlugin>>;
-
-  public:
-    OSRM_impl(LibOSRMConfig &lib_config);
-    OSRM_impl(const OSRM_impl &) = delete;
-    int RunQuery(const RouteParameters &route_parameters, osrm::json::Object &json_result);
-
-  private:
-    void RegisterPlugin(BasePlugin *plugin);
-    PluginMap plugin_map;
-    // 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;
-
-    // decrease number of concurrent queries
-    void decrease_concurrent_query_count();
-    // increase number of concurrent queries
-    void increase_concurrent_query_count();
-};
-
-#endif // OSRM_IMPL_HPP
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..46c0bb7
--- /dev/null
+++ b/package.json
@@ -0,0 +1,39 @@
+{
+  "name": "osrm-backend-test-suite",
+  "version": "0.0.0",
+  "private": true,
+  "description": "The Open Source Routing Machine is a high performance routing engine written in C++11 designed to run on OpenStreetMap data.",
+  "dependencies": {
+    "cucumber": "^0.9.4",
+    "d3-queue": "^2.0.3",
+    "node-timeout": "0.0.4",
+    "request": "^2.69.0",
+    "xmlbuilder": "^4.2.1",
+    "chalk": "^1.1.3"
+  },
+  "bin": {
+    "cucumber": "./node_modules/cucumber/bin/cucumber.js"
+  },
+  "scripts": {
+    "lint": "eslint -c ./.eslintrc features/step_definitions/ features/support/",
+    "test": "npm run lint && ./node_modules/cucumber/bin/cucumber.js features/ -p verify",
+    "clean-test": "rm -rf test/cache",
+    "cucumber": "./node_modules/cucumber/bin/cucumber.js"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/Project-OSRM/osrm-backend.git"
+  },
+  "author": "",
+  "license": "ISC",
+  "bugs": {
+    "url": "https://github.com/Project-OSRM/osrm-backend/issues"
+  },
+  "homepage": "https://github.com/Project-OSRM/osrm-backend",
+  "engines": {
+    "node": ">=4.0.0"
+  },
+  "devDependencies": {
+    "eslint": "^2.4.0"
+  }
+}
diff --git a/plugins/distance_table.hpp b/plugins/distance_table.hpp
deleted file mode 100644
index c4ed250..0000000
--- a/plugins/distance_table.hpp
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 DISTANCE_TABLE_HPP
-#define DISTANCE_TABLE_HPP
-
-#include "plugin_base.hpp"
-
-#include "../algorithms/object_encoder.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 <osrm/json_container.hpp>
-
-#include <cstdlib>
-
-#include <algorithm>
-#include <memory>
-#include <unordered_map>
-#include <string>
-#include <vector>
-
-template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
-{
-  private:
-    std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
-    int max_locations_distance_table;
-
-  public:
-    explicit DistanceTablePlugin(DataFacadeT *facade, const int max_locations_distance_table)
-        : max_locations_distance_table(max_locations_distance_table), descriptor_string("table"),
-          facade(facade)
-    {
-        search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
-    }
-
-    virtual ~DistanceTablePlugin() {}
-
-    const std::string GetDescriptor() const override final { return descriptor_string; }
-
-    Status HandleRequest(const RouteParameters &route_parameters,
-                      osrm::json::Object &json_result) override final
-    {
-        if (!check_all_coordinates(route_parameters.coordinates))
-        {
-            json_result.values["status_message"] = "Coordinates are invalid";
-            return Status::Error;
-        }
-
-        const auto &input_bearings = route_parameters.bearings;
-        if (input_bearings.size() > 0 &&
-            route_parameters.coordinates.size() != input_bearings.size())
-        {
-            json_result.values["status_message"] =
-                "Number of bearings does not match number of coordinates";
-            return Status::Error;
-        }
-
-        auto number_of_sources =
-            std::count_if(route_parameters.is_source.begin(), route_parameters.is_source.end(),
-                          [](const bool is_source)
-                          {
-                              return is_source;
-                          });
-        auto number_of_destination =
-            std::count_if(route_parameters.is_destination.begin(),
-                          route_parameters.is_destination.end(), [](const bool is_destination)
-                          {
-                              return is_destination;
-                          });
-
-        if (max_locations_distance_table > 0 &&
-            (number_of_sources * number_of_destination >
-             max_locations_distance_table * max_locations_distance_table))
-        {
-            json_result.values["status_message"] =
-                "Number of entries " + std::to_string(number_of_sources * number_of_destination) +
-                " is higher than current maximum (" +
-                std::to_string(max_locations_distance_table * max_locations_distance_table) + ")";
-            return Status::Error;
-        }
-
-        const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
-
-        std::vector<PhantomNodePair> phantom_node_source_vector(number_of_sources);
-        std::vector<PhantomNodePair> phantom_node_target_vector(number_of_destination);
-        auto phantom_node_source_out_iter = phantom_node_source_vector.begin();
-        auto phantom_node_target_out_iter = phantom_node_target_vector.begin();
-        for (const auto i : osrm::irange<std::size_t>(0u, route_parameters.coordinates.size()))
-        {
-            if (checksum_OK && i < route_parameters.hints.size() &&
-                !route_parameters.hints[i].empty())
-            {
-                PhantomNode current_phantom_node;
-                ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
-                if (current_phantom_node.is_valid(facade->GetNumberOfNodes()))
-                {
-                    if (route_parameters.is_source[i])
-                    {
-                        *phantom_node_source_out_iter =
-                            std::make_pair(current_phantom_node, current_phantom_node);
-                        if (route_parameters.is_destination[i])
-                        {
-                            *phantom_node_target_out_iter = *phantom_node_source_out_iter;
-                            phantom_node_target_out_iter++;
-                        }
-                        phantom_node_source_out_iter++;
-                    }
-                    else
-                    {
-                        BOOST_ASSERT(route_parameters.is_destination[i] &&
-                                     !route_parameters.is_source[i]);
-                        *phantom_node_target_out_iter =
-                            std::make_pair(current_phantom_node, current_phantom_node);
-                        phantom_node_target_out_iter++;
-                    }
-                    continue;
-                }
-            }
-            const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
-            const int range = input_bearings.size() > 0
-                                  ? (input_bearings[i].second ? *input_bearings[i].second : 10)
-                                  : 180;
-            if (route_parameters.is_source[i])
-            {
-                *phantom_node_source_out_iter =
-                    facade->NearestPhantomNodeWithAlternativeFromBigComponent(
-                        route_parameters.coordinates[i], bearing, range);
-                // we didn't found a fitting node, return error
-                if (!phantom_node_source_out_iter->first.is_valid(facade->GetNumberOfNodes()))
-                {
-                    json_result.values["status_message"] =
-                        std::string("Could not find a matching segment for coordinate ") + std::to_string(i);
-                    return Status::NoSegment;
-                }
-
-                if (route_parameters.is_destination[i])
-                {
-                    *phantom_node_target_out_iter = *phantom_node_source_out_iter;
-                    phantom_node_target_out_iter++;
-                }
-                phantom_node_source_out_iter++;
-            }
-            else
-            {
-                BOOST_ASSERT(route_parameters.is_destination[i] && !route_parameters.is_source[i]);
-
-                *phantom_node_target_out_iter =
-                    facade->NearestPhantomNodeWithAlternativeFromBigComponent(
-                        route_parameters.coordinates[i], bearing, range);
-                // we didn't found a fitting node, return error
-                if (!phantom_node_target_out_iter->first.is_valid(facade->GetNumberOfNodes()))
-                {
-                    json_result.values["status_message"] =
-                        std::string("Could not find a matching segment for coordinate ") + std::to_string(i);
-                    return Status::NoSegment;
-                }
-                phantom_node_target_out_iter++;
-            }
-        }
-
-        BOOST_ASSERT((phantom_node_source_out_iter - phantom_node_source_vector.begin()) ==
-                     number_of_sources);
-        BOOST_ASSERT((phantom_node_target_out_iter - phantom_node_target_vector.begin()) ==
-                     number_of_destination);
-
-        // FIXME we should clear phantom_node_source_vector and phantom_node_target_vector after
-        // this
-        auto snapped_source_phantoms = snapPhantomNodes(phantom_node_source_vector);
-        auto snapped_target_phantoms = snapPhantomNodes(phantom_node_target_vector);
-
-        auto result_table =
-            search_engine_ptr->distance_table(snapped_source_phantoms, snapped_target_phantoms);
-
-        if (!result_table)
-        {
-            json_result.values["status_message"] = "No distance table found";
-            return Status::EmptyResult;
-        }
-
-        osrm::json::Array matrix_json_array;
-        for (const auto row : osrm::irange<std::size_t>(0, number_of_sources))
-        {
-            osrm::json::Array json_row;
-            auto row_begin_iterator = result_table->begin() + (row * number_of_destination);
-            auto row_end_iterator = result_table->begin() + ((row + 1) * number_of_destination);
-            json_row.values.insert(json_row.values.end(), row_begin_iterator, row_end_iterator);
-            matrix_json_array.values.push_back(json_row);
-        }
-        json_result.values["distance_table"] = matrix_json_array;
-
-        osrm::json::Array target_coord_json_array;
-        for (const auto &phantom : snapped_target_phantoms)
-        {
-            osrm::json::Array json_coord;
-            json_coord.values.push_back(phantom.location.lat / COORDINATE_PRECISION);
-            json_coord.values.push_back(phantom.location.lon / COORDINATE_PRECISION);
-            target_coord_json_array.values.push_back(json_coord);
-        }
-        json_result.values["destination_coordinates"] = target_coord_json_array;
-        osrm::json::Array source_coord_json_array;
-        for (const auto &phantom : snapped_source_phantoms)
-        {
-            osrm::json::Array json_coord;
-            json_coord.values.push_back(phantom.location.lat / COORDINATE_PRECISION);
-            json_coord.values.push_back(phantom.location.lon / COORDINATE_PRECISION);
-            source_coord_json_array.values.push_back(json_coord);
-        }
-        json_result.values["source_coordinates"] = source_coord_json_array;
-        return Status::Ok;
-    }
-
-  private:
-    std::string descriptor_string;
-    DataFacadeT *facade;
-};
-
-#endif // DISTANCE_TABLE_HPP
diff --git a/plugins/hello_world.hpp b/plugins/hello_world.hpp
deleted file mode 100644
index 512fb07..0000000
--- a/plugins/hello_world.hpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 HELLO_WORLD_HPP
-#define HELLO_WORLD_HPP
-
-#include "plugin_base.hpp"
-
-#include "../util/json_renderer.hpp"
-
-#include <osrm/json_container.hpp>
-
-#include <string>
-
-class HelloWorldPlugin final : public BasePlugin
-{
-  private:
-    std::string temp_string;
-
-  public:
-    HelloWorldPlugin() : descriptor_string("hello") {}
-    virtual ~HelloWorldPlugin() {}
-    const std::string GetDescriptor() const override final { return descriptor_string; }
-
-    Status HandleRequest(const RouteParameters &routeParameters,
-                      osrm::json::Object &json_result) override final
-    {
-        std::string temp_string;
-        json_result.values["title"] = "Hello World";
-
-        temp_string = std::to_string(routeParameters.zoom_level);
-        json_result.values["zoom_level"] = temp_string;
-
-        temp_string = std::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["jsonp_parameter"] =
-            (!routeParameters.jsonp_parameter.empty() ? "yes" : "no");
-        json_result.values["language"] = (!routeParameters.language.empty() ? "yes" : "no");
-
-        temp_string = std::to_string(routeParameters.coordinates.size());
-        json_result.values["location_count"] = temp_string;
-
-        osrm::json::Array json_locations;
-        unsigned counter = 0;
-        for (const FixedPointCoordinate &coordinate : routeParameters.coordinates)
-        {
-            osrm::json::Object json_location;
-            osrm::json::Array 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[std::to_string(counter)] = json_coordinates;
-            json_locations.values.push_back(json_location);
-            ++counter;
-        }
-        json_result.values["locations"] = json_locations;
-        json_result.values["hint_count"] = routeParameters.hints.size();
-
-        osrm::json::Array json_hints;
-        counter = 0;
-        for (const std::string &current_hint : routeParameters.hints)
-        {
-            json_hints.values.push_back(current_hint);
-            ++counter;
-        }
-        json_result.values["hints"] = json_hints;
-        return Status::Ok;
-    }
-
-  private:
-    std::string descriptor_string;
-};
-
-#endif // HELLO_WORLD_HPP
diff --git a/plugins/match.hpp b/plugins/match.hpp
deleted file mode 100644
index e213d19..0000000
--- a/plugins/match.hpp
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 MATCH_HPP
-#define MATCH_HPP
-
-#include "plugin_base.hpp"
-
-#include "../algorithms/bayes_classifier.hpp"
-#include "../algorithms/object_encoder.hpp"
-#include "../data_structures/search_engine.hpp"
-#include "../descriptors/descriptor_base.hpp"
-#include "../descriptors/json_descriptor.hpp"
-#include "../routing_algorithms/map_matching.hpp"
-#include "../util/compute_angle.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/json_logger.hpp"
-#include "../util/json_util.hpp"
-#include "../util/string_util.hpp"
-
-#include <cstdlib>
-
-#include <algorithm>
-#include <memory>
-#include <string>
-#include <vector>
-
-template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
-{
-    std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
-
-    using ClassifierT = BayesClassifier<LaplaceDistribution, LaplaceDistribution, double>;
-    using TraceClassification = ClassifierT::ClassificationT;
-
-  public:
-    MapMatchingPlugin(DataFacadeT *facade, const int max_locations_map_matching)
-        : descriptor_string("match"), facade(facade),
-          max_locations_map_matching(max_locations_map_matching),
-          // the values where derived from fitting a laplace distribution
-          // to the values of manually classified traces
-          classifier(LaplaceDistribution(0.005986, 0.016646),
-                     LaplaceDistribution(0.054385, 0.458432),
-                     0.696774) // valid apriori probability
-    {
-        search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
-    }
-
-    virtual ~MapMatchingPlugin() {}
-
-    const std::string GetDescriptor() const final override { return descriptor_string; }
-
-    TraceClassification
-    classify(const float trace_length, const float matched_length, const int removed_points) const
-    {
-        (void)removed_points; // unused
-
-        const double distance_feature = -std::log(trace_length) + std::log(matched_length);
-
-        // matched to the same point
-        if (!std::isfinite(distance_feature))
-        {
-            return std::make_pair(ClassifierT::ClassLabel::NEGATIVE, 1.0);
-        }
-
-        const auto label_with_confidence = classifier.classify(distance_feature);
-
-        return label_with_confidence;
-    }
-
-    osrm::matching::CandidateLists getCandidates(
-        const std::vector<FixedPointCoordinate> &input_coords,
-        const std::vector<std::pair<const int, const boost::optional<int>>> &input_bearings,
-        const double gps_precision,
-        std::vector<double> &sub_trace_lengths)
-    {
-        osrm::matching::CandidateLists candidates_lists;
-
-        // assuming the gps_precision is the standart-diviation of normal distribution that models
-        // GPS noise (in this model) this should give us the correct candidate with >0.95
-        double query_radius = 3 * gps_precision;
-        double last_distance =
-            coordinate_calculation::haversine_distance(input_coords[0], input_coords[1]);
-
-        sub_trace_lengths.resize(input_coords.size());
-        sub_trace_lengths[0] = 0;
-        for (const auto current_coordinate : osrm::irange<std::size_t>(0, input_coords.size()))
-        {
-            bool allow_uturn = false;
-            if (0 < current_coordinate)
-            {
-                last_distance = coordinate_calculation::haversine_distance(
-                    input_coords[current_coordinate - 1], input_coords[current_coordinate]);
-
-                sub_trace_lengths[current_coordinate] +=
-                    sub_trace_lengths[current_coordinate - 1] + last_distance;
-            }
-
-            if (input_coords.size() - 1 > current_coordinate && 0 < current_coordinate)
-            {
-                double turn_angle = ComputeAngle::OfThreeFixedPointCoordinates(
-                    input_coords[current_coordinate - 1], input_coords[current_coordinate],
-                    input_coords[current_coordinate + 1]);
-
-                // sharp turns indicate a possible uturn
-                if (turn_angle <= 90.0 || turn_angle >= 270.0)
-                {
-                    allow_uturn = true;
-                }
-            }
-
-            // Use bearing values if supplied, otherwise fallback to 0,180 defaults
-            auto bearing = input_bearings.size() > 0 ? input_bearings[current_coordinate].first : 0;
-            auto range = input_bearings.size() > 0
-                             ? (input_bearings[current_coordinate].second
-                                    ? *input_bearings[current_coordinate].second
-                                    : 10)
-                             : 180;
-            auto candidates = facade->NearestPhantomNodesInRange(input_coords[current_coordinate],
-                                                                 query_radius, bearing, range);
-
-            if (candidates.size() == 0)
-            {
-                break;
-            }
-
-            // sort by foward id, then by reverse id and then by distance
-            std::sort(
-                candidates.begin(), candidates.end(),
-                [](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
-                {
-                    return lhs.phantom_node.forward_node_id < rhs.phantom_node.forward_node_id ||
-                           (lhs.phantom_node.forward_node_id == rhs.phantom_node.forward_node_id &&
-                            (lhs.phantom_node.reverse_node_id < rhs.phantom_node.reverse_node_id ||
-                             (lhs.phantom_node.reverse_node_id ==
-                                  rhs.phantom_node.reverse_node_id &&
-                              lhs.distance < rhs.distance)));
-                });
-
-            auto new_end = std::unique(
-                candidates.begin(), candidates.end(),
-                [](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
-                {
-                    return lhs.phantom_node.forward_node_id == rhs.phantom_node.forward_node_id &&
-                           lhs.phantom_node.reverse_node_id == rhs.phantom_node.reverse_node_id;
-                });
-            candidates.resize(new_end - candidates.begin());
-
-            if (!allow_uturn)
-            {
-                const auto compact_size = candidates.size();
-                for (const auto i : osrm::irange<std::size_t>(0, compact_size))
-                {
-                    // Split edge if it is bidirectional and append reverse direction to end of list
-                    if (candidates[i].phantom_node.forward_node_id != SPECIAL_NODEID &&
-                        candidates[i].phantom_node.reverse_node_id != SPECIAL_NODEID)
-                    {
-                        PhantomNode reverse_node(candidates[i].phantom_node);
-                        reverse_node.forward_node_id = SPECIAL_NODEID;
-                        candidates.push_back(
-                            PhantomNodeWithDistance{reverse_node, candidates[i].distance});
-
-                        candidates[i].phantom_node.reverse_node_id = SPECIAL_NODEID;
-                    }
-                }
-            }
-
-            // sort by distance to make pruning effective
-            std::sort(candidates.begin(), candidates.end(),
-                      [](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
-                      {
-                          return lhs.distance < rhs.distance;
-                      });
-
-            candidates_lists.push_back(std::move(candidates));
-        }
-
-        return candidates_lists;
-    }
-
-    osrm::json::Object submatchingToJSON(const osrm::matching::SubMatching &sub,
-                                         const RouteParameters &route_parameters,
-                                         const InternalRouteResult &raw_route)
-    {
-        osrm::json::Object subtrace;
-
-        if (route_parameters.classify)
-        {
-            subtrace.values["confidence"] = sub.confidence;
-        }
-
-        JSONDescriptor<DataFacadeT> json_descriptor(facade);
-        json_descriptor.SetConfig(route_parameters);
-
-        subtrace.values["hint_data"] = json_descriptor.BuildHintData(raw_route);
-
-        if (route_parameters.geometry || route_parameters.print_instructions)
-        {
-            DescriptionFactory factory;
-            FixedPointCoordinate current_coordinate;
-            factory.SetStartSegment(raw_route.segment_end_coordinates.front().source_phantom,
-                                    raw_route.source_traversed_in_reverse.front());
-            for (const auto i :
-                 osrm::irange<std::size_t>(0, raw_route.unpacked_path_segments.size()))
-            {
-                for (const PathData &path_data : raw_route.unpacked_path_segments[i])
-                {
-                    current_coordinate = facade->GetCoordinateOfNode(path_data.node);
-                    factory.AppendSegment(current_coordinate, path_data);
-                }
-                factory.SetEndSegment(raw_route.segment_end_coordinates[i].target_phantom,
-                                      raw_route.target_traversed_in_reverse[i],
-                                      raw_route.is_via_leg(i));
-            }
-
-            factory.Run(route_parameters.zoom_level);
-
-            // we need because we don't run path simplification
-            for (auto &segment : factory.path_description)
-            {
-                segment.necessary = true;
-            }
-
-            if (route_parameters.geometry)
-            {
-                subtrace.values["geometry"] =
-                    factory.AppendGeometryString(route_parameters.compression);
-            }
-
-            if (route_parameters.print_instructions)
-            {
-                std::vector<typename JSONDescriptor<DataFacadeT>::Segment> temp_segments;
-                subtrace.values["instructions"] =
-                    json_descriptor.BuildTextualDescription(factory, temp_segments);
-            }
-
-            factory.BuildRouteSummary(factory.get_entire_length(), raw_route.shortest_path_length);
-            osrm::json::Object json_route_summary;
-            json_route_summary.values["total_distance"] = factory.summary.distance;
-            json_route_summary.values["total_time"] = factory.summary.duration;
-            subtrace.values["route_summary"] = json_route_summary;
-        }
-
-        subtrace.values["indices"] = osrm::json::make_array(sub.indices);
-
-        osrm::json::Array points;
-        for (const auto &node : sub.nodes)
-        {
-            points.values.emplace_back(
-                osrm::json::make_array(node.location.lat / COORDINATE_PRECISION,
-                                       node.location.lon / COORDINATE_PRECISION));
-        }
-        subtrace.values["matched_points"] = points;
-
-        osrm::json::Array names;
-        for (const auto &node : sub.nodes)
-        {
-            names.values.emplace_back(facade->get_name_for_id(node.name_id));
-        }
-        subtrace.values["matched_names"] = names;
-
-        return subtrace;
-    }
-
-    Status HandleRequest(const RouteParameters &route_parameters,
-                         osrm::json::Object &json_result) final override
-    {
-        // enforce maximum number of locations for performance reasons
-        if (max_locations_map_matching > 0 &&
-            static_cast<int>(route_parameters.coordinates.size()) > max_locations_map_matching)
-        {
-            json_result.values["status_message"] = "Too many coodindates";
-            return Status::Error;
-        }
-
-        // check number of parameters
-        if (!check_all_coordinates(route_parameters.coordinates))
-        {
-            json_result.values["status_message"] = "Invalid coordinates";
-            return Status::Error;
-        }
-
-        std::vector<double> sub_trace_lengths;
-        const auto &input_coords = route_parameters.coordinates;
-        const auto &input_timestamps = route_parameters.timestamps;
-        const auto &input_bearings = route_parameters.bearings;
-        if (input_timestamps.size() > 0 && input_coords.size() != input_timestamps.size())
-        {
-            json_result.values["status_message"] =
-                "Number of timestamps does not match number of coordinates";
-            return Status::Error;
-        }
-
-        if (input_bearings.size() > 0 && input_coords.size() != input_bearings.size())
-        {
-            json_result.values["status_message"] =
-                "Number of bearings does not match number of coordinates";
-            return Status::Error;
-        }
-
-        // enforce maximum number of locations for performance reasons
-        if (static_cast<int>(input_coords.size()) < 2)
-        {
-            json_result.values["status_message"] = "At least two coordinates needed";
-            return Status::Error;
-        }
-
-        const auto candidates_lists = getCandidates(
-            input_coords, input_bearings, route_parameters.gps_precision, sub_trace_lengths);
-        if (candidates_lists.size() != input_coords.size())
-        {
-            BOOST_ASSERT(candidates_lists.size() < input_coords.size());
-            json_result.values["status_message"] =
-                std::string("Could not find a matching segment for coordinate ") +
-                std::to_string(candidates_lists.size());
-            return Status::NoSegment;
-        }
-
-        // setup logging if enabled
-        if (osrm::json::Logger::get())
-            osrm::json::Logger::get()->initialize("matching");
-
-        // call the actual map matching
-        osrm::matching::SubMatchingList sub_matchings;
-        search_engine_ptr->map_matching(candidates_lists, input_coords, input_timestamps,
-                                        route_parameters.matching_beta,
-                                        route_parameters.gps_precision, sub_matchings);
-
-        osrm::json::Array matchings;
-        for (auto &sub : sub_matchings)
-        {
-            // classify result
-            if (route_parameters.classify)
-            {
-                double trace_length =
-                    sub_trace_lengths[sub.indices.back()] - sub_trace_lengths[sub.indices.front()];
-                TraceClassification classification =
-                    classify(trace_length, sub.length,
-                             (sub.indices.back() - sub.indices.front() + 1) - sub.nodes.size());
-                if (classification.first == ClassifierT::ClassLabel::POSITIVE)
-                {
-                    sub.confidence = classification.second;
-                }
-                else
-                {
-                    sub.confidence = 1 - classification.second;
-                }
-            }
-
-            BOOST_ASSERT(sub.nodes.size() > 1);
-
-            // FIXME we only run this to obtain the geometry
-            // The clean way would be to get this directly from the map matching plugin
-            InternalRouteResult raw_route;
-            PhantomNodes current_phantom_node_pair;
-            for (unsigned i = 0; i < sub.nodes.size() - 1; ++i)
-            {
-                current_phantom_node_pair.source_phantom = sub.nodes[i];
-                current_phantom_node_pair.target_phantom = sub.nodes[i + 1];
-                BOOST_ASSERT(current_phantom_node_pair.source_phantom.is_valid());
-                BOOST_ASSERT(current_phantom_node_pair.target_phantom.is_valid());
-                raw_route.segment_end_coordinates.emplace_back(current_phantom_node_pair);
-            }
-            search_engine_ptr->shortest_path(
-                raw_route.segment_end_coordinates,
-                std::vector<bool>(raw_route.segment_end_coordinates.size() + 1, true), raw_route);
-
-            BOOST_ASSERT(raw_route.shortest_path_length != INVALID_EDGE_WEIGHT);
-
-            matchings.values.emplace_back(submatchingToJSON(sub, route_parameters, raw_route));
-        }
-
-        if (osrm::json::Logger::get())
-            osrm::json::Logger::get()->render("matching", json_result);
-        json_result.values["matchings"] = matchings;
-
-        if (sub_matchings.empty())
-        {
-            json_result.values["status_message"] = "Cannot find matchings";
-            return Status::EmptyResult;
-        }
-
-        json_result.values["status_message"] = "Found matchings";
-        return Status::Ok;
-    }
-
-  private:
-    std::string descriptor_string;
-    DataFacadeT *facade;
-    int max_locations_map_matching;
-    ClassifierT classifier;
-};
-
-#endif // MATCH_HPP
diff --git a/plugins/nearest.hpp b/plugins/nearest.hpp
deleted file mode 100644
index 2459819..0000000
--- a/plugins/nearest.hpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 NEAREST_HPP
-#define NEAREST_HPP
-
-#include "plugin_base.hpp"
-
-#include "../data_structures/phantom_node.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/json_renderer.hpp"
-
-#include <osrm/json_container.hpp>
-
-#include <string>
-
-/*
- * This Plugin locates the nearest point on a street in the road network for a given coordinate.
- */
-
-template <class DataFacadeT> class NearestPlugin final : public BasePlugin
-{
-  public:
-    explicit NearestPlugin(DataFacadeT *facade) : facade(facade), descriptor_string("nearest") {}
-
-    const std::string GetDescriptor() const override final { return descriptor_string; }
-
-    Status HandleRequest(const RouteParameters &route_parameters,
-                      osrm::json::Object &json_result) override final
-    {
-        // check number of parameters
-        if (route_parameters.coordinates.empty() ||
-            !route_parameters.coordinates.front().is_valid())
-        {
-            return Status::Error;
-        }
-
-        const auto &input_bearings = route_parameters.bearings;
-        if (input_bearings.size() > 0 &&
-            route_parameters.coordinates.size() != input_bearings.size())
-        {
-            json_result.values["status_message"] =
-                "Number of bearings does not match number of coordinates";
-            return Status::Error;
-        }
-
-        auto number_of_results = static_cast<std::size_t>(route_parameters.num_results);
-        const int bearing = input_bearings.size() > 0 ? input_bearings.front().first : 0;
-        const int range =
-            input_bearings.size() > 0
-                ? (input_bearings.front().second ? *input_bearings.front().second : 10)
-                : 180;
-        auto phantom_node_vector = facade->NearestPhantomNodes(route_parameters.coordinates.front(),
-                                                               number_of_results, bearing, range);
-
-        if (phantom_node_vector.empty())
-        {
-            json_result.values["status_message"] =
-                std::string("Could not find a matching segments for coordinate");
-            return Status::NoSegment;
-        }
-        else
-        {
-            json_result.values["status_message"] = "Found nearest edge";
-            if (number_of_results > 1)
-            {
-                osrm::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)))
-                {
-                    const auto &node = phantom_node_vector[i].phantom_node;
-                    osrm::json::Array json_coordinate;
-                    osrm::json::Object result;
-                    json_coordinate.values.push_back(node.location.lat / COORDINATE_PRECISION);
-                    json_coordinate.values.push_back(node.location.lon / COORDINATE_PRECISION);
-                    result.values["mapped coordinate"] = json_coordinate;
-                    result.values["name"] = facade->get_name_for_id(node.name_id);
-                    results.values.push_back(result);
-                }
-                json_result.values["results"] = results;
-            }
-            else
-            {
-                osrm::json::Array json_coordinate;
-                json_coordinate.values.push_back(
-                    phantom_node_vector.front().phantom_node.location.lat / COORDINATE_PRECISION);
-                json_coordinate.values.push_back(
-                    phantom_node_vector.front().phantom_node.location.lon / COORDINATE_PRECISION);
-                json_result.values["mapped_coordinate"] = json_coordinate;
-                json_result.values["name"] =
-                    facade->get_name_for_id(phantom_node_vector.front().phantom_node.name_id);
-            }
-        }
-        return Status::Ok;
-    }
-
-  private:
-    DataFacadeT *facade;
-    std::string descriptor_string;
-};
-
-#endif /* NEAREST_HPP */
diff --git a/plugins/plugin_base.hpp b/plugins/plugin_base.hpp
deleted file mode 100644
index a05785a..0000000
--- a/plugins/plugin_base.hpp
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 BASE_PLUGIN_HPP
-#define BASE_PLUGIN_HPP
-
-#include "../data_structures/phantom_node.hpp"
-
-#include <osrm/coordinate.hpp>
-#include <osrm/json_container.hpp>
-#include <osrm/route_parameters.hpp>
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-class BasePlugin
-{
-  public:
-    enum class Status : int
-    {
-      Ok = 200,
-      EmptyResult = 207,
-      NoSegment = 208,
-      Error = 400
-    };
-
-    BasePlugin() {}
-    // Maybe someone can explain the pure virtual destructor thing to me (dennis)
-    virtual ~BasePlugin() {}
-    virtual const std::string GetDescriptor() const = 0;
-    virtual Status HandleRequest(const RouteParameters &, osrm::json::Object &) = 0;
-    virtual bool check_all_coordinates(const std::vector<FixedPointCoordinate> &coordinates,
-                                       const unsigned min = 2) const final
-    {
-        if (min > coordinates.size() || std::any_of(std::begin(coordinates), std::end(coordinates),
-                                                    [](const FixedPointCoordinate &coordinate)
-                                                    {
-                                                        return !coordinate.is_valid();
-                                                    }))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    // Decides whether to use the phantom node from a big or small component if both are found.
-    // Returns true if all phantom nodes are in the same component after snapping.
-    std::vector<PhantomNode> snapPhantomNodes(
-        const std::vector<std::pair<PhantomNode, PhantomNode>> &phantom_node_pair_list) const
-    {
-        const auto check_component_id_is_tiny =
-            [](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
-        {
-            return phantom_pair.first.component.is_tiny;
-        };
-
-        // are all phantoms from a tiny cc?
-        const auto check_all_in_same_component =
-            [](const std::vector<std::pair<PhantomNode, PhantomNode>> &nodes)
-        {
-            const auto component_id = nodes.front().first.component.id;
-
-            return std::all_of(std::begin(nodes), std::end(nodes),
-                               [component_id](const PhantomNodePair &phantom_pair)
-                               {
-                                   return component_id == phantom_pair.first.component.id;
-                               });
-        };
-
-        const auto fallback_to_big_component =
-            [](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
-        {
-            if (phantom_pair.first.component.is_tiny && phantom_pair.second.is_valid() &&
-                !phantom_pair.second.component.is_tiny)
-            {
-                return phantom_pair.second;
-            }
-            return phantom_pair.first;
-        };
-
-        const auto use_closed_phantom = [](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
-        {
-            return phantom_pair.first;
-        };
-
-        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);
-        auto all_in_same_component = check_all_in_same_component(phantom_node_pair_list);
-
-        std::vector<PhantomNode> snapped_phantoms;
-        snapped_phantoms.reserve(phantom_node_pair_list.size());
-
-        // The only case we don't snap to the big component if all phantoms are in the same small
-        // component
-        if (every_phantom_is_in_tiny_cc && all_in_same_component)
-        {
-            std::transform(phantom_node_pair_list.begin(), phantom_node_pair_list.end(),
-                           std::back_inserter(snapped_phantoms), use_closed_phantom);
-        }
-        else
-        {
-            std::transform(phantom_node_pair_list.begin(), phantom_node_pair_list.end(),
-                           std::back_inserter(snapped_phantoms), fallback_to_big_component);
-        }
-
-        return snapped_phantoms;
-    }
-};
-
-#endif /* BASE_PLUGIN_HPP */
diff --git a/plugins/timestamp.hpp b/plugins/timestamp.hpp
deleted file mode 100644
index 899ef46..0000000
--- a/plugins/timestamp.hpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 TIMESTAMP_PLUGIN_H
-#define TIMESTAMP_PLUGIN_H
-
-#include "plugin_base.hpp"
-
-#include "../util/json_renderer.hpp"
-
-#include <osrm/json_container.hpp>
-
-#include <string>
-
-template <class DataFacadeT> class TimestampPlugin final : public BasePlugin
-{
-  public:
-    explicit TimestampPlugin(const DataFacadeT *facade)
-        : facade(facade), descriptor_string("timestamp")
-    {
-    }
-    const std::string GetDescriptor() const override final { return descriptor_string; }
-    Status HandleRequest(const RouteParameters &route_parameters,
-                      osrm::json::Object &json_result) override final
-    {
-        (void)route_parameters; // unused
-
-        const std::string timestamp = facade->GetTimestamp();
-        json_result.values["timestamp"] = timestamp;
-        return Status::Ok;
-    }
-
-  private:
-    const DataFacadeT *facade;
-    std::string descriptor_string;
-};
-
-#endif /* TIMESTAMP_PLUGIN_H */
diff --git a/plugins/trip.hpp b/plugins/trip.hpp
deleted file mode 100644
index b1ba55b..0000000
--- a/plugins/trip.hpp
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 TRIP_HPP
-#define TRIP_HPP
-
-#include "plugin_base.hpp"
-
-#include "../algorithms/object_encoder.hpp"
-#include "../algorithms/tarjan_scc.hpp"
-#include "../algorithms/trip_nearest_neighbour.hpp"
-#include "../algorithms/trip_farthest_insertion.hpp"
-#include "../algorithms/trip_brute_force.hpp"
-#include "../data_structures/search_engine.hpp"
-#include "../data_structures/matrix_graph_wrapper.hpp" // wrapper to use tarjan
-                                                       // scc on dist table
-#include "../descriptors/descriptor_base.hpp"          // to make json output
-#include "../descriptors/json_descriptor.hpp"          // to make json output
-#include "../util/make_unique.hpp"
-#include "../util/timing_util.hpp"        // to time runtime
-//#include "../util/simple_logger.hpp"      // for logging output
-#include "../util/dist_table_wrapper.hpp" // to access the dist
-                                          // table more easily
-
-#include <osrm/json_container.hpp>
-#include <boost/assert.hpp>
-
-#include <cstdlib>
-#include <algorithm>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-#include <iterator>
-
-template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
-{
-  private:
-    std::string descriptor_string;
-    DataFacadeT *facade;
-    std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
-    int max_locations_trip;
-
-  public:
-    explicit RoundTripPlugin(DataFacadeT *facade, int max_locations_trip)
-        : descriptor_string("trip"), facade(facade), max_locations_trip(max_locations_trip)
-    {
-        search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
-    }
-
-    const std::string GetDescriptor() const override final { return descriptor_string; }
-
-    std::vector<PhantomNode> GetPhantomNodes(const RouteParameters &route_parameters)
-    {
-        const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
-        const auto &input_bearings = route_parameters.bearings;
-
-        std::vector<PhantomNode> phantom_node_list;
-        phantom_node_list.reserve(route_parameters.coordinates.size());
-
-        // find phantom nodes for all input coords
-        for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
-        {
-            // if client hints are helpful, encode hints
-            if (checksum_OK && i < route_parameters.hints.size() &&
-                !route_parameters.hints[i].empty())
-            {
-                PhantomNode current_phantom_node;
-                ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
-                if (current_phantom_node.is_valid(facade->GetNumberOfNodes()))
-                {
-                    phantom_node_list.push_back(std::move(current_phantom_node));
-                    continue;
-                }
-            }
-            const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
-            const int range = input_bearings.size() > 0
-                                  ? (input_bearings[i].second ? *input_bearings[i].second : 10)
-                                  : 180;
-            auto results = facade->NearestPhantomNodes(route_parameters.coordinates[i], 1, bearing, range);
-            if (results.empty())
-            {
-                break;
-            }
-            phantom_node_list.push_back(std::move(results.front().phantom_node));
-            BOOST_ASSERT(phantom_node_list.back().is_valid(facade->GetNumberOfNodes()));
-        }
-
-        return phantom_node_list;
-    }
-
-    // Object to hold all strongly connected components (scc) of a graph
-    // to access all graphs with component ID i, get the iterators by:
-    // auto start = std::begin(scc_component.component) + scc_component.range[i];
-    // auto end = std::begin(scc_component.component) + scc_component.range[i+1];
-    struct SCC_Component
-    {
-        // in_component: all NodeIDs sorted by component ID
-        // in_range: index where a new component starts
-        //
-        // example: NodeID 0, 1, 2, 4, 5 are in component 0
-        //          NodeID 3, 6, 7, 8    are in component 1
-        //          => in_component = [0, 1, 2, 4, 5, 3, 6, 7, 8]
-        //          => in_range = [0, 5]
-        SCC_Component(std::vector<NodeID> in_component_nodes, std::vector<size_t> in_range)
-            : component(std::move(in_component_nodes)), range(std::move(in_range))
-        {
-            BOOST_ASSERT_MSG(component.size() > 0, "there's no scc component");
-            BOOST_ASSERT_MSG(*std::max_element(range.begin(), range.end()) == component.size(),
-                             "scc component ranges are out of bound");
-            BOOST_ASSERT_MSG(*std::min_element(range.begin(), range.end()) == 0,
-                             "invalid scc component range");
-            BOOST_ASSERT_MSG(std::is_sorted(std::begin(range), std::end(range)),
-                             "invalid component ranges");
-        };
-
-        std::size_t GetNumberOfComponents() const
-        {
-            BOOST_ASSERT_MSG(range.size() > 0, "there's no range");
-            return range.size() - 1;
-        }
-
-        const std::vector<NodeID> component;
-        std::vector<std::size_t> range;
-    };
-
-    // takes the number of locations and its distance matrix,
-    // identifies and splits the graph in its strongly connected components (scc)
-    // and returns an SCC_Component
-    SCC_Component SplitUnaccessibleLocations(const std::size_t number_of_locations,
-                                             const DistTableWrapper<EdgeWeight> &result_table)
-    {
-
-        if (std::find(std::begin(result_table), std::end(result_table), INVALID_EDGE_WEIGHT) ==
-            std::end(result_table))
-        {
-            // whole graph is one scc
-            std::vector<NodeID> location_ids(number_of_locations);
-            std::iota(std::begin(location_ids), std::end(location_ids), 0);
-            std::vector<size_t> range = {0, location_ids.size()};
-            return SCC_Component(std::move(location_ids), std::move(range));
-        }
-
-        // Run TarjanSCC
-        auto wrapper = std::make_shared<MatrixGraphWrapper<EdgeWeight>>(result_table.GetTable(),
-                                                                        number_of_locations);
-        auto scc = TarjanSCC<MatrixGraphWrapper<EdgeWeight>>(wrapper);
-        scc.run();
-
-        const auto number_of_components = scc.get_number_of_components();
-
-        std::vector<std::size_t> range_insertion;
-        std::vector<std::size_t> range;
-        range_insertion.reserve(number_of_components);
-        range.reserve(number_of_components);
-
-        std::vector<NodeID> components(number_of_locations, 0);
-
-        std::size_t prefix = 0;
-        for (std::size_t j = 0; j < number_of_components; ++j)
-        {
-            range_insertion.push_back(prefix);
-            range.push_back(prefix);
-            prefix += scc.get_component_size(j);
-        }
-        // senitel
-        range.push_back(components.size());
-
-        for (std::size_t i = 0; i < number_of_locations; ++i)
-        {
-            components[range_insertion[scc.get_component_id(i)]] = i;
-            ++range_insertion[scc.get_component_id(i)];
-        }
-
-        return SCC_Component(std::move(components), std::move(range));
-    }
-
-    void SetLocPermutationOutput(const std::vector<NodeID> &permutation,
-                                 osrm::json::Object &json_result)
-    {
-        osrm::json::Array json_permutation;
-        json_permutation.values.insert(std::end(json_permutation.values), std::begin(permutation),
-                                       std::end(permutation));
-        json_result.values["permutation"] = json_permutation;
-    }
-
-    InternalRouteResult ComputeRoute(const std::vector<PhantomNode> &phantom_node_list,
-                                     const RouteParameters &route_parameters,
-                                     const std::vector<NodeID> &trip)
-    {
-        InternalRouteResult min_route;
-        // given he final trip, compute total distance and return the route and location permutation
-        PhantomNodes viapoint;
-        const auto start = std::begin(trip);
-        const auto end = std::end(trip);
-        // computes a roundtrip from the nodes in trip
-        for (auto it = start; it != end; ++it)
-        {
-            const auto from_node = *it;
-            // if from_node is the last node, compute the route from the last to the first location
-            const auto to_node = std::next(it) != end ? *std::next(it) : *start;
-
-            viapoint = PhantomNodes{phantom_node_list[from_node], phantom_node_list[to_node]};
-            min_route.segment_end_coordinates.emplace_back(viapoint);
-        }
-        BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size());
-
-        std::vector<bool> uturns(trip.size() + 1);
-        BOOST_ASSERT(route_parameters.uturns.size() > 0);
-        std::transform(trip.begin(), trip.end(), uturns.begin(),
-                       [&route_parameters](const NodeID idx)
-                       {
-                           return route_parameters.uturns[idx];
-                       });
-        BOOST_ASSERT(uturns.size() > 0);
-        uturns.back() = route_parameters.uturns[trip.front()];
-
-        search_engine_ptr->shortest_path(min_route.segment_end_coordinates, uturns, min_route);
-
-        BOOST_ASSERT_MSG(min_route.shortest_path_length < INVALID_EDGE_WEIGHT, "unroutable route");
-        return min_route;
-    }
-
-    Status HandleRequest(const RouteParameters &route_parameters,
-                      osrm::json::Object &json_result) override final
-    {
-        if (max_locations_trip > 0 &&
-            (static_cast<int>(route_parameters.coordinates.size()) > max_locations_trip))
-        {
-            json_result.values["status_message"] =
-                "Number of entries " + std::to_string(route_parameters.coordinates.size()) +
-                " is higher than current maximum (" + std::to_string(max_locations_trip) + ")";
-            return Status::Error;
-        }
-
-        // check if all inputs are coordinates
-        if (!check_all_coordinates(route_parameters.coordinates))
-        {
-            json_result.values["status_message"] = "Invalid coordinates";
-            return Status::Error;
-        }
-
-        const auto &input_bearings = route_parameters.bearings;
-        if (input_bearings.size() > 0 &&
-            route_parameters.coordinates.size() != input_bearings.size())
-        {
-            json_result.values["status_message"] =
-                "Number of bearings does not match number of coordinates";
-            return Status::Error;
-        }
-
-        // get phantom nodes
-        auto phantom_node_list = GetPhantomNodes(route_parameters);
-        if (phantom_node_list.size() != route_parameters.coordinates.size())
-        {
-            BOOST_ASSERT(phantom_node_list.size() < route_parameters.coordinates.size());
-            json_result.values["status_message"] =
-                std::string("Could not find a matching segment for coordinate ") +
-                std::to_string(phantom_node_list.size());
-            return Status::NoSegment;
-        }
-
-        const auto number_of_locations = phantom_node_list.size();
-
-        // compute the distance table of all phantom nodes
-        const auto result_table = DistTableWrapper<EdgeWeight>(
-            *search_engine_ptr->distance_table(phantom_node_list, phantom_node_list),
-            number_of_locations);
-
-        if (result_table.size() == 0)
-        {
-            return Status::Error;
-        }
-
-        const constexpr std::size_t BF_MAX_FEASABLE = 10;
-        BOOST_ASSERT_MSG(result_table.size() == number_of_locations * number_of_locations,
-                         "Distance Table has wrong size");
-
-        // get scc components
-        SCC_Component scc = SplitUnaccessibleLocations(number_of_locations, result_table);
-
-        using NodeIDIterator = typename std::vector<NodeID>::const_iterator;
-
-        std::vector<std::vector<NodeID>> route_result;
-        route_result.reserve(scc.GetNumberOfComponents());
-        TIMER_START(TRIP_TIMER);
-        // run Trip computation for every SCC
-        for (std::size_t k = 0; k < scc.GetNumberOfComponents(); ++k)
-        {
-            const auto component_size = scc.range[k + 1] - scc.range[k];
-
-            BOOST_ASSERT_MSG(component_size > 0, "invalid component size");
-
-            std::vector<NodeID> scc_route;
-            NodeIDIterator start = std::begin(scc.component) + scc.range[k];
-            NodeIDIterator end = std::begin(scc.component) + scc.range[k + 1];
-
-            if (component_size > 1)
-            {
-
-                if (component_size < BF_MAX_FEASABLE)
-                {
-                    scc_route =
-                        osrm::trip::BruteForceTrip(start, end, number_of_locations, result_table);
-                }
-                else
-                {
-                    scc_route = osrm::trip::FarthestInsertionTrip(start, end, number_of_locations,
-                                                                  result_table);
-                }
-
-                // use this output if debugging of route is needed:
-                // SimpleLogger().Write() << "Route #" << k << ": " << [&scc_route]()
-                // {
-                //     std::string s = "";
-                //     for (auto x : scc_route)
-                //     {
-                //         s += std::to_string(x) + " ";
-                //     }
-                //     return s;
-                // }();
-
-            }
-            else
-            {
-                scc_route = std::vector<NodeID>(start, end);
-            }
-
-            route_result.push_back(std::move(scc_route));
-        }
-
-        // compute all round trip routes
-        std::vector<InternalRouteResult> comp_route;
-        comp_route.reserve(route_result.size());
-        for (auto &elem : route_result)
-        {
-            comp_route.push_back(ComputeRoute(phantom_node_list, route_parameters, elem));
-        }
-
-        TIMER_STOP(TRIP_TIMER);
-
-        // prepare JSON output
-        // create a json object for every trip
-        osrm::json::Array trip;
-        for (std::size_t i = 0; i < route_result.size(); ++i)
-        {
-            std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor =
-                osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
-            descriptor->SetConfig(route_parameters);
-
-            osrm::json::Object scc_trip;
-
-            // set permutation output
-            SetLocPermutationOutput(route_result[i], scc_trip);
-            // set viaroute output
-            descriptor->Run(comp_route[i], scc_trip);
-
-            trip.values.push_back(std::move(scc_trip));
-        }
-
-
-        if (trip.values.empty())
-        {
-            json_result.values["status_message"] = "Cannot find trips";
-            return Status::EmptyResult;
-        }
-
-        json_result.values["trips"] = std::move(trip);
-        json_result.values["status_message"] = "Found trips";
-        return Status::Ok;
-    }
-};
-
-#endif // TRIP_HPP
diff --git a/plugins/viaroute.hpp b/plugins/viaroute.hpp
deleted file mode 100644
index 21e8714..0000000
--- a/plugins/viaroute.hpp
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "../util/timing_util.hpp"
-
-#include <osrm/json_container.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;
-    int max_locations_viaroute;
-
-  public:
-    explicit ViaRoutePlugin(DataFacadeT *facade, int max_locations_viaroute)
-        : descriptor_string("viaroute"), facade(facade),
-          max_locations_viaroute(max_locations_viaroute)
-    {
-        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 override final { return descriptor_string; }
-
-    Status HandleRequest(const RouteParameters &route_parameters,
-                      osrm::json::Object &json_result) override final
-    {
-        if (max_locations_viaroute > 0 &&
-            (static_cast<int>(route_parameters.coordinates.size()) > max_locations_viaroute))
-        {
-            json_result.values["status_message"] =
-                "Number of entries " + std::to_string(route_parameters.coordinates.size()) +
-                " is higher than current maximum (" + std::to_string(max_locations_viaroute) + ")";
-            return Status::Error;
-        }
-
-        if (!check_all_coordinates(route_parameters.coordinates))
-        {
-            json_result.values["status_message"] = "Invalid coordinates";
-            return Status::Error;
-        }
-
-        const auto &input_bearings = route_parameters.bearings;
-        if (input_bearings.size() > 0 &&
-            route_parameters.coordinates.size() != input_bearings.size())
-        {
-            json_result.values["status_message"] =
-                "Number of bearings does not match number of coordinate";
-            return Status::Error;
-        }
-
-        std::vector<PhantomNodePair> 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].first);
-                if (phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()))
-                {
-                    continue;
-                }
-            }
-            const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
-            const int range = input_bearings.size() > 0
-                                  ? (input_bearings[i].second ? *input_bearings[i].second : 10)
-                                  : 180;
-            phantom_node_pair_list[i] = facade->NearestPhantomNodeWithAlternativeFromBigComponent(
-                route_parameters.coordinates[i], bearing, range);
-            // we didn't found a fitting node, return error
-            if (!phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()))
-            {
-                json_result.values["status_message"] =
-                    std::string("Could not find a matching segment for coordinate ") +
-                    std::to_string(i);
-                return Status::NoSegment;
-            }
-            BOOST_ASSERT(phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()));
-            BOOST_ASSERT(phantom_node_pair_list[i].second.is_valid(facade->GetNumberOfNodes()));
-        }
-
-        auto snapped_phantoms = snapPhantomNodes(phantom_node_pair_list);
-
-        InternalRouteResult raw_route;
-        auto build_phantom_pairs = [&raw_route](const PhantomNode &first_node,
-                                                const PhantomNode &second_node)
-        {
-            raw_route.segment_end_coordinates.push_back(PhantomNodes{first_node, second_node});
-        };
-        osrm::for_each_pair(snapped_phantoms, build_phantom_pairs);
-
-        if (1 == raw_route.segment_end_coordinates.size())
-        {
-            if (route_parameters.alternate_route)
-            {
-                search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
-                                                    raw_route);
-            }
-            else
-            {
-                search_engine_ptr->direct_shortest_path(raw_route.segment_end_coordinates,
-                                                        route_parameters.uturns, raw_route);
-            }
-        }
-        else
-        {
-            search_engine_ptr->shortest_path(raw_route.segment_end_coordinates,
-                                             route_parameters.uturns, raw_route);
-        }
-
-        // we can only know this after the fact, different SCC ids still
-        // allow for connection in one direction.
-        if (raw_route.shortest_path_length == INVALID_EDGE_WEIGHT)
-        {
-            auto first_component_id = snapped_phantoms.front().component.id;
-            auto not_in_same_component =
-                std::any_of(snapped_phantoms.begin(), snapped_phantoms.end(),
-                            [first_component_id](const PhantomNode &node)
-                            {
-                                return node.component.id != first_component_id;
-                            });
-
-            if (not_in_same_component)
-            {
-                json_result.values["status_message"] = "Impossible route between points";
-                return Status::EmptyResult;
-            }
-            else
-            {
-                json_result.values["status_message"] = "No route found between points";
-                return Status::Error;
-            }
-        }
-        else
-        {
-            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, json_result);
-            json_result.values["status_message"] = "Found route between points";
-        }
-
-        return Status::Ok;
-    }
-};
-
-#endif // VIA_ROUTE_HPP
diff --git a/prepare.cpp b/prepare.cpp
deleted file mode 100644
index aaf9376..0000000
--- a/prepare.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-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 "contractor/processing_chain.hpp"
-#include "contractor/contractor_options.hpp"
-#include "util/simple_logger.hpp"
-
-#include <boost/program_options/errors.hpp>
-
-#include <tbb/task_scheduler_init.h>
-
-#include <cstdlib>
-#include <exception>
-#include <ostream>
-#include <new>
-
-int main(int argc, char *argv[]) try
-{
-    LogPolicy::GetInstance().Unmute();
-    ContractorConfig contractor_config;
-
-    const return_code result = ContractorOptions::ParseArguments(argc, argv, contractor_config);
-
-    if (return_code::fail == result)
-    {
-        return EXIT_FAILURE;
-    }
-
-    if (return_code::exit == result)
-    {
-        return EXIT_SUCCESS;
-    }
-
-    ContractorOptions::GenerateOutputFilesNames(contractor_config);
-
-    if (1 > contractor_config.requested_num_threads)
-    {
-        SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
-        return EXIT_FAILURE;
-    }
-
-    const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
-
-    if (recommended_num_threads != contractor_config.requested_num_threads)
-    {
-        SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
-                                         << recommended_num_threads
-                                         << "! This setting may have performance side-effects.";
-    }
-
-    if (!boost::filesystem::is_regular_file(contractor_config.osrm_input_path))
-    {
-        SimpleLogger().Write(logWARNING)
-            << "Input file " << contractor_config.osrm_input_path.string() << " not found!";
-        return EXIT_FAILURE;
-    }
-
-    if (!boost::filesystem::is_regular_file(contractor_config.profile_path))
-    {
-        SimpleLogger().Write(logWARNING) << "Profile " << contractor_config.profile_path.string()
-                                         << " not found!";
-        return EXIT_FAILURE;
-    }
-
-    SimpleLogger().Write() << "Input file: "
-                           << contractor_config.osrm_input_path.filename().string();
-    SimpleLogger().Write() << "Profile: " << contractor_config.profile_path.filename().string();
-    SimpleLogger().Write() << "Threads: " << contractor_config.requested_num_threads;
-
-    tbb::task_scheduler_init init(contractor_config.requested_num_threads);
-
-    return Prepare(contractor_config).Run();
-}
-catch (const std::bad_alloc &e)
-{
-    SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
-    SimpleLogger().Write(logWARNING)
-        << "Please provide more memory or consider using a larger swapfile";
-    return EXIT_FAILURE;
-}
-catch (const std::exception &e)
-{
-    SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
-    return EXIT_FAILURE;
-}
diff --git a/profiles/bicycle.lua b/profiles/bicycle.lua
index 1ebbffd..5575747 100644
--- a/profiles/bicycle.lua
+++ b/profiles/bicycle.lua
@@ -91,9 +91,10 @@ surface_speeds = {
 }
 
 -- these need to be global because they are accesed externaly
-traffic_signal_penalty          = 2
-use_turn_restrictions           = false
-u_turn_penalty                  = 20
+properties.traffic_signal_penalty = 2
+properties.use_turn_restrictions  = false
+properties.u_turn_penalty         = 20
+properties.allow_u_turn_at_via    = true
 
 local obey_oneway               = true
 local ignore_areas              = true
@@ -105,13 +106,6 @@ local safety_penalty            = 1.0
 local use_public_transport      = true
 local fallback_names            = true
 
---modes
-local mode_normal = 1
-local mode_pushing = 2
-local mode_ferry = 3
-local mode_train = 4
-local mode_movable_bridge = 5
-
 local function parse_maxspeed(source)
     if not source then
         return 0
@@ -191,6 +185,9 @@ function way_function (way, result)
     return
   end
 
+  result.forward_mode = mode.cycling
+  result.backward_mode = mode.cycling
+
   -- other tags
   local name = way:get_value_by_key("name")
   local ref = way:get_value_by_key("ref")
@@ -237,14 +234,14 @@ function way_function (way, result)
     if duration and durationIsValid(duration) then
       result.duration = math.max( parseDuration(duration), 1 )
     end
-    result.forward_mode = mode_movable_bridge
-    result.backward_mode = mode_movable_bridge
+    result.forward_mode = mode.movable_bridge
+    result.backward_mode = mode.movable_bridge
     result.forward_speed = bridge_speed
     result.backward_speed = bridge_speed
   elseif route_speeds[route] then
     -- ferries (doesn't cover routes tagged using relations)
-    result.forward_mode = mode_ferry
-    result.backward_mode = mode_ferry
+    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) )
@@ -262,8 +259,8 @@ function way_function (way, result)
     result.forward_speed = platform_speeds[public_transport]
     result.backward_speed = platform_speeds[public_transport]
   elseif use_public_transport and railway and railway_speeds[railway] then
-      result.forward_mode = mode_train
-      result.backward_mode = mode_train
+      result.forward_mode = mode.train
+      result.backward_mode = mode.train
      -- railways
     if access and access_tag_whitelist[access] then
       result.forward_speed = railway_speeds[railway]
@@ -293,27 +290,27 @@ function way_function (way, result)
         -- pedestrian-only ways and areas
         result.forward_speed = pedestrian_speeds[highway]
         result.backward_speed = pedestrian_speeds[highway]
-        result.forward_mode = mode_pushing
-        result.backward_mode = mode_pushing
+        result.forward_mode = mode.pushing_bike
+        result.backward_mode = mode.pushing_bike
       elseif man_made and man_made_speeds[man_made] then
         -- man made structures
         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
+        result.forward_mode = mode.pushing_bike
+        result.backward_mode = mode.pushing_bike
       elseif foot == 'yes' then
         result.forward_speed = walking_speed
         result.backward_speed = walking_speed
-        result.forward_mode = mode_pushing
-        result.backward_mode = mode_pushing
+        result.forward_mode = mode.pushing_bike
+        result.backward_mode = mode.pushing_bike
       elseif foot_forward == 'yes' then
         result.forward_speed = walking_speed
-        result.forward_mode = mode_pushing
-        result.backward_mode = 0
+        result.forward_mode = mode.pushing_bike
+        result.backward_mode = mode.inaccessible
       elseif foot_backward == 'yes' then
         result.forward_speed = walking_speed
-        result.forward_mode = 0
-        result.backward_mode = mode_pushing
+        result.forward_mode = mode.inaccessible
+        result.backward_mode = mode.pushing_bike
       end
     end
   end
@@ -325,48 +322,48 @@ function way_function (way, result)
   end
 
   if onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then
-    result.backward_mode = 0
+    result.backward_mode = mode.inaccessible
   elseif onewayClass == "no" or onewayClass == "0" or onewayClass == "false" then
     -- prevent implied oneway
   elseif onewayClass == "-1" then
-    result.forward_mode = 0
+    result.forward_mode = mode.inaccessible
   elseif oneway == "no" or oneway == "0" or oneway == "false" then
     -- prevent implied oneway
   elseif cycleway and string.find(cycleway, "opposite") == 1 then
     if impliedOneway then
-      result.forward_mode = 0
-      result.backward_mode = mode_normal
+      result.forward_mode = mode.inaccessible
+      result.backward_mode = mode.cycling
       result.backward_speed = bicycle_speeds["cycleway"]
     end
   elseif cycleway_left and cycleway_tags[cycleway_left] and cycleway_right and cycleway_tags[cycleway_right] then
     -- prevent implied
   elseif cycleway_left and cycleway_tags[cycleway_left] then
     if impliedOneway then
-      result.forward_mode = 0
-      result.backward_mode = mode_normal
+      result.forward_mode = mode.inaccessible
+      result.backward_mode = mode.cycling
       result.backward_speed = bicycle_speeds["cycleway"]
     end
   elseif cycleway_right and cycleway_tags[cycleway_right] then
     if impliedOneway then
-      result.forward_mode = mode_normal
+      result.forward_mode = mode.cycling
       result.backward_speed = bicycle_speeds["cycleway"]
-      result.backward_mode = 0
+      result.backward_mode = mode.inaccessible
     end
   elseif oneway == "-1" then
-    result.forward_mode = 0
+    result.forward_mode = mode.inaccessible
   elseif oneway == "yes" or oneway == "1" or oneway == "true" or impliedOneway then
-    result.backward_mode = 0
+    result.backward_mode = mode.inaccessible
   end
 
   -- pushing bikes
   if bicycle_speeds[highway] or pedestrian_speeds[highway] then
     if foot ~= "no" and junction ~= "roundabout" then
-      if result.backward_mode == 0 then
+      if result.backward_mode == mode.inaccessible then
         result.backward_speed = walking_speed
-        result.backward_mode = mode_pushing
-      elseif result.forward_mode == 0 then
+        result.backward_mode = mode.pushing_bike
+      elseif result.forward_mode == mode.inaccessible then
         result.forward_speed = walking_speed
-        result.forward_mode = mode_pushing
+        result.forward_mode = mode.pushing_bike
       end
     end
   end
@@ -382,8 +379,8 @@ function way_function (way, result)
 
   -- dismount
   if bicycle == "dismount" then
-    result.forward_mode = mode_pushing
-    result.backward_mode = mode_pushing
+    result.forward_mode = mode.pushing_bike
+    result.backward_mode = mode.pushing_bike
     result.forward_speed = walking_speed
     result.backward_speed = walking_speed
   end
diff --git a/profiles/car.lua b/profiles/car.lua
index 959558f..8b1e7f2 100644
--- a/profiles/car.lua
+++ b/profiles/car.lua
@@ -128,18 +128,20 @@ maxspeed_table = {
   ["uk:motorway"] = (70*1609)/1000
 }
 
--- these need to be global because they are accesed externaly
-u_turn_penalty                  = 20
-traffic_signal_penalty          = 2
-use_turn_restrictions           = true
+-- set profile properties
+properties.u_turn_penalty                  = 20
+properties.traffic_signal_penalty          = 2
+properties.use_turn_restrictions           = true
 
-local turn_penalty              = 10
+local side_road_speed_multiplier = 0.8
+
+local turn_penalty               = 10
 -- Note: this biases right-side driving.  Should be
 -- inverted for left-driving countries.
-local turn_bias                 = 1.2
+local turn_bias                  = 1.2
 
-local obey_oneway               = true
-local ignore_areas              = true
+local obey_oneway                = true
+local ignore_areas               = true
 
 local abs = math.abs
 local min = math.min
@@ -147,11 +149,6 @@ local max = math.max
 
 local speed_reduction = 0.8
 
---modes
-local mode_normal = 1
-local mode_ferry = 2
-local mode_movable_bridge = 3
-
 function get_exceptions(vector)
   for i,v in ipairs(restriction_exception_tags) do
     vector:Add(v)
@@ -246,6 +243,9 @@ function way_function (way, result)
     return
   end
 
+  result.forward_mode = mode.driving
+  result.backward_mode = mode.driving
+
   -- handling ferries and piers
   local route_speed = speed_profile[route]
   if (route_speed and route_speed > 0) then
@@ -254,8 +254,8 @@ function way_function (way, result)
     if duration and durationIsValid(duration) then
       result.duration = max( parseDuration(duration), 1 )
     end
-    result.forward_mode = mode_ferry
-    result.backward_mode = mode_ferry
+    result.forward_mode = mode.ferry
+    result.backward_mode = mode.ferry
     result.forward_speed = route_speed
     result.backward_speed = route_speed
   end
@@ -269,8 +269,8 @@ function way_function (way, result)
     if duration and durationIsValid(duration) then
       result.duration = max( parseDuration(duration), 1 )
     end
-    result.forward_mode = mode_movable_bridge
-    result.backward_mode = mode_movable_bridge
+    result.forward_mode = mode.movable_bridge
+    result.backward_mode = mode.movable_bridge
     result.forward_speed = bridge_speed
     result.backward_speed = bridge_speed
   end
@@ -311,6 +311,14 @@ function way_function (way, result)
     return
   end
 
+  -- reduce speed on special side roads
+  local sideway = way:get_value_by_key("side_road")
+  if "yes" == sideway or
+  "rotary" == sideway then
+    result.forward_speed = result.forward_speed * side_road_speed_multiplier
+    result.backward_speed = result.backward_speed * side_road_speed_multiplier
+  end
+
   -- reduce speed on bad surfaces
   local surface = way:get_value_by_key("surface")
   local tracktype = way:get_value_by_key("tracktype")
@@ -368,14 +376,14 @@ function way_function (way, result)
   -- Set direction according to tags on way
   if obey_oneway then
     if oneway == "-1" then
-      result.forward_mode = 0
+      result.forward_mode = mode.inaccessible
     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
-      result.backward_mode = 0
+      result.backward_mode = mode.inaccessible
     end
   end
 
@@ -383,7 +391,7 @@ function way_function (way, result)
   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
+    if mode.inaccessible ~= result.forward_mode and mode.inaccessible ~= result.backward_mode then
       result.backward_speed = result.forward_speed
     end
     result.forward_speed = maxspeed_forward
@@ -398,15 +406,15 @@ function way_function (way, result)
   local advisory_backward = parse_maxspeed(way:get_value_by_key("maxspeed:advisory:backward"))
   -- apply bi-directional advisory speed first
   if advisory_speed and advisory_speed > 0 then
-    if 0 ~= result.forward_mode then
+    if mode.inaccessible ~= result.forward_mode then
       result.forward_speed = advisory_speed
     end
-    if 0 ~= result.backward_mode then
+    if mode.inaccessible ~= result.backward_mode then
       result.backward_speed = advisory_speed
     end
   end
   if advisory_forward and advisory_forward > 0 then
-    if 0 ~= result.forward_mode and 0 ~= result.backward_mode then
+    if mode.inaccessible ~= result.forward_mode and mode.inaccessible ~= result.backward_mode then
       result.backward_speed = result.forward_speed
     end
     result.forward_speed = advisory_forward
@@ -429,7 +437,7 @@ function way_function (way, result)
     end
   end
 
-  local is_bidirectional = result.forward_mode ~= 0 and result.backward_mode ~= 0
+  local is_bidirectional = result.forward_mode ~= mode.inaccessible and result.backward_mode ~= mode.inaccessible
 
   -- scale speeds to get better avg driving times
   if result.forward_speed > 0 then
@@ -451,7 +459,7 @@ function way_function (way, result)
   end
 
   -- only allow this road as start point if it not a ferry
-  result.is_startpoint = result.forward_mode == mode_normal or result.backward_mode == mode_normal
+  result.is_startpoint = result.forward_mode == mode.driving or result.backward_mode == mode.driving
 end
 
 function turn_function (angle)
diff --git a/profiles/foot.lua b/profiles/foot.lua
index 61751e3..af1f76e 100644
--- a/profiles/foot.lua
+++ b/profiles/foot.lua
@@ -64,14 +64,12 @@ leisure_speeds = {
   ["track"] = walking_speed
 }
 
-traffic_signal_penalty   = 2
-u_turn_penalty           = 2
-use_turn_restrictions    = false
-local fallback_names     = true
+properties.traffic_signal_penalty   = 2
+properties.u_turn_penalty           = 2
+properties.use_turn_restrictions    = false
+properties.allow_u_turn_at_via      = true
 
---modes
-local mode_normal = 1
-local mode_ferry = 2
+local fallback_names     = true
 
 function get_exceptions(vector)
   for i,v in ipairs(restriction_exception_tags) do
@@ -138,6 +136,9 @@ function way_function (way, result)
     return
   end
 
+  result.forward_mode = mode.walking
+  result.backward_mode = mode.walking
+
   local name = way:get_value_by_key("name")
   local ref = way:get_value_by_key("ref")
   local junction = way:get_value_by_key("junction")
@@ -175,8 +176,8 @@ function way_function (way, result)
     result.forward_speed = route_speeds[route]
     result.backward_speed = route_speeds[route]
   end
-    result.forward_mode = mode_ferry
-    result.backward_mode = mode_ferry
+    result.forward_mode = mode.ferry
+    result.backward_mode = mode.ferry
   elseif railway and platform_speeds[railway] then
     -- railway platforms (old tagging scheme)
     result.forward_speed = platform_speeds[railway]
@@ -205,11 +206,11 @@ function way_function (way, result)
 
   -- oneway
   if onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then
-    result.backward_mode = 0
+    result.backward_mode = mode.inaccessible
   elseif onewayClass == "no" or onewayClass == "0" or onewayClass == "false" then
     -- nothing to do
   elseif onewayClass == "-1" then
-    result.forward_mode = 0
+    result.forward_mode = mode.inaccessible
   end
 
   -- surfaces
diff --git a/profiles/rasterbot.lua b/profiles/rasterbot.lua
index 847384d..03ff8f2 100644
--- a/profiles/rasterbot.lua
+++ b/profiles/rasterbot.lua
@@ -13,6 +13,9 @@ function way_function (way, result)
     result.name = name
   end
 
+  result.forward_mode = mode.cycling
+  result.backward_mode = mode.cycling
+
   result.forward_speed = 15
   result.backward_speed = 15
 end
@@ -32,15 +35,15 @@ end
 function segment_function (source, target, distance, weight)
   local sourceData = sources:query(raster_source, source.lon, source.lat)
   local targetData = sources:query(raster_source, target.lon, target.lat)
-  print ("evaluating segment: " .. sourceData.datum .. " " .. targetData.datum)
+  io.write("evaluating segment: " .. sourceData.datum .. " " .. targetData.datum .. "\n")
   local invalid = sourceData.invalid_data()
 
   if sourceData.datum ~= invalid and targetData.datum ~= invalid then
     local slope = math.abs(sourceData.datum - targetData.datum) / distance
-    print ("   slope: " .. slope)
-    print ("   was speed: " .. weight.speed)
+    io.write("   slope: " .. slope .. "\n")
+    io.write("   was speed: " .. weight.speed .. "\n")
 
     weight.speed = weight.speed * (1 - (slope * 5))
-    print ("   new speed: " .. weight.speed)
+    io.write("   new speed: " .. weight.speed .. "\n")
   end
 end
diff --git a/profiles/rasterbot-interp.lua b/profiles/rasterbotinterp.lua
similarity index 77%
rename from profiles/rasterbot-interp.lua
rename to profiles/rasterbotinterp.lua
index 42c98b6..8266b07 100644
--- a/profiles/rasterbot-interp.lua
+++ b/profiles/rasterbotinterp.lua
@@ -13,6 +13,9 @@ function way_function (way, result)
     result.name = name
   end
 
+  result.forward_mode = mode.cycling
+  result.backward_mode = mode.cycling
+
   result.forward_speed = 15
   result.backward_speed = 15
 end
@@ -32,15 +35,15 @@ end
 function segment_function (source, target, distance, weight)
   local sourceData = sources:interpolate(raster_source, source.lon, source.lat)
   local targetData = sources:interpolate(raster_source, target.lon, target.lat)
-  print ("evaluating segment: " .. sourceData.datum .. " " .. targetData.datum)
+  io.write("evaluating segment: " .. sourceData.datum .. " " .. targetData.datum .. "\n")
   local invalid = sourceData.invalid_data()
 
   if sourceData.datum ~= invalid and targetData.datum ~= invalid then
     local slope = math.abs(sourceData.datum - targetData.datum) / distance
-    print ("   slope: " .. slope)
-    print ("   was speed: " .. weight.speed)
+    io.write("   slope: " .. slope .. "\n")
+    io.write("   was speed: " .. weight.speed .. "\n")
 
     weight.speed = weight.speed * (1 - (slope * 5))
-    print ("   new speed: " .. weight.speed)
+    io.write("   new speed: " .. weight.speed .. "\n")
   end
 end
diff --git a/profiles/testbot.lua b/profiles/testbot.lua
index 6b10d04..aecffae 100644
--- a/profiles/testbot.lua
+++ b/profiles/testbot.lua
@@ -6,14 +6,6 @@
 -- 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,
@@ -24,13 +16,10 @@ speed_profile = {
 
 -- these settings are read directly by osrm
 
-take_minimum_of_speeds  = true
-obey_oneway             = true
-obey_barriers           = true
-use_turn_restrictions   = true
-ignore_areas            = true  -- future feature
-traffic_signal_penalty  = 7     -- seconds
-u_turn_penalty          = 20
+properties.allow_u_turn_at_via     = false
+properties.use_turn_restrictions   = true
+properties.traffic_signal_penalty  = 7     -- seconds
+properties.u_turn_penalty          = 20
 
 function limit_speed(speed, limits)
   -- don't use ipairs(), since it stops at the first nil value
@@ -68,24 +57,26 @@ function way_function (way, result)
   if name then
     result.name = name
   end
+  result.forward_mode = mode.driving
+  result.backward_mode = mode.driving
 
   if duration and durationIsValid(duration) then
     result.duration = math.max( 1, parseDuration(duration) )
-    result.forward_mode = 2
-    result.backward_mode = 2
+    result.forward_mode = mode.route
+    result.backward_mode = mode.route
   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
+      result.forward_mode = mode.river_down
+      result.backward_mode = mode.river_up
       speed_forw = temp_speed*1.5
       speed_back = temp_speed/1.5
     elseif highway == "steps" then
-      result.forward_mode = 5
-      result.backward_mode = 6
+      result.forward_mode = mode.steps_down
+      result.backward_mode = mode.steps_up
     end
 
     if maxspeed_forward ~= nil and maxspeed_forward > 0 then
@@ -111,9 +102,9 @@ function way_function (way, result)
   if oneway == "no" or oneway == "0" or oneway == "false" then
     -- nothing to do
   elseif oneway == "-1" then
-    result.forward_mode = 0
+    result.forward_mode = mode.inaccessible
   elseif oneway == "yes" or oneway == "1" or oneway == "true" or junction == "roundabout" then
-    result.backward_mode = 0
+    result.backward_mode = mode.inaccessible
   end
 
   if junction == 'roundabout' then
diff --git a/routed.cpp b/routed.cpp
deleted file mode 100644
index b4404c1..0000000
--- a/routed.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "server/server.hpp"
-#include "util/version.hpp"
-#include "util/routed_options.hpp"
-#include "util/simple_logger.hpp"
-
-#include <osrm/osrm.hpp>
-#include <osrm/libosrm_config.hpp>
-
-#ifdef __linux__
-#include <sys/mman.h>
-#endif
-
-#include <cstdlib>
-
-#include <signal.h>
-
-#include <chrono>
-#include <future>
-#include <iostream>
-#include <thread>
-#include <new>
-
-#ifdef _WIN32
-boost::function0<void> console_ctrl_function;
-
-BOOL WINAPI console_ctrl_handler(DWORD ctrl_type)
-{
-    switch (ctrl_type)
-    {
-    case CTRL_C_EVENT:
-    case CTRL_BREAK_EVENT:
-    case CTRL_CLOSE_EVENT:
-    case CTRL_SHUTDOWN_EVENT:
-        console_ctrl_function();
-        return TRUE;
-    default:
-        return FALSE;
-    }
-}
-#endif
-
-int main(int argc, const char *argv[]) try
-{
-    LogPolicy::GetInstance().Unmute();
-
-    bool trial_run = false;
-    std::string ip_address;
-    int ip_port, requested_thread_num;
-
-    LibOSRMConfig lib_config;
-    const unsigned init_result = GenerateServerProgramOptions(
-        argc, argv, lib_config.server_paths, ip_address, ip_port, requested_thread_num,
-        lib_config.use_shared_memory, trial_run, lib_config.max_locations_trip, lib_config.max_locations_viaroute,
-        lib_config.max_locations_distance_table,
-        lib_config.max_locations_map_matching);
-    if (init_result == INIT_OK_DO_NOT_START_ENGINE)
-    {
-        return EXIT_SUCCESS;
-    }
-    if (init_result == INIT_FAILED)
-    {
-        return EXIT_FAILURE;
-    }
-
-#ifdef __linux__
-    struct MemoryLocker final
-    {
-        explicit MemoryLocker(bool shouldLock_) : shouldLock(shouldLock_)
-        {
-            if (shouldLock && -1 == mlockall(MCL_CURRENT | MCL_FUTURE))
-            {
-                couldLock = false;
-                SimpleLogger().Write(logWARNING) << "memory could not be locked to RAM";
-            }
-        }
-        ~MemoryLocker()
-        {
-            if (shouldLock && couldLock)
-                (void)munlockall();
-        }
-        bool shouldLock = false, couldLock = true;
-    } memoryLocker(lib_config.use_shared_memory);
-#endif
-    SimpleLogger().Write() << "starting up engines, " << OSRM_VERSION;
-
-    if (lib_config.use_shared_memory)
-    {
-        SimpleLogger().Write(logDEBUG) << "Loading from shared memory";
-    }
-
-    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;
-    sigset_t old_mask;
-    sigfillset(&new_mask);
-    pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask);
-#endif
-
-    OSRM osrm_lib(lib_config);
-    auto routing_server = Server::CreateServer(ip_address, ip_port, requested_thread_num);
-
-    routing_server->GetRequestHandlerPtr().RegisterRoutingMachine(&osrm_lib);
-
-    if (trial_run)
-    {
-        SimpleLogger().Write() << "trial run, quitting after successful initialization";
-    }
-    else
-    {
-        std::packaged_task<int()> server_task([&]() -> int
-                                              {
-                                                  routing_server->Run();
-                                                  return 0;
-                                              });
-        auto future = server_task.get_future();
-        std::thread server_thread(std::move(server_task));
-
-#ifndef _WIN32
-        sigset_t wait_mask;
-        pthread_sigmask(SIG_SETMASK, &old_mask, nullptr);
-        sigemptyset(&wait_mask);
-        sigaddset(&wait_mask, SIGINT);
-        sigaddset(&wait_mask, SIGQUIT);
-        sigaddset(&wait_mask, SIGTERM);
-        pthread_sigmask(SIG_BLOCK, &wait_mask, nullptr);
-        SimpleLogger().Write() << "running and waiting for requests";
-        sigwait(&wait_mask, &sig);
-#else
-        // Set console control handler to allow server to be stopped.
-        console_ctrl_function = std::bind(&Server::Stop, routing_server);
-        SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
-        SimpleLogger().Write() << "running and waiting for requests";
-        routing_server->Run();
-#endif
-        SimpleLogger().Write() << "initiating shutdown";
-        routing_server->Stop();
-        SimpleLogger().Write() << "stopping threads";
-
-        auto status = future.wait_for(std::chrono::seconds(2));
-
-        if (status == std::future_status::ready)
-        {
-            server_thread.join();
-        }
-        else
-        {
-            SimpleLogger().Write(logWARNING) << "Didn't exit within 2 seconds. Hard abort!";
-            server_task.reset(); // just kill it
-        }
-    }
-
-    SimpleLogger().Write() << "freeing objects";
-    routing_server.reset();
-    SimpleLogger().Write() << "shutdown completed";
-}
-catch (const std::bad_alloc &e)
-{
-    SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
-    SimpleLogger().Write(logWARNING)
-        << "Please provide more memory or consider using a larger swapfile";
-    return EXIT_FAILURE;
-}
-catch (const std::exception &e)
-{
-    SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
-    return EXIT_FAILURE;
-}
diff --git a/routing_algorithms/routing_base.hpp b/routing_algorithms/routing_base.hpp
deleted file mode 100644
index ecbc07e..0000000
--- a/routing_algorithms/routing_base.hpp
+++ /dev/null
@@ -1,687 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 ROUTING_BASE_HPP
-#define ROUTING_BASE_HPP
-
-#include "../algorithms/coordinate_calculation.hpp"
-#include "../data_structures/internal_route_result.hpp"
-#include "../data_structures/search_engine_data.hpp"
-#include "../data_structures/turn_instructions.hpp"
-
-#include <boost/assert.hpp>
-
-#include <stack>
-
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_1;
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_1;
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_2;
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_2;
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_3;
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_3;
-
-template <class DataFacadeT, class Derived> class BasicRoutingInterface
-{
-  private:
-    using EdgeData = typename DataFacadeT::EdgeData;
-
-  protected:
-    DataFacadeT *facade;
-
-  public:
-    BasicRoutingInterface() = delete;
-    BasicRoutingInterface(const BasicRoutingInterface &) = delete;
-    explicit BasicRoutingInterface(DataFacadeT *facade) : facade(facade) {}
-    ~BasicRoutingInterface() {}
-
-    // min_edge_offset is needed in case we use multiple
-    // nodes as start/target nodes with different (even negative) offsets.
-    // In that case the termination criterion is not correct
-    // anymore.
-    //
-    // Example:
-    // forward heap: a(-100), b(0),
-    // reverse heap: c(0), d(100)
-    //
-    // a --- d
-    //   \ /
-    //   / \
-    // b --- c
-    //
-    // This is equivalent to running a bi-directional Dijkstra on the following graph:
-    //
-    //     a --- d
-    //    /  \ /  \
-    //   y    x    z
-    //    \  / \  /
-    //     b --- c
-    //
-    // The graph is constructed by inserting nodes y and z that are connected to the initial nodes
-    // using edges (y, a) with weight -100, (y, b) with weight 0 and,
-    // (d, z) with weight 100, (c, z) with weight 0 corresponding.
-    // Since we are dealing with a graph that contains _negative_ edges,
-    // we need to add an offset to the termination criterion.
-    void RoutingStep(SearchEngineData::QueryHeap &forward_heap,
-                     SearchEngineData::QueryHeap &reverse_heap,
-                     NodeID &middle_node_id,
-                     int &upper_bound,
-                     int min_edge_offset,
-                     const bool forward_direction,
-                     const bool stalling = true) const
-    {
-        const NodeID node = forward_heap.DeleteMin();
-        const int distance = forward_heap.GetKey(node);
-
-        if (reverse_heap.WasInserted(node))
-        {
-            const int new_distance = reverse_heap.GetKey(node) + distance;
-            if (new_distance < upper_bound)
-            {
-                if (new_distance >= 0)
-                {
-                    middle_node_id = node;
-                    upper_bound = new_distance;
-                }
-            }
-        }
-
-        // make sure we don't terminate too early if we initialize the distance
-        // for the nodes in the forward heap with the forward/reverse offset
-        BOOST_ASSERT(min_edge_offset <= 0);
-        if (distance + min_edge_offset > upper_bound)
-        {
-            forward_heap.DeleteAll();
-            return;
-        }
-
-        // Stalling
-        if (stalling)
-        {
-            for (const auto edge : facade->GetAdjacentEdgeRange(node))
-            {
-                const EdgeData &data = facade->GetEdgeData(edge);
-                const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
-                if (reverse_flag)
-                {
-                    const NodeID to = facade->GetTarget(edge);
-                    const int edge_weight = data.distance;
-
-                    BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
-
-                    if (forward_heap.WasInserted(to))
-                    {
-                        if (forward_heap.GetKey(to) + edge_weight < distance)
-                        {
-                            return;
-                        }
-                    }
-                }
-            }
-        }
-
-        for (const auto edge : facade->GetAdjacentEdgeRange(node))
-        {
-            const EdgeData &data = facade->GetEdgeData(edge);
-            bool forward_directionFlag = (forward_direction ? data.forward : data.backward);
-            if (forward_directionFlag)
-            {
-
-                const NodeID to = facade->GetTarget(edge);
-                const int edge_weight = data.distance;
-
-                BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
-                const int to_distance = distance + edge_weight;
-
-                // New Node discovered -> Add to Heap + Node Info Storage
-                if (!forward_heap.WasInserted(to))
-                {
-                    forward_heap.Insert(to, to_distance, node);
-                }
-                // Found a shorter Path -> Update distance
-                else if (to_distance < forward_heap.GetKey(to))
-                {
-                    // new parent
-                    forward_heap.GetData(to).parent = node;
-                    forward_heap.DecreaseKey(to, to_distance);
-                }
-            }
-        }
-    }
-
-    template <typename RandomIter>
-    void UnpackPath(RandomIter packed_path_begin,
-                    RandomIter packed_path_end,
-                    const PhantomNodes &phantom_node_pair,
-                    std::vector<PathData> &unpacked_path) const
-    {
-        const bool start_traversed_in_reverse =
-            (*packed_path_begin != phantom_node_pair.source_phantom.forward_node_id);
-        const bool target_traversed_in_reverse =
-            (*std::prev(packed_path_end) != phantom_node_pair.target_phantom.forward_node_id);
-
-        BOOST_ASSERT(std::distance(packed_path_begin, packed_path_end) > 0);
-        std::stack<std::pair<NodeID, NodeID>> recursion_stack;
-
-        // We have to push the path in reverse order onto the stack because it's LIFO.
-        for (auto current = std::prev(packed_path_end); current != packed_path_begin;
-             current = std::prev(current))
-        {
-            recursion_stack.emplace(*std::prev(current), *current);
-        }
-
-        std::pair<NodeID, NodeID> edge;
-        while (!recursion_stack.empty())
-        {
-            // edge.first         edge.second
-            //     *------------------>*
-            //            edge_id
-            edge = recursion_stack.top();
-            recursion_stack.pop();
-
-            // facade->FindEdge does not suffice here in case of shortcuts.
-            // The above explanation unclear? Think!
-            EdgeID smaller_edge_id = SPECIAL_EDGEID;
-            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) &&
-                    facade->GetEdgeData(edge_id).forward)
-                {
-                    smaller_edge_id = edge_id;
-                    edge_weight = weight;
-                }
-            }
-
-            // edge.first         edge.second
-            //     *<------------------*
-            //            edge_id
-            if (SPECIAL_EDGEID == smaller_edge_id)
-            {
-                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) &&
-                        facade->GetEdgeData(edge_id).backward)
-                    {
-                        smaller_edge_id = edge_id;
-                        edge_weight = weight;
-                    }
-                }
-            }
-            BOOST_ASSERT_MSG(edge_weight != INVALID_EDGE_WEIGHT, "edge id invalid");
-
-            const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
-            if (ed.shortcut)
-            { // unpack
-                const NodeID middle_node_id = ed.id;
-                // again, we need to this in reversed order
-                recursion_stack.emplace(middle_node_id, edge.second);
-                recursion_stack.emplace(edge.first, middle_node_id);
-            }
-            else
-            {
-                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))
-                {
-                    BOOST_ASSERT(!facade->EdgeIsCompressed(ed.id));
-                    unpacked_path.emplace_back(facade->GetGeometryIndexForEdgeID(ed.id), name_index,
-                                               turn_instruction, ed.distance, travel_mode);
-                }
-                else
-                {
-                    std::vector<unsigned> id_vector;
-                    facade->GetUncompressedGeometry(facade->GetGeometryIndexForEdgeID(ed.id),
-                                                    id_vector);
-
-                    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 std::size_t end_index = id_vector.size();
-
-                    BOOST_ASSERT(start_index >= 0);
-                    BOOST_ASSERT(start_index <= end_index);
-                    for (std::size_t i = start_index; i < end_index; ++i)
-                    {
-                        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;
-                }
-            }
-        }
-        if (SPECIAL_EDGEID != phantom_node_pair.target_phantom.packed_geometry_id)
-        {
-            std::vector<unsigned> id_vector;
-            facade->GetUncompressedGeometry(phantom_node_pair.target_phantom.packed_geometry_id,
-                                            id_vector);
-            const bool is_local_path = (phantom_node_pair.source_phantom.packed_geometry_id ==
-                                        phantom_node_pair.target_phantom.packed_geometry_id) &&
-                                       unpacked_path.empty();
-
-            std::size_t start_index = 0;
-            if (is_local_path)
-            {
-                start_index = phantom_node_pair.source_phantom.fwd_segment_position;
-                if (target_traversed_in_reverse)
-                {
-                    start_index =
-                        id_vector.size() - phantom_node_pair.source_phantom.fwd_segment_position;
-                }
-            }
-
-            std::size_t end_index = phantom_node_pair.target_phantom.fwd_segment_position;
-            if (target_traversed_in_reverse)
-            {
-                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.forward_travel_mode});
-            }
-        }
-
-        // there is no equivalent to a node-based node in an edge-expanded graph.
-        // two equivalent routes may start (or end) at different node-based edges
-        // as they are added with the offset how much "distance" on the edge
-        // has already been traversed. Depending on offset one needs to remove
-        // the last node.
-        if (unpacked_path.size() > 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);
-
-            if (unpacked_path[last_index].node == unpacked_path[second_to_last_index].node)
-            {
-                unpacked_path.pop_back();
-            }
-            BOOST_ASSERT(!unpacked_path.empty());
-        }
-    }
-
-    void UnpackEdge(const NodeID s, const NodeID t, std::vector<NodeID> &unpacked_path) const
-    {
-        std::stack<std::pair<NodeID, NodeID>> recursion_stack;
-        recursion_stack.emplace(s, t);
-
-        std::pair<NodeID, NodeID> edge;
-        while (!recursion_stack.empty())
-        {
-            edge = recursion_stack.top();
-            recursion_stack.pop();
-
-            EdgeID smaller_edge_id = SPECIAL_EDGEID;
-            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) &&
-                    facade->GetEdgeData(edge_id).forward)
-                {
-                    smaller_edge_id = edge_id;
-                    edge_weight = weight;
-                }
-            }
-
-            if (SPECIAL_EDGEID == smaller_edge_id)
-            {
-                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) &&
-                        facade->GetEdgeData(edge_id).backward)
-                    {
-                        smaller_edge_id = edge_id;
-                        edge_weight = weight;
-                    }
-                }
-            }
-            BOOST_ASSERT_MSG(edge_weight != std::numeric_limits<EdgeWeight>::max(),
-                             "edge weight invalid");
-
-            const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
-            if (ed.shortcut)
-            { // unpack
-                const NodeID middle_node_id = ed.id;
-                // again, we need to this in reversed order
-                recursion_stack.emplace(middle_node_id, edge.second);
-                recursion_stack.emplace(edge.first, middle_node_id);
-            }
-            else
-            {
-                BOOST_ASSERT_MSG(!ed.shortcut, "edge must be shortcut");
-                unpacked_path.emplace_back(edge.first);
-            }
-        }
-        unpacked_path.emplace_back(t);
-    }
-
-    void RetrievePackedPathFromHeap(const SearchEngineData::QueryHeap &forward_heap,
-                                    const SearchEngineData::QueryHeap &reverse_heap,
-                                    const NodeID middle_node_id,
-                                    std::vector<NodeID> &packed_path) const
-    {
-        RetrievePackedPathFromSingleHeap(forward_heap, middle_node_id, packed_path);
-        std::reverse(packed_path.begin(), packed_path.end());
-        packed_path.emplace_back(middle_node_id);
-        RetrievePackedPathFromSingleHeap(reverse_heap, middle_node_id, packed_path);
-    }
-
-    void RetrievePackedPathFromSingleHeap(const SearchEngineData::QueryHeap &search_heap,
-                                          const NodeID middle_node_id,
-                                          std::vector<NodeID> &packed_path) const
-    {
-        NodeID current_node_id = middle_node_id;
-        while (current_node_id != search_heap.GetData(current_node_id).parent)
-        {
-            current_node_id = search_heap.GetData(current_node_id).parent;
-            packed_path.emplace_back(current_node_id);
-        }
-    }
-
-    // assumes that heaps are already setup correctly.
-    void Search(SearchEngineData::QueryHeap &forward_heap,
-                SearchEngineData::QueryHeap &reverse_heap,
-                int &distance,
-                std::vector<NodeID> &packed_leg) const
-    {
-        NodeID middle = SPECIAL_NODEID;
-
-        // get offset to account for offsets on phantom nodes on compressed edges
-        const auto min_edge_offset = std::min(0, forward_heap.MinKey());
-        BOOST_ASSERT(min_edge_offset <= 0);
-        // we only every insert negative offsets for nodes in the forward heap
-        BOOST_ASSERT(reverse_heap.MinKey() >= 0);
-
-        // run two-Target Dijkstra routing step.
-        while (0 < (forward_heap.Size() + reverse_heap.Size()))
-        {
-            if (!forward_heap.Empty())
-            {
-                RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset, true);
-            }
-            if (!reverse_heap.Empty())
-            {
-                RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset, false);
-            }
-        }
-
-        // No path found for both target nodes?
-        if (INVALID_EDGE_WEIGHT == distance || SPECIAL_NODEID == middle)
-        {
-            return;
-        }
-
-        // Was a paths over one of the forward/reverse nodes not found?
-        BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance),
-                         "no path found");
-
-        RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
-    }
-
-    // assumes that heaps are already setup correctly.
-    void SearchWithCore(SearchEngineData::QueryHeap &forward_heap,
-                        SearchEngineData::QueryHeap &reverse_heap,
-                        SearchEngineData::QueryHeap &forward_core_heap,
-                        SearchEngineData::QueryHeap &reverse_core_heap,
-                        int &distance,
-                        std::vector<NodeID> &packed_leg) const
-    {
-        NodeID middle = SPECIAL_NODEID;
-
-        std::vector<std::pair<NodeID, EdgeWeight>> forward_entry_points;
-        std::vector<std::pair<NodeID, EdgeWeight>> reverse_entry_points;
-
-        // get offset to account for offsets on phantom nodes on compressed edges
-        const auto min_edge_offset = std::min(0, forward_heap.MinKey());
-        // we only every insert negative offsets for nodes in the forward heap
-        BOOST_ASSERT(reverse_heap.MinKey() >= 0);
-
-        // run two-Target Dijkstra routing step.
-        while (0 < (forward_heap.Size() + reverse_heap.Size()))
-        {
-            if (!forward_heap.Empty())
-            {
-                if (facade->IsCoreNode(forward_heap.Min()))
-                {
-                    const NodeID node = forward_heap.DeleteMin();
-                    const int key = forward_heap.GetKey(node);
-                    forward_entry_points.emplace_back(node, key);
-                }
-                else
-                {
-                    RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset,
-                                true);
-                }
-            }
-            if (!reverse_heap.Empty())
-            {
-                if (facade->IsCoreNode(reverse_heap.Min()))
-                {
-                    const NodeID node = reverse_heap.DeleteMin();
-                    const int key = reverse_heap.GetKey(node);
-                    reverse_entry_points.emplace_back(node, key);
-                }
-                else
-                {
-                    RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset,
-                                false);
-                }
-            }
-        }
-
-        // TODO check if unordered_set might be faster
-        // sort by id and increasing by distance
-        auto entry_point_comparator = [](const std::pair<NodeID, EdgeWeight> &lhs,
-                                         const std::pair<NodeID, EdgeWeight> &rhs)
-        {
-            return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second < rhs.second);
-        };
-        std::sort(forward_entry_points.begin(), forward_entry_points.end(), entry_point_comparator);
-        std::sort(reverse_entry_points.begin(), reverse_entry_points.end(), entry_point_comparator);
-
-        NodeID last_id = SPECIAL_NODEID;
-        for (const auto p : forward_entry_points)
-        {
-            if (p.first == last_id)
-            {
-                continue;
-            }
-            forward_core_heap.Insert(p.first, p.second, p.first);
-            last_id = p.first;
-        }
-        last_id = SPECIAL_NODEID;
-        for (const auto p : reverse_entry_points)
-        {
-            if (p.first == last_id)
-            {
-                continue;
-            }
-            reverse_core_heap.Insert(p.first, p.second, p.first);
-            last_id = p.first;
-        }
-
-        // get offset to account for offsets on phantom nodes on compressed edges
-        int min_core_edge_offset = 0;
-        if (forward_core_heap.Size() > 0)
-        {
-            min_core_edge_offset = std::min(min_core_edge_offset, forward_core_heap.MinKey());
-        }
-        if (reverse_core_heap.Size() > 0 && reverse_core_heap.MinKey() < 0)
-        {
-            min_core_edge_offset = std::min(min_core_edge_offset, reverse_core_heap.MinKey());
-        }
-        BOOST_ASSERT(min_core_edge_offset <= 0);
-
-        // run two-target Dijkstra routing step on core with termination criterion
-        while (0 < (forward_core_heap.Size() + reverse_core_heap.Size()) &&
-               distance > (forward_core_heap.MinKey() + reverse_core_heap.MinKey()))
-        {
-            if (!forward_core_heap.Empty())
-            {
-                RoutingStep(forward_core_heap, reverse_core_heap, middle, distance,
-                            min_core_edge_offset, true, false);
-            }
-            if (!reverse_core_heap.Empty())
-            {
-                RoutingStep(reverse_core_heap, forward_core_heap, middle, distance,
-                            min_core_edge_offset, false, false);
-            }
-        }
-
-        // No path found for both target nodes?
-        if (INVALID_EDGE_WEIGHT == distance || SPECIAL_NODEID == middle)
-        {
-            return;
-        }
-
-        // Was a paths over one of the forward/reverse nodes not found?
-        BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance),
-                         "no path found");
-
-        // we need to unpack sub path from core heaps
-        if (facade->IsCoreNode(middle))
-        {
-            std::vector<NodeID> packed_core_leg;
-            RetrievePackedPathFromHeap(forward_core_heap, reverse_core_heap, middle,
-                                       packed_core_leg);
-            BOOST_ASSERT(packed_core_leg.size() > 0);
-            RetrievePackedPathFromSingleHeap(forward_heap, packed_core_leg.front(), packed_leg);
-            std::reverse(packed_leg.begin(), packed_leg.end());
-            packed_leg.insert(packed_leg.end(), packed_core_leg.begin(), packed_core_leg.end());
-            RetrievePackedPathFromSingleHeap(reverse_heap, packed_core_leg.back(), packed_leg);
-        }
-        else
-        {
-            RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
-        }
-    }
-
-    double get_network_distance(SearchEngineData::QueryHeap &forward_heap,
-                                SearchEngineData::QueryHeap &reverse_heap,
-                                const PhantomNode &source_phantom,
-                                const PhantomNode &target_phantom) const
-    {
-        EdgeWeight upper_bound = INVALID_EDGE_WEIGHT;
-        NodeID middle_node = SPECIAL_NODEID;
-        EdgeWeight edge_offset = std::min(0, -source_phantom.GetForwardWeightPlusOffset());
-        edge_offset = std::min(edge_offset, -source_phantom.GetReverseWeightPlusOffset());
-
-        if (source_phantom.forward_node_id != SPECIAL_NODEID)
-        {
-            forward_heap.Insert(source_phantom.forward_node_id,
-                                -source_phantom.GetForwardWeightPlusOffset(),
-                                source_phantom.forward_node_id);
-        }
-        if (source_phantom.reverse_node_id != SPECIAL_NODEID)
-        {
-            forward_heap.Insert(source_phantom.reverse_node_id,
-                                -source_phantom.GetReverseWeightPlusOffset(),
-                                source_phantom.reverse_node_id);
-        }
-
-        if (target_phantom.forward_node_id != SPECIAL_NODEID)
-        {
-            reverse_heap.Insert(target_phantom.forward_node_id,
-                                target_phantom.GetForwardWeightPlusOffset(),
-                                target_phantom.forward_node_id);
-        }
-        if (target_phantom.reverse_node_id != SPECIAL_NODEID)
-        {
-            reverse_heap.Insert(target_phantom.reverse_node_id,
-                                target_phantom.GetReverseWeightPlusOffset(),
-                                target_phantom.reverse_node_id);
-        }
-
-        // search from s and t till new_min/(1+epsilon) > length_of_shortest_path
-        while (0 < (forward_heap.Size() + reverse_heap.Size()))
-        {
-            if (0 < forward_heap.Size())
-            {
-                RoutingStep(forward_heap, reverse_heap, middle_node, upper_bound, edge_offset,
-                            true);
-            }
-            if (0 < reverse_heap.Size())
-            {
-                RoutingStep(reverse_heap, forward_heap, middle_node, upper_bound, edge_offset,
-                            false);
-            }
-        }
-
-        double distance = std::numeric_limits<double>::max();
-        if (upper_bound != INVALID_EDGE_WEIGHT)
-        {
-            std::vector<NodeID> packed_leg;
-            RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle_node, packed_leg);
-            std::vector<PathData> unpacked_path;
-            PhantomNodes nodes;
-            nodes.source_phantom = source_phantom;
-            nodes.target_phantom = target_phantom;
-            UnpackPath(packed_leg.begin(), packed_leg.end(), nodes, unpacked_path);
-
-            FixedPointCoordinate previous_coordinate = source_phantom.location;
-            FixedPointCoordinate current_coordinate;
-            distance = 0;
-            for (const auto &p : unpacked_path)
-            {
-                current_coordinate = facade->GetCoordinateOfNode(p.node);
-                distance += coordinate_calculation::haversine_distance(previous_coordinate,
-                                                                       current_coordinate);
-                previous_coordinate = current_coordinate;
-            }
-            distance += coordinate_calculation::haversine_distance(previous_coordinate,
-                                                                   target_phantom.location);
-        }
-        return distance;
-    }
-};
-
-#endif // ROUTING_BASE_HPP
diff --git a/scripts/check_taginfo.py b/scripts/check_taginfo.py
new file mode 100755
index 0000000..c2c4c72
--- /dev/null
+++ b/scripts/check_taginfo.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python2
+
+import json
+import sys
+import re
+
+WHITELIST = set(["mph"])
+
+if len(sys.argv) < 3:
+    print "Not enough arguments.\nUsage: " + sys.argv[0] + " taginfo.json profile.lua"
+    sys.exit(1)
+
+taginfo_path = sys.argv[1]
+profile_path = sys.argv[2]
+
+taginfo = None
+with open(taginfo_path) as f:
+    taginfo = json.load(f)
+
+valid_strings = [t["key"] for t in taginfo["tags"]]
+valid_strings += [t["value"] for t in taginfo["tags"] if "value" in t]
+
+string_regxp = re.compile("\"([\d\w\_:]+)\"")
+
+profile = None
+with open(profile_path) as f:
+    profile = f.readlines()
+
+n_errors = 0
+for n, line in enumerate(profile):
+    # ignore comments
+    if line.strip().startswith("--"):
+        continue
+    tokens = set(string_regxp.findall(line))
+    errors = []
+    for token in tokens:
+        if token not in WHITELIST and token not in valid_strings:
+            idx = line.find("\""+token+"\"")
+            errors.append((idx, token))
+    errors = sorted(errors)
+    n_errors += len(errors)
+    if len(errors) > 0:
+        prefix = "%i: " % n
+        offset = len(prefix)
+        for idx, token in errors:
+            sys.stdout.write(prefix + line)
+            marker = " "*(idx+offset) + "~"*(len(token)+2)
+            print(marker)
+
+if n_errors > 0:
+    sys.exit(1)
diff --git a/scripts/format.sh b/scripts/format.sh
new file mode 100755
index 0000000..561db87
--- /dev/null
+++ b/scripts/format.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+
+# Runs the Clang Formatter in parallel on the code base.
+# Return codes:
+#  - 1 there are files to be formatted
+#  - 0 everything looks fine
+
+set -eu -o pipefail
+
+find src include unit_tests example -type f -name '*.hpp' -o -name '*.cpp' \
+  | xargs -I{} -P $(nproc) clang-format -i -style=file {}
+
+
+dirty=$(git ls-files --modified)
+
+if [[ $dirty ]]; then
+    echo "The following files do not adhere to the .clang-format style file:"
+    echo $dirty
+    exit 1
+else
+    exit 0
+fi
diff --git a/scripts/install_node.sh b/scripts/install_node.sh
new file mode 100644
index 0000000..a22bfd2
--- /dev/null
+++ b/scripts/install_node.sh
@@ -0,0 +1,9 @@
+# here we set up the node version on the fly. currently only node 4, but can be used for more values if need be
+# This is done manually so that the build works the same on OS X
+rm -rf ~/.nvm/ && git clone --depth 1 --branch v0.30.1 https://github.com/creationix/nvm.git ~/.nvm
+source ~/.nvm/nvm.sh
+nvm install $1
+nvm use $1
+node --version
+npm --version
+which node
diff --git a/scripts/modernize.sh b/scripts/modernize.sh
index ee0f2ed..48d90ba 100755
--- a/scripts/modernize.sh
+++ b/scripts/modernize.sh
@@ -3,4 +3,17 @@
 # Runs the Clang Modernizer in parallel on the code base.
 # Requires a compilation database in the build directory.
 
-git ls-files '*.cpp' | xargs -I{} -P $(nproc) clang-modernize -p build -final-syntax-check -format -style=file -summary -for-compilers=clang-3.4,gcc-4.8 -include . -exclude third_party {}
+find src include unit_tests -type f -name '*.hpp' -o -name '*.cpp' \
+  | xargs \
+      -I{} \
+      -P $(nproc) \
+      clang-modernize \
+        -p build \
+        -final-syntax-check \
+        -format \
+        -style=file \
+        -summary \
+        -for-compilers=clang-3.4,gcc-4.8 \
+        -include . \
+        -exclude third_party \
+      {}
diff --git a/scripts/tidy.sh b/scripts/tidy.sh
index 7ecabfa..7f4ba14 100755
--- a/scripts/tidy.sh
+++ b/scripts/tidy.sh
@@ -3,4 +3,12 @@
 # Runs the Clang Tidy Tool in parallel on the code base.
 # Requires a compilation database in the build directory.
 
-git ls-files '*.cpp' | grep -v third_party | xargs -I{} -P $(nproc) clang-tidy -p build -header-filter='.*' {}
+
+find src include unit_tests -type f -name '*.hpp' -o -name '*.cpp' \
+  | xargs \
+      -I{} \
+      -P $(nproc) \
+      clang-tidy \
+        -p build \
+        -header-filter='.*' \
+      {}
diff --git a/scripts/update_depdendencies.sh b/scripts/update_depdendencies.sh
index e443cfa..ec0210c 100755
--- a/scripts/update_depdendencies.sh
+++ b/scripts/update_depdendencies.sh
@@ -1,10 +1,10 @@
 #!/usr/bin/env bash
 
 OSMIUM_REPO=https://github.com/osmcode/libosmium.git
-OSMIUM_TAG=v2.3.0
+OSMIUM_TAG=v2.6.1
 
 VARIANT_REPO=https://github.com/mapbox/variant.git
-VARIANT_TAG=v1.0
+VARIANT_TAG=v1.1.0
 
 VARIANT_LATEST=$(curl https://api.github.com/repos/mapbox/variant/releases/latest | jq ".tag_name")
 OSMIUM_LATEST=$(curl https://api.github.com/repos/osmcode/libosmium/releases/latest | jq ".tag_name")
diff --git a/server/api_grammar.hpp b/server/api_grammar.hpp
deleted file mode 100644
index 28bd1df..0000000
--- a/server/api_grammar.hpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-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 API_GRAMMAR_HPP
-#define API_GRAMMAR_HPP
-
-#include <boost/bind.hpp>
-#include <boost/spirit/include/qi.hpp>
-#include <boost/spirit/include/qi_action.hpp>
-
-namespace qi = boost::spirit::qi;
-
-template <typename Iterator, class HandlerT> 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 | uturns | location_with_options | destination_with_options | source_with_options |  cmp |
-                            language | instruction | geometry | alt_route | old_API | num_results |
-                            matching_beta | gps_precision | classify | locs);
-        // all combinations of timestamp, uturn, hint and bearing without duplicates
-        t_u = (u >> -timestamp) | (timestamp >> -u);
-        t_h = (hint >> -timestamp) | (timestamp >> -hint);
-        u_h = (u >> -hint) | (hint >> -u);
-        t_u_h = (hint >> -t_u) | (u >> -t_h) | (timestamp >> -u_h);
-        location_options = (bearing >> -t_u_h) | (t_u_h >> -bearing) | //
-                           (u >> bearing >> -t_h) | (timestamp >> bearing >> -u_h) | (hint >> bearing >> t_u) | //
-                           (t_h >> bearing >> -u) | (u_h >> bearing >> -timestamp) | (t_u >> bearing >> -hint);
-        location_with_options = location >> -location_options;
-        source_with_options = source >> -location_options;
-        destination_with_options = destination >> -location_options;
-        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)];
-        jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >>
-                stringwithPercent[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
-        checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >>
-                   qi::uint_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
-        instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >>
-                      qi::bool_[boost::bind(&HandlerT::setInstructionFlag, handler, ::_1)];
-        geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >>
-                   qi::bool_[boost::bind(&HandlerT::setGeometryFlag, handler, ::_1)];
-        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)];
-        destination = (-qi::lit('&')) >> qi::lit("dst") >> '=' >>
-                   (qi::double_ >> qi::lit(',') >>
-                    qi::double_)[boost::bind(&HandlerT::addDestination, handler, ::_1)];
-        source = (-qi::lit('&')) >> qi::lit("src") >> '=' >>
-                   (qi::double_ >> qi::lit(',') >>
-                    qi::double_)[boost::bind(&HandlerT::addSource, handler, ::_1)];
-        hint = (-qi::lit('&')) >> qi::lit("hint") >> '=' >>
-               stringwithDot[boost::bind(&HandlerT::addHint, handler, ::_1)];
-        timestamp = (-qi::lit('&')) >> qi::lit("t") >> '=' >>
-               qi::uint_[boost::bind(&HandlerT::addTimestamp, handler, ::_1)];
-        bearing = (-qi::lit('&')) >> qi::lit("b") >> '=' >>
-               (qi::int_ >> -(qi::lit(',') >> qi::int_ | qi::attr(10)))[boost::bind(&HandlerT::addBearing, handler, ::_1, ::_2, ::_3)];
-        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)];
-        matching_beta = (-qi::lit('&')) >> qi::lit("matching_beta") >> '=' >>
-               qi::float_[boost::bind(&HandlerT::setMatchingBeta, handler, ::_1)];
-        gps_precision = (-qi::lit('&')) >> qi::lit("gps_precision") >> '=' >>
-               qi::float_[boost::bind(&HandlerT::setGPSPrecision, handler, ::_1)];
-        classify = (-qi::lit('&')) >> qi::lit("classify") >> '=' >>
-            qi::bool_[boost::bind(&HandlerT::setClassify, handler, ::_1)];
-        locs = (-qi::lit('&')) >> qi::lit("locs") >> '=' >>
-            stringforPolyline[boost::bind(&HandlerT::getCoordinatesFromGeometry, handler, ::_1)];
-
-        string = +(qi::char_("a-zA-Z"));
-        stringwithDot = +(qi::char_("a-zA-Z0-9_.-"));
-        stringwithPercent = +(qi::char_("a-zA-Z0-9_.-") | qi::char_('[') | qi::char_(']') |
-                              (qi::char_('%') >> qi::char_("0-9A-Z") >> qi::char_("0-9A-Z")));
-        stringforPolyline = +(qi::char_("a-zA-Z0-9_.-[]{}@?|\\%~`^"));
-    }
-
-    qi::rule<Iterator> api_call, query, location_options, location_with_options, destination_with_options, source_with_options, t_u, t_h, u_h, t_u_h;
-    qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location, destination, source,
-        hint, timestamp, bearing, stringwithDot, stringwithPercent, language, geometry, cmp, alt_route, u,
-        uturns, old_API, num_results, matching_beta, gps_precision, classify, locs, instruction, stringforPolyline;
-
-    HandlerT *handler;
-};
-
-#endif /* API_GRAMMAR_HPP */
diff --git a/server/connection.hpp b/server/connection.hpp
deleted file mode 100644
index aa6fd05..0000000
--- a/server/connection.hpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 CONNECTION_HPP
-#define CONNECTION_HPP
-
-#include "http/compression_type.hpp"
-#include "http/reply.hpp"
-#include "http/request.hpp"
-#include "request_parser.hpp"
-
-#include <boost/array.hpp>
-#include <boost/asio.hpp>
-#include <boost/config.hpp>
-#include <boost/version.hpp>
-
-#include <memory>
-#include <vector>
-
-// workaround for incomplete std::shared_ptr compatibility in old boost versions
-#if BOOST_VERSION < 105300 || defined BOOST_NO_CXX11_SMART_PTR
-
-namespace boost
-{
-template <class T> const T *get_pointer(std::shared_ptr<T> const &p) { return p.get(); }
-
-template <class T> T *get_pointer(std::shared_ptr<T> &p) { return p.get(); }
-} // namespace boost
-
-#endif
-
-class RequestHandler;
-
-namespace http
-{
-
-/// Represents a single connection from a client.
-class Connection : public std::enable_shared_from_this<Connection>
-{
-  public:
-    explicit Connection(boost::asio::io_service &io_service, RequestHandler &handler);
-    Connection(const Connection &) = delete;
-    Connection() = delete;
-
-    boost::asio::ip::tcp::socket &socket();
-
-    /// Start the first asynchronous operation for the connection.
-    void start();
-
-  private:
-    void handle_read(const boost::system::error_code &e, std::size_t bytes_transferred);
-
-    /// Handle completion of a write operation.
-    void handle_write(const boost::system::error_code &e);
-
-    std::vector<char> compress_buffers(const std::vector<char> &uncompressed_data,
-                                       const compression_type compression_type);
-
-    boost::asio::io_service::strand strand;
-    boost::asio::ip::tcp::socket TCP_socket;
-    RequestHandler &request_handler;
-    RequestParser request_parser;
-    boost::array<char, 8192> incoming_data_buffer;
-    request current_request;
-    reply current_reply;
-    std::vector<char> compressed_output;
-};
-
-} // namespace http
-
-#endif // CONNECTION_HPP
diff --git a/server/data_structures/datafacade_base.hpp b/server/data_structures/datafacade_base.hpp
deleted file mode 100644
index 5c5c522..0000000
--- a/server/data_structures/datafacade_base.hpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 DATAFACADE_BASE_HPP
-#define DATAFACADE_BASE_HPP
-
-// Exposes all data access interfaces to the algorithms via base class ptr
-
-#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 <osrm/coordinate.hpp>
-
-#include <string>
-#include <boost/optional.hpp>
-
-using EdgeRange = osrm::range<EdgeID>;
-
-template <class EdgeDataT> class BaseDataFacade
-{
-  public:
-    using RTreeLeaf = EdgeBasedNode;
-    using EdgeData = EdgeDataT;
-    BaseDataFacade() {}
-    virtual ~BaseDataFacade() {}
-
-    // search graph access
-    virtual unsigned GetNumberOfNodes() const = 0;
-
-    virtual unsigned GetNumberOfEdges() const = 0;
-
-    virtual unsigned GetOutDegree(const NodeID n) const = 0;
-
-    virtual NodeID GetTarget(const EdgeID e) const = 0;
-
-    virtual const EdgeDataT &GetEdgeData(const EdgeID e) const = 0;
-
-    virtual EdgeID BeginEdges(const NodeID n) const = 0;
-
-    virtual EdgeID EndEdges(const NodeID n) const = 0;
-
-    virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0;
-
-    // searches for a specific edge
-    virtual EdgeID FindEdge(const NodeID from, const NodeID to) const = 0;
-
-    virtual EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const = 0;
-
-    virtual EdgeID
-    FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const = 0;
-
-    // node and edge information access
-    virtual FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const = 0;
-
-    virtual bool EdgeIsCompressed(const unsigned id) const = 0;
-
-    virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const = 0;
-
-    virtual void GetUncompressedGeometry(const unsigned id,
-                                         std::vector<unsigned> &result_nodes) const = 0;
-
-    virtual TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const = 0;
-
-    virtual TravelMode GetTravelModeForEdgeID(const unsigned id) const = 0;
-
-    virtual std::vector<PhantomNodeWithDistance>
-    NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate,
-                               const float max_distance,
-                               const int bearing = 0,
-                               const int bearing_range = 180) = 0;
-
-    virtual std::vector<PhantomNodeWithDistance>
-    NearestPhantomNodes(const FixedPointCoordinate &input_coordinate,
-                        const unsigned max_results,
-                        const int bearing = 0,
-                        const int bearing_range = 180) = 0;
-
-    virtual std::pair<PhantomNode, PhantomNode>
-    NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate,
-                                                      const int bearing = 0,
-                                                      const int bearing_range = 180) = 0;
-
-    virtual unsigned GetCheckSum() const = 0;
-
-    virtual bool IsCoreNode(const NodeID id) const = 0;
-
-    virtual unsigned GetNameIndexFromEdgeID(const unsigned id) const = 0;
-
-    virtual std::string get_name_for_id(const unsigned name_id) const = 0;
-
-    virtual std::size_t GetCoreSize() const = 0;
-
-    virtual std::string GetTimestamp() const = 0;
-};
-
-#endif // DATAFACADE_BASE_HPP
diff --git a/server/data_structures/internal_datafacade.hpp b/server/data_structures/internal_datafacade.hpp
deleted file mode 100644
index a2f74e5..0000000
--- a/server/data_structures/internal_datafacade.hpp
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 INTERNAL_DATAFACADE_HPP
-#define INTERNAL_DATAFACADE_HPP
-
-// implements all data storage when shared memory is _NOT_ used
-
-#include "datafacade_base.hpp"
-
-#include "../../algorithms/geospatial_query.hpp"
-#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/graph_loader.hpp"
-#include "../../util/simple_logger.hpp"
-
-#include <osrm/coordinate.hpp>
-
-#include <boost/thread.hpp>
-
-#include <limits>
-
-template <class EdgeDataT> class InternalDataFacade final : public BaseDataFacade<EdgeDataT>
-{
-
-  private:
-    using super = BaseDataFacade<EdgeDataT>;
-    using QueryGraph = StaticGraph<typename super::EdgeData>;
-    using InputEdge = typename QueryGraph::InputEdge;
-    using RTreeLeaf = typename super::RTreeLeaf;
-    using InternalRTree = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>;
-    using InternalGeospatialQuery = GeospatialQuery<InternalRTree>;
-
-    InternalDataFacade() {}
-
-    unsigned m_check_sum;
-    unsigned m_number_of_nodes;
-    std::unique_ptr<QueryGraph> m_query_graph;
-    std::string m_timestamp;
-
-    std::shared_ptr<ShM<FixedPointCoordinate, false>::vector> m_coordinate_list;
-    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_edge_is_compressed;
-    ShM<unsigned, false>::vector m_geometry_indices;
-    ShM<unsigned, false>::vector m_geometry_list;
-    ShM<bool, false>::vector m_is_core_node;
-
-    boost::thread_specific_ptr<InternalRTree> m_static_rtree;
-    boost::thread_specific_ptr<InternalGeospatialQuery> m_geospatial_query;
-    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)
-    {
-        if (boost::filesystem::exists(timestamp_path))
-        {
-            SimpleLogger().Write() << "Loading Timestamp";
-            boost::filesystem::ifstream timestamp_stream(timestamp_path);
-            if (!timestamp_stream)
-            {
-                SimpleLogger().Write(logWARNING) << timestamp_path << " not found";
-            }
-            getline(timestamp_stream, m_timestamp);
-            timestamp_stream.close();
-        }
-        if (m_timestamp.empty())
-        {
-            m_timestamp = "n/a";
-        }
-        if (25 < m_timestamp.length())
-        {
-            m_timestamp.resize(25);
-        }
-    }
-
-    void LoadGraph(const boost::filesystem::path &hsgr_path)
-    {
-        typename ShM<typename QueryGraph::NodeArrayEntry, false>::vector node_list;
-        typename ShM<typename QueryGraph::EdgeArrayEntry, false>::vector edge_list;
-
-        SimpleLogger().Write() << "loading graph from " << hsgr_path.string();
-
-        m_number_of_nodes = readHSGRFromStream(hsgr_path, node_list, edge_list, &m_check_sum);
-
-        BOOST_ASSERT_MSG(0 != node_list.size(), "node list empty");
-        // BOOST_ASSERT_MSG(0 != edge_list.size(), "edge list empty");
-        SimpleLogger().Write() << "loaded " << node_list.size() << " nodes and " << edge_list.size()
-                               << " edges";
-        m_query_graph = std::unique_ptr<QueryGraph>(new 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");
-        SimpleLogger().Write() << "Data checksum is " << m_check_sum;
-    }
-
-    void LoadNodeAndEdgeInformation(const boost::filesystem::path &nodes_file,
-                                    const boost::filesystem::path &edges_file)
-    {
-        boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
-
-        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(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);
-        }
-        nodes_input_stream.close();
-
-        boost::filesystem::ifstream edges_input_stream(edges_file, std::ios::binary);
-        unsigned number_of_edges = 0;
-        edges_input_stream.read((char *)&number_of_edges, sizeof(unsigned));
-        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_travel_mode_list.resize(number_of_edges);
-        m_edge_is_compressed.resize(number_of_edges);
-
-        unsigned compressed = 0;
-
-        OriginalEdgeData current_edge_data;
-        for (unsigned i = 0; i < number_of_edges; ++i)
-        {
-            edges_input_stream.read((char *)&(current_edge_data), sizeof(OriginalEdgeData));
-            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_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;
-            }
-        }
-
-        edges_input_stream.close();
-    }
-
-    void LoadCoreInformation(const boost::filesystem::path &core_data_file)
-    {
-        std::ifstream core_stream(core_data_file.string().c_str(), std::ios::binary);
-        unsigned number_of_markers;
-        core_stream.read((char *)&number_of_markers, sizeof(unsigned));
-
-        std::vector<char> unpacked_core_markers(number_of_markers);
-        core_stream.read((char *)unpacked_core_markers.data(), sizeof(char) * number_of_markers);
-
-        // in this case we have nothing to do
-        if (number_of_markers <= 0)
-        {
-            return;
-        }
-
-        m_is_core_node.resize(number_of_markers);
-        for (auto i = 0u; i < number_of_markers; ++i)
-        {
-            BOOST_ASSERT(unpacked_core_markers[i] == 0 || unpacked_core_markers[i] == 1);
-            m_is_core_node[i] = unpacked_core_markers[i] == 1;
-        }
-    }
-
-    void LoadGeometries(const boost::filesystem::path &geometry_file)
-    {
-        std::ifstream geometry_stream(geometry_file.string().c_str(), std::ios::binary);
-        unsigned number_of_indices = 0;
-        unsigned number_of_compressed_geometries = 0;
-
-        geometry_stream.read((char *)&number_of_indices, sizeof(unsigned));
-
-        m_geometry_indices.resize(number_of_indices);
-        if (number_of_indices > 0)
-        {
-            geometry_stream.read((char *)&(m_geometry_indices[0]),
-                                 number_of_indices * sizeof(unsigned));
-        }
-
-        geometry_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
-
-        BOOST_ASSERT(m_geometry_indices.back() == number_of_compressed_geometries);
-        m_geometry_list.resize(number_of_compressed_geometries);
-
-        if (number_of_compressed_geometries > 0)
-        {
-            geometry_stream.read((char *)&(m_geometry_list[0]),
-                                 number_of_compressed_geometries * sizeof(unsigned));
-        }
-        geometry_stream.close();
-    }
-
-    void LoadRTree()
-    {
-        BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
-
-        m_static_rtree.reset(new InternalRTree(ram_index_path, file_index_path, m_coordinate_list));
-        m_geospatial_query.reset(new InternalGeospatialQuery(*m_static_rtree, m_coordinate_list));
-    }
-
-    void LoadStreetNames(const boost::filesystem::path &names_file)
-    {
-        boost::filesystem::ifstream name_stream(names_file, std::ios::binary);
-
-        name_stream >> m_name_table;
-
-        unsigned number_of_chars = 0;
-        name_stream.read((char *)&number_of_chars, sizeof(unsigned));
-        BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
-        m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element
-        name_stream.read((char *)&m_names_char_list[0], number_of_chars * sizeof(char));
-        if (0 == m_names_char_list.size())
-        {
-            SimpleLogger().Write(logWARNING) << "list of street names is empty";
-        }
-        name_stream.close();
-    }
-
-  public:
-    virtual ~InternalDataFacade()
-    {
-        m_static_rtree.reset();
-        m_geospatial_query.reset();
-    }
-
-    explicit InternalDataFacade(const std::unordered_map<std::string, boost::filesystem::path> &server_paths)
-    {
-        // cache end iterator to quickly check .find against
-        const auto end_it = end(server_paths);
-
-        const auto file_for = [&server_paths, &end_it](const std::string &path)
-        {
-            const auto it = server_paths.find(path);
-            if (it == end_it || !boost::filesystem::is_regular_file(it->second))
-                throw osrm::exception("no valid " + path + " file given in ini file");
-            return it->second;
-        };
-
-        ram_index_path = file_for("ramindex");
-        file_index_path = file_for("fileindex");
-
-        SimpleLogger().Write() << "loading graph data";
-        LoadGraph(file_for("hsgrdata"));
-
-        SimpleLogger().Write() << "loading edge information";
-        LoadNodeAndEdgeInformation(file_for("nodesdata"), file_for("edgesdata"));
-
-        SimpleLogger().Write() << "loading core information";
-        LoadCoreInformation(file_for("coredata"));
-
-        SimpleLogger().Write() << "loading geometries";
-        LoadGeometries(file_for("geometries"));
-
-        SimpleLogger().Write() << "loading timestamp";
-        LoadTimestamp(file_for("timestamp"));
-
-        SimpleLogger().Write() << "loading street names";
-        LoadStreetNames(file_for("namesdata"));
-    }
-
-    // search graph access
-    unsigned GetNumberOfNodes() const override final { return m_query_graph->GetNumberOfNodes(); }
-
-    unsigned GetNumberOfEdges() const override final { return m_query_graph->GetNumberOfEdges(); }
-
-    unsigned GetOutDegree(const NodeID n) const override final
-    {
-        return m_query_graph->GetOutDegree(n);
-    }
-
-    NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); }
-
-    EdgeDataT &GetEdgeData(const EdgeID e) const override final
-    {
-        return m_query_graph->GetEdgeData(e);
-    }
-
-    EdgeID BeginEdges(const NodeID n) const override final { return m_query_graph->BeginEdges(n); }
-
-    EdgeID EndEdges(const NodeID n) const override final { return m_query_graph->EndEdges(n); }
-
-    EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
-    {
-        return m_query_graph->GetAdjacentEdgeRange(node);
-    };
-
-    // searches for a specific edge
-    EdgeID FindEdge(const NodeID from, const NodeID to) const override final
-    {
-        return m_query_graph->FindEdge(from, to);
-    }
-
-    EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const override final
-    {
-        return m_query_graph->FindEdgeInEitherDirection(from, to);
-    }
-
-    EdgeID
-    FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const override final
-    {
-        return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
-    }
-
-    // node and edge information access
-    FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const override final
-    {
-        return m_coordinate_list->at(id);
-    };
-
-    bool EdgeIsCompressed(const unsigned id) const override final
-    {
-        return m_edge_is_compressed.at(id);
-    }
-
-    TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const override final
-    {
-        return m_turn_instruction_list.at(id);
-    }
-
-    TravelMode GetTravelModeForEdgeID(const unsigned id) const override final
-    {
-        return m_travel_mode_list.at(id);
-    }
-
-
-    std::vector<PhantomNodeWithDistance>
-    NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate,
-                               const float max_distance,
-                               const int bearing = 0,
-                               const int bearing_range = 180) override final
-    {
-        if (!m_static_rtree.get())
-        {
-            LoadRTree();
-            BOOST_ASSERT(m_geospatial_query.get());
-        }
-
-        return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance, bearing, bearing_range);
-    }
-
-    std::vector<PhantomNodeWithDistance>
-    NearestPhantomNodes(const FixedPointCoordinate &input_coordinate,
-                        const unsigned max_results,
-                        const int bearing = 0,
-                        const int bearing_range = 180) override final
-    {
-        if (!m_static_rtree.get())
-        {
-            LoadRTree();
-            BOOST_ASSERT(m_geospatial_query.get());
-        }
-
-        return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, bearing, bearing_range);
-    }
-
-    std::pair<PhantomNode, PhantomNode>
-    NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate,
-                                                      const int bearing = 0,
-                                                      const int bearing_range = 180) override final
-    {
-        if (!m_static_rtree.get())
-        {
-            LoadRTree();
-            BOOST_ASSERT(m_geospatial_query.get());
-        }
-
-        return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(input_coordinate, bearing, bearing_range);
-    }
-
-
-    unsigned GetCheckSum() const override final { return m_check_sum; }
-
-    unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
-    {
-        return m_name_ID_list.at(id);
-    }
-
-    std::string get_name_for_id(const unsigned name_id) const override final
-    {
-        if (std::numeric_limits<unsigned>::max() == name_id)
-        {
-            return "";
-        }
-        auto range = m_name_table.GetRange(name_id);
-
-        std::string result;
-        result.reserve(range.size());
-        if (range.begin() != range.end())
-        {
-            result.resize(range.back() - range.front() + 1);
-            std::copy(m_names_char_list.begin() + range.front(),
-                      m_names_char_list.begin() + range.back() + 1, result.begin());
-        }
-        return result;
-    }
-
-    virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const override final
-    {
-        return m_via_node_list.at(id);
-    }
-
-    virtual std::size_t GetCoreSize() const override final
-    {
-        return m_is_core_node.size();
-    }
-
-    virtual bool IsCoreNode(const NodeID id) const override final
-    {
-        if (m_is_core_node.size() > 0)
-        {
-            return m_is_core_node[id];
-        }
-        else
-        {
-            return false;
-        }
-    }
-
-    virtual void GetUncompressedGeometry(const unsigned id,
-                                         std::vector<unsigned> &result_nodes) const override final
-    {
-        const unsigned begin = m_geometry_indices.at(id);
-        const unsigned end = m_geometry_indices.at(id + 1);
-
-        result_nodes.clear();
-        result_nodes.insert(result_nodes.begin(), m_geometry_list.begin() + begin,
-                            m_geometry_list.begin() + end);
-    }
-
-    std::string GetTimestamp() const override final { return m_timestamp; }
-};
-
-#endif // INTERNAL_DATAFACADE_HPP
diff --git a/server/data_structures/shared_barriers.hpp b/server/data_structures/shared_barriers.hpp
deleted file mode 100644
index e6f1234..0000000
--- a/server/data_structures/shared_barriers.hpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 SHARED_BARRIERS_HPP
-#define SHARED_BARRIERS_HPP
-
-#include <boost/interprocess/sync/named_mutex.hpp>
-#include <boost/interprocess/sync/named_condition.hpp>
-
-struct SharedBarriers
-{
-
-    SharedBarriers()
-        : pending_update_mutex(boost::interprocess::open_or_create, "pending_update"),
-          update_mutex(boost::interprocess::open_or_create, "update"),
-          query_mutex(boost::interprocess::open_or_create, "query"),
-          no_running_queries_condition(boost::interprocess::open_or_create, "no_running_queries"),
-          update_ongoing(false), number_of_queries(0)
-    {
-    }
-
-    // Mutex to protect access to the boolean variable
-    boost::interprocess::named_mutex pending_update_mutex;
-    boost::interprocess::named_mutex update_mutex;
-    boost::interprocess::named_mutex query_mutex;
-
-    // Condition that no update is running
-    boost::interprocess::named_condition no_running_queries_condition;
-
-    // Is there an ongoing update?
-    bool update_ongoing;
-    // Is there any query?
-    int number_of_queries;
-};
-
-#endif // SHARED_BARRIERS_HPP
diff --git a/server/data_structures/shared_datafacade.hpp b/server/data_structures/shared_datafacade.hpp
deleted file mode 100644
index 4bbf076..0000000
--- a/server/data_structures/shared_datafacade.hpp
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 SHARED_DATAFACADE_HPP
-#define SHARED_DATAFACADE_HPP
-
-// implements all data storage when shared memory _IS_ used
-
-#include "datafacade_base.hpp"
-#include "shared_datatype.hpp"
-
-#include "../../algorithms/geospatial_query.hpp"
-#include "../../data_structures/range_table.hpp"
-#include "../../data_structures/static_graph.hpp"
-#include "../../data_structures/static_rtree.hpp"
-#include "../../util/make_unique.hpp"
-#include "../../util/simple_logger.hpp"
-
-#include <boost/thread.hpp>
-
-#include <algorithm>
-#include <limits>
-#include <memory>
-
-template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade<EdgeDataT>
-{
-
-  private:
-    using EdgeData = EdgeDataT;
-    using super = BaseDataFacade<EdgeData>;
-    using QueryGraph = StaticGraph<EdgeData, true>;
-    using GraphNode = typename StaticGraph<EdgeData, true>::NodeArrayEntry;
-    using GraphEdge = typename StaticGraph<EdgeData, true>::EdgeArrayEntry;
-    using NameIndexBlock = typename RangeTable<16, true>::BlockT;
-    using InputEdge = typename QueryGraph::InputEdge;
-    using RTreeLeaf = typename super::RTreeLeaf;
-    using SharedRTree = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>;
-    using SharedGeospatialQuery = GeospatialQuery<SharedRTree>;
-    using TimeStampedRTreePair = std::pair<unsigned, std::shared_ptr<SharedRTree>>;
-    using RTreeNode = typename SharedRTree::TreeNode;
-
-    SharedDataLayout *data_layout;
-    char *shared_memory;
-    SharedDataTimestamp *data_timestamp_ptr;
-
-    SharedDataType CURRENT_LAYOUT;
-    SharedDataType CURRENT_DATA;
-    unsigned CURRENT_TIMESTAMP;
-
-    unsigned m_check_sum;
-    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_edge_is_compressed;
-    ShM<unsigned, true>::vector m_geometry_indices;
-    ShM<unsigned, true>::vector m_geometry_list;
-    ShM<bool, true>::vector m_is_core_node;
-
-    boost::thread_specific_ptr<std::pair<unsigned, std::shared_ptr<SharedRTree>>> m_static_rtree;
-    boost::thread_specific_ptr<SharedGeospatialQuery> m_geospatial_query;
-    boost::filesystem::path file_index_path;
-
-    std::shared_ptr<RangeTable<16, true>> m_name_table;
-
-    void LoadChecksum()
-    {
-        m_check_sum =
-            *data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::HSGR_CHECKSUM);
-        SimpleLogger().Write() << "set checksum: " << m_check_sum;
-    }
-
-    void LoadTimestamp()
-    {
-        char *timestamp_ptr =
-            data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::TIMESTAMP);
-        m_timestamp.resize(data_layout->GetBlockSize(SharedDataLayout::TIMESTAMP));
-        std::copy(timestamp_ptr,
-                  timestamp_ptr + data_layout->GetBlockSize(SharedDataLayout::TIMESTAMP),
-                  m_timestamp.begin());
-    }
-
-    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.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_geospatial_query.reset(new SharedGeospatialQuery(*m_static_rtree->second, m_coordinate_list));
-    }
-
-    void LoadGraph()
-    {
-        GraphNode *graph_nodes_ptr =
-            data_layout->GetBlockPtr<GraphNode>(shared_memory, SharedDataLayout::GRAPH_NODE_LIST);
-
-        GraphEdge *graph_edges_ptr =
-            data_layout->GetBlockPtr<GraphEdge>(shared_memory, SharedDataLayout::GRAPH_EDGE_LIST);
-
-        typename ShM<GraphNode, true>::vector node_list(
-            graph_nodes_ptr, data_layout->num_entries[SharedDataLayout::GRAPH_NODE_LIST]);
-        typename ShM<GraphEdge, true>::vector edge_list(
-            graph_edges_ptr, data_layout->num_entries[SharedDataLayout::GRAPH_EDGE_LIST]);
-        m_query_graph.reset(new QueryGraph(node_list, edge_list));
-    }
-
-    void LoadNodeAndEdgeInformation()
-    {
-
-        FixedPointCoordinate *coordinate_list_ptr = data_layout->GetBlockPtr<FixedPointCoordinate>(
-            shared_memory, SharedDataLayout::COORDINATE_LIST);
-        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(
-            turn_instruction_list_ptr,
-            data_layout->num_entries[SharedDataLayout::TURN_INSTRUCTION]);
-        m_turn_instruction_list.swap(turn_instruction_list);
-
-        unsigned *name_id_list_ptr =
-            data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::NAME_ID_LIST);
-        typename ShM<unsigned, true>::vector name_id_list(
-            name_id_list_ptr, data_layout->num_entries[SharedDataLayout::NAME_ID_LIST]);
-        m_name_ID_list.swap(name_id_list);
-    }
-
-    void LoadViaNodeList()
-    {
-        NodeID *via_node_list_ptr =
-            data_layout->GetBlockPtr<NodeID>(shared_memory, SharedDataLayout::VIA_NODE_LIST);
-        typename ShM<NodeID, true>::vector via_node_list(
-            via_node_list_ptr, data_layout->num_entries[SharedDataLayout::VIA_NODE_LIST]);
-        m_via_node_list.swap(via_node_list);
-    }
-
-    void LoadNames()
-    {
-        unsigned *offsets_ptr =
-            data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::NAME_OFFSETS);
-        NameIndexBlock *blocks_ptr =
-            data_layout->GetBlockPtr<NameIndexBlock>(shared_memory, SharedDataLayout::NAME_BLOCKS);
-        typename ShM<unsigned, true>::vector name_offsets(
-            offsets_ptr, data_layout->num_entries[SharedDataLayout::NAME_OFFSETS]);
-        typename ShM<NameIndexBlock, true>::vector name_blocks(
-            blocks_ptr, data_layout->num_entries[SharedDataLayout::NAME_BLOCKS]);
-
-        char *names_list_ptr =
-            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 = 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);
-    }
-
-    void LoadCoreInformation()
-    {
-        if (data_layout->num_entries[SharedDataLayout::CORE_MARKER] <= 0)
-        {
-            return;
-        }
-
-        unsigned *core_marker_ptr = data_layout->GetBlockPtr<unsigned>(
-            shared_memory, SharedDataLayout::CORE_MARKER);
-        typename ShM<bool, true>::vector is_core_node(
-            core_marker_ptr,
-            data_layout->num_entries[SharedDataLayout::CORE_MARKER]);
-        m_is_core_node.swap(is_core_node);
-    }
-
-    void LoadGeometries()
-    {
-        unsigned *geometries_compressed_ptr = data_layout->GetBlockPtr<unsigned>(
-            shared_memory, SharedDataLayout::GEOMETRIES_INDICATORS);
-        typename ShM<bool, true>::vector edge_is_compressed(
-            geometries_compressed_ptr,
-            data_layout->num_entries[SharedDataLayout::GEOMETRIES_INDICATORS]);
-        m_edge_is_compressed.swap(edge_is_compressed);
-
-        unsigned *geometries_index_ptr =
-            data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::GEOMETRIES_INDEX);
-        typename ShM<unsigned, true>::vector geometry_begin_indices(
-            geometries_index_ptr, data_layout->num_entries[SharedDataLayout::GEOMETRIES_INDEX]);
-        m_geometry_indices.swap(geometry_begin_indices);
-
-        unsigned *geometries_list_ptr =
-            data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::GEOMETRIES_LIST);
-        typename ShM<unsigned, true>::vector geometry_list(
-            geometries_list_ptr, data_layout->num_entries[SharedDataLayout::GEOMETRIES_LIST]);
-        m_geometry_list.swap(geometry_list);
-    }
-
-  public:
-    virtual ~SharedDataFacade() {}
-
-    boost::shared_mutex data_mutex;
-
-    SharedDataFacade()
-    {
-        if (!SharedMemory::RegionExists(CURRENT_REGIONS))
-        {
-            throw osrm::exception("No shared memory blocks found, have you forgotten to run osrm-datastore?");
-        }
-        data_timestamp_ptr = (SharedDataTimestamp *)SharedMemoryFactory::Get(
-                                 CURRENT_REGIONS, sizeof(SharedDataTimestamp), false, false)
-                                 ->Ptr();
-        CURRENT_LAYOUT = LAYOUT_NONE;
-        CURRENT_DATA = DATA_NONE;
-        CURRENT_TIMESTAMP = 0;
-
-        // load data
-        CheckAndReloadFacade();
-    }
-
-    void CheckAndReloadFacade()
-    {
-        if (CURRENT_LAYOUT != data_timestamp_ptr->layout ||
-            CURRENT_DATA != data_timestamp_ptr->data ||
-            CURRENT_TIMESTAMP != data_timestamp_ptr->timestamp)
-        {
-            // Get exclusive lock
-            SimpleLogger().Write(logDEBUG) << "Updates available, getting exclusive lock";
-            boost::unique_lock<boost::shared_mutex> lock(data_mutex);
-
-            if (CURRENT_LAYOUT != data_timestamp_ptr->layout ||
-                CURRENT_DATA != data_timestamp_ptr->data)
-            {
-                // release the previous shared memory segments
-                SharedMemory::Remove(CURRENT_LAYOUT);
-                SharedMemory::Remove(CURRENT_DATA);
-
-                CURRENT_LAYOUT = data_timestamp_ptr->layout;
-                CURRENT_DATA = data_timestamp_ptr->data;
-                CURRENT_TIMESTAMP = 0;  // Force trigger a reload
-
-                SimpleLogger().Write(logDEBUG) << "Current layout was different to new layout, swapping";
-            }
-            else
-            {
-                SimpleLogger().Write(logDEBUG) << "Current layout was same to new layout, not swapping";
-            }
-
-            if (CURRENT_TIMESTAMP != data_timestamp_ptr->timestamp)
-            {
-                CURRENT_TIMESTAMP = data_timestamp_ptr->timestamp;
-
-                SimpleLogger().Write(logDEBUG) << "Performing data reload";
-                m_layout_memory.reset(SharedMemoryFactory::Get(CURRENT_LAYOUT));
-
-                data_layout = (SharedDataLayout *) (m_layout_memory->Ptr());
-
-                m_large_memory.reset(SharedMemoryFactory::Get(CURRENT_DATA));
-                shared_memory = (char *) (m_large_memory->Ptr());
-
-                const char *file_index_ptr =
-                        data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::FILE_INDEX_PATH);
-                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 osrm::exception("Could not load leaf index file. "
-                                                  "Is any data loaded into shared memory?");
-                }
-
-                LoadGraph();
-                LoadChecksum();
-                LoadNodeAndEdgeInformation();
-                LoadGeometries();
-                LoadTimestamp();
-                LoadViaNodeList();
-                LoadNames();
-                LoadCoreInformation();
-
-                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";
-                    }
-                }
-            }
-            SimpleLogger().Write(logDEBUG) << "Releasing exclusive lock";
-        }
-    }
-
-    // search graph access
-    unsigned GetNumberOfNodes() const override final { return m_query_graph->GetNumberOfNodes(); }
-
-    unsigned GetNumberOfEdges() const override final { return m_query_graph->GetNumberOfEdges(); }
-
-    unsigned GetOutDegree(const NodeID n) const override final
-    {
-        return m_query_graph->GetOutDegree(n);
-    }
-
-    NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); }
-
-    EdgeDataT &GetEdgeData(const EdgeID e) const override final
-    {
-        return m_query_graph->GetEdgeData(e);
-    }
-
-    EdgeID BeginEdges(const NodeID n) const override final { return m_query_graph->BeginEdges(n); }
-
-    EdgeID EndEdges(const NodeID n) const override final { return m_query_graph->EndEdges(n); }
-
-    EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
-    {
-        return m_query_graph->GetAdjacentEdgeRange(node);
-    };
-
-    // searches for a specific edge
-    EdgeID FindEdge(const NodeID from, const NodeID to) const override final
-    {
-        return m_query_graph->FindEdge(from, to);
-    }
-
-    EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const override final
-    {
-        return m_query_graph->FindEdgeInEitherDirection(from, to);
-    }
-
-    EdgeID
-    FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const override final
-    {
-        return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
-    }
-
-    // node and edge information access
-    FixedPointCoordinate GetCoordinateOfNode(const NodeID id) const override final
-    {
-        return m_coordinate_list->at(id);
-    };
-
-    virtual bool EdgeIsCompressed(const unsigned id) const override final
-    {
-        return m_edge_is_compressed.at(id);
-    }
-
-    virtual void GetUncompressedGeometry(const unsigned id,
-                                         std::vector<unsigned> &result_nodes) const override final
-    {
-        const unsigned begin = m_geometry_indices.at(id);
-        const unsigned end = m_geometry_indices.at(id + 1);
-
-        result_nodes.clear();
-        result_nodes.insert(result_nodes.begin(), m_geometry_list.begin() + begin,
-                            m_geometry_list.begin() + end);
-    }
-
-    virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const override final
-    {
-        return m_via_node_list.at(id);
-    }
-
-    TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const override final
-    {
-        return m_turn_instruction_list.at(id);
-    }
-
-    TravelMode GetTravelModeForEdgeID(const unsigned id) const override final
-    {
-        return m_travel_mode_list.at(id);
-    }
-
-    std::vector<PhantomNodeWithDistance>
-    NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate,
-                               const float max_distance,
-                               const int bearing = 0,
-                               const int bearing_range = 180) override final
-    {
-        if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
-        {
-            LoadRTree();
-            BOOST_ASSERT(m_geospatial_query.get());
-        }
-
-        return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance, bearing, bearing_range);
-    }
-
-    std::vector<PhantomNodeWithDistance>
-    NearestPhantomNodes(const FixedPointCoordinate &input_coordinate,
-                        const unsigned max_results,
-                        const int bearing = 0,
-                        const int bearing_range = 180) override final
-    {
-        if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
-        {
-            LoadRTree();
-            BOOST_ASSERT(m_geospatial_query.get());
-        }
-
-        return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, bearing, bearing_range);
-    }
-
-    std::pair<PhantomNode, PhantomNode>
-    NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate,
-                                                      const int bearing = 0,
-                                                      const int bearing_range = 180) override final
-    {
-        if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
-        {
-            LoadRTree();
-            BOOST_ASSERT(m_geospatial_query.get());
-        }
-
-        return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(input_coordinate, bearing, bearing_range);
-    }
-
-    unsigned GetCheckSum() const override final { return m_check_sum; }
-
-    unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
-    {
-        return m_name_ID_list.at(id);
-    };
-
-    std::string get_name_for_id(const unsigned name_id) const override final
-    {
-        if (std::numeric_limits<unsigned>::max() == name_id)
-        {
-            return "";
-        }
-        auto range = m_name_table->GetRange(name_id);
-
-        std::string result;
-        result.reserve(range.size());
-        if (range.begin() != range.end())
-        {
-            result.resize(range.back() - range.front() + 1);
-            std::copy(m_names_char_list.begin() + range.front(),
-                      m_names_char_list.begin() + range.back() + 1, result.begin());
-        }
-        return result;
-    }
-
-    bool IsCoreNode(const NodeID id) const override final
-    {
-        if (m_is_core_node.size() > 0)
-        {
-            return m_is_core_node.at(id);
-        }
-
-        return false;
-    }
-
-    virtual std::size_t GetCoreSize() const override final
-    {
-        return m_is_core_node.size();
-    }
-
-    std::string GetTimestamp() const override final { return m_timestamp; }
-};
-
-#endif // SHARED_DATAFACADE_HPP
diff --git a/server/data_structures/shared_datatype.hpp b/server/data_structures/shared_datatype.hpp
deleted file mode 100644
index c0ad7d4..0000000
--- a/server/data_structures/shared_datatype.hpp
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 SHARED_DATA_TYPE_HPP
-#define SHARED_DATA_TYPE_HPP
-
-#include "../../util/osrm_exception.hpp"
-#include "../../util/simple_logger.hpp"
-
-#include <cstdint>
-
-#include <array>
-
-namespace
-{
-// Added at the start and end of each block as sanity check
-static const char CANARY[] = "OSRM";
-}
-
-struct SharedDataLayout
-{
-    enum BlockID
-    {
-        NAME_OFFSETS = 0,
-        NAME_BLOCKS,
-        NAME_CHAR_LIST,
-        NAME_ID_LIST,
-        VIA_NODE_LIST,
-        GRAPH_NODE_LIST,
-        GRAPH_EDGE_LIST,
-        COORDINATE_LIST,
-        TURN_INSTRUCTION,
-        TRAVEL_MODE,
-        R_SEARCH_TREE,
-        GEOMETRIES_INDEX,
-        GEOMETRIES_LIST,
-        GEOMETRIES_INDICATORS,
-        HSGR_CHECKSUM,
-        TIMESTAMP,
-        FILE_INDEX_PATH,
-        CORE_MARKER,
-        NUM_BLOCKS
-    };
-
-    std::array<uint64_t, NUM_BLOCKS> num_entries;
-    std::array<uint64_t, NUM_BLOCKS> entry_size;
-
-    SharedDataLayout() : num_entries(), entry_size() {}
-
-    void PrintInformation() const
-    {
-        SimpleLogger().Write(logDEBUG) << "NAME_OFFSETS         "
-                                       << ": " << GetBlockSize(NAME_OFFSETS);
-        SimpleLogger().Write(logDEBUG) << "NAME_BLOCKS          "
-                                       << ": " << GetBlockSize(NAME_BLOCKS);
-        SimpleLogger().Write(logDEBUG) << "NAME_CHAR_LIST       "
-                                       << ": " << GetBlockSize(NAME_CHAR_LIST);
-        SimpleLogger().Write(logDEBUG) << "NAME_ID_LIST         "
-                                       << ": " << GetBlockSize(NAME_ID_LIST);
-        SimpleLogger().Write(logDEBUG) << "VIA_NODE_LIST        "
-                                       << ": " << GetBlockSize(VIA_NODE_LIST);
-        SimpleLogger().Write(logDEBUG) << "GRAPH_NODE_LIST      "
-                                       << ": " << GetBlockSize(GRAPH_NODE_LIST);
-        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);
-        SimpleLogger().Write(logDEBUG) << "GEOMETRIES_INDICATORS"
-                                       << ": " << GetBlockSize(GEOMETRIES_INDICATORS);
-        SimpleLogger().Write(logDEBUG) << "HSGR_CHECKSUM        "
-                                       << ": " << GetBlockSize(HSGR_CHECKSUM);
-        SimpleLogger().Write(logDEBUG) << "TIMESTAMP            "
-                                       << ": " << GetBlockSize(TIMESTAMP);
-        SimpleLogger().Write(logDEBUG) << "FILE_INDEX_PATH      "
-                                       << ": " << GetBlockSize(FILE_INDEX_PATH);
-        SimpleLogger().Write(logDEBUG) << "CORE_MARKER          "
-                                       << ": " << GetBlockSize(CORE_MARKER);
-    }
-
-    template <typename T> inline void SetBlockSize(BlockID bid, uint64_t entries)
-    {
-        num_entries[bid] = entries;
-        entry_size[bid] = sizeof(T);
-    }
-
-    inline uint64_t GetBlockSize(BlockID bid) const
-    {
-        // special bit encoding
-        if (bid == GEOMETRIES_INDICATORS || bid == CORE_MARKER)
-        {
-            return (num_entries[bid] / 32 + 1) *
-                   entry_size[bid];
-        }
-
-        return num_entries[bid] * entry_size[bid];
-    }
-
-    inline uint64_t GetSizeOfLayout() const
-    {
-        return GetBlockOffset(NUM_BLOCKS) + NUM_BLOCKS * 2 * sizeof(CANARY);
-    }
-
-    inline uint64_t GetBlockOffset(BlockID bid) const
-    {
-        uint64_t result = sizeof(CANARY);
-        for (auto i = 0; i < bid; i++)
-        {
-            result += GetBlockSize((BlockID)i) + 2 * sizeof(CANARY);
-        }
-        return result;
-    }
-
-    template <typename T, bool WRITE_CANARY = false>
-    inline T *GetBlockPtr(char *shared_memory, BlockID bid)
-    {
-        T *ptr = (T *)(shared_memory + GetBlockOffset(bid));
-        if (WRITE_CANARY)
-        {
-            char *start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
-            char *end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
-            std::copy(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
-            std::copy(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
-        }
-        else
-        {
-            char *start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
-            char *end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
-            bool start_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
-            bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
-            if (!start_canary_alive)
-            {
-                throw osrm::exception("Start canary of block corrupted.");
-            }
-            if (!end_canary_alive)
-            {
-                throw osrm::exception("End canary of block corrupted.");
-            }
-        }
-
-        return ptr;
-    }
-};
-
-enum SharedDataType
-{
-    CURRENT_REGIONS,
-    LAYOUT_1,
-    DATA_1,
-    LAYOUT_2,
-    DATA_2,
-    LAYOUT_NONE,
-    DATA_NONE
-};
-
-struct SharedDataTimestamp
-{
-    SharedDataType layout;
-    SharedDataType data;
-    unsigned timestamp;
-};
-
-#endif /* SHARED_DATA_TYPE_HPP */
diff --git a/server/http/header.hpp b/server/http/header.hpp
deleted file mode 100644
index f2598ba..0000000
--- a/server/http/header.hpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 HEADER_HPP
-#define HEADER_HPP
-
-#include <string>
-#include <algorithm>
-
-namespace http
-{
-struct header
-{
-    // explicitly use default copy c'tor as adding move c'tor
-    header &operator=(const header &other) = default;
-    header(std::string name, std::string value) : name(std::move(name)), value(std::move(value)) {}
-    header(header &&other) : name(std::move(other.name)), value(std::move(other.value)) {}
-
-    void clear()
-    {
-        name.clear();
-        value.clear();
-    }
-
-    std::string name;
-    std::string value;
-};
-}
-
-#endif // HEADER_HPP
diff --git a/server/http/reply.hpp b/server/http/reply.hpp
deleted file mode 100644
index 733818c..0000000
--- a/server/http/reply.hpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 REPLY_HPP
-#define REPLY_HPP
-
-#include "header.hpp"
-
-#include <boost/asio.hpp>
-
-#include <vector>
-
-namespace http
-{
-class reply
-{
-  public:
-    enum status_type
-    {
-        ok = 200,
-        bad_request = 400,
-        internal_server_error = 500
-    } status;
-
-    std::vector<header> headers;
-    std::vector<boost::asio::const_buffer> to_buffers();
-    std::vector<boost::asio::const_buffer> headers_to_buffers();
-    std::vector<char> content;
-    static reply stock_reply(const status_type status);
-    void set_size(const std::size_t size);
-    void set_uncompressed_size();
-
-    reply();
-
-  private:
-    std::string status_to_string(reply::status_type status);
-    boost::asio::const_buffer status_to_buffer(reply::status_type status);
-};
-}
-
-#endif // REPLY_HPP
diff --git a/server/http/request.hpp b/server/http/request.hpp
deleted file mode 100644
index c487fba..0000000
--- a/server/http/request.hpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 REQUEST_HPP
-#define REQUEST_HPP
-
-#include <boost/asio.hpp>
-
-#include <string>
-
-namespace http
-{
-
-struct request
-{
-    std::string uri;
-    std::string referrer;
-    std::string agent;
-    boost::asio::ip::address endpoint;
-};
-
-} // namespace http
-
-#endif // REQUEST_HPP
diff --git a/server/request_handler.cpp b/server/request_handler.cpp
deleted file mode 100644
index 54f0395..0000000
--- a/server/request_handler.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "request_handler.hpp"
-
-#include "api_grammar.hpp"
-#include "http/reply.hpp"
-#include "http/request.hpp"
-
-#include "../util/json_renderer.hpp"
-#include "../util/simple_logger.hpp"
-#include "../util/string_util.hpp"
-#include "../util/xml_renderer.hpp"
-#include "../typedefs.h"
-
-#include <osrm/route_parameters.hpp>
-#include <osrm/json_container.hpp>
-#include <osrm/osrm.hpp>
-
-#include <ctime>
-
-#include <algorithm>
-#include <iostream>
-#include <string>
-
-RequestHandler::RequestHandler() : routing_machine(nullptr) {}
-
-void RequestHandler::handle_request(const http::request &current_request,
-                                    http::reply &current_reply)
-{
-    osrm::json::Object json_result;
-
-    // parse command
-    try
-    {
-        std::string request_string;
-        URIDecode(current_request.uri, request_string);
-
-        // deactivated as GCC apparently does not implement that, not even in 4.9
-        // std::time_t t = std::time(nullptr);
-        // SimpleLogger().Write() << std::put_time(std::localtime(&t), "%m-%d-%Y %H:%M:%S") <<
-        //     " " << current_request.endpoint.to_string() << " " <<
-        //     current_request.referrer << ( 0 == current_request.referrer.length() ? "- " :" ") <<
-        //     current_request.agent << ( 0 == current_request.agent.length() ? "- " :" ") <<
-        //     request;
-
-        time_t ltime;
-        struct tm *time_stamp;
-
-        ltime = time(nullptr);
-        time_stamp = localtime(&ltime);
-
-        // log timestamp
-        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 << " " << current_request.endpoint.to_string()
-                               << " " << current_request.referrer
-                               << (0 == current_request.referrer.length() ? "- " : " ")
-                               << current_request.agent
-                               << (0 == current_request.agent.length() ? "- " : " ")
-                               << request_string;
-
-        RouteParameters route_parameters;
-        APIGrammarParser api_parser(&route_parameters);
-
-        auto api_iterator = request_string.begin();
-        const bool result =
-            boost::spirit::qi::parse(api_iterator, request_string.end(), api_parser);
-
-        // check if the was an error with the request
-        if (result && api_iterator == request_string.end())
-        {
-            // parsing done, lets call the right plugin to handle the request
-            BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed");
-
-            if (!route_parameters.jsonp_parameter.empty())
-            { // prepend response with jsonp parameter
-                const std::string json_p = (route_parameters.jsonp_parameter + "(");
-                current_reply.content.insert(current_reply.content.end(), json_p.begin(), json_p.end());
-            }
-
-            const int return_code = routing_machine->RunQuery(route_parameters, json_result);
-            json_result.values["status"] = return_code;
-            // 4xx bad request return code
-            if (return_code / 100 == 4)
-            {
-                current_reply.status = http::reply::bad_request;
-                current_reply.content.clear();
-                route_parameters.output_format.clear();
-            }
-            else
-            {
-                // 2xx valid request
-                BOOST_ASSERT(return_code / 100 == 2);
-            }
-        }
-        else
-        {
-            const auto position = std::distance(request_string.begin(), api_iterator);
-
-            current_reply.status = http::reply::bad_request;
-            json_result.values["status"] = http::reply::bad_request;
-            json_result.values["status_message"] = "Query string malformed close to position " + std::to_string(position);
-        }
-
-        current_reply.headers.emplace_back("Access-Control-Allow-Origin", "*");
-        current_reply.headers.emplace_back("Access-Control-Allow-Methods", "GET");
-        current_reply.headers.emplace_back("Access-Control-Allow-Headers",
-                                           "X-Requested-With, Content-Type");
-
-        // set headers
-        current_reply.headers.emplace_back("Content-Length",
-                                           std::to_string(current_reply.content.size()));
-        if ("gpx" == route_parameters.output_format)
-        { // gpx file
-            osrm::json::gpx_render(current_reply.content, json_result.values["route"]);
-            current_reply.headers.emplace_back("Content-Type",
-                                               "application/gpx+xml; charset=UTF-8");
-            current_reply.headers.emplace_back("Content-Disposition",
-                                               "attachment; filename=\"route.gpx\"");
-        }
-        else if (route_parameters.jsonp_parameter.empty())
-        { // json file
-            osrm::json::render(current_reply.content, json_result);
-            current_reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8");
-            current_reply.headers.emplace_back("Content-Disposition",
-                                               "inline; filename=\"response.json\"");
-        }
-        else
-        { // jsonp
-            osrm::json::render(current_reply.content, json_result);
-            current_reply.headers.emplace_back("Content-Type", "text/javascript; charset=UTF-8");
-            current_reply.headers.emplace_back("Content-Disposition",
-                                               "inline; filename=\"response.js\"");
-        }
-        if (!route_parameters.jsonp_parameter.empty())
-        { // append brace to jsonp response
-            current_reply.content.push_back(')');
-        }
-    }
-    catch (const std::exception &e)
-    {
-        current_reply = http::reply::stock_reply(http::reply::internal_server_error);;
-        SimpleLogger().Write(logWARNING) << "[server error] code: " << e.what()
-                                         << ", uri: " << current_request.uri;
-    }
-}
-
-void RequestHandler::RegisterRoutingMachine(OSRM *osrm) { routing_machine = osrm; }
diff --git a/server/request_handler.hpp b/server/request_handler.hpp
deleted file mode 100644
index b4019db..0000000
--- a/server/request_handler.hpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 REQUEST_HANDLER_HPP
-#define REQUEST_HANDLER_HPP
-
-#include <string>
-
-template <typename Iterator, class HandlerT> struct APIGrammar;
-struct RouteParameters;
-class OSRM;
-
-namespace http
-{
-class reply;
-struct request;
-}
-
-class RequestHandler
-{
-
-  public:
-    using APIGrammarParser = APIGrammar<std::string::iterator, RouteParameters>;
-
-    RequestHandler();
-    RequestHandler(const RequestHandler &) = delete;
-
-    void handle_request(const http::request &current_request, http::reply &current_reply);
-    void RegisterRoutingMachine(OSRM *osrm);
-
-  private:
-    OSRM *routing_machine;
-};
-
-#endif // REQUEST_HANDLER_HPP
diff --git a/server/request_parser.cpp b/server/request_parser.cpp
deleted file mode 100644
index b52d730..0000000
--- a/server/request_parser.cpp
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "request_parser.hpp"
-
-#include "http/compression_type.hpp"
-#include "http/header.hpp"
-#include "http/request.hpp"
-
-#include "../data_structures/tribool.hpp"
-
-#include <boost/algorithm/string/predicate.hpp>
-
-#include <string>
-
-namespace http
-{
-
-RequestParser::RequestParser()
-    : state(internal_state::method_start), current_header({"", ""}),
-      selected_compression(no_compression), is_post_header(false),
-      content_length(0)
-{
-}
-
-std::tuple<osrm::tribool, compression_type>
-RequestParser::parse(request &current_request, char *begin, char *end)
-{
-    while (begin != end)
-    {
-        osrm::tribool result = consume(current_request, *begin++);
-        if (result != osrm::tribool::indeterminate)
-        {
-            return std::make_tuple(result, selected_compression);
-        }
-    }
-    osrm::tribool result = osrm::tribool::indeterminate;
-    
-    if(state == internal_state::post_request && content_length <= 0)
-    {
-        result = osrm::tribool::yes;
-    }
-    return std::make_tuple(result, selected_compression);
-}
-
-osrm::tribool RequestParser::consume(request &current_request, const char input)
-{
-    switch (state)
-    {
-    case internal_state::method_start:
-        if (!is_char(input) || is_CTL(input) || is_special(input))
-        {
-            return osrm::tribool::no;
-        }
-        if(input == 'P')
-        {
-            state = internal_state::post_O;
-            return osrm::tribool::indeterminate;
-        }
-        state = internal_state::method;
-        return osrm::tribool::indeterminate;
-    case internal_state::post_O:
-        if(input == 'O')
-        {
-          state = internal_state::post_S;
-          return osrm::tribool::indeterminate;
-        }
-        return osrm::tribool::no;
-    case internal_state::post_S:
-        if(input == 'S')
-        {
-          state = internal_state::post_T;
-          return osrm::tribool::indeterminate;
-        }
-        return osrm::tribool::no;
-    case internal_state::post_T:
-        if(input == 'T')
-        {
-          is_post_header = true;
-          state = internal_state::method;
-          return osrm::tribool::indeterminate;
-        }
-        return osrm::tribool::no;
-    case internal_state::post_request:
-        current_request.uri.push_back(input);
-        --content_length;
-        return osrm::tribool::indeterminate;
-    case internal_state::method:
-        if (input == ' ')
-        {
-            state = internal_state::uri;
-            return osrm::tribool::indeterminate;
-        }
-        if (!is_char(input) || is_CTL(input) || is_special(input))
-        {
-            return osrm::tribool::no;
-        }
-        return osrm::tribool::indeterminate;
-    case internal_state::uri_start:
-        if (is_CTL(input))
-        {
-            return osrm::tribool::no;
-        }
-        state = internal_state::uri;
-        current_request.uri.push_back(input);
-        return osrm::tribool::indeterminate;
-    case internal_state::uri:
-        if (input == ' ')
-        {
-            state = internal_state::http_version_h;
-            return osrm::tribool::indeterminate;
-        }
-        if (is_CTL(input))
-        {
-            return osrm::tribool::no;
-        }
-        current_request.uri.push_back(input);
-        return osrm::tribool::indeterminate;
-    case internal_state::http_version_h:
-        if (input == 'H')
-        {
-            state = internal_state::http_version_t_1;
-            return osrm::tribool::indeterminate;
-        }
-        return osrm::tribool::no;
-    case internal_state::http_version_t_1:
-        if (input == 'T')
-        {
-            state = internal_state::http_version_t_2;
-            return osrm::tribool::indeterminate;
-        }
-        return osrm::tribool::no;
-    case internal_state::http_version_t_2:
-        if (input == 'T')
-        {
-            state = internal_state::http_version_p;
-            return osrm::tribool::indeterminate;
-        }
-        return osrm::tribool::no;
-    case internal_state::http_version_p:
-        if (input == 'P')
-        {
-            state = internal_state::http_version_slash;
-            return osrm::tribool::indeterminate;
-        }
-        return osrm::tribool::no;
-    case internal_state::http_version_slash:
-        if (input == '/')
-        {
-            state = internal_state::http_version_major_start;
-            return osrm::tribool::indeterminate;
-        }
-        return osrm::tribool::no;
-    case internal_state::http_version_major_start:
-        if (is_digit(input))
-        {
-            state = internal_state::http_version_major;
-            return osrm::tribool::indeterminate;
-        }
-        return osrm::tribool::no;
-    case internal_state::http_version_major:
-        if (input == '.')
-        {
-            state = internal_state::http_version_minor_start;
-            return osrm::tribool::indeterminate;
-        }
-        if (is_digit(input))
-        {
-            return osrm::tribool::indeterminate;
-        }
-        return osrm::tribool::no;
-    case internal_state::http_version_minor_start:
-        if (is_digit(input))
-        {
-            state = internal_state::http_version_minor;
-            return osrm::tribool::indeterminate;
-        }
-        return osrm::tribool::no;
-    case internal_state::http_version_minor:
-        if (input == '\r')
-        {
-            state = internal_state::expecting_newline_1;
-            return osrm::tribool::indeterminate;
-        }
-        if (is_digit(input))
-        {
-            return osrm::tribool::indeterminate;
-        }
-        return osrm::tribool::no;
-    case internal_state::expecting_newline_1:
-        if (input == '\n')
-        {
-            state = internal_state::header_line_start;
-            return osrm::tribool::indeterminate;
-        }
-        return osrm::tribool::no;
-    case internal_state::header_line_start:
-        if (boost::iequals(current_header.name, "Accept-Encoding"))
-        {
-            /* giving gzip precedence over deflate */
-            if (boost::icontains(current_header.value, "deflate"))
-            {
-                selected_compression = deflate_rfc1951;
-            }
-            if (boost::icontains(current_header.value, "gzip"))
-            {
-                selected_compression = gzip_rfc1952;
-            }
-        }
-
-        if (boost::iequals(current_header.name, "Referer"))
-        {
-            current_request.referrer = current_header.value;
-        }
-
-        if (boost::iequals(current_header.name, "User-Agent"))
-        {
-            current_request.agent = current_header.value;
-        }
-        if (boost::iequals(current_header.name, "Content-Length"))
-        {
-            try 
-            {
-                content_length = std::stoi(current_header.value);
-            }
-            catch (const std::exception &e)
-            {
-                // Ignore the header if the parameter isn't an int
-            }
-        }
-        if (boost::iequals(current_header.name, "Content-Type"))
-        {
-            if (!boost::icontains(current_header.value, "application/x-www-form-urlencoded"))
-            {
-                return osrm::tribool::no;
-            }
-        }
-
-        if (input == '\r')
-        {
-            state = internal_state::expecting_newline_3;
-            return osrm::tribool::indeterminate;
-        }
-        if (!is_char(input) || is_CTL(input) || is_special(input))
-        {
-            return osrm::tribool::no;
-        }
-        state = internal_state::header_name;
-        current_header.clear();
-        current_header.name.push_back(input);
-        return osrm::tribool::indeterminate;
-    case internal_state::header_lws:
-        if (input == '\r')
-        {
-            state = internal_state::expecting_newline_2;
-            return osrm::tribool::indeterminate;
-        }
-        if (input == ' ' || input == '\t')
-        {
-            return osrm::tribool::indeterminate;
-        }
-        if (is_CTL(input))
-        {
-            return osrm::tribool::no;
-        }
-        state = internal_state::header_value;
-        return osrm::tribool::indeterminate;
-    case internal_state::header_name:
-        if (input == ':')
-        {
-            state = internal_state::space_before_header_value;
-            return osrm::tribool::indeterminate;
-        }
-        if (!is_char(input) || is_CTL(input) || is_special(input))
-        {
-            return osrm::tribool::no;
-        }
-        current_header.name.push_back(input);
-        return osrm::tribool::indeterminate;
-    case internal_state::space_before_header_value:
-        if (input == ' ')
-        {
-            state = internal_state::header_value;
-            return osrm::tribool::indeterminate;
-        }
-        return osrm::tribool::no;
-    case internal_state::header_value:
-        if (input == '\r')
-        {
-            state = internal_state::expecting_newline_2;
-            return osrm::tribool::indeterminate;
-        }
-        if (is_CTL(input))
-        {
-            return osrm::tribool::no;
-        }
-        current_header.value.push_back(input);
-        return osrm::tribool::indeterminate;
-    case internal_state::expecting_newline_2:
-        if (input == '\n')
-        {
-            state = internal_state::header_line_start;
-            return osrm::tribool::indeterminate;
-        }
-        return osrm::tribool::no;
-    case internal_state::expecting_newline_3:
-        if (input == '\n')
-        {
-            if (is_post_header)
-            {
-		if (content_length > 0)
-		{
-		    current_request.uri.push_back('?');
-		}
-                state = internal_state::post_request;
-                return osrm::tribool::indeterminate;
-            }
-            return osrm::tribool::yes;
-        }
-        return osrm::tribool::no;
-    default: // should never be reached
-        return input == '\n' ? osrm::tribool::yes : osrm::tribool::no;
-    }
-}
-
-bool RequestParser::is_char(const int character) const
-{
-    return character >= 0 && character <= 127;
-}
-
-bool RequestParser::is_CTL(const int character) const
-{
-    return (character >= 0 && character <= 31) || (character == 127);
-}
-
-bool RequestParser::is_special(const int character) const
-{
-    switch (character)
-    {
-    case '(':
-    case ')':
-    case '<':
-    case '>':
-    case '@':
-    case ',':
-    case ';':
-    case ':':
-    case '\\':
-    case '"':
-    case '/':
-    case '[':
-    case ']':
-    case '?':
-    case '=':
-    case '{':
-    case '}':
-    case ' ':
-    case '\t':
-        return true;
-    default:
-        return false;
-    }
-}
-
-bool RequestParser::is_digit(const int character) const
-{
-    return character >= '0' && character <= '9';
-}
-}
diff --git a/server/request_parser.hpp b/server/request_parser.hpp
deleted file mode 100644
index 3724613..0000000
--- a/server/request_parser.hpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 REQUEST_PARSER_HPP
-#define REQUEST_PARSER_HPP
-
-#include "http/compression_type.hpp"
-#include "http/header.hpp"
-#include "../data_structures/tribool.hpp"
-
-#include <tuple>
-
-namespace http
-{
-
-struct request;
-
-class RequestParser
-{
-  public:
-    RequestParser();
-
-    std::tuple<osrm::tribool, compression_type>
-    parse(request &current_request, char *begin, char *end);
-
-  private:
-    osrm::tribool consume(request &current_request, const char input);
-
-    bool is_char(const int character) const;
-
-    bool is_CTL(const int character) const;
-
-    bool is_special(const int character) const;
-
-    bool is_digit(const int character) const;
-
-    enum class internal_state : unsigned char
-    {
-        method_start,
-        method,
-        uri_start,
-        uri,
-        http_version_h,
-        http_version_t_1,
-        http_version_t_2,
-        http_version_p,
-        http_version_slash,
-        http_version_major_start,
-        http_version_major,
-        http_version_minor_start,
-        http_version_minor,
-        expecting_newline_1,
-        header_line_start,
-        header_lws,
-        header_name,
-        space_before_header_value,
-        header_value,
-        expecting_newline_2,
-        expecting_newline_3,
-        post_O,
-        post_S,
-        post_T,
-        post_request
-    } state;
-
-    header current_header;
-    compression_type selected_compression;
-    bool is_post_header;
-    int content_length;
-};
-
-} // namespace http
-
-#endif // REQUEST_PARSER_HPP
diff --git a/src/benchmarks/static_rtree.cpp b/src/benchmarks/static_rtree.cpp
new file mode 100644
index 0000000..32929eb
--- /dev/null
+++ b/src/benchmarks/static_rtree.cpp
@@ -0,0 +1,115 @@
+#include "engine/geospatial_query.hpp"
+#include "extractor/query_node.hpp"
+#include "extractor/edge_based_node.hpp"
+#include "util/static_rtree.hpp"
+#include "util/timing_util.hpp"
+#include "util/coordinate.hpp"
+#include "mocks/mock_datafacade.hpp"
+
+#include <iostream>
+#include <random>
+
+#include <boost/filesystem/fstream.hpp>
+
+namespace osrm
+{
+namespace benchmarks
+{
+
+using namespace osrm::test;
+
+// 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 = extractor::EdgeBasedNode;
+using CoordinateListPtr = std::shared_ptr<std::vector<util::Coordinate>>;
+using BenchStaticRTree =
+    util::StaticRTree<RTreeLeaf, util::ShM<util::Coordinate, false>::vector, false>;
+
+CoordinateListPtr loadCoordinates(const boost::filesystem::path &nodes_file)
+{
+    boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
+
+    extractor::QueryNode current_node;
+    unsigned coordinate_count = 0;
+    nodes_input_stream.read((char *)&coordinate_count, sizeof(unsigned));
+    auto coords = std::make_shared<std::vector<Coordinate>>(coordinate_count);
+    for (unsigned i = 0; i < coordinate_count; ++i)
+    {
+        nodes_input_stream.read((char *)&current_node, sizeof(extractor::QueryNode));
+        coords->at(i) = util::Coordinate(current_node.lon, current_node.lat);
+    }
+    return coords;
+}
+
+template <typename QueryT>
+void benchmarkQuery(const std::vector<util::Coordinate> &queries,
+                    const std::string &name,
+                    QueryT query)
+{
+    std::cout << "Running " << name << " with " << queries.size() << " coordinates: " << std::flush;
+
+    TIMER_START(query);
+    for (const auto &q : queries)
+    {
+        auto result = query(q);
+        (void)result;
+    }
+    TIMER_STOP(query);
+
+    std::cout << "Took " << TIMER_SEC(query) << " seconds "
+              << "(" << TIMER_MSEC(query) << "ms"
+              << ")  ->  " << TIMER_MSEC(query) / queries.size() << " ms/query "
+              << "(" << TIMER_MSEC(query) << "ms"
+              << ")" << std::endl;
+}
+
+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<util::Coordinate> queries;
+    for (unsigned i = 0; i < num_queries; i++)
+    {
+        queries.emplace_back(util::FixedLongitude{lon_udist(mt_rand)},
+                             util::FixedLatitude{lat_udist(mt_rand)});
+    }
+
+    benchmarkQuery(queries, "raw RTree queries (1 result)", [&rtree](const util::Coordinate &q)
+                   {
+                       return rtree.Nearest(q, 1);
+                   });
+    benchmarkQuery(queries, "raw RTree queries (10 results)", [&rtree](const util::Coordinate &q)
+                   {
+                       return rtree.Nearest(q, 10);
+                   });
+}
+}
+}
+
+int main(int argc, char **argv)
+{
+    if (argc < 4)
+    {
+        std::cout << "./rtree-bench file.ramIndex file.fileIndx file.nodes"
+                  << "\n";
+        return 1;
+    }
+
+    const char *ram_path = argv[1];
+    const char *file_path = argv[2];
+    const char *nodes_path = argv[3];
+
+    auto coords = osrm::benchmarks::loadCoordinates(nodes_path);
+
+    osrm::benchmarks::BenchStaticRTree rtree(ram_path, file_path, coords);
+
+    osrm::benchmarks::benchmark(rtree, 10000);
+
+    return 0;
+}
diff --git a/src/contractor/contractor.cpp b/src/contractor/contractor.cpp
new file mode 100644
index 0000000..39d6f48
--- /dev/null
+++ b/src/contractor/contractor.cpp
@@ -0,0 +1,686 @@
+#include "contractor/contractor.hpp"
+#include "contractor/crc32_processor.hpp"
+#include "contractor/graph_contractor.hpp"
+
+#include "extractor/node_based_edge.hpp"
+#include "extractor/compressed_edge_container.hpp"
+
+#include "util/static_graph.hpp"
+#include "util/static_rtree.hpp"
+#include "util/graph_loader.hpp"
+#include "util/io.hpp"
+#include "util/integer_range.hpp"
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+#include "util/string_util.hpp"
+#include "util/timing_util.hpp"
+#include "util/typedefs.hpp"
+
+#include <fast-cpp-csv-parser/csv.h>
+
+#include <boost/assert.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+#include <tbb/parallel_sort.h>
+
+#include <cstdint>
+#include <bitset>
+#include <chrono>
+#include <memory>
+#include <thread>
+#include <iterator>
+
+namespace std
+{
+
+template <> struct hash<std::pair<OSMNodeID, OSMNodeID>>
+{
+    std::size_t operator()(const std::pair<OSMNodeID, OSMNodeID> &k) const
+    {
+        return static_cast<uint64_t>(k.first) ^ (static_cast<uint64_t>(k.second) << 12);
+    }
+};
+}
+
+namespace osrm
+{
+namespace contractor
+{
+
+int Contractor::Run()
+{
+#ifdef WIN32
+#pragma message("Memory consumption on Windows can be higher due to different bit packing")
+#else
+    static_assert(sizeof(extractor::NodeBasedEdge) == 20,
+                  "changing extractor::NodeBasedEdge type has influence on memory consumption!");
+    static_assert(sizeof(extractor::EdgeBasedEdge) == 16,
+                  "changing EdgeBasedEdge type has influence on memory consumption!");
+#endif
+
+    if (config.core_factor > 1.0 || config.core_factor < 0)
+    {
+        throw util::exception("Core factor must be between 0.0 to 1.0 (inclusive)");
+    }
+
+    TIMER_START(preparing);
+
+    util::SimpleLogger().Write() << "Loading edge-expanded graph representation";
+
+    util::DeallocatingVector<extractor::EdgeBasedEdge> edge_based_edge_list;
+
+    std::size_t max_edge_id = LoadEdgeExpandedGraph(
+        config.edge_based_graph_path, edge_based_edge_list, config.edge_segment_lookup_path,
+        config.edge_penalty_path, config.segment_speed_lookup_paths, config.node_based_graph_path,
+        config.geometry_path, config.datasource_names_path, config.datasource_indexes_path,
+        config.rtree_leaf_path);
+
+    // Contracting the edge-expanded graph
+
+    TIMER_START(contraction);
+    std::vector<bool> is_core_node;
+    std::vector<float> node_levels;
+    if (config.use_cached_priority)
+    {
+        ReadNodeLevels(node_levels);
+    }
+
+    util::SimpleLogger().Write() << "Reading node weights.";
+    std::vector<EdgeWeight> node_weights;
+    std::string node_file_name = config.osrm_input_path.string() + ".enw";
+    if (util::deserializeVector(node_file_name, node_weights))
+    {
+        util::SimpleLogger().Write() << "Done reading node weights.";
+    }
+    else
+    {
+        throw util::exception("Failed reading node weights.");
+    }
+
+    util::DeallocatingVector<QueryEdge> contracted_edge_list;
+    ContractGraph(max_edge_id, edge_based_edge_list, contracted_edge_list, std::move(node_weights),
+                  is_core_node, node_levels);
+    TIMER_STOP(contraction);
+
+    util::SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
+
+    std::size_t number_of_used_edges = WriteContractedGraph(max_edge_id, contracted_edge_list);
+    WriteCoreNodeMarker(std::move(is_core_node));
+    if (!config.use_cached_priority)
+    {
+        WriteNodeLevels(std::move(node_levels));
+    }
+
+    TIMER_STOP(preparing);
+
+    util::SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
+    util::SimpleLogger().Write() << "Contraction: " << ((max_edge_id + 1) / TIMER_SEC(contraction))
+                                 << " nodes/sec and "
+                                 << number_of_used_edges / TIMER_SEC(contraction) << " edges/sec";
+
+    util::SimpleLogger().Write() << "finished preprocessing";
+
+    return 0;
+}
+
+std::size_t Contractor::LoadEdgeExpandedGraph(
+    std::string const &edge_based_graph_filename,
+    util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
+    const std::string &edge_segment_lookup_filename,
+    const std::string &edge_penalty_filename,
+    const std::vector<std::string> &segment_speed_filenames,
+    const std::string &nodes_filename,
+    const std::string &geometry_filename,
+    const std::string &datasource_names_filename,
+    const std::string &datasource_indexes_filename,
+    const std::string &rtree_leaf_filename)
+{
+    util::SimpleLogger().Write() << "Opening " << edge_based_graph_filename;
+    boost::filesystem::ifstream input_stream(edge_based_graph_filename, std::ios::binary);
+
+    const bool update_edge_weights = !segment_speed_filenames.empty();
+
+    boost::filesystem::ifstream edge_segment_input_stream;
+    boost::filesystem::ifstream edge_fixed_penalties_input_stream;
+
+    if (update_edge_weights)
+    {
+        edge_segment_input_stream.open(edge_segment_lookup_filename, std::ios::binary);
+        edge_fixed_penalties_input_stream.open(edge_penalty_filename, std::ios::binary);
+        if (!edge_segment_input_stream || !edge_fixed_penalties_input_stream)
+        {
+            throw util::exception("Could not load .edge_segment_lookup or .edge_penalties, did you "
+                                  "run osrm-extract with '--generate-edge-lookup'?");
+        }
+    }
+
+    const util::FingerPrint fingerprint_valid = util::FingerPrint::GetValid();
+    util::FingerPrint fingerprint_loaded;
+    input_stream.read((char *)&fingerprint_loaded, sizeof(util::FingerPrint));
+    fingerprint_loaded.TestContractor(fingerprint_valid);
+
+    // TODO std::size_t can vary on systems. Our files are not transferable, but we might want to
+    // consider using a fixed size type for I/O
+    std::size_t number_of_edges = 0;
+    std::size_t max_edge_id = SPECIAL_EDGEID;
+    input_stream.read((char *)&number_of_edges, sizeof(std::size_t));
+    input_stream.read((char *)&max_edge_id, sizeof(std::size_t));
+
+    edge_based_edge_list.resize(number_of_edges);
+    util::SimpleLogger().Write() << "Reading " << number_of_edges
+                                 << " edges from the edge based graph";
+
+    std::unordered_map<std::pair<OSMNodeID, OSMNodeID>, std::pair<unsigned, uint8_t>>
+        segment_speed_lookup;
+
+    // If we update the edge weights, this file will hold the datasource information
+    // for each segment
+    std::vector<uint8_t> m_geometry_datasource;
+
+    if (update_edge_weights)
+    {
+        uint8_t file_id = 1;
+        for (auto segment_speed_filename : segment_speed_filenames)
+        {
+            util::SimpleLogger().Write()
+                << "Segment speed data supplied, will update edge weights from "
+                << segment_speed_filename;
+            io::CSVReader<3> csv_in(segment_speed_filename);
+            csv_in.set_header("from_node", "to_node", "speed");
+            uint64_t from_node_id{};
+            uint64_t to_node_id{};
+            unsigned speed{};
+            while (csv_in.read_row(from_node_id, to_node_id, speed))
+            {
+                segment_speed_lookup[std::make_pair(OSMNodeID(from_node_id),
+                                                    OSMNodeID(to_node_id))] =
+                    std::make_pair(speed, file_id);
+            }
+            ++file_id;
+
+            // Check for overflow
+            if (file_id == 0)
+            {
+                throw util::exception(
+                    "Sorry, there's a limit of 254 segment speed files, you supplied too many");
+            }
+        }
+
+        std::vector<extractor::QueryNode> internal_to_external_node_map;
+
+        // Here, we have to update the compressed geometry weights
+        // First, we need the external-to-internal node lookup table
+        {
+            boost::filesystem::ifstream nodes_input_stream(nodes_filename, std::ios::binary);
+
+            if (!nodes_input_stream)
+            {
+                throw util::exception("Failed to open " + nodes_filename);
+            }
+
+            unsigned number_of_nodes = 0;
+            nodes_input_stream.read((char *)&number_of_nodes, sizeof(unsigned));
+            internal_to_external_node_map.resize(number_of_nodes);
+
+            // Load all the query nodes into a vector
+            nodes_input_stream.read(reinterpret_cast<char *>(&(internal_to_external_node_map[0])),
+                                    number_of_nodes * sizeof(extractor::QueryNode));
+        }
+
+        std::vector<unsigned> m_geometry_indices;
+        std::vector<extractor::CompressedEdgeContainer::CompressedEdge> m_geometry_list;
+
+        {
+            std::ifstream geometry_stream(geometry_filename, std::ios::binary);
+            if (!geometry_stream)
+            {
+                throw util::exception("Failed to open " + geometry_filename);
+            }
+            unsigned number_of_indices = 0;
+            unsigned number_of_compressed_geometries = 0;
+
+            geometry_stream.read((char *)&number_of_indices, sizeof(unsigned));
+
+            m_geometry_indices.resize(number_of_indices);
+            if (number_of_indices > 0)
+            {
+                geometry_stream.read((char *)&(m_geometry_indices[0]),
+                                     number_of_indices * sizeof(unsigned));
+            }
+
+            geometry_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
+
+            BOOST_ASSERT(m_geometry_indices.back() == number_of_compressed_geometries);
+            m_geometry_list.resize(number_of_compressed_geometries);
+
+            if (number_of_compressed_geometries > 0)
+            {
+                geometry_stream.read(
+                    (char *)&(m_geometry_list[0]),
+                    number_of_compressed_geometries *
+                        sizeof(extractor::CompressedEdgeContainer::CompressedEdge));
+            }
+        }
+
+        // This is a list of the "data source id" for every segment in the compressed
+        // geometry container.  We assume that everything so far has come from the
+        // profile (data source 0).  Here, we replace the 0's with the index of the
+        // CSV file that supplied the value that gets used for that segment, then
+        // we write out this list so that it can be returned by the debugging
+        // vector tiles later on.
+        m_geometry_datasource.resize(m_geometry_list.size(), 0);
+
+        // Now, we iterate over all the segments stored in the StaticRTree, updating
+        // the packed geometry weights in the `.geometries` file (note: we do not
+        // update the RTree itself, we just use the leaf nodes to iterate over all segments)
+        {
+
+            using LeafNode = util::StaticRTree<extractor::EdgeBasedNode>::LeafNode;
+
+            std::ifstream leaf_node_file(rtree_leaf_filename, std::ios::binary | std::ios::in);
+            if (!leaf_node_file)
+            {
+                throw util::exception("Failed to open " + rtree_leaf_filename);
+            }
+            uint64_t m_element_count;
+            leaf_node_file.read((char *)&m_element_count, sizeof(uint64_t));
+
+            LeafNode current_node;
+            while (m_element_count > 0)
+            {
+                leaf_node_file.read(reinterpret_cast<char *>(&current_node), sizeof(current_node));
+
+                for (size_t i = 0; i < current_node.object_count; i++)
+                {
+                    auto &leaf_object = current_node.objects[i];
+                    extractor::QueryNode *u;
+                    extractor::QueryNode *v;
+
+                    if (leaf_object.forward_packed_geometry_id != SPECIAL_EDGEID)
+                    {
+                        const unsigned forward_begin =
+                            m_geometry_indices.at(leaf_object.forward_packed_geometry_id);
+
+                        if (leaf_object.fwd_segment_position == 0)
+                        {
+                            u = &(internal_to_external_node_map[leaf_object.u]);
+                            v = &(internal_to_external_node_map[m_geometry_list[forward_begin]
+                                                                    .node_id]);
+                        }
+                        else
+                        {
+                            u = &(internal_to_external_node_map
+                                      [m_geometry_list[forward_begin +
+                                                       leaf_object.fwd_segment_position - 1]
+                                           .node_id]);
+                            v = &(internal_to_external_node_map
+                                      [m_geometry_list[forward_begin +
+                                                       leaf_object.fwd_segment_position]
+                                           .node_id]);
+                        }
+                        const double segment_length =
+                            util::coordinate_calculation::greatCircleDistance(
+                                util::Coordinate{u->lon, u->lat}, util::Coordinate{v->lon, v->lat});
+
+                        auto forward_speed_iter =
+                            segment_speed_lookup.find(std::make_pair(u->node_id, v->node_id));
+                        if (forward_speed_iter != segment_speed_lookup.end())
+                        {
+                            int new_segment_weight =
+                                std::max(1, static_cast<int>(std::floor(
+                                                (segment_length * 10.) /
+                                                    (forward_speed_iter->second.first / 3.6) +
+                                                .5)));
+                            m_geometry_list[forward_begin + leaf_object.fwd_segment_position]
+                                .weight = new_segment_weight;
+                            m_geometry_datasource[forward_begin +
+                                                  leaf_object.fwd_segment_position] =
+                                forward_speed_iter->second.second;
+                        }
+                    }
+                    if (leaf_object.reverse_packed_geometry_id != SPECIAL_EDGEID)
+                    {
+                        const unsigned reverse_begin =
+                            m_geometry_indices.at(leaf_object.reverse_packed_geometry_id);
+                        const unsigned reverse_end =
+                            m_geometry_indices.at(leaf_object.reverse_packed_geometry_id + 1);
+
+                        int rev_segment_position =
+                            (reverse_end - reverse_begin) - leaf_object.fwd_segment_position - 1;
+                        if (rev_segment_position == 0)
+                        {
+                            u = &(internal_to_external_node_map[leaf_object.v]);
+                            v = &(internal_to_external_node_map[m_geometry_list[reverse_begin]
+                                                                    .node_id]);
+                        }
+                        else
+                        {
+                            u = &(internal_to_external_node_map
+                                      [m_geometry_list[reverse_begin + rev_segment_position - 1]
+                                           .node_id]);
+                            v = &(
+                                internal_to_external_node_map[m_geometry_list[reverse_begin +
+                                                                              rev_segment_position]
+                                                                  .node_id]);
+                        }
+                        const double segment_length =
+                            util::coordinate_calculation::greatCircleDistance(
+                                util::Coordinate{u->lon, u->lat}, util::Coordinate{v->lon, v->lat});
+
+                        auto reverse_speed_iter =
+                            segment_speed_lookup.find(std::make_pair(u->node_id, v->node_id));
+                        if (reverse_speed_iter != segment_speed_lookup.end())
+                        {
+                            int new_segment_weight =
+                                std::max(1, static_cast<int>(std::floor(
+                                                (segment_length * 10.) /
+                                                    (reverse_speed_iter->second.first / 3.6) +
+                                                .5)));
+                            m_geometry_list[reverse_begin + rev_segment_position].weight =
+                                new_segment_weight;
+                            m_geometry_datasource[reverse_begin + rev_segment_position] =
+                                reverse_speed_iter->second.second;
+                        }
+                    }
+                }
+                m_element_count -= current_node.object_count;
+            }
+        }
+
+        // Now save out the updated compressed geometries
+        {
+            std::ofstream geometry_stream(geometry_filename, std::ios::binary);
+            if (!geometry_stream)
+            {
+                throw util::exception("Failed to open " + geometry_filename + " for writing");
+            }
+            const unsigned number_of_indices = m_geometry_indices.size();
+            const unsigned number_of_compressed_geometries = m_geometry_list.size();
+            geometry_stream.write(reinterpret_cast<const char *>(&number_of_indices),
+                                  sizeof(unsigned));
+            geometry_stream.write(reinterpret_cast<char *>(&(m_geometry_indices[0])),
+                                  number_of_indices * sizeof(unsigned));
+            geometry_stream.write(reinterpret_cast<const char *>(&number_of_compressed_geometries),
+                                  sizeof(unsigned));
+            geometry_stream.write(reinterpret_cast<char *>(&(m_geometry_list[0])),
+                                  number_of_compressed_geometries *
+                                      sizeof(extractor::CompressedEdgeContainer::CompressedEdge));
+        }
+    }
+
+    {
+        std::ofstream datasource_stream(datasource_indexes_filename, std::ios::binary);
+        if (!datasource_stream)
+        {
+            throw util::exception("Failed to open " + datasource_indexes_filename +
+                                  " for writing");
+        }
+        auto number_of_datasource_entries = m_geometry_datasource.size();
+        datasource_stream.write(reinterpret_cast<const char *>(&number_of_datasource_entries),
+                                sizeof(number_of_datasource_entries));
+        if (number_of_datasource_entries > 0)
+        {
+            datasource_stream.write(reinterpret_cast<char *>(&(m_geometry_datasource[0])),
+                                    number_of_datasource_entries * sizeof(uint8_t));
+        }
+    }
+
+    {
+        std::ofstream datasource_stream(datasource_names_filename, std::ios::binary);
+        if (!datasource_stream)
+        {
+            throw util::exception("Failed to open " + datasource_names_filename +
+                                  " for writing");
+        }
+        datasource_stream << "lua profile" << std::endl;
+        for (auto const &name : segment_speed_filenames)
+        {
+            datasource_stream << name << std::endl;
+        }
+    }
+
+    // TODO: can we read this in bulk?  util::DeallocatingVector isn't necessarily
+    // all stored contiguously
+    for (; number_of_edges > 0; --number_of_edges)
+    {
+        extractor::EdgeBasedEdge inbuffer;
+        input_stream.read((char *)&inbuffer, sizeof(extractor::EdgeBasedEdge));
+        if (update_edge_weights)
+        {
+            // Processing-time edge updates
+            unsigned fixed_penalty;
+            edge_fixed_penalties_input_stream.read(reinterpret_cast<char *>(&fixed_penalty),
+                                                   sizeof(fixed_penalty));
+
+            int new_weight = 0;
+
+            unsigned num_osm_nodes = 0;
+            edge_segment_input_stream.read(reinterpret_cast<char *>(&num_osm_nodes),
+                                           sizeof(num_osm_nodes));
+            OSMNodeID previous_osm_node_id;
+            edge_segment_input_stream.read(reinterpret_cast<char *>(&previous_osm_node_id),
+                                           sizeof(previous_osm_node_id));
+            OSMNodeID this_osm_node_id;
+            double segment_length;
+            int segment_weight;
+            --num_osm_nodes;
+            for (; num_osm_nodes != 0; --num_osm_nodes)
+            {
+                edge_segment_input_stream.read(reinterpret_cast<char *>(&this_osm_node_id),
+                                               sizeof(this_osm_node_id));
+                edge_segment_input_stream.read(reinterpret_cast<char *>(&segment_length),
+                                               sizeof(segment_length));
+                edge_segment_input_stream.read(reinterpret_cast<char *>(&segment_weight),
+                                               sizeof(segment_weight));
+
+                auto speed_iter = segment_speed_lookup.find(
+                    std::make_pair(previous_osm_node_id, this_osm_node_id));
+                if (speed_iter != segment_speed_lookup.end())
+                {
+                    // This sets the segment weight using the same formula as the
+                    // EdgeBasedGraphFactory for consistency.  The *why* of this formula
+                    // is lost in the annals of time.
+                    int new_segment_weight = std::max(
+                        1, static_cast<int>(std::floor(
+                               (segment_length * 10.) / (speed_iter->second.first / 3.6) + .5)));
+                    new_weight += new_segment_weight;
+                }
+                else
+                {
+                    // If no lookup found, use the original weight value for this segment
+                    new_weight += segment_weight;
+                }
+
+                previous_osm_node_id = this_osm_node_id;
+            }
+
+            inbuffer.weight = fixed_penalty + new_weight;
+        }
+
+        edge_based_edge_list.emplace_back(std::move(inbuffer));
+    }
+
+    util::SimpleLogger().Write() << "Done reading edges";
+    return max_edge_id;
+}
+
+void Contractor::ReadNodeLevels(std::vector<float> &node_levels) const
+{
+    boost::filesystem::ifstream order_input_stream(config.level_output_path, std::ios::binary);
+
+    unsigned level_size;
+    order_input_stream.read((char *)&level_size, sizeof(unsigned));
+    node_levels.resize(level_size);
+    order_input_stream.read((char *)node_levels.data(), sizeof(float) * node_levels.size());
+}
+
+void Contractor::WriteNodeLevels(std::vector<float> &&in_node_levels) const
+{
+    std::vector<float> node_levels(std::move(in_node_levels));
+
+    boost::filesystem::ofstream order_output_stream(config.level_output_path, std::ios::binary);
+
+    unsigned level_size = node_levels.size();
+    order_output_stream.write((char *)&level_size, sizeof(unsigned));
+    order_output_stream.write((char *)node_levels.data(), sizeof(float) * node_levels.size());
+}
+
+void Contractor::WriteCoreNodeMarker(std::vector<bool> &&in_is_core_node) const
+{
+    std::vector<bool> is_core_node(std::move(in_is_core_node));
+    std::vector<char> unpacked_bool_flags(std::move(is_core_node.size()));
+    for (auto i = 0u; i < is_core_node.size(); ++i)
+    {
+        unpacked_bool_flags[i] = is_core_node[i] ? 1 : 0;
+    }
+
+    boost::filesystem::ofstream core_marker_output_stream(config.core_output_path,
+                                                          std::ios::binary);
+    unsigned size = unpacked_bool_flags.size();
+    core_marker_output_stream.write((char *)&size, sizeof(unsigned));
+    core_marker_output_stream.write((char *)unpacked_bool_flags.data(),
+                                    sizeof(char) * unpacked_bool_flags.size());
+}
+
+std::size_t
+Contractor::WriteContractedGraph(unsigned max_node_id,
+                                 const util::DeallocatingVector<QueryEdge> &contracted_edge_list)
+{
+    // 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();
+    util::SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count
+                                 << " edges";
+
+    const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
+    boost::filesystem::ofstream hsgr_output_stream(config.graph_output_path, std::ios::binary);
+    hsgr_output_stream.write((char *)&fingerprint, sizeof(util::FingerPrint));
+    const unsigned max_used_node_id = [&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;
+    }();
+
+    util::SimpleLogger().Write(logDEBUG) << "input graph has " << (max_node_id + 1) << " nodes";
+    util::SimpleLogger().Write(logDEBUG) << "contracted graph has " << (max_used_node_id + 1)
+                                         << " nodes";
+
+    std::vector<util::StaticGraph<EdgeData>::NodeArrayEntry> node_array;
+    // make sure we have at least one sentinel
+    node_array.resize(max_node_id + 2);
+
+    util::SimpleLogger().Write() << "Building node array";
+    util::StaticGraph<EdgeData>::EdgeIterator edge = 0;
+    util::StaticGraph<EdgeData>::EdgeIterator position = 0;
+    util::StaticGraph<EdgeData>::EdgeIterator last_edge;
+
+    // initializing 'first_edge'-field of nodes:
+    for (const auto node : util::irange(0u, max_used_node_id + 1))
+    {
+        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 :
+         util::irange<unsigned>(max_used_node_id + 1, node_array.size()))
+    {
+        // sentinel element, guarded against underflow
+        node_array[sentinel_counter].first_edge = contracted_edge_count;
+    }
+
+    util::SimpleLogger().Write() << "Serializing node array";
+
+    RangebasedCRC32 crc32_calculator;
+    const unsigned edges_crc32 = crc32_calculator(contracted_edge_list);
+    util::SimpleLogger().Write() << "Writing CRC32: " << edges_crc32;
+
+    const unsigned node_array_size = node_array.size();
+    // serialize crc32, aka checksum
+    hsgr_output_stream.write((char *)&edges_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(util::StaticGraph<EdgeData>::NodeArrayEntry) *
+                                     node_array_size);
+    }
+
+    // serialize all edges
+    util::SimpleLogger().Write() << "Building edge array";
+    int number_of_used_edges = 0;
+
+    util::StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
+    for (const auto edge : util::irange<std::size_t>(0, contracted_edge_list.size()))
+    {
+        // some self-loops are required for oneway handling. Need to assertthat we only keep these
+        // (TODO)
+        // no eigen loops
+        // BOOST_ASSERT(contracted_edge_list[edge].source != contracted_edge_list[edge].target ||
+        // node_represents_oneway[contracted_edge_list[edge].source]);
+        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)
+        {
+            util::SimpleLogger().Write(logWARNING)
+                << "Edge: " << edge << ",source: " << contracted_edge_list[edge].source
+                << ", target: " << contracted_edge_list[edge].target
+                << ", dist: " << current_edge.data.distance;
+
+            util::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(util::StaticGraph<EdgeData>::EdgeArrayEntry));
+
+        ++number_of_used_edges;
+    }
+
+    return number_of_used_edges;
+}
+
+/**
+ \brief Build contracted graph.
+ */
+void Contractor::ContractGraph(
+    const unsigned max_edge_id,
+    util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
+    util::DeallocatingVector<QueryEdge> &contracted_edge_list,
+    std::vector<EdgeWeight> &&node_weights,
+    std::vector<bool> &is_core_node,
+    std::vector<float> &inout_node_levels) const
+{
+    std::vector<float> node_levels;
+    node_levels.swap(inout_node_levels);
+
+    GraphContractor graph_contractor(max_edge_id + 1, edge_based_edge_list, std::move(node_levels),
+                                     std::move(node_weights));
+    graph_contractor.Run(config.core_factor);
+    graph_contractor.GetEdges(contracted_edge_list);
+    graph_contractor.GetCoreMarker(is_core_node);
+    graph_contractor.GetNodeLevels(inout_node_levels);
+}
+}
+}
diff --git a/src/engine/api/json_factory.cpp b/src/engine/api/json_factory.cpp
new file mode 100644
index 0000000..5c3663d
--- /dev/null
+++ b/src/engine/api/json_factory.cpp
@@ -0,0 +1,230 @@
+#include "engine/api/json_factory.hpp"
+
+#include "engine/polyline_compressor.hpp"
+#include "engine/hint.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/range/irange.hpp>
+#include <boost/optional.hpp>
+
+#include <string>
+#include <utility>
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+using TurnType = osrm::extractor::guidance::TurnType;
+using DirectionModifier = osrm::extractor::guidance::DirectionModifier;
+using TurnInstruction = osrm::extractor::guidance::TurnInstruction;
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+namespace json
+{
+namespace detail
+{
+
+const constexpr char *modifier_names[] = {"uturn",
+                                          "sharp right",
+                                          "right",
+                                          "slight right",
+                                          "straight",
+                                          "slight left",
+                                          "left",
+                                          "sharp left"};
+
+// translations of TurnTypes. Not all types are exposed to the outside world.
+// invalid types should never be returned as part of the API
+const constexpr char *turn_type_names[] = {
+    "invalid",        "no turn", "invalid",    "new name",    "continue",       "turn",
+    "turn",           "turn",    "turn",       "turn",        "merge",          "ramp",
+    "ramp",           "ramp",    "ramp",       "ramp",        "fork",           "end of road",
+    "roundabout",     "invalid", "roundabout", "invalid",     "traffic circle", "invalid",
+    "traffic circle", "invalid", "invalid",    "restriction", "notification"};
+const constexpr char *waypoint_type_names[] = {"invalid", "arrive", "depart"};
+
+// Check whether to include a modifier in the result of the API
+inline bool isValidModifier(const guidance::StepManeuver maneuver)
+{
+    if (maneuver.waypoint_type != guidance::WaypointType::None &&
+        maneuver.instruction.direction_modifier == DirectionModifier::UTurn)
+        return false;
+    return true;
+}
+
+std::string instructionTypeToString(const TurnType type)
+{
+    return turn_type_names[static_cast<std::size_t>(type)];
+}
+
+std::string instructionModifierToString(const DirectionModifier modifier)
+{
+    return modifier_names[static_cast<std::size_t>(modifier)];
+}
+
+std::string waypointTypeToString(const guidance::WaypointType waypoint_type)
+{
+    return waypoint_type_names[static_cast<std::size_t>(waypoint_type)];
+}
+
+util::json::Array coordinateToLonLat(const util::Coordinate coordinate)
+{
+    util::json::Array array;
+    array.values.push_back(static_cast<double>(toFloating(coordinate.lon)));
+    array.values.push_back(static_cast<double>(toFloating(coordinate.lat)));
+    return array;
+}
+
+// FIXME this actually needs to be configurable from the profiles
+std::string modeToString(const extractor::TravelMode mode)
+{
+    std::string token;
+    switch (mode)
+    {
+    case TRAVEL_MODE_INACCESSIBLE:
+        token = "inaccessible";
+        break;
+    case TRAVEL_MODE_DRIVING:
+        token = "driving";
+        break;
+    case TRAVEL_MODE_CYCLING:
+        token = "cycling";
+        break;
+    case TRAVEL_MODE_WALKING:
+        token = "walking";
+        break;
+    case TRAVEL_MODE_FERRY:
+        token = "ferry";
+        break;
+    case TRAVEL_MODE_TRAIN:
+        token = "train";
+        break;
+    case TRAVEL_MODE_PUSHING_BIKE:
+        token = "pushing bike";
+        break;
+    case TRAVEL_MODE_MOVABLE_BRIDGE:
+        token = "movable bridge";
+        break;
+    case TRAVEL_MODE_STEPS_UP:
+        token = "steps up";
+        break;
+    case TRAVEL_MODE_STEPS_DOWN:
+        token = "steps down";
+        break;
+    case TRAVEL_MODE_RIVER_UP:
+        token = "river upstream";
+        break;
+    case TRAVEL_MODE_RIVER_DOWN:
+        token = "river downstream";
+        break;
+    case TRAVEL_MODE_ROUTE:
+        token = "route";
+        break;
+    default:
+        token = "other";
+        break;
+    }
+    return token;
+}
+
+} // namespace detail
+
+util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
+{
+    util::json::Object step_maneuver;
+    if (maneuver.waypoint_type == guidance::WaypointType::None)
+        step_maneuver.values["type"] = detail::instructionTypeToString(maneuver.instruction.type);
+    else
+        step_maneuver.values["type"] = detail::waypointTypeToString(maneuver.waypoint_type);
+
+    if (detail::isValidModifier(maneuver))
+        step_maneuver.values["modifier"] =
+            detail::instructionModifierToString(maneuver.instruction.direction_modifier);
+    step_maneuver.values["location"] = detail::coordinateToLonLat(maneuver.location);
+    step_maneuver.values["bearing_before"] = std::round(maneuver.bearing_before);
+    step_maneuver.values["bearing_after"] = std::round(maneuver.bearing_after);
+    if (maneuver.exit != 0)
+        step_maneuver.values["exit"] = maneuver.exit;
+
+    // TODO currently we need this to comply with the api.
+    // We should move this to an additional entry, the moment we
+    // actually compute the correct locations of the intersections
+    if (!maneuver.intersections.empty() && maneuver.exit == 0)
+        step_maneuver.values["exit"] = maneuver.intersections.size();
+    return step_maneuver;
+}
+
+util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geometry)
+{
+    util::json::Object route_step;
+    route_step.values["distance"] = std::round(step.distance * 10) / 10.;
+    route_step.values["duration"] = std::round(step.duration * 10) / 10.;
+    route_step.values["name"] = std::move(step.name);
+    route_step.values["mode"] = detail::modeToString(std::move(step.mode));
+    route_step.values["maneuver"] = makeStepManeuver(std::move(step.maneuver));
+    route_step.values["geometry"] = std::move(geometry);
+    return route_step;
+}
+
+util::json::Object makeRoute(const guidance::Route &route,
+                             util::json::Array legs,
+                             boost::optional<util::json::Value> geometry)
+{
+    util::json::Object json_route;
+    json_route.values["distance"] = std::round(route.distance * 10) / 10.;
+    json_route.values["duration"] = std::round(route.duration * 10) / 10.;
+    json_route.values["legs"] = std::move(legs);
+    if (geometry)
+    {
+        json_route.values["geometry"] = *std::move(geometry);
+    }
+    return json_route;
+}
+
+util::json::Object makeWaypoint(const util::Coordinate location, std::string name, const Hint &hint)
+{
+    util::json::Object waypoint;
+    waypoint.values["location"] = detail::coordinateToLonLat(location);
+    waypoint.values["name"] = std::move(name);
+    waypoint.values["hint"] = hint.ToBase64();
+    return waypoint;
+}
+
+util::json::Object makeRouteLeg(guidance::RouteLeg leg, util::json::Array steps)
+{
+    util::json::Object route_leg;
+    route_leg.values["distance"] = std::round(leg.distance * 10) / 10.;
+    route_leg.values["duration"] = std::round(leg.duration * 10) / 10.;
+    route_leg.values["summary"] = std::move(leg.summary);
+    route_leg.values["steps"] = std::move(steps);
+    return route_leg;
+}
+
+util::json::Array makeRouteLegs(std::vector<guidance::RouteLeg> legs,
+                                std::vector<util::json::Value> step_geometries)
+{
+    util::json::Array json_legs;
+    auto step_geometry_iter = step_geometries.begin();
+    for (const auto idx : boost::irange(0UL, legs.size()))
+    {
+        auto leg = std::move(legs[idx]);
+        util::json::Array json_steps;
+        json_steps.values.reserve(leg.steps.size());
+        std::transform(
+            std::make_move_iterator(leg.steps.begin()), std::make_move_iterator(leg.steps.end()),
+            std::back_inserter(json_steps.values), [&step_geometry_iter](guidance::RouteStep step)
+            {
+                return makeRouteStep(std::move(step), std::move(*step_geometry_iter++));
+            });
+        json_legs.values.push_back(makeRouteLeg(std::move(leg), std::move(json_steps)));
+    }
+    return json_legs;
+}
+} // namespace json
+} // namespace api
+} // namespace engine
+} // namespace osrm
diff --git a/src/engine/douglas_peucker.cpp b/src/engine/douglas_peucker.cpp
new file mode 100644
index 0000000..e7e2f90
--- /dev/null
+++ b/src/engine/douglas_peucker.cpp
@@ -0,0 +1,100 @@
+#include "engine/douglas_peucker.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/coordinate.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/range/irange.hpp>
+
+#include <cmath>
+#include <algorithm>
+#include <iterator>
+#include <stack>
+#include <utility>
+
+namespace osrm
+{
+namespace engine
+{
+
+std::vector<util::Coordinate> douglasPeucker(std::vector<util::Coordinate>::const_iterator begin,
+                                             std::vector<util::Coordinate>::const_iterator end,
+                                             const unsigned zoom_level)
+{
+    BOOST_ASSERT_MSG(zoom_level < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE,
+                     "unsupported zoom level");
+
+    const auto size = std::distance(begin, end);
+    if (size < 2)
+    {
+        return {};
+    }
+
+    std::vector<bool> is_necessary(size, false);
+    BOOST_ASSERT(is_necessary.size() >= 2);
+    is_necessary.front() = true;
+    is_necessary.back() = true;
+    using GeometryRange = std::pair<std::size_t, std::size_t>;
+
+    std::stack<GeometryRange> recursion_stack;
+
+    recursion_stack.emplace(0UL, size - 1);
+
+    // mark locations as 'necessary' by divide-and-conquer
+    while (!recursion_stack.empty())
+    {
+        // pop next element
+        const GeometryRange pair = recursion_stack.top();
+        recursion_stack.pop();
+        // sanity checks
+        BOOST_ASSERT_MSG(is_necessary[pair.first], "left border must be necessary");
+        BOOST_ASSERT_MSG(is_necessary[pair.second], "right border must be necessary");
+        BOOST_ASSERT_MSG(pair.second < size, "right border outside of geometry");
+        BOOST_ASSERT_MSG(pair.first <= pair.second, "left border on the wrong side");
+
+        double max_distance = 0;
+        auto farthest_entry_index = pair.second;
+
+        // sweep over range to find the maximum
+        for (auto idx = pair.first + 1; idx != pair.second; ++idx)
+        {
+            using namespace util::coordinate_calculation;
+            const auto distance = perpendicularDistance(begin[pair.first], begin[pair.second], begin[idx]);
+            // found new feasible maximum?
+            if (distance > max_distance &&
+                distance > detail::DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
+            {
+                farthest_entry_index = idx;
+                max_distance = distance;
+            }
+        }
+
+        // check if maximum violates a zoom level dependent threshold
+        if (max_distance > detail::DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
+        {
+            //  mark idx as necessary
+            is_necessary[farthest_entry_index] = true;
+            if (pair.first < farthest_entry_index)
+            {
+                recursion_stack.emplace(pair.first, farthest_entry_index);
+            }
+            if (farthest_entry_index < pair.second)
+            {
+                recursion_stack.emplace(farthest_entry_index, pair.second);
+            }
+        }
+    }
+
+    auto simplified_size = std::count(is_necessary.begin(), is_necessary.end(), true);
+    std::vector<util::Coordinate> simplified_geometry;
+    simplified_geometry.reserve(simplified_size);
+    for (auto idx : boost::irange<std::size_t>(0UL, size))
+    {
+        if (is_necessary[idx])
+        {
+            simplified_geometry.push_back(begin[idx]);
+        }
+    }
+    return simplified_geometry;
+}
+} // ns engine
+} // ns osrm
diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp
new file mode 100644
index 0000000..9207c44
--- /dev/null
+++ b/src/engine/engine.cpp
@@ -0,0 +1,190 @@
+#include "engine/engine.hpp"
+#include "engine/engine_config.hpp"
+#include "engine/api/route_parameters.hpp"
+#include "engine/status.hpp"
+
+#include "engine/plugins/table.hpp"
+#include "engine/plugins/nearest.hpp"
+#include "engine/plugins/trip.hpp"
+#include "engine/plugins/viaroute.hpp"
+#include "engine/plugins/tile.hpp"
+#include "engine/plugins/match.hpp"
+
+#include "engine/datafacade/datafacade_base.hpp"
+#include "engine/datafacade/internal_datafacade.hpp"
+#include "engine/datafacade/shared_datafacade.hpp"
+
+#include "storage/shared_barriers.hpp"
+#include "util/make_unique.hpp"
+#include "util/simple_logger.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/interprocess/sync/named_condition.hpp>
+#include <boost/interprocess/sync/scoped_lock.hpp>
+#include <boost/thread/lock_types.hpp>
+
+#include <algorithm>
+#include <fstream>
+#include <utility>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+struct Engine::EngineLock
+{
+    // will only be initialized if shared memory is used
+    storage::SharedBarriers barrier;
+    // decrease number of concurrent queries
+    void DecreaseQueryCount();
+    // increase number of concurrent queries
+    void IncreaseQueryCount();
+};
+
+// decrease number of concurrent queries
+void Engine::EngineLock::DecreaseQueryCount()
+{
+    // lock query
+    boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
+        barrier.query_mutex);
+
+    // decrement query count
+    --(barrier.number_of_queries);
+    BOOST_ASSERT_MSG(0 <= barrier.number_of_queries, "invalid number of queries");
+
+    // notify all processes that were waiting for this condition
+    if (0 == barrier.number_of_queries)
+    {
+        barrier.no_running_queries_condition.notify_all();
+    }
+}
+
+// increase number of concurrent queries
+void Engine::EngineLock::IncreaseQueryCount()
+{
+    // lock update pending
+    boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock(
+        barrier.pending_update_mutex);
+
+    // lock query
+    boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
+        barrier.query_mutex);
+
+    // unlock update pending
+    pending_lock.unlock();
+
+    // increment query count
+    ++(barrier.number_of_queries);
+}
+} // ns engine
+} // ns osrm
+
+namespace
+{
+// Abstracted away the query locking into a template function
+// Works the same for every plugin.
+template <typename ParameterT, typename PluginT, typename ResultT>
+osrm::engine::Status RunQuery(const std::unique_ptr<osrm::engine::Engine::EngineLock> &lock,
+                              osrm::engine::datafacade::BaseDataFacade &facade,
+                              const ParameterT &parameters,
+                              PluginT &plugin,
+                              ResultT &result)
+{
+    if (!lock)
+    {
+        return plugin.HandleRequest(parameters, result);
+    }
+
+    BOOST_ASSERT(lock);
+    lock->IncreaseQueryCount();
+
+    auto &shared_facade = static_cast<osrm::engine::datafacade::SharedDataFacade &>(facade);
+    shared_facade.CheckAndReloadFacade();
+    // Get a shared data lock so that other threads won't update
+    // things while the query is running
+    boost::shared_lock<boost::shared_mutex> data_lock{shared_facade.data_mutex};
+
+    osrm::engine::Status status = plugin.HandleRequest(parameters, result);
+
+    lock->DecreaseQueryCount();
+    return status;
+}
+
+template <typename Plugin, typename Facade, typename... Args>
+std::unique_ptr<Plugin> create(Facade &facade, Args... args)
+{
+    return osrm::util::make_unique<Plugin>(facade, std::forward<Args>(args)...);
+}
+
+} // anon. ns
+
+namespace osrm
+{
+namespace engine
+{
+
+Engine::Engine(EngineConfig &config)
+{
+    if (config.use_shared_memory)
+    {
+        lock = util::make_unique<EngineLock>();
+        query_data_facade = util::make_unique<datafacade::SharedDataFacade>();
+    }
+    else
+    {
+        if (!config.storage_config.IsValid())
+        {
+            throw util::exception("Invalid file paths given!");
+        }
+        query_data_facade = util::make_unique<datafacade::InternalDataFacade>(config.storage_config);
+    }
+
+    // Register plugins
+    using namespace plugins;
+
+    route_plugin = create<ViaRoutePlugin>(*query_data_facade, config.max_locations_viaroute);
+    table_plugin = create<TablePlugin>(*query_data_facade, config.max_locations_distance_table);
+    nearest_plugin = create<NearestPlugin>(*query_data_facade);
+    trip_plugin = create<TripPlugin>(*query_data_facade, config.max_locations_trip);
+    match_plugin = create<MatchPlugin>(*query_data_facade, config.max_locations_map_matching);
+    tile_plugin = create<TilePlugin>(*query_data_facade);
+}
+
+// make sure we deallocate the unique ptr at a position where we know the size of the plugins
+Engine::~Engine() = default;
+Engine::Engine(Engine &&) noexcept = default;
+Engine &Engine::operator=(Engine &&) noexcept = default;
+
+Status Engine::Route(const api::RouteParameters &params, util::json::Object &result)
+{
+    return RunQuery(lock, *query_data_facade, params, *route_plugin, result);
+}
+
+Status Engine::Table(const api::TableParameters &params, util::json::Object &result)
+{
+    return RunQuery(lock, *query_data_facade, params, *table_plugin, result);
+}
+
+Status Engine::Nearest(const api::NearestParameters &params, util::json::Object &result)
+{
+    return RunQuery(lock, *query_data_facade, params, *nearest_plugin, result);
+}
+
+Status Engine::Trip(const api::TripParameters &params, util::json::Object &result)
+{
+    return RunQuery(lock, *query_data_facade, params, *trip_plugin, result);
+}
+
+Status Engine::Match(const api::MatchParameters &params, util::json::Object &result)
+{
+    return RunQuery(lock, *query_data_facade, params, *match_plugin, result);
+}
+
+Status Engine::Tile(const api::TileParameters &params, std::string &result)
+{
+    return RunQuery(lock, *query_data_facade, params, *tile_plugin, result);
+}
+
+} // engine ns
+} // osrm ns
diff --git a/src/engine/engine_config.cpp b/src/engine/engine_config.cpp
new file mode 100644
index 0000000..e26a67e
--- /dev/null
+++ b/src/engine/engine_config.cpp
@@ -0,0 +1,27 @@
+#include "engine/engine_config.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+
+bool EngineConfig::IsValid() const
+{
+    const bool all_path_are_empty =
+        storage_config.ram_index_path.empty() && storage_config.file_index_path.empty() &&
+        storage_config.hsgr_data_path.empty() && storage_config.nodes_data_path.empty() &&
+        storage_config.edges_data_path.empty() && storage_config.core_data_path.empty() &&
+        storage_config.geometries_path.empty() && storage_config.timestamp_path.empty() &&
+        storage_config.datasource_names_path.empty() &&
+        storage_config.datasource_indexes_path.empty() && storage_config.names_data_path.empty();
+
+    const bool limits_valid =
+        (max_locations_distance_table == -1 || max_locations_distance_table > 2) &&
+        (max_locations_map_matching == -1 || max_locations_map_matching > 2) &&
+        (max_locations_trip == -1 || max_locations_trip > 2) &&
+        (max_locations_viaroute == -1 || max_locations_viaroute > 2);
+
+    return ((use_shared_memory && all_path_are_empty) || storage_config.IsValid()) && limits_valid;
+}
+}
+}
diff --git a/src/engine/guidance/assemble_overview.cpp b/src/engine/guidance/assemble_overview.cpp
new file mode 100644
index 0000000..aa25411
--- /dev/null
+++ b/src/engine/guidance/assemble_overview.cpp
@@ -0,0 +1,103 @@
+#ifndef ENGINE_GUIDANCE_ASSEMBLE_OVERVIEW_HPP
+#define ENGINE_GUIDANCE_ASSEMBLE_OVERVIEW_HPP
+
+#include "engine/guidance/leg_geometry.hpp"
+#include "engine/douglas_peucker.hpp"
+#include "util/viewport.hpp"
+
+#include <vector>
+#include <tuple>
+#include <numeric>
+#include <utility>
+#include <iterator>
+#include <limits>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+namespace
+{
+
+unsigned calculateOverviewZoomLevel(const std::vector<LegGeometry> &leg_geometries)
+{
+    util::Coordinate south_west{util::FixedLongitude{std::numeric_limits<int>::max()}, util::FixedLatitude{std::numeric_limits<int>::max()}};
+    util::Coordinate north_east{util::FixedLongitude{std::numeric_limits<int>::min()}, util::FixedLatitude{std::numeric_limits<int>::min()}};
+
+    for (const auto &leg_geometry : leg_geometries)
+    {
+        for (const auto coord : leg_geometry.locations)
+        {
+            south_west.lon = std::min(south_west.lon, coord.lon);
+            south_west.lat = std::min(south_west.lat, coord.lat);
+
+            north_east.lon = std::max(north_east.lon, coord.lon);
+            north_east.lat = std::max(north_east.lat, coord.lat);
+        }
+    }
+
+    return util::viewport::getFittedZoom(south_west, north_east);
+}
+
+std::vector<util::Coordinate> simplifyGeometry(const std::vector<LegGeometry> &leg_geometries,
+                                               const unsigned zoom_level)
+{
+    std::vector<util::Coordinate> overview_geometry;
+    auto leg_index = 0UL;
+    for (const auto geometry : leg_geometries)
+    {
+        auto simplified_geometry =
+            douglasPeucker(geometry.locations.begin(), geometry.locations.end(), zoom_level);
+        // not the last leg
+        if (leg_index < leg_geometries.size() - 1)
+        {
+            simplified_geometry.pop_back();
+        }
+        overview_geometry.insert(overview_geometry.end(), simplified_geometry.begin(),
+                                 simplified_geometry.end());
+    }
+    return overview_geometry;
+}
+}
+
+std::vector<util::Coordinate> assembleOverview(const std::vector<LegGeometry> &leg_geometries,
+                                               const bool use_simplification)
+{
+    if (use_simplification)
+    {
+        const auto zoom_level = std::min(18u, calculateOverviewZoomLevel(leg_geometries));
+        return simplifyGeometry(leg_geometries, zoom_level);
+    }
+    BOOST_ASSERT(!use_simplification);
+
+    auto overview_size = std::accumulate(leg_geometries.begin(), leg_geometries.end(), 0,
+                                         [](const std::size_t sum, const LegGeometry &leg_geometry)
+                                         {
+                                             return sum + leg_geometry.locations.size();
+                                         }) -
+                         leg_geometries.size() + 1;
+    std::vector<util::Coordinate> overview_geometry;
+    overview_geometry.reserve(overview_size);
+
+    auto leg_index = 0UL;
+    for (const auto geometry : leg_geometries)
+    {
+        auto begin = geometry.locations.begin();
+        auto end = geometry.locations.end();
+        if (leg_index < leg_geometries.size() - 1)
+        {
+            end = std::prev(end);
+        }
+        overview_geometry.insert(overview_geometry.end(), begin, end);
+    }
+
+    return overview_geometry;
+}
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
+
+#endif
diff --git a/src/engine/guidance/assemble_route.cpp b/src/engine/guidance/assemble_route.cpp
new file mode 100644
index 0000000..cdc3a98
--- /dev/null
+++ b/src/engine/guidance/assemble_route.cpp
@@ -0,0 +1,30 @@
+#include "engine/guidance/assemble_route.hpp"
+
+#include <numeric>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+Route assembleRoute(const std::vector<RouteLeg> &route_legs)
+{
+    auto distance = std::accumulate(route_legs.begin(), route_legs.end(), 0.,
+                                    [](const double sum, const RouteLeg &leg)
+                                    {
+                                        return sum + leg.distance;
+                                    });
+    auto duration = std::accumulate(route_legs.begin(), route_legs.end(), 0.,
+                                    [](const double sum, const RouteLeg &leg)
+                                    {
+                                        return sum + leg.duration;
+                                    });
+
+    return Route{duration, distance};
+}
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
diff --git a/src/engine/guidance/assemble_steps.cpp b/src/engine/guidance/assemble_steps.cpp
new file mode 100644
index 0000000..207a6d2
--- /dev/null
+++ b/src/engine/guidance/assemble_steps.cpp
@@ -0,0 +1,82 @@
+#include "engine/guidance/assemble_steps.hpp"
+
+#include <boost/assert.hpp>
+
+#include <cstddef>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+namespace detail
+{
+
+StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction,
+                                      const WaypointType waypoint_type,
+                                      const LegGeometry &leg_geometry)
+{
+    BOOST_ASSERT(waypoint_type != WaypointType::None);
+    BOOST_ASSERT(leg_geometry.locations.size() >= 2);
+
+    double pre_turn_bearing = 0, post_turn_bearing = 0;
+    Coordinate turn_coordinate;
+    if (waypoint_type == WaypointType::Depart)
+    {
+        turn_coordinate = leg_geometry.locations.front();
+        const auto post_turn_coordinate = *(leg_geometry.locations.begin() + 1);
+        post_turn_bearing =
+            util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate);
+    }
+    else
+    {
+        BOOST_ASSERT(waypoint_type == WaypointType::Arrive);
+        turn_coordinate = leg_geometry.locations.back();
+        const auto pre_turn_coordinate = *(leg_geometry.locations.end() - 2);
+        pre_turn_bearing =
+            util::coordinate_calculation::bearing(pre_turn_coordinate, turn_coordinate);
+    }
+    return StepManeuver{
+        std::move(turn_coordinate),
+        pre_turn_bearing,
+        post_turn_bearing,
+        std::move(instruction),
+        waypoint_type,
+        INVALID_EXIT_NR,
+        {} // no intermediate intersections
+    };
+}
+
+StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction,
+                                      const LegGeometry &leg_geometry,
+                                      const std::size_t segment_index)
+{
+    auto turn_index = leg_geometry.BackIndex(segment_index);
+    BOOST_ASSERT(turn_index > 0);
+    BOOST_ASSERT(turn_index + 1 < leg_geometry.locations.size());
+
+    // TODO chose a bigger look-a-head to smooth complex geometry
+    const auto pre_turn_coordinate = leg_geometry.locations[turn_index - 1];
+    const auto turn_coordinate = leg_geometry.locations[turn_index];
+    const auto post_turn_coordinate = leg_geometry.locations[turn_index + 1];
+
+    const double pre_turn_bearing =
+        util::coordinate_calculation::bearing(pre_turn_coordinate, turn_coordinate);
+    const double post_turn_bearing =
+        util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate);
+
+    return StepManeuver{
+        std::move(turn_coordinate),
+        pre_turn_bearing,
+        post_turn_bearing,
+        std::move(instruction),
+        WaypointType::None,
+        INVALID_EXIT_NR,
+        {} // no intermediate intersections
+    };
+}
+} // ns detail
+} // ns engine
+} // ns guidance
+} // ns detail
diff --git a/src/engine/guidance/post_processing.cpp b/src/engine/guidance/post_processing.cpp
new file mode 100644
index 0000000..0f3fc34
--- /dev/null
+++ b/src/engine/guidance/post_processing.cpp
@@ -0,0 +1,494 @@
+#include "engine/guidance/post_processing.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+
+#include "engine/guidance/toolkit.hpp"
+#include "engine/guidance/assemble_steps.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/range/algorithm_ext/erase.hpp>
+
+#include <algorithm>
+#include <iostream>
+#include <cmath>
+#include <cstddef>
+#include <limits>
+#include <utility>
+
+using TurnInstruction = osrm::extractor::guidance::TurnInstruction;
+using TurnType = osrm::extractor::guidance::TurnType;
+using DirectionModifier = osrm::extractor::guidance::DirectionModifier;
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+namespace detail
+{
+bool canMergeTrivially(const RouteStep &destination, const RouteStep &source)
+{
+    return destination.maneuver.exit == 0 && destination.name_id == source.name_id &&
+           isSilent(source.maneuver.instruction);
+}
+
+RouteStep forwardInto(RouteStep destination, const RouteStep &source)
+{
+    // Merge a turn into a silent turn
+    // Overwrites turn instruction and increases exit NR
+    destination.duration += source.duration;
+    destination.distance += source.distance;
+    destination.geometry_begin = std::min(destination.geometry_begin, source.geometry_begin);
+    destination.geometry_end = std::max(destination.geometry_end, source.geometry_end);
+    return destination;
+}
+
+void fixFinalRoundabout(std::vector<RouteStep> &steps)
+{
+    for (std::size_t propagation_index = steps.size() - 1; propagation_index > 0;
+         --propagation_index)
+    {
+        auto &propagation_step = steps[propagation_index];
+        if (propagation_index == 0 || entersRoundabout(propagation_step.maneuver.instruction))
+        {
+            propagation_step.maneuver.exit = 0;
+            propagation_step.geometry_end = steps.back().geometry_begin;
+            break;
+        }
+        else if (propagation_step.maneuver.instruction.type == TurnType::StayOnRoundabout)
+        {
+            // TODO this operates on the data that is in the instructions.
+            // We are missing out on the final segment after the last stay-on-roundabout
+            // instruction though. it is not contained somewhere until now
+            steps[propagation_index - 1] =
+                forwardInto(std::move(steps[propagation_index - 1]), propagation_step);
+            propagation_step.maneuver.instruction =
+                TurnInstruction::NO_TURN(); // mark intermediate instructions invalid
+        }
+    }
+}
+
+bool setUpRoundabout(RouteStep &step)
+{
+    // basic entry into a roundabout
+    // Special case handling, if an entry is directly tied to an exit
+    const auto instruction = step.maneuver.instruction;
+    if (instruction.type == TurnType::EnterRotaryAtExit ||
+        instruction.type == TurnType::EnterRoundaboutAtExit)
+    {
+        step.maneuver.exit = 1;
+        // prevent futher special case handling of these two.
+        if (instruction.type == TurnType::EnterRotaryAtExit)
+            step.maneuver.instruction = TurnType::EnterRotary;
+        else
+            step.maneuver.instruction = TurnType::EnterRoundabout;
+    }
+
+    if (leavesRoundabout(instruction))
+    {
+        step.maneuver.exit = 1; // count the otherwise missing exit
+        if (instruction.type == TurnType::EnterRotaryAtExit)
+            step.maneuver.instruction = TurnType::EnterRotary;
+        else
+            step.maneuver.instruction = TurnType::EnterRoundabout;
+        return false;
+    }
+    else
+    {
+        return true;
+    }
+}
+
+void closeOffRoundabout(const bool on_roundabout,
+                        std::vector<RouteStep> &steps,
+                        const std::size_t step_index)
+{
+    auto &step = steps[step_index];
+    step.maneuver.exit += 1;
+    if (!on_roundabout)
+    {
+
+        // We reached a special case that requires the addition of a special route step in
+        // the beginning.
+        // We started in a roundabout, so to announce the exit, we move use the exit
+        // instruction and
+        // move it right to the beginning to make sure to immediately announce the exit.
+        BOOST_ASSERT(leavesRoundabout(steps[1].maneuver.instruction) ||
+                     steps[1].maneuver.instruction.type == TurnType::StayOnRoundabout);
+        steps[0].geometry_end = 1;
+        steps[1] = detail::forwardInto(steps[1], steps[0]);
+        steps[0].duration = 0;
+        steps[0].distance = 0;
+        steps[1].maneuver.instruction.type = step.maneuver.instruction.type == TurnType::ExitRotary
+                                                 ? TurnType::EnterRotary
+                                                 : TurnType::EnterRoundabout;
+    }
+
+    // Normal exit from the roundabout, or exit from a previously fixed roundabout.
+    // Propagate the index back to the entering
+    // location and
+    // prepare the current silent set of instructions for removal.
+    if (step_index > 1)
+    {
+        // The very first route-step is head, so we cannot iterate past that one
+        for (std::size_t propagation_index = step_index - 1; propagation_index > 0;
+             --propagation_index)
+        {
+            auto &propagation_step = steps[propagation_index];
+            propagation_step = detail::forwardInto(propagation_step, steps[propagation_index + 1]);
+            if (entersRoundabout(propagation_step.maneuver.instruction))
+            {
+                // TODO at this point, we can remember the additional name for a rotary
+                // This requires some initial thought on the data format, though
+
+                propagation_step.maneuver.exit = step.maneuver.exit;
+                propagation_step.geometry_end = step.geometry_end;
+                propagation_step.name = step.name;
+                propagation_step.name_id = step.name_id;
+                break;
+            }
+            else
+            {
+                BOOST_ASSERT(propagation_step.maneuver.instruction.type =
+                                 TurnType::StayOnRoundabout);
+                propagation_step.maneuver.instruction =
+                    TurnInstruction::NO_TURN(); // mark intermediate instructions invalid
+            }
+        }
+        // remove exit
+        step.maneuver.instruction = TurnInstruction::NO_TURN();
+    }
+}
+} // namespace detail
+
+void print(const std::vector<RouteStep> &steps)
+{
+    std::cout << "Path\n";
+    int segment = 0;
+    for (const auto &step : steps)
+    {
+        const auto type = static_cast<int>(step.maneuver.instruction.type);
+        const auto modifier = static_cast<int>(step.maneuver.instruction.direction_modifier);
+
+        std::cout << "\t[" << ++segment << "]: " << type << " " << modifier
+                  << " Duration: " << step.duration << " Distance: " << step.distance
+                  << " Geometry: " << step.geometry_begin << " " << step.geometry_end
+                  << " exit: " << step.maneuver.exit
+                  << " Intersections: " << step.maneuver.intersections.size() << " [";
+
+        for (auto intersection : step.maneuver.intersections)
+            std::cout << "(" << intersection.duration << " " << intersection.distance << ")";
+
+        std::cout << "] name[" << step.name_id << "]: " << step.name << std::endl;
+    }
+}
+
+// Every Step Maneuver consists of the information until the turn.
+// This list contains a set of instructions, called silent, which should
+// not be part of the final output.
+// They are required for maintenance purposes. We can calculate the number
+// of exits to pass in a roundabout and the number of intersections
+// that we come across.
+
+std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
+{
+    // the steps should always include the first/last step in form of a location
+    BOOST_ASSERT(steps.size() >= 2);
+    if (steps.size() == 2)
+        return steps;
+
+    // Count Street Exits forward
+    bool on_roundabout = false;
+    bool has_entered_roundabout = false;
+
+    // adds an intersection to the initial route step
+    // It includes the length of the last step, until the intersection
+    // Also updates the length of the respective segment
+    auto addIntersection =
+        [](RouteStep into, const RouteStep &last_step, const RouteStep &intersection)
+    {
+        into.maneuver.intersections.push_back(
+            {last_step.duration, last_step.distance, intersection.maneuver.location});
+
+        return detail::forwardInto(std::move(into), intersection);
+    };
+
+    // count the exits forward. if enter/exit roundabout happen both, no further treatment is
+    // required. We might end up with only one of them (e.g. starting within a roundabout)
+    // or having a via-point in the roundabout.
+    // In this case, exits are numbered from the start of the lag.
+    std::size_t last_valid_instruction = 0;
+    for (std::size_t step_index = 0; step_index < steps.size(); ++step_index)
+    {
+        auto &step = steps[step_index];
+        const auto instruction = step.maneuver.instruction;
+        if (entersRoundabout(instruction))
+        {
+            last_valid_instruction = step_index;
+            has_entered_roundabout = detail::setUpRoundabout(step);
+
+            if (has_entered_roundabout && step_index + 1 < steps.size())
+                steps[step_index + 1].maneuver.exit = step.maneuver.exit;
+        }
+        else if (instruction.type == TurnType::StayOnRoundabout)
+        {
+            on_roundabout = true;
+            // increase the exit number we require passing the exit
+            step.maneuver.exit += 1;
+            if (step_index + 1 < steps.size())
+                steps[step_index + 1].maneuver.exit = step.maneuver.exit;
+        }
+        else if (leavesRoundabout(instruction))
+        {
+            if (!has_entered_roundabout)
+            {
+                // in case the we are not on a roundabout, the very first instruction
+                // after the depart will be transformed into a roundabout and become
+                // the first valid instruction
+                last_valid_instruction = 1;
+            }
+            detail::closeOffRoundabout(has_entered_roundabout, steps, step_index);
+            has_entered_roundabout = false;
+            on_roundabout = false;
+        }
+        else if (instruction.type == TurnType::Suppressed)
+        {
+            // count intersections. We cannot use exit, since intersections can follow directly
+            // after a roundabout
+            steps[last_valid_instruction] = addIntersection(
+                std::move(steps[last_valid_instruction]), steps[step_index - 1], step);
+            step.maneuver.instruction = TurnInstruction::NO_TURN();
+        }
+        else if (!isSilent(instruction))
+        {
+            // Remember the last non silent instruction
+            last_valid_instruction = step_index;
+        }
+    }
+    // unterminated roundabout
+    // Move backwards through the instructions until the start and remove the exit number
+    // A roundabout without exit translates to enter-roundabout.
+    if (has_entered_roundabout || on_roundabout)
+    {
+        detail::fixFinalRoundabout(steps);
+    }
+
+    // finally clean up the post-processed instructions.
+    // Remove all invalid instructions from the set of instructions.
+    // An instruction is invalid, if its NO_TURN and has WaypointType::None.
+    // Two valid NO_TURNs exist in each leg in the form of Depart/Arrive
+
+    // keep valid instructions
+    const auto not_is_valid = [](const RouteStep &step)
+    {
+        return step.maneuver.instruction == TurnInstruction::NO_TURN() &&
+               step.maneuver.waypoint_type == WaypointType::None;
+    };
+
+    boost::remove_erase_if(steps, not_is_valid);
+
+    return steps;
+}
+
+void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
+{
+    // Doing this step in post-processing provides a few challenges we cannot overcome.
+    // The removal of an initial step imposes some copy overhead in the steps, moving all later
+    // steps to the front.
+    // In addition, we cannot reduce the travel time that is accumulated at a different location.
+    // As a direct implication, we have to keep the time of the initial/final turns (which adds a
+    // few seconds of inaccuracy at both ends. This is acceptable, however, since the turn should
+    // usually not be as relevant.
+
+    if (steps.size() < 2 || geometry.locations.size() <= 2)
+        return;
+
+    // if phantom node is located at the connection of two segments, either one can be selected as
+    // turn
+    //
+    // a --- b
+    //       |
+    //       c
+    //
+    // If a route from b to c is requested, both a--b and b--c could be selected as start segment.
+    // In case of a--b, we end up with an unwanted turn saying turn-right onto b-c.
+    // These cases start off with an initial segment which is of zero length.
+    // We have to be careful though, since routing that starts in a roundabout has a valid.
+    // To catch these cases correctly, we have to perform trimming prior to the post-processing
+
+    BOOST_ASSERT(geometry.locations.size() >= steps.size());
+    // Look for distances under 1m
+    const bool zero_length_step = steps.front().distance <= 1;
+    const bool duplicated_coordinate = util::coordinate_calculation::haversineDistance(
+                                           geometry.locations[0], geometry.locations[1]) <= 1;
+    if (zero_length_step || duplicated_coordinate)
+    {
+        // fixup the coordinate
+        geometry.locations.erase(geometry.locations.begin());
+
+        // remove the initial distance value
+        geometry.segment_distances.erase(geometry.segment_distances.begin());
+
+        // We have to adjust the first step both for its name and the bearings
+        if (zero_length_step)
+        {
+            // move offsets to front
+            BOOST_ASSERT(geometry.segment_offsets[1] == 1);
+            // geometry offsets have to be adjusted. Move all offsets to the front and reduce by
+            // one. (This is an inplace forward one and reduce by one)
+            std::transform(geometry.segment_offsets.begin() + 1, geometry.segment_offsets.end(),
+                           geometry.segment_offsets.begin(), [](const std::size_t val)
+                           {
+                               return val - 1;
+                           });
+
+            geometry.segment_offsets.pop_back();
+            const auto &current_depart = steps.front();
+            auto &designated_depart = *(steps.begin() + 1);
+
+            // FIXME this is required to be consistent with the route durations. The initial turn is
+            // not actually part of the route, though
+            designated_depart.duration += current_depart.duration;
+
+            // update initial turn direction/bearings. Due to the duplicated first coordinate, the
+            // initial bearing is invalid
+            designated_depart.maneuver = detail::stepManeuverFromGeometry(
+                TurnInstruction::NO_TURN(), WaypointType::Depart, geometry);
+
+            // finally remove the initial (now duplicated move)
+            steps.erase(steps.begin());
+        }
+        else
+        {
+            steps.front().geometry_begin = 1;
+            // reduce all offsets by one (inplace)
+            std::transform(geometry.segment_offsets.begin(), geometry.segment_offsets.end(),
+                           geometry.segment_offsets.begin(), [](const std::size_t val)
+                           {
+                               return val - 1;
+                           });
+
+            steps.front().maneuver = detail::stepManeuverFromGeometry(
+                TurnInstruction::NO_TURN(), WaypointType::Depart, geometry);
+        }
+
+        // and update the leg geometry indices for the removed entry
+        std::for_each(steps.begin(), steps.end(), [](RouteStep &step)
+                      {
+                          --step.geometry_begin;
+                          --step.geometry_end;
+                      });
+    }
+
+    // make sure we still have enough segments
+    if (steps.size() < 2 || geometry.locations.size() == 2)
+        return;
+
+    BOOST_ASSERT(geometry.locations.size() >= steps.size());
+    auto &next_to_last_step = *(steps.end() - 2);
+    // in the end, the situation with the roundabout cannot occur. As a result, we can remove all
+    // zero-length instructions
+    if (next_to_last_step.distance <= 1)
+    {
+        geometry.locations.pop_back();
+        geometry.segment_offsets.pop_back();
+        BOOST_ASSERT(geometry.segment_distances.back() < 1);
+        geometry.segment_distances.pop_back();
+
+        next_to_last_step.maneuver = detail::stepManeuverFromGeometry(
+            TurnInstruction::NO_TURN(), WaypointType::Arrive, geometry);
+        steps.pop_back();
+
+        // Because we eliminated a really short segment, it was probably
+        // near an intersection.  The convention is *not* to make the
+        // turn, so the `arrive` instruction should be on the same road
+        // as the segment before it.  Thus, we have to copy the names
+        // and travel modes from the new next_to_last step.
+        auto &new_next_to_last = *(steps.end() - 2);
+        next_to_last_step.name = new_next_to_last.name;
+        next_to_last_step.name_id = new_next_to_last.name_id;
+        next_to_last_step.mode = new_next_to_last.mode;
+        // the geometry indices of the last step are already correct;
+    }
+    else if (util::coordinate_calculation::haversineDistance(
+                 geometry.locations[geometry.locations.size() - 2],
+                 geometry.locations[geometry.locations.size() - 1]) <= 1)
+    {
+        // correct steps but duplicated coordinate in the end.
+        // This can happen if the last coordinate snaps to a node in the unpacked geometry
+        geometry.locations.pop_back();
+        geometry.segment_offsets.back()--;
+        BOOST_ASSERT(next_to_last_step.geometry_end == steps.back().geometry_begin);
+        BOOST_ASSERT(next_to_last_step.geometry_begin < next_to_last_step.geometry_end);
+        next_to_last_step.geometry_end--;
+        steps.back().geometry_begin--;
+        steps.back().geometry_end--;
+        steps.back().maneuver = detail::stepManeuverFromGeometry(TurnInstruction::NO_TURN(),
+                                                                 WaypointType::Arrive, geometry);
+    }
+}
+
+// assign relative locations to depart/arrive instructions
+std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
+                                               const LegGeometry &leg_geometry,
+                                               const PhantomNode &source_node,
+                                               const PhantomNode &target_node)
+{
+    // We report the relative position of source/target to the road only within a range that is
+    // sufficiently different but not full of the path
+    BOOST_ASSERT(steps.size() >= 2);
+    BOOST_ASSERT(leg_geometry.locations.size() >= 2);
+    const constexpr double MINIMAL_RELATIVE_DISTANCE = 5., MAXIMAL_RELATIVE_DISTANCE = 300.;
+    const auto distance_to_start = util::coordinate_calculation::haversineDistance(
+        source_node.input_location, leg_geometry.locations[0]);
+    const auto initial_modifier =
+        distance_to_start >= MINIMAL_RELATIVE_DISTANCE &&
+                distance_to_start <= MAXIMAL_RELATIVE_DISTANCE
+            ? angleToDirectionModifier(util::coordinate_calculation::computeAngle(
+                  source_node.input_location, leg_geometry.locations[0], leg_geometry.locations[1]))
+            : extractor::guidance::DirectionModifier::UTurn;
+
+    steps.front().maneuver.instruction.direction_modifier = initial_modifier;
+
+    const auto distance_from_end = util::coordinate_calculation::haversineDistance(
+        target_node.input_location, leg_geometry.locations.back());
+    const auto final_modifier =
+        distance_from_end >= MINIMAL_RELATIVE_DISTANCE &&
+                distance_from_end <= MAXIMAL_RELATIVE_DISTANCE
+            ? angleToDirectionModifier(util::coordinate_calculation::computeAngle(
+                  leg_geometry.locations[leg_geometry.locations.size() - 2],
+                  leg_geometry.locations[leg_geometry.locations.size() - 1],
+                  target_node.input_location))
+            : extractor::guidance::DirectionModifier::UTurn;
+
+    steps.back().maneuver.instruction.direction_modifier = final_modifier;
+    return steps;
+}
+
+LegGeometry resyncGeometry(LegGeometry leg_geometry, const std::vector<RouteStep> &steps)
+{
+    // The geometry uses an adjacency array-like structure for representation.
+    // To sync it back up with the steps, we cann add a segment for every step.
+    leg_geometry.segment_offsets.clear();
+    leg_geometry.segment_distances.clear();
+    leg_geometry.segment_offsets.push_back(0);
+
+    for (const auto &step : steps)
+    {
+        leg_geometry.segment_distances.push_back(step.distance);
+        // the leg geometry does not follow the begin/end-convetion. So we have to subtract one
+        // to get the back-index.
+        leg_geometry.segment_offsets.push_back(step.geometry_end - 1);
+    }
+
+    // remove the data fromt the reached-target step again
+    leg_geometry.segment_offsets.pop_back();
+    leg_geometry.segment_distances.pop_back();
+
+    return leg_geometry;
+}
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
diff --git a/src/engine/hint.cpp b/src/engine/hint.cpp
new file mode 100644
index 0000000..d031fbe
--- /dev/null
+++ b/src/engine/hint.cpp
@@ -0,0 +1,59 @@
+#include "engine/hint.hpp"
+#include "engine/base64.hpp"
+#include "engine/datafacade/datafacade_base.hpp"
+
+#include <boost/assert.hpp>
+
+#include <iterator>
+#include <algorithm>
+#include <ostream>
+#include <tuple>
+
+namespace osrm
+{
+namespace engine
+{
+
+bool Hint::IsValid(const util::Coordinate new_input_coordinates,
+                   const datafacade::BaseDataFacade &facade) const
+{
+    auto is_same_input_coordinate = new_input_coordinates.lon == phantom.input_location.lon &&
+                                    new_input_coordinates.lat == phantom.input_location.lat;
+    return is_same_input_coordinate && phantom.IsValid(facade.GetNumberOfNodes()) &&
+           facade.GetCheckSum() == data_checksum;
+}
+
+std::string Hint::ToBase64() const
+{
+    auto base64 = encodeBase64Bytewise(*this);
+
+    // Make safe for usage as GET parameter in URLs
+    std::replace(begin(base64), end(base64), '+', '-');
+    std::replace(begin(base64), end(base64), '/', '_');
+
+    return base64;
+}
+
+Hint Hint::FromBase64(const std::string &base64Hint)
+{
+    BOOST_ASSERT_MSG(base64Hint.size() == ENCODED_HINT_SIZE, "Hint has invalid size");
+
+    // We need mutability but don't want to change the API
+    auto encoded = base64Hint;
+
+    // Reverses above encoding we need for GET parameters in URL
+    std::replace(begin(encoded), end(encoded), '-', '+');
+    std::replace(begin(encoded), end(encoded), '_', '/');
+
+    return decodeBase64Bytewise<Hint>(encoded);
+}
+
+bool operator==(const Hint &lhs, const Hint &rhs)
+{
+    return std::tie(lhs.phantom, lhs.data_checksum) == std::tie(rhs.phantom, rhs.data_checksum);
+}
+
+std::ostream &operator<<(std::ostream &out, const Hint &hint) { return out << hint.ToBase64(); }
+
+} // ns engine
+} // ns osrm
diff --git a/src/engine/plugins/match.cpp b/src/engine/plugins/match.cpp
new file mode 100644
index 0000000..1fff3fe
--- /dev/null
+++ b/src/engine/plugins/match.cpp
@@ -0,0 +1,197 @@
+#include "engine/plugins/plugin_base.hpp"
+#include "engine/plugins/match.hpp"
+
+#include "engine/map_matching/bayes_classifier.hpp"
+#include "engine/api/match_parameters.hpp"
+#include "engine/api/match_api.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/integer_range.hpp"
+#include "util/json_logger.hpp"
+#include "util/json_util.hpp"
+#include "util/string_util.hpp"
+
+#include <cstdlib>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+// Filters PhantomNodes to obtain a set of viable candiates
+void filterCandidates(const std::vector<util::Coordinate> &coordinates,
+                      MatchPlugin::CandidateLists &candidates_lists)
+{
+    for (const auto current_coordinate : util::irange<std::size_t>(0, coordinates.size()))
+    {
+        bool allow_uturn = false;
+
+        if (coordinates.size() - 1 > current_coordinate && 0 < current_coordinate)
+        {
+            double turn_angle = util::coordinate_calculation::computeAngle(
+                coordinates[current_coordinate - 1], coordinates[current_coordinate],
+                coordinates[current_coordinate + 1]);
+
+            // sharp turns indicate a possible uturn
+            if (turn_angle <= 90.0 || turn_angle >= 270.0)
+            {
+                allow_uturn = true;
+            }
+        }
+
+        auto &candidates = candidates_lists[current_coordinate];
+        if (candidates.empty())
+        {
+            continue;
+        }
+
+        // sort by forward id, then by reverse id and then by distance
+        std::sort(
+            candidates.begin(), candidates.end(),
+            [](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
+            {
+                return lhs.phantom_node.forward_segment_id.id < rhs.phantom_node.forward_segment_id.id ||
+                       (lhs.phantom_node.forward_segment_id.id == rhs.phantom_node.forward_segment_id.id &&
+                        (lhs.phantom_node.reverse_segment_id.id < rhs.phantom_node.reverse_segment_id.id ||
+                         (lhs.phantom_node.reverse_segment_id.id == rhs.phantom_node.reverse_segment_id.id &&
+                          lhs.distance < rhs.distance)));
+            });
+
+        auto new_end = std::unique(
+            candidates.begin(), candidates.end(),
+            [](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
+            {
+                return lhs.phantom_node.forward_segment_id.id == rhs.phantom_node.forward_segment_id.id &&
+                       lhs.phantom_node.reverse_segment_id.id == rhs.phantom_node.reverse_segment_id.id;
+            });
+        candidates.resize(new_end - candidates.begin());
+
+        if (!allow_uturn)
+        {
+            const auto compact_size = candidates.size();
+            for (const auto i : util::irange<std::size_t>(0, compact_size))
+            {
+                // Split edge if it is bidirectional and append reverse direction to end of list
+                if (candidates[i].phantom_node.forward_segment_id.enabled &&
+                    candidates[i].phantom_node.reverse_segment_id.enabled)
+                {
+                    PhantomNode reverse_node(candidates[i].phantom_node);
+                    reverse_node.forward_segment_id.enabled = false;
+                    candidates.push_back(
+                        PhantomNodeWithDistance{reverse_node, candidates[i].distance});
+
+                    candidates[i].phantom_node.reverse_segment_id.enabled = false;
+                }
+            }
+        }
+
+        // sort by distance to make pruning effective
+        std::sort(candidates.begin(), candidates.end(),
+                  [](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
+                  {
+                      return lhs.distance < rhs.distance;
+                  });
+    }
+}
+
+Status MatchPlugin::HandleRequest(const api::MatchParameters &parameters,
+                                  util::json::Object &json_result)
+{
+    BOOST_ASSERT(parameters.IsValid());
+
+    // enforce maximum number of locations for performance reasons
+    if (max_locations_map_matching > 0 &&
+        static_cast<int>(parameters.coordinates.size()) > max_locations_map_matching)
+    {
+        return Error("TooBig", "Too many trace coordinates", json_result);
+    }
+
+    if (!CheckAllCoordinates(parameters.coordinates))
+    {
+        return Error("InvalidValue", "Invalid coordinate value.", json_result);
+    }
+
+    // assuming radius is the standard deviation of a normal distribution
+    // that models GPS noise (in this model), x3 should give us the correct
+    // search radius with > 99% confidence
+    std::vector<double> search_radiuses;
+    if (parameters.radiuses.empty())
+    {
+        search_radiuses.resize(parameters.coordinates.size(),
+                               DEFAULT_GPS_PRECISION * RADIUS_MULTIPLIER);
+    }
+    else
+    {
+        search_radiuses.resize(parameters.coordinates.size());
+        std::transform(parameters.radiuses.begin(), parameters.radiuses.end(),
+                       search_radiuses.begin(), [](const boost::optional<double> &maybe_radius)
+                       {
+                           if (maybe_radius)
+                           {
+                               return *maybe_radius * RADIUS_MULTIPLIER;
+                           }
+                           else
+                           {
+                               return DEFAULT_GPS_PRECISION * RADIUS_MULTIPLIER;
+                           }
+
+                       });
+    }
+
+    auto candidates_lists = GetPhantomNodesInRange(parameters, search_radiuses);
+
+    filterCandidates(parameters.coordinates, candidates_lists);
+    if (std::all_of(candidates_lists.begin(), candidates_lists.end(),
+                    [](const std::vector<PhantomNodeWithDistance> &candidates)
+                    {
+                        return candidates.empty();
+                    }))
+    {
+        return Error("NoSegment",
+                     std::string("Could not find a matching segment for any coordinate."),
+                     json_result);
+    }
+
+    // call the actual map matching
+    SubMatchingList sub_matchings = map_matching(candidates_lists, parameters.coordinates,
+                                                 parameters.timestamps, parameters.radiuses);
+
+    if (sub_matchings.size() == 0)
+    {
+        return Error("NoMatch", "Could not match the trace.", json_result);
+    }
+
+    std::vector<InternalRouteResult> sub_routes(sub_matchings.size());
+    for (auto index : util::irange(0UL, sub_matchings.size()))
+    {
+        BOOST_ASSERT(sub_matchings[index].nodes.size() > 1);
+
+        // FIXME we only run this to obtain the geometry
+        // The clean way would be to get this directly from the map matching plugin
+        PhantomNodes current_phantom_node_pair;
+        for (unsigned i = 0; i < sub_matchings[index].nodes.size() - 1; ++i)
+        {
+            current_phantom_node_pair.source_phantom = sub_matchings[index].nodes[i];
+            current_phantom_node_pair.target_phantom = sub_matchings[index].nodes[i + 1];
+            BOOST_ASSERT(current_phantom_node_pair.source_phantom.IsValid());
+            BOOST_ASSERT(current_phantom_node_pair.target_phantom.IsValid());
+            sub_routes[index].segment_end_coordinates.emplace_back(current_phantom_node_pair);
+        }
+        shortest_path(sub_routes[index].segment_end_coordinates, {}, sub_routes[index]);
+        BOOST_ASSERT(sub_routes[index].shortest_path_length != INVALID_EDGE_WEIGHT);
+    }
+
+    api::MatchAPI match_api{BasePlugin::facade, parameters};
+    match_api.MakeResponse(sub_matchings, sub_routes, json_result);
+
+    return Status::Ok;
+}
+}
+}
+}
diff --git a/src/engine/plugins/nearest.cpp b/src/engine/plugins/nearest.cpp
new file mode 100644
index 0000000..96b63e3
--- /dev/null
+++ b/src/engine/plugins/nearest.cpp
@@ -0,0 +1,49 @@
+#include "engine/plugins/nearest.hpp"
+#include "engine/api/nearest_parameters.hpp"
+#include "engine/api/nearest_api.hpp"
+#include "engine/phantom_node.hpp"
+#include "util/integer_range.hpp"
+
+#include <cstddef>
+#include <string>
+
+#include <boost/assert.hpp>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+NearestPlugin::NearestPlugin(datafacade::BaseDataFacade &facade) : BasePlugin{facade} {}
+
+Status NearestPlugin::HandleRequest(const api::NearestParameters &params,
+                                    util::json::Object &json_result)
+{
+    BOOST_ASSERT(params.IsValid());
+
+    if (!CheckAllCoordinates(params.coordinates))
+        return Error("InvalidOptions", "Coordinates are invalid", json_result);
+
+    if (params.coordinates.size() != 1)
+    {
+        return Error("InvalidOptions", "Only one input coordinate is supported", json_result);
+    }
+
+    auto phantom_nodes = GetPhantomNodes(params, params.number_of_results);
+
+    if (phantom_nodes.front().size() == 0)
+    {
+        return Error("NoSegment", "Could not find a matching segments for coordinate", json_result);
+    }
+    BOOST_ASSERT(phantom_nodes.front().size() > 0);
+
+    api::NearestAPI nearest_api(facade, params);
+    nearest_api.MakeResponse(phantom_nodes, json_result);
+
+    return Status::Ok;
+}
+}
+}
+}
diff --git a/src/engine/plugins/table.cpp b/src/engine/plugins/table.cpp
new file mode 100644
index 0000000..27e3100
--- /dev/null
+++ b/src/engine/plugins/table.cpp
@@ -0,0 +1,76 @@
+#include "engine/plugins/table.hpp"
+
+#include "engine/api/table_parameters.hpp"
+#include "engine/api/table_api.hpp"
+#include "engine/routing_algorithms/many_to_many.hpp"
+#include "engine/search_engine_data.hpp"
+#include "util/string_util.hpp"
+#include "util/json_container.hpp"
+
+#include <cstdlib>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <boost/assert.hpp>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+TablePlugin::TablePlugin(datafacade::BaseDataFacade &facade, const int max_locations_distance_table)
+    : BasePlugin{facade}, distance_table(&facade, heaps),
+      max_locations_distance_table(max_locations_distance_table)
+{
+}
+
+Status TablePlugin::HandleRequest(const api::TableParameters &params, util::json::Object &result)
+{
+    BOOST_ASSERT(params.IsValid());
+
+    if (!CheckAllCoordinates(params.coordinates))
+    {
+        return Error("InvalidOptions", "Coordinates are invalid", result);
+    }
+
+    if (params.bearings.size() > 0 && params.coordinates.size() != params.bearings.size())
+    {
+        return Error("InvalidOptions", "Number of bearings does not match number of coordinates",
+                     result);
+    }
+
+    // Empty sources or destinations means the user wants all of them included, respectively
+    // The ManyToMany routing algorithm we dispatch to below already handles this perfectly.
+    const auto num_sources =
+        params.sources.empty() ? params.coordinates.size() : params.sources.size();
+    const auto num_destinations =
+        params.destinations.empty() ? params.coordinates.size() : params.destinations.size();
+
+    if (max_locations_distance_table > 0 &&
+        ((num_sources * num_destinations) >
+         static_cast<std::size_t>(max_locations_distance_table * max_locations_distance_table)))
+    {
+        return Error("TooBig", "Too many table coordinates", result);
+    }
+
+    auto snapped_phantoms = SnapPhantomNodes(GetPhantomNodes(params));
+    auto result_table = distance_table(snapped_phantoms, params.sources, params.destinations);
+
+    if (result_table.empty())
+    {
+        return Error("NoTable", "No table found", result);
+    }
+
+    api::TableAPI table_api{facade, params};
+    table_api.MakeResponse(result_table, snapped_phantoms, result);
+
+    return Status::Ok;
+}
+}
+}
+}
diff --git a/src/engine/plugins/tile.cpp b/src/engine/plugins/tile.cpp
new file mode 100644
index 0000000..7d18d90
--- /dev/null
+++ b/src/engine/plugins/tile.cpp
@@ -0,0 +1,455 @@
+#include "engine/plugins/plugin_base.hpp"
+#include "engine/plugins/tile.hpp"
+
+#include "util/coordinate_calculation.hpp"
+
+#include <boost/geometry.hpp>
+#include <boost/geometry/geometries/point_xy.hpp>
+#include <boost/geometry/geometries/geometries.hpp>
+#include <boost/geometry/multi/geometries/multi_linestring.hpp>
+
+#include <protozero/varint.hpp>
+#include <protozero/pbf_writer.hpp>
+
+#include <string>
+#include <vector>
+#include <utility>
+
+#include <cmath>
+#include <cstdint>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+namespace detail
+{
+// Vector tiles are 4096 virtual pixels on each side
+const constexpr double VECTOR_TILE_EXTENT = 4096.0;
+const constexpr double VECTOR_TILE_BUFFER = 128.0;
+
+// Simple container class for WGS84 coordinates
+template <typename T> struct Point final
+{
+    Point(T _x, T _y) : x(_x), y(_y) {}
+
+    const T x;
+    const T y;
+};
+
+// from mapnik-vector-tile
+namespace pbf
+{
+inline unsigned encode_length(const unsigned len) { return (len << 3u) | 2u; }
+}
+
+struct BBox final
+{
+    BBox(const double _minx, const double _miny, const double _maxx, const double _maxy)
+        : minx(_minx), miny(_miny), maxx(_maxx), maxy(_maxy)
+    {
+    }
+
+    double width() const { return maxx - minx; }
+    double height() const { return maxy - miny; }
+
+    const double minx;
+    const double miny;
+    const double maxx;
+    const double maxy;
+};
+
+// Simple container for integer coordinates (i.e. pixel coords)
+struct point_type_i final
+{
+    point_type_i(std::int64_t _x, std::int64_t _y) : x(_x), y(_y) {}
+
+    const std::int64_t x;
+    const std::int64_t y;
+};
+
+using FixedLine = std::vector<detail::Point<std::int32_t>>;
+using FloatLine = std::vector<detail::Point<double>>;
+
+typedef boost::geometry::model::point<double, 2, boost::geometry::cs::cartesian> point_t;
+typedef boost::geometry::model::linestring<point_t> linestring_t;
+typedef boost::geometry::model::box<point_t> box_t;
+typedef boost::geometry::model::multi_linestring<linestring_t> multi_linestring_t;
+const static box_t clip_box(point_t(-detail::VECTOR_TILE_BUFFER, -detail::VECTOR_TILE_BUFFER),
+                            point_t(detail::VECTOR_TILE_EXTENT + detail::VECTOR_TILE_BUFFER,
+                                    detail::VECTOR_TILE_EXTENT + detail::VECTOR_TILE_BUFFER));
+
+// from mapnik-vector-tile
+// Encodes a linestring using protobuf zigzag encoding
+inline bool encodeLinestring(const FixedLine &line,
+                             protozero::packed_field_uint32 &geometry,
+                             std::int32_t &start_x,
+                             std::int32_t &start_y)
+{
+    const std::size_t line_size = line.size();
+    if (line_size < 2)
+    {
+        return false;
+    }
+
+    const unsigned line_to_length = static_cast<const unsigned>(line_size) - 1;
+
+    auto pt = line.begin();
+    geometry.add_element(9); // move_to | (1 << 3)
+    geometry.add_element(protozero::encode_zigzag32(pt->x - start_x));
+    geometry.add_element(protozero::encode_zigzag32(pt->y - start_y));
+    start_x = pt->x;
+    start_y = pt->y;
+    geometry.add_element(detail::pbf::encode_length(line_to_length));
+    for (++pt; pt != line.end(); ++pt)
+    {
+        const std::int32_t dx = pt->x - start_x;
+        const std::int32_t dy = pt->y - start_y;
+        geometry.add_element(protozero::encode_zigzag32(dx));
+        geometry.add_element(protozero::encode_zigzag32(dy));
+        start_x = pt->x;
+        start_y = pt->y;
+    }
+    return true;
+}
+
+FixedLine coordinatesToTileLine(const util::Coordinate start,
+                                const util::Coordinate target,
+                                const detail::BBox &tile_bbox)
+{
+    using namespace util::coordinate_calculation;
+    FloatLine geo_line;
+    geo_line.emplace_back(static_cast<double>(util::toFloating(start.lon)),
+                          static_cast<double>(util::toFloating(start.lat)));
+    geo_line.emplace_back(static_cast<double>(util::toFloating(target.lon)),
+                          static_cast<double>(util::toFloating(target.lat)));
+
+    linestring_t unclipped_line;
+
+    for (auto const &pt : geo_line)
+    {
+        double px_merc = pt.x * mercator::DEGREE_TO_PX;
+        double py_merc = mercator::latToY(util::FloatLatitude(pt.y)) * mercator::DEGREE_TO_PX;
+        // convert lon/lat to tile coordinates
+        const auto px = std::round(
+            ((px_merc - tile_bbox.minx) * mercator::TILE_SIZE / tile_bbox.width()) *
+            detail::VECTOR_TILE_EXTENT / util::coordinate_calculation::mercator::TILE_SIZE);
+        const auto py = std::round(
+            ((tile_bbox.maxy - py_merc) * mercator::TILE_SIZE / tile_bbox.height()) *
+            detail::VECTOR_TILE_EXTENT / util::coordinate_calculation::mercator::TILE_SIZE);
+
+        boost::geometry::append(unclipped_line, point_t(px, py));
+    }
+
+    multi_linestring_t clipped_line;
+
+    boost::geometry::intersection(clip_box, unclipped_line, clipped_line);
+
+    FixedLine tile_line;
+
+    // b::g::intersection might return a line with one point if the
+    // original line was very short and coords were dupes
+    if (!clipped_line.empty() && clipped_line[0].size() == 2)
+    {
+        if (clipped_line[0].size() == 2)
+        {
+            for (const auto &p : clipped_line[0])
+            {
+                tile_line.emplace_back(p.get<0>(), p.get<1>());
+            }
+        }
+    }
+
+    return tile_line;
+}
+}
+
+Status TilePlugin::HandleRequest(const api::TileParameters &parameters, std::string &pbf_buffer)
+{
+    BOOST_ASSERT(parameters.IsValid());
+
+    using namespace util::coordinate_calculation;
+    double min_lon, min_lat, max_lon, max_lat;
+
+    // Convert the z,x,y mercator tile coordinates into WGS84 lon/lat values
+    mercator::xyzToWGS84(parameters.x, parameters.y, parameters.z, min_lon, min_lat, max_lon,
+                         max_lat);
+
+    util::Coordinate southwest{util::FloatLongitude(min_lon), util::FloatLatitude(min_lat)};
+    util::Coordinate northeast{util::FloatLongitude(max_lon), util::FloatLatitude(max_lat)};
+
+    // Fetch all the segments that are in our bounding box.
+    // This hits the OSRM StaticRTree
+    const auto edges = facade.GetEdgesInBox(southwest, northeast);
+
+    std::vector<int> used_weights;
+    std::unordered_map<int, std::size_t> weight_offsets;
+    uint8_t max_datasource_id = 0;
+
+    // Loop over all edges once to tally up all the attributes we'll need.
+    // We need to do this so that we know the attribute offsets to use
+    // when we encode each feature in the tile.
+    for (const auto &edge : edges)
+    {
+        int forward_weight = 0, reverse_weight = 0;
+        uint8_t forward_datasource = 0;
+        uint8_t reverse_datasource = 0;
+
+        if (edge.forward_packed_geometry_id != SPECIAL_EDGEID)
+        {
+            std::vector<EdgeWeight> forward_weight_vector;
+            facade.GetUncompressedWeights(edge.forward_packed_geometry_id, forward_weight_vector);
+            forward_weight = forward_weight_vector[edge.fwd_segment_position];
+
+            std::vector<uint8_t> forward_datasource_vector;
+            facade.GetUncompressedDatasources(edge.forward_packed_geometry_id,
+                                              forward_datasource_vector);
+            forward_datasource = forward_datasource_vector[edge.fwd_segment_position];
+
+            if (weight_offsets.find(forward_weight) == weight_offsets.end())
+            {
+                used_weights.push_back(forward_weight);
+                weight_offsets[forward_weight] = used_weights.size() - 1;
+            }
+        }
+
+        if (edge.reverse_packed_geometry_id != SPECIAL_EDGEID)
+        {
+            std::vector<EdgeWeight> reverse_weight_vector;
+            facade.GetUncompressedWeights(edge.reverse_packed_geometry_id, reverse_weight_vector);
+
+            BOOST_ASSERT(edge.fwd_segment_position < reverse_weight_vector.size());
+
+            reverse_weight =
+                reverse_weight_vector[reverse_weight_vector.size() - edge.fwd_segment_position - 1];
+
+            if (weight_offsets.find(reverse_weight) == weight_offsets.end())
+            {
+                used_weights.push_back(reverse_weight);
+                weight_offsets[reverse_weight] = used_weights.size() - 1;
+            }
+            std::vector<uint8_t> reverse_datasource_vector;
+            facade.GetUncompressedDatasources(edge.reverse_packed_geometry_id,
+                                              reverse_datasource_vector);
+            reverse_datasource = reverse_datasource_vector[reverse_datasource_vector.size() -
+                                                           edge.fwd_segment_position - 1];
+        }
+        // Keep track of the highest datasource seen so that we don't write unnecessary
+        // data to the layer attribute values
+        max_datasource_id = std::max(max_datasource_id, forward_datasource);
+        max_datasource_id = std::max(max_datasource_id, reverse_datasource);
+    }
+
+    // TODO: extract speed values for compressed and uncompressed geometries
+
+    // Convert tile coordinates into mercator coordinates
+    mercator::xyzToMercator(parameters.x, parameters.y, parameters.z, min_lon, min_lat, max_lon,
+                            max_lat);
+    const detail::BBox tile_bbox{min_lon, min_lat, max_lon, max_lat};
+
+    // Protobuf serialized blocks when objects go out of scope, hence
+    // the extra scoping below.
+    protozero::pbf_writer tile_writer{pbf_buffer};
+    {
+        // Add a layer object to the PBF stream.  3=='layer' from the vector tile spec (2.1)
+        protozero::pbf_writer layer_writer(tile_writer, 3);
+        // TODO: don't write a layer if there are no features
+
+        layer_writer.add_uint32(15, 2); // version
+        // Field 1 is the "layer name" field, it's a string
+        layer_writer.add_string(1, "speeds"); // name
+        // Field 5 is the tile extent.  It's a uint32 and should be set to 4096
+        // for normal vector tiles.
+        layer_writer.add_uint32(5, 4096); // extent
+
+        // Begin the layer features block
+        {
+            // Each feature gets a unique id, starting at 1
+            unsigned id = 1;
+            for (const auto &edge : edges)
+            {
+                // Get coordinates for start/end nodes of segmet (NodeIDs u and v)
+                const auto a = facade.GetCoordinateOfNode(edge.u);
+                const auto b = facade.GetCoordinateOfNode(edge.v);
+                // Calculate the length in meters
+                const double length = osrm::util::coordinate_calculation::haversineDistance(a, b);
+
+                int forward_weight = 0;
+                int reverse_weight = 0;
+
+                uint8_t forward_datasource = 0;
+                uint8_t reverse_datasource = 0;
+
+                if (edge.forward_packed_geometry_id != SPECIAL_EDGEID)
+                {
+                    std::vector<EdgeWeight> forward_weight_vector;
+                    facade.GetUncompressedWeights(edge.forward_packed_geometry_id,
+                                                  forward_weight_vector);
+                    forward_weight = forward_weight_vector[edge.fwd_segment_position];
+
+                    std::vector<uint8_t> forward_datasource_vector;
+                    facade.GetUncompressedDatasources(edge.forward_packed_geometry_id,
+                                                      forward_datasource_vector);
+                    forward_datasource = forward_datasource_vector[edge.fwd_segment_position];
+                }
+
+                if (edge.reverse_packed_geometry_id != SPECIAL_EDGEID)
+                {
+                    std::vector<EdgeWeight> reverse_weight_vector;
+                    facade.GetUncompressedWeights(edge.reverse_packed_geometry_id,
+                                                  reverse_weight_vector);
+
+                    BOOST_ASSERT(edge.fwd_segment_position < reverse_weight_vector.size());
+
+                    reverse_weight = reverse_weight_vector[reverse_weight_vector.size() -
+                                                           edge.fwd_segment_position - 1];
+
+                    std::vector<uint8_t> reverse_datasource_vector;
+                    facade.GetUncompressedDatasources(edge.reverse_packed_geometry_id,
+                                                      reverse_datasource_vector);
+                    reverse_datasource =
+                        reverse_datasource_vector[reverse_datasource_vector.size() -
+                                                  edge.fwd_segment_position - 1];
+                }
+
+                // Keep track of the highest datasource seen so that we don't write unnecessary
+                // data to the layer attribute values
+                max_datasource_id = std::max(max_datasource_id, forward_datasource);
+                max_datasource_id = std::max(max_datasource_id, reverse_datasource);
+
+                const auto encode_tile_line = [&layer_writer, &edge, &id, &max_datasource_id](
+                    const detail::FixedLine &tile_line, const std::uint32_t speed_kmh,
+                    const std::size_t duration, const std::uint8_t datasource,
+                    std::int32_t &start_x, std::int32_t &start_y)
+                {
+                    // Here, we save the two attributes for our feature: the speed and the
+                    // is_small
+                    // boolean.  We onl serve up speeds from 0-139, so all we do is save the
+                    // first
+                    protozero::pbf_writer feature_writer(layer_writer, 2);
+                    // Field 3 is the "geometry type" field.  Value 2 is "line"
+                    feature_writer.add_enum(3, 2); // geometry type
+                    // Field 1 for the feature is the "id" field.
+                    feature_writer.add_uint64(1, id++); // id
+                    {
+                        // When adding attributes to a feature, we have to write
+                        // pairs of numbers.  The first value is the index in the
+                        // keys array (written later), and the second value is the
+                        // index into the "values" array (also written later).  We're
+                        // not writing the actual speed or bool value here, we're saving
+                        // an index into the "values" array.  This means many features
+                        // can share the same value data, leading to smaller tiles.
+                        protozero::packed_field_uint32 field(feature_writer, 2);
+
+                        field.add_element(0); // "speed" tag key offset
+                        field.add_element(
+                            std::min(speed_kmh, 127u)); // save the speed value, capped at 127
+                        field.add_element(1);           // "is_small" tag key offset
+                        field.add_element(128 +
+                                          (edge.component.is_tiny ? 0 : 1)); // is_small feature
+                        field.add_element(2);                // "datasource" tag key offset
+                        field.add_element(130 + datasource); // datasource value offset
+                        field.add_element(3);                // "duration" tag key offset
+                        field.add_element(130 + max_datasource_id + 1 +
+                                          duration); // duration value offset
+                    }
+                    {
+
+                        // Encode the geometry for the feature
+                        protozero::packed_field_uint32 geometry(feature_writer, 4);
+                        encodeLinestring(tile_line, geometry, start_x, start_y);
+                    }
+                };
+
+                // If this is a valid forward edge, go ahead and add it to the tile
+                if (forward_weight != 0 && edge.forward_segment_id.enabled)
+                {
+                    std::int32_t start_x = 0;
+                    std::int32_t start_y = 0;
+
+                    // Calculate the speed for this line
+                    std::uint32_t speed_kmh =
+                        static_cast<std::uint32_t>(round(length / forward_weight * 10 * 3.6));
+
+                    auto tile_line = coordinatesToTileLine(a, b, tile_bbox);
+                    if (!tile_line.empty())
+                    {
+                        encode_tile_line(tile_line, speed_kmh, weight_offsets[forward_weight],
+                                         forward_datasource, start_x, start_y);
+                    }
+                }
+
+                // Repeat the above for the coordinates reversed and using the `reverse`
+                // properties
+                if (reverse_weight != 0 && edge.reverse_segment_id.enabled)
+                {
+                    std::int32_t start_x = 0;
+                    std::int32_t start_y = 0;
+
+                    // Calculate the speed for this line
+                    std::uint32_t speed_kmh =
+                        static_cast<std::uint32_t>(round(length / reverse_weight * 10 * 3.6));
+
+                    auto tile_line = coordinatesToTileLine(b, a, tile_bbox);
+                    if (!tile_line.empty())
+                    {
+                        encode_tile_line(tile_line, speed_kmh, weight_offsets[reverse_weight],
+                                         reverse_datasource, start_x, start_y);
+                    }
+                }
+            }
+        }
+
+        // Field id 3 is the "keys" attribute
+        // We need two "key" fields, these are referred to with 0 and 1 (their array indexes)
+        // earlier
+        layer_writer.add_string(3, "speed");
+        layer_writer.add_string(3, "is_small");
+        layer_writer.add_string(3, "datasource");
+        layer_writer.add_string(3, "duration");
+
+        // Now, we write out the possible speed value arrays and possible is_tiny
+        // values.  Field type 4 is the "values" field.  It's a variable type field,
+        // so requires a two-step write (create the field, then write its value)
+        for (std::size_t i = 0; i < 128; i++)
+        {
+            // Writing field type 4 == variant type
+            protozero::pbf_writer values_writer(layer_writer, 4);
+            // Attribute value 5 == uin64 type
+            values_writer.add_uint64(5, i);
+        }
+        {
+            protozero::pbf_writer values_writer(layer_writer, 4);
+            // Attribute value 7 == bool type
+            values_writer.add_bool(7, true);
+        }
+        {
+            protozero::pbf_writer values_writer(layer_writer, 4);
+            // Attribute value 7 == bool type
+            values_writer.add_bool(7, false);
+        }
+        for (std::size_t i = 0; i <= max_datasource_id; i++)
+        {
+            // Writing field type 4 == variant type
+            protozero::pbf_writer values_writer(layer_writer, 4);
+            // Attribute value 1 == string type
+            values_writer.add_string(1, facade.GetDatasourceName(i));
+        }
+        for (auto weight : used_weights)
+        {
+            // Writing field type 4 == variant type
+            protozero::pbf_writer values_writer(layer_writer, 4);
+            // Attribute value 2 == float type
+            // Durations come out of OSRM in integer deciseconds, so we convert them
+            // to seconds with a simple /10 for display
+            values_writer.add_double(3, weight / 10.);
+        }
+    }
+
+    return Status::Ok;
+}
+}
+}
+}
diff --git a/src/engine/plugins/trip.cpp b/src/engine/plugins/trip.cpp
new file mode 100644
index 0000000..c834f46
--- /dev/null
+++ b/src/engine/plugins/trip.cpp
@@ -0,0 +1,245 @@
+#include "engine/plugins/trip.hpp"
+
+#include "extractor/tarjan_scc.hpp"
+
+#include "engine/api/trip_api.hpp"
+#include "engine/api/trip_parameters.hpp"
+#include "engine/trip/trip_nearest_neighbour.hpp"
+#include "engine/trip/trip_farthest_insertion.hpp"
+#include "engine/trip/trip_brute_force.hpp"
+#include "util/dist_table_wrapper.hpp"   // to access the dist table more easily
+#include "util/matrix_graph_wrapper.hpp" // wrapper to use tarjan scc on dist table
+#include "util/json_container.hpp"
+
+#include <boost/assert.hpp>
+
+#include <cstdlib>
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+#include <iterator>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+// Object to hold all strongly connected components (scc) of a graph
+// to access all graphs with component ID i, get the iterators by:
+// auto start = std::begin(scc_component.component) + scc_component.range[i];
+// auto end = std::begin(scc_component.component) + scc_component.range[i+1];
+struct SCC_Component
+{
+    // in_component: all NodeIDs sorted by component ID
+    // in_range: index where a new component starts
+    //
+    // example: NodeID 0, 1, 2, 4, 5 are in component 0
+    //          NodeID 3, 6, 7, 8    are in component 1
+    //          => in_component = [0, 1, 2, 4, 5, 3, 6, 7, 8]
+    //          => in_range = [0, 5]
+    SCC_Component(std::vector<NodeID> in_component_nodes, std::vector<size_t> in_range)
+        : component(std::move(in_component_nodes)), range(std::move(in_range))
+    {
+        BOOST_ASSERT_MSG(component.size() > 0, "there's no scc component");
+        BOOST_ASSERT_MSG(*std::max_element(range.begin(), range.end()) == component.size(),
+                         "scc component ranges are out of bound");
+        BOOST_ASSERT_MSG(*std::min_element(range.begin(), range.end()) == 0,
+                         "invalid scc component range");
+        BOOST_ASSERT_MSG(std::is_sorted(std::begin(range), std::end(range)),
+                         "invalid component ranges");
+    }
+
+    std::size_t GetNumberOfComponents() const
+    {
+        BOOST_ASSERT_MSG(range.size() > 0, "there's no range");
+        return range.size() - 1;
+    }
+
+    const std::vector<NodeID> component;
+    std::vector<std::size_t> range;
+};
+
+// takes the number of locations and its duration matrix,
+// identifies and splits the graph in its strongly connected components (scc)
+// and returns an SCC_Component
+SCC_Component SplitUnaccessibleLocations(const std::size_t number_of_locations,
+                                         const util::DistTableWrapper<EdgeWeight> &result_table)
+{
+
+    if (std::find(std::begin(result_table), std::end(result_table), INVALID_EDGE_WEIGHT) ==
+        std::end(result_table))
+    {
+        // whole graph is one scc
+        std::vector<NodeID> location_ids(number_of_locations);
+        std::iota(std::begin(location_ids), std::end(location_ids), 0);
+        std::vector<size_t> range = {0, location_ids.size()};
+        return SCC_Component(std::move(location_ids), std::move(range));
+    }
+
+    // Run TarjanSCC
+    auto wrapper = std::make_shared<util::MatrixGraphWrapper<EdgeWeight>>(result_table.GetTable(),
+                                                                          number_of_locations);
+    auto scc = extractor::TarjanSCC<util::MatrixGraphWrapper<EdgeWeight>>(wrapper);
+    scc.run();
+
+    const auto number_of_components = scc.get_number_of_components();
+
+    std::vector<std::size_t> range_insertion;
+    std::vector<std::size_t> range;
+    range_insertion.reserve(number_of_components);
+    range.reserve(number_of_components);
+
+    std::vector<NodeID> components(number_of_locations, 0);
+
+    std::size_t prefix = 0;
+    for (std::size_t j = 0; j < number_of_components; ++j)
+    {
+        range_insertion.push_back(prefix);
+        range.push_back(prefix);
+        prefix += scc.get_component_size(j);
+    }
+    // senitel
+    range.push_back(components.size());
+
+    for (std::size_t i = 0; i < number_of_locations; ++i)
+    {
+        components[range_insertion[scc.get_component_id(i)]] = i;
+        ++range_insertion[scc.get_component_id(i)];
+    }
+
+    return SCC_Component(std::move(components), std::move(range));
+}
+
+InternalRouteResult TripPlugin::ComputeRoute(const std::vector<PhantomNode> &snapped_phantoms,
+                                             const api::TripParameters &parameters,
+                                             const std::vector<NodeID> &trip)
+{
+    InternalRouteResult min_route;
+    // given he final trip, compute total duration and return the route and location permutation
+    PhantomNodes viapoint;
+    const auto start = std::begin(trip);
+    const auto end = std::end(trip);
+    // computes a roundtrip from the nodes in trip
+    for (auto it = start; it != end; ++it)
+    {
+        const auto from_node = *it;
+        // if from_node is the last node, compute the route from the last to the first location
+        const auto to_node = std::next(it) != end ? *std::next(it) : *start;
+
+        viapoint = PhantomNodes{snapped_phantoms[from_node], snapped_phantoms[to_node]};
+        min_route.segment_end_coordinates.emplace_back(viapoint);
+    }
+    BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size());
+
+    shortest_path(min_route.segment_end_coordinates, parameters.uturns, min_route);
+
+    BOOST_ASSERT_MSG(min_route.shortest_path_length < INVALID_EDGE_WEIGHT, "unroutable route");
+    return min_route;
+}
+
+Status TripPlugin::HandleRequest(const api::TripParameters &parameters,
+                                 util::json::Object &json_result)
+{
+    BOOST_ASSERT(parameters.IsValid());
+
+    // enforce maximum number of locations for performance reasons
+    if (max_locations_trip > 0 &&
+        static_cast<int>(parameters.coordinates.size()) > max_locations_trip)
+    {
+        return Error("TooBig", "Too many trip coordinates", json_result);
+    }
+
+    if (!CheckAllCoordinates(parameters.coordinates))
+    {
+        return Error("InvalidValue", "Invalid coordinate value.", json_result);
+    }
+
+    auto phantom_node_pairs = GetPhantomNodes(parameters);
+    if (phantom_node_pairs.size() != parameters.coordinates.size())
+    {
+        return Error("NoSegment",
+                     std::string("Could not find a matching segment for coordinate ") +
+                         std::to_string(phantom_node_pairs.size()),
+                     json_result);
+    }
+    BOOST_ASSERT(phantom_node_pairs.size() == parameters.coordinates.size());
+
+    auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs);
+
+    const auto number_of_locations = snapped_phantoms.size();
+
+    // compute the duration table of all phantom nodes
+    const auto result_table = util::DistTableWrapper<EdgeWeight>(
+        duration_table(snapped_phantoms, {}, {}), number_of_locations);
+
+    if (result_table.size() == 0)
+    {
+        return Status::Error;
+    }
+
+    const constexpr std::size_t BF_MAX_FEASABLE = 10;
+    BOOST_ASSERT_MSG(result_table.size() == number_of_locations * number_of_locations,
+                     "Distance Table has wrong size");
+
+    // get scc components
+    SCC_Component scc = SplitUnaccessibleLocations(number_of_locations, result_table);
+
+    std::vector<std::vector<NodeID>> trips;
+    trips.reserve(scc.GetNumberOfComponents());
+    // run Trip computation for every SCC
+    for (std::size_t k = 0; k < scc.GetNumberOfComponents(); ++k)
+    {
+        const auto component_size = scc.range[k + 1] - scc.range[k];
+
+        BOOST_ASSERT_MSG(component_size > 0, "invalid component size");
+
+        std::vector<NodeID> scc_route;
+        auto route_begin = std::begin(scc.component) + scc.range[k];
+        auto route_end = std::begin(scc.component) + scc.range[k + 1];
+
+        if (component_size > 1)
+        {
+
+            if (component_size < BF_MAX_FEASABLE)
+            {
+                scc_route =
+                    trip::BruteForceTrip(route_begin, route_end, number_of_locations, result_table);
+            }
+            else
+            {
+                scc_route = trip::FarthestInsertionTrip(route_begin, route_end, number_of_locations,
+                                                        result_table);
+            }
+        }
+        else
+        {
+            scc_route = std::vector<NodeID>(route_begin, route_end);
+        }
+
+        trips.push_back(std::move(scc_route));
+    }
+    if (trips.empty())
+    {
+        return Error("NoTrips", "Cannot find trips", json_result);
+    }
+
+    // compute all round trip routes
+    std::vector<InternalRouteResult> routes;
+    routes.reserve(trips.size());
+    for (const auto &trip : trips)
+    {
+        routes.push_back(ComputeRoute(snapped_phantoms, parameters, trip));
+    }
+
+    api::TripAPI trip_api{BasePlugin::facade, parameters};
+    trip_api.MakeResponse(trips, routes, snapped_phantoms, json_result);
+
+    return Status::Ok;
+}
+}
+}
+}
diff --git a/src/engine/plugins/viaroute.cpp b/src/engine/plugins/viaroute.cpp
new file mode 100644
index 0000000..ffd62b3
--- /dev/null
+++ b/src/engine/plugins/viaroute.cpp
@@ -0,0 +1,129 @@
+#include "engine/plugins/viaroute.hpp"
+#include "engine/datafacade/datafacade_base.hpp"
+#include "engine/api/route_api.hpp"
+#include "engine/status.hpp"
+
+#include "util/for_each_pair.hpp"
+#include "util/integer_range.hpp"
+#include "util/json_container.hpp"
+
+#include <cstdlib>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+ViaRoutePlugin::ViaRoutePlugin(datafacade::BaseDataFacade &facade_, int max_locations_viaroute)
+    : BasePlugin(facade_), shortest_path(&facade_, heaps), alternative_path(&facade_, heaps),
+      direct_shortest_path(&facade_, heaps), max_locations_viaroute(max_locations_viaroute)
+{
+}
+
+Status ViaRoutePlugin::HandleRequest(const api::RouteParameters &route_parameters,
+                                     util::json::Object &json_result)
+{
+    BOOST_ASSERT(route_parameters.IsValid());
+
+    if (max_locations_viaroute > 0 &&
+        (static_cast<int>(route_parameters.coordinates.size()) > max_locations_viaroute))
+    {
+        return Error("TooBig",
+                     "Number of entries " + std::to_string(route_parameters.coordinates.size()) +
+                         " is higher than current maximum (" +
+                         std::to_string(max_locations_viaroute) + ")",
+                     json_result);
+    }
+
+    if (!CheckAllCoordinates(route_parameters.coordinates))
+    {
+        return Error("InvalidValue", "Invalid coordinate value.", json_result);
+    }
+
+    auto phantom_node_pairs = GetPhantomNodes(route_parameters);
+    if (phantom_node_pairs.size() != route_parameters.coordinates.size())
+    {
+        return Error("NoSegment", std::string("Could not find a matching segment for coordinate ") +
+                                      std::to_string(phantom_node_pairs.size()),
+                     json_result);
+    }
+    BOOST_ASSERT(phantom_node_pairs.size() == route_parameters.coordinates.size());
+
+    auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs);
+
+    const bool allow_u_turn_at_via =
+        route_parameters.uturns ? *route_parameters.uturns : facade.GetUTurnsDefault();
+
+    InternalRouteResult raw_route;
+    auto build_phantom_pairs = [&raw_route, allow_u_turn_at_via](const PhantomNode &first_node,
+                                                                 const PhantomNode &second_node)
+    {
+        raw_route.segment_end_coordinates.push_back(PhantomNodes{first_node, second_node});
+        auto &last_inserted = raw_route.segment_end_coordinates.back();
+        // enable forward direction if possible
+        if (last_inserted.source_phantom.forward_segment_id.id != SPECIAL_SEGMENTID)
+        {
+            last_inserted.source_phantom.forward_segment_id.enabled |= allow_u_turn_at_via;
+        }
+        // enable reverse direction if possible
+        if (last_inserted.source_phantom.reverse_segment_id.id != SPECIAL_SEGMENTID)
+        {
+            last_inserted.source_phantom.reverse_segment_id.enabled |= allow_u_turn_at_via;
+        }
+    };
+    util::for_each_pair(snapped_phantoms, build_phantom_pairs);
+
+    if (1 == raw_route.segment_end_coordinates.size())
+    {
+        if (route_parameters.alternatives && facade.GetCoreSize() == 0)
+        {
+            alternative_path(raw_route.segment_end_coordinates.front(), raw_route);
+        }
+        else
+        {
+            direct_shortest_path(raw_route.segment_end_coordinates, raw_route);
+        }
+    }
+    else
+    {
+        shortest_path(raw_route.segment_end_coordinates, route_parameters.uturns, raw_route);
+    }
+
+    // we can only know this after the fact, different SCC ids still
+    // allow for connection in one direction.
+    if (raw_route.is_valid())
+    {
+        api::RouteAPI route_api{BasePlugin::facade, route_parameters};
+        route_api.MakeResponse(raw_route, json_result);
+    }
+    else
+    {
+        auto first_component_id = snapped_phantoms.front().component.id;
+        auto not_in_same_component = std::any_of(snapped_phantoms.begin(), snapped_phantoms.end(),
+                                                 [first_component_id](const PhantomNode &node)
+                                                 {
+                                                     return node.component.id != first_component_id;
+                                                 });
+
+        if (not_in_same_component)
+        {
+            return Error("NoRoute", "Impossible route between points", json_result);
+        }
+        else
+        {
+            return Error("NoRoute", "No route found between points", json_result);
+        }
+    }
+
+    return Status::Ok;
+}
+}
+}
+}
diff --git a/src/engine/polyline_compressor.cpp b/src/engine/polyline_compressor.cpp
new file mode 100644
index 0000000..4cbfe1c
--- /dev/null
+++ b/src/engine/polyline_compressor.cpp
@@ -0,0 +1,128 @@
+#include "engine/polyline_compressor.hpp"
+
+#include <boost/assert.hpp>
+#include <cstddef>
+#include <cstdlib>
+#include <cmath>
+#include <algorithm>
+
+namespace osrm
+{
+namespace engine
+{
+namespace /*detail*/ // anonymous to keep TU local
+{
+
+std::string encode(int number_to_encode)
+{
+    std::string output;
+    while (number_to_encode >= 0x20)
+    {
+        const int next_value = (0x20 | (number_to_encode & 0x1f)) + 63;
+        output += static_cast<char>(next_value);
+        number_to_encode >>= 5;
+    }
+
+    number_to_encode += 63;
+    output += static_cast<char>(number_to_encode);
+    return output;
+}
+
+std::string encode(std::vector<int> &numbers)
+{
+    std::string output;
+    for (auto &number : numbers)
+    {
+        bool isNegative = number < 0;
+
+        if (isNegative)
+        {
+            const unsigned binary = std::llabs(number);
+            const unsigned twos = (~binary) + 1u;
+            number = twos;
+        }
+
+        number <<= 1u;
+
+        if (isNegative)
+        {
+            number = ~number;
+        }
+    }
+    for (const int number : numbers)
+    {
+        output += encode(number);
+    }
+    return output;
+}
+} // anonymous ns
+
+std::string encodePolyline(CoordVectorForwardIter begin, CoordVectorForwardIter end)
+{
+    auto size = std::distance(begin, end);
+    if (size == 0)
+    {
+        return {};
+    }
+
+    std::vector<int> delta_numbers;
+    BOOST_ASSERT(size > 0);
+    delta_numbers.reserve((size - 1) * 2);
+    int current_lat = 0;
+    int current_lon = 0;
+    std::for_each(begin, end,
+                  [&delta_numbers, &current_lat, &current_lon](const util::Coordinate loc)
+                  {
+                      const int lat_diff =
+                          std::round(static_cast<int>(loc.lat) * detail::COORDINATE_TO_POLYLINE) -
+                          current_lat;
+                      const int lon_diff =
+                          std::round(static_cast<int>(loc.lon) * detail::COORDINATE_TO_POLYLINE) -
+                          current_lon;
+                      delta_numbers.emplace_back(lat_diff);
+                      delta_numbers.emplace_back(lon_diff);
+                      current_lat += lat_diff;
+                      current_lon += lon_diff;
+                  });
+    return encode(delta_numbers);
+}
+
+std::vector<util::Coordinate> decodePolyline(const std::string &geometry_string)
+{
+    std::vector<util::Coordinate> new_coordinates;
+    int index = 0, len = geometry_string.size();
+    int lat = 0, lng = 0;
+
+    while (index < len)
+    {
+        int b, shift = 0, result = 0;
+        do
+        {
+            b = geometry_string.at(index++) - 63;
+            result |= (b & 0x1f) << shift;
+            shift += 5;
+        } while (b >= 0x20);
+        int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
+        lat += dlat;
+
+        shift = 0;
+        result = 0;
+        do
+        {
+            b = geometry_string.at(index++) - 63;
+            result |= (b & 0x1f) << shift;
+            shift += 5;
+        } while (b >= 0x20);
+        int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
+        lng += dlng;
+
+        util::Coordinate p;
+        p.lat = util::FixedLatitude(lat * detail::POLYLINE_TO_COORDINATE);
+        p.lon = util::FixedLongitude(lng * detail::POLYLINE_TO_COORDINATE);
+        new_coordinates.push_back(p);
+    }
+
+    return new_coordinates;
+}
+}
+}
diff --git a/src/engine/search_engine_data.cpp b/src/engine/search_engine_data.cpp
new file mode 100644
index 0000000..72963bb
--- /dev/null
+++ b/src/engine/search_engine_data.cpp
@@ -0,0 +1,80 @@
+#include "engine/search_engine_data.hpp"
+
+#include "util/binary_heap.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_1;
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_1;
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_2;
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_2;
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_3;
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_3;
+
+void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes)
+{
+    if (forward_heap_1.get())
+    {
+        forward_heap_1->Clear();
+    }
+    else
+    {
+        forward_heap_1.reset(new QueryHeap(number_of_nodes));
+    }
+
+    if (reverse_heap_1.get())
+    {
+        reverse_heap_1->Clear();
+    }
+    else
+    {
+        reverse_heap_1.reset(new QueryHeap(number_of_nodes));
+    }
+}
+
+void SearchEngineData::InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes)
+{
+    if (forward_heap_2.get())
+    {
+        forward_heap_2->Clear();
+    }
+    else
+    {
+        forward_heap_2.reset(new QueryHeap(number_of_nodes));
+    }
+
+    if (reverse_heap_2.get())
+    {
+        reverse_heap_2->Clear();
+    }
+    else
+    {
+        reverse_heap_2.reset(new QueryHeap(number_of_nodes));
+    }
+}
+
+void SearchEngineData::InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes)
+{
+    if (forward_heap_3.get())
+    {
+        forward_heap_3->Clear();
+    }
+    else
+    {
+        forward_heap_3.reset(new QueryHeap(number_of_nodes));
+    }
+
+    if (reverse_heap_3.get())
+    {
+        reverse_heap_3->Clear();
+    }
+    else
+    {
+        reverse_heap_3.reset(new QueryHeap(number_of_nodes));
+    }
+}
+}
+}
diff --git a/data_structures/compressed_edge_container.cpp b/src/extractor/compressed_edge_container.cpp
similarity index 63%
rename from data_structures/compressed_edge_container.cpp
rename to src/extractor/compressed_edge_container.cpp
index da916ce..70b1f77 100644
--- a/data_structures/compressed_edge_container.cpp
+++ b/src/extractor/compressed_edge_container.cpp
@@ -1,32 +1,5 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "compressed_edge_container.hpp"
-#include "../util/simple_logger.hpp"
+#include "extractor/compressed_edge_container.hpp"
+#include "util/simple_logger.hpp"
 
 #include <boost/assert.hpp>
 #include <boost/filesystem.hpp>
@@ -37,6 +10,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <iostream>
 
+namespace osrm
+{
+namespace extractor
+{
+
 CompressedEdgeContainer::CompressedEdgeContainer()
 {
     m_free_list.reserve(100);
@@ -81,7 +59,7 @@ void CompressedEdgeContainer::SerializeInternalVector(const std::string &path) c
     {
         geometry_out_stream.write((char *)&prefix_sum_of_list_indices, sizeof(unsigned));
 
-        const std::vector<CompressedNode> &current_vector = elem;
+        const std::vector<CompressedEdge> &current_vector = elem;
         const unsigned unpacked_size = current_vector.size();
         BOOST_ASSERT(std::numeric_limits<unsigned>::max() != unpacked_size);
         prefix_sum_of_list_indices += unpacked_size;
@@ -96,26 +74,32 @@ void CompressedEdgeContainer::SerializeInternalVector(const std::string &path) c
     // write compressed geometries
     for (auto &elem : m_compressed_geometries)
     {
-        const std::vector<CompressedNode> &current_vector = elem;
+        const std::vector<CompressedEdge> &current_vector = elem;
         const unsigned unpacked_size = current_vector.size();
         control_sum += unpacked_size;
         BOOST_ASSERT(std::numeric_limits<unsigned>::max() != unpacked_size);
-        for (const CompressedNode current_node : current_vector)
+        for (const auto &current_node : current_vector)
         {
-            geometry_out_stream.write((char *)&(current_node.first), sizeof(NodeID));
+            geometry_out_stream.write((char *)&(current_node), sizeof(CompressedEdge));
         }
     }
     BOOST_ASSERT(control_sum == prefix_sum_of_list_indices);
-    // all done, let's close the resource
-    geometry_out_stream.close();
 }
 
+// Adds info for a compressed edge to the container.   edge_id_2
+// has been removed from the graph, so we have to save These edges/nodes
+// have already been trimmed from the graph, this function just stores
+// the original data for unpacking later.
+//
+//     edge_id_1               edge_id_2
+//   ----------> via_node_id -----------> target_node_id
+//     weight_1                weight_2
 void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
-                                      const EdgeID edge_id_2,
-                                      const NodeID via_node_id,
-                                      const NodeID target_node_id,
-                                      const EdgeWeight weight1,
-                                      const EdgeWeight weight2)
+                                           const EdgeID edge_id_2,
+                                           const NodeID via_node_id,
+                                           const NodeID target_node_id,
+                                           const EdgeWeight weight1,
+                                           const EdgeWeight weight2)
 {
     // remove super-trivial geometries
     BOOST_ASSERT(SPECIAL_EDGEID != edge_id_1);
@@ -153,13 +137,13 @@ void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
     BOOST_ASSERT(edge_bucket_id1 == GetPositionForID(edge_id_1));
     BOOST_ASSERT(edge_bucket_id1 < m_compressed_geometries.size());
 
-    std::vector<CompressedNode> &edge_bucket_list1 = m_compressed_geometries[edge_bucket_id1];
+    std::vector<CompressedEdge> &edge_bucket_list1 = m_compressed_geometries[edge_bucket_id1];
 
     // note we don't save the start coordinate: it is implicitly given by edge 1
     // weight1 is the distance to the (currently) last coordinate in the bucket
     if (edge_bucket_list1.empty())
     {
-        edge_bucket_list1.emplace_back(via_node_id, weight1);
+        edge_bucket_list1.emplace_back(CompressedEdge{via_node_id, weight1});
     }
 
     BOOST_ASSERT(0 < edge_bucket_list1.size());
@@ -171,7 +155,7 @@ void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
         const unsigned list_to_remove_index = GetPositionForID(edge_id_2);
         BOOST_ASSERT(list_to_remove_index < m_compressed_geometries.size());
 
-        std::vector<CompressedNode> &edge_bucket_list2 =
+        std::vector<CompressedEdge> &edge_bucket_list2 =
             m_compressed_geometries[list_to_remove_index];
 
         // found an existing list, append it to the list of edge_id_1
@@ -190,7 +174,48 @@ void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
     else
     {
         // we are certain that the second edge is atomic.
-        edge_bucket_list1.emplace_back(target_node_id, weight2);
+        edge_bucket_list1.emplace_back(CompressedEdge{target_node_id, weight2});
+    }
+}
+
+void CompressedEdgeContainer::AddUncompressedEdge(const EdgeID edge_id,
+                                                  const NodeID target_node_id,
+                                                  const EdgeWeight weight)
+{
+    // remove super-trivial geometries
+    BOOST_ASSERT(SPECIAL_EDGEID != edge_id);
+    BOOST_ASSERT(SPECIAL_NODEID != target_node_id);
+    BOOST_ASSERT(INVALID_EDGE_WEIGHT != weight);
+
+    // Add via node id. List is created if it does not exist
+    if (!HasEntryForID(edge_id))
+    {
+        // create a new entry in the map
+        if (0 == m_free_list.size())
+        {
+            // make sure there is a place to put the entries
+            IncreaseFreeList();
+        }
+        BOOST_ASSERT(!m_free_list.empty());
+        m_edge_id_to_list_index_map[edge_id] = m_free_list.back();
+        m_free_list.pop_back();
+    }
+
+    // find bucket index
+    const auto iter = m_edge_id_to_list_index_map.find(edge_id);
+    BOOST_ASSERT(iter != m_edge_id_to_list_index_map.end());
+    const unsigned edge_bucket_id = iter->second;
+    BOOST_ASSERT(edge_bucket_id == GetPositionForID(edge_id));
+    BOOST_ASSERT(edge_bucket_id < m_compressed_geometries.size());
+
+    std::vector<CompressedEdge> &edge_bucket_list = m_compressed_geometries[edge_bucket_id];
+
+    // note we don't save the start coordinate: it is implicitly given by edge_id
+    // weight is the distance to the (currently) last coordinate in the bucket
+    // Don't re-add this if it's already in there.
+    if (edge_bucket_list.empty())
+    {
+        edge_bucket_list.emplace_back(CompressedEdge{target_node_id, weight});
     }
 }
 
@@ -202,24 +227,23 @@ void CompressedEdgeContainer::PrintStatistics() const
 
     uint64_t compressed_geometries = 0;
     uint64_t longest_chain_length = 0;
-    for (const std::vector<CompressedNode> &current_vector : m_compressed_geometries)
+    for (const std::vector<CompressedEdge> &current_vector : m_compressed_geometries)
     {
         compressed_geometries += current_vector.size();
         longest_chain_length = std::max(longest_chain_length, (uint64_t)current_vector.size());
     }
 
-    SimpleLogger().Write() << "Geometry successfully removed:"
-                              "\n  compressed edges: " << compressed_edges
-                           << "\n  compressed geometries: " << compressed_geometries
-                           << "\n  longest chain length: " << longest_chain_length
-                           << "\n  cmpr ratio: " << ((float)compressed_edges /
-                                                     std::max(compressed_geometries, (uint64_t)1))
-                           << "\n  avg chain length: "
-                           << (float)compressed_geometries /
-                                  std::max((uint64_t)1, compressed_edges);
+    util::SimpleLogger().Write()
+        << "Geometry successfully removed:"
+           "\n  compressed edges: "
+        << compressed_edges << "\n  compressed geometries: " << compressed_geometries
+        << "\n  longest chain length: " << longest_chain_length << "\n  cmpr ratio: "
+        << ((float)compressed_edges / std::max(compressed_geometries, (uint64_t)1))
+        << "\n  avg chain length: "
+        << (float)compressed_geometries / std::max((uint64_t)1, compressed_edges);
 }
 
-const CompressedEdgeContainer::EdgeBucket&
+const CompressedEdgeContainer::EdgeBucket &
 CompressedEdgeContainer::GetBucketReference(const EdgeID edge_id) const
 {
     const unsigned index = m_edge_id_to_list_index_map.at(edge_id);
@@ -230,11 +254,13 @@ NodeID CompressedEdgeContainer::GetFirstEdgeTargetID(const EdgeID edge_id) const
 {
     const auto &bucket = GetBucketReference(edge_id);
     BOOST_ASSERT(bucket.size() >= 2);
-    return bucket.front().first;
+    return bucket.front().node_id;
 }
 NodeID CompressedEdgeContainer::GetLastEdgeSourceID(const EdgeID edge_id) const
 {
     const auto &bucket = GetBucketReference(edge_id);
     BOOST_ASSERT(bucket.size() >= 2);
-    return bucket[bucket.size() - 2].first;
+    return bucket[bucket.size() - 2].node_id;
+}
+}
 }
diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp
new file mode 100644
index 0000000..4cbde57
--- /dev/null
+++ b/src/extractor/edge_based_graph_factory.cpp
@@ -0,0 +1,481 @@
+#include "extractor/edge_based_edge.hpp"
+#include "extractor/edge_based_graph_factory.hpp"
+#include "util/coordinate.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/percent.hpp"
+#include "util/integer_range.hpp"
+#include "util/lua_util.hpp"
+#include "util/simple_logger.hpp"
+#include "util/timing_util.hpp"
+#include "util/exception.hpp"
+
+#include "extractor/guidance/toolkit.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <algorithm>
+#include <cmath>
+#include <fstream>
+#include <iomanip>
+#include <limits>
+#include <sstream>
+#include <string>
+
+namespace osrm
+{
+namespace extractor
+{
+// Configuration to find representative candidate for turn angle calculations
+
+EdgeBasedGraphFactory::EdgeBasedGraphFactory(
+    std::shared_ptr<util::NodeBasedDynamicGraph> node_based_graph,
+    const CompressedEdgeContainer &compressed_edge_container,
+    const std::unordered_set<NodeID> &barrier_nodes,
+    const std::unordered_set<NodeID> &traffic_lights,
+    std::shared_ptr<const RestrictionMap> restriction_map,
+    const std::vector<QueryNode> &node_info_list,
+    ProfileProperties profile_properties,
+    const util::NameTable &name_table)
+    : m_max_edge_id(0), m_node_info_list(node_info_list),
+      m_node_based_graph(std::move(node_based_graph)),
+      m_restriction_map(std::move(restriction_map)), m_barrier_nodes(barrier_nodes),
+      m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container),
+      profile_properties(std::move(profile_properties)), name_table(name_table)
+{
+}
+
+void EdgeBasedGraphFactory::GetEdgeBasedEdges(
+    util::DeallocatingVector<EdgeBasedEdge> &output_edge_list)
+{
+    BOOST_ASSERT_MSG(0 == output_edge_list.size(), "Vector is not empty");
+    using std::swap; // Koenig swap
+    swap(m_edge_based_edge_list, output_edge_list);
+}
+
+void EdgeBasedGraphFactory::GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes)
+{
+#ifndef NDEBUG
+    for (const EdgeBasedNode &node : m_edge_based_node_list)
+    {
+        BOOST_ASSERT(
+            util::Coordinate(m_node_info_list[node.u].lon, m_node_info_list[node.u].lat).IsValid());
+        BOOST_ASSERT(
+            util::Coordinate(m_node_info_list[node.v].lon, m_node_info_list[node.v].lat).IsValid());
+    }
+#endif
+    using std::swap; // Koenig swap
+    swap(nodes, m_edge_based_node_list);
+}
+
+void EdgeBasedGraphFactory::GetStartPointMarkers(std::vector<bool> &node_is_startpoint)
+{
+    using std::swap; // Koenig swap
+    swap(m_edge_based_node_is_startpoint, node_is_startpoint);
+}
+
+void EdgeBasedGraphFactory::GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights)
+{
+    using std::swap; // Koenig swap
+    swap(m_edge_based_node_weights, output_node_weights);
+}
+
+unsigned EdgeBasedGraphFactory::GetHighestEdgeID() { return m_max_edge_id; }
+
+void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeID node_v)
+{
+    // merge edges together into one EdgeBasedNode
+    BOOST_ASSERT(node_u != SPECIAL_NODEID);
+    BOOST_ASSERT(node_v != SPECIAL_NODEID);
+
+    // find forward edge id and
+    const EdgeID edge_id_1 = m_node_based_graph->FindEdge(node_u, node_v);
+    BOOST_ASSERT(edge_id_1 != SPECIAL_EDGEID);
+
+    const EdgeData &forward_data = m_node_based_graph->GetEdgeData(edge_id_1);
+
+    // find reverse edge id and
+    const EdgeID edge_id_2 = m_node_based_graph->FindEdge(node_v, node_u);
+    BOOST_ASSERT(edge_id_2 != SPECIAL_EDGEID);
+
+    const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(edge_id_2);
+
+    if (forward_data.edge_id == SPECIAL_NODEID && reverse_data.edge_id == SPECIAL_NODEID)
+    {
+        return;
+    }
+
+    if (forward_data.edge_id != SPECIAL_NODEID && reverse_data.edge_id == SPECIAL_NODEID)
+        m_edge_based_node_weights[forward_data.edge_id] = INVALID_EDGE_WEIGHT;
+
+    BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_1) ==
+                 m_compressed_edge_container.HasEntryForID(edge_id_2));
+    BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_1));
+    BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_2));
+    const auto &forward_geometry = m_compressed_edge_container.GetBucketReference(edge_id_1);
+    BOOST_ASSERT(forward_geometry.size() ==
+                 m_compressed_edge_container.GetBucketReference(edge_id_2).size());
+    const auto geometry_size = forward_geometry.size();
+
+    // There should always be some geometry
+    BOOST_ASSERT(0 != geometry_size);
+
+    NodeID current_edge_source_coordinate_id = node_u;
+
+    const auto edge_id_to_segment_id = [](const NodeID edge_based_node_id)
+    {
+        if (edge_based_node_id == SPECIAL_NODEID)
+        {
+            return SegmentID{SPECIAL_SEGMENTID, false};
+        }
+
+        return SegmentID{edge_based_node_id, true};
+    };
+
+    // traverse arrays from start and end respectively
+    for (const auto i : util::irange(std::size_t{ 0 }, geometry_size))
+    {
+        BOOST_ASSERT(
+            current_edge_source_coordinate_id ==
+            m_compressed_edge_container.GetBucketReference(edge_id_2)[geometry_size - 1 - i]
+                .node_id);
+        const NodeID current_edge_target_coordinate_id = forward_geometry[i].node_id;
+        BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id);
+
+        // build edges
+        m_edge_based_node_list.emplace_back(
+            edge_id_to_segment_id(forward_data.edge_id),
+            edge_id_to_segment_id(reverse_data.edge_id), current_edge_source_coordinate_id,
+            current_edge_target_coordinate_id, forward_data.name_id,
+            m_compressed_edge_container.GetPositionForID(edge_id_1),
+            m_compressed_edge_container.GetPositionForID(edge_id_2), false, INVALID_COMPONENTID, i,
+            forward_data.travel_mode, reverse_data.travel_mode);
+
+        m_edge_based_node_is_startpoint.push_back(forward_data.startpoint ||
+                                                  reverse_data.startpoint);
+        current_edge_source_coordinate_id = current_edge_target_coordinate_id;
+    }
+
+    BOOST_ASSERT(current_edge_source_coordinate_id == node_v);
+}
+
+void EdgeBasedGraphFactory::FlushVectorToStream(
+    std::ofstream &edge_data_file, std::vector<OriginalEdgeData> &original_edge_data_vector) const
+{
+    if (original_edge_data_vector.empty())
+    {
+        return;
+    }
+    edge_data_file.write((char *)&(original_edge_data_vector[0]),
+                         original_edge_data_vector.size() * sizeof(OriginalEdgeData));
+    original_edge_data_vector.clear();
+}
+
+void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename,
+                                lua_State *lua_state,
+                                const std::string &edge_segment_lookup_filename,
+                                const std::string &edge_penalty_filename,
+                                const bool generate_edge_lookup)
+{
+    TIMER_START(renumber);
+    m_max_edge_id = RenumberEdges() - 1;
+    TIMER_STOP(renumber);
+
+    TIMER_START(generate_nodes);
+    m_edge_based_node_weights.reserve(m_max_edge_id + 1);
+    GenerateEdgeExpandedNodes();
+    TIMER_STOP(generate_nodes);
+
+    TIMER_START(generate_edges);
+    GenerateEdgeExpandedEdges(original_edge_data_filename, lua_state, edge_segment_lookup_filename,
+                              edge_penalty_filename, generate_edge_lookup);
+
+    TIMER_STOP(generate_edges);
+
+    util::SimpleLogger().Write() << "Timing statistics for edge-expanded graph:";
+    util::SimpleLogger().Write() << "Renumbering edges: " << TIMER_SEC(renumber) << "s";
+    util::SimpleLogger().Write() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s";
+    util::SimpleLogger().Write() << "Generating edges: " << TIMER_SEC(generate_edges) << "s";
+}
+
+/// Renumbers all _forward_ edges and sets the edge_id.
+/// A specific numbering is not important. Any unique ID will do.
+/// Returns the number of edge based nodes.
+unsigned EdgeBasedGraphFactory::RenumberEdges()
+{
+    // renumber edge based node of outgoing edges
+    unsigned numbered_edges_count = 0;
+    for (const auto current_node : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
+    {
+        for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
+        {
+            EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
+
+            // only number incoming edges
+            if (edge_data.reversed)
+            {
+                continue;
+            }
+
+            // oneway streets always require this self-loop. Other streets only if a u-turn plus
+            // traversal
+            // of the street takes longer than the loop
+            m_edge_based_node_weights.push_back(edge_data.distance +
+                                                profile_properties.u_turn_penalty);
+
+            BOOST_ASSERT(numbered_edges_count < m_node_based_graph->GetNumberOfEdges());
+            edge_data.edge_id = numbered_edges_count;
+            ++numbered_edges_count;
+
+            BOOST_ASSERT(SPECIAL_NODEID != edge_data.edge_id);
+        }
+    }
+
+    return numbered_edges_count;
+}
+
+/// Creates the nodes in the edge expanded graph from edges in the node-based graph.
+void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
+{
+    util::Percent progress(m_node_based_graph->GetNumberOfNodes());
+
+    // loop over all edges and generate new set of nodes
+    for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
+    {
+        BOOST_ASSERT(node_u != SPECIAL_NODEID);
+        BOOST_ASSERT(node_u < m_node_based_graph->GetNumberOfNodes());
+        progress.printStatus(node_u);
+        for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
+        {
+            const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
+            BOOST_ASSERT(e1 != SPECIAL_EDGEID);
+            const NodeID node_v = m_node_based_graph->GetTarget(e1);
+
+            BOOST_ASSERT(SPECIAL_NODEID != node_v);
+            // pick only every other edge, since we have every edge as an outgoing
+            // and incoming egde
+            if (node_u > node_v)
+            {
+                continue;
+            }
+
+            BOOST_ASSERT(node_u < node_v);
+
+            // if we found a non-forward edge reverse and try again
+            if (edge_data.edge_id == SPECIAL_NODEID)
+            {
+                InsertEdgeBasedNode(node_v, node_u);
+            }
+            else
+            {
+                InsertEdgeBasedNode(node_u, node_v);
+            }
+        }
+    }
+
+    BOOST_ASSERT(m_edge_based_node_list.size() == m_edge_based_node_is_startpoint.size());
+    BOOST_ASSERT(m_max_edge_id + 1 == m_edge_based_node_weights.size());
+
+    util::SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
+                                 << " nodes in edge-expanded graph";
+}
+
+/// Actually it also generates OriginalEdgeData and serializes them...
+void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
+    const std::string &original_edge_data_filename,
+    lua_State *lua_state,
+    const std::string &edge_segment_lookup_filename,
+    const std::string &edge_fixed_penalties_filename,
+    const bool generate_edge_lookup)
+{
+    util::SimpleLogger().Write() << "generating edge-expanded edges";
+
+    BOOST_ASSERT(lua_state != nullptr);
+    const bool use_turn_function = util::luaFunctionExists(lua_state, "turn_function");
+
+    std::size_t node_based_edge_counter = 0;
+    std::size_t original_edges_counter = 0;
+    restricted_turns_counter = 0;
+    skipped_uturns_counter = 0;
+    skipped_barrier_turns_counter = 0;
+
+    std::ofstream edge_data_file(original_edge_data_filename.c_str(), std::ios::binary);
+    std::ofstream edge_segment_file;
+    std::ofstream edge_penalty_file;
+
+    if (generate_edge_lookup)
+    {
+        edge_segment_file.open(edge_segment_lookup_filename.c_str(), std::ios::binary);
+        edge_penalty_file.open(edge_fixed_penalties_filename.c_str(), std::ios::binary);
+    }
+
+    // Writes a dummy value at the front that is updated later with the total length
+    const unsigned length_prefix_empty_space{0};
+    edge_data_file.write(reinterpret_cast<const char *>(&length_prefix_empty_space),
+                         sizeof(length_prefix_empty_space));
+
+    std::vector<OriginalEdgeData> original_edge_data_vector;
+    original_edge_data_vector.reserve(1024 * 1024);
+
+    // Loop over all turns and generate new set of edges.
+    // Three nested loop look super-linear, but we are dealing with a (kind of)
+    // linear number of turns only.
+    util::Percent progress(m_node_based_graph->GetNumberOfNodes());
+    guidance::TurnAnalysis turn_analysis(*m_node_based_graph, m_node_info_list, *m_restriction_map,
+                                         m_barrier_nodes, m_compressed_edge_container, name_table);
+    for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
+    {
+        // progress.printStatus(node_u);
+        for (const EdgeID edge_from_u : m_node_based_graph->GetAdjacentEdgeRange(node_u))
+        {
+            if (m_node_based_graph->GetEdgeData(edge_from_u).reversed)
+            {
+                continue;
+            }
+
+            ++node_based_edge_counter;
+            auto possible_turns = turn_analysis.getTurns(node_u, edge_from_u);
+
+            const NodeID node_v = m_node_based_graph->GetTarget(edge_from_u);
+
+            for (const auto turn : possible_turns)
+            {
+                const double turn_angle = turn.angle;
+
+                // only add an edge if turn is not prohibited
+                const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(edge_from_u);
+                const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(turn.eid);
+
+                BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
+                BOOST_ASSERT(!edge_data1.reversed);
+                BOOST_ASSERT(!edge_data2.reversed);
+
+                // the following is the core of the loop.
+                unsigned distance = edge_data1.distance;
+                if (m_traffic_lights.find(node_v) != m_traffic_lights.end())
+                {
+                    distance += profile_properties.traffic_signal_penalty;
+                }
+
+                const int turn_penalty =
+                    use_turn_function ? GetTurnPenalty(turn_angle, lua_state) : 0;
+                const auto turn_instruction = turn.instruction;
+
+                if (guidance::isUturn(turn_instruction))
+                {
+                    distance += profile_properties.u_turn_penalty;
+                }
+
+                distance += turn_penalty;
+
+                BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_from_u));
+                original_edge_data_vector.emplace_back(
+                    m_compressed_edge_container.GetPositionForID(edge_from_u), edge_data1.name_id,
+                    turn_instruction, edge_data1.travel_mode);
+
+                ++original_edges_counter;
+
+                if (original_edge_data_vector.size() > 1024 * 1024 * 10)
+                {
+                    FlushVectorToStream(edge_data_file, original_edge_data_vector);
+                }
+
+                BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id);
+                BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id);
+
+                // NOTE: potential overflow here if we hit 2^32 routable edges
+                BOOST_ASSERT(m_edge_based_edge_list.size() <= std::numeric_limits<NodeID>::max());
+                m_edge_based_edge_list.emplace_back(edge_data1.edge_id, edge_data2.edge_id,
+                                                    m_edge_based_edge_list.size(), distance, true,
+                                                    false);
+
+                // Here is where we write out the mapping between the edge-expanded edges, and
+                // the node-based edges that are originally used to calculate the `distance`
+                // for the edge-expanded edges.  About 40 lines back, there is:
+                //
+                //                 unsigned distance = edge_data1.distance;
+                //
+                // This tells us that the weight for an edge-expanded-edge is based on the weight
+                // of the *source* node-based edge.  Therefore, we will look up the individual
+                // segments of the source node-based edge, and write out a mapping between
+                // those and the edge-based-edge ID.
+                // External programs can then use this mapping to quickly perform
+                // updates to the edge-expanded-edge based directly on its ID.
+                if (generate_edge_lookup)
+                {
+                    unsigned fixed_penalty = distance - edge_data1.distance;
+                    edge_penalty_file.write(reinterpret_cast<const char *>(&fixed_penalty),
+                                            sizeof(fixed_penalty));
+                    const auto node_based_edges =
+                        m_compressed_edge_container.GetBucketReference(edge_from_u);
+                    NodeID previous = node_u;
+
+                    const unsigned node_count = node_based_edges.size() + 1;
+                    edge_segment_file.write(reinterpret_cast<const char *>(&node_count),
+                                            sizeof(node_count));
+                    const QueryNode &first_node = m_node_info_list[previous];
+                    edge_segment_file.write(reinterpret_cast<const char *>(&first_node.node_id),
+                                            sizeof(first_node.node_id));
+
+                    for (auto target_node : node_based_edges)
+                    {
+                        const QueryNode &from = m_node_info_list[previous];
+                        const QueryNode &to = m_node_info_list[target_node.node_id];
+                        const double segment_length =
+                            util::coordinate_calculation::greatCircleDistance(from, to);
+
+                        edge_segment_file.write(reinterpret_cast<const char *>(&to.node_id),
+                                                sizeof(to.node_id));
+                        edge_segment_file.write(reinterpret_cast<const char *>(&segment_length),
+                                                sizeof(segment_length));
+                        edge_segment_file.write(reinterpret_cast<const char *>(&target_node.weight),
+                                                sizeof(target_node.weight));
+                        previous = target_node.node_id;
+                    }
+                }
+            }
+        }
+    }
+
+    FlushVectorToStream(edge_data_file, original_edge_data_vector);
+
+    // Finally jump back to the empty space at the beginning and write length prefix
+    edge_data_file.seekp(std::ios::beg);
+
+    const auto length_prefix = boost::numeric_cast<unsigned>(original_edges_counter);
+    static_assert(sizeof(length_prefix_empty_space) == sizeof(length_prefix), "type mismatch");
+
+    edge_data_file.write(reinterpret_cast<const char *>(&length_prefix), sizeof(length_prefix));
+
+    util::SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
+                                 << " edge based nodes";
+    util::SimpleLogger().Write() << "Node-based graph contains " << node_based_edge_counter
+                                 << " edges";
+    util::SimpleLogger().Write() << "Edge-expanded graph ...";
+    util::SimpleLogger().Write() << "  contains " << m_edge_based_edge_list.size() << " edges";
+    util::SimpleLogger().Write() << "  skips " << restricted_turns_counter << " turns, "
+                                                                              "defined by "
+                                 << m_restriction_map->size() << " restrictions";
+    util::SimpleLogger().Write() << "  skips " << skipped_uturns_counter << " U turns";
+    util::SimpleLogger().Write() << "  skips " << skipped_barrier_turns_counter
+                                 << " turns over barriers";
+}
+
+int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) const
+{
+    BOOST_ASSERT(lua_state != nullptr);
+    try
+    {
+        // call lua profile to compute turn penalty
+        double penalty = luabind::call_function<double>(lua_state, "turn_function", 180. - angle);
+        return boost::numeric_cast<int>(penalty);
+    }
+    catch (const luabind::error &er)
+    {
+        util::SimpleLogger().Write(logWARNING) << er.what();
+    }
+    return 0;
+}
+
+} // namespace extractor
+} // namespace osrm
diff --git a/extractor/extraction_containers.cpp b/src/extractor/extraction_containers.cpp
similarity index 74%
rename from extractor/extraction_containers.cpp
rename to src/extractor/extraction_containers.cpp
index 48a626b..5106ca9 100644
--- a/extractor/extraction_containers.cpp
+++ b/src/extractor/extraction_containers.cpp
@@ -1,48 +1,20 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "extraction_containers.hpp"
-#include "extraction_way.hpp"
-
-#include "../algorithms/coordinate_calculation.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 "../util/fingerprint.hpp"
-#include "../util/lua_util.hpp"
+#include "extractor/extraction_containers.hpp"
+#include "extractor/extraction_way.hpp"
+
+#include "util/coordinate_calculation.hpp"
+#include "util/range_table.hpp"
+
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+#include "util/timing_util.hpp"
+#include "util/fingerprint.hpp"
+#include "util/lua_util.hpp"
 
 #include <boost/assert.hpp>
 #include <boost/filesystem.hpp>
 #include <boost/filesystem/fstream.hpp>
-#include <boost/ref.hpp>
 #include <boost/numeric/conversion/cast.hpp>
+#include <boost/ref.hpp>
 
 #include <luabind/luabind.hpp>
 
@@ -51,6 +23,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <chrono>
 #include <limits>
 
+namespace
+{
+// Needed for STXXL comparison - STXXL requires max_value(), min_value(), so we can not use
+// std::less<OSMNodeId>{}. Anonymous namespace to keep translation unit local.
+struct OSMNodeIDSTXXLLess
+{
+    using value_type = OSMNodeID;
+    bool operator()(const value_type left, const value_type right) const { return left < right; }
+    value_type max_value() { return MAX_OSM_NODEID; }
+    value_type min_value() { return MIN_OSM_NODEID; }
+};
+}
+
+namespace osrm
+{
+namespace extractor
+{
+
 static const int WRITE_BLOCK_BUFFER_SIZE = 8000;
 
 ExtractionContainers::ExtractionContainers()
@@ -92,16 +82,14 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
     {
         std::ofstream file_out_stream;
         file_out_stream.open(output_file_name.c_str(), std::ios::binary);
-        const FingerPrint fingerprint = FingerPrint::GetValid();
-        file_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
+        const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
+        file_out_stream.write((char *)&fingerprint, sizeof(util::FingerPrint));
 
         PrepareNodes();
         WriteNodes(file_out_stream);
         PrepareEdges(segment_state);
         WriteEdges(file_out_stream);
 
-        file_out_stream.close();
-
         PrepareRestrictions();
         WriteRestrictions(restrictions_file_name);
 
@@ -113,7 +101,7 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
     }
 }
 
-void ExtractionContainers::WriteNames(const std::string& names_file_name) const
+void ExtractionContainers::WriteNames(const std::string &names_file_name) const
 {
     std::cout << "[extractor] writing street name index ... " << std::flush;
     TIMER_START(write_name_index);
@@ -127,12 +115,11 @@ void ExtractionContainers::WriteNames(const std::string& names_file_name) const
     }
 
     // builds and writes the index
-    RangeTable<> name_index_range(name_lengths);
+    util::RangeTable<> name_index_range(name_lengths);
     name_file_stream << name_index_range;
 
     name_file_stream.write((char *)&total_length, sizeof(unsigned));
 
-
     // write all chars consecutively
     char write_buffer[WRITE_BLOCK_BUFFER_SIZE];
     unsigned buffer_len = 0;
@@ -150,7 +137,6 @@ void ExtractionContainers::WriteNames(const std::string& names_file_name) const
 
     name_file_stream.write(write_buffer, buffer_len);
 
-    name_file_stream.close();
     TIMER_STOP(write_name_index);
     std::cout << "ok, after " << TIMER_SEC(write_name_index) << "s" << std::endl;
 }
@@ -159,7 +145,8 @@ void ExtractionContainers::PrepareNodes()
 {
     std::cout << "[extractor] Sorting used nodes        ... " << std::flush;
     TIMER_START(sorting_used_nodes);
-    stxxl::sort(used_node_id_list.begin(), used_node_id_list.end(), Cmp(), stxxl_memory);
+    stxxl::sort(used_node_id_list.begin(), used_node_id_list.end(), OSMNodeIDSTXXLLess(),
+                stxxl_memory);
     TIMER_STOP(sorting_used_nodes);
     std::cout << "ok, after " << TIMER_SEC(sorting_used_nodes) << "s" << std::endl;
 
@@ -210,12 +197,12 @@ void ExtractionContainers::PrepareNodes()
     }
     if (internal_id > std::numeric_limits<NodeID>::max())
     {
-        throw osrm::exception("There are too many nodes remaining after filtering, OSRM only supports 2^32 unique nodes");
+        throw util::exception("There are too many nodes remaining after filtering, OSRM only "
+                              "supports 2^32 unique nodes");
     }
     max_internal_node_id = boost::numeric_cast<NodeID>(internal_id);
     TIMER_STOP(id_map);
     std::cout << "ok, after " << TIMER_SEC(id_map) << "s" << std::endl;
-
 }
 
 void ExtractionContainers::PrepareEdges(lua_State *segment_state)
@@ -240,7 +227,8 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
     {
         if (edge_iterator->result.osm_source_id < node_iterator->node_id)
         {
-            SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference " << edge_iterator->result.source;
+            util::SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference "
+                                                             << edge_iterator->result.source;
             edge_iterator->result.source = SPECIAL_NODEID;
             ++edge_iterator;
             continue;
@@ -276,8 +264,8 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
     // them. This happens when using osmosis with bbox or polygon to extract smaller areas.
     auto markSourcesInvalid = [](InternalExtractorEdge &edge)
     {
-        SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference "
-                                                   << edge.result.source;
+        util::SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference "
+                                                         << edge.result.source;
         edge.result.source = SPECIAL_NODEID;
         edge.result.osm_source_id = SPECIAL_OSM_NODEID;
     };
@@ -288,8 +276,7 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
     // Sort Edges by target
     std::cout << "[extractor] Sorting edges by target   ... " << std::flush;
     TIMER_START(sort_edges_by_target);
-    stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByOSMTargetID(),
-                stxxl_memory);
+    stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByOSMTargetID(), stxxl_memory);
     TIMER_STOP(sort_edges_by_target);
     std::cout << "ok, after " << TIMER_SEC(sort_edges_by_target) << "s" << std::endl;
 
@@ -301,6 +288,8 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
     const auto all_edges_list_end_ = all_edges_list.end();
     const auto all_nodes_list_end_ = all_nodes_list.end();
 
+    const auto has_segment_function = util::luaFunctionExists(segment_state, "segment_function");
+
     while (edge_iterator != all_edges_list_end_ && node_iterator != all_nodes_list_end_)
     {
         // skip all invalid edges
@@ -312,7 +301,9 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
 
         if (edge_iterator->result.osm_target_id < node_iterator->node_id)
         {
-            SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference " << OSMNodeID_to_uint64_t(edge_iterator->result.osm_target_id);
+            util::SimpleLogger().Write(LogLevel::logWARNING)
+                << "Found invalid node reference "
+                << static_cast<uint64_t>(edge_iterator->result.osm_target_id);
             edge_iterator->result.target = SPECIAL_NODEID;
             ++edge_iterator;
             continue;
@@ -325,40 +316,40 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
 
         BOOST_ASSERT(edge_iterator->result.osm_target_id == node_iterator->node_id);
         BOOST_ASSERT(edge_iterator->weight_data.speed >= 0);
-        BOOST_ASSERT(edge_iterator->source_coordinate.lat != std::numeric_limits<int>::min());
-        BOOST_ASSERT(edge_iterator->source_coordinate.lon != std::numeric_limits<int>::min());
+        BOOST_ASSERT(edge_iterator->source_coordinate.lat !=
+                     util::FixedLatitude(std::numeric_limits<int>::min()));
+        BOOST_ASSERT(edge_iterator->source_coordinate.lon !=
+                     util::FixedLongitude(std::numeric_limits<int>::min()));
 
-        const double distance = coordinate_calculation::great_circle_distance(
-            edge_iterator->source_coordinate.lat, edge_iterator->source_coordinate.lon,
-            node_iterator->lat, node_iterator->lon);
+        const double distance = util::coordinate_calculation::greatCircleDistance(
+            edge_iterator->source_coordinate,
+            util::Coordinate(node_iterator->lon, node_iterator->lat));
 
-        if (lua_function_exists(segment_state, "segment_function"))
+        if (has_segment_function)
         {
             luabind::call_function<void>(
-                segment_state, "segment_function",
-                boost::cref(edge_iterator->source_coordinate),
-                boost::cref(*node_iterator),
-                distance,
-                boost::ref(edge_iterator->weight_data));
+                segment_state, "segment_function", boost::cref(edge_iterator->source_coordinate),
+                boost::cref(*node_iterator), distance, boost::ref(edge_iterator->weight_data));
         }
 
-        const double weight = [distance](const InternalExtractorEdge::WeightData& data) {
+        const double weight = [distance](const InternalExtractorEdge::WeightData &data)
+        {
             switch (data.type)
             {
-                case InternalExtractorEdge::WeightType::EDGE_DURATION:
-                case InternalExtractorEdge::WeightType::WAY_DURATION:
-                    return data.duration * 10.;
-                    break;
-                case InternalExtractorEdge::WeightType::SPEED:
-                    return (distance * 10.) / (data.speed / 3.6);
-                    break;
-                case InternalExtractorEdge::WeightType::INVALID:
-                    osrm::exception("invalid weight type");
+            case InternalExtractorEdge::WeightType::EDGE_DURATION:
+            case InternalExtractorEdge::WeightType::WAY_DURATION:
+                return data.duration * 10.;
+                break;
+            case InternalExtractorEdge::WeightType::SPEED:
+                return (distance * 10.) / (data.speed / 3.6);
+                break;
+            case InternalExtractorEdge::WeightType::INVALID:
+                util::exception("invalid weight type");
             }
             return -1.0;
         }(edge_iterator->weight_data);
 
-        auto& edge = edge_iterator->result;
+        auto &edge = edge_iterator->result;
         edge.weight = std::max(1, static_cast<int>(std::floor(weight + .5)));
 
         // assign new node id
@@ -384,8 +375,8 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
     // them. This happens when using osmosis with bbox or polygon to extract smaller areas.
     auto markTargetsInvalid = [](InternalExtractorEdge &edge)
     {
-        SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference "
-                                                   << edge.result.target;
+        util::SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference "
+                                                         << edge.result.target;
         edge.result.target = SPECIAL_NODEID;
     };
     std::for_each(edge_iterator, all_edges_list_end_, markTargetsInvalid);
@@ -395,7 +386,8 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
     // Sort edges by start.
     std::cout << "[extractor] Sorting edges by renumbered start ... " << std::flush;
     TIMER_START(sort_edges_by_renumbered_start);
-    stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByInternalStartThenInternalTargetID(), stxxl_memory);
+    stxxl::sort(all_edges_list.begin(), all_edges_list.end(),
+                CmpEdgeByInternalStartThenInternalTargetID(), stxxl_memory);
     TIMER_STOP(sort_edges_by_renumbered_start);
     std::cout << "ok, after " << TIMER_SEC(sort_edges_by_renumbered_start) << "s" << std::endl;
 
@@ -427,11 +419,13 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
         while (all_edges_list[i].result.source == source &&
                all_edges_list[i].result.target == target)
         {
-            if (all_edges_list[i].result.forward && all_edges_list[i].result.weight < min_forward_weight)
+            if (all_edges_list[i].result.forward &&
+                all_edges_list[i].result.weight < min_forward_weight)
             {
                 min_forward_idx = i;
             }
-            if (all_edges_list[i].result.backward && all_edges_list[i].result.weight < min_backward_weight)
+            if (all_edges_list[i].result.backward &&
+                all_edges_list[i].result.weight < min_backward_weight)
             {
                 min_backward_idx = i;
             }
@@ -440,8 +434,10 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
             i++;
         }
 
-        BOOST_ASSERT(min_forward_idx == std::numeric_limits<unsigned>::max() || min_forward_idx < i);
-        BOOST_ASSERT(min_backward_idx == std::numeric_limits<unsigned>::max() || min_backward_idx < i);
+        BOOST_ASSERT(min_forward_idx == std::numeric_limits<unsigned>::max() ||
+                     min_forward_idx < i);
+        BOOST_ASSERT(min_backward_idx == std::numeric_limits<unsigned>::max() ||
+                     min_backward_idx < i);
         BOOST_ASSERT(min_backward_idx != std::numeric_limits<unsigned>::max() ||
                      min_forward_idx != std::numeric_limits<unsigned>::max());
 
@@ -484,7 +480,7 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
     }
 }
 
-void ExtractionContainers::WriteEdges(std::ofstream& file_out_stream) const
+void ExtractionContainers::WriteEdges(std::ofstream &file_out_stream) const
 {
     std::cout << "[extractor] Writing used edges       ... " << std::flush;
     TIMER_START(write_edges);
@@ -495,7 +491,7 @@ void ExtractionContainers::WriteEdges(std::ofstream& file_out_stream) const
     auto start_position = file_out_stream.tellp();
     file_out_stream.write((char *)&used_edges_counter_buffer, sizeof(unsigned));
 
-    for (const auto& edge : all_edges_list)
+    for (const auto &edge : all_edges_list)
     {
         if (edge.result.source == SPECIAL_NODEID || edge.result.target == SPECIAL_NODEID)
         {
@@ -505,13 +501,13 @@ void ExtractionContainers::WriteEdges(std::ofstream& file_out_stream) const
         // IMPORTANT: here, we're using slicing to only write the data from the base
         // class of NodeBasedEdgeWithOSM
         NodeBasedEdge tmp = edge.result;
-        file_out_stream.write((char*) &tmp, sizeof(NodeBasedEdge));
+        file_out_stream.write((char *)&tmp, sizeof(NodeBasedEdge));
         used_edges_counter++;
     }
 
     if (used_edges_counter > std::numeric_limits<unsigned>::max())
     {
-        throw osrm::exception("There are too many edges, OSRM only supports 2^32");
+        throw util::exception("There are too many edges, OSRM only supports 2^32");
     }
     TIMER_STOP(write_edges);
     std::cout << "ok, after " << TIMER_SEC(write_edges) << "s" << std::endl;
@@ -524,10 +520,10 @@ void ExtractionContainers::WriteEdges(std::ofstream& file_out_stream) const
     file_out_stream.write((char *)&used_edges_counter_buffer, sizeof(unsigned));
     std::cout << "ok" << std::endl;
 
-    SimpleLogger().Write() << "Processed " << used_edges_counter << " edges";
+    util::SimpleLogger().Write() << "Processed " << used_edges_counter << " edges";
 }
 
-void ExtractionContainers::WriteNodes(std::ofstream& file_out_stream) const
+void ExtractionContainers::WriteNodes(std::ofstream &file_out_stream) const
 {
     // write dummy value, will be overwritten later
     std::cout << "[extractor] setting number of nodes   ... " << std::flush;
@@ -564,18 +560,17 @@ void ExtractionContainers::WriteNodes(std::ofstream& file_out_stream) const
     TIMER_STOP(write_nodes);
     std::cout << "ok, after " << TIMER_SEC(write_nodes) << "s" << std::endl;
 
-
-    SimpleLogger().Write() << "Processed " << max_internal_node_id << " nodes";
+    util::SimpleLogger().Write() << "Processed " << max_internal_node_id << " nodes";
 }
 
-void ExtractionContainers::WriteRestrictions(const std::string& path) const
+void ExtractionContainers::WriteRestrictions(const std::string &path) const
 {
     // serialize restrictions
     std::ofstream restrictions_out_stream;
     unsigned written_restriction_count = 0;
     restrictions_out_stream.open(path.c_str(), std::ios::binary);
-    const FingerPrint fingerprint = FingerPrint::GetValid();
-    restrictions_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
+    const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
+    restrictions_out_stream.write((char *)&fingerprint, sizeof(util::FingerPrint));
     const auto count_position = restrictions_out_stream.tellp();
     restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
 
@@ -592,8 +587,7 @@ void ExtractionContainers::WriteRestrictions(const std::string& path) const
     }
     restrictions_out_stream.seekp(count_position);
     restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
-    restrictions_out_stream.close();
-    SimpleLogger().Write() << "usable restrictions: " << written_restriction_count;
+    util::SimpleLogger().Write() << "usable restrictions: " << written_restriction_count;
 }
 
 void ExtractionContainers::PrepareRestrictions()
@@ -605,11 +599,11 @@ void ExtractionContainers::PrepareRestrictions()
     TIMER_STOP(sort_ways);
     std::cout << "ok, after " << TIMER_SEC(sort_ways) << "s" << std::endl;
 
-    std::cout << "[extractor] Sorting " << restrictions_list.size()
-              << " restriction. by from... " << std::flush;
+    std::cout << "[extractor] Sorting " << restrictions_list.size() << " restriction. by from... "
+              << std::flush;
     TIMER_START(sort_restrictions);
-    stxxl::sort(restrictions_list.begin(), restrictions_list.end(),
-                CmpRestrictionContainerByFrom(), stxxl_memory);
+    stxxl::sort(restrictions_list.begin(), restrictions_list.end(), CmpRestrictionContainerByFrom(),
+                stxxl_memory);
     TIMER_STOP(sort_restrictions);
     std::cout << "ok, after " << TIMER_SEC(sort_restrictions) << "s" << std::endl;
 
@@ -623,15 +617,19 @@ void ExtractionContainers::PrepareRestrictions()
     while (way_start_and_end_iterator != way_start_end_id_list_end &&
            restrictions_iterator != restrictions_list_end)
     {
-        if (way_start_and_end_iterator->way_id < OSMWayID(restrictions_iterator->restriction.from.way))
+        if (way_start_and_end_iterator->way_id <
+            OSMWayID(restrictions_iterator->restriction.from.way))
         {
             ++way_start_and_end_iterator;
             continue;
         }
 
-        if (way_start_and_end_iterator->way_id > OSMWayID(restrictions_iterator->restriction.from.way))
+        if (way_start_and_end_iterator->way_id >
+            OSMWayID(restrictions_iterator->restriction.from.way))
         {
-            SimpleLogger().Write(LogLevel::logDEBUG) << "Restriction references invalid way: " << restrictions_iterator->restriction.from.way;
+            util::SimpleLogger().Write(LogLevel::logWARNING)
+                << "Restriction references invalid way: "
+                << restrictions_iterator->restriction.from.way;
             restrictions_iterator->restriction.from.node = SPECIAL_NODEID;
             ++restrictions_iterator;
             continue;
@@ -644,9 +642,11 @@ void ExtractionContainers::PrepareRestrictions()
 
         // check if via is actually valid, if not invalidate
         auto via_id_iter = external_to_internal_node_id_map.find(via_node_id);
-        if(via_id_iter == external_to_internal_node_id_map.end())
+        if (via_id_iter == external_to_internal_node_id_map.end())
         {
-            SimpleLogger().Write(LogLevel::logDEBUG) << "Restriction references invalid node: " << restrictions_iterator->restriction.via.node;
+            util::SimpleLogger().Write(LogLevel::logWARNING)
+                << "Restriction references invalid node: "
+                << restrictions_iterator->restriction.via.node;
             restrictions_iterator->restriction.via.node = SPECIAL_NODEID;
             ++restrictions_iterator;
             continue;
@@ -656,16 +656,34 @@ void ExtractionContainers::PrepareRestrictions()
         {
             // assign new from node id
             auto id_iter = external_to_internal_node_id_map.find(
-                    OSMNodeID(way_start_and_end_iterator->first_segment_target_id));
-            BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
+                OSMNodeID(way_start_and_end_iterator->first_segment_target_id));
+            if (id_iter == external_to_internal_node_id_map.end())
+            {
+                util::SimpleLogger().Write(LogLevel::logWARNING)
+                    << "Way references invalid node: "
+                    << way_start_and_end_iterator->first_segment_target_id;
+                restrictions_iterator->restriction.from.node = SPECIAL_NODEID;
+                ++restrictions_iterator;
+                ++way_start_and_end_iterator;
+                continue;
+            }
             restrictions_iterator->restriction.from.node = id_iter->second;
         }
         else if (OSMNodeID(way_start_and_end_iterator->last_segment_target_id) == via_node_id)
         {
             // assign new from node id
             auto id_iter = external_to_internal_node_id_map.find(
-                    OSMNodeID(way_start_and_end_iterator->last_segment_source_id));
-            BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
+                OSMNodeID(way_start_and_end_iterator->last_segment_source_id));
+            if (id_iter == external_to_internal_node_id_map.end())
+            {
+                util::SimpleLogger().Write(LogLevel::logWARNING)
+                    << "Way references invalid node: "
+                    << way_start_and_end_iterator->last_segment_target_id;
+                restrictions_iterator->restriction.from.node = SPECIAL_NODEID;
+                ++restrictions_iterator;
+                ++way_start_and_end_iterator;
+                continue;
+            }
             restrictions_iterator->restriction.from.node = id_iter->second;
         }
         ++restrictions_iterator;
@@ -676,8 +694,8 @@ void ExtractionContainers::PrepareRestrictions()
 
     std::cout << "[extractor] Sorting restrictions. by to  ... " << std::flush;
     TIMER_START(sort_restrictions_to);
-    stxxl::sort(restrictions_list.begin(), restrictions_list.end(),
-                CmpRestrictionContainerByTo(), stxxl_memory);
+    stxxl::sort(restrictions_list.begin(), restrictions_list.end(), CmpRestrictionContainerByTo(),
+                stxxl_memory);
     TIMER_STOP(sort_restrictions_to);
     std::cout << "ok, after " << TIMER_SEC(sort_restrictions_to) << "s" << std::endl;
 
@@ -691,7 +709,8 @@ void ExtractionContainers::PrepareRestrictions()
     while (way_start_and_end_iterator != way_start_end_id_list_end_ &&
            restrictions_iterator != restrictions_list_end_)
     {
-        if (way_start_and_end_iterator->way_id < OSMWayID(restrictions_iterator->restriction.to.way))
+        if (way_start_and_end_iterator->way_id <
+            OSMWayID(restrictions_iterator->restriction.to.way))
         {
             ++way_start_and_end_iterator;
             continue;
@@ -702,9 +721,12 @@ void ExtractionContainers::PrepareRestrictions()
             ++restrictions_iterator;
             continue;
         }
-        if (way_start_and_end_iterator->way_id > OSMWayID(restrictions_iterator->restriction.to.way))
+        if (way_start_and_end_iterator->way_id >
+            OSMWayID(restrictions_iterator->restriction.to.way))
         {
-            SimpleLogger().Write(LogLevel::logDEBUG) << "Restriction references invalid way: " << restrictions_iterator->restriction.to.way;
+            util::SimpleLogger().Write(LogLevel::logDEBUG)
+                << "Restriction references invalid way: "
+                << restrictions_iterator->restriction.to.way;
             restrictions_iterator->restriction.to.way = SPECIAL_NODEID;
             ++restrictions_iterator;
             continue;
@@ -721,15 +743,33 @@ void ExtractionContainers::PrepareRestrictions()
         if (OSMNodeID(way_start_and_end_iterator->first_segment_source_id) == via_node_id)
         {
             auto to_id_iter = external_to_internal_node_id_map.find(
-                    OSMNodeID(way_start_and_end_iterator->first_segment_target_id));
-            BOOST_ASSERT(to_id_iter != external_to_internal_node_id_map.end());
+                OSMNodeID(way_start_and_end_iterator->first_segment_target_id));
+            if (to_id_iter == external_to_internal_node_id_map.end())
+            {
+                util::SimpleLogger().Write(LogLevel::logWARNING)
+                    << "Way references invalid node: "
+                    << way_start_and_end_iterator->first_segment_source_id;
+                restrictions_iterator->restriction.to.node = SPECIAL_NODEID;
+                ++restrictions_iterator;
+                ++way_start_and_end_iterator;
+                continue;
+            }
             restrictions_iterator->restriction.to.node = to_id_iter->second;
         }
         else if (OSMNodeID(way_start_and_end_iterator->last_segment_target_id) == via_node_id)
         {
             auto to_id_iter = external_to_internal_node_id_map.find(
-                    OSMNodeID(way_start_and_end_iterator->last_segment_source_id));
-            BOOST_ASSERT(to_id_iter != external_to_internal_node_id_map.end());
+                OSMNodeID(way_start_and_end_iterator->last_segment_source_id));
+            if (to_id_iter == external_to_internal_node_id_map.end())
+            {
+                util::SimpleLogger().Write(LogLevel::logWARNING)
+                    << "Way references invalid node: "
+                    << way_start_and_end_iterator->last_segment_source_id;
+                restrictions_iterator->restriction.to.node = SPECIAL_NODEID;
+                ++restrictions_iterator;
+                ++way_start_and_end_iterator;
+                continue;
+            }
             restrictions_iterator->restriction.to.node = to_id_iter->second;
         }
         ++restrictions_iterator;
@@ -737,3 +777,5 @@ void ExtractionContainers::PrepareRestrictions()
     TIMER_STOP(fix_restriction_ends);
     std::cout << "ok, after " << TIMER_SEC(fix_restriction_ends) << "s" << std::endl;
 }
+}
+}
diff --git a/extractor/extractor.cpp b/src/extractor/extractor.cpp
similarity index 57%
rename from extractor/extractor.cpp
rename to src/extractor/extractor.cpp
index 80bd33d..368867d 100644
--- a/extractor/extractor.cpp
+++ b/src/extractor/extractor.cpp
@@ -1,55 +1,30 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "restriction_parser.hpp"
-#include "scripting_environment.hpp"
-
-#include "../data_structures/raster_source.hpp"
-#include "../util/make_unique.hpp"
-#include "../util/simple_logger.hpp"
-#include "../util/timing_util.hpp"
-#include "../util/lua_util.hpp"
-#include "../util/graph_loader.hpp"
-
-#include "../typedefs.h"
-
-#include "../data_structures/static_graph.hpp"
-#include "../data_structures/static_rtree.hpp"
-#include "../data_structures/restriction_map.hpp"
-#include "../data_structures/compressed_edge_container.hpp"
-
-#include "../algorithms/tarjan_scc.hpp"
-#include "../algorithms/crc32_processor.hpp"
+#include "extractor/extractor.hpp"
+
+#include "extractor/edge_based_edge.hpp"
+#include "extractor/extraction_containers.hpp"
+#include "extractor/extraction_node.hpp"
+#include "extractor/extraction_way.hpp"
+#include "extractor/extractor_callbacks.hpp"
+#include "extractor/restriction_parser.hpp"
+#include "extractor/scripting_environment.hpp"
+
+#include "extractor/raster_source.hpp"
+#include "util/io.hpp"
+#include "util/make_unique.hpp"
+#include "util/simple_logger.hpp"
+#include "util/timing_util.hpp"
+#include "util/lua_util.hpp"
+#include "util/graph_loader.hpp"
+#include "util/name_table.hpp"
+
+#include "util/typedefs.hpp"
+
+#include "util/static_graph.hpp"
+#include "util/static_rtree.hpp"
+#include "extractor/compressed_edge_container.hpp"
+#include "extractor/restriction_map.hpp"
+
+#include "extractor/tarjan_scc.hpp"
 
 #include <boost/filesystem.hpp>
 #include <boost/filesystem/fstream.hpp>
@@ -72,6 +47,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <thread>
 #include <unordered_map>
 #include <vector>
+#include <bitset>
+#include <chrono>
+
+namespace osrm
+{
+namespace extractor
+{
 
 /**
  * TODO: Refactor this function into smaller functions for better readability.
@@ -87,16 +69,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * The result of this process are the following files:
  *  .names : Names of all streets, stored as long consecutive string with prefix sum based index
- *  .osrm  : Nodes and edges in a intermediate format that easy to digest for osrm-prepare
- *  .restrictions : Turn restrictions that are used my osrm-prepare to construct the edge-expanded
+ *  .osrm  : Nodes and edges in a intermediate format that easy to digest for osrm-contract
+ *  .restrictions : Turn restrictions that are used by osrm-contract to construct the edge-expanded
  * graph
  *
  */
-int extractor::run()
+int Extractor::run()
 {
+    // setup scripting environment
+    ScriptingEnvironment scripting_environment(config.profile_path.string().c_str());
+
     try
     {
-        LogPolicy::GetInstance().Unmute();
+        util::LogPolicy::GetInstance().Unmute();
         TIMER_START(extracting);
 
         const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
@@ -104,15 +89,12 @@ int extractor::run()
             std::min(recommended_num_threads, config.requested_num_threads);
         tbb::task_scheduler_init init(number_of_threads);
 
-        SimpleLogger().Write() << "Input file: " << config.input_path.filename().string();
-        SimpleLogger().Write() << "Profile: " << config.profile_path.filename().string();
-        SimpleLogger().Write() << "Threads: " << number_of_threads;
-
-        // setup scripting environment
-        ScriptingEnvironment scripting_environment(config.profile_path.string().c_str());
+        util::SimpleLogger().Write() << "Input file: " << config.input_path.filename().string();
+        util::SimpleLogger().Write() << "Profile: " << config.profile_path.filename().string();
+        util::SimpleLogger().Write() << "Threads: " << number_of_threads;
 
         ExtractionContainers extraction_containers;
-        auto extractor_callbacks = osrm::make_unique<ExtractorCallbacks>(extraction_containers);
+        auto extractor_callbacks = util::make_unique<ExtractorCallbacks>(extraction_containers);
 
         const osmium::io::File input_file(config.input_path.string());
         osmium::io::Reader reader(input_file);
@@ -123,18 +105,15 @@ int extractor::run()
         std::atomic<unsigned> number_of_relations{0};
         std::atomic<unsigned> number_of_others{0};
 
-        SimpleLogger().Write() << "Parsing in progress..";
+        util::SimpleLogger().Write() << "Parsing in progress..";
         TIMER_START(parsing);
 
-        lua_State *segment_state = scripting_environment.get_lua_state();
+        auto &main_context = scripting_environment.GetContex();
 
-        if (lua_function_exists(segment_state, "source_function"))
+        // setup raster sources
+        if (util::luaFunctionExists(main_context.state, "source_function"))
         {
-            // bind a single instance of SourceContainer class to relevant lua state
-            SourceContainer sources;
-            luabind::globals(segment_state)["sources"] = sources;
-
-            luabind::call_function<void>(segment_state, "source_function");
+            luabind::call_function<void>(main_context.state, "source_function");
         }
 
         std::string generator = header.get("generator");
@@ -142,7 +121,7 @@ int extractor::run()
         {
             generator = "unknown tool";
         }
-        SimpleLogger().Write() << "input file generated by " << generator;
+        util::SimpleLogger().Write() << "input file generated by " << generator;
 
         // write .timestamp data file
         std::string timestamp = header.get("osmosis_replication_timestamp");
@@ -150,11 +129,10 @@ int extractor::run()
         {
             timestamp = "n/a";
         }
-        SimpleLogger().Write() << "timestamp: " << timestamp;
+        util::SimpleLogger().Write() << "timestamp: " << timestamp;
 
         boost::filesystem::ofstream timestamp_out(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;
@@ -162,7 +140,7 @@ int extractor::run()
         tbb::concurrent_vector<boost::optional<InputRestrictionContainer>> resulting_restrictions;
 
         // setup restriction parser
-        const RestrictionParser restriction_parser(scripting_environment.get_lua_state());
+        const RestrictionParser restriction_parser(main_context.state, main_context.properties);
 
         while (const osmium::memory::Buffer buffer = reader.read())
         {
@@ -185,7 +163,7 @@ int extractor::run()
                 {
                     ExtractionNode result_node;
                     ExtractionWay result_way;
-                    lua_State *local_state = scripting_environment.get_lua_state();
+                    auto &local_context = scripting_environment.GetContex();
 
                     for (auto x = range.begin(), end = range.end(); x != end; ++x)
                     {
@@ -197,7 +175,7 @@ int extractor::run()
                             result_node.clear();
                             ++number_of_nodes;
                             luabind::call_function<void>(
-                                local_state, "node_function",
+                                local_context.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));
@@ -206,7 +184,7 @@ int extractor::run()
                             result_way.clear();
                             ++number_of_ways;
                             luabind::call_function<void>(
-                                local_state, "way_function",
+                                local_context.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));
@@ -241,134 +219,117 @@ int extractor::run()
             }
         }
         TIMER_STOP(parsing);
-        SimpleLogger().Write() << "Parsing finished after " << TIMER_SEC(parsing) << " seconds";
+        util::SimpleLogger().Write() << "Parsing finished after " << TIMER_SEC(parsing)
+                                     << " seconds";
 
-        SimpleLogger().Write() << "Raw input contains " << number_of_nodes.load() << " nodes, "
-                               << number_of_ways.load() << " ways, and "
-                               << number_of_relations.load() << " relations, and "
-                               << number_of_others.load() << " unknown entities";
+        util::SimpleLogger().Write() << "Raw input contains " << number_of_nodes.load()
+                                     << " nodes, " << number_of_ways.load() << " ways, and "
+                                     << number_of_relations.load() << " relations, and "
+                                     << number_of_others.load() << " unknown entities";
 
         extractor_callbacks.reset();
 
         if (extraction_containers.all_edges_list.empty())
         {
-            SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
+            util::SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
             return 1;
         }
 
         extraction_containers.PrepareData(config.output_file_name, config.restriction_file_name,
-                                          config.names_file_name, segment_state);
+                                          config.names_file_name, main_context.state);
+
+        WriteProfileProperties(config.profile_properties_output_path, main_context.properties);
 
         TIMER_STOP(extracting);
-        SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting) << "s";
+        util::SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting)
+                                     << "s";
     }
+    // we do this for scoping
+    // TODO move to own functions
     catch (const std::exception &e)
     {
-        SimpleLogger().Write(logWARNING) << e.what();
+        util::SimpleLogger().Write(logWARNING) << e.what();
         return 1;
     }
-
     try
     {
         // Transform the node-based graph that OSM is based on into an edge-based graph
         // that is better for routing.  Every edge becomes a node, and every valid
         // movement (e.g. turn from A->B, and B->A) becomes an edge
         //
-        //
-        //    // Create a new lua state
 
-        SimpleLogger().Write() << "Generating edge-expanded graph representation";
+        auto &main_context = scripting_environment.GetContex();
+
+        util::SimpleLogger().Write() << "Generating edge-expanded graph representation";
 
         TIMER_START(expansion);
 
-        std::vector<EdgeBasedNode> node_based_edge_list;
-        DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
+        std::vector<EdgeBasedNode> edge_based_node_list;
+        util::DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
         std::vector<bool> node_is_startpoint;
+        std::vector<EdgeWeight> edge_based_node_weights;
         std::vector<QueryNode> internal_to_external_node_map;
-        auto graph_size =
-            BuildEdgeExpandedGraph(internal_to_external_node_map, node_based_edge_list,
-                                   node_is_startpoint, edge_based_edge_list);
+        auto graph_size = BuildEdgeExpandedGraph(main_context.state, main_context.properties,
+                                                 internal_to_external_node_map,
+                                                 edge_based_node_list, node_is_startpoint,
+                                                 edge_based_node_weights, edge_based_edge_list);
 
         auto number_of_node_based_nodes = graph_size.first;
         auto max_edge_id = graph_size.second;
 
         TIMER_STOP(expansion);
 
-        SimpleLogger().Write() << "building r-tree ...";
+        util::SimpleLogger().Write() << "Saving edge-based node weights to file.";
+        TIMER_START(timer_write_node_weights);
+        util::serializeVector(config.edge_based_node_weights_output_path, edge_based_node_weights);
+        TIMER_STOP(timer_write_node_weights);
+        util::SimpleLogger().Write() << "Done writing. (" << TIMER_SEC(timer_write_node_weights)
+                                     << ")";
+
+        util::SimpleLogger().Write() << "building r-tree ...";
         TIMER_START(rtree);
 
-        FindComponents(max_edge_id, edge_based_edge_list, node_based_edge_list);
+        FindComponents(max_edge_id, edge_based_edge_list, edge_based_node_list);
 
-        BuildRTree(std::move(node_based_edge_list), std::move(node_is_startpoint),
+        BuildRTree(std::move(edge_based_node_list), std::move(node_is_startpoint),
                    internal_to_external_node_map);
 
         TIMER_STOP(rtree);
 
-        SimpleLogger().Write() << "writing node map ...";
+        util::SimpleLogger().Write() << "writing node map ...";
         WriteNodeMapping(internal_to_external_node_map);
 
         WriteEdgeBasedGraph(config.edge_graph_output_path, max_edge_id, edge_based_edge_list);
 
-        SimpleLogger().Write() << "Expansion  : "
-                               << (number_of_node_based_nodes / TIMER_SEC(expansion))
-                               << " nodes/sec and " << ((max_edge_id + 1) / TIMER_SEC(expansion))
-                               << " edges/sec";
-        SimpleLogger().Write() << "To prepare the data for routing, run: "
-                               << "./osrm-prepare " << config.output_file_name << std::endl;
+        util::SimpleLogger().Write()
+            << "Expansion  : " << (number_of_node_based_nodes / TIMER_SEC(expansion))
+            << " nodes/sec and " << ((max_edge_id + 1) / TIMER_SEC(expansion)) << " edges/sec";
+        util::SimpleLogger().Write() << "To prepare the data for routing, run: "
+                                     << "./osrm-contract " << config.output_file_name << std::endl;
     }
     catch (const std::exception &e)
     {
-        SimpleLogger().Write(logWARNING) << e.what();
+        util::SimpleLogger().Write(logWARNING) << e.what();
         return 1;
     }
 
     return 0;
 }
 
-/**
-    \brief Setups scripting environment (lua-scripting)
-    Also initializes speed profile.
-*/
-void extractor::SetupScriptingEnvironment(lua_State *lua_state,
-                                          SpeedProfileProperties &speed_profile)
+void Extractor::WriteProfileProperties(const std::string &output_path,
+                                       const ProfileProperties &properties) const
 {
-    // open utility libraries string library;
-    luaL_openlibs(lua_state);
-
-    // adjust lua load path
-    luaAddScriptFolderToLoadPath(lua_state, config.profile_path.string().c_str());
-
-    // Now call our function in a lua script
-    if (0 != luaL_dofile(lua_state, config.profile_path.string().c_str()))
-    {
-        std::stringstream msg;
-        msg << lua_tostring(lua_state, -1) << " occured in scripting block";
-        throw osrm::exception(msg.str());
-    }
-
-    if (0 != luaL_dostring(lua_state, "return traffic_signal_penalty\n"))
-    {
-        std::stringstream msg;
-        msg << lua_tostring(lua_state, -1) << " occured in scripting block";
-        throw osrm::exception(msg.str());
-    }
-    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"))
+    boost::filesystem::ofstream out_stream(output_path);
+    if (!out_stream)
     {
-        std::stringstream msg;
-        msg << lua_tostring(lua_state, -1) << " occured in scripting block";
-        throw osrm::exception(msg.str());
+        throw util::exception("Could not open " + output_path + " for writing.");
     }
 
-    speed_profile.u_turn_penalty = 10 * lua_tointeger(lua_state, -1);
-    speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function");
+    out_stream.write(reinterpret_cast<const char *>(&properties), sizeof(properties));
 }
 
-void extractor::FindComponents(unsigned max_edge_id,
-                               const DeallocatingVector<EdgeBasedEdge> &input_edge_list,
+void Extractor::FindComponents(unsigned max_edge_id,
+                               const util::DeallocatingVector<EdgeBasedEdge> &input_edge_list,
                                std::vector<EdgeBasedNode> &input_nodes) const
 {
     struct UncontractedEdgeData
@@ -390,7 +351,7 @@ void extractor::FindComponents(unsigned max_edge_id,
             return source == rhs.source && target == rhs.target;
         }
     };
-    using UncontractedGraph = StaticGraph<UncontractedEdgeData>;
+    using UncontractedGraph = util::StaticGraph<UncontractedEdgeData>;
     std::vector<InputEdge> edges;
     edges.reserve(input_edge_list.size() * 2);
 
@@ -398,6 +359,8 @@ void extractor::FindComponents(unsigned max_edge_id,
     {
         BOOST_ASSERT_MSG(static_cast<unsigned int>(std::max(edge.weight, 1)) > 0,
                          "edge distance < 1");
+        BOOST_ASSERT(edge.source <= max_edge_id);
+        BOOST_ASSERT(edge.target <= max_edge_id);
         if (edge.forward)
         {
             edges.push_back({edge.source, edge.target, {}});
@@ -412,10 +375,12 @@ void extractor::FindComponents(unsigned max_edge_id,
     // connect forward and backward nodes of each edge
     for (const auto &node : input_nodes)
     {
-        if (node.reverse_edge_based_node_id != SPECIAL_NODEID)
+        if (node.reverse_segment_id.enabled)
         {
-            edges.push_back({node.forward_edge_based_node_id, node.reverse_edge_based_node_id, {}});
-            edges.push_back({node.reverse_edge_based_node_id, node.forward_edge_based_node_id, {}});
+            BOOST_ASSERT(node.forward_segment_id.id <= max_edge_id);
+            BOOST_ASSERT(node.reverse_segment_id.id <= max_edge_id);
+            edges.push_back({node.forward_segment_id.id, node.reverse_segment_id.id, {}});
+            edges.push_back({node.reverse_segment_id.id, node.forward_segment_id.id, {}});
         }
     }
 
@@ -431,10 +396,10 @@ void extractor::FindComponents(unsigned max_edge_id,
 
     for (auto &node : input_nodes)
     {
-        auto forward_component = component_search.get_component_id(node.forward_edge_based_node_id);
-        BOOST_ASSERT(node.reverse_edge_based_node_id == SPECIAL_EDGEID ||
+        auto forward_component = component_search.get_component_id(node.forward_segment_id.id);
+        BOOST_ASSERT(!node.reverse_segment_id.enabled ||
                      forward_component ==
-                         component_search.get_component_id(node.reverse_edge_based_node_id));
+                         component_search.get_component_id(node.reverse_segment_id.id));
 
         const unsigned component_size = component_search.get_component_size(forward_component);
         node.component.is_tiny = component_size < config.small_component_size;
@@ -445,15 +410,15 @@ void extractor::FindComponents(unsigned max_edge_id,
 /**
   \brief Build load restrictions from .restriction file
   */
-std::shared_ptr<RestrictionMap> extractor::LoadRestrictionMap()
+std::shared_ptr<RestrictionMap> Extractor::LoadRestrictionMap()
 {
     boost::filesystem::ifstream input_stream(config.restriction_file_name,
                                              std::ios::in | std::ios::binary);
 
     std::vector<TurnRestriction> restriction_list;
-    loadRestrictionsFromFile(input_stream, restriction_list);
+    util::loadRestrictionsFromFile(input_stream, restriction_list);
 
-    SimpleLogger().Write() << " - " << restriction_list.size() << " restrictions.";
+    util::SimpleLogger().Write() << " - " << restriction_list.size() << " restrictions.";
 
     return std::make_shared<RestrictionMap>(restriction_list);
 }
@@ -461,8 +426,8 @@ std::shared_ptr<RestrictionMap> extractor::LoadRestrictionMap()
 /**
   \brief Load node based graph from .osrm file
   */
-std::shared_ptr<NodeBasedDynamicGraph>
-extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
+std::shared_ptr<util::NodeBasedDynamicGraph>
+Extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
                               std::unordered_set<NodeID> &traffic_lights,
                               std::vector<QueryNode> &internal_to_external_node_map)
 {
@@ -473,11 +438,11 @@ extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
 
     std::vector<NodeID> barrier_list;
     std::vector<NodeID> traffic_light_list;
-    NodeID number_of_node_based_nodes = loadNodesFromFile(
+    NodeID number_of_node_based_nodes = util::loadNodesFromFile(
         input_stream, barrier_list, traffic_light_list, internal_to_external_node_map);
 
-    SimpleLogger().Write() << " - " << barrier_list.size() << " bollard nodes, "
-                           << traffic_light_list.size() << " traffic lights";
+    util::SimpleLogger().Write() << " - " << barrier_list.size() << " bollard nodes, "
+                                 << traffic_light_list.size() << " traffic lights";
 
     // insert into unordered sets for fast lookup
     barrier_nodes.insert(barrier_list.begin(), barrier_list.end());
@@ -488,32 +453,29 @@ extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
     traffic_light_list.clear();
     traffic_light_list.shrink_to_fit();
 
-    loadEdgesFromFile(input_stream, edge_list);
+    util::loadEdgesFromFile(input_stream, edge_list);
 
     if (edge_list.empty())
     {
-        SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
-        return std::shared_ptr<NodeBasedDynamicGraph>();
+        util::SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
+        return std::shared_ptr<util::NodeBasedDynamicGraph>();
     }
 
-    return NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list);
+    return util::NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list);
 }
 
 /**
  \brief Building an edge-expanded graph from node-based input and turn restrictions
 */
 std::pair<std::size_t, std::size_t>
-extractor::BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map,
+Extractor::BuildEdgeExpandedGraph(lua_State *lua_state,
+                                  const ProfileProperties &profile_properties,
+                                  std::vector<QueryNode> &internal_to_external_node_map,
                                   std::vector<EdgeBasedNode> &node_based_edge_list,
                                   std::vector<bool> &node_is_startpoint,
-                                  DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list)
+                                  std::vector<EdgeWeight> &edge_based_node_weights,
+                                  util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list)
 {
-    lua_State *lua_state = luaL_newstate();
-    luabind::open(lua_state);
-
-    SpeedProfileProperties speed_profile;
-    SetupScriptingEnvironment(lua_state, speed_profile);
-
     std::unordered_set<NodeID> barrier_nodes;
     std::unordered_set<NodeID> traffic_lights;
 
@@ -522,30 +484,27 @@ extractor::BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_n
         LoadNodeBasedGraph(barrier_nodes, traffic_lights, internal_to_external_node_map);
 
     CompressedEdgeContainer compressed_edge_container;
-    GraphCompressor graph_compressor(speed_profile);
+    GraphCompressor graph_compressor;
     graph_compressor.Compress(barrier_nodes, traffic_lights, *restriction_map, *node_based_graph,
                               compressed_edge_container);
 
+    compressed_edge_container.SerializeInternalVector(config.geometry_output_path);
+
+    util::NameTable name_table(config.names_file_name);
+
     EdgeBasedGraphFactory edge_based_graph_factory(
         node_based_graph, compressed_edge_container, barrier_nodes, traffic_lights,
         std::const_pointer_cast<RestrictionMap const>(restriction_map),
-        internal_to_external_node_map, speed_profile);
-
-    compressed_edge_container.SerializeInternalVector(config.geometry_output_path);
+        internal_to_external_node_map, profile_properties, name_table);
 
     edge_based_graph_factory.Run(config.edge_output_path, lua_state,
                                  config.edge_segment_lookup_path, config.edge_penalty_path,
-                                 config.generate_edge_lookup
-#ifdef DEBUG_GEOMETRY
-                                 ,
-                                 config.debug_turns_path
-#endif
-                                 );
-    lua_close(lua_state);
+                                 config.generate_edge_lookup);
 
     edge_based_graph_factory.GetEdgeBasedEdges(edge_based_edge_list);
     edge_based_graph_factory.GetEdgeBasedNodes(node_based_edge_list);
     edge_based_graph_factory.GetStartPointMarkers(node_is_startpoint);
+    edge_based_graph_factory.GetEdgeBasedNodeWeights(edge_based_node_weights);
     auto max_edge_id = edge_based_graph_factory.GetHighestEdgeID();
 
     const std::size_t number_of_node_based_nodes = node_based_graph->GetNumberOfNodes();
@@ -555,7 +514,7 @@ extractor::BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_n
 /**
   \brief Writing info on original (node-based) nodes
  */
-void extractor::WriteNodeMapping(const std::vector<QueryNode> &internal_to_external_node_map)
+void Extractor::WriteNodeMapping(const std::vector<QueryNode> &internal_to_external_node_map)
 {
     boost::filesystem::ofstream node_stream(config.node_output_path, std::ios::binary);
     const unsigned size_of_mapping = internal_to_external_node_map.size();
@@ -565,7 +524,6 @@ void extractor::WriteNodeMapping(const std::vector<QueryNode> &internal_to_exter
         node_stream.write((char *)internal_to_external_node_map.data(),
                           size_of_mapping * sizeof(QueryNode));
     }
-    node_stream.close();
 }
 
 /**
@@ -573,20 +531,20 @@ void extractor::WriteNodeMapping(const std::vector<QueryNode> &internal_to_exter
 
     Saves tree into '.ramIndex' and leaves into '.fileIndex'.
  */
-void extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
+void Extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
                            std::vector<bool> node_is_startpoint,
                            const std::vector<QueryNode> &internal_to_external_node_map)
 {
-    SimpleLogger().Write() << "constructing r-tree of " << node_based_edge_list.size()
-                           << " edge elements build on-top of "
-                           << internal_to_external_node_map.size() << " coordinates";
+    util::SimpleLogger().Write() << "constructing r-tree of " << node_based_edge_list.size()
+                                 << " edge elements build on-top of "
+                                 << internal_to_external_node_map.size() << " coordinates";
 
     BOOST_ASSERT(node_is_startpoint.size() == node_based_edge_list.size());
 
     // Filter node based edges based on startpoint
     auto out_iter = node_based_edge_list.begin();
     auto in_iter = node_based_edge_list.begin();
-    for (auto index : osrm::irange<std::size_t>(0, node_is_startpoint.size()))
+    for (auto index : util::irange<std::size_t>(0, node_is_startpoint.size()))
     {
         BOOST_ASSERT(in_iter != node_based_edge_list.end());
         if (node_is_startpoint[index])
@@ -600,25 +558,28 @@ void extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
     node_based_edge_list.resize(new_size);
 
     TIMER_START(construction);
-    StaticRTree<EdgeBasedNode>(node_based_edge_list, config.rtree_nodes_output_path,
-                               config.rtree_leafs_output_path, internal_to_external_node_map);
+    util::StaticRTree<EdgeBasedNode> rtree(node_based_edge_list, config.rtree_nodes_output_path,
+                                           config.rtree_leafs_output_path,
+                                           internal_to_external_node_map);
 
     TIMER_STOP(construction);
-    SimpleLogger().Write() << "finished r-tree construction in " << TIMER_SEC(construction)
-                           << " seconds";
+    util::SimpleLogger().Write() << "finished r-tree construction in " << TIMER_SEC(construction)
+                                 << " seconds";
 }
 
-void extractor::WriteEdgeBasedGraph(std::string const &output_file_filename,
-                                    size_t const max_edge_id,
-                                    DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list)
+void Extractor::WriteEdgeBasedGraph(
+    std::string const &output_file_filename,
+    size_t const max_edge_id,
+    util::DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list)
 {
 
     std::ofstream file_out_stream;
     file_out_stream.open(output_file_filename.c_str(), std::ios::binary);
-    const FingerPrint fingerprint = FingerPrint::GetValid();
-    file_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
+    const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
+    file_out_stream.write((char *)&fingerprint, sizeof(util::FingerPrint));
 
-    std::cout << "[extractor] Writing edge-based-graph egdes       ... " << std::flush;
+    util::SimpleLogger().Write() << "[extractor] Writing edge-based-graph edges       ... "
+                                 << std::flush;
     TIMER_START(write_edges);
 
     size_t number_of_used_edges = edge_based_edge_list.size();
@@ -631,8 +592,9 @@ void extractor::WriteEdgeBasedGraph(std::string const &output_file_filename,
     }
 
     TIMER_STOP(write_edges);
-    std::cout << "ok, after " << TIMER_SEC(write_edges) << "s" << std::endl;
+    util::SimpleLogger().Write() << "ok, after " << TIMER_SEC(write_edges) << "s" << std::endl;
 
-    SimpleLogger().Write() << "Processed " << number_of_used_edges << " edges";
-    file_out_stream.close();
+    util::SimpleLogger().Write() << "Processed " << number_of_used_edges << " edges";
+}
+}
 }
diff --git a/extractor/extractor_callbacks.cpp b/src/extractor/extractor_callbacks.cpp
similarity index 65%
rename from extractor/extractor_callbacks.cpp
rename to src/extractor/extractor_callbacks.cpp
index 2eb1a9b..a289ec6 100644
--- a/extractor/extractor_callbacks.cpp
+++ b/src/extractor/extractor_callbacks.cpp
@@ -1,50 +1,28 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "extractor/extractor_callbacks.hpp"
+#include "extractor/extraction_containers.hpp"
+#include "extractor/extraction_node.hpp"
+#include "extractor/extraction_way.hpp"
+
+#include "extractor/external_memory_node.hpp"
+#include "extractor/restriction.hpp"
+#include "util/simple_logger.hpp"
+#include "util/for_each_pair.hpp"
 
 #include <boost/optional/optional.hpp>
 
 #include <osmium/osm.hpp>
 
-#include <osrm/coordinate.hpp>
+#include "osrm/coordinate.hpp"
 
 #include <limits>
 #include <string>
 #include <vector>
 
+namespace osrm
+{
+namespace extractor
+{
+
 ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containers)
     : external_memory(extraction_containers)
 {
@@ -61,11 +39,9 @@ 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),
-         OSMNodeID(input_node.id()),
-         result_node.barrier,
-         result_node.traffic_lights});
+        {util::toFixed(util::FloatLongitude(input_node.location().lon())),
+         util::toFixed(util::FloatLatitude(input_node.location().lat())),
+         OSMNodeID(input_node.id()), result_node.barrier, result_node.traffic_lights});
 }
 
 void ExtractorCallbacks::ProcessRestriction(
@@ -74,7 +50,7 @@ void ExtractorCallbacks::ProcessRestriction(
     if (restriction)
     {
         external_memory.restrictions_list.push_back(restriction.get());
-        // SimpleLogger().Write() << "from: " << restriction.get().restriction.from.node <<
+        // util::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 ?
@@ -108,8 +84,8 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
 
     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();
+        util::SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << input_way.id()
+                                             << " of size " << input_way.nodes().size();
         return;
     }
 
@@ -147,17 +123,27 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
     if (forward_weight_data.type == InternalExtractorEdge::WeightType::INVALID &&
         backward_weight_data.type == InternalExtractorEdge::WeightType::INVALID)
     {
-        SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << input_way.id();
+        util::SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: "
+                                             << input_way.id();
         return;
     }
 
+    // FIXME this need to be moved into the profiles
+    const char *data = input_way.get_value_by_key("highway");
+    guidance::RoadClassificationData road_classification;
+    if (data)
+    {
+        road_classification.road_class = guidance::functionalRoadClassFromTag(data);
+    }
+
     // 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_lengths.size();
     if (string_map.end() == string_map_iterator)
     {
         auto name_length = std::min<unsigned>(255u, parsed_way.name.size());
-        std::copy(parsed_way.name.c_str(), parsed_way.name.c_str() + name_length, std::back_inserter(external_memory.name_char_data));
+        std::copy(parsed_way.name.c_str(), parsed_way.name.c_str() + name_length,
+                  std::back_inserter(external_memory.name_char_data));
         external_memory.name_lengths.push_back(name_length);
         string_map.insert(std::make_pair(parsed_way.name, name_id));
     }
@@ -187,55 +173,56 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
     {
         BOOST_ASSERT(split_edge == false);
         BOOST_ASSERT(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE);
-        osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(),
+        util::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(),
                             [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
                             {
                                 external_memory.all_edges_list.push_back(InternalExtractorEdge(
-                                    OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()), name_id,
-                                    backward_weight_data, true, false, parsed_way.roundabout,
-                                    parsed_way.is_access_restricted, parsed_way.is_startpoint,
-                                    parsed_way.backward_travel_mode, false));
+                                    OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()),
+                                    name_id, backward_weight_data, true, false,
+                                    parsed_way.roundabout, parsed_way.is_access_restricted,
+                                    parsed_way.is_startpoint, parsed_way.backward_travel_mode,
+                                    false, road_classification));
                             });
 
         external_memory.way_start_end_id_list.push_back(
-            {OSMWayID(input_way.id()),
-             OSMNodeID(input_way.nodes().back().ref()),
+            {OSMWayID(input_way.id()), OSMNodeID(input_way.nodes().back().ref()),
              OSMNodeID(input_way.nodes()[input_way.nodes().size() - 2].ref()),
-             OSMNodeID(input_way.nodes()[1].ref()),
-             OSMNodeID(input_way.nodes()[0].ref())});
+             OSMNodeID(input_way.nodes()[1].ref()), OSMNodeID(input_way.nodes()[0].ref())});
     }
     else
     {
         const bool forward_only =
             split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode;
-        osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(),
+        util::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(),
                             [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
                             {
                                 external_memory.all_edges_list.push_back(InternalExtractorEdge(
-                                    OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()), name_id, forward_weight_data,
-                                    true, !forward_only, parsed_way.roundabout,
-                                    parsed_way.is_access_restricted, parsed_way.is_startpoint, parsed_way.forward_travel_mode,
-                                    split_edge));
+                                    OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()),
+                                    name_id, forward_weight_data, true, !forward_only,
+                                    parsed_way.roundabout, parsed_way.is_access_restricted,
+                                    parsed_way.is_startpoint, parsed_way.forward_travel_mode,
+                                    split_edge, road_classification));
                             });
         if (split_edge)
         {
             BOOST_ASSERT(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE);
-            osrm::for_each_pair(
+            util::for_each_pair(
                 input_way.nodes().cbegin(), input_way.nodes().cend(),
                 [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
                 {
                     external_memory.all_edges_list.push_back(InternalExtractorEdge(
-                        OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()), name_id, backward_weight_data, false,
-                        true, parsed_way.roundabout, parsed_way.is_access_restricted,
-                        parsed_way.is_startpoint, parsed_way.backward_travel_mode, true));
+                        OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()), name_id,
+                        backward_weight_data, false, true, parsed_way.roundabout,
+                        parsed_way.is_access_restricted, parsed_way.is_startpoint,
+                        parsed_way.backward_travel_mode, true, road_classification));
                 });
         }
 
         external_memory.way_start_end_id_list.push_back(
-            {OSMWayID(input_way.id()),
-             OSMNodeID(input_way.nodes().back().ref()),
+            {OSMWayID(input_way.id()), OSMNodeID(input_way.nodes().back().ref()),
              OSMNodeID(input_way.nodes()[input_way.nodes().size() - 2].ref()),
-             OSMNodeID(input_way.nodes()[1].ref()),
-             OSMNodeID(input_way.nodes()[0].ref())});
+             OSMNodeID(input_way.nodes()[1].ref()), OSMNodeID(input_way.nodes()[0].ref())});
     }
 }
+}
+}
diff --git a/algorithms/graph_compressor.cpp b/src/extractor/graph_compressor.cpp
similarity index 65%
rename from algorithms/graph_compressor.cpp
rename to src/extractor/graph_compressor.cpp
index f3b5f8d..6df9a38 100644
--- a/algorithms/graph_compressor.cpp
+++ b/src/extractor/graph_compressor.cpp
@@ -1,31 +1,30 @@
-#include "graph_compressor.hpp"
+#include "extractor/graph_compressor.hpp"
 
-#include "../data_structures/compressed_edge_container.hpp"
-#include "../data_structures/dynamic_graph.hpp"
-#include "../data_structures/node_based_graph.hpp"
-#include "../data_structures/restriction_map.hpp"
-#include "../data_structures/percent.hpp"
+#include "extractor/compressed_edge_container.hpp"
+#include "extractor/restriction_map.hpp"
+#include "util/dynamic_graph.hpp"
+#include "util/node_based_graph.hpp"
+#include "util/percent.hpp"
 
-#include "../util/simple_logger.hpp"
+#include "util/simple_logger.hpp"
 
-GraphCompressor::GraphCompressor(SpeedProfileProperties speed_profile)
-    : speed_profile(std::move(speed_profile))
+namespace osrm
+{
+namespace extractor
 {
-}
-
 
-void GraphCompressor::Compress(const std::unordered_set<NodeID>& barrier_nodes,
-                               const std::unordered_set<NodeID>& traffic_lights,
-                               RestrictionMap& restriction_map,
-                               NodeBasedDynamicGraph& graph,
-                               CompressedEdgeContainer& geometry_compressor)
+void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
+                               const std::unordered_set<NodeID> &traffic_lights,
+                               RestrictionMap &restriction_map,
+                               util::NodeBasedDynamicGraph &graph,
+                               CompressedEdgeContainer &geometry_compressor)
 {
     const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
     const unsigned original_number_of_edges = graph.GetNumberOfEdges();
 
-    Percent progress(original_number_of_nodes);
+    util::Percent progress(original_number_of_nodes);
 
-    for (const NodeID node_v : osrm::irange(0u, original_number_of_nodes))
+    for (const NodeID node_v : util::irange(0u, original_number_of_nodes))
     {
         progress.printStatus(node_v);
 
@@ -64,12 +63,10 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID>& barrier_nodes,
         const bool reverse_edge_order = graph.GetEdgeData(graph.BeginEdges(node_v)).reversed;
         const EdgeID forward_e2 = graph.BeginEdges(node_v) + reverse_edge_order;
         BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
-        BOOST_ASSERT(forward_e2 >= graph.BeginEdges(node_v) &&
-                     forward_e2 < graph.EndEdges(node_v));
+        BOOST_ASSERT(forward_e2 >= graph.BeginEdges(node_v) && forward_e2 < graph.EndEdges(node_v));
         const EdgeID reverse_e2 = graph.BeginEdges(node_v) + 1 - reverse_edge_order;
         BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2);
-        BOOST_ASSERT(reverse_e2 >= graph.BeginEdges(node_v) &&
-                     reverse_e2 < graph.EndEdges(node_v));
+        BOOST_ASSERT(reverse_e2 >= graph.BeginEdges(node_v) && reverse_e2 < graph.EndEdges(node_v));
 
         const EdgeData &fwd_edge_data2 = graph.GetEdgeData(forward_e2);
         const EdgeData &rev_edge_data2 = graph.GetEdgeData(reverse_e2);
@@ -103,13 +100,24 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID>& barrier_nodes,
             continue;
         }
 
-        if (fwd_edge_data1.IsCompatibleTo(fwd_edge_data2) && rev_edge_data1.IsCompatibleTo(rev_edge_data2))
+        if (fwd_edge_data1.IsCompatibleTo(fwd_edge_data2) &&
+            rev_edge_data1.IsCompatibleTo(rev_edge_data2))
         {
             BOOST_ASSERT(graph.GetEdgeData(forward_e1).name_id ==
                          graph.GetEdgeData(reverse_e1).name_id);
             BOOST_ASSERT(graph.GetEdgeData(forward_e2).name_id ==
                          graph.GetEdgeData(reverse_e2).name_id);
 
+            // Do not compress edge if it crosses a traffic signal.
+            // This can't be done in IsCompatibleTo, becase we only store the
+            // traffic signals in the `traffic_lights` list, which EdgeData
+            // doesn't have access to.
+            const bool has_node_penalty = traffic_lights.find(node_v) != traffic_lights.end();
+            if (has_node_penalty)
+            {
+                continue;
+            }
+
             // Get distances before graph is modified
             const int forward_weight1 = graph.GetEdgeData(forward_e1).distance;
             const int forward_weight2 = graph.GetEdgeData(forward_e2).distance;
@@ -123,18 +131,9 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID>& barrier_nodes,
             BOOST_ASSERT(0 != reverse_weight1);
             BOOST_ASSERT(0 != reverse_weight2);
 
-            const bool has_node_penalty = traffic_lights.find(node_v) != traffic_lights.end();
-
             // add weight of e2's to e1
             graph.GetEdgeData(forward_e1).distance += fwd_edge_data2.distance;
             graph.GetEdgeData(reverse_e1).distance += rev_edge_data2.distance;
-            if (has_node_penalty)
-            {
-                graph.GetEdgeData(forward_e1).distance +=
-                    speed_profile.traffic_signal_penalty;
-                graph.GetEdgeData(reverse_e1).distance +=
-                    speed_profile.traffic_signal_penalty;
-            }
 
             // extend e1's to targets of e2's
             graph.SetTarget(forward_e1, node_w);
@@ -152,28 +151,38 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID>& barrier_nodes,
             restriction_map.FixupArrivingTurnRestriction(node_w, node_v, node_u, graph);
 
             // store compressed geometry in container
-            geometry_compressor.CompressEdge(
-                forward_e1, forward_e2, node_v, node_w,
-                forward_weight1 + (has_node_penalty ? speed_profile.traffic_signal_penalty : 0),
-                forward_weight2);
-            geometry_compressor.CompressEdge(
-                reverse_e1, reverse_e2, node_v, node_u, reverse_weight1,
-                reverse_weight2 + (has_node_penalty ? speed_profile.traffic_signal_penalty : 0));
+            geometry_compressor.CompressEdge(forward_e1, forward_e2, node_v, node_w,
+                                             forward_weight1, forward_weight2);
+            geometry_compressor.CompressEdge(reverse_e1, reverse_e2, node_v, node_u,
+                                             reverse_weight1, reverse_weight2);
         }
     }
 
     PrintStatistics(original_number_of_nodes, original_number_of_edges, graph);
+
+    // Repeate the loop, but now add all edges as uncompressed values.
+    // The function AddUncompressedEdge does nothing if the edge is already
+    // in the CompressedEdgeContainer.
+    for (const NodeID node_u : util::irange(0u, original_number_of_nodes))
+    {
+        for (const auto edge_id : util::irange(graph.BeginEdges(node_u), graph.EndEdges(node_u)))
+        {
+            const EdgeData &data = graph.GetEdgeData(edge_id);
+            const NodeID target = graph.GetTarget(edge_id);
+            geometry_compressor.AddUncompressedEdge(edge_id, target, data.distance);
+        }
+    }
 }
 
 void GraphCompressor::PrintStatistics(unsigned original_number_of_nodes,
                                       unsigned original_number_of_edges,
-                                      const NodeBasedDynamicGraph& graph) const
+                                      const util::NodeBasedDynamicGraph &graph) const
 {
 
     unsigned new_node_count = 0;
     unsigned new_edge_count = 0;
 
-    for (const auto i : osrm::irange(0u, graph.GetNumberOfNodes()))
+    for (const auto i : util::irange(0u, graph.GetNumberOfNodes()))
     {
         if (graph.GetOutDegree(i) > 0)
         {
@@ -181,8 +190,10 @@ void GraphCompressor::PrintStatistics(unsigned original_number_of_nodes,
             new_edge_count += (graph.EndEdges(i) - graph.BeginEdges(i));
         }
     }
-    SimpleLogger().Write() << "Node compression ratio: "
-                           << new_node_count / (double)original_number_of_nodes;
-    SimpleLogger().Write() << "Edge compression ratio: "
-                           << new_edge_count / (double)original_number_of_edges;
+    util::SimpleLogger().Write() << "Node compression ratio: "
+                                 << new_node_count / (double)original_number_of_nodes;
+    util::SimpleLogger().Write() << "Edge compression ratio: "
+                                 << new_edge_count / (double)original_number_of_edges;
+}
+}
 }
diff --git a/src/extractor/guidance/classification_data.cpp b/src/extractor/guidance/classification_data.cpp
new file mode 100644
index 0000000..70ccaff
--- /dev/null
+++ b/src/extractor/guidance/classification_data.cpp
@@ -0,0 +1,53 @@
+#include "extractor/guidance/classification_data.hpp"
+#include "util/simple_logger.hpp"
+
+#include <unordered_map>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+FunctionalRoadClass functionalRoadClassFromTag(std::string const &value)
+{
+    // FIXME at some point this should be part of the profiles
+    const static auto class_hash = []
+    {
+        std::unordered_map<std::string, FunctionalRoadClass> hash;
+        hash["motorway"] = FunctionalRoadClass::MOTORWAY;
+        hash["motorway_link"] = FunctionalRoadClass::MOTORWAY_LINK;
+        hash["trunk"] = FunctionalRoadClass::TRUNK;
+        hash["trunk_link"] = FunctionalRoadClass::TRUNK_LINK;
+        hash["primary"] = FunctionalRoadClass::PRIMARY;
+        hash["primary_link"] = FunctionalRoadClass::PRIMARY_LINK;
+        hash["secondary"] = FunctionalRoadClass::SECONDARY;
+        hash["secondary_link"] = FunctionalRoadClass::SECONDARY_LINK;
+        hash["tertiary"] = FunctionalRoadClass::TERTIARY;
+        hash["tertiary_link"] = FunctionalRoadClass::TERTIARY_LINK;
+        hash["unclassified"] = FunctionalRoadClass::UNCLASSIFIED;
+        hash["residential"] = FunctionalRoadClass::RESIDENTIAL;
+        hash["service"] = FunctionalRoadClass::SERVICE;
+        hash["living_street"] = FunctionalRoadClass::LIVING_STREET;
+        hash["track"] = FunctionalRoadClass::LOW_PRIORITY_ROAD;
+        hash["road"] = FunctionalRoadClass::LOW_PRIORITY_ROAD;
+        hash["path"] = FunctionalRoadClass::LOW_PRIORITY_ROAD;
+        hash["driveway"] = FunctionalRoadClass::LOW_PRIORITY_ROAD;
+        return hash;
+    }();
+
+    if (class_hash.find(value) != class_hash.end())
+    {
+        return class_hash.find(value)->second;
+    }
+    else
+    {
+        util::SimpleLogger().Write(logDEBUG) << "Unknown road class encountered: " << value;
+        return FunctionalRoadClass::UNKNOWN;
+    }
+}
+
+} // ns guidance
+} // ns extractor
+} // ns osrm
diff --git a/src/extractor/guidance/turn_analysis.cpp b/src/extractor/guidance/turn_analysis.cpp
new file mode 100644
index 0000000..0281e16
--- /dev/null
+++ b/src/extractor/guidance/turn_analysis.cpp
@@ -0,0 +1,2313 @@
+#include "extractor/guidance/turn_analysis.hpp"
+
+#include "util/simple_logger.hpp"
+#include "util/coordinate.hpp"
+
+#include <cstddef>
+#include <limits>
+#include <iomanip>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+// configuration of turn classification
+const bool constexpr INVERT = true;
+
+// what angle is interpreted as going straight
+const double constexpr STRAIGHT_ANGLE = 180.;
+// if a turn deviates this much from going straight, it will be kept straight
+const double constexpr MAXIMAL_ALLOWED_NO_TURN_DEVIATION = 3.;
+// angle that lies between two nearly indistinguishable roads
+const double constexpr NARROW_TURN_ANGLE = 30.;
+const double constexpr GROUP_ANGLE = 90;
+// angle difference that can be classified as straight, if its the only narrow turn
+const double constexpr FUZZY_ANGLE_DIFFERENCE = 15.;
+const double constexpr DISTINCTION_RATIO = 2;
+const unsigned constexpr INVALID_NAME_ID = 0;
+
+using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
+
+ConnectedRoad::ConnectedRoad(const TurnOperation turn, const bool entry_allowed)
+    : turn(turn), entry_allowed(entry_allowed)
+{
+}
+
+bool requiresAnnouncement(const EdgeData &from, const EdgeData &to)
+{
+    return !from.IsCompatibleTo(to);
+}
+
+struct Localizer
+{
+    const std::vector<QueryNode> *node_info_list = nullptr;
+
+    util::Coordinate operator()(const NodeID nid)
+    {
+        if (node_info_list)
+        {
+            return {(*node_info_list)[nid].lon, (*node_info_list)[nid].lat};
+        }
+        return {};
+    }
+};
+
+static Localizer localizer;
+
+TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
+                           const std::vector<QueryNode> &node_info_list,
+                           const RestrictionMap &restriction_map,
+                           const std::unordered_set<NodeID> &barrier_nodes,
+                           const CompressedEdgeContainer &compressed_edge_container,
+                           const util::NameTable &name_table)
+    : node_based_graph(node_based_graph), node_info_list(node_info_list),
+      restriction_map(restriction_map), barrier_nodes(barrier_nodes),
+      compressed_edge_container(compressed_edge_container), name_table(name_table)
+{
+}
+
+// some small tool functions to simplify decisions down the line
+namespace detail
+{
+
+inline FunctionalRoadClass roadClass(const ConnectedRoad &road,
+                                     const util::NodeBasedDynamicGraph &graph)
+{
+    return graph.GetEdgeData(road.turn.eid).road_classification.road_class;
+}
+
+inline bool isMotorwayClass(FunctionalRoadClass road_class)
+{
+    return road_class == FunctionalRoadClass::MOTORWAY || road_class == FunctionalRoadClass::TRUNK;
+}
+
+inline bool isMotorwayClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph)
+{
+    return isMotorwayClass(node_based_graph.GetEdgeData(eid).road_classification.road_class);
+}
+
+inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph)
+{
+    return isRampClass(node_based_graph.GetEdgeData(eid).road_classification.road_class);
+}
+
+} // namespace detail
+
+std::vector<TurnOperation> TurnAnalysis::getTurns(const NodeID from, const EdgeID via_edge) const
+{
+    localizer.node_info_list = &node_info_list;
+    auto intersection = getConnectedRoads(from, via_edge);
+
+    const auto &in_edge_data = node_based_graph.GetEdgeData(via_edge);
+
+    // main priority: roundabouts
+    bool on_roundabout = in_edge_data.roundabout;
+    bool can_enter_roundabout = false;
+    bool can_exit_roundabout_separately = false;
+    for (const auto &road : intersection)
+    {
+        const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
+        // only check actual outgoing edges
+        if (edge_data.reversed)
+            continue;
+
+        if (edge_data.roundabout)
+        {
+            can_enter_roundabout = true;
+        }
+        // Exiting roundabouts at an entry point is technically a data-modelling issue.
+        // This workaround handles cases in which an exit follows the entry.
+        // To correctly represent perceived exits, we only count exits leading to a
+        // separate vertex than the one we are coming from that are in the direction of
+        // the roundabout.
+        // The sorting of the angles represents a problem for left-sided driving, though.
+        // FIXME in case of left-sided driving, we have to check whether we can enter the
+        // roundabout later in the cycle, rather than prior.
+        else if (node_based_graph.GetTarget(road.turn.eid) != from && !can_enter_roundabout)
+        {
+            can_exit_roundabout_separately = true;
+        }
+    }
+    if (on_roundabout || can_enter_roundabout)
+    {
+        intersection = handleRoundabouts(via_edge, on_roundabout, can_exit_roundabout_separately,
+                                         std::move(intersection));
+    }
+    else
+    {
+        // set initial defaults for normal turns and modifier based on angle
+        intersection = setTurnTypes(from, via_edge, std::move(intersection));
+        if (isMotorwayJunction(via_edge, intersection))
+        {
+            intersection = handleMotorwayJunction(via_edge, std::move(intersection));
+        }
+
+        else if (intersection.size() == 1)
+        {
+            intersection = handleOneWayTurn(std::move(intersection));
+        }
+        else if (intersection.size() == 2)
+        {
+            intersection = handleTwoWayTurn(via_edge, std::move(intersection));
+        }
+        else if (intersection.size() == 3)
+        {
+            intersection = handleThreeWayTurn(via_edge, std::move(intersection));
+        }
+        else
+        {
+            intersection = handleComplexTurn(via_edge, std::move(intersection));
+        }
+        // complex intersection, potentially requires conflict resolution
+    }
+
+    std::vector<TurnOperation> turns;
+    for (auto road : intersection)
+        if (road.entry_allowed)
+            turns.emplace_back(road.turn);
+
+    return turns;
+}
+
+inline std::size_t countValid(const std::vector<ConnectedRoad> &intersection)
+{
+    return std::count_if(intersection.begin(), intersection.end(), [](const ConnectedRoad &road)
+                         {
+                             return road.entry_allowed;
+                         });
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::handleRoundabouts(const EdgeID via_edge,
+                                const bool on_roundabout,
+                                const bool can_exit_roundabout_separately,
+                                std::vector<ConnectedRoad> intersection) const
+{
+    // TODO requires differentiation between roundabouts and rotaries
+    // detect via radius (get via circle through three vertices)
+    NodeID node_v = node_based_graph.GetTarget(via_edge);
+    if (on_roundabout)
+    {
+        // Shoule hopefully have only a single exit and continue
+        // at least for cars. How about bikes?
+        for (auto &road : intersection)
+        {
+            auto &turn = road.turn;
+            const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+            if (out_data.roundabout)
+            {
+                // TODO can forks happen in roundabouts? E.g. required lane changes
+                if (1 == node_based_graph.GetDirectedOutDegree(node_v))
+                {
+                    // No turn possible.
+                    turn.instruction = TurnInstruction::NO_TURN();
+                }
+                else
+                {
+                    turn.instruction =
+                        TurnInstruction::REMAIN_ROUNDABOUT(getTurnDirection(turn.angle));
+                }
+            }
+            else
+            {
+                turn.instruction = TurnInstruction::EXIT_ROUNDABOUT(getTurnDirection(turn.angle));
+            }
+        }
+        return intersection;
+    }
+    else
+    {
+        for (auto &road : intersection)
+        {
+            if (!road.entry_allowed)
+                continue;
+            auto &turn = road.turn;
+            const auto &out_data = node_based_graph.GetEdgeData(turn.eid);
+            if (out_data.roundabout)
+            {
+                turn.instruction = TurnInstruction::ENTER_ROUNDABOUT(getTurnDirection(turn.angle));
+                if (can_exit_roundabout_separately)
+                {
+                    if (turn.instruction.type == TurnType::EnterRotary)
+                        turn.instruction.type = TurnType::EnterRotaryAtExit;
+                    if (turn.instruction.type == TurnType::EnterRoundabout)
+                        turn.instruction.type = TurnType::EnterRoundaboutAtExit;
+                }
+            }
+            else
+            {
+                turn.instruction = {TurnType::EnterAndExitRoundabout, getTurnDirection(turn.angle)};
+            }
+        }
+        return intersection;
+    }
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::fallbackTurnAssignmentMotorway(std::vector<ConnectedRoad> intersection) const
+{
+    for (auto &road : intersection)
+    {
+        const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+
+        util::SimpleLogger().Write(logWARNING)
+            << "road: " << road.toString() << " Name: " << out_data.name_id
+            << " Road Class: " << (int)out_data.road_classification.road_class
+            << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
+
+        if (!road.entry_allowed)
+            continue;
+
+        const auto type = detail::isMotorwayClass(out_data.road_classification.road_class)
+                              ? TurnType::Merge
+                              : TurnType::Turn;
+        if (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)
+            road.turn.instruction = {type, DirectionModifier::Straight};
+        else
+        {
+            road.turn.instruction = {type,
+                                     road.turn.angle > STRAIGHT_ANGLE
+                                         ? DirectionModifier::SlightLeft
+                                         : DirectionModifier::SlightRight};
+        }
+    }
+    return intersection;
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
+                                 std::vector<ConnectedRoad> intersection) const
+{
+    const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+    BOOST_ASSERT(detail::isMotorwayClass(in_data.road_classification.road_class));
+
+    const auto countExitingMotorways = [this](const std::vector<ConnectedRoad> &intersection)
+    {
+        unsigned count = 0;
+        for (const auto &road : intersection)
+        {
+            if (road.entry_allowed && detail::isMotorwayClass(road.turn.eid, node_based_graph))
+                ++count;
+        }
+        return count;
+    };
+
+    // find the angle that continues on our current highway
+    const auto getContinueAngle = [this, in_data](const std::vector<ConnectedRoad> &intersection)
+    {
+        for (const auto &road : intersection)
+        {
+            const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+            if (road.turn.angle != 0 && in_data.name_id == out_data.name_id &&
+                in_data.name_id != 0 &&
+                detail::isMotorwayClass(out_data.road_classification.road_class))
+                return road.turn.angle;
+        }
+        return intersection[0].turn.angle;
+    };
+
+    const auto getMostLikelyContinue =
+        [this, in_data](const std::vector<ConnectedRoad> &intersection)
+    {
+        double angle = intersection[0].turn.angle;
+        double best = 180;
+        for (const auto &road : intersection)
+        {
+            const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+            if (detail::isMotorwayClass(out_data.road_classification.road_class) &&
+                angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < best)
+            {
+                best = angularDeviation(road.turn.angle, STRAIGHT_ANGLE);
+                angle = road.turn.angle;
+            }
+        }
+        return angle;
+    };
+
+    const auto findBestContinue = [&]()
+    {
+        const double continue_angle = getContinueAngle(intersection);
+        if (continue_angle != intersection[0].turn.angle)
+            return continue_angle;
+        else
+            return getMostLikelyContinue(intersection);
+    };
+
+    // find continue angle
+    const double continue_angle = findBestContinue();
+
+    // highway does not continue and has no obvious choice
+    if (continue_angle == intersection[0].turn.angle)
+    {
+        if (intersection.size() == 2)
+        {
+            // do not announce ramps at the end of a highway
+            intersection[1].turn.instruction = {TurnType::NoTurn,
+                                                getTurnDirection(intersection[1].turn.angle)};
+        }
+        else if (intersection.size() == 3)
+        {
+            // splitting ramp at the end of a highway
+            if (intersection[1].entry_allowed && intersection[2].entry_allowed)
+            {
+                assignFork(via_edge, intersection[2], intersection[1]);
+            }
+            else
+            {
+                // ending in a passing ramp
+                if (intersection[1].entry_allowed)
+                    intersection[1].turn.instruction = {
+                        TurnType::NoTurn, getTurnDirection(intersection[1].turn.angle)};
+                else
+                    intersection[2].turn.instruction = {
+                        TurnType::NoTurn, getTurnDirection(intersection[2].turn.angle)};
+            }
+        }
+        else if (intersection.size() == 4 &&
+                 detail::roadClass(intersection[1], node_based_graph) ==
+                     detail::roadClass(intersection[2], node_based_graph) &&
+                 detail::roadClass(intersection[2], node_based_graph) ==
+                     detail::roadClass(intersection[3], node_based_graph))
+        {
+            // tripple fork at the end
+            assignFork(via_edge, intersection[3], intersection[2], intersection[1]);
+        }
+        else if (countValid(intersection) > 0) // check whether turns exist at all
+        {
+            // FALLBACK, this should hopefully never be reached
+            auto coord = localizer(node_based_graph.GetTarget(via_edge));
+            util::SimpleLogger().Write(logWARNING)
+                << "Fallback reached from motorway at " << std::setprecision(12)
+                << toFloating(coord.lat) << " " << toFloating(coord.lon) << ", no continue angle, "
+                << intersection.size() << " roads, " << countValid(intersection) << " valid ones.";
+            fallbackTurnAssignmentMotorway(intersection);
+        }
+    }
+    else
+    {
+        const unsigned exiting_motorways = countExitingMotorways(intersection);
+
+        if (exiting_motorways == 0)
+        {
+            // Ending in Ramp
+            for (auto &road : intersection)
+            {
+                if (road.entry_allowed)
+                {
+                    BOOST_ASSERT(detail::isRampClass(road.turn.eid, node_based_graph));
+                    road.turn.instruction =
+                        TurnInstruction::SUPPRESSED(getTurnDirection(road.turn.angle));
+                }
+            }
+        }
+        else if (exiting_motorways == 1)
+        {
+            // normal motorway passing some ramps or mering onto another motorway
+            if (intersection.size() == 2)
+            {
+                BOOST_ASSERT(!detail::isRampClass(intersection[1].turn.eid, node_based_graph));
+
+                intersection[1].turn.instruction =
+                    getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+            }
+            else
+            {
+                // continue on the same highway
+                bool continues = (getContinueAngle(intersection) != intersection[0].turn.angle);
+                // Normal Highway exit or merge
+                for (auto &road : intersection)
+                {
+                    // ignore invalid uturns/other
+                    if (!road.entry_allowed)
+                        continue;
+
+                    if (road.turn.angle == continue_angle)
+                    {
+                        if (continues)
+                            road.turn.instruction =
+                                TurnInstruction::SUPPRESSED(DirectionModifier::Straight);
+                        else // TODO handle turn direction correctly
+                            road.turn.instruction = {TurnType::Merge, DirectionModifier::Straight};
+                    }
+                    else if (road.turn.angle < continue_angle)
+                    {
+                        road.turn.instruction = {
+                            detail::isRampClass(road.turn.eid, node_based_graph) ? TurnType::Ramp
+                                                                                 : TurnType::Turn,
+                            (road.turn.angle < 145) ? DirectionModifier::Right
+                                                    : DirectionModifier::SlightRight};
+                    }
+                    else if (road.turn.angle > continue_angle)
+                    {
+                        road.turn.instruction = {
+                            detail::isRampClass(road.turn.eid, node_based_graph) ? TurnType::Ramp
+                                                                                 : TurnType::Turn,
+                            (road.turn.angle > 215) ? DirectionModifier::Left
+                                                    : DirectionModifier::SlightLeft};
+                    }
+                }
+            }
+        }
+        // handle motorway forks
+        else if (exiting_motorways > 1)
+        {
+            if (exiting_motorways == 2 && intersection.size() == 2)
+            {
+                intersection[1].turn.instruction =
+                    getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+                util::SimpleLogger().Write(logWARNING)
+                    << "Disabled U-Turn on a freeway at "
+                    << localizer(node_based_graph.GetTarget(via_edge));
+                intersection[0].entry_allowed = false; // UTURN on the freeway
+            }
+            else if (exiting_motorways == 2)
+            {
+                // standard fork
+                std::size_t first_valid = std::numeric_limits<std::size_t>::max(),
+                            second_valid = std::numeric_limits<std::size_t>::max();
+                for (std::size_t i = 0; i < intersection.size(); ++i)
+                {
+                    if (intersection[i].entry_allowed &&
+                        detail::isMotorwayClass(intersection[i].turn.eid, node_based_graph))
+                    {
+                        if (first_valid < intersection.size())
+                        {
+                            second_valid = i;
+                            break;
+                        }
+                        else
+                        {
+                            first_valid = i;
+                        }
+                    }
+                }
+                assignFork(via_edge, intersection[second_valid], intersection[first_valid]);
+            }
+            else if (exiting_motorways == 3)
+            {
+                // triple fork
+                std::size_t first_valid = std::numeric_limits<std::size_t>::max(),
+                            second_valid = std::numeric_limits<std::size_t>::max(),
+                            third_valid = std::numeric_limits<std::size_t>::max();
+                for (std::size_t i = 0; i < intersection.size(); ++i)
+                {
+                    if (intersection[i].entry_allowed &&
+                        detail::isMotorwayClass(intersection[i].turn.eid, node_based_graph))
+                    {
+                        if (second_valid < intersection.size())
+                        {
+                            third_valid = i;
+                            break;
+                        }
+                        else if (first_valid < intersection.size())
+                        {
+                            second_valid = i;
+                        }
+                        else
+                        {
+                            first_valid = i;
+                        }
+                    }
+                }
+                assignFork(via_edge, intersection[third_valid], intersection[second_valid],
+                           intersection[first_valid]);
+            }
+            else
+            {
+                auto coord = localizer(node_based_graph.GetTarget(via_edge));
+                util::SimpleLogger().Write(logWARNING)
+                    << "Found motorway junction with more than "
+                       "2 exiting motorways or additional ramps at " << std::setprecision(12)
+                    << toFloating(coord.lat) << " " << toFloating(coord.lon);
+                fallbackTurnAssignmentMotorway(intersection);
+            }
+        } // done for more than one highway exit
+    }
+    return intersection;
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::handleMotorwayRamp(const EdgeID via_edge,
+                                 std::vector<ConnectedRoad> intersection) const
+{
+    auto num_valid_turns = countValid(intersection);
+    // ramp straight into a motorway/ramp
+    if (intersection.size() == 2 && num_valid_turns == 1)
+    {
+        BOOST_ASSERT(!intersection[0].entry_allowed);
+        BOOST_ASSERT(detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph));
+
+        intersection[1].turn.instruction =
+            getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+    }
+    else if (intersection.size() == 3)
+    {
+        // merging onto a passing highway / or two ramps merging onto the same highway
+        if (num_valid_turns == 1)
+        {
+            BOOST_ASSERT(!intersection[0].entry_allowed);
+            // check order of highways
+            //          4
+            //     5         3
+            //
+            //   6              2
+            //
+            //     7         1
+            //          0
+            if (intersection[1].entry_allowed)
+            {
+                if (detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph))
+                {
+                    // circular order indicates a merge to the left (0-3 onto 4
+                    if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) <
+                        NARROW_TURN_ANGLE)
+                        intersection[1].turn.instruction = {TurnType::Merge,
+                                                            DirectionModifier::SlightLeft};
+                    else // fallback
+                        intersection[1].turn.instruction = {
+                            TurnType::Merge, getTurnDirection(intersection[1].turn.angle)};
+                }
+                else // passing by the end of a motorway
+                    intersection[1].turn.instruction =
+                        getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+            }
+            else
+            {
+                BOOST_ASSERT(intersection[2].entry_allowed);
+                if (detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph))
+                {
+                    // circular order (5-0) onto 4
+                    if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) <
+                        NARROW_TURN_ANGLE)
+                        intersection[2].turn.instruction = {TurnType::Merge,
+                                                            DirectionModifier::SlightRight};
+                    else // fallback
+                        intersection[2].turn.instruction = {
+                            TurnType::Merge, getTurnDirection(intersection[2].turn.angle)};
+                }
+                else // passing the end of a highway
+                    intersection[1].turn.instruction =
+                        getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+            }
+        }
+        else
+        {
+            BOOST_ASSERT(num_valid_turns == 2);
+            // UTurn on ramps is not possible
+            BOOST_ASSERT(!intersection[0].entry_allowed);
+            BOOST_ASSERT(intersection[1].entry_allowed);
+            BOOST_ASSERT(intersection[2].entry_allowed);
+            // two motorways starting at end of ramp (fork)
+            //  M       M
+            //    \   /
+            //      |
+            //      R
+            if (detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph) &&
+                detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph))
+            {
+                assignFork(via_edge, intersection[2], intersection[1]);
+            }
+            else
+            {
+                // continued ramp passing motorway entry
+                //      M  R
+                //      M  R
+                //      | /
+                //      R
+                if (detail::isMotorwayClass(node_based_graph.GetEdgeData(intersection[1].turn.eid)
+                                                .road_classification.road_class))
+                {
+                    intersection[1].turn.instruction = {TurnType::Merge,
+                                                        DirectionModifier::SlightRight};
+                    intersection[2].turn.instruction = {TurnType::Fork,
+                                                        DirectionModifier::SlightLeft};
+                }
+                else
+                {
+                    intersection[1].turn.instruction = {TurnType::Fork,
+                                                        DirectionModifier::SlightRight};
+                    intersection[2].turn.instruction = {TurnType::Merge,
+                                                        DirectionModifier::SlightLeft};
+                }
+            }
+        }
+    }
+    // On - Off Ramp on passing Motorway, Ramp onto Fork(?)
+    else if (intersection.size() == 4)
+    {
+        bool passed_highway_entry = false;
+        for (auto &road : intersection)
+        {
+            const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
+            if (!road.entry_allowed &&
+                detail::isMotorwayClass(edge_data.road_classification.road_class))
+            {
+                passed_highway_entry = true;
+            }
+            else if (detail::isMotorwayClass(edge_data.road_classification.road_class))
+            {
+                road.turn.instruction = {TurnType::Merge,
+                                         passed_highway_entry ? DirectionModifier::SlightRight
+                                                              : DirectionModifier::SlightLeft};
+            }
+            else
+            {
+                BOOST_ASSERT(isRampClass(edge_data.road_classification.road_class));
+                road.turn.instruction = {TurnType::Ramp, getTurnDirection(road.turn.angle)};
+            }
+        }
+    }
+    else
+    { // FALLBACK, hopefully this should never been reached
+        util::SimpleLogger().Write(logWARNING) << "Reached fallback on motorway ramp with "
+                                               << intersection.size() << " roads and "
+                                               << countValid(intersection) << " valid turns.";
+        fallbackTurnAssignmentMotorway(intersection);
+    }
+    return intersection;
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::handleMotorwayJunction(const EdgeID via_edge,
+                                     std::vector<ConnectedRoad> intersection) const
+{
+    // BOOST_ASSERT(!intersection[0].entry_allowed); //This fails due to @themarex handling of dead
+    // end
+    // streets
+    const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+
+    // coming from motorway
+    if (detail::isMotorwayClass(in_data.road_classification.road_class))
+    {
+        return handleFromMotorway(via_edge, std::move(intersection));
+    }
+    else // coming from a ramp
+    {
+        return handleMotorwayRamp(via_edge, std::move(intersection));
+        // ramp merging straight onto motorway
+    }
+}
+
+bool TurnAnalysis::isMotorwayJunction(const EdgeID via_edge,
+                                      const std::vector<ConnectedRoad> &intersection) const
+{
+    bool has_motorway = false;
+    bool has_normal_roads = false;
+
+    for (const auto &road : intersection)
+    {
+        const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+        // not merging or forking?
+        if ((angularDeviation(road.turn.angle, 0) > 35 &&
+             angularDeviation(road.turn.angle, 180) > 35) ||
+            (road.entry_allowed && angularDeviation(road.turn.angle, 0) < 35))
+            return false;
+        else if (out_data.road_classification.road_class == FunctionalRoadClass::MOTORWAY ||
+                 out_data.road_classification.road_class == FunctionalRoadClass::TRUNK)
+        {
+            if (road.entry_allowed)
+                has_motorway = true;
+        }
+        else if (!isRampClass(out_data.road_classification.road_class))
+            has_normal_roads = true;
+    }
+
+    if (has_normal_roads)
+        return false;
+
+    const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+    return has_motorway ||
+           in_data.road_classification.road_class == FunctionalRoadClass::MOTORWAY ||
+           in_data.road_classification.road_class == FunctionalRoadClass::TRUNK;
+}
+
+TurnType TurnAnalysis::findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &road) const
+{
+
+    const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+    const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+
+    bool on_ramp = isRampClass(in_data.road_classification.road_class);
+
+    bool onto_ramp = isRampClass(out_data.road_classification.road_class);
+
+    if (!on_ramp && onto_ramp)
+        return TurnType::Ramp;
+
+    if (in_data.name_id == out_data.name_id && in_data.name_id != INVALID_NAME_ID)
+    {
+        return TurnType::Continue;
+    }
+
+    return TurnType::Turn;
+}
+
+TurnInstruction TurnAnalysis::getInstructionForObvious(const std::size_t num_roads,
+                                                       const EdgeID via_edge,
+                                                       const ConnectedRoad &road) const
+{
+    const auto type = findBasicTurnType(via_edge, road);
+    // handle travel modes:
+    const auto in_mode = node_based_graph.GetEdgeData(via_edge).travel_mode;
+    const auto out_mode = node_based_graph.GetEdgeData(road.turn.eid).travel_mode;
+    if (type == TurnType::Ramp)
+    {
+        return {TurnType::Ramp, getTurnDirection(road.turn.angle)};
+    }
+
+    if (angularDeviation(road.turn.angle, 0) < 0.01)
+    {
+        return {TurnType::Turn, DirectionModifier::UTurn};
+    }
+    if (type == TurnType::Turn)
+    {
+        const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+        const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+        if (in_data.name_id != out_data.name_id &&
+            requiresNameAnnounced(name_table.GetNameForID(in_data.name_id),
+                                  name_table.GetNameForID(out_data.name_id)))
+            return {TurnType::NewName, getTurnDirection(road.turn.angle)};
+        else
+        {
+            if (in_mode == out_mode)
+                return {TurnType::Suppressed, getTurnDirection(road.turn.angle)};
+            else
+                return {TurnType::Notification, getTurnDirection(road.turn.angle)};
+        }
+    }
+    BOOST_ASSERT(type == TurnType::Continue);
+    if (in_mode != out_mode)
+    {
+        return {TurnType::Notification, getTurnDirection(road.turn.angle)};
+    }
+    if (num_roads > 2)
+    {
+        return {TurnType::Suppressed, getTurnDirection(road.turn.angle)};
+    }
+    else
+    {
+        return {TurnType::NoTurn, getTurnDirection(road.turn.angle)};
+    }
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::handleOneWayTurn(std::vector<ConnectedRoad> intersection) const
+{
+    BOOST_ASSERT(intersection[0].turn.angle < 0.001);
+    return intersection;
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::handleTwoWayTurn(const EdgeID via_edge, std::vector<ConnectedRoad> intersection) const
+{
+    BOOST_ASSERT(intersection[0].turn.angle < 0.001);
+    intersection[1].turn.instruction =
+        getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+
+    if (intersection[1].turn.instruction.type == TurnType::Suppressed)
+        intersection[1].turn.instruction.type = TurnType::NoTurn;
+
+    return intersection;
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
+                                 std::vector<ConnectedRoad> intersection) const
+{
+    BOOST_ASSERT(intersection[0].turn.angle < 0.001);
+    const auto isObviousOfTwo = [](const ConnectedRoad road, const ConnectedRoad other)
+    {
+        return (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
+                angularDeviation(other.turn.angle, STRAIGHT_ANGLE) > 85) ||
+               (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <
+                std::numeric_limits<double>::epsilon()) ||
+               (angularDeviation(other.turn.angle, STRAIGHT_ANGLE) /
+                    angularDeviation(road.turn.angle, STRAIGHT_ANGLE) >
+                1.4);
+    };
+
+    /* Two nearly straight turns -> FORK
+                OOOOOOO
+              /
+       IIIIII
+              \
+                OOOOOOO
+    */
+    if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
+        angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE)
+    {
+        if (intersection[1].entry_allowed && intersection[2].entry_allowed)
+        {
+            const auto left_class = node_based_graph.GetEdgeData(intersection[2].turn.eid)
+                                        .road_classification.road_class;
+            const auto right_class = node_based_graph.GetEdgeData(intersection[1].turn.eid)
+                                         .road_classification.road_class;
+            if (canBeSeenAsFork(left_class, right_class))
+                assignFork(via_edge, intersection[2], intersection[1]);
+            else if (getPriority(left_class) > getPriority(right_class))
+            {
+                intersection[1].turn.instruction =
+                    getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+                intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+                                                    DirectionModifier::SlightLeft};
+            }
+            else
+            {
+                intersection[2].turn.instruction =
+                    getInstructionForObvious(intersection.size(), via_edge, intersection[2]);
+                intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+                                                    DirectionModifier::SlightRight};
+            }
+        }
+        else
+        {
+            if (intersection[1].entry_allowed)
+                intersection[1].turn.instruction =
+                    getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+            if (intersection[2].entry_allowed)
+                intersection[2].turn.instruction =
+                    getInstructionForObvious(intersection.size(), via_edge, intersection[2]);
+        }
+    }
+    /*  T Intersection
+
+      OOOOOOO T OOOOOOOO
+              I
+              I
+              I
+    */
+    else if (angularDeviation(intersection[1].turn.angle, 90) < NARROW_TURN_ANGLE &&
+             angularDeviation(intersection[2].turn.angle, 270) < NARROW_TURN_ANGLE &&
+             angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >
+                 NARROW_TURN_ANGLE)
+    {
+        if (intersection[1].entry_allowed)
+        {
+            if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[1]))
+                intersection[1].turn.instruction = {TurnType::EndOfRoad, DirectionModifier::Right};
+            else
+                intersection[1].turn.instruction = {TurnType::Ramp, DirectionModifier::Right};
+        }
+        if (intersection[2].entry_allowed)
+        {
+            if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[2]))
+
+                intersection[2].turn.instruction = {TurnType::EndOfRoad, DirectionModifier::Left};
+            else
+                intersection[2].turn.instruction = {TurnType::Ramp, DirectionModifier::Left};
+        }
+    }
+    /* T Intersection, Cross left
+              O
+              O
+              O
+     IIIIIIII - OOOOOOOOOO
+    */
+    else if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
+             angularDeviation(intersection[2].turn.angle, 270) < NARROW_TURN_ANGLE &&
+             angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >
+                 NARROW_TURN_ANGLE)
+    {
+        if (intersection[1].entry_allowed)
+        {
+            if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[1]))
+                intersection[1].turn.instruction =
+                    getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+            else
+                intersection[1].turn.instruction = {TurnType::Ramp, DirectionModifier::Straight};
+        }
+        if (intersection[2].entry_allowed)
+        {
+            intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+                                                DirectionModifier::Left};
+        }
+    }
+    /* T Intersection, Cross right
+
+     IIIIIIII T OOOOOOOOOO
+              O
+              O
+              O
+    */
+    else if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
+             angularDeviation(intersection[1].turn.angle, 90) < NARROW_TURN_ANGLE &&
+             angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >
+                 NARROW_TURN_ANGLE)
+    {
+        if (intersection[2].entry_allowed)
+            intersection[2].turn.instruction =
+                getInstructionForObvious(intersection.size(), via_edge, intersection[2]);
+        if (intersection[1].entry_allowed)
+            intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+                                                DirectionModifier::Right};
+    }
+    // merge onto a through street
+    else if (INVALID_NAME_ID != node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id &&
+             node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id ==
+                 node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id)
+    {
+        const auto findTurn = [isObviousOfTwo](const ConnectedRoad turn, const ConnectedRoad other)
+                                  -> TurnInstruction
+        {
+            return {isObviousOfTwo(turn, other) ? TurnType::Merge : TurnType::Turn,
+                    getTurnDirection(turn.turn.angle)};
+        };
+        intersection[1].turn.instruction = findTurn(intersection[1], intersection[2]);
+        intersection[2].turn.instruction = findTurn(intersection[2], intersection[1]);
+    }
+
+    // other street merges from the left
+    else if (INVALID_NAME_ID != node_based_graph.GetEdgeData(via_edge).name_id &&
+             node_based_graph.GetEdgeData(via_edge).name_id ==
+                 node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id)
+    {
+        if (isObviousOfTwo(intersection[1], intersection[2]))
+        {
+            intersection[1].turn.instruction =
+                TurnInstruction::SUPPRESSED(DirectionModifier::Straight);
+        }
+        else
+        {
+            intersection[1].turn.instruction = {TurnType::Continue,
+                                                getTurnDirection(intersection[1].turn.angle)};
+        }
+        intersection[2].turn.instruction = {TurnType::Turn,
+                                            getTurnDirection(intersection[2].turn.angle)};
+    }
+    // other street merges from the right
+    else if (INVALID_NAME_ID != node_based_graph.GetEdgeData(via_edge).name_id &&
+             node_based_graph.GetEdgeData(via_edge).name_id ==
+                 node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id)
+    {
+        if (isObviousOfTwo(intersection[2], intersection[1]))
+        {
+            intersection[2].turn.instruction =
+                TurnInstruction::SUPPRESSED(DirectionModifier::Straight);
+        }
+        else
+        {
+            intersection[2].turn.instruction = {TurnType::Continue,
+                                                getTurnDirection(intersection[2].turn.angle)};
+        }
+        intersection[1].turn.instruction = {TurnType::Turn,
+                                            getTurnDirection(intersection[1].turn.angle)};
+    }
+    else
+    {
+        if (isObviousOfTwo(intersection[1], intersection[2]))
+        {
+            intersection[1].turn.instruction = getInstructionForObvious(3,via_edge,intersection[1]);
+        }
+        else
+        {
+            intersection[1].turn.instruction = {TurnType::Turn,
+                                                getTurnDirection(intersection[1].turn.angle)};
+        }
+
+        if (isObviousOfTwo(intersection[2], intersection[1]))
+        {
+            intersection[2].turn.instruction = getInstructionForObvious(3,via_edge,intersection[2]);
+        }
+        else
+        {
+            intersection[2].turn.instruction = {TurnType::Turn,
+                                                getTurnDirection(intersection[2].turn.angle)};
+        }
+    }
+    // unnamed intersections or basic three way turn
+
+    // remain at basic turns
+    // TODO handle obviousness, Handle Merges
+    return intersection;
+}
+
+void TurnAnalysis::handleDistinctConflict(const EdgeID via_edge,
+                                          ConnectedRoad &left,
+                                          ConnectedRoad &right) const
+{
+    // single turn of both is valid (don't change the valid one)
+    // or multiple identical angles -> bad OSM intersection
+    if ((!left.entry_allowed || !right.entry_allowed) || (left.turn.angle == right.turn.angle))
+    {
+        if (left.entry_allowed)
+            left.turn.instruction = {findBasicTurnType(via_edge, left),
+                                     getTurnDirection(left.turn.angle)};
+        if (right.entry_allowed)
+            right.turn.instruction = {findBasicTurnType(via_edge, right),
+                                      getTurnDirection(right.turn.angle)};
+        return;
+    }
+
+    if (getTurnDirection(left.turn.angle) == DirectionModifier::Straight ||
+        getTurnDirection(left.turn.angle) == DirectionModifier::SlightLeft ||
+        getTurnDirection(right.turn.angle) == DirectionModifier::SlightRight)
+    {
+        const auto left_class =
+            node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class;
+        const auto right_class =
+            node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class;
+        if (canBeSeenAsFork(left_class, right_class))
+            assignFork(via_edge, left, right);
+        else if (getPriority(left_class) > getPriority(right_class))
+        {
+            // FIXME this should possibly know about the actual roads?
+            right.turn.instruction = getInstructionForObvious(4, via_edge, right);
+            left.turn.instruction = {findBasicTurnType(via_edge, left),
+                                     DirectionModifier::SlightLeft};
+        }
+        else
+        {
+            // FIXME this should possibly know about the actual roads?
+            left.turn.instruction = getInstructionForObvious(4, via_edge, left);
+            right.turn.instruction = {findBasicTurnType(via_edge, right),
+                                      DirectionModifier::SlightRight};
+        }
+    }
+
+    const auto left_type = findBasicTurnType(via_edge, left);
+    const auto right_type = findBasicTurnType(via_edge, right);
+    // Two Right Turns
+    if (angularDeviation(left.turn.angle, 90) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+    {
+        // Keep left perfect, shift right
+        left.turn.instruction = {left_type, DirectionModifier::Right};
+        right.turn.instruction = {right_type, DirectionModifier::SharpRight};
+        return;
+    }
+    if (angularDeviation(right.turn.angle, 90) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+    {
+        // Keep Right perfect, shift left
+        left.turn.instruction = {left_type, DirectionModifier::SlightRight};
+        right.turn.instruction = {right_type, DirectionModifier::Right};
+        return;
+    }
+    // Two Right Turns
+    if (angularDeviation(left.turn.angle, 270) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+    {
+        // Keep left perfect, shift right
+        left.turn.instruction = {left_type, DirectionModifier::Left};
+        right.turn.instruction = {right_type, DirectionModifier::SlightLeft};
+        return;
+    }
+    if (angularDeviation(right.turn.angle, 270) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+    {
+        // Keep Right perfect, shift left
+        left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
+        right.turn.instruction = {right_type, DirectionModifier::Left};
+        return;
+    }
+    // Both turns?
+    if (TurnType::Ramp != left_type && TurnType::Ramp != right_type)
+    {
+        if (left.turn.angle < STRAIGHT_ANGLE)
+        {
+            left.turn.instruction = {TurnType::FirstTurn, getTurnDirection(left.turn.angle)};
+            right.turn.instruction = {TurnType::SecondTurn, getTurnDirection(right.turn.angle)};
+        }
+        else
+        {
+            left.turn.instruction = {TurnType::SecondTurn, getTurnDirection(left.turn.angle)};
+            right.turn.instruction = {TurnType::FirstTurn, getTurnDirection(right.turn.angle)};
+        }
+        return;
+    }
+    // Shift the lesser penalty
+    if (getTurnDirection(left.turn.angle) == DirectionModifier::SharpLeft)
+    {
+        left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
+        right.turn.instruction = {right_type, DirectionModifier::Left};
+        return;
+    }
+    if (getTurnDirection(right.turn.angle) == DirectionModifier::SharpRight)
+    {
+        left.turn.instruction = {left_type, DirectionModifier::Right};
+        right.turn.instruction = {right_type, DirectionModifier::SharpRight};
+        return;
+    }
+
+    if (getTurnDirection(left.turn.angle) == DirectionModifier::Right)
+    {
+        if (angularDeviation(left.turn.angle, 90) > angularDeviation(right.turn.angle, 90))
+        {
+            left.turn.instruction = {left_type, DirectionModifier::SlightRight};
+            right.turn.instruction = {right_type, DirectionModifier::Right};
+        }
+        else
+        {
+            left.turn.instruction = {left_type, DirectionModifier::Right};
+            right.turn.instruction = {right_type, DirectionModifier::SharpRight};
+        }
+    }
+    else
+    {
+        if (angularDeviation(left.turn.angle, 270) > angularDeviation(right.turn.angle, 270))
+        {
+            left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
+            right.turn.instruction = {right_type, DirectionModifier::Left};
+        }
+        else
+        {
+            left.turn.instruction = {left_type, DirectionModifier::Left};
+            right.turn.instruction = {right_type, DirectionModifier::SlightLeft};
+        }
+    }
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::handleComplexTurn(const EdgeID via_edge,
+                                std::vector<ConnectedRoad> intersection) const
+{
+    static int fallback_count = 0;
+    const std::size_t obvious_index = findObviousTurn(via_edge, intersection);
+    const auto fork_range = findFork(intersection);
+    std::size_t straightmost_turn = 0;
+    double straightmost_deviation = 180;
+    for (std::size_t i = 0; i < intersection.size(); ++i)
+    {
+        const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
+        if (deviation < straightmost_deviation)
+        {
+            straightmost_deviation = deviation;
+            straightmost_turn = i;
+        }
+    }
+
+    if (obvious_index != 0)
+    {
+        intersection[obvious_index].turn.instruction =
+            getInstructionForObvious(intersection.size(), via_edge, intersection[obvious_index]);
+
+        // assign left/right turns
+        intersection = assignLeftTurns(via_edge, std::move(intersection), obvious_index + 1);
+        intersection = assignRightTurns(via_edge, std::move(intersection), obvious_index);
+    }
+    else if (fork_range.first != 0 && fork_range.second - fork_range.first <= 2) // found fork
+    {
+        if (fork_range.second - fork_range.first == 1)
+        {
+            auto &left = intersection[fork_range.second];
+            auto &right = intersection[fork_range.first];
+            const auto left_class =
+                node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class;
+            const auto right_class =
+                node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class;
+            if (canBeSeenAsFork(left_class, right_class))
+                assignFork(via_edge, left, right);
+            else if (getPriority(left_class) > getPriority(right_class))
+            {
+                right.turn.instruction =
+                    getInstructionForObvious(intersection.size(), via_edge, right);
+                left.turn.instruction = {findBasicTurnType(via_edge, left),
+                                         DirectionModifier::SlightLeft};
+            }
+            else
+            {
+                left.turn.instruction =
+                    getInstructionForObvious(intersection.size(), via_edge, left);
+                right.turn.instruction = {findBasicTurnType(via_edge, right),
+                                          DirectionModifier::SlightRight};
+            }
+        }
+        else if (fork_range.second - fork_range.second == 2)
+        {
+            assignFork(via_edge, intersection[fork_range.second],
+                       intersection[fork_range.first + 1], intersection[fork_range.first]);
+        }
+        // assign left/right turns
+        intersection = assignLeftTurns(via_edge, std::move(intersection), fork_range.second + 1);
+        intersection = assignRightTurns(via_edge, std::move(intersection), fork_range.first);
+    }
+    else if (straightmost_deviation < FUZZY_ANGLE_DIFFERENCE &&
+             !intersection[straightmost_turn].entry_allowed)
+    {
+        // invalid straight turn
+        intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn + 1);
+        intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn);
+    }
+    // no straight turn
+    else if (intersection[straightmost_turn].turn.angle > 180)
+    {
+        // at most three turns on either side
+        intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn);
+        intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn);
+    }
+    else if (intersection[straightmost_turn].turn.angle < 180)
+    {
+        intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn + 1);
+        intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn + 1);
+    }
+    else
+    {
+        if (fallback_count++ < 10)
+        {
+            const auto coord = localizer(node_based_graph.GetTarget(via_edge));
+            util::SimpleLogger().Write(logWARNING)
+                << "Resolved to keep fallback on complex turn assignment at "
+                << std::setprecision(12) << toFloating(coord.lat) << " " << toFloating(coord.lon)
+                << "Straightmost: " << straightmost_turn;
+            ;
+            for (const auto &road : intersection)
+            {
+                const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+                util::SimpleLogger().Write(logWARNING)
+                    << "road: " << road.toString() << " Name: " << out_data.name_id
+                    << " Road Class: " << (int)out_data.road_classification.road_class
+                    << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
+            }
+        }
+    }
+    return intersection;
+}
+
+// Sets basic turn types as fallback for otherwise unhandled turns
+std::vector<ConnectedRoad> TurnAnalysis::setTurnTypes(const NodeID from,
+                                                      const EdgeID via_edge,
+                                                      std::vector<ConnectedRoad> intersection) const
+{
+    for (auto &road : intersection)
+    {
+        if (!road.entry_allowed)
+            continue;
+
+        const EdgeID onto_edge = road.turn.eid;
+        const NodeID to_node = node_based_graph.GetTarget(onto_edge);
+
+        road.turn.instruction = (from == to_node)
+                                    ? TurnInstruction{TurnType::Turn, DirectionModifier::UTurn}
+                                    : TurnInstruction{findBasicTurnType(via_edge, road),
+                                                      getTurnDirection(road.turn.angle)};
+    }
+    return intersection;
+}
+
+//                                               a
+//                                               |
+//                                               |
+//                                               v
+// For an intersection from_node --via_edi--> turn_node ----> c
+//                                               ^
+//                                               |
+//                                               |
+//                                               b
+// This functions returns _all_ turns as if the graph was undirected.
+// That means we not only get (from_node, turn_node, c) in the above example
+// but also (from_node, turn_node, a), (from_node, turn_node, b). These turns are
+// marked as invalid and only needed for intersection classification.
+std::vector<ConnectedRoad> TurnAnalysis::getConnectedRoads(const NodeID from_node,
+                                                           const EdgeID via_eid) const
+{
+    std::vector<ConnectedRoad> intersection;
+    const NodeID turn_node = node_based_graph.GetTarget(via_eid);
+    const NodeID only_restriction_to_node =
+        restriction_map.CheckForEmanatingIsOnlyTurn(from_node, turn_node);
+    const bool is_barrier_node = barrier_nodes.find(turn_node) != barrier_nodes.end();
+
+    bool has_uturn_edge = false;
+    for (const EdgeID onto_edge : node_based_graph.GetAdjacentEdgeRange(turn_node))
+    {
+        BOOST_ASSERT(onto_edge != SPECIAL_EDGEID);
+        const NodeID to_node = node_based_graph.GetTarget(onto_edge);
+
+        bool turn_is_valid =
+            // reverse edges are never valid turns because the resulting turn would look like this:
+            // from_node --via_edge--> turn_node <--onto_edge-- to_node
+            // however we need this for capture intersection shape for incoming one-ways
+            !node_based_graph.GetEdgeData(onto_edge).reversed &&
+            // we are not turning over a barrier
+            (!is_barrier_node || from_node == to_node) &&
+            // We are at an only_-restriction but not at the right turn.
+            (only_restriction_to_node == SPECIAL_NODEID || to_node == only_restriction_to_node) &&
+            // the turn is not restricted
+            !restriction_map.CheckIfTurnIsRestricted(from_node, turn_node, to_node);
+
+        auto angle = 0.;
+        if (from_node == to_node)
+        {
+            if (turn_is_valid && !is_barrier_node)
+            {
+                // we only add u-turns for dead-end streets.
+                if (node_based_graph.GetOutDegree(turn_node) > 1)
+                {
+                    auto number_of_emmiting_bidirectional_edges = 0;
+                    for (auto edge : node_based_graph.GetAdjacentEdgeRange(turn_node))
+                    {
+                        auto target = node_based_graph.GetTarget(edge);
+                        auto reverse_edge = node_based_graph.FindEdge(target, turn_node);
+                        BOOST_ASSERT(reverse_edge != SPECIAL_EDGEID);
+                        if (!node_based_graph.GetEdgeData(reverse_edge).reversed)
+                        {
+                            ++number_of_emmiting_bidirectional_edges;
+                        }
+                    }
+                    // is a dead-end
+                    turn_is_valid = number_of_emmiting_bidirectional_edges <= 1;
+                }
+            }
+            has_uturn_edge = true;
+            BOOST_ASSERT(angle >= 0. && angle < std::numeric_limits<double>::epsilon());
+        }
+        else
+        {
+            // unpack first node of second segment if packed
+            const auto first_coordinate = getRepresentativeCoordinate(
+                from_node, turn_node, via_eid, INVERT, compressed_edge_container, node_info_list);
+            const auto third_coordinate = getRepresentativeCoordinate(
+                turn_node, to_node, onto_edge, !INVERT, compressed_edge_container, node_info_list);
+            angle = util::coordinate_calculation::computeAngle(
+                first_coordinate, node_info_list[turn_node], third_coordinate);
+            if (angle < std::numeric_limits<double>::epsilon())
+                has_uturn_edge = true;
+        }
+
+        intersection.push_back(ConnectedRoad(
+            TurnOperation{onto_edge, angle, {TurnType::Invalid, DirectionModifier::UTurn}},
+            turn_is_valid));
+    }
+
+    // We hit the case of a street leading into nothing-ness. Since the code here assumes that this
+    // will
+    // never happen we add an artificial invalid uturn in this case.
+    if (!has_uturn_edge)
+    {
+        intersection.push_back(
+            {TurnOperation{via_eid, 0., {TurnType::Invalid, DirectionModifier::UTurn}}, false});
+    }
+
+    const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second)
+    {
+        return first.turn.angle < second.turn.angle;
+    };
+    std::sort(std::begin(intersection), std::end(intersection), ByAngle);
+
+    BOOST_ASSERT(intersection[0].turn.angle >= 0. &&
+                 intersection[0].turn.angle < std::numeric_limits<double>::epsilon());
+
+    return mergeSegregatedRoads(std::move(intersection));
+}
+
+/*
+ * Segregated Roads often merge onto a single intersection.
+ * While technically representing different roads, they are
+ * often looked at as a single road.
+ * Due to the merging, turn Angles seem off, wenn we compute them from the
+ * initial positions.
+ *
+ *         b<b<b<b(1)<b<b<b
+ * aaaaa-b
+ *         b>b>b>b(2)>b>b>b
+ *
+ * Would be seen as a slight turn going fro a to (2). A Sharp turn going from
+ * (1) to (2).
+ *
+ * In cases like these, we megre this segregated roads into a single road to
+ * end up with a case like:
+ *
+ * aaaaa-bbbbbb
+ *
+ * for the turn representation.
+ * Anything containing the first u-turn in a merge affects all other angles
+ * and is handled separately from all others.
+ */
+std::vector<ConnectedRoad>
+TurnAnalysis::mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) const
+{
+    const auto getRight = [&](std::size_t index)
+    {
+        return (index + intersection.size() - 1) % intersection.size();
+    };
+
+    const auto mergable = [&](std::size_t first, std::size_t second) -> bool
+    {
+        const auto &first_data = node_based_graph.GetEdgeData(intersection[first].turn.eid);
+        const auto &second_data = node_based_graph.GetEdgeData(intersection[second].turn.eid);
+
+        return first_data.name_id != INVALID_NAME_ID && first_data.name_id == second_data.name_id &&
+               !first_data.roundabout && !second_data.roundabout &&
+               first_data.travel_mode == second_data.travel_mode &&
+               first_data.road_classification == second_data.road_classification &&
+               // compatible threshold
+               angularDeviation(intersection[first].turn.angle, intersection[second].turn.angle) <
+                   60 &&
+               first_data.reversed != second_data.reversed;
+    };
+
+    const auto merge = [](const ConnectedRoad &first, const ConnectedRoad &second) -> ConnectedRoad
+    {
+        if (!first.entry_allowed)
+        {
+            ConnectedRoad result = second;
+            result.turn.angle = (first.turn.angle + second.turn.angle) / 2;
+            if (first.turn.angle - second.turn.angle > 180)
+                result.turn.angle += 180;
+            if (result.turn.angle > 360)
+                result.turn.angle -= 360;
+
+            return result;
+        }
+        else
+        {
+            BOOST_ASSERT(!second.entry_allowed);
+            ConnectedRoad result = first;
+            result.turn.angle = (first.turn.angle + second.turn.angle) / 2;
+
+            if (first.turn.angle - second.turn.angle > 180)
+                result.turn.angle += 180;
+            if (result.turn.angle > 360)
+                result.turn.angle -= 360;
+
+            return result;
+        }
+    };
+    if (intersection.size() == 1)
+        return intersection;
+
+    // check for merges including the basic u-turn
+    // these result in an adjustment of all other angles
+    if (mergable(0, intersection.size() - 1))
+    {
+        // std::cout << "First merge" << std::endl;
+        const double correction_factor =
+            (360 - intersection[intersection.size() - 1].turn.angle) / 2;
+        for (std::size_t i = 1; i + 1 < intersection.size(); ++i)
+            intersection[i].turn.angle += correction_factor;
+        intersection[0] = merge(intersection.front(), intersection.back());
+        intersection[0].turn.angle = 0;
+        intersection.pop_back();
+    }
+    else if (mergable(0, 1))
+    {
+        // std::cout << "First merge" << std::endl;
+        const double correction_factor = (intersection[1].turn.angle) / 2;
+        for (std::size_t i = 2; i < intersection.size(); ++i)
+            intersection[i].turn.angle += correction_factor;
+        intersection[0] = merge(intersection[0], intersection[1]);
+        intersection[0].turn.angle = 0;
+        intersection.erase(intersection.begin() + 1);
+    }
+
+    // a merge including the first u-turn requres an adjustment of the turn angles
+    // therefore these are handled prior to this step
+    for (std::size_t index = 2; index < intersection.size(); ++index)
+    {
+        if (mergable(index, getRight(index)))
+        {
+            intersection[getRight(index)] =
+                merge(intersection[getRight(index)], intersection[index]);
+            intersection.erase(intersection.begin() + index);
+            --index;
+        }
+    }
+
+    const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second)
+    {
+        return first.turn.angle < second.turn.angle;
+    };
+    std::sort(std::begin(intersection), std::end(intersection), ByAngle);
+    return intersection;
+}
+
+void TurnAnalysis::assignFork(const EdgeID via_edge,
+                              ConnectedRoad &left,
+                              ConnectedRoad &right) const
+{
+    const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+    const bool low_priority_left = isLowPriorityRoadClass(
+        node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class);
+    const bool low_priority_right = isLowPriorityRoadClass(
+        node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class);
+    if ((angularDeviation(left.turn.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
+         angularDeviation(right.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE))
+    {
+        // left side is actually straight
+        const auto &out_data = node_based_graph.GetEdgeData(left.turn.eid);
+        if (requiresAnnouncement(in_data, out_data))
+        {
+            if (low_priority_right && !low_priority_left)
+            {
+                left.turn.instruction = getInstructionForObvious(3, via_edge, left);
+                right.turn.instruction = {findBasicTurnType(via_edge, right),
+                                          DirectionModifier::SlightRight};
+            }
+            else
+            {
+                if (low_priority_left && !low_priority_right)
+                {
+                    left.turn.instruction = {findBasicTurnType(via_edge, left),
+                                             DirectionModifier::SlightLeft};
+                    right.turn.instruction = {findBasicTurnType(via_edge, right),
+                                              DirectionModifier::SlightRight};
+                }
+                else
+                {
+                    left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
+                    right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
+                }
+            }
+        }
+        else
+        {
+            left.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
+            right.turn.instruction = {findBasicTurnType(via_edge, right),
+                                      DirectionModifier::SlightRight};
+        }
+    }
+    else if (angularDeviation(right.turn.angle, STRAIGHT_ANGLE) <
+                 MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
+             angularDeviation(left.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
+    {
+        // right side is actually straight
+        const auto &out_data = node_based_graph.GetEdgeData(right.turn.eid);
+        if (angularDeviation(right.turn.angle, STRAIGHT_ANGLE) <
+                MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
+            angularDeviation(left.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
+        {
+            if (requiresAnnouncement(in_data, out_data))
+            {
+                if (low_priority_left && !low_priority_right)
+                {
+                    left.turn.instruction = {findBasicTurnType(via_edge, left),
+                                             DirectionModifier::SlightLeft};
+                    right.turn.instruction = getInstructionForObvious(3, via_edge, right);
+                }
+                else
+                {
+                    if (low_priority_right && !low_priority_left)
+                    {
+                        left.turn.instruction = {findBasicTurnType(via_edge, left),
+                                                 DirectionModifier::SlightLeft};
+                        right.turn.instruction = {findBasicTurnType(via_edge, right),
+                                                  DirectionModifier::SlightRight};
+                    }
+                    else
+                    {
+                        right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
+                        left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
+                    }
+                }
+            }
+            else
+            {
+                right.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
+                left.turn.instruction = {findBasicTurnType(via_edge, left),
+                                         DirectionModifier::SlightLeft};
+            }
+        }
+    }
+    else
+    {
+        // left side of fork
+        if (low_priority_right && !low_priority_left)
+            left.turn.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
+        else
+        {
+            if (low_priority_left && !low_priority_right)
+                left.turn.instruction = {TurnType::Turn, DirectionModifier::SlightLeft};
+            else
+                left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
+        }
+
+        // right side of fork
+        if (low_priority_left && !low_priority_right)
+            right.turn.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
+        else
+        {
+            if (low_priority_right && !low_priority_left)
+                right.turn.instruction = {TurnType::Turn, DirectionModifier::SlightRight};
+            else
+                right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
+        }
+    }
+}
+
+void TurnAnalysis::assignFork(const EdgeID via_edge,
+                              ConnectedRoad &left,
+                              ConnectedRoad &center,
+                              ConnectedRoad &right) const
+{
+    // TODO handle low priority road classes in a reasonable way
+    if (left.entry_allowed && center.entry_allowed && right.entry_allowed)
+    {
+        left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
+        if (angularDeviation(center.turn.angle, 180) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+        {
+            const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+            const auto &out_data = node_based_graph.GetEdgeData(center.turn.eid);
+            if (requiresAnnouncement(in_data, out_data))
+            {
+                center.turn.instruction = {TurnType::Fork, DirectionModifier::Straight};
+            }
+            else
+            {
+                center.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
+            }
+        }
+        else
+        {
+            center.turn.instruction = {TurnType::Fork, DirectionModifier::Straight};
+        }
+        right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
+    }
+    else if (left.entry_allowed)
+    {
+        if (right.entry_allowed)
+            assignFork(via_edge, left, right);
+        else if (center.entry_allowed)
+            assignFork(via_edge, left, center);
+        else
+            left.turn.instruction = {findBasicTurnType(via_edge, left),
+                                     getTurnDirection(left.turn.angle)};
+    }
+    else if (right.entry_allowed)
+    {
+        if (center.entry_allowed)
+            assignFork(via_edge, center, right);
+        else
+            right.turn.instruction = {findBasicTurnType(via_edge, right),
+                                      getTurnDirection(right.turn.angle)};
+    }
+    else
+    {
+        if (center.entry_allowed)
+            center.turn.instruction = {findBasicTurnType(via_edge, center),
+                                       getTurnDirection(center.turn.angle)};
+    }
+}
+
+std::size_t TurnAnalysis::findObviousTurn(const EdgeID via_edge,
+                                          const std::vector<ConnectedRoad> &intersection) const
+{
+    // no obvious road
+    if (intersection.size() == 1)
+        return 0;
+
+    // a single non u-turn is obvious
+    if (intersection.size() == 2)
+        return 1;
+
+    // at least three roads
+    std::size_t best = 0;
+    double best_deviation = 180;
+
+    std::size_t best_continue = 0;
+    double best_continue_deviation = 180;
+
+    const EdgeData &in_data = node_based_graph.GetEdgeData(via_edge);
+    for (std::size_t i = 1; i < intersection.size(); ++i)
+    {
+        const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
+        if (intersection[i].entry_allowed && deviation < best_deviation)
+        {
+            best_deviation = deviation;
+            best = i;
+        }
+
+        const auto out_data = node_based_graph.GetEdgeData(intersection[i].turn.eid);
+        if (intersection[i].entry_allowed && out_data.name_id == in_data.name_id &&
+            deviation < best_continue_deviation)
+        {
+            best_continue_deviation = deviation;
+            best_continue = i;
+        }
+    }
+
+    if (best == 0)
+        return 0;
+
+    if (best_deviation >= 2 * NARROW_TURN_ANGLE)
+        return 0;
+
+    // TODO incorporate road class in decision
+    if (best != 0 && best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+    {
+        return best;
+    }
+
+    // has no obvious continued road
+    if (best_continue == 0 || true)
+    {
+        // Find left/right deviation
+        const double left_deviation = angularDeviation(
+            intersection[(best + 1) % intersection.size()].turn.angle, STRAIGHT_ANGLE);
+        const double right_deviation =
+            angularDeviation(intersection[best - 1].turn.angle, STRAIGHT_ANGLE);
+
+        if (best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
+            std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
+            return best;
+
+        // other narrow turns?
+        if (angularDeviation(intersection[best - 1].turn.angle, STRAIGHT_ANGLE) <=
+            FUZZY_ANGLE_DIFFERENCE)
+            return 0;
+        if (angularDeviation(intersection[(best + 1) % intersection.size()].turn.angle,
+                             STRAIGHT_ANGLE) <= FUZZY_ANGLE_DIFFERENCE)
+            return 0;
+
+        // Well distinct turn that is nearly straight
+        if (left_deviation / best_deviation >= DISTINCTION_RATIO &&
+            right_deviation / best_deviation >= DISTINCTION_RATIO)
+        {
+            return best;
+        }
+    }
+
+    return 0; // no obvious turn
+}
+
+std::pair<std::size_t, std::size_t>
+TurnAnalysis::findFork(const std::vector<ConnectedRoad> &intersection) const
+{
+
+    std::size_t best = 0;
+    double best_deviation = 180;
+
+    // TODO handle road classes
+    for (std::size_t i = 1; i < intersection.size(); ++i)
+    {
+        const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
+        if (intersection[i].entry_allowed && deviation < best_deviation)
+        {
+            best_deviation = deviation;
+            best = i;
+        }
+    }
+
+    if (best_deviation <= NARROW_TURN_ANGLE)
+    {
+        std::size_t left = best, right = best;
+        while (left + 1 < intersection.size() &&
+               angularDeviation(intersection[left].turn.angle, intersection[left + 1].turn.angle) <
+                   NARROW_TURN_ANGLE)
+            ++left;
+        while (right > 1 &&
+               angularDeviation(intersection[right].turn.angle,
+                                intersection[right - 1].turn.angle) < NARROW_TURN_ANGLE)
+            --right;
+
+        // TODO check whether 2*NARROW_TURN is too large
+        if (right < left &&
+            angularDeviation(intersection[left].turn.angle,
+                             intersection[(left + 1) % intersection.size()].turn.angle) >=
+                2 * NARROW_TURN_ANGLE &&
+            angularDeviation(intersection[right].turn.angle, intersection[right - 1].turn.angle) >=
+                2 * NARROW_TURN_ANGLE)
+            return std::make_pair(right, left);
+    }
+    return std::make_pair(0llu, 0llu);
+}
+
+// Can only assign three turns
+std::vector<ConnectedRoad> TurnAnalysis::assignLeftTurns(const EdgeID via_edge,
+                                                         std::vector<ConnectedRoad> intersection,
+                                                         const std::size_t starting_at) const
+{
+    const auto count_valid = [&intersection, starting_at]()
+    {
+        std::size_t count = 0;
+        for (std::size_t i = starting_at; i < intersection.size(); ++i)
+            if (intersection[i].entry_allowed)
+                ++count;
+        return count;
+    };
+    if (starting_at == intersection.size() || count_valid() == 0)
+        return intersection;
+    // handle single turn
+    if (intersection.size() - starting_at == 1)
+    {
+        if (!intersection[starting_at].entry_allowed)
+            return intersection;
+
+        if (angularDeviation(intersection[starting_at].turn.angle, STRAIGHT_ANGLE) >
+                NARROW_TURN_ANGLE &&
+            angularDeviation(intersection[starting_at].turn.angle, 0) > NARROW_TURN_ANGLE)
+        {
+            // assign left turn
+            intersection[starting_at].turn.instruction = {
+                findBasicTurnType(via_edge, intersection[starting_at]), DirectionModifier::Left};
+        }
+        else if (angularDeviation(intersection[starting_at].turn.angle, STRAIGHT_ANGLE) <=
+                 NARROW_TURN_ANGLE)
+        {
+            intersection[starting_at].turn.instruction = {
+                findBasicTurnType(via_edge, intersection[starting_at]),
+                DirectionModifier::SlightLeft};
+        }
+        else
+        {
+            intersection[starting_at].turn.instruction = {
+                findBasicTurnType(via_edge, intersection[starting_at]),
+                DirectionModifier::SharpLeft};
+        }
+    }
+    // two turns on at the side
+    else if (intersection.size() - starting_at == 2)
+    {
+        const auto first_direction = getTurnDirection(intersection[starting_at].turn.angle);
+        const auto second_direction = getTurnDirection(intersection[starting_at + 1].turn.angle);
+        if (first_direction == second_direction)
+        {
+            // conflict
+            handleDistinctConflict(via_edge, intersection[starting_at + 1],
+                                   intersection[starting_at]);
+        }
+        else
+        {
+            intersection[starting_at].turn.instruction = {
+                findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
+            intersection[starting_at + 1].turn.instruction = {
+                findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
+        }
+    }
+    else if (intersection.size() - starting_at == 3)
+    {
+        const auto first_direction = getTurnDirection(intersection[starting_at].turn.angle);
+        const auto second_direction = getTurnDirection(intersection[starting_at + 1].turn.angle);
+        const auto third_direction = getTurnDirection(intersection[starting_at + 2].turn.angle);
+        if (first_direction != second_direction && second_direction != third_direction)
+        {
+            // implies first != third, based on the angles and clockwise order
+            if (intersection[starting_at].entry_allowed)
+                intersection[starting_at].turn.instruction = {
+                    findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
+            if (intersection[starting_at + 1].entry_allowed)
+                intersection[starting_at + 1].turn.instruction = {
+                    findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
+            if (intersection[starting_at + 2].entry_allowed)
+                intersection[starting_at + 2].turn.instruction = {
+                    findBasicTurnType(via_edge, intersection[starting_at + 2]), second_direction};
+        }
+        else if (2 >= (intersection[starting_at].entry_allowed +
+                       intersection[starting_at + 1].entry_allowed +
+                       intersection[starting_at + 2].entry_allowed))
+        {
+            // at least one invalid turn
+            if (!intersection[starting_at].entry_allowed)
+            {
+                handleDistinctConflict(via_edge, intersection[starting_at + 2],
+                                       intersection[starting_at + 1]);
+            }
+            else if (!intersection[starting_at + 1].entry_allowed)
+            {
+                handleDistinctConflict(via_edge, intersection[starting_at + 2],
+                                       intersection[starting_at]);
+            }
+            else
+            {
+                handleDistinctConflict(via_edge, intersection[starting_at + 1],
+                                       intersection[starting_at]);
+            }
+        }
+        else if (intersection[starting_at].entry_allowed &&
+                 intersection[starting_at + 1].entry_allowed &&
+                 intersection[starting_at + 2].entry_allowed &&
+                 angularDeviation(intersection[starting_at].turn.angle,
+                                  intersection[starting_at + 1].turn.angle) >= NARROW_TURN_ANGLE &&
+                 angularDeviation(intersection[starting_at + 1].turn.angle,
+                                  intersection[starting_at + 2].turn.angle) >= NARROW_TURN_ANGLE)
+        {
+            intersection[starting_at].turn.instruction = {
+                findBasicTurnType(via_edge, intersection[starting_at]),
+                DirectionModifier::SlightLeft};
+            intersection[starting_at + 1].turn.instruction = {
+                findBasicTurnType(via_edge, intersection[starting_at + 1]),
+                DirectionModifier::Left};
+            intersection[starting_at + 2].turn.instruction = {
+                findBasicTurnType(via_edge, intersection[starting_at + 2]),
+                DirectionModifier::SharpLeft};
+        }
+        else if (intersection[starting_at].entry_allowed &&
+                 intersection[starting_at + 1].entry_allowed &&
+                 intersection[starting_at + 2].entry_allowed &&
+                 ((first_direction == second_direction && second_direction == third_direction) ||
+                  (third_direction == second_direction &&
+                   angularDeviation(intersection[starting_at].turn.angle,
+                                    intersection[starting_at + 1].turn.angle) < GROUP_ANGLE) ||
+                  (second_direction == first_direction &&
+                   angularDeviation(intersection[starting_at + 1].turn.angle,
+                                    intersection[starting_at + 2].turn.angle) < GROUP_ANGLE)))
+        {
+            intersection[starting_at].turn.instruction = {
+                detail::isRampClass(intersection[starting_at].turn.eid, node_based_graph)
+                    ? FirstRamp
+                    : FirstTurn,
+                second_direction};
+            intersection[starting_at + 1].turn.instruction = {
+                detail::isRampClass(intersection[starting_at + 1].turn.eid, node_based_graph)
+                    ? SecondRamp
+                    : SecondTurn,
+                second_direction};
+            intersection[starting_at + 2].turn.instruction = {
+                detail::isRampClass(intersection[starting_at + 2].turn.eid, node_based_graph)
+                    ? ThirdRamp
+                    : ThirdTurn,
+                second_direction};
+        }
+        else if (intersection[starting_at].entry_allowed &&
+                 intersection[starting_at + 1].entry_allowed &&
+                 intersection[starting_at + 2].entry_allowed &&
+                 ((third_direction == second_direction &&
+                   angularDeviation(intersection[starting_at].turn.angle,
+                                    intersection[starting_at + 1].turn.angle) >= GROUP_ANGLE) ||
+                  (second_direction == first_direction &&
+                   angularDeviation(intersection[starting_at + 1].turn.angle,
+                                    intersection[starting_at + 2].turn.angle) >= GROUP_ANGLE)))
+        {
+            // conflict one side with an additional very sharp turn
+            if (angularDeviation(intersection[starting_at + 1].turn.angle,
+                                 intersection[starting_at + 2].turn.angle) >= GROUP_ANGLE)
+            {
+                handleDistinctConflict(via_edge, intersection[starting_at + 1],
+                                       intersection[starting_at]);
+                intersection[starting_at + 2].turn.instruction = {
+                    findBasicTurnType(via_edge, intersection[starting_at + 2]), third_direction};
+            }
+            else
+            {
+                intersection[starting_at].turn.instruction = {
+                    findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
+                handleDistinctConflict(via_edge, intersection[starting_at + 2],
+                                       intersection[starting_at + 1]);
+            }
+        }
+
+        else if ((first_direction == second_direction &&
+                  intersection[starting_at].entry_allowed !=
+                      intersection[starting_at + 1].entry_allowed) ||
+                 (second_direction == third_direction &&
+                  intersection[starting_at + 1].entry_allowed !=
+                      intersection[starting_at + 2].entry_allowed))
+        {
+            // no conflict, due to conflict being restricted to valid/invalid
+            if (intersection[starting_at].entry_allowed)
+                intersection[starting_at].turn.instruction = {
+                    findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
+            if (intersection[starting_at + 1].entry_allowed)
+                intersection[starting_at + 1].turn.instruction = {
+                    findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
+            if (intersection[starting_at + 2].entry_allowed)
+                intersection[starting_at + 2].turn.instruction = {
+                    findBasicTurnType(via_edge, intersection[starting_at + 2]), third_direction};
+        }
+        else
+        {
+            auto coord = localizer(node_based_graph.GetTarget(via_edge));
+            util::SimpleLogger().Write(logWARNING)
+                << "Reached fallback for left turns, size 3: " << std::setprecision(12)
+                << toFloating(coord.lat) << " " << toFloating(coord.lon);
+            for (const auto road : intersection)
+            {
+                const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+                util::SimpleLogger().Write(logWARNING)
+                    << "\troad: " << road.toString() << " Name: " << out_data.name_id
+                    << " Road Class: " << (int)out_data.road_classification.road_class
+                    << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
+            }
+
+            for (std::size_t i = starting_at; i < intersection.size(); ++i)
+                if (intersection[i].entry_allowed)
+                    intersection[i].turn.instruction = {
+                        findBasicTurnType(via_edge, intersection[i]),
+                        getTurnDirection(intersection[i].turn.angle)};
+        }
+    }
+    else if (intersection.size() - starting_at == 4)
+    {
+        if (intersection[starting_at].entry_allowed)
+            intersection[starting_at].turn.instruction = {
+                detail::isRampClass(intersection[starting_at].turn.eid, node_based_graph)
+                    ? FirstRamp
+                    : FirstTurn,
+                DirectionModifier::Left};
+        if (intersection[starting_at + 1].entry_allowed)
+            intersection[starting_at + 1].turn.instruction = {
+                detail::isRampClass(intersection[starting_at + 1].turn.eid, node_based_graph)
+                    ? SecondRamp
+                    : SecondTurn,
+                DirectionModifier::Left};
+        if (intersection[starting_at + 2].entry_allowed)
+            intersection[starting_at + 2].turn.instruction = {
+                detail::isRampClass(intersection[starting_at + 2].turn.eid, node_based_graph)
+                    ? ThirdRamp
+                    : ThirdTurn,
+                DirectionModifier::Left};
+        if (intersection[starting_at + 3].entry_allowed)
+            intersection[starting_at + 3].turn.instruction = {
+                detail::isRampClass(intersection[starting_at + 3].turn.eid, node_based_graph)
+                    ? FourthRamp
+                    : FourthTurn,
+                DirectionModifier::Left};
+    }
+    else
+    {
+        for (auto &road : intersection)
+        {
+            if (!road.entry_allowed)
+                continue;
+            road.turn.instruction = {detail::isRampClass(road.turn.eid, node_based_graph) ? Ramp
+                                                                                          : Turn,
+                                     getTurnDirection(road.turn.angle)};
+        }
+        /*
+        auto coord = localizer(node_based_graph.GetTarget(via_edge));
+        util::SimpleLogger().Write(logWARNING)
+            << "Reached fallback for left turns (" << starting_at << ") " << std::setprecision(12)
+            << toFloating(coord.lat) << " " << toFloating(coord.lon);
+        for (const auto road : intersection)
+        {
+            const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+            util::SimpleLogger().Write(logWARNING)
+                << "\troad: " << road.toString() << " Name: " << out_data.name_id
+                << " Road Class: " << (int)out_data.road_classification.road_class
+                << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
+        }
+        */
+    }
+    return intersection;
+}
+
+// can only assign three turns
+std::vector<ConnectedRoad> TurnAnalysis::assignRightTurns(const EdgeID via_edge,
+                                                          std::vector<ConnectedRoad> intersection,
+                                                          const std::size_t up_to) const
+{
+    BOOST_ASSERT(up_to <= intersection.size());
+    const auto count_valid = [&intersection, up_to]()
+    {
+        std::size_t count = 0;
+        for (std::size_t i = 1; i < up_to; ++i)
+            if (intersection[i].entry_allowed)
+                ++count;
+        return count;
+    };
+    if (up_to <= 1 || count_valid() == 0)
+        return intersection;
+    // handle single turn
+    if (up_to == 2)
+    {
+        if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) > NARROW_TURN_ANGLE &&
+            angularDeviation(intersection[1].turn.angle, 0) > NARROW_TURN_ANGLE)
+        {
+            // assign left turn
+            intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+                                                DirectionModifier::Right};
+        }
+        else if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) <= NARROW_TURN_ANGLE)
+        {
+            intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+                                                DirectionModifier::SlightRight};
+        }
+        else
+        {
+            intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+                                                DirectionModifier::SharpRight};
+        }
+    }
+    else if (up_to == 3)
+    {
+        const auto first_direction = getTurnDirection(intersection[1].turn.angle);
+        const auto second_direction = getTurnDirection(intersection[2].turn.angle);
+        if (first_direction == second_direction)
+        {
+            // conflict
+            handleDistinctConflict(via_edge, intersection[2], intersection[1]);
+        }
+        else
+        {
+            intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+                                                first_direction};
+            intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+                                                second_direction};
+        }
+    }
+    else if (up_to == 4)
+    {
+        const auto first_direction = getTurnDirection(intersection[1].turn.angle);
+        const auto second_direction = getTurnDirection(intersection[2].turn.angle);
+        const auto third_direction = getTurnDirection(intersection[3].turn.angle);
+        if (first_direction != second_direction && second_direction != third_direction)
+        {
+            if (intersection[1].entry_allowed)
+                intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+                                                    first_direction};
+            if (intersection[2].entry_allowed)
+                intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+                                                    second_direction};
+            if (intersection[3].entry_allowed)
+                intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
+                                                    third_direction};
+        }
+        else if (2 >= (intersection[1].entry_allowed + intersection[2].entry_allowed +
+                       intersection[3].entry_allowed))
+        {
+            // at least a single invalid
+            if (!intersection[3].entry_allowed)
+            {
+                handleDistinctConflict(via_edge, intersection[2], intersection[1]);
+            }
+            else if (!intersection[1].entry_allowed)
+            {
+                handleDistinctConflict(via_edge, intersection[3], intersection[2]);
+            }
+            else // handles one-valid as well as two valid (1,3)
+            {
+                handleDistinctConflict(via_edge, intersection[3], intersection[1]);
+            }
+        }
+
+        else if (intersection[1].entry_allowed && intersection[2].entry_allowed &&
+                 intersection[3].entry_allowed &&
+                 angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >=
+                     NARROW_TURN_ANGLE &&
+                 angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
+                     NARROW_TURN_ANGLE)
+        {
+            intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+                                                DirectionModifier::SharpRight};
+            intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+                                                DirectionModifier::Right};
+            intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
+                                                DirectionModifier::SlightRight};
+        }
+        else if (intersection[1].entry_allowed && intersection[2].entry_allowed &&
+                 intersection[3].entry_allowed &&
+                 ((first_direction == second_direction && second_direction == third_direction) ||
+                  (first_direction == second_direction &&
+                   angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) <
+                       GROUP_ANGLE) ||
+                  (second_direction == third_direction &&
+                   angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) <
+                       GROUP_ANGLE)))
+        {
+            intersection[1].turn.instruction = {
+                detail::isRampClass(intersection[1].turn.eid, node_based_graph) ? ThirdRamp
+                                                                                : ThirdTurn,
+                second_direction};
+            intersection[2].turn.instruction = {
+                detail::isRampClass(intersection[2].turn.eid, node_based_graph) ? SecondRamp
+                                                                                : SecondTurn,
+                second_direction};
+            intersection[3].turn.instruction = {
+                detail::isRampClass(intersection[3].turn.eid, node_based_graph) ? FirstRamp
+                                                                                : FirstTurn,
+                second_direction};
+        }
+        else if (intersection[1].entry_allowed && intersection[2].entry_allowed &&
+                 intersection[3].entry_allowed &&
+                 ((first_direction == second_direction &&
+                   angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
+                       GROUP_ANGLE) ||
+                  (second_direction == third_direction &&
+                   angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >=
+                       GROUP_ANGLE)))
+        {
+            if (angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
+                GROUP_ANGLE)
+            {
+                handleDistinctConflict(via_edge, intersection[2], intersection[1]);
+                intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
+                                                    third_direction};
+            }
+            else
+            {
+                intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+                                                    first_direction};
+                handleDistinctConflict(via_edge, intersection[3], intersection[2]);
+            }
+        }
+        else if ((first_direction == second_direction &&
+                  intersection[1].entry_allowed != intersection[2].entry_allowed) ||
+                 (second_direction == third_direction &&
+                  intersection[2].entry_allowed != intersection[3].entry_allowed))
+        {
+            if (intersection[1].entry_allowed)
+                intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+                                                    first_direction};
+            if (intersection[2].entry_allowed)
+                intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+                                                    second_direction};
+            if (intersection[3].entry_allowed)
+                intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
+                                                    third_direction};
+        }
+        else
+        {
+            auto coord = localizer(node_based_graph.GetTarget(via_edge));
+            util::SimpleLogger().Write(logWARNING)
+                << "Reached fallback for right turns, size 3: " << std::setprecision(12)
+                << toFloating(coord.lat) << " " << toFloating(coord.lon)
+                << " Valids: " << (intersection[1].entry_allowed + intersection[2].entry_allowed +
+                                   intersection[3].entry_allowed);
+            for (const auto road : intersection)
+            {
+                const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+                util::SimpleLogger().Write(logWARNING)
+                    << "\troad: " << road.toString() << " Name: " << out_data.name_id
+                    << " Road Class: " << (int)out_data.road_classification.road_class
+                    << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
+            }
+
+            for (std::size_t i = 1; i < up_to; ++i)
+                if (intersection[i].entry_allowed)
+                    intersection[i].turn.instruction = {
+                        findBasicTurnType(via_edge, intersection[i]),
+                        getTurnDirection(intersection[i].turn.angle)};
+        }
+    }
+    else if (up_to == 5)
+    {
+        if (intersection[4].entry_allowed)
+            intersection[4].turn.instruction = {
+                detail::isRampClass(intersection[4].turn.eid, node_based_graph) ? FirstRamp
+                                                                                : FirstTurn,
+                DirectionModifier::Right};
+        if (intersection[3].entry_allowed)
+            intersection[3].turn.instruction = {
+                detail::isRampClass(intersection[3].turn.eid, node_based_graph) ? SecondRamp
+                                                                                : SecondTurn,
+                DirectionModifier::Right};
+        if (intersection[2].entry_allowed)
+            intersection[2].turn.instruction = {
+                detail::isRampClass(intersection[2].turn.eid, node_based_graph) ? ThirdRamp
+                                                                                : ThirdTurn,
+                DirectionModifier::Right};
+        if (intersection[1].entry_allowed)
+            intersection[1].turn.instruction = {
+                detail::isRampClass(intersection[1].turn.eid, node_based_graph) ? FourthRamp
+                                                                                : FourthTurn,
+                DirectionModifier::Right};
+    }
+    else
+    {
+        for (std::size_t i = 1; i < up_to; ++i)
+        {
+            auto &road = intersection[i];
+            if (!road.entry_allowed)
+                continue;
+            road.turn.instruction = {detail::isRampClass(road.turn.eid, node_based_graph) ? Ramp
+                                                                                          : Turn,
+                                     getTurnDirection(road.turn.angle)};
+        }
+
+        /*
+        auto coord = localizer(node_based_graph.GetTarget(via_edge));
+        util::SimpleLogger().Write(logWARNING)
+            << "Reached fallback for right turns (" << up_to << ") " << std::setprecision(12)
+            << toFloating(coord.lat) << " " << toFloating(coord.lon);
+        for (const auto road : intersection)
+        {
+            const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+            util::SimpleLogger().Write(logWARNING)
+                << "\troad: " << road.toString() << " Name: " << out_data.name_id
+                << " Road Class: " << (int)out_data.road_classification.road_class
+                << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
+        }
+        */
+    }
+    return intersection;
+}
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
diff --git a/data_structures/raster_source.cpp b/src/extractor/raster_source.cpp
similarity index 59%
rename from data_structures/raster_source.cpp
rename to src/extractor/raster_source.cpp
index 9e880a2..16e41f9 100644
--- a/data_structures/raster_source.cpp
+++ b/src/extractor/raster_source.cpp
@@ -1,39 +1,15 @@
-/*
+#include "extractor/raster_source.hpp"
 
-Copyright (c) 2015, Project OSRM contributors
-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 "raster_source.hpp"
-
-#include "../util/simple_logger.hpp"
-#include "../util/timing_util.hpp"
-
-#include <osrm/coordinate.hpp>
+#include "util/simple_logger.hpp"
+#include "util/timing_util.hpp"
 
 #include <cmath>
 
+namespace osrm
+{
+namespace extractor
+{
+
 RasterSource::RasterSource(RasterGrid _raster_data,
                            std::size_t _width,
                            std::size_t _height,
@@ -106,28 +82,28 @@ int SourceContainer::loadRasterSource(const std::string &path_string,
                                       std::size_t nrows,
                                       std::size_t ncols)
 {
-    const auto _xmin = static_cast<int>(xmin * COORDINATE_PRECISION);
-    const auto _xmax = static_cast<int>(xmax * COORDINATE_PRECISION);
-    const auto _ymin = static_cast<int>(ymin * COORDINATE_PRECISION);
-    const auto _ymax = static_cast<int>(ymax * COORDINATE_PRECISION);
+    const auto _xmin = static_cast<int>(util::toFixed(util::FloatLongitude(xmin)));
+    const auto _xmax = static_cast<int>(util::toFixed(util::FloatLongitude(xmax)));
+    const auto _ymin = static_cast<int>(util::toFixed(util::FloatLatitude(ymin)));
+    const auto _ymax = static_cast<int>(util::toFixed(util::FloatLatitude(ymax)));
 
     const auto itr = LoadedSourcePaths.find(path_string);
     if (itr != LoadedSourcePaths.end())
     {
-        SimpleLogger().Write() << "[source loader] Already loaded source '" << path_string
-                               << "' at source_id " << itr->second;
+        util::SimpleLogger().Write() << "[source loader] Already loaded source '" << path_string
+                                     << "' at source_id " << itr->second;
         return itr->second;
     }
 
     int source_id = static_cast<int>(LoadedSources.size());
 
-    SimpleLogger().Write() << "[source loader] Loading from " << path_string << "  ... ";
+    util::SimpleLogger().Write() << "[source loader] Loading from " << path_string << "  ... ";
     TIMER_START(loading_source);
 
     boost::filesystem::path filepath(path_string);
     if (!boost::filesystem::exists(filepath))
     {
-        throw osrm::exception("error reading: no such path");
+        throw util::exception("error reading: no such path");
     }
 
     RasterGrid rasterData{filepath, ncols, nrows};
@@ -137,42 +113,47 @@ int SourceContainer::loadRasterSource(const std::string &path_string,
     LoadedSourcePaths.emplace(path_string, source_id);
     LoadedSources.push_back(std::move(source));
 
-    SimpleLogger().Write() << "[source loader] ok, after " << TIMER_SEC(loading_source) << "s";
+    util::SimpleLogger().Write() << "[source loader] ok, after " << TIMER_SEC(loading_source)
+                                 << "s";
 
     return source_id;
 }
 
 // External function for looking up nearest data point from a specified source
-RasterDatum SourceContainer::getRasterDataFromSource(unsigned int source_id, int lon, int lat)
+RasterDatum SourceContainer::getRasterDataFromSource(unsigned int source_id, double lon, double lat)
 {
     if (LoadedSources.size() < source_id + 1)
     {
-        throw osrm::exception("error reading: no such loaded source");
+        throw util::exception("error reading: no such loaded source");
     }
 
-    BOOST_ASSERT(lat < (90 * COORDINATE_PRECISION));
-    BOOST_ASSERT(lat > (-90 * COORDINATE_PRECISION));
-    BOOST_ASSERT(lon < (180 * COORDINATE_PRECISION));
-    BOOST_ASSERT(lon > (-180 * COORDINATE_PRECISION));
+    BOOST_ASSERT(lat < 90);
+    BOOST_ASSERT(lat > -90);
+    BOOST_ASSERT(lon < 180);
+    BOOST_ASSERT(lon > -180);
 
     const auto &found = LoadedSources[source_id];
-    return found.getRasterData(lon, lat);
+    return found.getRasterData(static_cast<int>(util::toFixed(util::FloatLongitude(lon))),
+                               static_cast<int>(util::toFixed(util::FloatLatitude(lat))));
 }
 
 // External function for looking up interpolated data from a specified source
 RasterDatum
-SourceContainer::getRasterInterpolateFromSource(unsigned int source_id, int lon, int lat)
+SourceContainer::getRasterInterpolateFromSource(unsigned int source_id, double lon, double lat)
 {
     if (LoadedSources.size() < source_id + 1)
     {
-        throw osrm::exception("error reading: no such loaded source");
+        throw util::exception("error reading: no such loaded source");
     }
 
-    BOOST_ASSERT(lat < (90 * COORDINATE_PRECISION));
-    BOOST_ASSERT(lat > (-90 * COORDINATE_PRECISION));
-    BOOST_ASSERT(lon < (180 * COORDINATE_PRECISION));
-    BOOST_ASSERT(lon > (-180 * COORDINATE_PRECISION));
+    BOOST_ASSERT(lat < 90);
+    BOOST_ASSERT(lat > -90);
+    BOOST_ASSERT(lon < 180);
+    BOOST_ASSERT(lon > -180);
 
     const auto &found = LoadedSources[source_id];
-    return found.getRasterInterpolate(lon, lat);
+    return found.getRasterInterpolate(static_cast<int>(util::toFixed(util::FloatLongitude(lon))),
+                                      static_cast<int>(util::toFixed(util::FloatLatitude(lat))));
+}
+}
 }
diff --git a/data_structures/restriction_map.cpp b/src/extractor/restriction_map.cpp
similarity index 78%
rename from data_structures/restriction_map.cpp
rename to src/extractor/restriction_map.cpp
index eb685be..d41b1c4 100644
--- a/data_structures/restriction_map.cpp
+++ b/src/extractor/restriction_map.cpp
@@ -1,31 +1,9 @@
-/*
+#include "extractor/restriction_map.hpp"
 
-Copyright (c) 2015, Project OSRM contributors
-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_map.hpp"
+namespace osrm
+{
+namespace extractor
+{
 
 RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_list) : m_count(0)
 {
@@ -42,7 +20,8 @@ RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_l
         m_no_turn_via_node_set.insert(restriction.via.node);
 
         // This explicit downcasting is also OK for the same reason.
-        RestrictionSource restriction_source = {static_cast<NodeID>(restriction.from.node), static_cast<NodeID>(restriction.via.node)};
+        RestrictionSource restriction_source = {static_cast<NodeID>(restriction.from.node),
+                                                static_cast<NodeID>(restriction.via.node)};
 
         std::size_t index;
         auto restriction_iter = m_restriction_map.find(restriction_source);
@@ -176,9 +155,7 @@ bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID node_u,
 // check of node is the start of any restriction
 bool RestrictionMap::IsSourceNode(const NodeID node) const
 {
-    if (m_restriction_start_nodes.find(node) == m_restriction_start_nodes.end())
-    {
-        return false;
-    }
-    return true;
+    return m_restriction_start_nodes.find(node) != m_restriction_start_nodes.end();
+}
+}
 }
diff --git a/extractor/restriction_parser.cpp b/src/extractor/restriction_parser.cpp
similarity index 63%
rename from extractor/restriction_parser.cpp
rename to src/extractor/restriction_parser.cpp
index afb1947..b56af20 100644
--- a/extractor/restriction_parser.cpp
+++ b/src/extractor/restriction_parser.cpp
@@ -1,256 +1,213 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "../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/algorithm/string/predicate.hpp>
-#include <boost/ref.hpp>
-#include <boost/regex.hpp>
-#include <boost/optional/optional.hpp>
-
-#include <osmium/osm.hpp>
-#include <osmium/tags/regex_filter.hpp>
-
-#include <algorithm>
-#include <iterator>
-
-namespace
-{
-int lua_error_callback(lua_State *lua_state)
-{
-    std::string error_msg = lua_tostring(lua_state, -1);
-    throw osrm::exception("ERROR occured in profile script:\n" + error_msg);
-}
-}
-
-RestrictionParser::RestrictionParser(lua_State *lua_state) : 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";
-    }
-}
-
-/**
- * Tries to parse an relation as turn restriction. This can fail for a number of
- * reasons, this the return type is a boost::optional<T>.
- *
- * Some restrictions can also be ignored: See the ```get_exceptions``` function
- * in the corresponding profile.
- */
-boost::optional<InputRestrictionContainer>
-RestrictionParser::TryParse(const osmium::Relation &relation) const
-{
-    // return if turn restrictions should be ignored
-    if (!use_turn_restrictions)
-    {
-        return {};
-    }
-
-    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 {};
-    }
-
-    // check if the restriction should be ignored
-    const char *except = relation.get_value_by_key("except");
-    if (except != nullptr && ShouldIgnoreRestriction(except))
-    {
-        return {};
-    }
-
-    bool is_only_restriction = false;
-
-    for (; fi_begin != fi_end; ++fi_begin)
-    {
-        const std::string key(fi_begin->key());
-        const std::string value(fi_begin->value());
-
-        if (value.find("only_") == 0)
-        {
-            is_only_restriction = true;
-        }
-
-        // if the "restriction*" key is longer than 11 chars, it is a conditional exception (i.e.
-        // "restriction:<transportation_type>")
-        if (key.size() > 11)
-        {
-            const auto ex_suffix = [&](const std::string &exception)
-            {
-                return boost::algorithm::ends_with(key, exception);
-            };
-            bool is_actually_restricted =
-                std::any_of(begin(restriction_exceptions), end(restriction_exceptions), ex_suffix);
-
-            if (!is_actually_restricted)
-            {
-                return {};
-            }
-        }
-    }
-
-    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 via node id
-            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))
-            {
-                restriction_container.restriction.from.way = member.ref();
-            }
-            else if (0 == strcmp("to", role))
-            {
-                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...
-            break;
-        default:
-            // shouldn't ever happen
-            break;
-        }
-    }
-    return boost::make_optional(std::move(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("[;][ ]*"));
-
-    return std::any_of(std::begin(exceptions), std::end(exceptions),
-                       [&](const std::string &current_string)
-                       {
-                           if (std::end(restriction_exceptions) !=
-                               std::find(std::begin(restriction_exceptions),
-                                         std::end(restriction_exceptions), current_string))
-                           {
-                               return true;
-                           }
-                           return false;
-                       });
-}
+#include "extractor/restriction_parser.hpp"
+#include "extractor/profile_properties.hpp"
+
+#include "extractor/external_memory_node.hpp"
+#include "util/lua_util.hpp"
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/regex.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/optional/optional.hpp>
+#include <boost/ref.hpp>
+#include <boost/regex.hpp>
+
+#include <osmium/osm.hpp>
+#include <osmium/tags/regex_filter.hpp>
+
+#include <algorithm>
+#include <iterator>
+
+namespace osrm
+{
+namespace extractor
+{
+
+namespace
+{
+int luaErrorCallback(lua_State *lua_state)
+{
+    std::string error_msg = lua_tostring(lua_state, -1);
+    throw util::exception("ERROR occurred in profile script:\n" + error_msg);
+}
+}
+
+RestrictionParser::RestrictionParser(lua_State *lua_state, const ProfileProperties &properties)
+    : use_turn_restrictions(properties.use_turn_restrictions)
+{
+    if (use_turn_restrictions)
+    {
+        ReadRestrictionExceptions(lua_state);
+    }
+}
+
+void RestrictionParser::ReadRestrictionExceptions(lua_State *lua_state)
+{
+    if (util::luaFunctionExists(lua_state, "get_exceptions"))
+    {
+        luabind::set_pcall_callback(&luaErrorCallback);
+        // 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();
+        util::SimpleLogger().Write() << "Found " << exception_count
+                                     << " exceptions to turn restrictions:";
+        for (const std::string &str : restriction_exceptions)
+        {
+            util::SimpleLogger().Write() << "  " << str;
+        }
+    }
+    else
+    {
+        util::SimpleLogger().Write() << "Found no exceptions to turn restrictions";
+    }
+}
+
+/**
+ * Tries to parse an relation as turn restriction. This can fail for a number of
+ * reasons, this the return type is a boost::optional<T>.
+ *
+ * Some restrictions can also be ignored: See the ```get_exceptions``` function
+ * in the corresponding profile.
+ */
+boost::optional<InputRestrictionContainer>
+RestrictionParser::TryParse(const osmium::Relation &relation) const
+{
+    // return if turn restrictions should be ignored
+    if (!use_turn_restrictions)
+    {
+        return {};
+    }
+
+    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 {};
+    }
+
+    // check if the restriction should be ignored
+    const char *except = relation.get_value_by_key("except");
+    if (except != nullptr && ShouldIgnoreRestriction(except))
+    {
+        return {};
+    }
+
+    bool is_only_restriction = false;
+
+    for (; fi_begin != fi_end; ++fi_begin)
+    {
+        const std::string key(fi_begin->key());
+        const std::string value(fi_begin->value());
+
+        if (value.find("only_") == 0)
+        {
+            is_only_restriction = true;
+        }
+
+        // if the "restriction*" key is longer than 11 chars, it is a conditional exception (i.e.
+        // "restriction:<transportation_type>")
+        if (key.size() > 11)
+        {
+            const auto ex_suffix = [&](const std::string &exception)
+            {
+                return boost::algorithm::ends_with(key, exception);
+            };
+            bool is_actually_restricted =
+                std::any_of(begin(restriction_exceptions), end(restriction_exceptions), ex_suffix);
+
+            if (!is_actually_restricted)
+            {
+                return {};
+            }
+        }
+    }
+
+    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 via node id
+            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))
+            {
+                restriction_container.restriction.from.way = member.ref();
+            }
+            else if (0 == strcmp("to", role))
+            {
+                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...
+            break;
+        default:
+            // shouldn't ever happen
+            break;
+        }
+    }
+    return boost::make_optional(std::move(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("[;][ ]*"));
+
+    return std::any_of(std::begin(exceptions), std::end(exceptions),
+                       [&](const std::string &current_string)
+                       {
+                           return std::end(restriction_exceptions) !=
+                                  std::find(std::begin(restriction_exceptions),
+                                            std::end(restriction_exceptions), current_string);
+                       });
+}
+}
+}
diff --git a/src/extractor/scripting_environment.cpp b/src/extractor/scripting_environment.cpp
new file mode 100644
index 0000000..53cc8e1
--- /dev/null
+++ b/src/extractor/scripting_environment.cpp
@@ -0,0 +1,184 @@
+#include "extractor/scripting_environment.hpp"
+
+#include "extractor/extraction_helper_functions.hpp"
+#include "extractor/extraction_node.hpp"
+#include "extractor/extraction_way.hpp"
+#include "extractor/internal_extractor_edge.hpp"
+#include "extractor/external_memory_node.hpp"
+#include "extractor/raster_source.hpp"
+#include "extractor/profile_properties.hpp"
+#include "util/lua_util.hpp"
+#include "util/make_unique.hpp"
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+#include "util/typedefs.hpp"
+
+#include <luabind/tag_function.hpp>
+#include <luabind/operator.hpp>
+
+#include <osmium/osm.hpp>
+
+#include <sstream>
+
+namespace osrm
+{
+namespace extractor
+{
+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, "");
+}
+
+template <class T> double latToDouble(T const &object)
+{
+    return static_cast<double>(util::toFloating(object.lat));
+}
+
+template <class T> double lonToDouble(T const &object)
+{
+    return static_cast<double>(util::toFloating(object.lon));
+}
+
+// Error handler
+int luaErrorCallback(lua_State *state)
+{
+    std::string error_msg = lua_tostring(state, -1);
+    std::ostringstream error_stream;
+    error_stream << error_msg;
+    throw util::exception("ERROR occurred in profile script:\n" + error_stream.str());
+}
+}
+
+ScriptingEnvironment::ScriptingEnvironment(const std::string &file_name) : file_name(file_name)
+{
+    util::SimpleLogger().Write() << "Using script " << file_name;
+}
+
+void ScriptingEnvironment::InitContext(ScriptingEnvironment::Context &context)
+{
+    typedef double (osmium::Location::*location_member_ptr_type)() const;
+
+    luabind::open(context.state);
+    // open utility libraries string library;
+    luaL_openlibs(context.state);
+
+    util::luaAddScriptFolderToLoadPath(context.state, file_name.c_str());
+
+    // Add our function to the state's global scope
+    luabind::module(context.state)
+        [luabind::def("durationIsValid", durationIsValid),
+         luabind::def("parseDuration", parseDuration),
+         luabind::class_<TravelMode>("mode")
+             .enum_("enums")[luabind::value("inaccessible", TRAVEL_MODE_INACCESSIBLE),
+                             luabind::value("driving", TRAVEL_MODE_DRIVING),
+                             luabind::value("cycling", TRAVEL_MODE_CYCLING),
+                             luabind::value("walking", TRAVEL_MODE_WALKING),
+                             luabind::value("ferry", TRAVEL_MODE_FERRY),
+                             luabind::value("train", TRAVEL_MODE_TRAIN),
+                             luabind::value("pushing_bike", TRAVEL_MODE_PUSHING_BIKE),
+                             luabind::value("movable_bridge", TRAVEL_MODE_MOVABLE_BRIDGE),
+                             luabind::value("steps_up", TRAVEL_MODE_STEPS_UP),
+                             luabind::value("steps_down", TRAVEL_MODE_STEPS_DOWN),
+                             luabind::value("river_up", TRAVEL_MODE_RIVER_UP),
+                             luabind::value("river_down", TRAVEL_MODE_RIVER_DOWN),
+                             luabind::value("route", TRAVEL_MODE_ROUTE)],
+         luabind::class_<SourceContainer>("sources")
+             .def(luabind::constructor<>())
+             .def("load", &SourceContainer::loadRasterSource)
+             .def("query", &SourceContainer::getRasterDataFromSource)
+             .def("interpolate", &SourceContainer::getRasterInterpolateFromSource),
+         luabind::class_<const float>("constants")
+             .enum_("enums")[luabind::value("precision", COORDINATE_PRECISION)],
+
+         luabind::class_<ProfileProperties>("ProfileProperties")
+             .def(luabind::constructor<>())
+             .property("traffic_signal_penalty", &ProfileProperties::GetTrafficSignalPenalty,
+                       &ProfileProperties::SetTrafficSignalPenalty)
+             .property("u_turn_penalty", &ProfileProperties::GetUturnPenalty,
+                       &ProfileProperties::SetUturnPenalty)
+             .def_readwrite("use_turn_restrictions", &ProfileProperties::use_turn_restrictions)
+             .def_readwrite("allow_u_turn_at_via", &ProfileProperties::allow_u_turn_at_via),
+
+         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("location", &osmium::Node::location)
+             .def("get_value_by_key", &osmium::Node::get_value_by_key)
+             .def("get_value_by_key", &get_value_by_key<osmium::Node>)
+             .def("id", &osmium::Node::id),
+
+         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("is_startpoint", &ExtractionWay::is_startpoint)
+             .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),
+         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>)
+             .def("id", &osmium::Way::id),
+         luabind::class_<InternalExtractorEdge>("EdgeSource")
+             .def_readonly("source_coordinate", &InternalExtractorEdge::source_coordinate)
+             .def_readwrite("weight_data", &InternalExtractorEdge::weight_data),
+         luabind::class_<InternalExtractorEdge::WeightData>("WeightData")
+             .def_readwrite("speed", &InternalExtractorEdge::WeightData::speed),
+         luabind::class_<ExternalMemoryNode>("EdgeTarget")
+             .property("lon", &lonToDouble<ExternalMemoryNode>)
+             .property("lat", &latToDouble<ExternalMemoryNode>),
+         luabind::class_<util::Coordinate>("Coordinate")
+             .property("lon", &lonToDouble<util::Coordinate>)
+             .property("lat", &latToDouble<util::Coordinate>),
+         luabind::class_<RasterDatum>("RasterDatum")
+             .def_readonly("datum", &RasterDatum::datum)
+             .def("invalid_data", &RasterDatum::get_invalid)];
+
+    luabind::globals(context.state)["properties"] = &context.properties;
+    luabind::globals(context.state)["sources"] = &context.sources;
+
+    if (0 != luaL_dofile(context.state, file_name.c_str()))
+    {
+        luabind::object error_msg(luabind::from_stack(context.state, -1));
+        std::ostringstream error_stream;
+        error_stream << error_msg;
+        throw util::exception("ERROR occurred in profile script:\n" + error_stream.str());
+    }
+}
+
+ScriptingEnvironment::Context &ScriptingEnvironment::GetContex()
+{
+    std::lock_guard<std::mutex> lock(init_mutex);
+    bool initialized = false;
+    auto &ref = script_contexts.local(initialized);
+    if (!initialized)
+    {
+        ref = util::make_unique<Context>();
+        InitContext(*ref);
+    }
+    luabind::set_pcall_callback(&luaErrorCallback);
+
+    return *ref;
+}
+}
+}
diff --git a/src/osrm/osrm.cpp b/src/osrm/osrm.cpp
new file mode 100644
index 0000000..9a69e2e
--- /dev/null
+++ b/src/osrm/osrm.cpp
@@ -0,0 +1,54 @@
+#include "osrm/osrm.hpp"
+#include "engine/api/route_parameters.hpp"
+#include "engine/api/table_parameters.hpp"
+#include "engine/api/nearest_parameters.hpp"
+#include "engine/api/trip_parameters.hpp"
+#include "engine/api/match_parameters.hpp"
+#include "engine/engine.hpp"
+#include "engine/status.hpp"
+#include "engine/engine_config.hpp"
+#include "util/make_unique.hpp"
+
+namespace osrm
+{
+
+// Pimpl idiom
+
+OSRM::OSRM(engine::EngineConfig &config) : engine_(util::make_unique<engine::Engine>(config)) {}
+OSRM::~OSRM() = default;
+OSRM::OSRM(OSRM &&) noexcept = default;
+OSRM &OSRM::operator=(OSRM &&) noexcept = default;
+
+// Forward to implementation
+
+engine::Status OSRM::Route(const engine::api::RouteParameters &params, util::json::Object &result)
+{
+    return engine_->Route(params, result);
+}
+
+engine::Status OSRM::Table(const engine::api::TableParameters &params, json::Object &result)
+{
+    return engine_->Table(params, result);
+}
+
+engine::Status OSRM::Nearest(const engine::api::NearestParameters &params, json::Object &result)
+{
+    return engine_->Nearest(params, result);
+}
+
+engine::Status OSRM::Trip(const engine::api::TripParameters &params, json::Object &result)
+{
+    return engine_->Trip(params, result);
+}
+
+engine::Status OSRM::Match(const engine::api::MatchParameters &params, json::Object &result)
+{
+    return engine_->Match(params, result);
+}
+
+engine::Status OSRM::Tile(const engine::api::TileParameters &params, std::string &result)
+{
+    return engine_->Tile(params, result);
+}
+
+} // ns osrm
diff --git a/src/server/api/parameters_parser.cpp b/src/server/api/parameters_parser.cpp
new file mode 100644
index 0000000..1cf3050
--- /dev/null
+++ b/src/server/api/parameters_parser.cpp
@@ -0,0 +1,86 @@
+#include "server/api/parameters_parser.hpp"
+
+#include "server/api/route_parameters_grammar.hpp"
+#include "server/api/table_parameter_grammar.hpp"
+#include "server/api/nearest_parameter_grammar.hpp"
+#include "server/api/trip_parameter_grammar.hpp"
+#include "server/api/match_parameter_grammar.hpp"
+#include "server/api/tile_parameter_grammar.hpp"
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace detail
+{
+template <typename T>
+using is_grammar_t = std::integral_constant<bool,
+                                            std::is_base_of<BaseParametersGrammar, T>::value ||
+                                                std::is_same<TileParametersGrammar, T>::value>;
+
+template <typename ParameterT,
+          typename GrammarT,
+          typename std::enable_if<detail::is_parameter_t<ParameterT>::value, int>::type = 0,
+          typename std::enable_if<detail::is_grammar_t<GrammarT>::value, int>::type = 0>
+boost::optional<ParameterT> parseParameters(std::string::iterator &iter, std::string::iterator end)
+{
+    GrammarT grammar;
+    const auto result = boost::spirit::qi::parse(iter, end, grammar);
+
+    boost::optional<ParameterT> parameters;
+    if (result && iter == end)
+        parameters = std::move(grammar.parameters);
+
+    return parameters;
+}
+} // ns detail
+
+template <>
+boost::optional<engine::api::RouteParameters> parseParameters(std::string::iterator &iter,
+                                                              std::string::iterator end)
+{
+    return detail::parseParameters<engine::api::RouteParameters, RouteParametersGrammar>(iter, end);
+}
+
+template <>
+boost::optional<engine::api::TableParameters> parseParameters(std::string::iterator &iter,
+                                                              std::string::iterator end)
+{
+    return detail::parseParameters<engine::api::TableParameters, TableParametersGrammar>(iter, end);
+}
+
+template <>
+boost::optional<engine::api::NearestParameters> parseParameters(std::string::iterator &iter,
+                                                                std::string::iterator end)
+{
+    return detail::parseParameters<engine::api::NearestParameters, NearestParametersGrammar>(iter,
+                                                                                             end);
+}
+
+template <>
+boost::optional<engine::api::TripParameters> parseParameters(std::string::iterator &iter,
+                                                             std::string::iterator end)
+{
+    return detail::parseParameters<engine::api::TripParameters, TripParametersGrammar>(iter, end);
+}
+
+template <>
+boost::optional<engine::api::MatchParameters> parseParameters(std::string::iterator &iter,
+                                                              std::string::iterator end)
+{
+    return detail::parseParameters<engine::api::MatchParameters, MatchParametersGrammar>(iter, end);
+}
+
+template <>
+boost::optional<engine::api::TileParameters> parseParameters(std::string::iterator &iter,
+                                                             std::string::iterator end)
+{
+    return detail::parseParameters<engine::api::TileParameters, TileParametersGrammar>(iter, end);
+}
+
+} // ns api
+} // ns server
+} // ns osrm
diff --git a/src/server/api/url_parser.cpp b/src/server/api/url_parser.cpp
new file mode 100644
index 0000000..661b1f6
--- /dev/null
+++ b/src/server/api/url_parser.cpp
@@ -0,0 +1,88 @@
+#include "server/api/url_parser.hpp"
+
+#include "engine/polyline_compressor.hpp"
+
+#include <boost/bind.hpp>
+#include <boost/spirit/include/qi_char_.hpp>
+#include <boost/spirit/include/qi_grammar.hpp>
+#include <boost/spirit/include/qi_uint.hpp>
+#include <boost/spirit/include/qi_real.hpp>
+#include <boost/spirit/include/qi_lit.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_as_string.hpp>
+#include <boost/spirit/include/qi_operator.hpp>
+#include <boost/spirit/include/qi_plus.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace
+{
+
+namespace qi = boost::spirit::qi;
+using Iterator = std::string::iterator;
+struct URLGrammar : boost::spirit::qi::grammar<Iterator>
+{
+    URLGrammar() : URLGrammar::base_type(url_rule)
+    {
+        const auto set_service = [this](std::string &service)
+        {
+            parsed_url.service = std::move(service);
+        };
+        const auto set_version = [this](const unsigned version)
+        {
+            parsed_url.version = version;
+        };
+        const auto set_profile = [this](std::string &profile)
+        {
+            parsed_url.profile = std::move(profile);
+        };
+        const auto set_query = [this](std::string &query)
+        {
+            parsed_url.query = std::move(query);
+        };
+
+        alpha_numeral = qi::char_("a-zA-Z0-9");
+        polyline_chars = qi::char_("a-zA-Z0-9_.--[]{}@?|\\%~`^");
+        all_chars = polyline_chars | qi::char_("=,;:&().");
+
+        service_rule = +alpha_numeral;
+        version_rule = qi::uint_;
+        profile_rule = +alpha_numeral;
+        query_rule = +all_chars;
+
+        url_rule = qi::lit('/') >> service_rule[set_service] >> qi::lit('/') >> qi::lit('v') >>
+                   version_rule[set_version] >> qi::lit('/') >> profile_rule[set_profile] >>
+                   qi::lit('/') >> query_rule[set_query];
+    }
+
+    ParsedURL parsed_url;
+
+    qi::rule<Iterator> url_rule;
+    qi::rule<Iterator, std::string()> service_rule, profile_rule, query_rule;
+    qi::rule<Iterator, unsigned()> version_rule;
+    qi::rule<Iterator, char()> alpha_numeral, all_chars, polyline_chars;
+};
+}
+
+boost::optional<ParsedURL> parseURL(std::string::iterator &iter, std::string::iterator end)
+{
+    boost::optional<ParsedURL> parsed_url;
+
+    URLGrammar grammar;
+    const auto result = boost::spirit::qi::parse(iter, end, grammar);
+
+    if (result && iter == end)
+    {
+        parsed_url = std::move(grammar.parsed_url);
+    }
+
+    return parsed_url;
+}
+}
+}
+}
diff --git a/server/connection.cpp b/src/server/connection.cpp
similarity index 70%
rename from server/connection.cpp
rename to src/server/connection.cpp
index dbf85fd..e7725fb 100644
--- a/server/connection.cpp
+++ b/src/server/connection.cpp
@@ -1,33 +1,6 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "connection.hpp"
-#include "request_handler.hpp"
-#include "request_parser.hpp"
+#include "server/connection.hpp"
+#include "server/request_handler.hpp"
+#include "server/request_parser.hpp"
 
 #include <boost/assert.hpp>
 #include <boost/bind.hpp>
@@ -37,7 +10,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <string>
 #include <vector>
 
-namespace http
+namespace osrm
+{
+namespace server
 {
 
 Connection::Connection(boost::asio::io_service &io_service, RequestHandler &handler)
@@ -65,25 +40,22 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
     }
 
     // no error detected, let's parse the request
-    compression_type compression_type(no_compression);
-    osrm::tribool result;
+    http::compression_type compression_type(http::no_compression);
+    RequestParser::RequestStatus result;
     std::tie(result, compression_type) =
         request_parser.parse(current_request, incoming_data_buffer.data(),
                              incoming_data_buffer.data() + bytes_transferred);
 
     // the request has been parsed
-    if (result == osrm::tribool::yes)
+    if (result == RequestParser::RequestStatus::valid)
     {
         current_request.endpoint = TCP_socket.remote_endpoint().address();
-        request_handler.handle_request(current_request, current_reply);
-
-        // Header compression_header;
-        std::vector<boost::asio::const_buffer> output_buffer;
+        request_handler.HandleRequest(current_request, current_reply);
 
         // compress the result w/ gzip/deflate if requested
         switch (compression_type)
         {
-        case deflate_rfc1951:
+        case http::deflate_rfc1951:
             // use deflate for compression
             current_reply.headers.insert(current_reply.headers.begin(),
                                          {"Content-Encoding", "deflate"});
@@ -92,7 +64,7 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
             output_buffer = current_reply.headers_to_buffers();
             output_buffer.push_back(boost::asio::buffer(compressed_output));
             break;
-        case gzip_rfc1952:
+        case http::gzip_rfc1952:
             // use gzip for compression
             current_reply.headers.insert(current_reply.headers.begin(),
                                          {"Content-Encoding", "gzip"});
@@ -101,7 +73,7 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
             output_buffer = current_reply.headers_to_buffers();
             output_buffer.push_back(boost::asio::buffer(compressed_output));
             break;
-        case no_compression:
+        case http::no_compression:
             // don't use any compression
             current_reply.set_uncompressed_size();
             output_buffer = current_reply.to_buffers();
@@ -113,9 +85,9 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
             strand.wrap(boost::bind(&Connection::handle_write, this->shared_from_this(),
                                     boost::asio::placeholders::error)));
     }
-    else if (result == osrm::tribool::no)
+    else if (result == RequestParser::RequestStatus::invalid)
     { // request is not parseable
-        current_reply = reply::stock_reply(reply::bad_request);
+        current_reply = http::reply::stock_reply(http::reply::bad_request);
 
         boost::asio::async_write(
             TCP_socket, current_reply.to_buffers(),
@@ -145,14 +117,14 @@ void Connection::handle_write(const boost::system::error_code &error)
 }
 
 std::vector<char> Connection::compress_buffers(const std::vector<char> &uncompressed_data,
-                                               const compression_type compression_type)
+                                               const http::compression_type compression_type)
 {
     boost::iostreams::gzip_params compression_parameters;
 
     // there's a trade-off between speed and size. speed wins
     compression_parameters.level = boost::iostreams::zlib::best_speed;
     // check which compression flavor is used
-    if (deflate_rfc1951 == compression_type)
+    if (http::deflate_rfc1951 == compression_type)
     {
         compression_parameters.noheader = true;
     }
@@ -168,3 +140,4 @@ std::vector<char> Connection::compress_buffers(const std::vector<char> &uncompre
     return compressed_data;
 }
 }
+}
diff --git a/server/http/reply.cpp b/src/server/http/reply.cpp
similarity index 66%
rename from server/http/reply.cpp
rename to src/server/http/reply.cpp
index a3d3d96..d279417 100644
--- a/server/http/reply.cpp
+++ b/src/server/http/reply.cpp
@@ -1,41 +1,18 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "reply.hpp"
+#include "server/http/reply.hpp"
 
 #include <string>
 
+namespace osrm
+{
+namespace server
+{
 namespace http
 {
 
 const char ok_html[] = "";
-const char bad_request_html[] = "{\"status\": 400,\"status_message\":\"Bad Request\"}";
+const char bad_request_html[] = "";
 const char internal_server_error_html[] =
-    "{\"status\": 500,\"status_message\":\"Internal Server Error\"}";
+    "{\"code\": \"InternalError\",\"message\":\"Internal Server Error\"}";
 const char seperators[] = {':', ' '};
 const char crlf[] = {'\r', '\n'};
 const std::string http_ok_string = "HTTP/1.0 200 OK\r\n";
@@ -126,5 +103,11 @@ boost::asio::const_buffer reply::status_to_buffer(const reply::status_type statu
     return boost::asio::buffer(http_bad_request_string);
 }
 
-reply::reply() : status(ok) {}
+reply::reply() : status(ok)
+{
+    // We do not currently support keep alive. Always set 'Connection: close'.
+    headers.emplace_back("Connection", "close");
+}
+}
+}
 }
diff --git a/src/server/request_handler.cpp b/src/server/request_handler.cpp
new file mode 100644
index 0000000..888a92b
--- /dev/null
+++ b/src/server/request_handler.cpp
@@ -0,0 +1,151 @@
+#include "server/request_handler.hpp"
+#include "server/service_handler.hpp"
+
+#include "server/api/url_parser.hpp"
+#include "server/http/reply.hpp"
+#include "server/http/request.hpp"
+
+#include "util/json_renderer.hpp"
+#include "util/simple_logger.hpp"
+#include "util/string_util.hpp"
+#include "util/typedefs.hpp"
+
+#include "engine/status.hpp"
+#include "util/json_container.hpp"
+#include "osrm/osrm.hpp"
+
+#include <boost/iostreams/filtering_streambuf.hpp>
+#include <boost/iostreams/copy.hpp>
+#include <boost/iostreams/filter/gzip.hpp>
+
+#include <ctime>
+
+#include <algorithm>
+#include <iostream>
+#include <string>
+
+namespace osrm
+{
+namespace server
+{
+
+void RequestHandler::RegisterServiceHandler(std::unique_ptr<ServiceHandler> service_handler_)
+{
+    service_handler = std::move(service_handler_);
+}
+
+void RequestHandler::HandleRequest(const http::request &current_request, http::reply &current_reply)
+{
+    if (!service_handler)
+    {
+        current_reply = http::reply::stock_reply(http::reply::internal_server_error);
+        util::SimpleLogger().Write(logWARNING) << "No service handler registered." << std::endl;
+        return;
+    }
+
+    // parse command
+    try
+    {
+        std::string request_string;
+        util::URIDecode(current_request.uri, request_string);
+
+        // deactivated as GCC apparently does not implement that, not even in 4.9
+        // std::time_t t = std::time(nullptr);
+        // util::SimpleLogger().Write() << std::put_time(std::localtime(&t), "%m-%d-%Y %H:%M:%S") <<
+        //     " " << current_request.endpoint.to_string() << " " <<
+        //     current_request.referrer << ( 0 == current_request.referrer.length() ? "- " :" ") <<
+        //     current_request.agent << ( 0 == current_request.agent.length() ? "- " :" ") <<
+        //     request;
+
+        time_t ltime;
+        struct tm *time_stamp;
+
+        ltime = time(nullptr);
+        time_stamp = localtime(&ltime);
+
+        // log timestamp
+        util::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 << " " << current_request.endpoint.to_string() << " "
+            << current_request.referrer << (0 == current_request.referrer.length() ? "- " : " ")
+            << current_request.agent << (0 == current_request.agent.length() ? "- " : " ")
+            << request_string;
+
+        auto api_iterator = request_string.begin();
+        auto maybe_parsed_url = api::parseURL(api_iterator, request_string.end());
+        ;
+        ServiceHandler::ResultT result;
+
+        // check if the was an error with the request
+        if (maybe_parsed_url && api_iterator == request_string.end())
+        {
+
+            const engine::Status status =
+                service_handler->RunQuery(std::move(*maybe_parsed_url), result);
+            if (status != engine::Status::Ok)
+            {
+                // 4xx bad request return code
+                current_reply.status = http::reply::bad_request;
+            }
+            else
+            {
+                BOOST_ASSERT(status == engine::Status::Ok);
+            }
+        }
+        else
+        {
+            const auto position = std::distance(request_string.begin(), api_iterator);
+            BOOST_ASSERT(position >= 0);
+            const auto context_begin = request_string.begin() + ((position < 3) ? 0 : (position - 3UL));
+            BOOST_ASSERT(context_begin >= request_string.begin());
+            const auto context_end =
+                request_string.begin() + std::min(position + 3UL, request_string.size());
+            BOOST_ASSERT(context_end <= request_string.end());
+            std::string context(context_begin, context_end);
+
+            current_reply.status = http::reply::bad_request;
+            result = util::json::Object();
+            auto &json_result = result.get<util::json::Object>();
+            json_result.values["code"] = "InvalidUrl";
+            json_result.values["message"] = "URL string malformed close to position " +
+                                            std::to_string(position) + ": \"" + context + "\"";
+        }
+
+        current_reply.headers.emplace_back("Access-Control-Allow-Origin", "*");
+        current_reply.headers.emplace_back("Access-Control-Allow-Methods", "GET");
+        current_reply.headers.emplace_back("Access-Control-Allow-Headers",
+                                           "X-Requested-With, Content-Type");
+        if (result.is<util::json::Object>())
+        {
+            current_reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8");
+            current_reply.headers.emplace_back("Content-Disposition",
+                                               "inline; filename=\"response.json\"");
+
+            util::json::render(current_reply.content, result.get<util::json::Object>());
+        }
+        else
+        {
+            BOOST_ASSERT(result.is<std::string>());
+            std::copy(result.get<std::string>().cbegin(), result.get<std::string>().cend(),
+                      std::back_inserter(current_reply.content));
+
+            current_reply.headers.emplace_back("Content-Type", "application/x-protobuf");
+        }
+
+        // set headers
+        current_reply.headers.emplace_back("Content-Length",
+                                           std::to_string(current_reply.content.size()));
+    }
+    catch (const std::exception &e)
+    {
+        current_reply = http::reply::stock_reply(http::reply::internal_server_error);
+        util::SimpleLogger().Write(logWARNING) << "[server error] code: " << e.what()
+                                               << ", uri: " << current_request.uri;
+    }
+}
+}
+}
diff --git a/src/server/request_parser.cpp b/src/server/request_parser.cpp
new file mode 100644
index 0000000..e408a79
--- /dev/null
+++ b/src/server/request_parser.cpp
@@ -0,0 +1,299 @@
+#include "server/request_parser.hpp"
+
+#include "server/http/compression_type.hpp"
+#include "server/http/header.hpp"
+#include "server/http/request.hpp"
+
+#include <boost/algorithm/string/predicate.hpp>
+
+#include <string>
+
+namespace osrm
+{
+namespace server
+{
+
+RequestParser::RequestParser()
+    : state(internal_state::method_start), current_header({"", ""}),
+      selected_compression(http::no_compression)
+{
+}
+
+std::tuple<RequestParser::RequestStatus, http::compression_type>
+RequestParser::parse(http::request &current_request, char *begin, char *end)
+{
+    while (begin != end)
+    {
+        RequestStatus result = consume(current_request, *begin++);
+        if (result != RequestStatus::indeterminate)
+        {
+            return std::make_tuple(result, selected_compression);
+        }
+    }
+    RequestStatus result = RequestStatus::indeterminate;
+
+    return std::make_tuple(result, selected_compression);
+}
+
+RequestParser::RequestStatus RequestParser::consume(http::request &current_request,
+                                                    const char input)
+{
+    switch (state)
+    {
+    case internal_state::method_start:
+        if (!is_char(input) || is_CTL(input) || is_special(input))
+        {
+            return RequestStatus::invalid;
+        }
+        state = internal_state::method;
+        return RequestStatus::indeterminate;
+    case internal_state::method:
+        if (input == ' ')
+        {
+            state = internal_state::uri;
+            return RequestStatus::indeterminate;
+        }
+        if (!is_char(input) || is_CTL(input) || is_special(input))
+        {
+            return RequestStatus::invalid;
+        }
+        return RequestStatus::indeterminate;
+    case internal_state::uri_start:
+        if (is_CTL(input))
+        {
+            return RequestStatus::invalid;
+        }
+        state = internal_state::uri;
+        current_request.uri.push_back(input);
+        return RequestStatus::indeterminate;
+    case internal_state::uri:
+        if (input == ' ')
+        {
+            state = internal_state::http_version_h;
+            return RequestStatus::indeterminate;
+        }
+        if (is_CTL(input))
+        {
+            return RequestStatus::invalid;
+        }
+        current_request.uri.push_back(input);
+        return RequestStatus::indeterminate;
+    case internal_state::http_version_h:
+        if (input == 'H')
+        {
+            state = internal_state::http_version_t_1;
+            return RequestStatus::indeterminate;
+        }
+        return RequestStatus::invalid;
+    case internal_state::http_version_t_1:
+        if (input == 'T')
+        {
+            state = internal_state::http_version_t_2;
+            return RequestStatus::indeterminate;
+        }
+        return RequestStatus::invalid;
+    case internal_state::http_version_t_2:
+        if (input == 'T')
+        {
+            state = internal_state::http_version_p;
+            return RequestStatus::indeterminate;
+        }
+        return RequestStatus::invalid;
+    case internal_state::http_version_p:
+        if (input == 'P')
+        {
+            state = internal_state::http_version_slash;
+            return RequestStatus::indeterminate;
+        }
+        return RequestStatus::invalid;
+    case internal_state::http_version_slash:
+        if (input == '/')
+        {
+            state = internal_state::http_version_major_start;
+            return RequestStatus::indeterminate;
+        }
+        return RequestStatus::invalid;
+    case internal_state::http_version_major_start:
+        if (is_digit(input))
+        {
+            state = internal_state::http_version_major;
+            return RequestStatus::indeterminate;
+        }
+        return RequestStatus::invalid;
+    case internal_state::http_version_major:
+        if (input == '.')
+        {
+            state = internal_state::http_version_minor_start;
+            return RequestStatus::indeterminate;
+        }
+        if (is_digit(input))
+        {
+            return RequestStatus::indeterminate;
+        }
+        return RequestStatus::invalid;
+    case internal_state::http_version_minor_start:
+        if (is_digit(input))
+        {
+            state = internal_state::http_version_minor;
+            return RequestStatus::indeterminate;
+        }
+        return RequestStatus::invalid;
+    case internal_state::http_version_minor:
+        if (input == '\r')
+        {
+            state = internal_state::expecting_newline_1;
+            return RequestStatus::indeterminate;
+        }
+        if (is_digit(input))
+        {
+            return RequestStatus::indeterminate;
+        }
+        return RequestStatus::invalid;
+    case internal_state::expecting_newline_1:
+        if (input == '\n')
+        {
+            state = internal_state::header_line_start;
+            return RequestStatus::indeterminate;
+        }
+        return RequestStatus::invalid;
+    case internal_state::header_line_start:
+        if (boost::iequals(current_header.name, "Accept-Encoding"))
+        {
+            /* giving gzip precedence over deflate */
+            if (boost::icontains(current_header.value, "deflate"))
+            {
+                selected_compression = http::deflate_rfc1951;
+            }
+            if (boost::icontains(current_header.value, "gzip"))
+            {
+                selected_compression = http::gzip_rfc1952;
+            }
+        }
+
+        if (boost::iequals(current_header.name, "Referer"))
+        {
+            current_request.referrer = current_header.value;
+        }
+
+        if (boost::iequals(current_header.name, "User-Agent"))
+        {
+            current_request.agent = current_header.value;
+        }
+
+        if (input == '\r')
+        {
+            state = internal_state::expecting_newline_3;
+            return RequestStatus::indeterminate;
+        }
+        if (!is_char(input) || is_CTL(input) || is_special(input))
+        {
+            return RequestStatus::invalid;
+        }
+        state = internal_state::header_name;
+        current_header.clear();
+        current_header.name.push_back(input);
+        return RequestStatus::indeterminate;
+    case internal_state::header_lws:
+        if (input == '\r')
+        {
+            state = internal_state::expecting_newline_2;
+            return RequestStatus::indeterminate;
+        }
+        if (input == ' ' || input == '\t')
+        {
+            return RequestStatus::indeterminate;
+        }
+        if (is_CTL(input))
+        {
+            return RequestStatus::invalid;
+        }
+        state = internal_state::header_value;
+        return RequestStatus::indeterminate;
+    case internal_state::header_name:
+        if (input == ':')
+        {
+            state = internal_state::space_before_header_value;
+            return RequestStatus::indeterminate;
+        }
+        if (!is_char(input) || is_CTL(input) || is_special(input))
+        {
+            return RequestStatus::invalid;
+        }
+        current_header.name.push_back(input);
+        return RequestStatus::indeterminate;
+    case internal_state::space_before_header_value:
+        if (input == ' ')
+        {
+            state = internal_state::header_value;
+            return RequestStatus::indeterminate;
+        }
+        return RequestStatus::invalid;
+    case internal_state::header_value:
+        if (input == '\r')
+        {
+            state = internal_state::expecting_newline_2;
+            return RequestStatus::indeterminate;
+        }
+        if (is_CTL(input))
+        {
+            return RequestStatus::invalid;
+        }
+        current_header.value.push_back(input);
+        return RequestStatus::indeterminate;
+    case internal_state::expecting_newline_2:
+        if (input == '\n')
+        {
+            state = internal_state::header_line_start;
+            return RequestStatus::indeterminate;
+        }
+        return RequestStatus::invalid;
+    default: // expecting_newline_3
+        return input == '\n' ? RequestStatus::valid : RequestStatus::invalid;
+    }
+}
+
+bool RequestParser::is_char(const int character) const
+{
+    return character >= 0 && character <= 127;
+}
+
+bool RequestParser::is_CTL(const int character) const
+{
+    return (character >= 0 && character <= 31) || (character == 127);
+}
+
+bool RequestParser::is_special(const int character) const
+{
+    switch (character)
+    {
+    case '(':
+    case ')':
+    case '<':
+    case '>':
+    case '@':
+    case ',':
+    case ';':
+    case ':':
+    case '\\':
+    case '"':
+    case '/':
+    case '[':
+    case ']':
+    case '?':
+    case '=':
+    case '{':
+    case '}':
+    case ' ':
+    case '\t':
+        return true;
+    default:
+        return false;
+    }
+}
+
+bool RequestParser::is_digit(const int character) const
+{
+    return character >= '0' && character <= '9';
+}
+}
+}
diff --git a/src/server/service/match_service.cpp b/src/server/service/match_service.cpp
new file mode 100644
index 0000000..dec8006
--- /dev/null
+++ b/src/server/service/match_service.cpp
@@ -0,0 +1,73 @@
+#include "server/service/match_service.hpp"
+
+#include "engine/api/match_parameters.hpp"
+#include "server/api/parameters_parser.hpp"
+#include "server/service/utils.hpp"
+
+#include "util/json_container.hpp"
+
+#include <boost/format.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+namespace
+{
+std::string getWrongOptionHelp(const engine::api::MatchParameters &parameters)
+{
+    std::string help;
+
+    const auto coord_size = parameters.coordinates.size();
+
+    const bool param_size_mismatch = constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "hints",
+                                                        parameters.hints, coord_size, help) ||
+                                     constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "bearings",
+                                                        parameters.bearings, coord_size, help) ||
+                                     constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "radiuses",
+                                                        parameters.radiuses, coord_size, help) ||
+                                     constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "timestamps",
+                                                        parameters.timestamps, coord_size, help);
+
+    if (!param_size_mismatch && parameters.coordinates.size() < 2)
+    {
+        help = "Number of coordinates needs to be at least two.";
+    }
+
+    return help;
+}
+} // anon. ns
+
+engine::Status MatchService::RunQuery(std::string &query, ResultT &result)
+{
+    result = util::json::Object();
+    auto &json_result = result.get<util::json::Object>();
+
+    auto query_iterator = query.begin();
+    auto parameters =
+        api::parseParameters<engine::api::MatchParameters>(query_iterator, query.end());
+    if (!parameters || query_iterator != query.end())
+    {
+        const auto position = std::distance(query.begin(), query_iterator);
+        json_result.values["code"] = "InvalidQuery";
+        json_result.values["message"] =
+            "Query string malformed close to position " + std::to_string(position);
+        return engine::Status::Error;
+    }
+
+    BOOST_ASSERT(parameters);
+    if (!parameters->IsValid())
+    {
+        json_result.values["code"] = "InvalidOptions";
+        json_result.values["message"] = getWrongOptionHelp(*parameters);
+        return engine::Status::Error;
+    }
+    BOOST_ASSERT(parameters->IsValid());
+
+    return BaseService::routing_machine.Match(*parameters, json_result);
+}
+}
+}
+}
diff --git a/src/server/service/nearest_service.cpp b/src/server/service/nearest_service.cpp
new file mode 100644
index 0000000..1ea1fa8
--- /dev/null
+++ b/src/server/service/nearest_service.cpp
@@ -0,0 +1,72 @@
+#include "server/service/nearest_service.hpp"
+#include "server/service/utils.hpp"
+
+#include "engine/api/nearest_parameters.hpp"
+#include "server/api/parameters_parser.hpp"
+
+#include "util/json_container.hpp"
+
+#include <boost/format.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+namespace
+{
+std::string getWrongOptionHelp(const engine::api::NearestParameters &parameters)
+{
+    std::string help;
+
+    const auto coord_size = parameters.coordinates.size();
+
+    const bool param_size_mismatch = constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "hints",
+                                                        parameters.hints, coord_size, help) ||
+                                     constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "bearings",
+                                                        parameters.bearings, coord_size, help) ||
+                                     constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "radiuses",
+                                                        parameters.radiuses, coord_size, help);
+
+    if (!param_size_mismatch && parameters.coordinates.size() < 2)
+    {
+        help = "Number of coordinates needs to be at least two.";
+    }
+
+    return help;
+}
+} // anon. ns
+
+engine::Status NearestService::RunQuery(std::string &query, ResultT &result)
+{
+    result = util::json::Object();
+    auto &json_result = result.get<util::json::Object>();
+
+    auto query_iterator = query.begin();
+    auto parameters =
+        api::parseParameters<engine::api::NearestParameters>(query_iterator, query.end());
+    if (!parameters || query_iterator != query.end())
+    {
+        const auto position = std::distance(query.begin(), query_iterator);
+        json_result.values["code"] = "InvalidQuery";
+        json_result.values["message"] =
+            "Query string malformed close to position " + std::to_string(position);
+        return engine::Status::Error;
+    }
+    BOOST_ASSERT(parameters);
+
+    if (!parameters->IsValid())
+    {
+        json_result.values["code"] = "InvalidOptions";
+        json_result.values["message"] = getWrongOptionHelp(*parameters);
+        return engine::Status::Error;
+    }
+    BOOST_ASSERT(parameters->IsValid());
+
+    return BaseService::routing_machine.Nearest(*parameters, json_result);
+}
+}
+}
+}
diff --git a/src/server/service/route_service.cpp b/src/server/service/route_service.cpp
new file mode 100644
index 0000000..f06cbdb
--- /dev/null
+++ b/src/server/service/route_service.cpp
@@ -0,0 +1,69 @@
+#include "server/service/route_service.hpp"
+#include "server/service/utils.hpp"
+
+#include "engine/api/route_parameters.hpp"
+#include "server/api/parameters_parser.hpp"
+
+#include "util/json_container.hpp"
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+namespace
+{
+std::string getWrongOptionHelp(const engine::api::RouteParameters &parameters)
+{
+    std::string help;
+
+    const auto coord_size = parameters.coordinates.size();
+
+    const bool param_size_mismatch = constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "hints",
+                                                        parameters.hints, coord_size, help) ||
+                                     constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "bearings",
+                                                        parameters.bearings, coord_size, help) ||
+                                     constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "radiuses",
+                                                        parameters.radiuses, coord_size, help);
+
+    if (!param_size_mismatch && parameters.coordinates.size() < 2)
+    {
+        help = "Number of coordinates needs to be at least two.";
+    }
+
+    return help;
+}
+} // anon. ns
+
+engine::Status RouteService::RunQuery(std::string &query, ResultT &result)
+{
+    result = util::json::Object();
+    auto &json_result = result.get<util::json::Object>();
+
+    auto query_iterator = query.begin();
+    auto parameters =
+        api::parseParameters<engine::api::RouteParameters>(query_iterator, query.end());
+    if (!parameters || query_iterator != query.end())
+    {
+        const auto position = std::distance(query.begin(), query_iterator);
+        json_result.values["code"] = "InvalidQuery";
+        json_result.values["message"] =
+            "Query string malformed close to position " + std::to_string(position);
+        return engine::Status::Error;
+    }
+    BOOST_ASSERT(parameters);
+
+    if (!parameters->IsValid())
+    {
+        json_result.values["code"] = "InvalidOptions";
+        json_result.values["message"] = getWrongOptionHelp(*parameters);
+        return engine::Status::Error;
+    }
+    BOOST_ASSERT(parameters->IsValid());
+
+    return BaseService::routing_machine.Route(*parameters, json_result);
+}
+}
+}
+}
diff --git a/src/server/service/table_service.cpp b/src/server/service/table_service.cpp
new file mode 100644
index 0000000..9b0f817
--- /dev/null
+++ b/src/server/service/table_service.cpp
@@ -0,0 +1,90 @@
+#include "server/service/table_service.hpp"
+
+#include "engine/api/table_parameters.hpp"
+#include "server/api/parameters_parser.hpp"
+
+#include "util/json_container.hpp"
+
+#include <boost/format.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+namespace
+{
+
+const constexpr char PARAMETER_SIZE_MISMATCH_MSG[] =
+    "Number of elements in %1% size %2% does not match coordinate size %3%";
+
+template <typename ParamT>
+bool constrainParamSize(const char *msg_template,
+                        const char *name,
+                        const ParamT &param,
+                        const std::size_t target_size,
+                        std::string &help)
+{
+    if (param.size() > 0 && param.size() != target_size)
+    {
+        help = (boost::format(msg_template) % name % param.size() % target_size).str();
+        return true;
+    }
+    return false;
+}
+
+std::string getWrongOptionHelp(const engine::api::TableParameters &parameters)
+{
+    std::string help;
+
+    const auto coord_size = parameters.coordinates.size();
+
+    const bool param_size_mismatch = constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "hints",
+                                                        parameters.hints, coord_size, help) ||
+                                     constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "bearings",
+                                                        parameters.bearings, coord_size, help) ||
+                                     constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "radiuses",
+                                                        parameters.radiuses, coord_size, help);
+
+    if (!param_size_mismatch && parameters.coordinates.size() < 2)
+    {
+        help = "Number of coordinates needs to be at least two.";
+    }
+
+    return help;
+}
+} // anon. ns
+
+engine::Status TableService::RunQuery(std::string &query, ResultT &result)
+{
+    result = util::json::Object();
+    auto &json_result = result.get<util::json::Object>();
+
+    auto query_iterator = query.begin();
+    auto parameters =
+        api::parseParameters<engine::api::TableParameters>(query_iterator, query.end());
+    if (!parameters || query_iterator != query.end())
+    {
+        const auto position = std::distance(query.begin(), query_iterator);
+        json_result.values["code"] = "InvalidQuery";
+        json_result.values["message"] =
+            "Query string malformed close to position " + std::to_string(position);
+        return engine::Status::Error;
+    }
+    BOOST_ASSERT(parameters);
+
+    if (!parameters->IsValid())
+    {
+        json_result.values["code"] = "InvalidOptions";
+        json_result.values["message"] = getWrongOptionHelp(*parameters);
+        return engine::Status::Error;
+    }
+    BOOST_ASSERT(parameters->IsValid());
+
+    return BaseService::routing_machine.Table(*parameters, json_result);
+}
+}
+}
+}
diff --git a/src/server/service/tile_service.cpp b/src/server/service/tile_service.cpp
new file mode 100644
index 0000000..d8f1ba8
--- /dev/null
+++ b/src/server/service/tile_service.cpp
@@ -0,0 +1,51 @@
+#include "server/service/tile_service.hpp"
+#include "server/service/utils.hpp"
+
+#include "engine/api/tile_parameters.hpp"
+#include "server/api/parameters_parser.hpp"
+
+#include "util/json_container.hpp"
+
+#include <boost/format.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+engine::Status TileService::RunQuery(std::string &query, ResultT &result)
+{
+    auto query_iterator = query.begin();
+    auto parameters =
+        api::parseParameters<engine::api::TileParameters>(query_iterator, query.end());
+    if (!parameters || query_iterator != query.end())
+    {
+        const auto position = std::distance(query.begin(), query_iterator);
+        result = util::json::Object();
+        auto &json_result = result.get<util::json::Object>();
+        json_result.values["code"] = "InvalidQuery";
+        json_result.values["message"] =
+            "Query string malformed close to position " + std::to_string(position);
+        return engine::Status::Error;
+    }
+    BOOST_ASSERT(parameters);
+
+    if (!parameters->IsValid())
+    {
+        result = util::json::Object();
+        auto &json_result = result.get<util::json::Object>();
+        json_result.values["code"] = "InvalidOptions";
+        json_result.values["message"] = "Invalid coodinates. Only zoomlevel 12+ is supported";
+        return engine::Status::Error;
+    }
+    BOOST_ASSERT(parameters->IsValid());
+
+    result = std::string();
+    auto &string_result = result.get<std::string>();
+    return BaseService::routing_machine.Tile(*parameters, string_result);
+}
+}
+}
+}
diff --git a/src/server/service/trip_service.cpp b/src/server/service/trip_service.cpp
new file mode 100644
index 0000000..82a1bfd
--- /dev/null
+++ b/src/server/service/trip_service.cpp
@@ -0,0 +1,73 @@
+#include "server/service/trip_service.hpp"
+#include "server/service/utils.hpp"
+
+#include "engine/api/trip_parameters.hpp"
+#include "server/api/parameters_parser.hpp"
+
+#include "util/json_container.hpp"
+
+#include <boost/format.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+namespace
+{
+std::string getWrongOptionHelp(const engine::api::TripParameters &parameters)
+{
+    std::string help;
+
+    const auto coord_size = parameters.coordinates.size();
+
+    const bool param_size_mismatch = constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "hints",
+                                                        parameters.hints, coord_size, help) ||
+                                     constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "bearings",
+                                                        parameters.bearings, coord_size, help) ||
+                                     constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "radiuses",
+                                                        parameters.radiuses, coord_size, help);
+
+    if (!param_size_mismatch && parameters.coordinates.size() < 2)
+    {
+        help = "Number of coordinates needs to be at least two.";
+    }
+
+    return help;
+}
+} // anon. ns
+
+engine::Status TripService::RunQuery(std::string &query, ResultT &result)
+{
+    result = util::json::Object();
+    auto &json_result = result.get<util::json::Object>();
+
+    auto query_iterator = query.begin();
+    auto parameters =
+        api::parseParameters<engine::api::TripParameters>(query_iterator, query.end());
+    if (!parameters || query_iterator != query.end())
+    {
+        const auto position = std::distance(query.begin(), query_iterator);
+        result = util::json::Object();
+        auto &json_result = result.get<util::json::Object>();
+        json_result.values["code"] = "InvalidQuery";
+        json_result.values["message"] =
+            "Query string malformed close to position " + std::to_string(position);
+        return engine::Status::Error;
+    }
+    BOOST_ASSERT(parameters);
+
+    if (!parameters->IsValid())
+    {
+        json_result.values["code"] = "InvalidOptions";
+        json_result.values["message"] = getWrongOptionHelp(*parameters);
+        return engine::Status::Error;
+    }
+    BOOST_ASSERT(parameters->IsValid());
+
+    return BaseService::routing_machine.Trip(*parameters, json_result);
+}
+}
+}
+}
diff --git a/src/server/service_handler.cpp b/src/server/service_handler.cpp
new file mode 100644
index 0000000..98ba6a6
--- /dev/null
+++ b/src/server/service_handler.cpp
@@ -0,0 +1,54 @@
+#include "server/service_handler.hpp"
+
+#include "server/service/route_service.hpp"
+#include "server/service/table_service.hpp"
+#include "server/service/nearest_service.hpp"
+#include "server/service/trip_service.hpp"
+#include "server/service/match_service.hpp"
+#include "server/service/tile_service.hpp"
+
+#include "server/api/parsed_url.hpp"
+#include "util/json_util.hpp"
+#include "util/make_unique.hpp"
+
+namespace osrm
+{
+namespace server
+{
+ServiceHandler::ServiceHandler(osrm::EngineConfig &config) : routing_machine(config)
+{
+    service_map["route"] = util::make_unique<service::RouteService>(routing_machine);
+    service_map["table"] = util::make_unique<service::TableService>(routing_machine);
+    service_map["nearest"] = util::make_unique<service::NearestService>(routing_machine);
+    service_map["trip"] = util::make_unique<service::TripService>(routing_machine);
+    service_map["match"] = util::make_unique<service::MatchService>(routing_machine);
+    service_map["tile"] = util::make_unique<service::TileService>(routing_machine);
+}
+
+engine::Status ServiceHandler::RunQuery(api::ParsedURL parsed_url,
+                                        service::BaseService::ResultT &result)
+{
+    const auto &service_iter = service_map.find(parsed_url.service);
+    if (service_iter == service_map.end())
+    {
+        result = util::json::Object();
+        auto &json_result = result.get<util::json::Object>();
+        json_result.values["code"] = "InvalidService";
+        json_result.values["message"] = "Service " + parsed_url.service + " not found!";
+        return engine::Status::Error;
+    }
+    auto &service = service_iter->second;
+
+    if (service->GetVersion() != parsed_url.version)
+    {
+        result = util::json::Object();
+        auto &json_result = result.get<util::json::Object>();
+        json_result.values["code"] = "InvalidVersion";
+        json_result.values["message"] = "Service " + parsed_url.service + " not found!";
+        return engine::Status::Error;
+    }
+
+    return service->RunQuery(parsed_url.query, result);
+}
+}
+}
diff --git a/datastore.cpp b/src/storage/storage.cpp
similarity index 53%
rename from datastore.cpp
rename to src/storage/storage.cpp
index 504dd3d..862ca3c 100644
--- a/datastore.cpp
+++ b/src/storage/storage.cpp
@@ -1,54 +1,24 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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/range_table.hpp"
-#include "data_structures/query_edge.hpp"
-#include "data_structures/query_node.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/travel_mode.hpp"
-#include "data_structures/turn_instructions.hpp"
-#include "server/data_structures/datafacade_base.hpp"
-#include "server/data_structures/shared_datatype.hpp"
-#include "server/data_structures/shared_barriers.hpp"
-#include "util/datastore_options.hpp"
-#include "util/simple_logger.hpp"
-#include "util/osrm_exception.hpp"
+#include "extractor/original_edge_data.hpp"
+#include "util/range_table.hpp"
+#include "contractor/query_edge.hpp"
+#include "extractor/query_node.hpp"
+#include "extractor/profile_properties.hpp"
+#include "extractor/compressed_edge_container.hpp"
+#include "util/shared_memory_vector_wrapper.hpp"
+#include "util/static_graph.hpp"
+#include "util/static_rtree.hpp"
+#include "engine/datafacade/datafacade_base.hpp"
+#include "extractor/travel_mode.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+#include "storage/storage.hpp"
+#include "storage/shared_datatype.hpp"
+#include "storage/shared_barriers.hpp"
+#include "storage/shared_memory.hpp"
 #include "util/fingerprint.hpp"
-#include "typedefs.h"
-
-#include <osrm/coordinate.hpp>
-
-using RTreeLeaf = BaseDataFacade<QueryEdge::EdgeData>::RTreeLeaf;
-using RTreeNode = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>::TreeNode;
-using QueryGraph = StaticGraph<QueryEdge::EdgeData>;
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+#include "util/typedefs.hpp"
+#include "util/coordinate.hpp"
 
 #ifdef __linux__
 #include <sys/mman.h>
@@ -60,11 +30,21 @@ using QueryGraph = StaticGraph<QueryEdge::EdgeData>;
 #include <cstdint>
 
 #include <fstream>
-#include <string>
 #include <new>
+#include <string>
+
+namespace osrm
+{
+namespace storage
+{
+
+using RTreeLeaf = typename engine::datafacade::BaseDataFacade::RTreeLeaf;
+using RTreeNode =
+    util::StaticRTree<RTreeLeaf, util::ShM<util::Coordinate, true>::vector, true>::TreeNode;
+using QueryGraph = util::StaticGraph<contractor::QueryEdge::EdgeData>;
 
 // delete a shared memory region. report warning if it could not be deleted
-void delete_region(const SharedDataType region)
+void deleteRegion(const SharedDataType region)
 {
     if (SharedMemory::RegionExists(region) && !SharedMemory::Remove(region))
     {
@@ -89,13 +69,17 @@ void delete_region(const SharedDataType region)
             }
         }();
 
-        SimpleLogger().Write(logWARNING) << "could not delete shared memory region " << name;
+        util::SimpleLogger().Write(logWARNING) << "could not delete shared memory region " << name;
     }
 }
 
-int main(const int argc, const char *argv[]) try
+Storage::Storage(StorageConfig config_) : config(std::move(config_)) {}
+
+int Storage::Run()
 {
-    LogPolicy::GetInstance().Unmute();
+    BOOST_ASSERT_MSG(config.IsValid(), "Invalid storage config");
+
+    util::LogPolicy::GetInstance().Unmute();
     SharedBarriers barrier;
 
 #ifdef __linux__
@@ -103,7 +87,7 @@ int main(const int argc, const char *argv[]) try
     const bool lock_flags = MCL_CURRENT | MCL_FUTURE;
     if (-1 == mlockall(lock_flags))
     {
-        SimpleLogger().Write(logWARNING) << "Process " << argv[0] << " could not request RAM lock";
+        util::SimpleLogger().Write(logWARNING) << "Could not request RAM lock";
     }
 #endif
 
@@ -118,122 +102,47 @@ int main(const int argc, const char *argv[]) try
         barrier.pending_update_mutex.unlock();
     }
 
-    SimpleLogger().Write(logDEBUG) << "Checking input parameters";
-
-    std::unordered_map<std::string, boost::filesystem::path> server_paths;
-    if (!GenerateDataStoreOptions(argc, argv, server_paths))
-    {
-        return EXIT_SUCCESS;
-    }
-
-    if (server_paths.find("hsgrdata") == server_paths.end())
-    {
-        throw osrm::exception("no hsgr file found");
-    }
-    if (server_paths.find("ramindex") == server_paths.end())
-    {
-        throw osrm::exception("no ram index file found");
-    }
-    if (server_paths.find("fileindex") == server_paths.end())
-    {
-        throw osrm::exception("no leaf index file found");
-    }
-    if (server_paths.find("nodesdata") == server_paths.end())
-    {
-        throw osrm::exception("no nodes file found");
-    }
-    if (server_paths.find("edgesdata") == server_paths.end())
-    {
-        throw osrm::exception("no edges file found");
-    }
-    if (server_paths.find("namesdata") == server_paths.end())
-    {
-        throw osrm::exception("no names file found");
-    }
-    if (server_paths.find("geometry") == server_paths.end())
-    {
-        throw osrm::exception("no geometry file found");
-    }
-    if (server_paths.find("core") == server_paths.end())
-    {
-        throw osrm::exception("no core file found");
-    }
-
-    auto paths_iterator = server_paths.find("hsgrdata");
-    BOOST_ASSERT(server_paths.end() != paths_iterator);
-    BOOST_ASSERT(!paths_iterator->second.empty());
-    const boost::filesystem::path &hsgr_path = paths_iterator->second;
-    paths_iterator = server_paths.find("timestamp");
-    BOOST_ASSERT(server_paths.end() != paths_iterator);
-    BOOST_ASSERT(!paths_iterator->second.empty());
-    const boost::filesystem::path &timestamp_path = paths_iterator->second;
-    paths_iterator = server_paths.find("ramindex");
-    BOOST_ASSERT(server_paths.end() != paths_iterator);
-    BOOST_ASSERT(!paths_iterator->second.empty());
-    const boost::filesystem::path &ram_index_path = paths_iterator->second;
-    paths_iterator = server_paths.find("fileindex");
-    BOOST_ASSERT(server_paths.end() != paths_iterator);
-    BOOST_ASSERT(!paths_iterator->second.empty());
-    const boost::filesystem::path index_file_path_absolute =
-        boost::filesystem::canonical(paths_iterator->second);
-    const std::string &file_index_path = index_file_path_absolute.string();
-    paths_iterator = server_paths.find("nodesdata");
-    BOOST_ASSERT(server_paths.end() != paths_iterator);
-    BOOST_ASSERT(!paths_iterator->second.empty());
-    const boost::filesystem::path &nodes_data_path = paths_iterator->second;
-    paths_iterator = server_paths.find("edgesdata");
-    BOOST_ASSERT(server_paths.end() != paths_iterator);
-    BOOST_ASSERT(!paths_iterator->second.empty());
-    const boost::filesystem::path &edges_data_path = paths_iterator->second;
-    paths_iterator = server_paths.find("namesdata");
-    BOOST_ASSERT(server_paths.end() != paths_iterator);
-    BOOST_ASSERT(!paths_iterator->second.empty());
-    const boost::filesystem::path &names_data_path = paths_iterator->second;
-    paths_iterator = server_paths.find("geometry");
-    BOOST_ASSERT(server_paths.end() != paths_iterator);
-    BOOST_ASSERT(!paths_iterator->second.empty());
-    const boost::filesystem::path &geometries_data_path = paths_iterator->second;
-    paths_iterator = server_paths.find("core");
-    BOOST_ASSERT(server_paths.end() != paths_iterator);
-    BOOST_ASSERT(!paths_iterator->second.empty());
-    const boost::filesystem::path &core_marker_path = paths_iterator->second;
-
     // determine segment to use
     bool segment2_in_use = SharedMemory::RegionExists(LAYOUT_2);
-    const SharedDataType layout_region = [&]
+    const storage::SharedDataType layout_region = [&]
     {
         return segment2_in_use ? LAYOUT_1 : LAYOUT_2;
     }();
-    const SharedDataType data_region = [&]
+    const storage::SharedDataType data_region = [&]
     {
         return segment2_in_use ? DATA_1 : DATA_2;
     }();
-    const SharedDataType previous_layout_region = [&]
+    const storage::SharedDataType previous_layout_region = [&]
     {
         return segment2_in_use ? LAYOUT_2 : LAYOUT_1;
     }();
-    const SharedDataType previous_data_region = [&]
+    const storage::SharedDataType previous_data_region = [&]
     {
         return segment2_in_use ? DATA_2 : DATA_1;
     }();
 
     // Allocate a memory layout in shared memory, deallocate previous
-    auto *layout_memory = SharedMemoryFactory::Get(layout_region, sizeof(SharedDataLayout));
-    auto *shared_layout_ptr = new (layout_memory->Ptr()) SharedDataLayout();
+    auto *layout_memory = makeSharedMemory(layout_region, sizeof(SharedDataLayout));
+    auto shared_layout_ptr = new (layout_memory->Ptr()) SharedDataLayout();
+    auto absolute_file_index_path = boost::filesystem::absolute(config.file_index_path);
 
     shared_layout_ptr->SetBlockSize<char>(SharedDataLayout::FILE_INDEX_PATH,
-                                          file_index_path.length() + 1);
+                                          absolute_file_index_path.string().length() + 1);
 
     // collect number of elements to store in shared memory object
-    SimpleLogger().Write() << "load names from: " << names_data_path;
+    util::SimpleLogger().Write() << "load names from: " << config.names_data_path;
     // number of entries in name index
-    boost::filesystem::ifstream name_stream(names_data_path, std::ios::binary);
+    boost::filesystem::ifstream name_stream(config.names_data_path, std::ios::binary);
+    if (!name_stream)
+    {
+        throw util::exception("Could not open " + config.names_data_path.string() + " for reading.");
+    }
     unsigned name_blocks = 0;
     name_stream.read((char *)&name_blocks, sizeof(unsigned));
     shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::NAME_OFFSETS, name_blocks);
-    shared_layout_ptr->SetBlockSize<typename RangeTable<16, true>::BlockT>(
+    shared_layout_ptr->SetBlockSize<typename util::RangeTable<16, true>::BlockT>(
         SharedDataLayout::NAME_BLOCKS, name_blocks);
-    SimpleLogger().Write() << "name offsets size: " << name_blocks;
+    util::SimpleLogger().Write() << "name offsets size: " << name_blocks;
     BOOST_ASSERT_MSG(0 != name_blocks, "name file broken");
 
     unsigned number_of_chars = 0;
@@ -241,7 +150,11 @@ int main(const int argc, const char *argv[]) try
     shared_layout_ptr->SetBlockSize<char>(SharedDataLayout::NAME_CHAR_LIST, number_of_chars);
 
     // Loading information for original edges
-    boost::filesystem::ifstream edges_input_stream(edges_data_path, std::ios::binary);
+    boost::filesystem::ifstream edges_input_stream(config.edges_data_path, std::ios::binary);
+    if (!edges_input_stream)
+    {
+        throw util::exception("Could not open " + config.edges_data_path.string() + " for reading.");
+    }
     unsigned number_of_original_edges = 0;
     edges_input_stream.read((char *)&number_of_original_edges, sizeof(unsigned));
 
@@ -250,27 +163,28 @@ int main(const int argc, const char *argv[]) try
                                             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
-    shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::GEOMETRIES_INDICATORS,
-                                              number_of_original_edges);
+    shared_layout_ptr->SetBlockSize<extractor::TravelMode>(SharedDataLayout::TRAVEL_MODE,
+                                                           number_of_original_edges);
+    shared_layout_ptr->SetBlockSize<extractor::guidance::TurnInstruction>(
+        SharedDataLayout::TURN_INSTRUCTION, number_of_original_edges);
 
-    boost::filesystem::ifstream hsgr_input_stream(hsgr_path, std::ios::binary);
+    boost::filesystem::ifstream hsgr_input_stream(config.hsgr_data_path, std::ios::binary);
+    if (!hsgr_input_stream)
+    {
+        throw util::exception("Could not open " + config.hsgr_data_path.string() + " for reading.");
+    }
 
-    FingerPrint fingerprint_valid = FingerPrint::GetValid();
-    FingerPrint fingerprint_loaded;
-    hsgr_input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
+    util::FingerPrint fingerprint_valid = util::FingerPrint::GetValid();
+    util::FingerPrint fingerprint_loaded;
+    hsgr_input_stream.read((char *)&fingerprint_loaded, sizeof(util::FingerPrint));
     if (fingerprint_loaded.TestGraphUtil(fingerprint_valid))
     {
-        SimpleLogger().Write(logDEBUG) << "Fingerprint checked out ok";
+        util::SimpleLogger().Write(logDEBUG) << "Fingerprint checked out ok";
     }
     else
     {
-        SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build. "
-                                            "Reprocess to get rid of this warning.";
+        util::SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build. "
+                                                  "Reprocess to get rid of this warning.";
     }
 
     // load checksum
@@ -293,39 +207,27 @@ int main(const int argc, const char *argv[]) try
                                                                 number_of_graph_edges);
 
     // load rsearch tree size
-    boost::filesystem::ifstream tree_node_file(ram_index_path, std::ios::binary);
+    boost::filesystem::ifstream tree_node_file(config.ram_index_path, std::ios::binary);
 
     uint32_t tree_size = 0;
     tree_node_file.read((char *)&tree_size, sizeof(uint32_t));
     shared_layout_ptr->SetBlockSize<RTreeNode>(SharedDataLayout::R_SEARCH_TREE, tree_size);
 
+    // load profile properties
+    shared_layout_ptr->SetBlockSize<extractor::ProfileProperties>(SharedDataLayout::PROPERTIES, 1);
+
     // load timestamp size
+    boost::filesystem::ifstream timestamp_stream(config.timestamp_path);
     std::string m_timestamp;
-    if (boost::filesystem::exists(timestamp_path))
-    {
-        boost::filesystem::ifstream timestamp_stream(timestamp_path);
-        if (!timestamp_stream)
-        {
-            SimpleLogger().Write(logWARNING) << timestamp_path << " not found. setting to default";
-        }
-        else
-        {
-            getline(timestamp_stream, m_timestamp);
-            timestamp_stream.close();
-        }
-    }
-    if (m_timestamp.empty())
-    {
-        m_timestamp = "n/a";
-    }
-    if (25 < m_timestamp.length())
-    {
-        m_timestamp.resize(25);
-    }
+    getline(timestamp_stream, m_timestamp);
     shared_layout_ptr->SetBlockSize<char>(SharedDataLayout::TIMESTAMP, m_timestamp.length());
 
     // load core marker size
-    boost::filesystem::ifstream core_marker_file(core_marker_path, std::ios::binary);
+    boost::filesystem::ifstream core_marker_file(config.core_data_path, std::ios::binary);
+    if (!core_marker_file)
+    {
+        throw util::exception("Could not open " + config.core_data_path.string() + " for reading.");
+    }
 
     uint32_t number_of_core_markers = 0;
     core_marker_file.read((char *)&number_of_core_markers, sizeof(uint32_t));
@@ -333,14 +235,22 @@ int main(const int argc, const char *argv[]) try
                                               number_of_core_markers);
 
     // load coordinate size
-    boost::filesystem::ifstream nodes_input_stream(nodes_data_path, std::ios::binary);
+    boost::filesystem::ifstream nodes_input_stream(config.nodes_data_path, std::ios::binary);
+    if (!nodes_input_stream)
+    {
+        throw util::exception("Could not open " + config.core_data_path.string() + " for reading.");
+    }
     unsigned coordinate_list_size = 0;
     nodes_input_stream.read((char *)&coordinate_list_size, sizeof(unsigned));
-    shared_layout_ptr->SetBlockSize<FixedPointCoordinate>(SharedDataLayout::COORDINATE_LIST,
-                                                          coordinate_list_size);
+    shared_layout_ptr->SetBlockSize<util::Coordinate>(SharedDataLayout::COORDINATE_LIST,
+                                                      coordinate_list_size);
 
     // load geometries sizes
-    std::ifstream geometry_input_stream(geometries_data_path.string().c_str(), std::ios::binary);
+    boost::filesystem::ifstream geometry_input_stream(config.geometries_path, std::ios::binary);
+    if (!geometry_input_stream)
+    {
+        throw util::exception("Could not open " + config.geometries_path.string() + " for reading.");
+    }
     unsigned number_of_geometries_indices = 0;
     unsigned number_of_compressed_geometries = 0;
 
@@ -350,13 +260,59 @@ int main(const int argc, const char *argv[]) try
     boost::iostreams::seek(geometry_input_stream, number_of_geometries_indices * sizeof(unsigned),
                            BOOST_IOS::cur);
     geometry_input_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
-    shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::GEOMETRIES_LIST,
-                                              number_of_compressed_geometries);
+    shared_layout_ptr->SetBlockSize<extractor::CompressedEdgeContainer::CompressedEdge>(
+        SharedDataLayout::GEOMETRIES_LIST, number_of_compressed_geometries);
+
+    // load datasource sizes.  This file is optional, and it's non-fatal if it doesn't
+    // exist.
+    boost::filesystem::ifstream geometry_datasource_input_stream(config.datasource_indexes_path,
+                                                                 std::ios::binary);
+    if (!geometry_datasource_input_stream)
+    {
+        throw util::exception("Could not open " + config.datasource_indexes_path.string() + " for reading.");
+    }
+    std::size_t number_of_compressed_datasources = 0;
+    if (geometry_datasource_input_stream)
+    {
+        geometry_datasource_input_stream.read(
+            reinterpret_cast<char *>(&number_of_compressed_datasources), sizeof(std::size_t));
+    }
+    shared_layout_ptr->SetBlockSize<uint8_t>(SharedDataLayout::DATASOURCES_LIST,
+                                             number_of_compressed_datasources);
+
+    // Load datasource name sizes.  This file is optional, and it's non-fatal if it doesn't
+    // exist
+    boost::filesystem::ifstream datasource_names_input_stream(config.datasource_names_path,
+                                                              std::ios::binary);
+    if (!datasource_names_input_stream)
+    {
+        throw util::exception("Could not open " + config.datasource_names_path.string() + " for reading.");
+    }
+    std::vector<char> m_datasource_name_data;
+    std::vector<std::size_t> m_datasource_name_offsets;
+    std::vector<std::size_t> m_datasource_name_lengths;
+    if (datasource_names_input_stream)
+    {
+        std::string name;
+        while (std::getline(datasource_names_input_stream, name))
+        {
+            m_datasource_name_offsets.push_back(m_datasource_name_data.size());
+            std::copy(name.c_str(), name.c_str() + name.size(),
+                      std::back_inserter(m_datasource_name_data));
+            m_datasource_name_lengths.push_back(name.size());
+        }
+    }
+    shared_layout_ptr->SetBlockSize<char>(SharedDataLayout::DATASOURCE_NAME_DATA,
+                                          m_datasource_name_data.size());
+    shared_layout_ptr->SetBlockSize<std::size_t>(SharedDataLayout::DATASOURCE_NAME_OFFSETS,
+                                                 m_datasource_name_offsets.size());
+    shared_layout_ptr->SetBlockSize<std::size_t>(SharedDataLayout::DATASOURCE_NAME_LENGTHS,
+                                                 m_datasource_name_lengths.size());
+
     // allocate shared memory block
-    SimpleLogger().Write() << "allocating shared memory of " << shared_layout_ptr->GetSizeOfLayout()
-                           << " bytes";
-    SharedMemory *shared_memory =
-        SharedMemoryFactory::Get(data_region, shared_layout_ptr->GetSizeOfLayout());
+    util::SimpleLogger().Write() << "allocating shared memory of "
+                                 << shared_layout_ptr->GetSizeOfLayout() << " bytes";
+    auto *shared_memory = makeSharedMemory(data_region, shared_layout_ptr->GetSizeOfLayout());
     char *shared_memory_ptr = static_cast<char *>(shared_memory->Ptr());
 
     // read actual data into shared memory object //
@@ -374,7 +330,7 @@ int main(const int argc, const char *argv[]) try
               file_index_path_ptr +
                   shared_layout_ptr->GetBlockSize(SharedDataLayout::FILE_INDEX_PATH),
               0);
-    std::copy(file_index_path.begin(), file_index_path.end(), file_index_path_ptr);
+    std::copy(absolute_file_index_path.string().begin(), absolute_file_index_path.string().end(), file_index_path_ptr);
 
     // Loading street names
     unsigned *name_offsets_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
@@ -417,39 +373,22 @@ int main(const int argc, const char *argv[]) try
     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);
+    extractor::TravelMode *travel_mode_ptr =
+        shared_layout_ptr->GetBlockPtr<extractor::TravelMode, true>(shared_memory_ptr,
+                                                                    SharedDataLayout::TRAVEL_MODE);
 
-    unsigned *geometries_indicator_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
-        shared_memory_ptr, SharedDataLayout::GEOMETRIES_INDICATORS);
+    extractor::guidance::TurnInstruction *turn_instructions_ptr =
+        shared_layout_ptr->GetBlockPtr<extractor::guidance::TurnInstruction, true>(
+            shared_memory_ptr, SharedDataLayout::TURN_INSTRUCTION);
 
-    OriginalEdgeData current_edge_data;
+    extractor::OriginalEdgeData current_edge_data;
     for (unsigned i = 0; i < number_of_original_edges; ++i)
     {
-        edges_input_stream.read((char *)&(current_edge_data), sizeof(OriginalEdgeData));
+        edges_input_stream.read((char *)&(current_edge_data), sizeof(extractor::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;
-        const unsigned offset = i % 32;
-        const unsigned value = [&]
-        {
-            unsigned return_value = 0;
-            if (0 != offset)
-            {
-                return_value = geometries_indicator_ptr[bucket];
-            }
-            return return_value;
-        }();
-        if (current_edge_data.compressed_geometry)
-        {
-            geometries_indicator_ptr[bucket] = (value | (1 << offset));
-        }
     }
     edges_input_stream.close();
 
@@ -468,8 +407,9 @@ int main(const int argc, const char *argv[]) try
             (char *)geometries_index_ptr,
             shared_layout_ptr->GetBlockSize(SharedDataLayout::GEOMETRIES_INDEX));
     }
-    unsigned *geometries_list_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
-        shared_memory_ptr, SharedDataLayout::GEOMETRIES_LIST);
+    extractor::CompressedEdgeContainer::CompressedEdge *geometries_list_ptr =
+        shared_layout_ptr->GetBlockPtr<extractor::CompressedEdgeContainer::CompressedEdge, true>(
+            shared_memory_ptr, SharedDataLayout::GEOMETRIES_LIST);
 
     geometry_input_stream.read((char *)&temporary_value, sizeof(unsigned));
     BOOST_ASSERT(temporary_value ==
@@ -482,16 +422,52 @@ int main(const int argc, const char *argv[]) try
             shared_layout_ptr->GetBlockSize(SharedDataLayout::GEOMETRIES_LIST));
     }
 
+    // load datasource information (if it exists)
+    uint8_t *datasources_list_ptr = shared_layout_ptr->GetBlockPtr<uint8_t, true>(
+        shared_memory_ptr, SharedDataLayout::DATASOURCES_LIST);
+    if (shared_layout_ptr->GetBlockSize(SharedDataLayout::DATASOURCES_LIST) > 0)
+    {
+        geometry_datasource_input_stream.read(
+            reinterpret_cast<char *>(datasources_list_ptr),
+            shared_layout_ptr->GetBlockSize(SharedDataLayout::DATASOURCES_LIST));
+    }
+
+    // load datasource name information (if it exists)
+    char *datasource_name_data_ptr = shared_layout_ptr->GetBlockPtr<char, true>(
+        shared_memory_ptr, SharedDataLayout::DATASOURCE_NAME_DATA);
+    if (shared_layout_ptr->GetBlockSize(SharedDataLayout::DATASOURCE_NAME_DATA) > 0)
+    {
+        std::cout << "Copying " << (m_datasource_name_data.end() - m_datasource_name_data.begin())
+                  << " chars into name data ptr\n";
+        std::copy(m_datasource_name_data.begin(), m_datasource_name_data.end(),
+                  datasource_name_data_ptr);
+    }
+
+    auto datasource_name_offsets_ptr = shared_layout_ptr->GetBlockPtr<std::size_t, true>(
+        shared_memory_ptr, SharedDataLayout::DATASOURCE_NAME_OFFSETS);
+    if (shared_layout_ptr->GetBlockSize(SharedDataLayout::DATASOURCE_NAME_OFFSETS) > 0)
+    {
+        std::copy(m_datasource_name_offsets.begin(), m_datasource_name_offsets.end(),
+                  datasource_name_offsets_ptr);
+    }
+
+    auto datasource_name_lengths_ptr = shared_layout_ptr->GetBlockPtr<std::size_t, true>(
+        shared_memory_ptr, SharedDataLayout::DATASOURCE_NAME_LENGTHS);
+    if (shared_layout_ptr->GetBlockSize(SharedDataLayout::DATASOURCE_NAME_LENGTHS) > 0)
+    {
+        std::copy(m_datasource_name_lengths.begin(), m_datasource_name_lengths.end(),
+                  datasource_name_lengths_ptr);
+    }
+
     // Loading list of coordinates
-    FixedPointCoordinate *coordinates_ptr =
-        shared_layout_ptr->GetBlockPtr<FixedPointCoordinate, true>(
-            shared_memory_ptr, SharedDataLayout::COORDINATE_LIST);
+    util::Coordinate *coordinates_ptr = shared_layout_ptr->GetBlockPtr<util::Coordinate, true>(
+        shared_memory_ptr, SharedDataLayout::COORDINATE_LIST);
 
-    QueryNode current_node;
+    extractor::QueryNode current_node;
     for (unsigned i = 0; i < coordinate_list_size; ++i)
     {
-        nodes_input_stream.read((char *)&current_node, sizeof(QueryNode));
-        coordinates_ptr[i] = FixedPointCoordinate(current_node.lat, current_node.lon);
+        nodes_input_stream.read((char *)&current_node, sizeof(extractor::QueryNode));
+        coordinates_ptr[i] = util::Coordinate(current_node.lon, current_node.lat);
     }
     nodes_input_stream.close();
 
@@ -536,7 +512,7 @@ int main(const int argc, const char *argv[]) try
                 return return_value;
             }();
 
-            core_marker_ptr[bucket] = (value | (1 << offset));
+            core_marker_ptr[bucket] = (value | (1u << offset));
         }
     }
 
@@ -561,9 +537,18 @@ int main(const int argc, const char *argv[]) try
     }
     hsgr_input_stream.close();
 
+    // load profile properties
+    auto profile_properties_ptr = shared_layout_ptr->GetBlockPtr<extractor::ProfileProperties, true>(shared_memory_ptr, SharedDataLayout::PROPERTIES);
+    boost::filesystem::ifstream profile_properties_stream(config.properties_path);
+    if (!profile_properties_stream)
+    {
+        util::exception("Could not open " + config.properties_path.string() + " for reading!");
+    }
+    profile_properties_stream.read(reinterpret_cast<char*>(profile_properties_ptr), sizeof(extractor::ProfileProperties));
+
     // acquire lock
     SharedMemory *data_type_memory =
-        SharedMemoryFactory::Get(CURRENT_REGIONS, sizeof(SharedDataTimestamp), true, false);
+        makeSharedMemory(CURRENT_REGIONS, sizeof(SharedDataTimestamp), true, false);
     SharedDataTimestamp *data_timestamp_ptr =
         static_cast<SharedDataTimestamp *>(data_type_memory->Ptr());
 
@@ -579,20 +564,11 @@ int main(const int argc, const char *argv[]) try
     data_timestamp_ptr->layout = layout_region;
     data_timestamp_ptr->data = data_region;
     data_timestamp_ptr->timestamp += 1;
-    delete_region(previous_data_region);
-    delete_region(previous_layout_region);
-    SimpleLogger().Write() << "all data loaded";
+    deleteRegion(previous_data_region);
+    deleteRegion(previous_layout_region);
+    util::SimpleLogger().Write() << "all data loaded";
 
-    shared_layout_ptr->PrintInformation();
+    return EXIT_SUCCESS;
 }
-catch (const std::bad_alloc &e)
-{
-    SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
-    SimpleLogger().Write(logWARNING) << "Please provide more memory or disable locking the virtual "
-                                        "address space (note: this makes OSRM swap, i.e. slow)";
-    return EXIT_FAILURE;
 }
-catch (const std::exception &e)
-{
-    SimpleLogger().Write(logWARNING) << "caught exception: " << e.what();
 }
diff --git a/src/storage/storage_config.cpp b/src/storage/storage_config.cpp
new file mode 100644
index 0000000..6ade34a
--- /dev/null
+++ b/src/storage/storage_config.cpp
@@ -0,0 +1,38 @@
+#include "storage/storage_config.hpp"
+
+#include <boost/filesystem/operations.hpp>
+
+namespace osrm
+{
+namespace storage
+{
+
+StorageConfig::StorageConfig(const boost::filesystem::path &base)
+    : ram_index_path{base.string() + ".ramIndex"}, file_index_path{base.string() + ".fileIndex"},
+      hsgr_data_path{base.string() + ".hsgr"}, nodes_data_path{base.string() + ".nodes"},
+      edges_data_path{base.string() + ".edges"}, core_data_path{base.string() + ".core"},
+      geometries_path{base.string() + ".geometry"}, timestamp_path{base.string() + ".timestamp"},
+      datasource_names_path{base.string() + ".datasource_names"},
+      datasource_indexes_path{base.string() + ".datasource_indexes"},
+      names_data_path{base.string() + ".names"},
+      properties_path{base.string() + ".properties"}
+{
+}
+
+bool StorageConfig::IsValid() const
+{
+    return boost::filesystem::is_regular_file(ram_index_path) &&
+           boost::filesystem::is_regular_file(file_index_path) &&
+           boost::filesystem::is_regular_file(hsgr_data_path) &&
+           boost::filesystem::is_regular_file(nodes_data_path) &&
+           boost::filesystem::is_regular_file(edges_data_path) &&
+           boost::filesystem::is_regular_file(core_data_path) &&
+           boost::filesystem::is_regular_file(geometries_path) &&
+           boost::filesystem::is_regular_file(timestamp_path) &&
+           boost::filesystem::is_regular_file(datasource_names_path) &&
+           boost::filesystem::is_regular_file(datasource_indexes_path) &&
+           boost::filesystem::is_regular_file(names_data_path) &&
+           boost::filesystem::is_regular_file(properties_path);
+}
+}
+}
diff --git a/tools/.gitignore b/src/tools/.gitignore
similarity index 100%
rename from tools/.gitignore
rename to src/tools/.gitignore
diff --git a/src/tools/components.cpp b/src/tools/components.cpp
new file mode 100644
index 0000000..45131a8
--- /dev/null
+++ b/src/tools/components.cpp
@@ -0,0 +1,233 @@
+#include "util/typedefs.hpp"
+#include "extractor/tarjan_scc.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/dynamic_graph.hpp"
+#include "util/static_graph.hpp"
+#include "util/fingerprint.hpp"
+#include "util/graph_loader.hpp"
+#include "util/make_unique.hpp"
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+
+#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.hpp"
+
+#include <fstream>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace tools
+{
+
+struct TarjanEdgeData
+{
+    TarjanEdgeData() : distance(INVALID_EDGE_WEIGHT), name_id(INVALID_NAMEID) {}
+    TarjanEdgeData(unsigned distance, unsigned name_id) : distance(distance), name_id(name_id) {}
+    unsigned distance;
+    unsigned name_id;
+};
+
+using TarjanGraph = util::StaticGraph<TarjanEdgeData>;
+using TarjanEdge = TarjanGraph::InputEdge;
+
+void deleteFileIfExists(const std::string &file_name)
+{
+    if (boost::filesystem::exists(file_name))
+    {
+        boost::filesystem::remove(file_name);
+    }
+}
+
+std::size_t loadGraph(const char *path,
+                      std::vector<extractor::QueryNode> &coordinate_list,
+                      std::vector<TarjanEdge> &graph_edge_list)
+{
+    std::ifstream input_stream(path, std::ifstream::in | std::ifstream::binary);
+    if (!input_stream.is_open())
+    {
+        throw util::exception("Cannot open osrm file");
+    }
+
+    // load graph data
+    std::vector<extractor::NodeBasedEdge> edge_list;
+    std::vector<NodeID> traffic_light_node_list;
+    std::vector<NodeID> barrier_node_list;
+
+    auto number_of_nodes = util::loadNodesFromFile(input_stream, barrier_node_list,
+                                                   traffic_light_node_list, coordinate_list);
+
+    util::loadEdgesFromFile(input_stream, edge_list);
+
+    traffic_light_node_list.clear();
+    traffic_light_node_list.shrink_to_fit();
+
+    // Building an node-based graph
+    for (const auto &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)(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)(input_edge.weight, 1), input_edge.name_id);
+        }
+    }
+
+    return number_of_nodes;
+}
+}
+}
+
+int main(int argc, char *argv[]) try
+{
+    std::vector<osrm::extractor::QueryNode> coordinate_list;
+    osrm::util::LogPolicy::GetInstance().Unmute();
+
+    // enable logging
+    if (argc < 2)
+    {
+        osrm::util::SimpleLogger().Write(logWARNING) << "usage:\n" << argv[0] << " <osrm>";
+        return EXIT_FAILURE;
+    }
+
+    std::vector<osrm::tools::TarjanEdge> graph_edge_list;
+    auto number_of_nodes = osrm::tools::loadGraph(argv[1], coordinate_list, graph_edge_list);
+
+    tbb::parallel_sort(graph_edge_list.begin(), graph_edge_list.end());
+    const auto graph = std::make_shared<osrm::tools::TarjanGraph>(number_of_nodes, graph_edge_list);
+    graph_edge_list.clear();
+    graph_edge_list.shrink_to_fit();
+
+    osrm::util::SimpleLogger().Write() << "Starting SCC graph traversal";
+
+    auto tarjan =
+        osrm::util::make_unique<osrm::extractor::TarjanSCC<osrm::tools::TarjanGraph>>(graph);
+    tarjan->run();
+    osrm::util::SimpleLogger().Write() << "identified: " << tarjan->get_number_of_components()
+                                       << " many components";
+    osrm::util::SimpleLogger().Write() << "identified " << tarjan->get_size_one_count()
+                                       << " size 1 SCCs";
+
+    // output
+    TIMER_START(SCC_RUN_SETUP);
+
+    // remove files from previous run if exist
+    osrm::tools::deleteFileIfExists("component.dbf");
+    osrm::tools::deleteFileIfExists("component.shx");
+    osrm::tools::deleteFileIfExists("component.shp");
+
+    osrm::util::Percent percentage(graph->GetNumberOfNodes());
+
+    OGRRegisterAll();
+
+    const char *psz_driver_name = "ESRI Shapefile";
+    auto *po_driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(psz_driver_name);
+    if (nullptr == po_driver)
+    {
+        throw osrm::util::exception("ESRI Shapefile driver not available");
+    }
+    auto *po_datasource = po_driver->CreateDataSource("component.shp", nullptr);
+
+    if (nullptr == po_datasource)
+    {
+        throw osrm::util::exception("Creation of output file failed");
+    }
+
+    auto *po_srs = new OGRSpatialReference();
+    po_srs->importFromEPSG(4326);
+
+    auto *po_layer = po_datasource->CreateLayer("component", po_srs, wkbLineString, nullptr);
+
+    if (nullptr == po_layer)
+    {
+        throw osrm::util::exception("Layer creation failed.");
+    }
+    TIMER_STOP(SCC_RUN_SETUP);
+    osrm::util::SimpleLogger().Write() << "shapefile setup took "
+                                       << TIMER_MSEC(SCC_RUN_SETUP) / 1000. << "s";
+
+    uint64_t total_network_length = 0;
+    percentage.reinit(graph->GetNumberOfNodes());
+    TIMER_START(SCC_OUTPUT);
+    for (const NodeID source : osrm::util::irange(0u, graph->GetNumberOfNodes()))
+    {
+        percentage.printIncrement();
+        for (const auto current_edge : graph->GetAdjacentEdgeRange(source))
+        {
+            const auto target = graph->GetTarget(current_edge);
+
+            if (source < target || SPECIAL_EDGEID == graph->FindEdge(target, source))
+            {
+                total_network_length +=
+                    100 * osrm::util::coordinate_calculation::greatCircleDistance(
+                              coordinate_list[source], coordinate_list[target]);
+
+                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(tarjan->get_component_id(source)),
+                             tarjan->get_component_size(tarjan->get_component_id(target)));
+
+                // edges that end on bollard nodes may actually be in two distinct components
+                if (size_of_containing_component < 1000)
+                {
+                    OGRLineString line_string;
+                    line_string.addPoint(
+                        static_cast<double>(osrm::util::toFloating(coordinate_list[source].lon)),
+                        static_cast<double>(osrm::util::toFloating(coordinate_list[source].lat)));
+                    line_string.addPoint(
+                        static_cast<double>(osrm::util::toFloating(coordinate_list[target].lon)),
+                        static_cast<double>(osrm::util::toFloating(coordinate_list[target].lat)));
+
+                    OGRFeature *po_feature = OGRFeature::CreateFeature(po_layer->GetLayerDefn());
+
+                    po_feature->SetGeometry(&line_string);
+                    if (OGRERR_NONE != po_layer->CreateFeature(po_feature))
+                    {
+                        throw osrm::util::exception("Failed to create feature in shapefile.");
+                    }
+                    OGRFeature::DestroyFeature(po_feature);
+                }
+            }
+        }
+    }
+    OGRSpatialReference::DestroySpatialReference(po_srs);
+    OGRDataSource::DestroyDataSource(po_datasource);
+    TIMER_STOP(SCC_OUTPUT);
+    osrm::util::SimpleLogger().Write()
+        << "generating output took: " << TIMER_MSEC(SCC_OUTPUT) / 1000. << "s";
+
+    osrm::util::SimpleLogger().Write()
+        << "total network distance: " << static_cast<uint64_t>(total_network_length / 100 / 1000.)
+        << " km";
+
+    osrm::util::SimpleLogger().Write() << "finished component analysis";
+    return EXIT_SUCCESS;
+}
+catch (const std::exception &e)
+{
+    osrm::util::SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+    return EXIT_FAILURE;
+}
diff --git a/src/tools/contract.cpp b/src/tools/contract.cpp
new file mode 100644
index 0000000..5bc65c5
--- /dev/null
+++ b/src/tools/contract.cpp
@@ -0,0 +1,159 @@
+#include "contractor/contractor.hpp"
+#include "contractor/contractor_config.hpp"
+#include "util/simple_logger.hpp"
+#include "util/version.hpp"
+
+#include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
+#include <boost/program_options/errors.hpp>
+
+#include <tbb/task_scheduler_init.h>
+
+#include <cstdlib>
+#include <exception>
+#include <new>
+#include <ostream>
+
+using namespace osrm;
+
+enum class return_code : unsigned
+{
+    ok,
+    fail,
+    exit
+};
+
+return_code parseArguments(int argc, char *argv[], contractor::ContractorConfig &contractor_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");
+
+    // declare a group of options that will be allowed on command line
+    boost::program_options::options_description config_options("Configuration");
+    config_options.add_options()(
+        "threads,t",
+        boost::program_options::value<unsigned int>(&contractor_config.requested_num_threads)
+            ->default_value(tbb::task_scheduler_init::default_num_threads()),
+        "Number of threads to use")(
+        "core,k",
+        boost::program_options::value<double>(&contractor_config.core_factor)->default_value(1.0),
+        "Percentage of the graph (in vertices) to contract [0..1]")(
+        "segment-speed-file", boost::program_options::value<std::vector<std::string>>(
+                                  &contractor_config.segment_speed_lookup_paths)
+                                  ->composing(),
+        "Lookup files containing nodeA, nodeB, speed data to adjust edge weights")(
+        "level-cache,o", boost::program_options::value<bool>(&contractor_config.use_cached_priority)
+                             ->default_value(false),
+        "Use .level file to retain the contaction level for each node from the last run.");
+
+    // hidden options, will be allowed on command line, 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>(
+                                                &contractor_config.osrm_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 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"))
+    {
+        util::SimpleLogger().Write() << OSRM_VERSION;
+        return return_code::exit;
+    }
+
+    if (option_variables.count("help"))
+    {
+        util::SimpleLogger().Write() << visible_options;
+        return return_code::exit;
+    }
+
+    boost::program_options::notify(option_variables);
+
+    if (!option_variables.count("input"))
+    {
+        util::SimpleLogger().Write() << visible_options;
+        return return_code::fail;
+    }
+
+    return return_code::ok;
+}
+
+int main(int argc, char *argv[]) try
+{
+    util::LogPolicy::GetInstance().Unmute();
+    contractor::ContractorConfig contractor_config;
+
+    const return_code result = parseArguments(argc, argv, contractor_config);
+
+    if (return_code::fail == result)
+    {
+        return EXIT_FAILURE;
+    }
+
+    if (return_code::exit == result)
+    {
+        return EXIT_SUCCESS;
+    }
+
+    contractor_config.UseDefaultOutputNames();
+
+    if (1 > contractor_config.requested_num_threads)
+    {
+        util::SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
+        return EXIT_FAILURE;
+    }
+
+    const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
+
+    if (recommended_num_threads != contractor_config.requested_num_threads)
+    {
+        util::SimpleLogger().Write(logWARNING)
+            << "The recommended number of threads is " << recommended_num_threads
+            << "! This setting may have performance side-effects.";
+    }
+
+    if (!boost::filesystem::is_regular_file(contractor_config.osrm_input_path))
+    {
+        util::SimpleLogger().Write(logWARNING)
+            << "Input file " << contractor_config.osrm_input_path.string() << " not found!";
+        return EXIT_FAILURE;
+    }
+
+    util::SimpleLogger().Write() << "Input file: "
+                                 << contractor_config.osrm_input_path.filename().string();
+    util::SimpleLogger().Write() << "Threads: " << contractor_config.requested_num_threads;
+
+    tbb::task_scheduler_init init(contractor_config.requested_num_threads);
+
+    return contractor::Contractor(contractor_config).Run();
+}
+catch (const std::bad_alloc &e)
+{
+    util::SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+    util::SimpleLogger().Write(logWARNING)
+        << "Please provide more memory or consider using a larger swapfile";
+    return EXIT_FAILURE;
+}
+catch (const std::exception &e)
+{
+    util::SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+    return EXIT_FAILURE;
+}
diff --git a/src/tools/extract.cpp b/src/tools/extract.cpp
new file mode 100644
index 0000000..4c5fa4c
--- /dev/null
+++ b/src/tools/extract.cpp
@@ -0,0 +1,160 @@
+#include "extractor/extractor.hpp"
+#include "extractor/extractor_config.hpp"
+#include "util/simple_logger.hpp"
+#include "util/version.hpp"
+
+#include <tbb/task_scheduler_init.h>
+
+#include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
+
+#include <cstdlib>
+#include <exception>
+#include <new>
+
+using namespace osrm;
+
+enum class return_code : unsigned
+{
+    ok,
+    fail,
+    exit
+};
+
+return_code parseArguments(int argc, char *argv[], extractor::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");
+
+    // declare a group of options that will be allowed both on command line
+    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")(
+        "generate-edge-lookup",
+        boost::program_options::value<bool>(&extractor_config.generate_edge_lookup)
+            ->implicit_value(true)
+            ->default_value(false),
+        "Generate a lookup table for internal edge-expanded-edge IDs to OSM node pairs")(
+        "small-component-size",
+        boost::program_options::value<unsigned int>(&extractor_config.small_component_size)
+            ->default_value(1000),
+        "Number of nodes required before a strongly-connected-componennt is considered big "
+        "(affects nearest neighbor snapping)");
+
+    // hidden options, will be allowed on command line, 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 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
+    try
+    {
+        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"))
+        {
+            util::SimpleLogger().Write() << OSRM_VERSION;
+            return return_code::exit;
+        }
+
+        if (option_variables.count("help"))
+        {
+            util::SimpleLogger().Write() << visible_options;
+            return return_code::exit;
+        }
+
+        boost::program_options::notify(option_variables);
+
+        if (!option_variables.count("input"))
+        {
+            util::SimpleLogger().Write() << visible_options;
+            return return_code::exit;
+        }
+    }
+    catch (std::exception &e)
+    {
+        util::SimpleLogger().Write(logWARNING) << e.what();
+        return return_code::fail;
+    }
+
+    return return_code::ok;
+}
+
+int main(int argc, char *argv[]) try
+{
+    util::LogPolicy::GetInstance().Unmute();
+    extractor::ExtractorConfig extractor_config;
+
+    const auto result = parseArguments(argc, argv, extractor_config);
+
+    if (return_code::fail == result)
+    {
+        return EXIT_FAILURE;
+    }
+
+    if (return_code::exit == result)
+    {
+        return EXIT_SUCCESS;
+    }
+
+    extractor_config.UseDefaultOutputNames();
+
+    if (1 > extractor_config.requested_num_threads)
+    {
+        util::SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
+        return EXIT_FAILURE;
+    }
+
+    if (!boost::filesystem::is_regular_file(extractor_config.input_path))
+    {
+        util::SimpleLogger().Write(logWARNING)
+            << "Input file " << extractor_config.input_path.string() << " not found!";
+        return EXIT_FAILURE;
+    }
+
+    if (!boost::filesystem::is_regular_file(extractor_config.profile_path))
+    {
+        util::SimpleLogger().Write(logWARNING)
+            << "Profile " << extractor_config.profile_path.string() << " not found!";
+        return EXIT_FAILURE;
+    }
+    return extractor::Extractor(extractor_config).run();
+}
+catch (const std::bad_alloc &e)
+{
+    util::SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+    util::SimpleLogger().Write(logWARNING)
+        << "Please provide more memory or consider using a larger swapfile";
+    return EXIT_FAILURE;
+}
+catch (const std::exception &e)
+{
+    util::SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+    return EXIT_FAILURE;
+}
diff --git a/src/tools/io-benchmark.cpp b/src/tools/io-benchmark.cpp
new file mode 100644
index 0000000..0030740
--- /dev/null
+++ b/src/tools/io-benchmark.cpp
@@ -0,0 +1,325 @@
+#include "util/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 <fcntl.h>
+#ifdef __linux__
+#include <malloc.h>
+#endif
+
+#include <algorithm>
+#include <chrono>
+#include <iomanip>
+#include <numeric>
+#include <random>
+#include <vector>
+
+namespace osrm
+{
+namespace tools
+{
+
+const unsigned NUMBER_OF_ELEMENTS = 268435456;
+
+struct Statistics
+{
+    double min, max, med, mean, dev;
+};
+
+void runStatistics(std::vector<double> &timings_vector, Statistics &stats)
+{
+    std::sort(timings_vector.begin(), timings_vector.end());
+    stats.min = timings_vector.front();
+    stats.max = timings_vector.back();
+    stats.med = timings_vector[timings_vector.size() / 2];
+    double primary_sum = std::accumulate(timings_vector.begin(), timings_vector.end(), 0.0);
+    stats.mean = primary_sum / timings_vector.size();
+
+    double primary_sq_sum = std::inner_product(timings_vector.begin(), timings_vector.end(),
+                                               timings_vector.begin(), 0.0);
+    stats.dev = std::sqrt(primary_sq_sum / timings_vector.size() - (stats.mean * stats.mean));
+}
+}
+}
+
+boost::filesystem::path test_path;
+
+int main(int argc, char *argv[]) try
+{
+
+#ifdef __FreeBSD__
+    osrm::util::SimpleLogger().Write() << "Not supported on FreeBSD";
+    return 0;
+#endif
+#ifdef _WIN32
+    osrm::util::SimpleLogger().Write() << "Not supported on Windows";
+    return 0;
+#else
+
+    osrm::util::LogPolicy::GetInstance().Unmute();
+    if (1 == argc)
+    {
+        osrm::util::SimpleLogger().Write(logWARNING) << "usage: " << argv[0] << " /path/on/device";
+        return -1;
+    }
+
+    test_path = boost::filesystem::path(argv[1]);
+    test_path /= "osrm.tst";
+    osrm::util::SimpleLogger().Write(logDEBUG) << "temporary file: " << test_path.string();
+
+    // create files for testing
+    if (2 == argc)
+    {
+        // create file to test
+        if (boost::filesystem::exists(test_path))
+        {
+            throw osrm::util::exception("Data file already exists");
+        }
+
+        int *random_array = new int[osrm::tools::NUMBER_OF_ELEMENTS];
+        std::generate(random_array, random_array + osrm::tools::NUMBER_OF_ELEMENTS, std::rand);
+#ifdef __APPLE__
+        FILE *fd = fopen(test_path.string().c_str(), "w");
+        fcntl(fileno(fd), F_NOCACHE, 1);
+        fcntl(fileno(fd), F_RDAHEAD, 0);
+        TIMER_START(write_1gb);
+        write(fileno(fd), (char *)random_array, osrm::tools::NUMBER_OF_ELEMENTS * sizeof(unsigned));
+        TIMER_STOP(write_1gb);
+        fclose(fd);
+#endif
+#ifdef __linux__
+        int file_desc =
+            open(test_path.string().c_str(), O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, S_IRWXU);
+        if (-1 == file_desc)
+        {
+            throw osrm::util::exception("Could not open random data file");
+        }
+        TIMER_START(write_1gb);
+        int ret =
+            write(file_desc, random_array, osrm::tools::NUMBER_OF_ELEMENTS * sizeof(unsigned));
+        if (0 > ret)
+        {
+            throw osrm::util::exception("could not write random data file");
+        }
+        TIMER_STOP(write_1gb);
+        close(file_desc);
+#endif
+        delete[] random_array;
+        osrm::util::SimpleLogger().Write(logDEBUG) << "writing raw 1GB took "
+                                                   << TIMER_SEC(write_1gb) << "s";
+        osrm::util::SimpleLogger().Write() << "raw write performance: " << std::setprecision(5)
+                                           << std::fixed << 1024 * 1024 / TIMER_SEC(write_1gb)
+                                           << "MB/sec";
+
+        osrm::util::SimpleLogger().Write(logDEBUG)
+            << "finished creation of random data. Flush disk cache now!";
+    }
+    else
+    {
+        // Run Non-Cached I/O benchmarks
+        if (!boost::filesystem::exists(test_path))
+        {
+            throw osrm::util::exception("data file does not exist");
+        }
+
+        // volatiles do not get optimized
+        osrm::tools::Statistics stats;
+
+#ifdef __APPLE__
+        volatile unsigned single_block[1024];
+        char *raw_array = new char[osrm::tools::NUMBER_OF_ELEMENTS * sizeof(unsigned)];
+        FILE *fd = fopen(test_path.string().c_str(), "r");
+        fcntl(fileno(fd), F_NOCACHE, 1);
+        fcntl(fileno(fd), F_RDAHEAD, 0);
+#endif
+#ifdef __linux__
+        char *single_block = (char *)memalign(512, 1024 * sizeof(unsigned));
+
+        int file_desc = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
+        if (-1 == file_desc)
+        {
+            osrm::util::SimpleLogger().Write(logDEBUG) << "opened, error: " << strerror(errno);
+            return -1;
+        }
+        char *raw_array = (char *)memalign(512, osrm::tools::NUMBER_OF_ELEMENTS * sizeof(unsigned));
+#endif
+        TIMER_START(read_1gb);
+#ifdef __APPLE__
+        read(fileno(fd), raw_array, osrm::tools::NUMBER_OF_ELEMENTS * sizeof(unsigned));
+        close(fileno(fd));
+        fd = fopen(test_path.string().c_str(), "r");
+#endif
+#ifdef __linux__
+        int ret = read(file_desc, raw_array, osrm::tools::NUMBER_OF_ELEMENTS * sizeof(unsigned));
+        osrm::util::SimpleLogger().Write(logDEBUG) << "read " << ret
+                                                   << " bytes, error: " << strerror(errno);
+        close(file_desc);
+        file_desc = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
+        osrm::util::SimpleLogger().Write(logDEBUG) << "opened, error: " << strerror(errno);
+#endif
+        TIMER_STOP(read_1gb);
+
+        osrm::util::SimpleLogger().Write(logDEBUG) << "reading raw 1GB took " << TIMER_SEC(read_1gb)
+                                                   << "s";
+        osrm::util::SimpleLogger().Write() << "raw read performance: " << std::setprecision(5)
+                                           << std::fixed << 1024 * 1024 / TIMER_SEC(read_1gb)
+                                           << "MB/sec";
+
+        std::vector<double> timing_results_raw_random;
+        osrm::util::SimpleLogger().Write(logDEBUG) << "running 1000 random I/Os of 4KB";
+
+#ifdef __APPLE__
+        fseek(fd, 0, SEEK_SET);
+#endif
+#ifdef __linux__
+        lseek(file_desc, 0, SEEK_SET);
+#endif
+        // make 1000 random access, time each I/O seperately
+        unsigned number_of_blocks = (osrm::tools::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 = uniform_dist(e1);
+            off_t current_offset = block_to_read * 4096;
+            TIMER_START(random_access);
+#ifdef __APPLE__
+            int ret1 = fseek(fd, current_offset, SEEK_SET);
+            int ret2 = read(fileno(fd), (char *)&single_block[0], 4096);
+#endif
+
+#ifdef __FreeBSD__
+            int ret1 = 0;
+            int ret2 = 0;
+#endif
+
+#ifdef __linux__
+            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)
+            {
+                osrm::util::SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
+                osrm::util::SimpleLogger().Write(logWARNING) << "seek error " << strerror(errno);
+                throw osrm::util::exception("seek error");
+            }
+            if (-1 == ret2)
+            {
+                osrm::util::SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
+                osrm::util::SimpleLogger().Write(logWARNING) << "read error " << strerror(errno);
+                throw osrm::util::exception("read error");
+            }
+            timing_results_raw_random.push_back(TIMER_SEC(random_access));
+        }
+
+        // Do statistics
+        osrm::util::SimpleLogger().Write(logDEBUG) << "running raw random I/O statistics";
+        std::ofstream random_csv("random.csv", std::ios::trunc);
+        for (unsigned i = 0; i < timing_results_raw_random.size(); ++i)
+        {
+            random_csv << i << ", " << timing_results_raw_random[i] << std::endl;
+        }
+        osrm::tools::runStatistics(timing_results_raw_random, stats);
+
+        osrm::util::SimpleLogger().Write() << "raw random I/O: " << std::setprecision(5)
+                                           << std::fixed << "min: " << stats.min << "ms, "
+                                           << "mean: " << stats.mean << "ms, "
+                                           << "med: " << stats.med << "ms, "
+                                           << "max: " << stats.max << "ms, "
+                                           << "dev: " << stats.dev << "ms";
+
+        std::vector<double> timing_results_raw_seq;
+#ifdef __APPLE__
+        fseek(fd, 0, SEEK_SET);
+#endif
+#ifdef __linux__
+        lseek(file_desc, 0, SEEK_SET);
+#endif
+
+        // read every 100th block
+        for (unsigned i = 0; i < 1000; ++i)
+        {
+            off_t current_offset = i * 4096;
+            TIMER_START(read_every_100);
+#ifdef __APPLE__
+            int ret1 = fseek(fd, current_offset, SEEK_SET);
+            int ret2 = read(fileno(fd), (char *)&single_block, 4096);
+#endif
+
+#ifdef __FreeBSD__
+            int ret1 = 0;
+            int ret2 = 0;
+#endif
+
+#ifdef __linux__
+            int ret1 = lseek(file_desc, current_offset, SEEK_SET);
+
+            int ret2 = read(file_desc, (char *)single_block, 4096);
+#endif
+            TIMER_STOP(read_every_100);
+            if (((off_t)-1) == ret1)
+            {
+                osrm::util::SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
+                osrm::util::SimpleLogger().Write(logWARNING) << "seek error " << strerror(errno);
+                throw osrm::util::exception("seek error");
+            }
+            if (-1 == ret2)
+            {
+                osrm::util::SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
+                osrm::util::SimpleLogger().Write(logWARNING) << "read error " << strerror(errno);
+                throw osrm::util::exception("read error");
+            }
+            timing_results_raw_seq.push_back(TIMER_SEC(read_every_100));
+        }
+#ifdef __APPLE__
+        fclose(fd);
+        // free(single_element);
+        free(raw_array);
+// free(single_block);
+#endif
+#ifdef __linux__
+        close(file_desc);
+#endif
+        // Do statistics
+        osrm::util::SimpleLogger().Write(logDEBUG) << "running sequential I/O statistics";
+        // print simple statistics: min, max, median, variance
+        std::ofstream seq_csv("sequential.csv", std::ios::trunc);
+        for (unsigned i = 0; i < timing_results_raw_seq.size(); ++i)
+        {
+            seq_csv << i << ", " << timing_results_raw_seq[i] << std::endl;
+        }
+        osrm::tools::runStatistics(timing_results_raw_seq, stats);
+        osrm::util::SimpleLogger().Write() << "raw sequential I/O: " << std::setprecision(5)
+                                           << std::fixed << "min: " << stats.min << "ms, "
+                                           << "mean: " << stats.mean << "ms, "
+                                           << "med: " << stats.med << "ms, "
+                                           << "max: " << stats.max << "ms, "
+                                           << "dev: " << stats.dev << "ms";
+
+        if (boost::filesystem::exists(test_path))
+        {
+            boost::filesystem::remove(test_path);
+            osrm::util::SimpleLogger().Write(logDEBUG) << "removing temporary files";
+        }
+    }
+    return EXIT_SUCCESS;
+#endif
+}
+catch (const std::exception &e)
+{
+    osrm::util::SimpleLogger().Write(logWARNING) << "caught exception: " << e.what();
+    osrm::util::SimpleLogger().Write(logWARNING) << "cleaning up, and exiting";
+    if (boost::filesystem::exists(test_path))
+    {
+        boost::filesystem::remove(test_path);
+        osrm::util::SimpleLogger().Write(logWARNING) << "removing temporary files";
+    }
+    return EXIT_FAILURE;
+}
diff --git a/src/tools/routed.cpp b/src/tools/routed.cpp
new file mode 100644
index 0000000..6c49d4e
--- /dev/null
+++ b/src/tools/routed.cpp
@@ -0,0 +1,348 @@
+#include "server/server.hpp"
+#include "util/make_unique.hpp"
+#include "util/simple_logger.hpp"
+#include "util/version.hpp"
+
+#include "osrm/osrm.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/storage_config.hpp"
+
+#include <boost/any.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
+
+#ifdef __linux__
+#include <sys/mman.h>
+#endif
+
+#include <cstdlib>
+
+#include <signal.h>
+
+#include <chrono>
+#include <future>
+#include <iostream>
+#include <new>
+#include <thread>
+#include <string>
+
+#ifdef _WIN32
+boost::function0<void> console_ctrl_function;
+
+BOOL WINAPI console_ctrl_handler(DWORD ctrl_type)
+{
+    switch (ctrl_type)
+    {
+    case CTRL_C_EVENT:
+    case CTRL_BREAK_EVENT:
+    case CTRL_CLOSE_EVENT:
+    case CTRL_SHUTDOWN_EVENT:
+        console_ctrl_function();
+        return TRUE;
+    default:
+        return FALSE;
+    }
+}
+#endif
+
+using namespace osrm;
+
+const static unsigned INIT_OK_START_ENGINE = 0;
+const static unsigned INIT_OK_DO_NOT_START_ENGINE = 1;
+const static unsigned INIT_FAILED = -1;
+
+// generate boost::program_options object for the routing part
+inline unsigned
+generateServerProgramOptions(const int argc,
+                             const char *argv[],
+                             boost::filesystem::path &base_path,
+                             std::string &ip_address,
+                             int &ip_port,
+                             int &requested_num_threads,
+                             bool &use_shared_memory,
+                             bool &trial,
+                             int &max_locations_trip,
+                             int &max_locations_viaroute,
+                             int &max_locations_distance_table,
+                             int &max_locations_map_matching)
+{
+    using boost::program_options::value;
+    using boost::filesystem::path;
+
+    // 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") //
+        ("trial", value<bool>(&trial)->implicit_value(true), "Quit after initialization");
+
+    // declare a group of options that will be allowed on command line
+    boost::program_options::options_description config_options("Configuration");
+    config_options.add_options()                                                             //
+        ("ip,i", value<std::string>(&ip_address)->default_value("0.0.0.0"),
+         "IP address") //
+        ("port,p", value<int>(&ip_port)->default_value(5000),
+         "TCP/IP port") //
+        ("threads,t", value<int>(&requested_num_threads)->default_value(8),
+         "Number of threads to use") //
+        ("shared-memory,s",
+         value<bool>(&use_shared_memory)->implicit_value(true)->default_value(false),
+         "Load data from shared memory") //
+        ("max-viaroute-size", value<int>(&max_locations_viaroute)->default_value(500),
+         "Max. locations supported in viaroute query") //
+        ("max-trip-size", value<int>(&max_locations_trip)->default_value(100),
+         "Max. locations supported in trip query") //
+        ("max-table-size", value<int>(&max_locations_distance_table)->default_value(100),
+         "Max. locations supported in distance table query") //
+        ("max-matching-size", value<int>(&max_locations_map_matching)->default_value(100),
+         "Max. locations supported in map matching query");
+
+    // hidden options, will be allowed on command line, but will not be shown to the user
+    boost::program_options::options_description hidden_options("Hidden options");
+    hidden_options.add_options()("base,b", value<boost::filesystem::path>(&base_path),
+                                 "base path to .osrm file");
+
+    // positional option
+    boost::program_options::positional_options_description positional_options;
+    positional_options.add("base", 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 visible_options(
+        boost::filesystem::path(argv[0]).stem().string() + " <base.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"))
+    {
+        util::SimpleLogger().Write() << OSRM_VERSION;
+        return INIT_OK_DO_NOT_START_ENGINE;
+    }
+
+    if (option_variables.count("help"))
+    {
+        util::SimpleLogger().Write() << visible_options;
+        return INIT_OK_DO_NOT_START_ENGINE;
+    }
+
+    boost::program_options::notify(option_variables);
+
+    if (!use_shared_memory && option_variables.count("base"))
+    {
+        return INIT_OK_START_ENGINE;
+    }
+    else if (use_shared_memory && !option_variables.count("base"))
+    {
+        return INIT_OK_START_ENGINE;
+    }
+    else if (use_shared_memory && option_variables.count("base"))
+    {
+        util::SimpleLogger().Write(logWARNING) << "Shared memory settings conflict with path settings.";
+    }
+
+    util::SimpleLogger().Write() << visible_options;
+    return INIT_OK_DO_NOT_START_ENGINE;
+}
+
+int main(int argc, const char *argv[]) try
+{
+    util::LogPolicy::GetInstance().Unmute();
+
+    bool trial_run = false;
+    std::string ip_address;
+    int ip_port, requested_thread_num;
+
+    EngineConfig config;
+    boost::filesystem::path base_path;
+    const unsigned init_result = generateServerProgramOptions(
+        argc, argv, base_path, ip_address, ip_port, requested_thread_num,
+        config.use_shared_memory, trial_run, config.max_locations_trip,
+        config.max_locations_viaroute, config.max_locations_distance_table,
+        config.max_locations_map_matching);
+    if (init_result == INIT_OK_DO_NOT_START_ENGINE)
+    {
+        return EXIT_SUCCESS;
+    }
+    if (init_result == INIT_FAILED)
+    {
+        return EXIT_FAILURE;
+    }
+    if (!base_path.empty())
+    {
+        config.storage_config = storage::StorageConfig(base_path);
+    }
+    if(!config.IsValid())
+    {
+        if (base_path.empty() != config.use_shared_memory)
+        {
+            util::SimpleLogger().Write(logWARNING) << "Path settings and shared memory conflicts.";
+        }
+        else
+        {
+            if(!boost::filesystem::is_regular_file(config.storage_config.ram_index_path))
+            {
+                util::SimpleLogger().Write(logWARNING) << config.storage_config.ram_index_path << " is not found";
+            }
+            if(!boost::filesystem::is_regular_file(config.storage_config.file_index_path))
+            {
+                util::SimpleLogger().Write(logWARNING) << config.storage_config.file_index_path << " is not found";
+            }
+            if(!boost::filesystem::is_regular_file(config.storage_config.hsgr_data_path))
+            {
+                util::SimpleLogger().Write(logWARNING) << config.storage_config.hsgr_data_path << " is not found";
+            }
+            if(!boost::filesystem::is_regular_file(config.storage_config.nodes_data_path))
+            {
+                util::SimpleLogger().Write(logWARNING) << config.storage_config.nodes_data_path << " is not found";
+            }
+            if(!boost::filesystem::is_regular_file(config.storage_config.edges_data_path))
+            {
+                util::SimpleLogger().Write(logWARNING) << config.storage_config.edges_data_path << " is not found";
+            }
+            if(!boost::filesystem::is_regular_file(config.storage_config.core_data_path))
+            {
+                util::SimpleLogger().Write(logWARNING) << config.storage_config.core_data_path << " is not found";
+            }
+            if(!boost::filesystem::is_regular_file(config.storage_config.geometries_path))
+            {
+                util::SimpleLogger().Write(logWARNING) << config.storage_config.geometries_path << " is not found";
+            }
+            if(!boost::filesystem::is_regular_file(config.storage_config.timestamp_path))
+            {
+                util::SimpleLogger().Write(logWARNING) << config.storage_config.timestamp_path << " is not found";
+            }
+            if(!boost::filesystem::is_regular_file(config.storage_config.datasource_names_path))
+            {
+                util::SimpleLogger().Write(logWARNING) << config.storage_config.datasource_names_path << " is not found";
+            }
+            if(!boost::filesystem::is_regular_file(config.storage_config.datasource_indexes_path))
+            {
+                util::SimpleLogger().Write(logWARNING) << config.storage_config.datasource_indexes_path << " is not found";
+            }
+            if(!boost::filesystem::is_regular_file(config.storage_config.names_data_path))
+            {
+                util::SimpleLogger().Write(logWARNING) << config.storage_config.names_data_path << " is not found";
+            }
+            if(!boost::filesystem::is_regular_file(config.storage_config.properties_path))
+            {
+                util::SimpleLogger().Write(logWARNING) << config.storage_config.properties_path << " is not found";
+            }
+        }
+        return EXIT_FAILURE;
+    }
+
+#ifdef __linux__
+    struct MemoryLocker final
+    {
+        explicit MemoryLocker(bool should_lock) : should_lock(should_lock)
+        {
+            if (should_lock && -1 == mlockall(MCL_CURRENT | MCL_FUTURE))
+            {
+                could_lock = false;
+                util::SimpleLogger().Write(logWARNING) << "memory could not be locked to RAM";
+            }
+        }
+        ~MemoryLocker()
+        {
+            if (should_lock && could_lock)
+                (void)munlockall();
+        }
+        bool should_lock = false, could_lock = true;
+    } memory_locker(config.use_shared_memory);
+#endif
+    util::SimpleLogger().Write() << "starting up engines, " << OSRM_VERSION;
+
+    if (config.use_shared_memory)
+    {
+        util::SimpleLogger().Write() << "Loading from shared memory";
+    }
+
+    util::SimpleLogger().Write() << "Threads: " << requested_thread_num;
+    util::SimpleLogger().Write() << "IP address: " << ip_address;
+    util::SimpleLogger().Write() << "IP port: " << ip_port;
+
+#ifndef _WIN32
+    int sig = 0;
+    sigset_t new_mask;
+    sigset_t old_mask;
+    sigfillset(&new_mask);
+    pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask);
+#endif
+
+    auto routing_server = server::Server::CreateServer(ip_address, ip_port, requested_thread_num);
+    auto service_handler = util::make_unique<server::ServiceHandler>(config);
+
+    routing_server->RegisterServiceHandler(std::move(service_handler));
+
+    if (trial_run)
+    {
+        util::SimpleLogger().Write() << "trial run, quitting after successful initialization";
+    }
+    else
+    {
+        std::packaged_task<int()> server_task([&]
+                                              {
+                                                  routing_server->Run();
+                                                  return 0;
+                                              });
+        auto future = server_task.get_future();
+        std::thread server_thread(std::move(server_task));
+
+#ifndef _WIN32
+        sigset_t wait_mask;
+        pthread_sigmask(SIG_SETMASK, &old_mask, nullptr);
+        sigemptyset(&wait_mask);
+        sigaddset(&wait_mask, SIGINT);
+        sigaddset(&wait_mask, SIGQUIT);
+        sigaddset(&wait_mask, SIGTERM);
+        pthread_sigmask(SIG_BLOCK, &wait_mask, nullptr);
+        util::SimpleLogger().Write() << "running and waiting for requests";
+        sigwait(&wait_mask, &sig);
+#else
+        // Set console control handler to allow server to be stopped.
+        console_ctrl_function = std::bind(&server::Server::Stop, routing_server);
+        SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
+        util::SimpleLogger().Write() << "running and waiting for requests";
+        routing_server->Run();
+#endif
+        util::SimpleLogger().Write() << "initiating shutdown";
+        routing_server->Stop();
+        util::SimpleLogger().Write() << "stopping threads";
+
+        auto status = future.wait_for(std::chrono::seconds(2));
+
+        if (status == std::future_status::ready)
+        {
+            server_thread.join();
+        }
+        else
+        {
+            util::SimpleLogger().Write(logWARNING) << "Didn't exit within 2 seconds. Hard abort!";
+            server_task.reset(); // just kill it
+        }
+    }
+
+    util::SimpleLogger().Write() << "freeing objects";
+    routing_server.reset();
+    util::SimpleLogger().Write() << "shutdown completed";
+}
+catch (const std::bad_alloc &e)
+{
+    util::SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+    util::SimpleLogger().Write(logWARNING)
+        << "Please provide more memory or consider using a larger swapfile";
+    return EXIT_FAILURE;
+}
+catch (const std::exception &e)
+{
+    util::SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+    return EXIT_FAILURE;
+}
diff --git a/src/tools/springclean.cpp b/src/tools/springclean.cpp
new file mode 100644
index 0000000..69a7cc1
--- /dev/null
+++ b/src/tools/springclean.cpp
@@ -0,0 +1,82 @@
+#include <cstdio>
+
+#include "storage/shared_memory.hpp"
+#include "storage/shared_datatype.hpp"
+#include "util/simple_logger.hpp"
+
+namespace osrm
+{
+namespace tools
+{
+
+// FIXME remove after folding back into datastore
+using namespace storage;
+
+void deleteRegion(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";
+            }
+        }();
+
+        util::SimpleLogger().Write(logWARNING) << "could not delete shared memory region " << name;
+    }
+}
+
+// find all existing shmem regions and remove them.
+void springclean()
+{
+    util::SimpleLogger().Write() << "spring-cleaning all shared memory regions";
+    deleteRegion(DATA_1);
+    deleteRegion(LAYOUT_1);
+    deleteRegion(DATA_2);
+    deleteRegion(LAYOUT_2);
+    deleteRegion(CURRENT_REGIONS);
+}
+}
+}
+
+int main() try
+{
+    osrm::util::LogPolicy::GetInstance().Unmute();
+    osrm::util::SimpleLogger().Write() << "Releasing all locks";
+    osrm::util::SimpleLogger().Write() << "ATTENTION! BE CAREFUL!";
+    osrm::util::SimpleLogger().Write() << "----------------------";
+    osrm::util::SimpleLogger().Write() << "This tool may put osrm-routed into an undefined state!";
+    osrm::util::SimpleLogger().Write()
+        << "Type 'Y' to acknowledge that you know what your are doing.";
+    osrm::util::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')
+    {
+        osrm::util::SimpleLogger().Write() << "aborted.";
+        return EXIT_SUCCESS;
+    }
+    osrm::tools::springclean();
+    return EXIT_SUCCESS;
+}
+catch (const std::exception &e)
+{
+    osrm::util::SimpleLogger().Write(logWARNING) << "[excpetion] " << e.what();
+    return EXIT_FAILURE;
+}
diff --git a/src/tools/store.cpp b/src/tools/store.cpp
new file mode 100644
index 0000000..7866cf3
--- /dev/null
+++ b/src/tools/store.cpp
@@ -0,0 +1,104 @@
+#include "storage/storage.hpp"
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+#include "util/typedefs.hpp"
+#include "util/version.hpp"
+
+#include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
+
+using namespace osrm;
+
+// generate boost::program_options object for the routing part
+bool generateDataStoreOptions(const int argc, const char *argv[], boost::filesystem::path& base_path)
+{
+    // 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")(
+        "springclean,s", "Remove all regions in shared memory");
+
+    // declare a group of options that will be allowed both on command line
+    // as well as in a config file
+    boost::program_options::options_description config_options("Configuration");
+
+    // hidden options, will be allowed on command line but will not be shown to the user
+    boost::program_options::options_description hidden_options("Hidden options");
+    hidden_options.add_options()(
+        "base,b", boost::program_options::value<boost::filesystem::path>(&base_path),
+        "base path to .osrm file");
+
+    // positional option
+    boost::program_options::positional_options_description positional_options;
+    positional_options.add("base", 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 visible_options(
+        boost::filesystem::basename(argv[0]) + " [<options>] <configuration>");
+    visible_options.add(generic_options).add(config_options);
+
+    // print help options if no infile is specified
+    if (argc < 2)
+    {
+        util::SimpleLogger().Write() << visible_options;
+        return false;
+    }
+
+    // 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"))
+    {
+        util::SimpleLogger().Write() << OSRM_VERSION;
+        return false;
+    }
+
+    if (option_variables.count("help"))
+    {
+        util::SimpleLogger().Write() << visible_options;
+        return false;
+    }
+
+    boost::program_options::notify(option_variables);
+
+    return true;
+}
+
+int main(const int argc, const char *argv[]) try
+{
+    util::LogPolicy::GetInstance().Unmute();
+
+    boost::filesystem::path base_path;
+    if (!generateDataStoreOptions(argc, argv, base_path))
+    {
+        return EXIT_SUCCESS;
+    }
+    storage::StorageConfig config(base_path);
+    if (!config.IsValid())
+    {
+        util::SimpleLogger().Write(logWARNING) << "Invalid file path given!";
+        return EXIT_FAILURE;
+    }
+    storage::Storage storage(std::move(config));
+    return storage.Run();
+}
+catch (const std::bad_alloc &e)
+{
+    util::SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+    util::SimpleLogger().Write(logWARNING)
+        << "Please provide more memory or disable locking the virtual "
+           "address space (note: this makes OSRM swap, i.e. slow)";
+    return EXIT_FAILURE;
+}
+catch (const std::exception &e)
+{
+    util::SimpleLogger().Write(logWARNING) << "caught exception: " << e.what();
+    return EXIT_FAILURE;
+}
diff --git a/src/tools/unlock_all_mutexes.cpp b/src/tools/unlock_all_mutexes.cpp
new file mode 100644
index 0000000..2af8477
--- /dev/null
+++ b/src/tools/unlock_all_mutexes.cpp
@@ -0,0 +1,20 @@
+#include "util/simple_logger.hpp"
+#include "storage/shared_barriers.hpp"
+
+#include <iostream>
+
+int main() try
+{
+    osrm::util::LogPolicy::GetInstance().Unmute();
+    osrm::util::SimpleLogger().Write() << "Releasing all locks";
+    osrm::storage::SharedBarriers barrier;
+    barrier.pending_update_mutex.unlock();
+    barrier.query_mutex.unlock();
+    barrier.update_mutex.unlock();
+    return 0;
+}
+catch (const std::exception &e)
+{
+    osrm::util::SimpleLogger().Write(logWARNING) << "[excpetion] " << e.what();
+    return EXIT_FAILURE;
+}
diff --git a/src/util/assert.cpp b/src/util/assert.cpp
new file mode 100644
index 0000000..7051784
--- /dev/null
+++ b/src/util/assert.cpp
@@ -0,0 +1,29 @@
+#include "util/assert.hpp"
+
+#include <sstream>
+
+namespace
+{
+// We throw to guarantee for stack-unwinding and therefore our destructors being called.
+void assertion_failed_msg_helper(
+    char const *expr, char const *msg, char const *function, char const *file, long line)
+{
+    std::ostringstream fmt;
+    fmt << file << ":" << line << "\nin: " << function << ": " << expr << "\n" << msg;
+    throw osrm::util::assertionError{fmt.str().c_str()};
+}
+}
+
+// Boost.Assert only declares the following two functions and let's us define them here.
+namespace boost
+{
+void assertion_failed(char const *expr, char const *function, char const *file, long line)
+{
+    ::assertion_failed_msg_helper(expr, "", function, file, line);
+}
+void assertion_failed_msg(
+    char const *expr, char const *msg, char const *function, char const *file, long line)
+{
+    ::assertion_failed_msg_helper(expr, msg, function, file, line);
+}
+}
diff --git a/src/util/coordinate.cpp b/src/util/coordinate.cpp
new file mode 100644
index 0000000..9ccbf17
--- /dev/null
+++ b/src/util/coordinate.cpp
@@ -0,0 +1,100 @@
+#include "util/coordinate_calculation.hpp"
+
+#ifndef NDEBUG
+#include "util/simple_logger.hpp"
+#endif
+#include "osrm/coordinate.hpp"
+
+#ifndef NDEBUG
+#include <bitset>
+#endif
+#include <iostream>
+#include <iomanip>
+#include <limits>
+
+namespace osrm
+{
+namespace util
+{
+
+Coordinate::Coordinate()
+    : lon(std::numeric_limits<int>::min()), lat(std::numeric_limits<int>::min())
+{
+}
+
+Coordinate::Coordinate(const FloatCoordinate &other)
+    : Coordinate(toFixed(other.lon), toFixed(other.lat))
+{
+}
+
+Coordinate::Coordinate(const FloatLongitude lon_, const FloatLatitude lat_)
+    : Coordinate(toFixed(lon_), toFixed(lat_))
+{
+}
+
+Coordinate::Coordinate(const FixedLongitude lon_, const FixedLatitude lat_) : lon(lon_), lat(lat_)
+{
+}
+
+bool Coordinate::IsValid() const
+{
+    return !(lat > FixedLatitude(90 * COORDINATE_PRECISION) ||
+             lat < FixedLatitude(-90 * COORDINATE_PRECISION) ||
+             lon > FixedLongitude(180 * COORDINATE_PRECISION) ||
+             lon < FixedLongitude(-180 * COORDINATE_PRECISION));
+}
+
+FloatCoordinate::FloatCoordinate()
+    : lon(std::numeric_limits<double>::min()), lat(std::numeric_limits<double>::min())
+{
+}
+
+FloatCoordinate::FloatCoordinate(const Coordinate other)
+    : FloatCoordinate(toFloating(other.lon), toFloating(other.lat))
+{
+}
+
+FloatCoordinate::FloatCoordinate(const FixedLongitude lon_, const FixedLatitude lat_)
+    : FloatCoordinate(toFloating(lon_), toFloating(lat_))
+{
+}
+
+FloatCoordinate::FloatCoordinate(const FloatLongitude lon_, const FloatLatitude lat_) : lon(lon_), lat(lat_)
+{
+}
+
+bool FloatCoordinate::IsValid() const
+{
+    return !(lat > FloatLatitude(90) ||
+             lat < FloatLatitude(-90) ||
+             lon > FloatLongitude(180) ||
+             lon < FloatLongitude(-180));
+}
+
+
+bool operator==(const Coordinate lhs, const Coordinate rhs)
+{
+    return lhs.lat == rhs.lat && lhs.lon == rhs.lon;
+}
+bool operator==(const FloatCoordinate lhs, const FloatCoordinate rhs)
+{
+    return lhs.lat == rhs.lat && lhs.lon == rhs.lon;
+}
+
+bool operator!=(const Coordinate lhs, const Coordinate rhs) { return !(lhs == rhs); }
+bool operator!=(const FloatCoordinate lhs, const FloatCoordinate rhs) { return !(lhs == rhs); }
+
+std::ostream &operator<<(std::ostream &out, const Coordinate coordinate)
+{
+    out << std::setprecision(12) << "(lon:" << toFloating(coordinate.lon)
+        << ", lat:" << toFloating(coordinate.lat) << ")";
+    return out;
+}
+std::ostream &operator<<(std::ostream &out, const FloatCoordinate coordinate)
+{
+    out << std::setprecision(12) << "(lon:" << coordinate.lon
+        << ", lat:" << coordinate.lat << ")";
+    return out;
+}
+}
+}
diff --git a/src/util/coordinate_calculation.cpp b/src/util/coordinate_calculation.cpp
new file mode 100644
index 0000000..8ed69c9
--- /dev/null
+++ b/src/util/coordinate_calculation.cpp
@@ -0,0 +1,325 @@
+#include "util/coordinate.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/trigonometry_table.hpp"
+
+#include <boost/assert.hpp>
+
+#include <cmath>
+
+#include <limits>
+#include <utility>
+
+namespace osrm
+{
+namespace util
+{
+
+namespace coordinate_calculation
+{
+
+// Does not project the coordinates!
+double squaredEuclideanDistance(const FloatCoordinate &lhs, const FloatCoordinate &rhs)
+{
+    const double dx = static_cast<double>(lhs.lon - rhs.lon);
+    const double dy = static_cast<double>(lhs.lat - rhs.lat);
+
+    return dx * dx + dy * dy;
+}
+
+double haversineDistance(const Coordinate coordinate_1, const Coordinate coordinate_2)
+{
+    auto lon1 = static_cast<int>(coordinate_1.lon);
+    auto lat1 = static_cast<int>(coordinate_1.lat);
+    auto lon2 = static_cast<int>(coordinate_2.lon);
+    auto lat2 = static_cast<int>(coordinate_2.lat);
+    BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
+    BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
+    BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
+    BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
+    const double lt1 = lat1 / COORDINATE_PRECISION;
+    const double ln1 = lon1 / COORDINATE_PRECISION;
+    const double lt2 = lat2 / COORDINATE_PRECISION;
+    const double ln2 = lon2 / COORDINATE_PRECISION;
+    const double dlat1 = lt1 * DEGREE_TO_RAD;
+
+    const double dlong1 = ln1 * DEGREE_TO_RAD;
+    const double dlat2 = lt2 * DEGREE_TO_RAD;
+    const double dlong2 = ln2 * DEGREE_TO_RAD;
+
+    const double dlong = dlong1 - dlong2;
+    const double dlat = dlat1 - dlat2;
+
+    const double aharv = std::pow(std::sin(dlat / 2.0), 2.0) +
+                         std::cos(dlat1) * std::cos(dlat2) * std::pow(std::sin(dlong / 2.), 2);
+    const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv));
+    return EARTH_RADIUS * charv;
+}
+
+double greatCircleDistance(const Coordinate coordinate_1, const Coordinate coordinate_2)
+{
+    auto lon1 = static_cast<int>(coordinate_1.lon);
+    auto lat1 = static_cast<int>(coordinate_1.lat);
+    auto lon2 = static_cast<int>(coordinate_2.lon);
+    auto lat2 = static_cast<int>(coordinate_2.lat);
+    BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
+    BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
+    BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
+    BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
+
+    const double float_lat1 = (lat1 / COORDINATE_PRECISION) * DEGREE_TO_RAD;
+    const double float_lon1 = (lon1 / COORDINATE_PRECISION) * DEGREE_TO_RAD;
+    const double float_lat2 = (lat2 / COORDINATE_PRECISION) * DEGREE_TO_RAD;
+    const double float_lon2 = (lon2 / COORDINATE_PRECISION) * DEGREE_TO_RAD;
+
+    const double x_value = (float_lon2 - float_lon1) * std::cos((float_lat1 + float_lat2) / 2.0);
+    const double y_value = float_lat2 - float_lat1;
+    return std::hypot(x_value, y_value) * EARTH_RADIUS;
+}
+
+std::pair<double, FloatCoordinate> projectPointOnSegment(const FloatCoordinate &source,
+                                                         const FloatCoordinate &target,
+                                                         const FloatCoordinate &coordinate)
+{
+    const FloatCoordinate slope_vector{target.lon - source.lon, target.lat - source.lat};
+    const FloatCoordinate rel_coordinate{coordinate.lon - source.lon, coordinate.lat - source.lat};
+    // dot product of two un-normed vectors
+    const auto unnormed_ratio = static_cast<double>(slope_vector.lon * rel_coordinate.lon) +
+                                static_cast<double>(slope_vector.lat * rel_coordinate.lat);
+    // squared length of the slope vector
+    const auto squared_length = static_cast<double>(slope_vector.lon * slope_vector.lon) +
+                                static_cast<double>(slope_vector.lat * slope_vector.lat);
+
+    if (squared_length < std::numeric_limits<double>::epsilon())
+    {
+        return {0, source};
+    }
+
+    const double normed_ratio = unnormed_ratio / squared_length;
+    double clamped_ratio = normed_ratio;
+    if (clamped_ratio > 1.)
+    {
+        clamped_ratio = 1.;
+    }
+    else if (clamped_ratio < 0.)
+    {
+        clamped_ratio = 0.;
+    }
+    return {clamped_ratio,
+            {
+                source.lon + slope_vector.lon * FloatLongitude(clamped_ratio),
+                source.lat + slope_vector.lat * FloatLatitude(clamped_ratio),
+            }};
+}
+
+double perpendicularDistance(const Coordinate segment_source,
+                             const Coordinate segment_target,
+                             const Coordinate query_location,
+                             Coordinate &nearest_location,
+                             double &ratio)
+{
+    using namespace coordinate_calculation;
+
+    BOOST_ASSERT(query_location.IsValid());
+
+    FloatCoordinate projected_nearest;
+    std::tie(ratio, projected_nearest) =
+        projectPointOnSegment(mercator::fromWGS84(segment_source), mercator::fromWGS84(segment_target), mercator::fromWGS84(query_location));
+    nearest_location = mercator::toWGS84(projected_nearest);
+
+    const double approximate_distance = greatCircleDistance(query_location, nearest_location);
+    BOOST_ASSERT(0.0 <= approximate_distance);
+    return approximate_distance;
+}
+
+double perpendicularDistance(const Coordinate source_coordinate,
+                             const Coordinate target_coordinate,
+                             const Coordinate query_location)
+{
+    double ratio;
+    Coordinate nearest_location;
+
+    return perpendicularDistance(source_coordinate, target_coordinate, query_location,
+                                 nearest_location, ratio);
+}
+
+Coordinate centroid(const Coordinate lhs, const Coordinate rhs)
+{
+    Coordinate centroid;
+    // The coordinates of the midpoints are given by:
+    // x = (x1 + x2) /2 and y = (y1 + y2) /2.
+    centroid.lon = (lhs.lon + rhs.lon) / FixedLongitude(2);
+    centroid.lat = (lhs.lat + rhs.lat) / FixedLatitude(2);
+    return centroid;
+}
+
+double degToRad(const double degree)
+{
+    using namespace boost::math::constants;
+    return degree * (pi<double>() / 180.0);
+}
+
+double radToDeg(const double radian)
+{
+    using namespace boost::math::constants;
+    return radian * (180.0 * (1. / pi<double>()));
+}
+
+double bearing(const Coordinate first_coordinate, const Coordinate second_coordinate)
+{
+    const double lon_diff =
+        static_cast<double>(toFloating(second_coordinate.lon - first_coordinate.lon));
+    const double lon_delta = degToRad(lon_diff);
+    const double lat1 = degToRad(static_cast<double>(toFloating(first_coordinate.lat)));
+    const double lat2 = degToRad(static_cast<double>(toFloating(second_coordinate.lat)));
+    const double y = std::sin(lon_delta) * std::cos(lat2);
+    const double x =
+        std::cos(lat1) * std::sin(lat2) - std::sin(lat1) * std::cos(lat2) * std::cos(lon_delta);
+    double result = radToDeg(std::atan2(y, x));
+    while (result < 0.0)
+    {
+        result += 360.0;
+    }
+
+    while (result >= 360.0)
+    {
+        result -= 360.0;
+    }
+    return result;
+}
+
+double computeAngle(const Coordinate first, const Coordinate second, const Coordinate third)
+{
+    using namespace boost::math::constants;
+    using namespace coordinate_calculation;
+
+    const double v1x = static_cast<double>(toFloating(first.lon - second.lon));
+    const double v1y =
+        mercator::latToY(toFloating(first.lat)) - mercator::latToY(toFloating(second.lat));
+    const double v2x = static_cast<double>(toFloating(third.lon - second.lon));
+    const double v2y =
+        mercator::latToY(toFloating(third.lat)) - mercator::latToY(toFloating(second.lat));
+
+    double angle = (atan2_lookup(v2y, v2x) - atan2_lookup(v1y, v1x)) * 180. / pi<double>();
+
+    while (angle < 0.)
+    {
+        angle += 360.;
+    }
+
+    return angle;
+}
+
+Coordinate interpolateLinear(double factor, const Coordinate from, const Coordinate to)
+{
+    BOOST_ASSERT(0 <= factor && factor <= 1.0);
+
+    FixedLongitude interpolated_lon(((1. - factor) * static_cast<std::int32_t>(from.lon)) +
+                                    (factor * static_cast<std::int32_t>(to.lon)));
+    FixedLatitude interpolated_lat(((1. - factor) * static_cast<std::int32_t>(from.lat)) +
+                                   (factor * static_cast<std::int32_t>(to.lat)));
+
+    return {std::move(interpolated_lon), std::move(interpolated_lat)};
+}
+
+namespace mercator
+{
+FloatLatitude yToLat(const double y)
+{
+    const auto clamped_y = std::max(-180., std::min(180., y));
+    const double normalized_lat =
+        RAD_TO_DEGREE * 2. * std::atan(std::exp(clamped_y * DEGREE_TO_RAD));
+
+    return FloatLatitude(normalized_lat - 90.);
+}
+
+double latToY(const FloatLatitude latitude)
+{
+    const double normalized_lat = 90. + static_cast<double>(latitude);
+
+    const double y = RAD_TO_DEGREE * std::log(std::tan(normalized_lat * DEGREE_TO_RAD * 0.5));
+    const auto clamped_y = std::max(-180., std::min(180., y));
+    return clamped_y;
+}
+
+FloatLatitude clamp(const FloatLatitude lat)
+{
+    return std::max(std::min(lat, FloatLatitude(detail::MAX_LATITUDE)),
+                    FloatLatitude(-detail::MAX_LATITUDE));
+}
+
+FloatLongitude clamp(const FloatLongitude lon)
+{
+    return std::max(std::min(lon, FloatLongitude(detail::MAX_LONGITUDE)),
+                    FloatLongitude(-detail::MAX_LONGITUDE));
+}
+
+inline void pixelToDegree(const double shift, double &x, double &y)
+{
+    const double b = shift / 2.0;
+    x = (x - b) / shift * 360.0;
+    // FIXME needs to be simplified
+    const double g = (y - b) / -(shift / (2 * M_PI)) / DEGREE_TO_RAD;
+    static_assert(DEGREE_TO_RAD / (2 * M_PI) - 1 / 360. < 0.0001, "");
+    y = static_cast<double>(util::coordinate_calculation::mercator::yToLat(g));
+}
+
+double degreeToPixel(FloatLongitude lon, unsigned zoom)
+{
+    const double shift = (1u << zoom) * TILE_SIZE;
+    const double b = shift / 2.0;
+    const double x = b * (1 + static_cast<double>(lon) / 180.0);
+    return x;
+}
+
+double degreeToPixel(FloatLatitude lat, unsigned zoom)
+{
+    const double shift = (1u << zoom) * TILE_SIZE;
+    const double b = shift / 2.0;
+    const double y = b * (1. - latToY(lat) / 180.);
+    return y;
+}
+
+FloatCoordinate fromWGS84(const FloatCoordinate &wgs84_coordinate)
+{
+    return {wgs84_coordinate.lon, FloatLatitude{coordinate_calculation::mercator::latToY(wgs84_coordinate.lat)}};
+}
+
+FloatCoordinate toWGS84(const FloatCoordinate &mercator_coordinate)
+{
+    return {mercator_coordinate.lon, coordinate_calculation::mercator::yToLat(static_cast<double>(mercator_coordinate.lat))};
+}
+
+// Converts a WMS tile coordinate (z,x,y) into a wgs bounding box
+void xyzToWGS84(
+    const int x, const int y, const int z, double &minx, double &miny, double &maxx, double &maxy)
+{
+    using util::coordinate_calculation::mercator::TILE_SIZE;
+
+    minx = x * TILE_SIZE;
+    miny = (y + 1.0) * TILE_SIZE;
+    maxx = (x + 1.0) * TILE_SIZE;
+    maxy = y * TILE_SIZE;
+    // 2^z * TILE_SIZE
+    const double shift = (1u << static_cast<unsigned>(z)) * TILE_SIZE;
+    pixelToDegree(shift, minx, miny);
+    pixelToDegree(shift, maxx, maxy);
+}
+
+// Converts a WMS tile coordinate (z,x,y) into a mercator bounding box
+void xyzToMercator(
+    const int x, const int y, const int z, double &minx, double &miny, double &maxx, double &maxy)
+{
+    using namespace util::coordinate_calculation::mercator;
+
+    xyzToWGS84(x, y, z, minx, miny, maxx, maxy);
+
+    minx = static_cast<double>(clamp(util::FloatLongitude(minx))) * DEGREE_TO_PX;
+    miny = latToY(clamp(util::FloatLatitude(miny))) * DEGREE_TO_PX;
+    maxx = static_cast<double>(clamp(util::FloatLongitude(maxx))) * DEGREE_TO_PX;
+    maxy = latToY(clamp(util::FloatLatitude(maxy))) * DEGREE_TO_PX;
+}
+
+} // ns mercato // ns mercatorr
+} // ns coordinate_calculation
+} // ns util
+} // ns osrm
diff --git a/src/util/exception.cpp b/src/util/exception.cpp
new file mode 100644
index 0000000..394d8c0
--- /dev/null
+++ b/src/util/exception.cpp
@@ -0,0 +1,21 @@
+#include "util/exception.hpp"
+
+// 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.
+
+namespace osrm
+{
+namespace util
+{
+
+void exception::anchor() const {}
+}
+}
diff --git a/src/util/fingerprint.cpp b/src/util/fingerprint.cpp
new file mode 100644
index 0000000..2764c7b
--- /dev/null
+++ b/src/util/fingerprint.cpp
@@ -0,0 +1,2 @@
+#include "util/fingerprint.hpp"
+#include "util/fingerprint_impl.hpp"
diff --git a/src/util/hilbert_value.cpp b/src/util/hilbert_value.cpp
new file mode 100644
index 0000000..a1505ee
--- /dev/null
+++ b/src/util/hilbert_value.cpp
@@ -0,0 +1,84 @@
+#include "util/hilbert_value.hpp"
+
+namespace osrm
+{
+namespace util
+{
+
+namespace
+{
+
+std::uint64_t bitInterleaving(const std::uint32_t longitude, const std::uint32_t latitude)
+{
+    std::uint64_t result = 0;
+    for (std::int8_t index = 31; index >= 0; --index)
+    {
+        result |= (latitude >> index) & 1;
+        result <<= 1;
+        result |= (longitude >> index) & 1;
+        if (0 != index)
+        {
+            result <<= 1;
+        }
+    }
+    return result;
+}
+
+void transposeCoordinate(std::uint32_t *x)
+{
+    std::uint32_t M = 1u << (32 - 1), P, Q, t;
+    int i;
+    // Inverse undo
+    for (Q = M; Q > 1; Q >>= 1)
+    {
+        P = Q - 1;
+        for (i = 0; i < 2; ++i)
+        {
+
+            const bool condition = (x[i] & Q);
+            if (condition)
+            {
+                x[0] ^= P; // invert
+            }
+            else
+            {
+                t = (x[0] ^ x[i]) & P;
+                x[0] ^= t;
+                x[i] ^= t;
+            }
+        } // exchange
+    }
+    // Gray encode
+    for (i = 1; i < 2; ++i)
+    {
+        x[i] ^= x[i - 1];
+    }
+    t = 0;
+    for (Q = M; Q > 1; Q >>= 1)
+    {
+        const bool condition = (x[2 - 1] & Q);
+        if (condition)
+        {
+            t ^= Q - 1;
+        }
+    } // check if this for loop is wrong
+    for (i = 0; i < 2; ++i)
+    {
+        x[i] ^= t;
+    }
+}
+} // anonymous ns
+
+std::uint64_t hilbertCode(const Coordinate coordinate)
+{
+    std::uint32_t location[2];
+    location[0] = static_cast<std::int32_t>(coordinate.lon) +
+                  static_cast<std::int32_t>(180 * COORDINATE_PRECISION);
+    location[1] = static_cast<std::int32_t>(coordinate.lat) +
+                  static_cast<std::int32_t>(90 * COORDINATE_PRECISION);
+
+    transposeCoordinate(location);
+    return bitInterleaving(location[0], location[1]);
+}
+}
+}
diff --git a/src/util/name_table.cpp b/src/util/name_table.cpp
new file mode 100644
index 0000000..e3d5cef
--- /dev/null
+++ b/src/util/name_table.cpp
@@ -0,0 +1,62 @@
+#include "util/name_table.hpp"
+#include "util/simple_logger.hpp"
+#include "util/exception.hpp"
+
+#include <algorithm>
+#include <limits>
+#include <fstream>
+
+#include <boost/filesystem/fstream.hpp>
+
+namespace osrm
+{
+namespace util
+{
+
+NameTable::NameTable(const std::string &filename)
+{
+    boost::filesystem::ifstream name_stream(filename, std::ios::binary);
+
+    if( !name_stream )
+        throw exception("Failed to open " + filename + " for reading.");
+
+    name_stream >> m_name_table;
+
+    unsigned number_of_chars = 0;
+    name_stream.read(reinterpret_cast<char *>(&number_of_chars), sizeof(number_of_chars));
+    if( !name_stream )
+        throw exception("Encountered invalid file, failed to read number of contained chars");
+
+    BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
+    m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element
+    name_stream.read(reinterpret_cast<char *>(&m_names_char_list[0]),
+                     number_of_chars * sizeof(m_names_char_list[0]));
+    if( !name_stream )
+        throw exception("Failed to read " + std::to_string(number_of_chars) + " characters from file.");
+
+    if (0 == m_names_char_list.size())
+    {
+        util::SimpleLogger().Write(logWARNING) << "list of street names is empty";
+    }
+}
+
+std::string NameTable::GetNameForID(const unsigned name_id) const
+{
+    if (std::numeric_limits<unsigned>::max() == name_id)
+    {
+        return "";
+    }
+    auto range = m_name_table.GetRange(name_id);
+
+    std::string result;
+    result.reserve(range.size());
+    if (range.begin() != range.end())
+    {
+        result.resize(range.back() - range.front() + 1);
+        std::copy(m_names_char_list.begin() + range.front(),
+                  m_names_char_list.begin() + range.back() + 1, result.begin());
+    }
+    return result;
+}
+} // namespace util
+} // namespace osrm
diff --git a/util/simple_logger.cpp b/src/util/simple_logger.cpp
similarity index 61%
rename from util/simple_logger.cpp
rename to src/util/simple_logger.cpp
index e3f4f8e..13ee103 100644
--- a/util/simple_logger.cpp
+++ b/src/util/simple_logger.cpp
@@ -1,31 +1,4 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "util/simple_logger.hpp"
 #ifdef _MSC_VER
 #include <io.h>
 #define isatty _isatty
@@ -38,6 +11,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <mutex>
 #include <string>
 
+namespace osrm
+{
+namespace util
+{
+
 namespace
 {
 static const char COL_RESET[]{"\x1b[0m"};
@@ -119,3 +97,5 @@ SimpleLogger::~SimpleLogger()
         }
     }
 }
+}
+}
diff --git a/taginfo.json b/taginfo.json
index 17a4f8f..4ef48de 100644
--- a/taginfo.json
+++ b/taginfo.json
@@ -6,13 +6,12 @@
         "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"
+        "contact_name": "Patrick Niklaus",
+        "contact_email": "patrick at mapbox.com"
     },
     "tags": [
         {
             "key": "highway",
-            "description": "Type of road.",
             "object_types": [ "way" ]
         },
         {
@@ -22,6 +21,23 @@
         },
         {
             "key": "oneway",
+            "value": "true",
+            "object_types": [ "way" ]
+        },
+        {
+            "key": "oneway",
+            "value": "1",
+            "object_types": [ "way" ]
+        },
+        {
+            "key": "oneway",
+            "value": "-1",
+            "object_types": [ "way" ]
+        },
+        {
+            "key": "oneway",
+            "value": "reversible",
+            "description": "is marked as non-routable because of time-dependence",
             "object_types": [ "way" ]
         },
         {
@@ -38,10 +54,127 @@
             "key": "status",
             "description": "This is used by HOT."
         },
-        {
-            "key": "access",
-            "object_types": [ "way" ]
-        },
+        {"key": "maxspeed:advisory"},
+        {"key": "maxspeed:advisory:forward"},
+        {"key": "maxspeed:advisory:backward"},
+        {"key": "bridge", "value": "movable", "description": "uses capacity and duration"},
+        {"key": "capacity:car", "description": "used for movable bridges"},
+        {"key": "side_road", "value": "yes", "description": "gets speed penalty"},
+        {"key": "side_road", "value": "rotary", "description": "gets speed penalty"},
+        {"key": "route", "object_types": ["way"]},
+        {"key": "highway", "value": "traffic_signals", "object_types": ["node"]},
+        {"key": "access", "value": "yes"},
+        {"key": "access", "value": "motorcar"},
+        {"key": "access", "value": "motor_vehicle"},
+        {"key": "access", "value": "vehicle"},
+        {"key": "access", "value": "permissive"},
+        {"key": "access", "value": "designated"},
+        {"key": "access", "value": "destination"},
+        {"key": "access", "value": "no"},
+        {"key": "access", "value": "private"},
+        {"key": "access", "value": "agricultural"},
+        {"key": "access", "value": "forestry"},
+        {"key": "access", "value": "emergency"},
+        {"key": "access", "value": "psv"},
+        {"key": "access", "value": "delivery"},
+        {"key": "maxspeed", "value": "urban"},
+        {"key": "maxspeed", "value": "rural"},
+        {"key": "maxspeed", "value": "trunk"},
+        {"key": "maxspeed", "value": "motorway"},
+        {"key": "maxspeed", "value": "ch:rural"},
+        {"key": "maxspeed", "value": "ch:trunk"},
+        {"key": "maxspeed", "value": "ch:motorway"},
+        {"key": "maxspeed", "value": "de:living_street"},
+        {"key": "maxspeed", "value": "ru:living_street"},
+        {"key": "maxspeed", "value": "ru:urban"},
+        {"key": "maxspeed", "value": "ua:urban"},
+        {"key": "maxspeed", "value": "at:rural"},
+        {"key": "maxspeed", "value": "de:rural"},
+        {"key": "maxspeed", "value": "at:trunk"},
+        {"key": "maxspeed", "value": "cz:trunk"},
+        {"key": "maxspeed", "value": "ro:trunk"},
+        {"key": "maxspeed", "value": "cz:motorway"},
+        {"key": "maxspeed", "value": "de:motorway"},
+        {"key": "maxspeed", "value": "ru:motorway"},
+        {"key": "maxspeed", "value": "gb:nsl_single"},
+        {"key": "maxspeed", "value": "gb:nsl_dual"},
+        {"key": "maxspeed", "value": "gb:motorway"},
+        {"key": "maxspeed", "value": "uk:nsl_single"},
+        {"key": "maxspeed", "value": "uk:nsl_dual"},
+        {"key": "maxspeed", "value": "uk:motorway"},
+        {"key": "smoothness", "value": "intermediate"},
+        {"key": "smoothness", "value": "bad"},
+        {"key": "smoothness", "value": "very_bad"},
+        {"key": "smoothness", "value": "horrible"},
+        {"key": "smoothness", "value": "very_horrible"},
+        {"key": "smoothness", "value": "impassable"},
+        {"key": "tracktype", "value": "grade1"},
+        {"key": "tracktype", "value": "grade2"},
+        {"key": "tracktype", "value": "grade3"},
+        {"key": "tracktype", "value": "grade4"},
+        {"key": "tracktype", "value": "grade5"},
+        {"key": "bollard", "value": "rising"},
+        {"key": "bollard", "description": "Non-rising bollards are barriers"},
+        {"key": "barrier", "value": "cattle_grid"},
+        {"key": "barrier", "value": "border_control"},
+        {"key": "barrier", "value": "checkpoint"},
+        {"key": "barrier", "value": "toll_booth"},
+        {"key": "barrier", "value": "sally_port"},
+        {"key": "barrier", "value": "gate"},
+        {"key": "barrier", "value": "lift_gate"},
+        {"key": "barrier", "value": "no"},
+        {"key": "barrier", "value": "entrance"},
+        {"key": "highway", "value": "motorway"},
+        {"key": "highway", "value": "motorway_link"},
+        {"key": "highway", "value": "trunk"},
+        {"key": "highway", "value": "trunk_link"},
+        {"key": "highway", "value": "primary"},
+        {"key": "highway", "value": "primary_link"},
+        {"key": "highway", "value": "secondary"},
+        {"key": "highway", "value": "secondary_link"},
+        {"key": "highway", "value": "tertiary"},
+        {"key": "highway", "value": "tertiary_link"},
+        {"key": "highway", "value": "unclassified"},
+        {"key": "highway", "value": "residential"},
+        {"key": "highway", "value": "living_street"},
+        {"key": "highway", "value": "service"},
+        {"key": "highway", "value": "ferry"},
+        {"key": "highway", "value": "movable"},
+        {"key": "highway", "value": "shuttle_train"},
+        {"key": "highway", "value": "default"},
+        {"key": "width", "description": "Penalties for narrow streets"},
+        {"key": "lanes", "description": "Penalties for shared single lane streets"},
+        {"key": "surface", "value": "asphalt"},
+        {"key": "surface", "value": "concrete"},
+        {"key": "surface", "value": "concrete:plates"},
+        {"key": "surface", "value": "concrete:lanes"},
+        {"key": "surface", "value": "paved"},
+        {"key": "surface", "value": "cement"},
+        {"key": "surface", "value": "compacted"},
+        {"key": "surface", "value": "fine_gravel"},
+        {"key": "surface", "value": "paving_stones"},
+        {"key": "surface", "value": "metal"},
+        {"key": "surface", "value": "bricks"},
+        {"key": "surface", "value": "grass"},
+        {"key": "surface", "value": "wood"},
+        {"key": "surface", "value": "sett"},
+        {"key": "surface", "value": "grass_paver"},
+        {"key": "surface", "value": "gravel"},
+        {"key": "surface", "value": "unpaved"},
+        {"key": "surface", "value": "ground"},
+        {"key": "surface", "value": "dirt"},
+        {"key": "surface", "value": "pebblestone"},
+        {"key": "surface", "value": "tartan"},
+        {"key": "surface", "value": "cobblestone"},
+        {"key": "surface", "value": "clay"},
+        {"key": "surface", "value": "earth"},
+        {"key": "surface", "value": "stone"},
+        {"key": "surface", "value": "rocky"},
+        {"key": "surface", "value": "sand"},
+        {"key": "surface", "value": "mud"},
+        {"key": "motorcar"},
+        {"key": "motor_vehicle"},
+        {"key": "vehicle"},
         {
             "key": "barrier"
         },
diff --git a/test/data/Makefile b/test/data/Makefile
new file mode 100755
index 0000000..0ddda31
--- /dev/null
+++ b/test/data/Makefile
@@ -0,0 +1,29 @@
+MONACO_URL:=https://s3.amazonaws.com/mapbox/osrm/testing/monaco.osm.pbf
+TOOL_ROOT:=../../build
+PROFILE_ROOT:=../../profiles
+OSRM_EXTRACT:=$(TOOL_ROOT)/osrm-extract
+OSRM_CONTRACT:=$(TOOL_ROOT)/osrm-contract
+PROFILE:=$(PROFILE_ROOT)/car.lua
+
+all: monaco.osrm.hsgr
+
+clean:
+	rm monaco.*
+
+monaco.osm.pbf:
+	wget $(MONACO_URL) -O monaco.osm.pbf
+
+monaco.osrm: monaco.osm.pbf $(PROFILE) $(OSRM_EXTRACT)
+	@echo "Verifiyng data file integrity..."
+	md5sum -c data.md5sum
+	@echo "Running osrm-extract..."
+	$(OSRM_EXTRACT) monaco.osm.pbf -p $(PROFILE)
+
+monaco.osrm.hsgr: monaco.osrm $(PROFILE) $(OSRM_CONTRACT)
+	@echo "Running osrm-contract..."
+	$(OSRM_CONTRACT) monaco.osrm
+
+checksum:
+	md5sum monaco.osm.pbf > data.md5sum
+
+.PHONY: clean checksum
diff --git a/test/data/data.md5sum b/test/data/data.md5sum
new file mode 100644
index 0000000..47151b4
--- /dev/null
+++ b/test/data/data.md5sum
@@ -0,0 +1 @@
+2b8dd9343d5e615afc9c67bcc7028a63  monaco.osm.pbf
diff --git a/third_party/variant/.clang-format b/third_party/variant/.clang-format
new file mode 100644
index 0000000..c1aca2a
--- /dev/null
+++ b/third_party/variant/.clang-format
@@ -0,0 +1,89 @@
+---
+# Mapbox.Variant C/C+ style
+Language:        Cpp
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: false
+AlignOperands:   true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: true
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+  AfterClass:      true
+  AfterControlStatement: true
+  AfterEnum:       true
+  AfterFunction:   true
+  AfterNamespace:  false
+  AfterObjCDeclaration: true
+  AfterStruct:     true
+  AfterUnion:      true
+  BeforeCatch:     true
+  BeforeElse:      true
+  IndentBraces:    false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+ColumnLimit:     0
+CommentPragmas:  '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+DisableFormat:   false
+ExperimentalAutoDetectBinPacking: false
+ForEachMacros:   [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeCategories:
+  - Regex:           '^"(llvm|llvm-c|clang|clang-c)/'
+    Priority:        2
+  - Regex:           '^(<|"(gtest|isl|json)/)'
+    Priority:        3
+  - Regex:           '.*'
+    Priority:        1
+IndentCaseLabels: false
+IndentWidth:     4
+IndentWrappedFunctionNames: false
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd:   ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Left
+ReflowComments:  true
+SortIncludes:    true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles:  false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard:        Cpp11
+TabWidth:        4
+UseTab:          Never
+...
diff --git a/third_party/variant/.gitignore b/third_party/variant/.gitignore
index 984cc2f..a9bc860 100644
--- a/third_party/variant/.gitignore
+++ b/third_party/variant/.gitignore
@@ -3,3 +3,6 @@ out
 profiling
 build
 deps
+*.gcda
+*.gcno
+.ycm_extra_conf.pyc
diff --git a/third_party/variant/.travis.yml b/third_party/variant/.travis.yml
index cd1e655..99d0b48 100644
--- a/third_party/variant/.travis.yml
+++ b/third_party/variant/.travis.yml
@@ -1,22 +1,127 @@
-language: cpp
+language: c
 
-# http://docs.travis-ci.com/user/multi-os/
-os:
-  - linux
-  - osx
+sudo: false
 
-compiler:
- - clang
- - gcc
+# Save common build configurations as shortcuts, so we can reference them later.
+addons_shortcuts:
+  addons_clang35: &clang35
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5', 'boost-latest' ]
+      packages: [ 'clang-3.5', 'libboost1.55-all-dev' ]
+  addons_clang36: &clang36
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6', 'boost-latest' ]
+      packages: [ 'clang-3.6', 'libboost1.55-all-dev' ]
+  addons_clang37: &clang37
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7', 'boost-latest' ]
+      packages: [ 'clang-3.7', 'libboost1.55-all-dev' ]
+  addons_clang38: &clang38
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise', 'boost-latest' ]
+      packages: [ 'clang-3.8', 'libboost1.55-all-dev']
+  addons_gcc47: &gcc47
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
+      packages: [ 'g++-4.7', 'libboost1.55-all-dev' ]
+  addons_gcc48: &gcc48
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
+      packages: [ 'g++-4.8', 'libboost1.55-all-dev' ]
+  addons_gcc49: &gcc49
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
+      packages: [ 'g++-4.9', 'libboost1.55-all-dev' ]
+  addons_gcc5: &gcc5
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
+      packages: [ 'g++-5', 'libboost1.55-all-dev' ]
+
+matrix:
+  include:
+    - os: osx
+      osx_image: xcode6
+      compiler: clang
+    - os: osx
+      osx_image: xcode7
+      env: TEST_GYP_BUILD=True
+      compiler: clang
+    - os: linux
+      compiler: "clang35"
+      env: CXX=clang++-3.5
+      addons: *clang35
+    - os: linux
+      compiler: "clang36"
+      env: CXX=clang++-3.6
+      addons: *clang36
+    - os: linux
+      compiler: "clang37"
+      env: CXX=clang++-3.7 COVERAGE=True
+      addons: *clang37
+    - os: linux
+      compiler: "clang38"
+      env: CXX=clang++-3.8
+      addons: *clang38
+    - os: linux
+      compiler: "clang38"
+      env: CXX=clang++-3.8 CXX_STD=c++14
+      addons: *clang38
+    - os: linux
+      compiler: "gcc47"
+      env: CXX=g++-4.7
+      addons: *gcc47
+    - os: linux
+      compiler: "gcc48"
+      env: CXX=g++-4.8
+      addons: *gcc48
+    - os: linux
+      compiler: "gcc49"
+      env: CXX=g++-4.9
+      addons: *gcc49
+    - os: linux
+      compiler: "gcc49"
+      env: CXX=g++-4.9 CXX_STD=c++14
+      addons: *gcc49
+    - os: linux
+      compiler: "gcc5"
+      env: CXX=g++-5 CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0"
+      addons: *gcc5
+    - os: linux
+      compiler: "gcc5"
+      env: CXX=g++-5 CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=1"
+      addons: *gcc5
 
 before_install:
- - true
+ - echo ${CXX}
+ - if [[ $(uname -s) == 'Linux' ]]; then
+     export PYTHONPATH=$(pwd)/.local/lib/python2.7/site-packages;
+   else
+     brew install boost;
+     export PYTHONPATH=$(pwd)/.local/lib/python/site-packages;
+   fi
+ - if [[ ${COVERAGE:-0} == 'True' ]]; then
+     PYTHONUSERBASE=$(pwd)/.local pip install --user cpp-coveralls;
+   fi
 
 install:
- - true
-
-before_script:
- - true
+ - make test
+ - make bench
+ - if [[ $(uname -s) == 'Linux' ]]; then
+     make sizes /usr/include/boost/variant.hpp;
+   else
+     make sizes `brew --prefix`/include/boost/variant.hpp;
+   fi
+ - scripts/run_compilation_failure_tests.sh
+ - if [[ ${TEST_GYP_BUILD:-0} == 'True' ]]; then
+     make clean;
+     make gyp;
+   fi
 
 script:
- - source "scripts/${TRAVIS_OS_NAME}.sh"
+ - if [[ ${COVERAGE:-0} == 'True' ]]; then
+    make clean;
+    make coverage;
+    ./out/cov-test;
+    cp unit*gc* test/;
+    ./.local/bin/cpp-coveralls -i optional.hpp -i recursive_wrapper.hpp -i variant.hpp -i variant_io.hpp --gcov-options '\-lp';
+   fi
diff --git a/third_party/variant/.ycm_extra_conf.py b/third_party/variant/.ycm_extra_conf.py
new file mode 100644
index 0000000..ba74668
--- /dev/null
+++ b/third_party/variant/.ycm_extra_conf.py
@@ -0,0 +1,40 @@
+#-----------------------------------------------------------------------------
+#
+#  Configuration for YouCompleteMe Vim plugin
+#
+#  http://valloric.github.io/YouCompleteMe/
+#
+#-----------------------------------------------------------------------------
+
+from os.path import realpath, dirname
+
+basedir = dirname(realpath(__file__))
+
+# some default flags
+# for more information install clang-3.2-doc package and
+# check UsersManual.html
+flags = [
+'-Werror',
+'-Wall',
+'-Wextra',
+'-pedantic',
+
+'-std=c++11',
+
+# '-x' and 'c++' also required
+# use 'c' for C projects
+'-x',
+'c++',
+
+# include third party libraries
+'-I.',
+]
+
+# youcompleteme is calling this function to get flags
+# You can also set database for flags. Check: JSONCompilationDatabase.html in
+# clang-3.2-doc package
+def FlagsForFile( filename ):
+  return {
+    'flags': flags,
+    'do_cache': True
+  }
diff --git a/third_party/variant/Jamroot b/third_party/variant/Jamroot
index aa21375..1e98cf5 100644
--- a/third_party/variant/Jamroot
+++ b/third_party/variant/Jamroot
@@ -1,3 +1,6 @@
+# Inofficial and incomplete build file using Boost build system.
+# You should use make unless you know what you are doing.
+
 local BOOST_DIR = "/usr/local" ;
 
 #using clang : : ;
@@ -15,7 +18,6 @@ exe variant-test
     :
     <include>$(BOOST_DIR)/include
     <include>./
-    <cxxflags>-std=c++11
     #<define>SINGLE_THREADED
     <variant>release:<cxxflags>-march=native
     ;
@@ -30,7 +32,6 @@ exe binary-visitor-test
     :
     <include>$(BOOST_DIR)/include
     <include>./
-    <cxxflags>-std=c++11
     <variant>release:<cxxflags>-march=native
     ;
 
@@ -43,7 +44,6 @@ exe recursive-wrapper-test
     :
     <include>$(BOOST_DIR)/include
     <include>./
-    <cxxflags>-std=c++11
     <variant>release:<cxxflags>-march=native
     ;
 
@@ -56,7 +56,6 @@ exe unique-ptr-test
     :
     <include>$(BOOST_DIR)/include
     <include>./
-    <cxxflags>-std=c++11
     <variant>release:<cxxflags>-march=native
     ;
 
@@ -70,6 +69,5 @@ exe reference_wrapper_test
     :
     <include>$(BOOST_DIR)/include
     <include>./
-    <cxxflags>-std=c++11
     <variant>release:<cxxflags>-march=native
     ;
diff --git a/third_party/variant/LICENSE_1_0.txt b/third_party/variant/LICENSE_1_0.txt
new file mode 100644
index 0000000..36b7cd9
--- /dev/null
+++ b/third_party/variant/LICENSE_1_0.txt
@@ -0,0 +1,23 @@
+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.
diff --git a/third_party/variant/Makefile b/third_party/variant/Makefile
index cae3d46..3665251 100644
--- a/third_party/variant/Makefile
+++ b/third_party/variant/Makefile
@@ -1,8 +1,11 @@
+
 CXX := $(CXX)
+CXX_STD ?= c++11
+
 BOOST_LIBS = -lboost_timer -lboost_system -lboost_chrono
-RELEASE_FLAGS = -O3 -DNDEBUG -finline-functions -march=native -DSINGLE_THREADED
+RELEASE_FLAGS = -O3 -DNDEBUG -march=native -DSINGLE_THREADED -fvisibility-inlines-hidden
 DEBUG_FLAGS = -O0 -g -DDEBUG -fno-inline-functions
-COMMON_FLAGS = -Wall -Wsign-compare -Wsign-conversion -Wshadow -Wunused-parameter -pedantic -fvisibility-inlines-hidden -std=c++11
+COMMON_FLAGS = -Wall -pedantic -Wextra -Wsign-compare -Wsign-conversion -Wshadow -Wunused-parameter -std=$(CXX_STD)
 CXXFLAGS := $(CXXFLAGS)
 LDFLAGS := $(LDFLAGS)
 
@@ -33,23 +36,23 @@ gyp: ./deps/gyp
 	make V=1 -C ./out tests
 	./out/Release/tests
 
-out/bench-variant-debug: Makefile test/bench_variant.cpp variant.hpp
+out/bench-variant-debug: Makefile test/bench_variant.cpp variant.hpp recursive_wrapper.hpp
 	mkdir -p ./out
-	$(CXX) -o out/bench-variant-debug test/bench_variant.cpp -I./ $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
+	$(CXX) -o out/bench-variant-debug test/bench_variant.cpp -I./ -pthreads $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
 
-out/bench-variant: Makefile test/bench_variant.cpp variant.hpp
+out/bench-variant: Makefile test/bench_variant.cpp variant.hpp recursive_wrapper.hpp
 	mkdir -p ./out
 	$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
 
-out/unique_ptr_test: Makefile test/unique_ptr_test.cpp variant.hpp
+out/unique_ptr_test: Makefile test/unique_ptr_test.cpp variant.hpp recursive_wrapper.hpp
 	mkdir -p ./out
 	$(CXX) -o out/unique_ptr_test test/unique_ptr_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
 
-out/recursive_wrapper_test: Makefile test/recursive_wrapper_test.cpp variant.hpp
+out/recursive_wrapper_test: Makefile test/recursive_wrapper_test.cpp variant.hpp recursive_wrapper.hpp
 	mkdir -p ./out
 	$(CXX) -o out/recursive_wrapper_test test/recursive_wrapper_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
 
-out/binary_visitor_test: Makefile test/binary_visitor_test.cpp variant.hpp
+out/binary_visitor_test: Makefile test/binary_visitor_test.cpp variant.hpp variant_io.hpp recursive_wrapper.hpp
 	mkdir -p ./out
 	$(CXX) -o out/binary_visitor_test test/binary_visitor_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
 
@@ -59,24 +62,30 @@ bench: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_w
 	./out/recursive_wrapper_test 100000
 	./out/binary_visitor_test 100000
 
-out/unit: Makefile test/unit.cpp test/optional_unit.cpp optional.hpp variant.hpp
+out/unit.o: Makefile test/unit.cpp
+	mkdir -p ./out
+	$(CXX) -c -o $@ test/unit.cpp -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS)
+
+out/%.o: test/t/%.cpp Makefile optional.hpp recursive_wrapper.hpp variant.hpp variant_io.hpp
+	mkdir -p ./out
+	$(CXX) -c -o $@ $< -I. -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS)
+
+out/unit: out/unit.o out/binary_visitor_1.o out/binary_visitor_2.o out/binary_visitor_3.o out/binary_visitor_4.o out/binary_visitor_5.o out/binary_visitor_6.o out/issue21.o out/mutating_visitor.o out/optional.o out/recursive_wrapper.o out/sizeof.o out/unary_visitor.o out/variant.o
 	mkdir -p ./out
-	$(CXX) -o out/unit test/unit.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
-	$(CXX) -o out/optional_unit test/optional_unit.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
+	$(CXX) -o $@ $^ $(LDFLAGS)
 
 test: out/unit
 	./out/unit
-	./out/optional_unit
 
 coverage:
 	mkdir -p ./out
-	$(CXX) -o out/cov-test --coverage test/unit.cpp -I./ $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
+	$(CXX) -o out/cov-test --coverage test/unit.cpp test/t/*.cpp -I./ -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
 
-sizes: Makefile variant.hpp
+sizes: Makefile variant.hpp recursive_wrapper.hpp
 	mkdir -p ./out
-	@$(CXX) -o ./out/variant_hello_world.out variant.hpp $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) &&  du -h ./out/variant_hello_world.out
+	@$(CXX) -o ./out/our_variant_hello_world.out variant.hpp $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) &&  du -h ./out/our_variant_hello_world.out
 	@$(CXX) -o ./out/boost_variant_hello_world.out $(RUN_ARGS) $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) &&  du -h ./out/boost_variant_hello_world.out
-	@$(CXX) -o ./out/variant_hello_world ./test/variant_hello_world.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) &&  du -h ./out/variant_hello_world
+	@$(CXX) -o ./out/our_variant_hello_world ./test/our_variant_hello_world.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) &&  du -h ./out/our_variant_hello_world
 	@$(CXX) -o ./out/boost_variant_hello_world ./test/boost_variant_hello_world.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) &&  du -h ./out/boost_variant_hello_world
 
 profile: out/bench-variant-debug
@@ -91,8 +100,9 @@ clean:
 	rm -f *gcov
 	rm -f test/unit.gc*
 	rm -f test/*gcov
+	rm -f *.gcda *.gcno
 
-pgo: out Makefile variant.hpp
+pgo: out Makefile variant.hpp recursive_wrapper.hpp
 	$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS) -pg -fprofile-generate
 	./test-variant 500000 >/dev/null 2>/dev/null
 	$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS) -fprofile-use
diff --git a/third_party/variant/README.md b/third_party/variant/README.md
index 791131d..24cdb57 100644
--- a/third_party/variant/README.md
+++ b/third_party/variant/README.md
@@ -4,11 +4,13 @@ An alternative to `boost::variant` for C++11.
 
 [![Build Status](https://secure.travis-ci.org/mapbox/variant.svg)](https://travis-ci.org/mapbox/variant)
 [![Build status](https://ci.appveyor.com/api/projects/status/v9tatx21j1k0fcgy)](https://ci.appveyor.com/project/Mapbox/variant)
-[![Coverage Status](https://coveralls.io/repos/mapbox/variant/badge.svg?branch=master)](https://coveralls.io/r/mapbox/variant?branch=master)
+[![Coverage Status](https://coveralls.io/repos/mapbox/variant/badge.svg?branch=master&service=github)](https://coveralls.io/r/mapbox/variant?branch=master)
 
-# Why use Mapbox Variant?
 
-Mapbox variant has the same speedy performance of `boost::variant` but is faster to compile, results in smaller binaries, and has no dependencies.
+## Why use Mapbox Variant?
+
+Mapbox variant has the same speedy performance of `boost::variant` but is
+faster to compile, results in smaller binaries, and has no dependencies.
 
 For example on OS X 10.9 with clang++ and libc++:
 
@@ -18,49 +20,91 @@ Size of pre-compiled header (release / debug) | 2.8/2.8 MB         | 12/15 MB
 Size of simple program linking variant (release / debug)     | 8/24 K             | 12/40 K
 Time to compile header     | 185 ms             |  675 ms
 
+(Numbers from an older version of Mapbox variant.)
+
+
+## Goals
+
+Mapbox `variant` has been a very valuable, lightweight alternative for apps
+that can use c++11 or c++14 but that do not want a boost dependency.
+Mapbox `variant` has also been useful in apps that do depend on boost, like
+mapnik, to help (slightly) with compile times and to majorly lessen dependence
+on boost in core headers. The original goal and near term goal is to maintain
+external API compatibility with `boost::variant` such that Mapbox `variant`
+can be a "drop in". At the same time the goal is to stay minimal: Only
+implement the features that are actually needed in existing software. So being
+an "incomplete" implementation is just fine.
+
+Currently Mapbox variant doesn't try to be API compatible with the upcoming
+variant standard, because the standard is not finished and it would be too much
+work. But we'll revisit this decision in the future if needed.
+
+If Mapbox variant is not for you, have a look at [these other
+implementations](doc/other_implementations.md).
 
-# Depends
+Want to know more about the upcoming standard? Have a look at our
+[overview](doc/standards_effort.md).
 
- - Compiler supporting `-std=c++11`
 
-Tested with
+## Depends
+
+ - Compiler supporting `-std=c++11` or `-std=c++14`
+
+Tested with:
 
  - g++-4.7
  - g++-4.8
- - clang++-3.4
+ - g++-4.9
+ - g++-5
  - clang++-3.5
- - Visual C++ Compiler November 2013 CTP
- - Visual C++ Compiler 2014 CTP 4
+ - clang++-3.6
+ - clang++-3.7
+ - clang++-3.8
+ - Visual Studio 2015
 
-Note: get the "2013 Nov CTP" release at http://www.microsoft.com/en-us/download/details.aspx?id=41151 and the 2014 CTP at http://www.visualstudio.com/en-us/downloads/visual-studio-14-ctp-vs.aspx
+## Usage
 
-# Usage
+There is nothing to build, just include `variant.hpp` and
+`recursive_wrapper.hpp` in your project. Include `variant_io.hpp` if you need
+the `operator<<` overload for variant.
 
-There is nothing to build, just include `variant.hpp` and `recursive_wrapper.hpp` in your project.
 
-# Tests
+## Unit Tests
 
-The tests depend on:
+On Unix systems compile and run the unit tests with `make test`.
 
- - Boost headers (for benchmarking against `boost::variant`)
- - Boost built with `--with-timer` (used for benchmark timing)
+On Windows run `scripts/build-local.bat`.
 
-On Unix systems set your boost includes and libs locations and run `make test`:
 
-    export LDFLAGS='-L/opt/boost/lib'
-    export CXXFLAGS='-I/opt/boost/include'
-    make test
+## Limitations
+
+* The `variant` can not hold references (something like `variant<int&>` is
+  not possible). You might want to try `std::reference_wrapper` instead.
+
+
+## Deprecations
+
+* The included implementation of `optional` is deprecated and will be removed
+  in a future version. See https://github.com/mapbox/variant/issues/64.
+* Old versions of the code needed visitors to derive from `static_visitor`.
+  This is not needed any more and marked as deprecated. The `static_visitor`
+  class will be removed in future versions.
+
 
-On windows do:
+## Benchmarks
 
-    vcbuild
+The benchmarks depend on:
 
-## Benchmark
+ - Boost headers (for benchmarking against `boost::variant`)
+ - Boost built with `--with-timer` (used for benchmark timing)
 
-On Unix systems run the benchmark like:
+On Unix systems set your boost includes and libs locations and run `make test`:
 
+    export LDFLAGS='-L/opt/boost/lib'
+    export CXXFLAGS='-I/opt/boost/include'
     make bench
 
+
 ## Check object sizes
 
     make sizes /path/to/boost/variant.hpp
diff --git a/third_party/variant/doc/other_implementations.md b/third_party/variant/doc/other_implementations.md
new file mode 100644
index 0000000..a0d8b9b
--- /dev/null
+++ b/third_party/variant/doc/other_implementations.md
@@ -0,0 +1,15 @@
+
+# Other implementations of variant and optional
+
+These are some other implementations of `variant` and/or `optional` types.
+They are not necessarily compatible with this implementation. This is an
+incomplete list.
+
+* [Boost Variant](http://www.boost.org/doc/libs/1_59_0/doc/html/variant.html) and [Boost Optional](http://www.boost.org/doc/libs/1_59_0/libs/optional/doc/html/index.html)
+* [Eggs Variant](http://eggs-cpp.github.io/variant/) by [Agustín Bergé](http://talesofcpp.fusionfenix.com/)
+* [anthonyw/variant](https://bitbucket.org/anthonyw/variant) (implementation of P0110R0)
+* [JasonL9000/cppcon14](https://github.com/JasonL9000/cppcon14)
+* [tomilov/variant](https://github.com/tomilov/variant)
+* [akrzemi1/Optional](https://github.com/akrzemi1/Optional)
+* [mpark/variant](https://github.com/mpark/variant)
+
diff --git a/third_party/variant/doc/standards_effort.md b/third_party/variant/doc/standards_effort.md
new file mode 100644
index 0000000..d2df488
--- /dev/null
+++ b/third_party/variant/doc/standards_effort.md
@@ -0,0 +1,28 @@
+
+# Standards efforts
+
+A `variant` type is on planned for inclusion in the C++ Standard, probably in
+C++17. Current working papers are (list extracted from [2015 working group
+papers](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/)):
+
+* 2015-09-28: Variant design review. [P0086R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0086r0.pdf)
+* 2015-09-28: Variant: a type-safe union without undefined behavior (v2) [P0087R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0087r0.pdf)
+* 2015-09-27: Variant: a type-safe union that is rarely invalid (v5) [P0088R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0088r0.pdf)
+* 2015-09-24: Simply a Strong Variant [P0093R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0093r0.html)
+* 2015-09-24: Simply a Basic Variant [P0094R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0094r0.html)
+* 2015-09-24: The Case for a Language Based Variant [P0096R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0095r0.html)
+* 2015-09-25: Implementing the strong guarantee for variant<> assignment [P0110R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0110r0.html)
+* 2015-09-24: Homogeneous interface for variant, any and optional (Revision 1) [P0032R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0032r1.pdf)
+
+Last state can be seen from
+[The Variant Saga: A happy ending?](https://isocpp.org/blog/2015/11/the-variant-saga-a-happy-ending).
+
+The `optional` type is also on the way into the standard.  The papers are:
+* 2013-10-03: A proposal to add a utility class to represent optional objects (Revision 5) [N3793](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3793.html)
+* 2014-01-18: Working Draft, Technical Specification on C++ Extensions for Library Fundamentals [N3848](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3848.html)
+
+## Older Papers
+
+* Older working drafts are: N4218 (rev 1), N4516 (rev 2), N4450 (rev 3), and [N4542](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4542.pdf) (rev 4). They have been split into P0086 (general design discussions) and P0087 and P0088 (containing two competing? specs).
+* 2015-07-28: Variant: Discriminated Union with Value Semantics [P0080R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0080r0.pdf) An alternative proposal to N4542.
+
diff --git a/third_party/variant/optional.hpp b/third_party/variant/optional.hpp
index 133e2c8..1185894 100644
--- a/third_party/variant/optional.hpp
+++ b/third_party/variant/optional.hpp
@@ -1,16 +1,18 @@
 #ifndef MAPBOX_UTIL_OPTIONAL_HPP
 #define MAPBOX_UTIL_OPTIONAL_HPP
 
+#pragma message("This implementation of optional is deprecated. See https://github.com/mapbox/variant/issues/64.")
+
 #include <type_traits>
+#include <utility>
 
 #include "variant.hpp"
 
-namespace mapbox
-{
-namespace util
-{
+namespace mapbox {
+namespace util {
 
-template <typename T> class optional
+template <typename T>
+class optional
 {
     static_assert(!std::is_reference<T>::value, "optional doesn't support references");
 
@@ -23,7 +25,7 @@ template <typename T> class optional
   public:
     optional() = default;
 
-    optional(optional const &rhs)
+    optional(optional const& rhs)
     {
         if (this != &rhs)
         { // protect against invalid self-assignment
@@ -31,23 +33,23 @@ template <typename T> class optional
         }
     }
 
-    optional(T const &v) { variant_ = v; }
+    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& get() const { return variant_.template get<T>(); }
+    T& get() { return variant_.template get<T>(); }
 
-    T const &operator*() const { return this->get(); }
+    T const& operator*() const { return this->get(); }
     T operator*() { return this->get(); }
 
-    optional &operator=(T const &v)
+    optional& operator=(T const& v)
     {
         variant_ = v;
         return *this;
     }
 
-    optional &operator=(optional const &rhs)
+    optional& operator=(optional const& rhs)
     {
         if (this != &rhs)
         {
@@ -56,14 +58,17 @@ template <typename T> class optional
         return *this;
     }
 
-    template <typename... Args> void emplace(Args &&... args)
+    template <typename... Args>
+    void emplace(Args&&... args)
     {
         variant_ = T{std::forward<Args>(args)...};
     }
 
     void reset() { variant_ = none_type{}; }
-};
-}
-}
 
-#endif
+}; // class optional
+
+} // namespace util
+} // namespace mapbox
+
+#endif // MAPBOX_UTIL_OPTIONAL_HPP
diff --git a/third_party/variant/recursive_wrapper.hpp b/third_party/variant/recursive_wrapper.hpp
index 54b2763..4becdd6 100644
--- a/third_party/variant/recursive_wrapper.hpp
+++ b/third_party/variant/recursive_wrapper.hpp
@@ -1,44 +1,72 @@
-#ifndef MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
-#define MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
-
+#ifndef MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
+#define MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
+
+// Based on variant/recursive_wrapper.hpp from boost.
+//
+// Original license:
+//
+// Copyright (c) 2002-2003
+// Eric Friedman, Itay Maman
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <cassert>
 #include <utility>
 
-namespace mapbox { namespace util {
+namespace mapbox {
+namespace util {
 
 template <typename T>
 class recursive_wrapper
 {
-public:
-    using type = T;
-private:
 
     T* p_;
 
-public:
+    void assign(T const& rhs)
+    {
+        this->get() = rhs;
+    }
+
+  public:
+    using type = T;
 
-    ~recursive_wrapper();
-    recursive_wrapper();
+    /**
+     * Default constructor default initializes the internally stored value.
+     * For POD types this means nothing is done and the storage is
+     * uninitialized.
+     *
+     * @throws std::bad_alloc if there is insufficient memory for an object
+     *         of type T.
+     * @throws any exception thrown by the default constructur of T.
+     */
+    recursive_wrapper()
+        : p_(new T){};
 
-    recursive_wrapper(recursive_wrapper const& operand);
-    recursive_wrapper(T const& operand);
-    recursive_wrapper(recursive_wrapper&& operand);
-    recursive_wrapper(T&& operand);
+    ~recursive_wrapper() noexcept { delete p_; };
 
-private:
+    recursive_wrapper(recursive_wrapper const& operand)
+        : p_(new T(operand.get())) {}
 
-    void assign(const T& rhs);
+    recursive_wrapper(T const& operand)
+        : p_(new T(operand)) {}
 
-public:
+    recursive_wrapper(recursive_wrapper&& operand)
+        : p_(new T(std::move(operand.get()))) {}
+
+    recursive_wrapper(T&& operand)
+        : p_(new T(std::move(operand))) {}
 
     inline recursive_wrapper& operator=(recursive_wrapper const& rhs)
     {
-        assign( rhs.get() );
+        assign(rhs.get());
         return *this;
     }
 
     inline recursive_wrapper& operator=(T const& rhs)
     {
-        assign( rhs );
+        assign(rhs);
         return *this;
     }
 
@@ -49,7 +77,6 @@ public:
         p_ = temp;
     }
 
-
     recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept
     {
         swap(rhs);
@@ -62,66 +89,34 @@ public:
         return *this;
     }
 
+    T& get()
+    {
+        assert(p_);
+        return *get_pointer();
+    }
 
-public:
+    T const& get() const
+    {
+        assert(p_);
+        return *get_pointer();
+    }
 
-    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))
-{
-}
+    const T* get_pointer() const { return p_; }
 
-template <typename T>
-recursive_wrapper<T>::recursive_wrapper(recursive_wrapper&& operand)
-    : p_(operand.p_)
-{
-    operand.p_ = nullptr;
-}
+    operator T const&() const { return this->get(); }
 
-template <typename T>
-recursive_wrapper<T>::recursive_wrapper(T&& operand)
-    : p_(new T( std::move(operand) ))
-{
-}
+    operator T&() { return this->get(); }
 
-template <typename T>
-void recursive_wrapper<T>::assign(const T& rhs)
-{
-    this->get() = rhs;
-}
+}; // class recursive_wrapper
 
 template <typename T>
 inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept
 {
     lhs.swap(rhs);
 }
+} // namespace util
+} // namespace mapbox
 
-}}
-
-#endif // MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
+#endif // MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
diff --git a/third_party/variant/scripts/build-appveyor.bat b/third_party/variant/scripts/build-appveyor.bat
index 9b9d7c8..bdee7ea 100644
--- a/third_party/variant/scripts/build-appveyor.bat
+++ b/third_party/variant/scripts/build-appveyor.bat
@@ -10,7 +10,7 @@ IF /I "%PLATFORM"=="x64" (
   CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
 )
 
-IF NOT EXIST deps\gyp git clone --depth 1 https://chromium.googlesource.com/external/gyp.git deps/gyp
+IF NOT EXIST deps\gyp git clone --quiet --depth 1 https://chromium.googlesource.com/external/gyp.git deps/gyp
 
 CALL deps\gyp\gyp.bat variant.gyp --depth=. ^
 -f msvs ^
diff --git a/third_party/variant/scripts/linux.sh b/third_party/variant/scripts/linux.sh
deleted file mode 100644
index f173db5..0000000
--- a/third_party/variant/scripts/linux.sh
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env bash
-
-set -e -u
-set -o pipefail
-
-# ppa for latest boost
-sudo add-apt-repository -y ppa:boost-latest/ppa
-# ppa for g++ 4.7 and 4.8
-sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
-sudo apt-get update -y
-
-# install boost headers and g++ upgrades
-sudo apt-get -y -qq install boost1.55 gcc-4.8 g++-4.8 gcc-4.7 g++-4.7
-
-if [[ "$CXX" == "clang++" ]]; then
-    echo 'running tests against clang++'
-    make test
-    make bench
-    make clean
-else
-    # run tests against g++ 4.7
-    export CXX="g++-4.7"; export CC="gcc-4.7"
-    echo 'running tests against g++ 4.7'
-    make test
-    make bench
-    make clean
-
-    # run tests against g++ 4.8
-    export CXX="g++-4.8"; export CC="gcc-4.8"
-    echo 'running tests against g++ 4.8'
-    make test
-    make bench
-    make clean
-
-fi
-
-# compare object sizes against boost::variant
-echo 'comparing object sizes to boost::variant'
-make sizes /usr/include/boost/variant.hpp
-make clean
-
-# test building with gyp
-echo 'testing build with gyp'
-make gyp
-
-# run coverage when using clang++
-if [[ $CXX == "clang++" ]]; then
-    make clean
-    make coverage
-    git status
-    ./out/cov-test
-    cp unit*gc* test/
-    sudo pip install cpp-coveralls
-    coveralls -i variant.hpp -i recursive_wrapper.hpp --gcov-options '\-lp'
-fi
-
-# set strictness back to normal
-# to avoid tripping up travis
-set +e +u
diff --git a/third_party/variant/scripts/osx.sh b/third_party/variant/scripts/osx.sh
deleted file mode 100644
index 14149ca..0000000
--- a/third_party/variant/scripts/osx.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env bash
-
-set -e -u
-set -o pipefail
-
-# install boost headers
-brew unlink boost
-brew install boost
-
-# run tests
-make test
-make bench
-make clean
-
-# compare object sizes against boost::variant
-make sizes `brew --prefix`/include/boost/variant.hpp
-make clean
-
-# test building with gyp
-make gyp
\ No newline at end of file
diff --git a/third_party/variant/scripts/run_compilation_failure_tests.sh b/third_party/variant/scripts/run_compilation_failure_tests.sh
new file mode 100755
index 0000000..c2608fe
--- /dev/null
+++ b/third_party/variant/scripts/run_compilation_failure_tests.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+#
+#  Try to compile all programs in the test/compilation_failure directory.
+#  Compilation must fail and the error message must match the pattern in the
+#  corresponding .pattern file.
+#
+
+DIR="test/compilation_failure"
+CXX=${CXX:-clang++}
+
+if [ `uname -s` = "Darwin" ]; then
+    CXXFLAGS="$CXXFLAGS -stdlib=libc++"
+fi
+
+error_msg() {
+    if [ ! -z "$1" ]; then
+        printf 'output was:\n=======\n%s\n=======\n' "$1"
+    fi
+}
+
+exit_code=0
+for test_code in $DIR/*.cpp; do
+    name=`basename $test_code .cpp`
+
+    result=`${CXX} -std=c++11 -c -o /dev/null -I. ${CXXFLAGS} ${test_code} 2>&1`
+    status=$?
+
+    if [ $status = 1 ]; then
+        expected=`sed -n -e '/@EXPECTED/s/.*: \+//p' ${test_code}`
+        if echo $result | grep -q "$expected"; then
+            echo "$name [OK]"
+        else
+            echo "$name [FAILED - wrong error message]"
+            echo "Expected error message: $expected"
+            error_msg "$result"
+            exit_code=1
+        fi
+    elif [ $status = 0 ]; then
+        echo "$name [FAILED - compile was successful]"
+        error_msg "$result"
+        exit_code=1
+    else
+        echo "$name [FAILED - unknown error in compile]"
+        error_msg "$result"
+        exit_code=1
+    fi
+done
+
+exit ${exit_code}
+
diff --git a/third_party/variant/test/bench_variant.cpp b/third_party/variant/test/bench_variant.cpp
index 474e3c3..700dac7 100644
--- a/third_party/variant/test/bench_variant.cpp
+++ b/third_party/variant/test/bench_variant.cpp
@@ -1,10 +1,16 @@
+
+#include <algorithm>
+#include <cstdlib>
 #include <iostream>
-#include <vector>
-#include <thread>
+#include <memory>
 #include <string>
+#include <thread>
 #include <utility>
-#include <boost/variant.hpp>
+#include <vector>
+
 #include <boost/timer/timer.hpp>
+#include <boost/variant.hpp>
+
 #include "variant.hpp"
 
 #define TEXT_SHORT "Test"
@@ -23,7 +29,7 @@ struct Holder
     std::vector<value_type> data;
 
     template <typename T>
-    void append_move(T && obj)
+    void append_move(T&& obj)
     {
         data.emplace_back(std::forward<T>(obj));
     }
@@ -37,49 +43,48 @@ struct Holder
 
 } // namespace test
 
-struct print : util::static_visitor<>
+struct print
 {
     template <typename T>
-    void operator() (T const& val) const
+    void operator()(T const& val) const
     {
         std::cerr << val << ":" << typeid(T).name() << std::endl;
     }
 };
 
-
 template <typename V>
 struct dummy : boost::static_visitor<>
 {
-    dummy(V & v)
+    dummy(V& v)
         : v_(v) {}
 
     template <typename T>
-    void operator() (T && val) const
+    void operator()(T&& val) const
     {
         v_ = std::move(val);
     }
-    V & v_;
+    V& v_;
 };
 
 template <typename V>
-struct dummy2 : util::static_visitor<>
+struct dummy2
 {
-    dummy2(V & v)
+    dummy2(V& v)
         : v_(v) {}
 
     template <typename T>
-    void operator() (T && val) const
+    void operator()(T&& val) const
     {
         v_ = std::move(val);
     }
-    V & v_;
+    V& v_;
 };
 
 void run_boost_test(std::size_t runs)
 {
     test::Holder<boost::variant<int, double, std::string>> h;
     h.data.reserve(runs);
-    for (std::size_t i=0; i< runs; ++i)
+    for (std::size_t i = 0; i < runs; ++i)
     {
         h.append_move(std::string(TEXT_SHORT));
         h.append_move(std::string(TEXT_LONG));
@@ -99,7 +104,7 @@ void run_variant_test(std::size_t runs)
 {
     test::Holder<util::variant<int, double, std::string>> h;
     h.data.reserve(runs);
-    for (std::size_t i=0; i< runs; ++i)
+    for (std::size_t i = 0; i < runs; ++i)
     {
         h.append_move(std::string(TEXT_SHORT));
         h.append_move(std::string(TEXT_LONG));
@@ -111,13 +116,13 @@ void run_variant_test(std::size_t runs)
     for (auto const& v2 : h.data)
     {
         dummy2<util::variant<int, double, std::string>> d(v);
-        util::apply_visitor (d, v2);
+        util::apply_visitor(d, v2);
     }
 }
 
-int main (int argc, char** argv)
+int main(int argc, char** argv)
 {
-    if (argc!=2)
+    if (argc != 2)
     {
         std::cerr << "Usage:" << argv[0] << " <num-runs>" << std::endl;
         return 1;
@@ -154,11 +159,11 @@ int main (int argc, char** argv)
             thread_group tg;
             std::cerr << "custom variant: ";
             boost::timer::auto_cpu_timer timer;
-            for (std::size_t i=0; i<THREADS; ++i)
+            for (std::size_t i = 0; i < THREADS; ++i)
             {
                 tg.emplace_back(new std::thread(run_variant_test, NUM_RUNS));
             }
-            std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
+            std::for_each(tg.begin(), tg.end(), [](value_type& t) {if (t->joinable()) t->join(); });
         }
 
         {
@@ -167,15 +172,14 @@ int main (int argc, char** argv)
             thread_group tg;
             std::cerr << "boost variant: ";
             boost::timer::auto_cpu_timer timer;
-            for (std::size_t i=0; i<THREADS; ++i)
+            for (std::size_t i = 0; i < THREADS; ++i)
             {
                 tg.emplace_back(new std::thread(run_boost_test, NUM_RUNS));
             }
-            std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
+            std::for_each(tg.begin(), tg.end(), [](value_type& t) {if (t->joinable()) t->join(); });
         }
     }
 #endif
 
-
     return EXIT_SUCCESS;
 }
diff --git a/third_party/variant/test/binary_visitor_test.cpp b/third_party/variant/test/binary_visitor_test.cpp
index de2a30e..fa0f2ea 100644
--- a/third_party/variant/test/binary_visitor_test.cpp
+++ b/third_party/variant/test/binary_visitor_test.cpp
@@ -1,13 +1,14 @@
+
+#include <algorithm>
 #include <cstdint>
+#include <cstdlib>
 #include <iostream>
-#include <vector>
-#include <thread>
-#include <string>
 #include <sstream>
-#include <utility>
+#include <string>
 #include <type_traits>
-#include <boost/variant.hpp>
-#include <boost/timer/timer.hpp>
+#include <utility>
+#include <vector>
+
 #include "variant.hpp"
 #include "variant_io.hpp"
 
@@ -16,12 +17,14 @@ using namespace mapbox;
 namespace test {
 
 template <typename T>
-struct string_to_number {};
+struct string_to_number
+{
+};
 
 template <>
 struct string_to_number<double>
 {
-    double operator() (std::string const& str) const
+    double operator()(std::string const& str) const
     {
         return std::stod(str);
     }
@@ -30,7 +33,7 @@ struct string_to_number<double>
 template <>
 struct string_to_number<std::int64_t>
 {
-    std::int64_t operator() (std::string const& str) const
+    std::int64_t operator()(std::string const& str) const
     {
         return std::stoll(str);
     }
@@ -39,7 +42,7 @@ struct string_to_number<std::int64_t>
 template <>
 struct string_to_number<std::uint64_t>
 {
-    std::uint64_t operator() (std::string const& str) const
+    std::uint64_t operator()(std::string const& str) const
     {
         return std::stoull(str);
     }
@@ -48,7 +51,7 @@ struct string_to_number<std::uint64_t>
 template <>
 struct string_to_number<bool>
 {
-    bool operator() (std::string const& str) const
+    bool operator()(std::string const& str) const
     {
         bool result;
         std::istringstream(str) >> std::boolalpha >> result;
@@ -56,28 +59,28 @@ struct string_to_number<bool>
     }
 };
 
-struct javascript_equal_visitor : util::static_visitor<bool>
+struct javascript_equal_visitor
 {
     template <typename T>
-    bool operator() (T lhs, T rhs) const
+    bool operator()(T lhs, T rhs) const
     {
         return lhs == rhs;
     }
 
     template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
-    bool operator() (T lhs, std::string const& rhs) const
+    bool operator()(T lhs, std::string const& rhs) const
     {
         return lhs == string_to_number<T>()(rhs);
     }
 
     template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
-    bool operator() (std::string const& lhs, T rhs) const
+    bool operator()(std::string const& lhs, T rhs) const
     {
         return string_to_number<T>()(lhs) == rhs;
     }
 
     template <typename T0, typename T1>
-    bool operator() (T0 lhs, T1 rhs) const
+    bool operator()(T0 lhs, T1 rhs) const
     {
         return lhs == static_cast<T0>(rhs);
     }
@@ -89,7 +92,7 @@ struct javascript_equal
     javascript_equal(T const& lhs)
         : lhs_(lhs) {}
 
-    bool operator() (T const& rhs) const
+    bool operator()(T const& rhs) const
     {
         return util::apply_visitor(test::javascript_equal_visitor(), lhs_, rhs);
     }
@@ -98,7 +101,7 @@ struct javascript_equal
 
 } // namespace test
 
-int main (/*int argc, char** argv*/)
+int main()
 {
     typedef util::variant<bool, std::int64_t, std::uint64_t, double, std::string> variant_type;
     variant_type v0(3.14159);
@@ -108,7 +111,6 @@ int main (/*int argc, char** argv*/)
     std::cerr << v0 << " == " << v1 << " -> "
               << std::boolalpha << util::apply_visitor(test::javascript_equal_visitor(), v0, v1) << std::endl;
 
-
     std::vector<variant_type> vec;
 
     vec.emplace_back(std::string("1"));
diff --git a/third_party/variant/test/boost_variant_hello_world.cpp b/third_party/variant/test/boost_variant_hello_world.cpp
index 0d0925a..fdb200e 100644
--- a/third_party/variant/test/boost_variant_hello_world.cpp
+++ b/third_party/variant/test/boost_variant_hello_world.cpp
@@ -1,17 +1,18 @@
 #include <boost/variant.hpp>
-#include <cstdint>
+
 #include <stdexcept>
 
 struct check : boost::static_visitor<>
 {
     template <typename T>
-    void operator() (T const& val) const
+    void operator()(T const& val) const
     {
         if (val != 0) throw std::runtime_error("invalid");
     }
 };
 
-int main() {
+int main()
+{
     typedef boost::variant<bool, int, double> variant_type;
     variant_type v(0);
     boost::apply_visitor(check(), v);
diff --git a/third_party/variant/test/catch.hpp b/third_party/variant/test/catch.hpp
deleted file mode 100644
index 057c82e..0000000
--- a/third_party/variant/test/catch.hpp
+++ /dev/null
@@ -1,8683 +0,0 @@
-/*
- *  CATCH v1.0 build 45 (master branch)
- *  Generated: 2014-05-19 18:22:42.461908
- *  ----------------------------------------------------------
- *  This file has been merged from multiple headers. Please don't edit it directly
- *  Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
- *
- *  Distributed under the Boost Software License, Version 1.0. (See accompanying
- *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- */
-#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
-#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
-
-#define TWOBLUECUBES_CATCH_HPP_INCLUDED
-
-#ifdef __clang__
-#pragma clang diagnostic ignored "-Wglobal-constructors"
-#pragma clang diagnostic ignored "-Wvariadic-macros"
-#pragma clang diagnostic ignored "-Wc99-extensions"
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wpadded"
-#pragma clang diagnostic ignored "-Wc++98-compat"
-#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
-#endif
-
-#ifdef CATCH_CONFIG_MAIN
-#  define CATCH_CONFIG_RUNNER
-#endif
-
-#ifdef CATCH_CONFIG_RUNNER
-#  ifndef CLARA_CONFIG_MAIN
-#    define CLARA_CONFIG_MAIN_NOT_DEFINED
-#    define CLARA_CONFIG_MAIN
-#  endif
-#endif
-
-// #included from: internal/catch_notimplemented_exception.h
-#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
-
-// #included from: catch_common.h
-#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
-
-#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
-#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
-#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
-
-#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
-#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
-
-#include <sstream>
-#include <stdexcept>
-#include <algorithm>
-
-// #included from: catch_compiler_capabilities.h
-#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
-
-// Much of the following code is based on Boost (1.53)
-
-#ifdef __clang__
-
-#  if __has_feature(cxx_nullptr)
-#    define CATCH_CONFIG_CPP11_NULLPTR
-#  endif
-
-#  if __has_feature(cxx_noexcept)
-#    define CATCH_CONFIG_CPP11_NOEXCEPT
-#  endif
-
-#endif // __clang__
-
-////////////////////////////////////////////////////////////////////////////////
-// Borland
-#ifdef __BORLANDC__
-
-#if (__BORLANDC__ > 0x582 )
-//#define CATCH_CONFIG_SFINAE // Not confirmed
-#endif
-
-#endif // __BORLANDC__
-
-////////////////////////////////////////////////////////////////////////////////
-// EDG
-#ifdef __EDG_VERSION__
-
-#if (__EDG_VERSION__ > 238 )
-//#define CATCH_CONFIG_SFINAE // Not confirmed
-#endif
-
-#endif // __EDG_VERSION__
-
-////////////////////////////////////////////////////////////////////////////////
-// Digital Mars
-#ifdef __DMC__
-
-#if (__DMC__ > 0x840 )
-//#define CATCH_CONFIG_SFINAE // Not confirmed
-#endif
-
-#endif // __DMC__
-
-////////////////////////////////////////////////////////////////////////////////
-// GCC
-#ifdef __GNUC__
-
-#if __GNUC__ < 3
-
-#if (__GNUC_MINOR__ >= 96 )
-//#define CATCH_CONFIG_SFINAE
-#endif
-
-#elif __GNUC__ >= 3
-
-// #define CATCH_CONFIG_SFINAE // Taking this out completely for now
-
-#endif // __GNUC__ < 3
-
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) )
-
-#define CATCH_CONFIG_CPP11_NULLPTR
-#endif
-
-#endif // __GNUC__
-
-////////////////////////////////////////////////////////////////////////////////
-// Visual C++
-#ifdef _MSC_VER
-
-#if (_MSC_VER >= 1310 ) // (VC++ 7.0+)
-//#define CATCH_CONFIG_SFINAE // Not confirmed
-#endif
-
-#endif // _MSC_VER
-
-// Use variadic macros if the compiler supports them
-#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
-    ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \
-    ( defined __GNUC__ && __GNUC__ >= 3 ) || \
-    ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L )
-
-#ifndef CATCH_CONFIG_NO_VARIADIC_MACROS
-#define CATCH_CONFIG_VARIADIC_MACROS
-#endif
-
-#endif
-
-////////////////////////////////////////////////////////////////////////////////
-// C++ language feature support
-
-// detect language version:
-#if (__cplusplus == 201103L)
-#  define CATCH_CPP11
-#  define CATCH_CPP11_OR_GREATER
-#elif (__cplusplus >= 201103L)
-#  define CATCH_CPP11_OR_GREATER
-#endif
-
-// noexcept support:
-#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
-#  define CATCH_NOEXCEPT noexcept
-#  define CATCH_NOEXCEPT_IS(x) noexcept(x)
-#else
-#  define CATCH_NOEXCEPT throw()
-#  define CATCH_NOEXCEPT_IS(x)
-#endif
-
-namespace Catch {
-
-    class NonCopyable {
-        NonCopyable( NonCopyable const& );
-        void operator = ( NonCopyable const& );
-    protected:
-        NonCopyable() {}
-        virtual ~NonCopyable();
-    };
-
-    class SafeBool {
-    public:
-        typedef void (SafeBool::*type)() const;
-
-        static type makeSafe( bool value ) {
-            return value ? &SafeBool::trueValue : 0;
-        }
-    private:
-        void trueValue() const {}
-    };
-
-    template<typename ContainerT>
-    inline void deleteAll( ContainerT& container ) {
-        typename ContainerT::const_iterator it = container.begin();
-        typename ContainerT::const_iterator itEnd = container.end();
-        for(; it != itEnd; ++it )
-            delete *it;
-    }
-    template<typename AssociativeContainerT>
-    inline void deleteAllValues( AssociativeContainerT& container ) {
-        typename AssociativeContainerT::const_iterator it = container.begin();
-        typename AssociativeContainerT::const_iterator itEnd = container.end();
-        for(; it != itEnd; ++it )
-            delete it->second;
-    }
-
-    bool startsWith( std::string const& s, std::string const& prefix );
-    bool endsWith( std::string const& s, std::string const& suffix );
-    bool contains( std::string const& s, std::string const& infix );
-    void toLowerInPlace( std::string& s );
-    std::string toLower( std::string const& s );
-    std::string trim( std::string const& str );
-
-    struct pluralise {
-        pluralise( std::size_t count, std::string const& label );
-
-        friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
-
-        std::size_t m_count;
-        std::string m_label;
-    };
-
-    struct SourceLineInfo {
-
-        SourceLineInfo();
-        SourceLineInfo( char const* _file, std::size_t _line );
-        SourceLineInfo( SourceLineInfo const& other );
-#  ifdef CATCH_CPP11_OR_GREATER
-        SourceLineInfo( SourceLineInfo && )                  = default;
-        SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
-        SourceLineInfo& operator = ( SourceLineInfo && )     = default;
-#  endif
-        bool empty() const;
-        bool operator == ( SourceLineInfo const& other ) const;
-
-        std::string file;
-        std::size_t line;
-    };
-
-    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
-
-    // This is just here to avoid compiler warnings with macro constants and boolean literals
-    inline bool isTrue( bool value ){ return value; }
-
-    void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
-
-    // Use this in variadic streaming macros to allow
-    //    >> +StreamEndStop
-    // as well as
-    //    >> stuff +StreamEndStop
-    struct StreamEndStop {
-        std::string operator+() {
-            return std::string();
-        }
-    };
-    template<typename T>
-    T const& operator + ( T const& value, StreamEndStop ) {
-        return value;
-    }
-}
-
-#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
-#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
-
-#include <ostream>
-
-namespace Catch {
-
-    class NotImplementedException : public std::exception
-    {
-    public:
-        NotImplementedException( SourceLineInfo const& lineInfo );
-
-        virtual ~NotImplementedException() CATCH_NOEXCEPT {}
-
-        virtual const char* what() const CATCH_NOEXCEPT;
-
-    private:
-        std::string m_what;
-        SourceLineInfo m_lineInfo;
-    };
-
-} // end namespace Catch
-
-///////////////////////////////////////////////////////////////////////////////
-#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO )
-
-// #included from: internal/catch_context.h
-#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
-
-// #included from: catch_interfaces_generators.h
-#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
-
-#include <string>
-
-namespace Catch {
-
-    struct IGeneratorInfo {
-        virtual ~IGeneratorInfo();
-        virtual bool moveNext() = 0;
-        virtual std::size_t getCurrentIndex() const = 0;
-    };
-
-    struct IGeneratorsForTest {
-        virtual ~IGeneratorsForTest();
-
-        virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0;
-        virtual bool moveNext() = 0;
-    };
-
-    IGeneratorsForTest* createGeneratorsForTest();
-
-} // end namespace Catch
-
-// #included from: catch_ptr.hpp
-#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wpadded"
-#endif
-
-namespace Catch {
-
-    // An intrusive reference counting smart pointer.
-    // T must implement addRef() and release() methods
-    // typically implementing the IShared interface
-    template<typename T>
-    class Ptr {
-    public:
-        Ptr() : m_p( NULL ){}
-        Ptr( T* p ) : m_p( p ){
-            if( m_p )
-                m_p->addRef();
-        }
-        Ptr( Ptr const& other ) : m_p( other.m_p ){
-            if( m_p )
-                m_p->addRef();
-        }
-        ~Ptr(){
-            if( m_p )
-                m_p->release();
-        }
-        void reset() {
-            if( m_p )
-                m_p->release();
-            m_p = NULL;
-        }
-        Ptr& operator = ( T* p ){
-            Ptr temp( p );
-            swap( temp );
-            return *this;
-        }
-        Ptr& operator = ( Ptr const& other ){
-            Ptr temp( other );
-            swap( temp );
-            return *this;
-        }
-        void swap( Ptr& other ) { std::swap( m_p, other.m_p ); }
-        T* get() { return m_p; }
-        const T* get() const{ return m_p; }
-        T& operator*() const { return *m_p; }
-        T* operator->() const { return m_p; }
-        bool operator !() const { return m_p == NULL; }
-        operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); }
-
-    private:
-        T* m_p;
-    };
-
-    struct IShared : NonCopyable {
-        virtual ~IShared();
-        virtual void addRef() const = 0;
-        virtual void release() const = 0;
-    };
-
-    template<typename T = IShared>
-    struct SharedImpl : T {
-
-        SharedImpl() : m_rc( 0 ){}
-
-        virtual void addRef() const {
-            ++m_rc;
-        }
-        virtual void release() const {
-            if( --m_rc == 0 )
-                delete this;
-        }
-
-        mutable unsigned int m_rc;
-    };
-
-} // end namespace Catch
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-#include <memory>
-#include <vector>
-#include <stdlib.h>
-
-namespace Catch {
-
-    class TestCase;
-    class Stream;
-    struct IResultCapture;
-    struct IRunner;
-    struct IGeneratorsForTest;
-    struct IConfig;
-
-    struct IContext
-    {
-        virtual ~IContext();
-
-        virtual IResultCapture& getResultCapture() = 0;
-        virtual IRunner& getRunner() = 0;
-        virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0;
-        virtual bool advanceGeneratorsForCurrentTest() = 0;
-        virtual Ptr<IConfig const> getConfig() const = 0;
-    };
-
-    struct IMutableContext : IContext
-    {
-        virtual ~IMutableContext();
-        virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
-        virtual void setRunner( IRunner* runner ) = 0;
-        virtual void setConfig( Ptr<IConfig const> const& config ) = 0;
-    };
-
-    IContext& getCurrentContext();
-    IMutableContext& getCurrentMutableContext();
-    void cleanUpContext();
-    Stream createStream( std::string const& streamName );
-
-}
-
-// #included from: internal/catch_test_registry.hpp
-#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
-
-// #included from: catch_interfaces_testcase.h
-#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
-
-#include <vector>
-
-namespace Catch {
-
-    class TestSpec;
-
-    struct ITestCase : IShared {
-        virtual void invoke () const = 0;
-    protected:
-        virtual ~ITestCase();
-    };
-
-    class TestCase;
-    struct IConfig;
-
-    struct ITestCaseRegistry {
-        virtual ~ITestCaseRegistry();
-        virtual std::vector<TestCase> const& getAllTests() const = 0;
-        virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases ) const = 0;
-
-    };
-}
-
-namespace Catch {
-
-template<typename C>
-class MethodTestCase : public SharedImpl<ITestCase> {
-
-public:
-    MethodTestCase( void (C::*method)() ) : m_method( method ) {}
-
-    virtual void invoke() const {
-        C obj;
-        (obj.*m_method)();
-    }
-
-private:
-    virtual ~MethodTestCase() {}
-
-    void (C::*m_method)();
-};
-
-typedef void(*TestFunction)();
-
-struct NameAndDesc {
-    NameAndDesc( const char* _name = "", const char* _description= "" )
-    : name( _name ), description( _description )
-    {}
-
-    const char* name;
-    const char* description;
-};
-
-struct AutoReg {
-
-    AutoReg(    TestFunction function,
-                SourceLineInfo const& lineInfo,
-                NameAndDesc const& nameAndDesc );
-
-    template<typename C>
-    AutoReg(    void (C::*method)(),
-                char const* className,
-                NameAndDesc const& nameAndDesc,
-                SourceLineInfo const& lineInfo ) {
-        registerTestCase(   new MethodTestCase<C>( method ),
-                            className,
-                            nameAndDesc,
-                            lineInfo );
-    }
-
-    void registerTestCase(  ITestCase* testCase,
-                            char const* className,
-                            NameAndDesc const& nameAndDesc,
-                            SourceLineInfo const& lineInfo );
-
-    ~AutoReg();
-
-private:
-    AutoReg( AutoReg const& );
-    void operator= ( AutoReg const& );
-};
-
-} // end namespace Catch
-
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
-    ///////////////////////////////////////////////////////////////////////////////
-    #define INTERNAL_CATCH_TESTCASE( ... ) \
-        static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
-        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME(  ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\
-        static void INTERNAL_CATCH_UNIQUE_NAME(  ____C_A_T_C_H____T_E_S_T____ )()
-
-    ///////////////////////////////////////////////////////////////////////////////
-    #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
-        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); }
-
-    ///////////////////////////////////////////////////////////////////////////////
-    #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\
-        namespace{ \
-            struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
-                void test(); \
-            }; \
-            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
-        } \
-        void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
-
-#else
-    ///////////////////////////////////////////////////////////////////////////////
-    #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
-        static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
-        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME(  ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
-        static void INTERNAL_CATCH_UNIQUE_NAME(  ____C_A_T_C_H____T_E_S_T____ )()
-
-    ///////////////////////////////////////////////////////////////////////////////
-    #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
-        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); }
-
-    ///////////////////////////////////////////////////////////////////////////////
-    #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
-        namespace{ \
-            struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
-                void test(); \
-            }; \
-            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
-        } \
-        void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
-
-#endif
-
-// #included from: internal/catch_capture.hpp
-#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
-
-// #included from: catch_expression_decomposer.hpp
-#define TWOBLUECUBES_CATCH_EXPRESSION_DECOMPOSER_HPP_INCLUDED
-
-// #included from: catch_expression_lhs.hpp
-#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
-
-// #included from: catch_expressionresult_builder.h
-#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_BUILDER_H_INCLUDED
-
-// #included from: catch_tostring.h
-#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
-
-// #included from: catch_sfinae.hpp
-#define TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED
-
-// Try to detect if the current compiler supports SFINAE
-
-namespace Catch {
-
-    struct TrueType {
-        static const bool value = true;
-        typedef void Enable;
-        char sizer[1];
-    };
-    struct FalseType {
-        static const bool value = false;
-        typedef void Disable;
-        char sizer[2];
-    };
-
-#ifdef CATCH_CONFIG_SFINAE
-
-    template<bool> struct NotABooleanExpression;
-
-    template<bool c> struct If : NotABooleanExpression<c> {};
-    template<> struct If<true> : TrueType {};
-    template<> struct If<false> : FalseType {};
-
-    template<int size> struct SizedIf;
-    template<> struct SizedIf<sizeof(TrueType)> : TrueType {};
-    template<> struct SizedIf<sizeof(FalseType)> : FalseType {};
-
-#endif // CATCH_CONFIG_SFINAE
-
-} // end namespace Catch
-
-#include <sstream>
-#include <iomanip>
-#include <limits>
-#include <vector>
-#include <cstddef>
-
-#ifdef __OBJC__
-// #included from: catch_objc_arc.hpp
-#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED
-
-#import <Foundation/Foundation.h>
-
-#ifdef __has_feature
-#define CATCH_ARC_ENABLED __has_feature(objc_arc)
-#else
-#define CATCH_ARC_ENABLED 0
-#endif
-
-void arcSafeRelease( NSObject* obj );
-id performOptionalSelector( id obj, SEL sel );
-
-#if !CATCH_ARC_ENABLED
-inline void arcSafeRelease( NSObject* obj ) {
-    [obj release];
-}
-inline id performOptionalSelector( id obj, SEL sel ) {
-    if( [obj respondsToSelector: sel] )
-        return [obj performSelector: sel];
-    return nil;
-}
-#define CATCH_UNSAFE_UNRETAINED
-#define CATCH_ARC_STRONG
-#else
-inline void arcSafeRelease( NSObject* ){}
-inline id performOptionalSelector( id obj, SEL sel ) {
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
-#endif
-    if( [obj respondsToSelector: sel] )
-        return [obj performSelector: sel];
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-    return nil;
-}
-#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
-#define CATCH_ARC_STRONG __strong
-#endif
-
-#endif
-
-namespace Catch {
-namespace Detail {
-
-// SFINAE is currently disabled by default for all compilers.
-// If the non SFINAE version of IsStreamInsertable is ambiguous for you
-// and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE
-#ifdef CATCH_CONFIG_SFINAE
-
-    template<typename T>
-    class IsStreamInsertableHelper {
-        template<int N> struct TrueIfSizeable : TrueType {};
-
-        template<typename T2>
-        static TrueIfSizeable<sizeof((*(std::ostream*)0) << *((T2 const*)0))> dummy(T2*);
-        static FalseType dummy(...);
-
-    public:
-        typedef SizedIf<sizeof(dummy((T*)0))> type;
-    };
-
-    template<typename T>
-    struct IsStreamInsertable : IsStreamInsertableHelper<T>::type {};
-
-#else
-
-    struct BorgType {
-        template<typename T> BorgType( T const& );
-    };
-
-    TrueType& testStreamable( std::ostream& );
-    FalseType testStreamable( FalseType );
-
-    FalseType operator<<( std::ostream const&, BorgType const& );
-
-    template<typename T>
-    struct IsStreamInsertable {
-        static std::ostream &s;
-        static T  const&t;
-        enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) };
-    };
-
-#endif
-
-    template<bool C>
-    struct StringMakerBase {
-        template<typename T>
-        static std::string convert( T const& ) { return "{?}"; }
-    };
-
-    template<>
-    struct StringMakerBase<true> {
-        template<typename T>
-        static std::string convert( T const& _value ) {
-            std::ostringstream oss;
-            oss << _value;
-            return oss.str();
-        }
-    };
-
-    struct Endianness {
-        enum Arch { Big, Little };
-
-        static Arch which() {
-            union _{
-                int asInt;
-                char asChar[sizeof (int)];
-            } u;
-
-            u.asInt = 1;
-            return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
-        }
-    };
-
-    // Writes the raw memory into a string, considering endianness
-    template<typename T>
-    std::string rawMemoryToString( T value ) {
-        union _ {
-            T typedValue;
-            unsigned char bytes[sizeof(T)];
-        } u;
-
-        u.typedValue = value;
-
-        std::ostringstream oss;
-        oss << "0x";
-
-        int i = 0, end = sizeof(T), inc = 1;
-        if( Endianness::which() == Endianness::Little ) {
-            i = end-1;
-            end = inc = -1;
-        }
-        for( ; i != end; i += inc )
-            oss << std::hex << std::setw(2) << std::setfill('0') << (unsigned int)u.bytes[i];
-        return oss.str();
-    }
-
-} // end namespace Detail
-
-template<typename T>
-std::string toString( T const& value );
-
-template<typename T>
-struct StringMaker :
-    Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {};
-
-template<typename T>
-struct StringMaker<T*> {
-    template<typename U>
-    static std::string convert( U* p ) {
-        if( !p )
-            return INTERNAL_CATCH_STRINGIFY( NULL );
-        else
-            return Detail::rawMemoryToString( p );
-    }
-};
-
-template<typename R, typename C>
-struct StringMaker<R C::*> {
-    static std::string convert( R C::* p ) {
-        if( !p )
-            return INTERNAL_CATCH_STRINGIFY( NULL );
-        else
-            return Detail::rawMemoryToString( p );
-    }
-};
-
-namespace Detail {
-    template<typename InputIterator>
-    std::string rangeToString( InputIterator first, InputIterator last );
-}
-
-template<typename T, typename Allocator>
-struct StringMaker<std::vector<T, Allocator> > {
-    static std::string convert( std::vector<T,Allocator> const& v ) {
-        return Detail::rangeToString( v.begin(), v.end() );
-    }
-};
-
-namespace Detail {
-    template<typename T>
-    std::string makeString( T const& value ) {
-        return StringMaker<T>::convert( value );
-    }
-} // end namespace Detail
-
-/// \brief converts any type to a string
-///
-/// The default template forwards on to ostringstream - except when an
-/// ostringstream overload does not exist - in which case it attempts to detect
-/// that and writes {?}.
-/// Overload (not specialise) this template for custom typs that you don't want
-/// to provide an ostream overload for.
-template<typename T>
-std::string toString( T const& value ) {
-    return StringMaker<T>::convert( value );
-}
-
-// Built in overloads
-
-std::string toString( std::string const& value );
-std::string toString( std::wstring const& value );
-std::string toString( const char* const value );
-std::string toString( char* const value );
-std::string toString( int value );
-std::string toString( unsigned long value );
-std::string toString( unsigned int value );
-std::string toString( const double value );
-std::string toString( bool value );
-std::string toString( char value );
-std::string toString( signed char value );
-std::string toString( unsigned char value );
-
-#ifdef CATCH_CONFIG_CPP11_NULLPTR
-std::string toString( std::nullptr_t );
-#endif
-
-#ifdef __OBJC__
-    std::string toString( NSString const * const& nsstring );
-    std::string toString( NSString * CATCH_ARC_STRONG const& nsstring );
-    std::string toString( NSObject* const& nsObject );
-#endif
-
-    namespace Detail {
-    template<typename InputIterator>
-    std::string rangeToString( InputIterator first, InputIterator last ) {
-        std::ostringstream oss;
-        oss << "{ ";
-        if( first != last ) {
-            oss << toString( *first );
-            for( ++first ; first != last ; ++first ) {
-                oss << ", " << toString( *first );
-            }
-        }
-        oss << " }";
-        return oss.str();
-    }
-}
-
-} // end namespace Catch
-
-// #included from: catch_assertionresult.h
-#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
-
-#include <string>
-// #included from: catch_result_type.h
-#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
-
-namespace Catch {
-
-    // ResultWas::OfType enum
-    struct ResultWas { enum OfType {
-        Unknown = -1,
-        Ok = 0,
-        Info = 1,
-        Warning = 2,
-
-        FailureBit = 0x10,
-
-        ExpressionFailed = FailureBit | 1,
-        ExplicitFailure = FailureBit | 2,
-
-        Exception = 0x100 | FailureBit,
-
-        ThrewException = Exception | 1,
-        DidntThrowException = Exception | 2
-
-    }; };
-
-    inline bool isOk( ResultWas::OfType resultType ) {
-        return ( resultType & ResultWas::FailureBit ) == 0;
-    }
-    inline bool isJustInfo( int flags ) {
-        return flags == ResultWas::Info;
-    }
-
-    // ResultAction::Value enum
-    struct ResultAction { enum Value {
-        None,
-        Failed = 1, // Failure - but no debug break if Debug bit not set
-        Debug = 2,  // If this bit is set, invoke the debugger
-        Abort = 4   // Test run should abort
-    }; };
-
-    // ResultDisposition::Flags enum
-    struct ResultDisposition { enum Flags {
-            Normal = 0x00,
-
-            ContinueOnFailure = 0x01,   // Failures fail test, but execution continues
-            NegateResult = 0x02,        // Prefix expressiom with !
-            SuppressFail = 0x04         // Failures are reported but do not fail the test
-    }; };
-
-    inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
-        return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
-    }
-
-    inline bool shouldContinueOnFailure( int flags )    { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
-    inline bool shouldNegate( int flags )               { return ( flags & ResultDisposition::NegateResult ) != 0; }
-    inline bool shouldSuppressFailure( int flags )      { return ( flags & ResultDisposition::SuppressFail ) != 0; }
-
-} // end namespace Catch
-
-
-namespace Catch {
-
-    struct AssertionInfo
-    {
-        AssertionInfo() {}
-        AssertionInfo(  std::string const& _macroName,
-                        SourceLineInfo const& _lineInfo,
-                        std::string const& _capturedExpression,
-                        ResultDisposition::Flags _resultDisposition );
-
-        std::string macroName;
-        SourceLineInfo lineInfo;
-        std::string capturedExpression;
-        ResultDisposition::Flags resultDisposition;
-    };
-
-    struct AssertionResultData
-    {
-        AssertionResultData() : resultType( ResultWas::Unknown ) {}
-
-        std::string reconstructedExpression;
-        std::string message;
-        ResultWas::OfType resultType;
-    };
-
-    class AssertionResult {
-    public:
-        AssertionResult();
-        AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
-        ~AssertionResult();
-#  ifdef CATCH_CPP11_OR_GREATER
-         AssertionResult( AssertionResult const& )              = default;
-         AssertionResult( AssertionResult && )                  = default;
-         AssertionResult& operator = ( AssertionResult const& ) = default;
-         AssertionResult& operator = ( AssertionResult && )     = default;
-#  endif
-
-        bool isOk() const;
-        bool succeeded() const;
-        ResultWas::OfType getResultType() const;
-        bool hasExpression() const;
-        bool hasMessage() const;
-        std::string getExpression() const;
-        std::string getExpressionInMacro() const;
-        bool hasExpandedExpression() const;
-        std::string getExpandedExpression() const;
-        std::string getMessage() const;
-        SourceLineInfo getSourceInfo() const;
-        std::string getTestMacroName() const;
-
-    protected:
-        AssertionInfo m_info;
-        AssertionResultData m_resultData;
-    };
-
-} // end namespace Catch
-
-// #included from: catch_evaluate.hpp
-#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
-
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
-#endif
-
-#include <cstddef>
-
-namespace Catch {
-namespace Internal {
-
-    enum Operator {
-        IsEqualTo,
-        IsNotEqualTo,
-        IsLessThan,
-        IsGreaterThan,
-        IsLessThanOrEqualTo,
-        IsGreaterThanOrEqualTo
-    };
-
-    template<Operator Op> struct OperatorTraits             { static const char* getName(){ return "*error*"; } };
-    template<> struct OperatorTraits<IsEqualTo>             { static const char* getName(){ return "=="; } };
-    template<> struct OperatorTraits<IsNotEqualTo>          { static const char* getName(){ return "!="; } };
-    template<> struct OperatorTraits<IsLessThan>            { static const char* getName(){ return "<"; } };
-    template<> struct OperatorTraits<IsGreaterThan>         { static const char* getName(){ return ">"; } };
-    template<> struct OperatorTraits<IsLessThanOrEqualTo>   { static const char* getName(){ return "<="; } };
-    template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
-
-    template<typename T>
-    inline T& opCast(T const& t) { return const_cast<T&>(t); }
-
-// nullptr_t support based on pull request #154 from Konstantin Baumann
-#ifdef CATCH_CONFIG_CPP11_NULLPTR
-    inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; }
-#endif // CATCH_CONFIG_CPP11_NULLPTR
-
-    // So the compare overloads can be operator agnostic we convey the operator as a template
-    // enum, which is used to specialise an Evaluator for doing the comparison.
-    template<typename T1, typename T2, Operator Op>
-    class Evaluator{};
-
-    template<typename T1, typename T2>
-    struct Evaluator<T1, T2, IsEqualTo> {
-        static bool evaluate( T1 const& lhs, T2 const& rhs) {
-            return opCast( lhs ) ==  opCast( rhs );
-        }
-    };
-    template<typename T1, typename T2>
-    struct Evaluator<T1, T2, IsNotEqualTo> {
-        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
-            return opCast( lhs ) != opCast( rhs );
-        }
-    };
-    template<typename T1, typename T2>
-    struct Evaluator<T1, T2, IsLessThan> {
-        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
-            return opCast( lhs ) < opCast( rhs );
-        }
-    };
-    template<typename T1, typename T2>
-    struct Evaluator<T1, T2, IsGreaterThan> {
-        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
-            return opCast( lhs ) > opCast( rhs );
-        }
-    };
-    template<typename T1, typename T2>
-    struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
-        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
-            return opCast( lhs ) >= opCast( rhs );
-        }
-    };
-    template<typename T1, typename T2>
-    struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
-        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
-            return opCast( lhs ) <= opCast( rhs );
-        }
-    };
-
-    template<Operator Op, typename T1, typename T2>
-    bool applyEvaluator( T1 const& lhs, T2 const& rhs ) {
-        return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
-    }
-
-    // This level of indirection allows us to specialise for integer types
-    // to avoid signed/ unsigned warnings
-
-    // "base" overload
-    template<Operator Op, typename T1, typename T2>
-    bool compare( T1 const& lhs, T2 const& rhs ) {
-        return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
-    }
-
-    // unsigned X to int
-    template<Operator Op> bool compare( unsigned int lhs, int rhs ) {
-        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
-    }
-    template<Operator Op> bool compare( unsigned long lhs, int rhs ) {
-        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
-    }
-    template<Operator Op> bool compare( unsigned char lhs, int rhs ) {
-        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
-    }
-
-    // unsigned X to long
-    template<Operator Op> bool compare( unsigned int lhs, long rhs ) {
-        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
-    }
-    template<Operator Op> bool compare( unsigned long lhs, long rhs ) {
-        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
-    }
-    template<Operator Op> bool compare( unsigned char lhs, long rhs ) {
-        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
-    }
-
-    // int to unsigned X
-    template<Operator Op> bool compare( int lhs, unsigned int rhs ) {
-        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
-    }
-    template<Operator Op> bool compare( int lhs, unsigned long rhs ) {
-        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
-    }
-    template<Operator Op> bool compare( int lhs, unsigned char rhs ) {
-        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
-    }
-
-    // long to unsigned X
-    template<Operator Op> bool compare( long lhs, unsigned int rhs ) {
-        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
-    }
-    template<Operator Op> bool compare( long lhs, unsigned long rhs ) {
-        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
-    }
-    template<Operator Op> bool compare( long lhs, unsigned char rhs ) {
-        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
-    }
-
-    // pointer to long (when comparing against NULL)
-    template<Operator Op, typename T> bool compare( long lhs, T* rhs ) {
-        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
-    }
-    template<Operator Op, typename T> bool compare( T* lhs, long rhs ) {
-        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
-    }
-
-    // pointer to int (when comparing against NULL)
-    template<Operator Op, typename T> bool compare( int lhs, T* rhs ) {
-        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
-    }
-    template<Operator Op, typename T> bool compare( T* lhs, int rhs ) {
-        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
-    }
-
-#ifdef CATCH_CONFIG_CPP11_NULLPTR
-    // pointer to nullptr_t (when comparing against nullptr)
-    template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) {
-        return Evaluator<T*, T*, Op>::evaluate( NULL, rhs );
-    }
-    template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) {
-        return Evaluator<T*, T*, Op>::evaluate( lhs, NULL );
-    }
-#endif // CATCH_CONFIG_CPP11_NULLPTR
-
-} // end of namespace Internal
-} // end of namespace Catch
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-namespace Catch {
-
-struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
-
-// Wraps the (stringised versions of) the lhs, operator and rhs of an expression - as well as
-// the result of evaluating it. This is used to build an AssertionResult object
-class ExpressionResultBuilder {
-public:
-
-    ExpressionResultBuilder( ResultWas::OfType resultType = ResultWas::Unknown );
-    ExpressionResultBuilder( ExpressionResultBuilder const& other );
-    ExpressionResultBuilder& operator=(ExpressionResultBuilder const& other );
-
-    ExpressionResultBuilder& setResultType( ResultWas::OfType result );
-    ExpressionResultBuilder& setResultType( bool result );
-    ExpressionResultBuilder& setLhs( std::string const& lhs );
-    ExpressionResultBuilder& setRhs( std::string const& rhs );
-    ExpressionResultBuilder& setOp( std::string const& op );
-
-    ExpressionResultBuilder& endExpression( ResultDisposition::Flags resultDisposition );
-
-    template<typename T>
-    ExpressionResultBuilder& operator << ( T const& value ) {
-        m_stream << value;
-        return *this;
-    }
-
-    std::string reconstructExpression( AssertionInfo const& info ) const;
-
-    AssertionResult buildResult( AssertionInfo const& info ) const;
-
-    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
-    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
-
-private:
-    AssertionResultData m_data;
-    struct ExprComponents {
-        ExprComponents() : shouldNegate( false ) {}
-        bool shouldNegate;
-        std::string lhs, rhs, op;
-    } m_exprComponents;
-    std::ostringstream m_stream;
-};
-
-} // end namespace Catch
-
-namespace Catch {
-
-// Wraps the LHS of an expression and captures the operator and RHS (if any) -
-// wrapping them all in an ExpressionResultBuilder object
-template<typename T>
-class ExpressionLhs {
-    ExpressionLhs& operator = ( ExpressionLhs const& );
-#  ifdef CATCH_CPP11_OR_GREATER
-    ExpressionLhs& operator = ( ExpressionLhs && ) = delete;
-#  endif
-
-public:
-    ExpressionLhs( T lhs ) : m_lhs( lhs ) {}
-#  ifdef CATCH_CPP11_OR_GREATER
-    ExpressionLhs( ExpressionLhs const& ) = default;
-    ExpressionLhs( ExpressionLhs && )     = default;
-#  endif
-
-    template<typename RhsT>
-    ExpressionResultBuilder& operator == ( RhsT const& rhs ) {
-        return captureExpression<Internal::IsEqualTo>( rhs );
-    }
-
-    template<typename RhsT>
-    ExpressionResultBuilder& operator != ( RhsT const& rhs ) {
-        return captureExpression<Internal::IsNotEqualTo>( rhs );
-    }
-
-    template<typename RhsT>
-    ExpressionResultBuilder& operator < ( RhsT const& rhs ) {
-        return captureExpression<Internal::IsLessThan>( rhs );
-    }
-
-    template<typename RhsT>
-    ExpressionResultBuilder& operator > ( RhsT const& rhs ) {
-        return captureExpression<Internal::IsGreaterThan>( rhs );
-    }
-
-    template<typename RhsT>
-    ExpressionResultBuilder& operator <= ( RhsT const& rhs ) {
-        return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
-    }
-
-    template<typename RhsT>
-    ExpressionResultBuilder& operator >= ( RhsT const& rhs ) {
-        return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
-    }
-
-    ExpressionResultBuilder& operator == ( bool rhs ) {
-        return captureExpression<Internal::IsEqualTo>( rhs );
-    }
-
-    ExpressionResultBuilder& operator != ( bool rhs ) {
-        return captureExpression<Internal::IsNotEqualTo>( rhs );
-    }
-
-    ExpressionResultBuilder& endExpression( ResultDisposition::Flags resultDisposition ) {
-        bool value = m_lhs ? true : false;
-        return m_result
-            .setLhs( Catch::toString( value ) )
-            .setResultType( value )
-            .endExpression( resultDisposition );
-    }
-
-    // Only simple binary expressions are allowed on the LHS.
-    // If more complex compositions are required then place the sub expression in parentheses
-    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& );
-    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& );
-    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& );
-    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& );
-    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
-    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
-
-private:
-    template<Internal::Operator Op, typename RhsT>
-    ExpressionResultBuilder& captureExpression( RhsT const& rhs ) {
-        return m_result
-            .setResultType( Internal::compare<Op>( m_lhs, rhs ) )
-            .setLhs( Catch::toString( m_lhs ) )
-            .setRhs( Catch::toString( rhs ) )
-            .setOp( Internal::OperatorTraits<Op>::getName() );
-    }
-
-private:
-    ExpressionResultBuilder m_result;
-    T m_lhs;
-};
-
-} // end namespace Catch
-
-namespace Catch {
-
-// Captures the LHS of the expression and wraps it in an Expression Lhs object
-class ExpressionDecomposer {
-public:
-
-    template<typename T>
-    ExpressionLhs<T const&> operator->* ( T const& operand ) {
-        return ExpressionLhs<T const&>( operand );
-    }
-
-    ExpressionLhs<bool> operator->* ( bool value ) {
-        return ExpressionLhs<bool>( value );
-    }
-};
-
-} // end namespace Catch
-
-// #included from: catch_message.h
-#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
-
-#include <string>
-
-namespace Catch {
-
-    struct MessageInfo {
-        MessageInfo(    std::string const& _macroName,
-                        SourceLineInfo const& _lineInfo,
-                        ResultWas::OfType _type );
-
-        std::string macroName;
-        SourceLineInfo lineInfo;
-        ResultWas::OfType type;
-        std::string message;
-        unsigned int sequence;
-
-        bool operator == ( MessageInfo const& other ) const {
-            return sequence == other.sequence;
-        }
-        bool operator < ( MessageInfo const& other ) const {
-            return sequence < other.sequence;
-        }
-    private:
-        static unsigned int globalCount;
-    };
-
-    struct MessageBuilder {
-        MessageBuilder( std::string const& macroName,
-                        SourceLineInfo const& lineInfo,
-                        ResultWas::OfType type )
-        : m_info( macroName, lineInfo, type )
-        {}
-
-        template<typename T>
-        MessageBuilder& operator << ( T const& value ) {
-            m_stream << value;
-            return *this;
-        }
-
-        MessageInfo m_info;
-        std::ostringstream m_stream;
-    };
-
-    class ScopedMessage {
-    public:
-        ScopedMessage( MessageBuilder const& builder );
-        ~ScopedMessage();
-
-        MessageInfo m_info;
-    };
-
-} // end namespace Catch
-
-// #included from: catch_interfaces_capture.h
-#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
-
-#include <string>
-
-namespace Catch {
-
-    class TestCase;
-    class ExpressionResultBuilder;
-    class AssertionResult;
-    struct AssertionInfo;
-    struct SectionInfo;
-    struct MessageInfo;
-    class ScopedMessageBuilder;
-    struct Counts;
-
-    struct IResultCapture {
-
-        virtual ~IResultCapture();
-
-        virtual void assertionEnded( AssertionResult const& result ) = 0;
-        virtual bool sectionStarted(    SectionInfo const& sectionInfo,
-                                        Counts& assertions ) = 0;
-        virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0;
-        virtual void pushScopedMessage( MessageInfo const& message ) = 0;
-        virtual void popScopedMessage( MessageInfo const& message ) = 0;
-
-        virtual bool shouldDebugBreak() const = 0;
-
-        virtual ResultAction::Value acceptExpression( ExpressionResultBuilder const& assertionResult, AssertionInfo const& assertionInfo ) = 0;
-
-        virtual std::string getCurrentTestName() const = 0;
-        virtual const AssertionResult* getLastResult() const = 0;
-    };
-}
-
-// #included from: catch_debugger.h
-#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
-
-// #included from: catch_platform.h
-#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
-
-#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
-#define CATCH_PLATFORM_MAC
-#elif  defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
-#define CATCH_PLATFORM_IPHONE
-#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
-#define CATCH_PLATFORM_WINDOWS
-#endif
-
-#include <string>
-
-namespace Catch{
-
-    bool isDebuggerActive();
-    void writeToDebugConsole( std::string const& text );
-}
-
-#ifdef CATCH_PLATFORM_MAC
-
-    // The following code snippet based on:
-    // http://cocoawithlove.com/2008/03/break-into-debugger.html
-    #ifdef DEBUG
-        #if defined(__ppc64__) || defined(__ppc__)
-            #define CATCH_BREAK_INTO_DEBUGGER() \
-                if( Catch::isDebuggerActive() ) { \
-                    __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
-                    : : : "memory","r0","r3","r4" ); \
-                }
-        #else
-            #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );}
-        #endif
-    #endif
-
-#elif defined(_MSC_VER)
-    #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); }
-#elif defined(__MINGW32__)
-    extern "C" __declspec(dllimport) void __stdcall DebugBreak();
-    #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); }
-#endif
-
-#ifndef CATCH_BREAK_INTO_DEBUGGER
-#define CATCH_BREAK_INTO_DEBUGGER() Catch::isTrue( true );
-#endif
-
-// #included from: catch_interfaces_registry_hub.h
-#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
-
-#include <string>
-
-namespace Catch {
-
-    class TestCase;
-    struct ITestCaseRegistry;
-    struct IExceptionTranslatorRegistry;
-    struct IExceptionTranslator;
-    struct IReporterRegistry;
-    struct IReporterFactory;
-
-    struct IRegistryHub {
-        virtual ~IRegistryHub();
-
-        virtual IReporterRegistry const& getReporterRegistry() const = 0;
-        virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
-        virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
-    };
-
-    struct IMutableRegistryHub {
-        virtual ~IMutableRegistryHub();
-        virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0;
-        virtual void registerTest( TestCase const& testInfo ) = 0;
-        virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
-    };
-
-    IRegistryHub& getRegistryHub();
-    IMutableRegistryHub& getMutableRegistryHub();
-    void cleanUp();
-    std::string translateActiveException();
-
-}
-
-// #included from: catch_interfaces_config.h
-#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
-
-#include <iostream>
-#include <string>
-#include <vector>
-
-namespace Catch {
-
-    struct Verbosity { enum Level {
-        NoOutput = 0,
-        Quiet,
-        Normal
-    }; };
-
-    struct WarnAbout { enum What {
-        Nothing = 0x00,
-        NoAssertions = 0x01
-    }; };
-
-    struct ShowDurations { enum OrNot {
-        DefaultForReporter,
-        Always,
-        Never
-    }; };
-
-    class TestSpec;
-
-    struct IConfig : IShared {
-
-        virtual ~IConfig();
-
-        virtual bool allowThrows() const = 0;
-        virtual std::ostream& stream() const = 0;
-        virtual std::string name() const = 0;
-        virtual bool includeSuccessfulResults() const = 0;
-        virtual bool shouldDebugBreak() const = 0;
-        virtual bool warnAboutMissingAssertions() const = 0;
-        virtual int abortAfter() const = 0;
-        virtual bool showInvisibles() const = 0;
-        virtual ShowDurations::OrNot showDurations() const = 0;
-        virtual TestSpec const& testSpec() const = 0;
-    };
-}
-
-#include <ostream>
-
-namespace Catch {
-
-    inline IResultCapture& getResultCapture() {
-        return getCurrentContext().getResultCapture();
-    }
-
-    template<typename MatcherT>
-    ExpressionResultBuilder expressionResultBuilderFromMatcher( MatcherT const& matcher,
-                                                                std::string const& matcherCallAsString ) {
-        std::string matcherAsString = matcher.toString();
-        if( matcherAsString == "{?}" )
-            matcherAsString = matcherCallAsString;
-        return ExpressionResultBuilder()
-            .setRhs( matcherAsString )
-            .setOp( "matches" );
-    }
-
-    template<typename MatcherT, typename ArgT>
-    ExpressionResultBuilder expressionResultBuilderFromMatcher( MatcherT const& matcher,
-                                                                ArgT const& arg,
-                                                                std::string const& matcherCallAsString ) {
-        return expressionResultBuilderFromMatcher( matcher, matcherCallAsString )
-            .setLhs( Catch::toString( arg ) )
-            .setResultType( matcher.match( arg ) );
-    }
-
-    template<typename MatcherT, typename ArgT>
-    ExpressionResultBuilder expressionResultBuilderFromMatcher( MatcherT const& matcher,
-                                                                ArgT* arg,
-                                                                std::string const& matcherCallAsString ) {
-        return expressionResultBuilderFromMatcher( matcher, matcherCallAsString )
-            .setLhs( Catch::toString( arg ) )
-            .setResultType( matcher.match( arg ) );
-    }
-
-struct TestFailureException{};
-
-} // end namespace Catch
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_ACCEPT_EXPR( evaluatedExpr, resultDisposition, originalExpr ) \
-    if( Catch::ResultAction::Value internal_catch_action = Catch::getResultCapture().acceptExpression( evaluatedExpr, __assertionInfo )  ) { \
-        if( internal_catch_action & Catch::ResultAction::Debug ) CATCH_BREAK_INTO_DEBUGGER(); \
-        if( internal_catch_action & Catch::ResultAction::Abort ) throw Catch::TestFailureException(); \
-        if( !Catch::shouldContinueOnFailure( resultDisposition ) ) throw Catch::TestFailureException(); \
-        Catch::isTrue( false && originalExpr ); \
-    }
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \
-    do { \
-        Catch::AssertionInfo __assertionInfo( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
-        try { \
-            INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionDecomposer()->*expr ).endExpression( resultDisposition ), resultDisposition, expr ); \
-        } catch( Catch::TestFailureException& ) { \
-            throw; \
-        } catch( ... ) { \
-            INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::ThrewException ) << Catch::translateActiveException(), \
-                Catch::ResultDisposition::Normal, expr ); \
-        } \
-    } while( Catch::isTrue( false ) )
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
-    INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
-    if( Catch::getResultCapture().getLastResult()->succeeded() )
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \
-    INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
-    if( !Catch::getResultCapture().getLastResult()->succeeded() )
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \
-    do { \
-        Catch::AssertionInfo __assertionInfo( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
-        try { \
-            expr; \
-            INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::Ok ), resultDisposition, false ); \
-        } \
-        catch( ... ) { \
-            INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::ThrewException ) << Catch::translateActiveException(), resultDisposition, false ); \
-        } \
-} while( Catch::isTrue( false ) )
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_THROWS_IMPL( expr, exceptionType, resultDisposition ) \
-    try { \
-        if( Catch::getCurrentContext().getConfig()->allowThrows() ) { \
-            expr; \
-            INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::DidntThrowException ), resultDisposition, false ); \
-        } \
-    } \
-    catch( Catch::TestFailureException& ) { \
-        throw; \
-    } \
-    catch( exceptionType ) { \
-        INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::Ok ), resultDisposition, false ); \
-    }
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_THROWS( expr, exceptionType, resultDisposition, macroName ) \
-    do { \
-        Catch::AssertionInfo __assertionInfo( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
-        INTERNAL_CATCH_THROWS_IMPL( expr, exceptionType, resultDisposition ) \
-    } while( Catch::isTrue( false ) )
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \
-    do { \
-        Catch::AssertionInfo __assertionInfo( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
-        INTERNAL_CATCH_THROWS_IMPL( expr, exceptionType, resultDisposition ) \
-        catch( ... ) { \
-            INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionResultBuilder( Catch::ResultWas::ThrewException ) << Catch::translateActiveException() ), \
-                resultDisposition | Catch::ResultDisposition::ContinueOnFailure, false ); \
-        } \
-    } while( Catch::isTrue( false ) )
-
-///////////////////////////////////////////////////////////////////////////////
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
-    #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \
-        do { \
-            Catch::AssertionInfo __assertionInfo( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
-            INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( messageType ) << __VA_ARGS__ +::Catch::StreamEndStop(), resultDisposition, true ) \
-        } while( Catch::isTrue( false ) )
-#else
-    #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \
-        do { \
-            Catch::AssertionInfo __assertionInfo( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
-            INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( messageType ) << log, resultDisposition, true ) \
-        } while( Catch::isTrue( false ) )
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_INFO( log, macroName ) \
-    Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \
-    do { \
-        Catch::AssertionInfo __assertionInfo( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \
-        try { \
-            INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::expressionResultBuilderFromMatcher( ::Catch::Matchers::matcher, arg, #matcher ) ), resultDisposition, false ); \
-        } catch( Catch::TestFailureException& ) { \
-            throw; \
-        } catch( ... ) { \
-            INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionResultBuilder( Catch::ResultWas::ThrewException ) << Catch::translateActiveException() ), \
-                resultDisposition | Catch::ResultDisposition::ContinueOnFailure, false ); \
-        } \
-    } while( Catch::isTrue( false ) )
-
-// #included from: internal/catch_section.h
-#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
-
-// #included from: catch_section_info.h
-#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
-
-namespace Catch {
-
-    struct SectionInfo {
-        SectionInfo(    std::string const& _name,
-                        std::string const& _description,
-                        SourceLineInfo const& _lineInfo )
-        :   name( _name ),
-            description( _description ),
-            lineInfo( _lineInfo )
-        {}
-
-        std::string name;
-        std::string description;
-        SourceLineInfo lineInfo;
-    };
-
-} // end namespace Catch
-
-// #included from: catch_totals.hpp
-#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
-
-#include <cstddef>
-
-namespace Catch {
-
-    struct Counts {
-        Counts() : passed( 0 ), failed( 0 ) {}
-
-        Counts operator - ( Counts const& other ) const {
-            Counts diff;
-            diff.passed = passed - other.passed;
-            diff.failed = failed - other.failed;
-            return diff;
-        }
-        Counts& operator += ( Counts const& other ) {
-            passed += other.passed;
-            failed += other.failed;
-            return *this;
-        }
-
-        std::size_t total() const {
-            return passed + failed;
-        }
-
-        std::size_t passed;
-        std::size_t failed;
-    };
-
-    struct Totals {
-
-        Totals operator - ( Totals const& other ) const {
-            Totals diff;
-            diff.assertions = assertions - other.assertions;
-            diff.testCases = testCases - other.testCases;
-            return diff;
-        }
-
-        Totals delta( Totals const& prevTotals ) const {
-            Totals diff = *this - prevTotals;
-            if( diff.assertions.failed > 0 )
-                ++diff.testCases.failed;
-            else
-                ++diff.testCases.passed;
-            return diff;
-        }
-
-        Totals& operator += ( Totals const& other ) {
-            assertions += other.assertions;
-            testCases += other.testCases;
-            return *this;
-        }
-
-        Counts assertions;
-        Counts testCases;
-    };
-}
-
-// #included from: catch_timer.h
-#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
-
-#ifdef CATCH_PLATFORM_WINDOWS
-typedef unsigned long long uint64_t;
-#else
-#include <stdint.h>
-#endif
-
-namespace Catch {
-
-    class Timer {
-    public:
-        Timer() : m_ticks( 0 ) {}
-        void start();
-        unsigned int getElapsedNanoseconds() const;
-        unsigned int getElapsedMilliseconds() const;
-        double getElapsedSeconds() const;
-
-    private:
-        uint64_t m_ticks;
-    };
-
-} // namespace Catch
-
-#include <string>
-
-namespace Catch {
-
-    class Section {
-    public:
-        Section(    SourceLineInfo const& lineInfo,
-                    std::string const& name,
-                    std::string const& description = "" );
-        ~Section();
-#  ifdef CATCH_CPP11_OR_GREATER
-        Section( Section const& )              = default;
-        Section( Section && )                  = default;
-        Section& operator = ( Section const& ) = default;
-        Section& operator = ( Section && )     = default;
-#  endif
-
-        // This indicates whether the section should be executed or not
-        operator bool();
-
-    private:
-
-        SectionInfo m_info;
-
-        std::string m_name;
-        Counts m_assertions;
-        bool m_sectionIncluded;
-        Timer m_timer;
-    };
-
-} // end namespace Catch
-
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
-    #define INTERNAL_CATCH_SECTION( ... ) \
-        if( Catch::Section INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
-#else
-    #define INTERNAL_CATCH_SECTION( name, desc ) \
-        if( Catch::Section INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, name, desc ) )
-#endif
-
-// #included from: internal/catch_generators.hpp
-#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
-
-#include <iterator>
-#include <vector>
-#include <string>
-#include <stdlib.h>
-
-namespace Catch {
-
-template<typename T>
-struct IGenerator {
-    virtual ~IGenerator() {}
-    virtual T getValue( std::size_t index ) const = 0;
-    virtual std::size_t size () const = 0;
-};
-
-template<typename T>
-class BetweenGenerator : public IGenerator<T> {
-public:
-    BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){}
-
-    virtual T getValue( std::size_t index ) const {
-        return m_from+static_cast<int>( index );
-    }
-
-    virtual std::size_t size() const {
-        return static_cast<std::size_t>( 1+m_to-m_from );
-    }
-
-private:
-
-    T m_from;
-    T m_to;
-};
-
-template<typename T>
-class ValuesGenerator : public IGenerator<T> {
-public:
-    ValuesGenerator(){}
-
-    void add( T value ) {
-        m_values.push_back( value );
-    }
-
-    virtual T getValue( std::size_t index ) const {
-        return m_values[index];
-    }
-
-    virtual std::size_t size() const {
-        return m_values.size();
-    }
-
-private:
-    std::vector<T> m_values;
-};
-
-template<typename T>
-class CompositeGenerator {
-public:
-    CompositeGenerator() : m_totalSize( 0 ) {}
-
-    // *** Move semantics, similar to auto_ptr ***
-    CompositeGenerator( CompositeGenerator& other )
-    :   m_fileInfo( other.m_fileInfo ),
-        m_totalSize( 0 )
-    {
-        move( other );
-    }
-
-    CompositeGenerator& setFileInfo( const char* fileInfo ) {
-        m_fileInfo = fileInfo;
-        return *this;
-    }
-
-    ~CompositeGenerator() {
-        deleteAll( m_composed );
-    }
-
-    operator T () const {
-        size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
-
-        typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
-        typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
-        for( size_t index = 0; it != itEnd; ++it )
-        {
-            const IGenerator<T>* generator = *it;
-            if( overallIndex >= index && overallIndex < index + generator->size() )
-            {
-                return generator->getValue( overallIndex-index );
-            }
-            index += generator->size();
-        }
-        CATCH_INTERNAL_ERROR( "Indexed past end of generated range" );
-        return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
-    }
-
-    void add( const IGenerator<T>* generator ) {
-        m_totalSize += generator->size();
-        m_composed.push_back( generator );
-    }
-
-    CompositeGenerator& then( CompositeGenerator& other ) {
-        move( other );
-        return *this;
-    }
-
-    CompositeGenerator& then( T value ) {
-        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
-        valuesGen->add( value );
-        add( valuesGen );
-        return *this;
-    }
-
-private:
-
-    void move( CompositeGenerator& other ) {
-        std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) );
-        m_totalSize += other.m_totalSize;
-        other.m_composed.clear();
-    }
-
-    std::vector<const IGenerator<T>*> m_composed;
-    std::string m_fileInfo;
-    size_t m_totalSize;
-};
-
-namespace Generators
-{
-    template<typename T>
-    CompositeGenerator<T> between( T from, T to ) {
-        CompositeGenerator<T> generators;
-        generators.add( new BetweenGenerator<T>( from, to ) );
-        return generators;
-    }
-
-    template<typename T>
-    CompositeGenerator<T> values( T val1, T val2 ) {
-        CompositeGenerator<T> generators;
-        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
-        valuesGen->add( val1 );
-        valuesGen->add( val2 );
-        generators.add( valuesGen );
-        return generators;
-    }
-
-    template<typename T>
-    CompositeGenerator<T> values( T val1, T val2, T val3 ){
-        CompositeGenerator<T> generators;
-        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
-        valuesGen->add( val1 );
-        valuesGen->add( val2 );
-        valuesGen->add( val3 );
-        generators.add( valuesGen );
-        return generators;
-    }
-
-    template<typename T>
-    CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) {
-        CompositeGenerator<T> generators;
-        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
-        valuesGen->add( val1 );
-        valuesGen->add( val2 );
-        valuesGen->add( val3 );
-        valuesGen->add( val4 );
-        generators.add( valuesGen );
-        return generators;
-    }
-
-} // end namespace Generators
-
-using namespace Generators;
-
-} // end namespace Catch
-
-#define INTERNAL_CATCH_LINESTR2( line ) #line
-#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line )
-
-#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" )
-
-// #included from: internal/catch_interfaces_exception.h
-#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
-
-#include <string>
-
-namespace Catch {
-
-    typedef std::string(*exceptionTranslateFunction)();
-
-    struct IExceptionTranslator {
-        virtual ~IExceptionTranslator();
-        virtual std::string translate() const = 0;
-    };
-
-    struct IExceptionTranslatorRegistry {
-        virtual ~IExceptionTranslatorRegistry();
-
-        virtual std::string translateActiveException() const = 0;
-    };
-
-    class ExceptionTranslatorRegistrar {
-        template<typename T>
-        class ExceptionTranslator : public IExceptionTranslator {
-        public:
-
-            ExceptionTranslator( std::string(*translateFunction)( T& ) )
-            : m_translateFunction( translateFunction )
-            {}
-
-            virtual std::string translate() const {
-                try {
-                    throw;
-                }
-                catch( T& ex ) {
-                    return m_translateFunction( ex );
-                }
-            }
-
-        protected:
-            std::string(*m_translateFunction)( T& );
-        };
-
-    public:
-        template<typename T>
-        ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
-            getMutableRegistryHub().registerTranslator
-                ( new ExceptionTranslator<T>( translateFunction ) );
-        }
-    };
-}
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \
-    static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \
-    namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\
-    static std::string INTERNAL_CATCH_UNIQUE_NAME(  catch_internal_ExceptionTranslator )( signature )
-
-// #included from: internal/catch_approx.hpp
-#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
-
-#include <cmath>
-#include <limits>
-
-namespace Catch {
-namespace Detail {
-
-    class Approx {
-    public:
-        explicit Approx ( double value )
-        :   m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
-            m_scale( 1.0 ),
-            m_value( value )
-        {}
-
-        Approx( Approx const& other )
-        :   m_epsilon( other.m_epsilon ),
-            m_scale( other.m_scale ),
-            m_value( other.m_value )
-        {}
-
-        static Approx custom() {
-            return Approx( 0 );
-        }
-
-        Approx operator()( double value ) {
-            Approx approx( value );
-            approx.epsilon( m_epsilon );
-            approx.scale( m_scale );
-            return approx;
-        }
-
-        friend bool operator == ( double lhs, Approx const& rhs ) {
-            // Thanks to Richard Harris for his help refining this formula
-            return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) );
-        }
-
-        friend bool operator == ( Approx const& lhs, double rhs ) {
-            return operator==( rhs, lhs );
-        }
-
-        friend bool operator != ( double lhs, Approx const& rhs ) {
-            return !operator==( lhs, rhs );
-        }
-
-        friend bool operator != ( Approx const& lhs, double rhs ) {
-            return !operator==( rhs, lhs );
-        }
-
-        Approx& epsilon( double newEpsilon ) {
-            m_epsilon = newEpsilon;
-            return *this;
-        }
-
-        Approx& scale( double newScale ) {
-            m_scale = newScale;
-            return *this;
-        }
-
-        std::string toString() const {
-            std::ostringstream oss;
-            oss << "Approx( " << Catch::toString( m_value ) << " )";
-            return oss.str();
-        }
-
-    private:
-        double m_epsilon;
-        double m_scale;
-        double m_value;
-    };
-}
-
-template<>
-inline std::string toString<Detail::Approx>( Detail::Approx const& value ) {
-    return value.toString();
-}
-
-} // end namespace Catch
-
-// #included from: internal/catch_matchers.hpp
-#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
-
-namespace Catch {
-namespace Matchers {
-    namespace Impl {
-
-    template<typename ExpressionT>
-    struct Matcher : SharedImpl<IShared>
-    {
-        typedef ExpressionT ExpressionType;
-
-        virtual ~Matcher() {}
-        virtual Ptr<Matcher> clone() const = 0;
-        virtual bool match( ExpressionT const& expr ) const = 0;
-        virtual std::string toString() const = 0;
-    };
-
-    template<typename DerivedT, typename ExpressionT>
-    struct MatcherImpl : Matcher<ExpressionT> {
-
-        virtual Ptr<Matcher<ExpressionT> > clone() const {
-            return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) );
-        }
-    };
-
-    namespace Generic {
-
-        template<typename ExpressionT>
-        class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> {
-        public:
-
-            AllOf() {}
-            AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {}
-
-            AllOf& add( Matcher<ExpressionT> const& matcher ) {
-                m_matchers.push_back( matcher.clone() );
-                return *this;
-            }
-            virtual bool match( ExpressionT const& expr ) const
-            {
-                for( std::size_t i = 0; i < m_matchers.size(); ++i )
-                    if( !m_matchers[i]->match( expr ) )
-                        return false;
-                return true;
-            }
-            virtual std::string toString() const {
-                std::ostringstream oss;
-                oss << "( ";
-                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
-                    if( i != 0 )
-                        oss << " and ";
-                    oss << m_matchers[i]->toString();
-                }
-                oss << " )";
-                return oss.str();
-            }
-
-        private:
-            std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
-        };
-
-        template<typename ExpressionT>
-        class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> {
-        public:
-
-            AnyOf() {}
-            AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {}
-
-            AnyOf& add( Matcher<ExpressionT> const& matcher ) {
-                m_matchers.push_back( matcher.clone() );
-                return *this;
-            }
-            virtual bool match( ExpressionT const& expr ) const
-            {
-                for( std::size_t i = 0; i < m_matchers.size(); ++i )
-                    if( m_matchers[i]->match( expr ) )
-                        return true;
-                return false;
-            }
-            virtual std::string toString() const {
-                std::ostringstream oss;
-                oss << "( ";
-                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
-                    if( i != 0 )
-                        oss << " or ";
-                    oss << m_matchers[i]->toString();
-                }
-                oss << " )";
-                return oss.str();
-            }
-
-        private:
-            std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
-        };
-
-    }
-
-    namespace StdString {
-
-        inline std::string makeString( std::string const& str ) { return str; }
-        inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); }
-
-        struct Equals : MatcherImpl<Equals, std::string> {
-            Equals( std::string const& str ) : m_str( str ){}
-            Equals( Equals const& other ) : m_str( other.m_str ){}
-
-            virtual ~Equals();
-
-            virtual bool match( std::string const& expr ) const {
-                return m_str == expr;
-            }
-            virtual std::string toString() const {
-                return "equals: \"" + m_str + "\"";
-            }
-
-            std::string m_str;
-        };
-
-        struct Contains : MatcherImpl<Contains, std::string> {
-            Contains( std::string const& substr ) : m_substr( substr ){}
-            Contains( Contains const& other ) : m_substr( other.m_substr ){}
-
-            virtual ~Contains();
-
-            virtual bool match( std::string const& expr ) const {
-                return expr.find( m_substr ) != std::string::npos;
-            }
-            virtual std::string toString() const {
-                return "contains: \"" + m_substr + "\"";
-            }
-
-            std::string m_substr;
-        };
-
-        struct StartsWith : MatcherImpl<StartsWith, std::string> {
-            StartsWith( std::string const& substr ) : m_substr( substr ){}
-            StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){}
-
-            virtual ~StartsWith();
-
-            virtual bool match( std::string const& expr ) const {
-                return expr.find( m_substr ) == 0;
-            }
-            virtual std::string toString() const {
-                return "starts with: \"" + m_substr + "\"";
-            }
-
-            std::string m_substr;
-        };
-
-        struct EndsWith : MatcherImpl<EndsWith, std::string> {
-            EndsWith( std::string const& substr ) : m_substr( substr ){}
-            EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){}
-
-            virtual ~EndsWith();
-
-            virtual bool match( std::string const& expr ) const {
-                return expr.find( m_substr ) == expr.size() - m_substr.size();
-            }
-            virtual std::string toString() const {
-                return "ends with: \"" + m_substr + "\"";
-            }
-
-            std::string m_substr;
-        };
-    } // namespace StdString
-    } // namespace Impl
-
-    // The following functions create the actual matcher objects.
-    // This allows the types to be inferred
-    template<typename ExpressionT>
-    inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
-                                                    Impl::Matcher<ExpressionT> const& m2 ) {
-        return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 );
-    }
-    template<typename ExpressionT>
-    inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
-                                                    Impl::Matcher<ExpressionT> const& m2,
-                                                    Impl::Matcher<ExpressionT> const& m3 ) {
-        return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
-    }
-    template<typename ExpressionT>
-    inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
-                                                    Impl::Matcher<ExpressionT> const& m2 ) {
-        return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 );
-    }
-    template<typename ExpressionT>
-    inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
-                                                    Impl::Matcher<ExpressionT> const& m2,
-                                                    Impl::Matcher<ExpressionT> const& m3 ) {
-        return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
-    }
-
-    inline Impl::StdString::Equals      Equals( std::string const& str ) {
-        return Impl::StdString::Equals( str );
-    }
-    inline Impl::StdString::Equals      Equals( const char* str ) {
-        return Impl::StdString::Equals( Impl::StdString::makeString( str ) );
-    }
-    inline Impl::StdString::Contains    Contains( std::string const& substr ) {
-        return Impl::StdString::Contains( substr );
-    }
-    inline Impl::StdString::Contains    Contains( const char* substr ) {
-        return Impl::StdString::Contains( Impl::StdString::makeString( substr ) );
-    }
-    inline Impl::StdString::StartsWith  StartsWith( std::string const& substr ) {
-        return Impl::StdString::StartsWith( substr );
-    }
-    inline Impl::StdString::StartsWith  StartsWith( const char* substr ) {
-        return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) );
-    }
-    inline Impl::StdString::EndsWith    EndsWith( std::string const& substr ) {
-        return Impl::StdString::EndsWith( substr );
-    }
-    inline Impl::StdString::EndsWith    EndsWith( const char* substr ) {
-        return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) );
-    }
-
-} // namespace Matchers
-
-using namespace Matchers;
-
-} // namespace Catch
-
-// These files are included here so the single_include script doesn't put them
-// in the conditionally compiled sections
-// #included from: internal/catch_test_case_info.h
-#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
-
-#include <string>
-#include <set>
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wpadded"
-#endif
-
-namespace Catch {
-
-    struct ITestCase;
-
-    struct TestCaseInfo {
-        TestCaseInfo(   std::string const& _name,
-                        std::string const& _className,
-                        std::string const& _description,
-                        std::set<std::string> const& _tags,
-                        bool _isHidden,
-                        SourceLineInfo const& _lineInfo );
-
-        TestCaseInfo( TestCaseInfo const& other );
-
-        std::string name;
-        std::string className;
-        std::string description;
-        std::set<std::string> tags;
-        std::string tagsAsString;
-        SourceLineInfo lineInfo;
-        bool isHidden;
-        bool throws;
-    };
-
-    class TestCase : public TestCaseInfo {
-    public:
-
-        TestCase( ITestCase* testCase, TestCaseInfo const& info );
-        TestCase( TestCase const& other );
-
-        TestCase withName( std::string const& _newName ) const;
-
-        void invoke() const;
-
-        TestCaseInfo const& getTestCaseInfo() const;
-
-        bool isHidden() const;
-        bool throws() const;
-
-        void swap( TestCase& other );
-        bool operator == ( TestCase const& other ) const;
-        bool operator < ( TestCase const& other ) const;
-        TestCase& operator = ( TestCase const& other );
-
-    private:
-        Ptr<ITestCase> test;
-    };
-
-    TestCase makeTestCase(  ITestCase* testCase,
-                            std::string const& className,
-                            std::string const& name,
-                            std::string const& description,
-                            SourceLineInfo const& lineInfo );
-}
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-// #included from: internal/catch_interfaces_runner.h
-#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
-
-namespace Catch {
-    class TestCase;
-
-    struct IRunner {
-        virtual ~IRunner();
-    };
-}
-
-
-#ifdef __OBJC__
-// #included from: internal/catch_objc.hpp
-#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
-
-#import <objc/runtime.h>
-
-#include <string>
-
-// NB. Any general catch headers included here must be included
-// in catch.hpp first to make sure they are included by the single
-// header for non obj-usage
-
-///////////////////////////////////////////////////////////////////////////////
-// This protocol is really only here for (self) documenting purposes, since
-// all its methods are optional.
- at protocol OcFixture
-
- at optional
-
--(void) setUp;
--(void) tearDown;
-
- at end
-
-namespace Catch {
-
-    class OcMethod : public SharedImpl<ITestCase> {
-
-    public:
-        OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
-
-        virtual void invoke() const {
-            id obj = [[m_cls alloc] init];
-
-            performOptionalSelector( obj, @selector(setUp)  );
-            performOptionalSelector( obj, m_sel );
-            performOptionalSelector( obj, @selector(tearDown)  );
-
-            arcSafeRelease( obj );
-        }
-    private:
-        virtual ~OcMethod() {}
-
-        Class m_cls;
-        SEL m_sel;
-    };
-
-    namespace Detail{
-
-        inline std::string getAnnotation(   Class cls,
-                                            std::string const& annotationName,
-                                            std::string const& testCaseName ) {
-            NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
-            SEL sel = NSSelectorFromString( selStr );
-            arcSafeRelease( selStr );
-            id value = performOptionalSelector( cls, sel );
-            if( value )
-                return [(NSString*)value UTF8String];
-            return "";
-        }
-    }
-
-    inline size_t registerTestMethods() {
-        size_t noTestMethods = 0;
-        int noClasses = objc_getClassList( NULL, 0 );
-
-        Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
-        objc_getClassList( classes, noClasses );
-
-        for( int c = 0; c < noClasses; c++ ) {
-            Class cls = classes[c];
-            {
-                u_int count;
-                Method* methods = class_copyMethodList( cls, &count );
-                for( u_int m = 0; m < count ; m++ ) {
-                    SEL selector = method_getName(methods[m]);
-                    std::string methodName = sel_getName(selector);
-                    if( startsWith( methodName, "Catch_TestCase_" ) ) {
-                        std::string testCaseName = methodName.substr( 15 );
-                        std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
-                        std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
-                        const char* className = class_getName( cls );
-
-                        getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) );
-                        noTestMethods++;
-                    }
-                }
-                free(methods);
-            }
-        }
-        return noTestMethods;
-    }
-
-    namespace Matchers {
-        namespace Impl {
-        namespace NSStringMatchers {
-
-            template<typename MatcherT>
-            struct StringHolder : MatcherImpl<MatcherT, NSString*>{
-                StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
-                StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
-                StringHolder() {
-                    arcSafeRelease( m_substr );
-                }
-
-                NSString* m_substr;
-            };
-
-            struct Equals : StringHolder<Equals> {
-                Equals( NSString* substr ) : StringHolder( substr ){}
-
-                virtual bool match( ExpressionType const& str ) const {
-                    return  (str != nil || m_substr == nil ) &&
-                            [str isEqualToString:m_substr];
-                }
-
-                virtual std::string toString() const {
-                    return "equals string: \"" + Catch::toString( m_substr ) + "\"";
-                }
-            };
-
-            struct Contains : StringHolder<Contains> {
-                Contains( NSString* substr ) : StringHolder( substr ){}
-
-                virtual bool match( ExpressionType const& str ) const {
-                    return  (str != nil || m_substr == nil ) &&
-                            [str rangeOfString:m_substr].location != NSNotFound;
-                }
-
-                virtual std::string toString() const {
-                    return "contains string: \"" + Catch::toString( m_substr ) + "\"";
-                }
-            };
-
-            struct StartsWith : StringHolder<StartsWith> {
-                StartsWith( NSString* substr ) : StringHolder( substr ){}
-
-                virtual bool match( ExpressionType const& str ) const {
-                    return  (str != nil || m_substr == nil ) &&
-                            [str rangeOfString:m_substr].location == 0;
-                }
-
-                virtual std::string toString() const {
-                    return "starts with: \"" + Catch::toString( m_substr ) + "\"";
-                }
-            };
-            struct EndsWith : StringHolder<EndsWith> {
-                EndsWith( NSString* substr ) : StringHolder( substr ){}
-
-                virtual bool match( ExpressionType const& str ) const {
-                    return  (str != nil || m_substr == nil ) &&
-                            [str rangeOfString:m_substr].location == [str length] - [m_substr length];
-                }
-
-                virtual std::string toString() const {
-                    return "ends with: \"" + Catch::toString( m_substr ) + "\"";
-                }
-            };
-
-        } // namespace NSStringMatchers
-        } // namespace Impl
-
-        inline Impl::NSStringMatchers::Equals
-            Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
-
-        inline Impl::NSStringMatchers::Contains
-            Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
-
-        inline Impl::NSStringMatchers::StartsWith
-            StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
-
-        inline Impl::NSStringMatchers::EndsWith
-            EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
-
-    } // namespace Matchers
-
-    using namespace Matchers;
-
-} // namespace Catch
-
-///////////////////////////////////////////////////////////////////////////////
-#define OC_TEST_CASE( name, desc )\
-+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
-{\
-return @ name; \
-}\
-+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
-{ \
-return @ desc; \
-} \
--(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
-
-#endif
-
-#ifdef CATCH_CONFIG_RUNNER
-// #included from: internal/catch_impl.hpp
-#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
-
-// Collect all the implementation files together here
-// These are the equivalent of what would usually be cpp files
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wweak-vtables"
-#endif
-
-// #included from: catch_runner.hpp
-#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
-
-// #included from: internal/catch_commandline.hpp
-#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
-
-// #included from: catch_config.hpp
-#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
-
-// #included from: catch_test_spec_parser.hpp
-#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wpadded"
-#endif
-
-// #included from: catch_test_spec.hpp
-#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wpadded"
-#endif
-
-#include <string>
-#include <vector>
-
-namespace Catch {
-
-    class TestSpec {
-        struct Pattern : SharedImpl<> {
-            virtual ~Pattern();
-            virtual bool matches( TestCaseInfo const& testCase ) const = 0;
-        };
-        class NamePattern : public Pattern {
-            enum WildcardPosition {
-                NoWildcard = 0,
-                WildcardAtStart = 1,
-                WildcardAtEnd = 2,
-                WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
-            };
-
-        public:
-            NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) {
-                if( startsWith( m_name, "*" ) ) {
-                    m_name = m_name.substr( 1 );
-                    m_wildcard = WildcardAtStart;
-                }
-                if( endsWith( m_name, "*" ) ) {
-                    m_name = m_name.substr( 0, m_name.size()-1 );
-                    m_wildcard = (WildcardPosition)( m_wildcard | WildcardAtEnd );
-                }
-            }
-            virtual ~NamePattern();
-            virtual bool matches( TestCaseInfo const& testCase ) const {
-                switch( m_wildcard ) {
-                    case NoWildcard:
-                        return m_name == toLower( testCase.name );
-                    case WildcardAtStart:
-                        return endsWith( toLower( testCase.name ), m_name );
-                    case WildcardAtEnd:
-                        return startsWith( toLower( testCase.name ), m_name );
-                    case WildcardAtBothEnds:
-                        return contains( toLower( testCase.name ), m_name );
-                }
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunreachable-code"
-#endif
-                throw std::logic_error( "Unknown enum" );
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-            }
-        private:
-            std::string m_name;
-            WildcardPosition m_wildcard;
-        };
-        class TagPattern : public Pattern {
-        public:
-            TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
-            virtual ~TagPattern();
-            virtual bool matches( TestCaseInfo const& testCase ) const {
-                return testCase.tags.find( m_tag ) != testCase.tags.end();
-            }
-        private:
-            std::string m_tag;
-        };
-        class ExcludedPattern : public Pattern {
-        public:
-            ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
-            virtual ~ExcludedPattern();
-            virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
-        private:
-            Ptr<Pattern> m_underlyingPattern;
-        };
-
-        struct Filter {
-            std::vector<Ptr<Pattern> > m_patterns;
-
-            bool matches( TestCaseInfo const& testCase ) const {
-                // All patterns in a filter must match for the filter to be a match
-                for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it )
-                    if( !(*it)->matches( testCase ) )
-                        return false;
-                    return true;
-            }
-        };
-
-    public:
-        bool hasFilters() const {
-            return !m_filters.empty();
-        }
-        bool matches( TestCaseInfo const& testCase ) const {
-            // A TestSpec matches if any filter matches
-            for( std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it )
-                if( it->matches( testCase ) )
-                    return true;
-            return false;
-        }
-
-    private:
-        std::vector<Filter> m_filters;
-
-        friend class TestSpecParser;
-    };
-}
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-namespace Catch {
-
-    class TestSpecParser {
-        enum Mode{ None, Name, QuotedName, Tag };
-        Mode m_mode;
-        bool m_exclusion;
-        std::size_t m_start, m_pos;
-        std::string m_arg;
-        TestSpec::Filter m_currentFilter;
-        TestSpec m_testSpec;
-
-    public:
-        TestSpecParser parse( std::string const& arg ) {
-            m_mode = None;
-            m_exclusion = false;
-            m_start = std::string::npos;
-            m_arg = arg;
-            for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
-                visitChar( m_arg[m_pos] );
-            if( m_mode == Name )
-                addPattern<TestSpec::NamePattern>();
-            addFilter();
-            return *this;
-        }
-        TestSpec testSpec() {
-            return m_testSpec;
-        }
-    private:
-        void visitChar( char c ) {
-            if( m_mode == None ) {
-                switch( c ) {
-                case ' ': return;
-                case '~': m_exclusion = true; return;
-                case '[': return startNewMode( Tag, ++m_pos );
-                case '"': return startNewMode( QuotedName, ++m_pos );
-                default: startNewMode( Name, m_pos ); break;
-                }
-            }
-            if( m_mode == Name ) {
-                if( c == ',' ) {
-                    addPattern<TestSpec::NamePattern>();
-                    addFilter();
-                }
-                else if( c == '[' ) {
-                    if( subString() == "exclude:" )
-                        m_exclusion = true;
-                    else
-                        addPattern<TestSpec::NamePattern>();
-                    startNewMode( Tag, ++m_pos );
-                }
-            }
-            else if( m_mode == QuotedName && c == '"' )
-                addPattern<TestSpec::NamePattern>();
-            else if( m_mode == Tag && c == ']' )
-                addPattern<TestSpec::TagPattern>();
-        }
-        void startNewMode( Mode mode, std::size_t start ) {
-            m_mode = mode;
-            m_start = start;
-        }
-        std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
-        template<typename T>
-        void addPattern() {
-            std::string token = subString();
-            if( startsWith( token, "exclude:" ) ) {
-                m_exclusion = true;
-                token = token.substr( 8 );
-            }
-            if( !token.empty() ) {
-                Ptr<TestSpec::Pattern> pattern = new T( token );
-                if( m_exclusion )
-                    pattern = new TestSpec::ExcludedPattern( pattern );
-                m_currentFilter.m_patterns.push_back( pattern );
-            }
-            m_exclusion = false;
-            m_mode = None;
-        }
-        void addFilter() {
-            if( !m_currentFilter.m_patterns.empty() ) {
-                m_testSpec.m_filters.push_back( m_currentFilter );
-                m_currentFilter = TestSpec::Filter();
-            }
-        }
-    };
-    inline TestSpec parseTestSpec( std::string const& arg ) {
-        return TestSpecParser().parse( arg ).testSpec();
-    }
-
-} // namespace Catch
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-// #included from: catch_stream.h
-#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
-
-#include <streambuf>
-
-#ifdef __clang__
-#pragma clang diagnostic ignored "-Wpadded"
-#endif
-
-namespace Catch {
-
-    class Stream {
-    public:
-        Stream();
-        Stream( std::streambuf* _streamBuf, bool _isOwned );
-        void release();
-
-        std::streambuf* streamBuf;
-
-    private:
-        bool isOwned;
-    };
-}
-
-#include <memory>
-#include <vector>
-#include <string>
-#include <iostream>
-
-#ifndef CATCH_CONFIG_CONSOLE_WIDTH
-#define CATCH_CONFIG_CONSOLE_WIDTH 80
-#endif
-
-namespace Catch {
-
-    struct ConfigData {
-
-        ConfigData()
-        :   listTests( false ),
-            listTags( false ),
-            listReporters( false ),
-            listTestNamesOnly( false ),
-            showSuccessfulTests( false ),
-            shouldDebugBreak( false ),
-            noThrow( false ),
-            showHelp( false ),
-            showInvisibles( false ),
-            abortAfter( -1 ),
-            verbosity( Verbosity::Normal ),
-            warnings( WarnAbout::Nothing ),
-            showDurations( ShowDurations::DefaultForReporter )
-        {}
-
-        bool listTests;
-        bool listTags;
-        bool listReporters;
-        bool listTestNamesOnly;
-
-        bool showSuccessfulTests;
-        bool shouldDebugBreak;
-        bool noThrow;
-        bool showHelp;
-        bool showInvisibles;
-
-        int abortAfter;
-
-        Verbosity::Level verbosity;
-        WarnAbout::What warnings;
-        ShowDurations::OrNot showDurations;
-
-        std::string reporterName;
-        std::string outputFilename;
-        std::string name;
-        std::string processName;
-
-        std::vector<std::string> testsOrTags;
-    };
-
-    class Config : public SharedImpl<IConfig> {
-    private:
-        Config( Config const& other );
-        Config& operator = ( Config const& other );
-        virtual void dummy();
-    public:
-
-        Config()
-        :   m_os( std::cout.rdbuf() )
-        {}
-
-        Config( ConfigData const& data )
-        :   m_data( data ),
-            m_os( std::cout.rdbuf() )
-        {
-            if( !data.testsOrTags.empty() ) {
-                TestSpecParser parser;
-                for( std::size_t i = 0; i < data.testsOrTags.size(); ++i )
-                    parser.parse( data.testsOrTags[i] );
-                m_testSpec = parser.testSpec();
-            }
-        }
-
-        virtual ~Config() {
-            m_os.rdbuf( std::cout.rdbuf() );
-            m_stream.release();
-        }
-
-        void setFilename( std::string const& filename ) {
-            m_data.outputFilename = filename;
-        }
-
-        std::string const& getFilename() const {
-            return m_data.outputFilename ;
-        }
-
-        bool listTests() const { return m_data.listTests; }
-        bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
-        bool listTags() const { return m_data.listTags; }
-        bool listReporters() const { return m_data.listReporters; }
-
-        std::string getProcessName() const { return m_data.processName; }
-
-        bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
-
-        void setStreamBuf( std::streambuf* buf ) {
-            m_os.rdbuf( buf ? buf : std::cout.rdbuf() );
-        }
-
-        void useStream( std::string const& streamName ) {
-            Stream stream = createStream( streamName );
-            setStreamBuf( stream.streamBuf );
-            m_stream.release();
-            m_stream = stream;
-        }
-
-        std::string getReporterName() const { return m_data.reporterName; }
-
-        int abortAfter() const { return m_data.abortAfter; }
-
-        TestSpec const& testSpec() const { return m_testSpec; }
-
-        bool showHelp() const { return m_data.showHelp; }
-        bool showInvisibles() const { return m_data.showInvisibles; }
-
-        // IConfig interface
-        virtual bool allowThrows() const        { return !m_data.noThrow; }
-        virtual std::ostream& stream() const    { return m_os; }
-        virtual std::string name() const        { return m_data.name.empty() ? m_data.processName : m_data.name; }
-        virtual bool includeSuccessfulResults() const   { return m_data.showSuccessfulTests; }
-        virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
-        virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; }
-
-    private:
-        ConfigData m_data;
-
-        Stream m_stream;
-        mutable std::ostream m_os;
-        TestSpec m_testSpec;
-    };
-
-} // end namespace Catch
-
-// #included from: catch_clara.h
-#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED
-
-// Use Catch's value for console width (store Clara's off to the side, if present)
-#ifdef CLARA_CONFIG_CONSOLE_WIDTH
-#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
-#undef CLARA_CONFIG_CONSOLE_WIDTH
-#endif
-#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
-
-// Declare Clara inside the Catch namespace
-#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
-// #included from: ../external/clara.h
-
-// Only use header guard if we are not using an outer namespace
-#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
-
-#ifndef STITCH_CLARA_OPEN_NAMESPACE
-#define TWOBLUECUBES_CLARA_H_INCLUDED
-#define STITCH_CLARA_OPEN_NAMESPACE
-#define STITCH_CLARA_CLOSE_NAMESPACE
-#else
-#define STITCH_CLARA_CLOSE_NAMESPACE }
-#endif
-
-#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
-
-// ----------- #included from tbc_text_format.h -----------
-
-// Only use header guard if we are not using an outer namespace
-#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE)
-#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-#define TBC_TEXT_FORMAT_H_INCLUDED
-#endif
-
-#include <string>
-#include <vector>
-#include <sstream>
-
-// Use optional outer namespace
-#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
-#endif
-
-namespace Tbc {
-
-#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
-    const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
-#else
-    const unsigned int consoleWidth = 80;
-#endif
-
-    struct TextAttributes {
-        TextAttributes()
-        :   initialIndent( std::string::npos ),
-            indent( 0 ),
-            width( consoleWidth-1 ),
-            tabChar( '\t' )
-        {}
-
-        TextAttributes& setInitialIndent( std::size_t _value )  { initialIndent = _value; return *this; }
-        TextAttributes& setIndent( std::size_t _value )         { indent = _value; return *this; }
-        TextAttributes& setWidth( std::size_t _value )          { width = _value; return *this; }
-        TextAttributes& setTabChar( char _value )               { tabChar = _value; return *this; }
-
-        std::size_t initialIndent;  // indent of first line, or npos
-        std::size_t indent;         // indent of subsequent lines, or all if initialIndent is npos
-        std::size_t width;          // maximum width of text, including indent. Longer text will wrap
-        char tabChar;               // If this char is seen the indent is changed to current pos
-    };
-
-    class Text {
-    public:
-        Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
-        : attr( _attr )
-        {
-            std::string wrappableChars = " [({.,/|\\-";
-            std::size_t indent = _attr.initialIndent != std::string::npos
-                ? _attr.initialIndent
-                : _attr.indent;
-            std::string remainder = _str;
-
-            while( !remainder.empty() ) {
-                if( lines.size() >= 1000 ) {
-                    lines.push_back( "... message truncated due to excessive size" );
-                    return;
-                }
-                std::size_t tabPos = std::string::npos;
-                std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
-                std::size_t pos = remainder.find_first_of( '\n' );
-                if( pos <= width ) {
-                    width = pos;
-                }
-                pos = remainder.find_last_of( _attr.tabChar, width );
-                if( pos != std::string::npos ) {
-                    tabPos = pos;
-                    if( remainder[width] == '\n' )
-                        width--;
-                    remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
-                }
-
-                if( width == remainder.size() ) {
-                    spliceLine( indent, remainder, width );
-                }
-                else if( remainder[width] == '\n' ) {
-                    spliceLine( indent, remainder, width );
-                    if( width <= 1 || remainder.size() != 1 )
-                        remainder = remainder.substr( 1 );
-                    indent = _attr.indent;
-                }
-                else {
-                    pos = remainder.find_last_of( wrappableChars, width );
-                    if( pos != std::string::npos && pos > 0 ) {
-                        spliceLine( indent, remainder, pos );
-                        if( remainder[0] == ' ' )
-                            remainder = remainder.substr( 1 );
-                    }
-                    else {
-                        spliceLine( indent, remainder, width-1 );
-                        lines.back() += "-";
-                    }
-                    if( lines.size() == 1 )
-                        indent = _attr.indent;
-                    if( tabPos != std::string::npos )
-                        indent += tabPos;
-                }
-            }
-        }
-
-        void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
-            lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
-            _remainder = _remainder.substr( _pos );
-        }
-
-        typedef std::vector<std::string>::const_iterator const_iterator;
-
-        const_iterator begin() const { return lines.begin(); }
-        const_iterator end() const { return lines.end(); }
-        std::string const& last() const { return lines.back(); }
-        std::size_t size() const { return lines.size(); }
-        std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
-        std::string toString() const {
-            std::ostringstream oss;
-            oss << *this;
-            return oss.str();
-        }
-
-        inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
-            for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
-                it != itEnd; ++it ) {
-                if( it != _text.begin() )
-                    _stream << "\n";
-                _stream << *it;
-            }
-            return _stream;
-        }
-
-    private:
-        std::string str;
-        TextAttributes attr;
-        std::vector<std::string> lines;
-    };
-
-} // end namespace Tbc
-
-#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-} // end outer namespace
-#endif
-
-#endif // TBC_TEXT_FORMAT_H_INCLUDED
-
-// ----------- end of #include from tbc_text_format.h -----------
-// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h
-
-#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
-
-#include <map>
-#include <algorithm>
-#include <stdexcept>
-#include <memory>
-
-// Use optional outer namespace
-#ifdef STITCH_CLARA_OPEN_NAMESPACE
-STITCH_CLARA_OPEN_NAMESPACE
-#endif
-
-namespace Clara {
-
-    struct UnpositionalTag {};
-
-    extern UnpositionalTag _;
-
-#ifdef CLARA_CONFIG_MAIN
-    UnpositionalTag _;
-#endif
-
-    namespace Detail {
-
-#ifdef CLARA_CONSOLE_WIDTH
-    const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
-#else
-    const unsigned int consoleWidth = 80;
-#endif
-
-        using namespace Tbc;
-
-        inline bool startsWith( std::string const& str, std::string const& prefix ) {
-            return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix;
-        }
-
-        template<typename T> struct RemoveConstRef{ typedef T type; };
-        template<typename T> struct RemoveConstRef<T&>{ typedef T type; };
-        template<typename T> struct RemoveConstRef<T const&>{ typedef T type; };
-        template<typename T> struct RemoveConstRef<T const>{ typedef T type; };
-
-        template<typename T>    struct IsBool       { static const bool value = false; };
-        template<>              struct IsBool<bool> { static const bool value = true; };
-
-        template<typename T>
-        void convertInto( std::string const& _source, T& _dest ) {
-            std::stringstream ss;
-            ss << _source;
-            ss >> _dest;
-            if( ss.fail() )
-                throw std::runtime_error( "Unable to convert " + _source + " to destination type" );
-        }
-        inline void convertInto( std::string const& _source, std::string& _dest ) {
-            _dest = _source;
-        }
-        inline void convertInto( std::string const& _source, bool& _dest ) {
-            std::string sourceLC = _source;
-            std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower );
-            if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" )
-                _dest = true;
-            else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" )
-                _dest = false;
-            else
-                throw std::runtime_error( "Expected a boolean value but did not recognise:\n  '" + _source + "'" );
-        }
-        inline void convertInto( bool _source, bool& _dest ) {
-            _dest = _source;
-        }
-        template<typename T>
-        inline void convertInto( bool, T& ) {
-            throw std::runtime_error( "Invalid conversion" );
-        }
-
-        template<typename ConfigT>
-        struct IArgFunction {
-            virtual ~IArgFunction() {}
-#  ifdef CATCH_CPP11_OR_GREATER
-            IArgFunction()                      = default;
-            IArgFunction( IArgFunction const& ) = default;
-#  endif
-            virtual void set( ConfigT& config, std::string const& value ) const = 0;
-            virtual void setFlag( ConfigT& config ) const = 0;
-            virtual bool takesArg() const = 0;
-            virtual IArgFunction* clone() const = 0;
-        };
-
-        template<typename ConfigT>
-        class BoundArgFunction {
-        public:
-            BoundArgFunction() : functionObj( NULL ) {}
-            BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {}
-            BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {}
-            BoundArgFunction& operator = ( BoundArgFunction const& other ) {
-                IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL;
-                delete functionObj;
-                functionObj = newFunctionObj;
-                return *this;
-            }
-            ~BoundArgFunction() { delete functionObj; }
-
-            void set( ConfigT& config, std::string const& value ) const {
-                functionObj->set( config, value );
-            }
-            void setFlag( ConfigT& config ) const {
-                functionObj->setFlag( config );
-            }
-            bool takesArg() const { return functionObj->takesArg(); }
-
-            bool isSet() const {
-                return functionObj != NULL;
-            }
-        private:
-            IArgFunction<ConfigT>* functionObj;
-        };
-
-        template<typename C>
-        struct NullBinder : IArgFunction<C>{
-            virtual void set( C&, std::string const& ) const {}
-            virtual void setFlag( C& ) const {}
-            virtual bool takesArg() const { return true; }
-            virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
-        };
-
-        template<typename C, typename M>
-        struct BoundDataMember : IArgFunction<C>{
-            BoundDataMember( M C::* _member ) : member( _member ) {}
-            virtual void set( C& p, std::string const& stringValue ) const {
-                convertInto( stringValue, p.*member );
-            }
-            virtual void setFlag( C& p ) const {
-                convertInto( true, p.*member );
-            }
-            virtual bool takesArg() const { return !IsBool<M>::value; }
-            virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
-            M C::* member;
-        };
-        template<typename C, typename M>
-        struct BoundUnaryMethod : IArgFunction<C>{
-            BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {}
-            virtual void set( C& p, std::string const& stringValue ) const {
-                typename RemoveConstRef<M>::type value;
-                convertInto( stringValue, value );
-                (p.*member)( value );
-            }
-            virtual void setFlag( C& p ) const {
-                typename RemoveConstRef<M>::type value;
-                convertInto( true, value );
-                (p.*member)( value );
-            }
-            virtual bool takesArg() const { return !IsBool<M>::value; }
-            virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
-            void (C::*member)( M );
-        };
-        template<typename C>
-        struct BoundNullaryMethod : IArgFunction<C>{
-            BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {}
-            virtual void set( C& p, std::string const& stringValue ) const {
-                bool value;
-                convertInto( stringValue, value );
-                if( value )
-                    (p.*member)();
-            }
-            virtual void setFlag( C& p ) const {
-                (p.*member)();
-            }
-            virtual bool takesArg() const { return false; }
-            virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
-            void (C::*member)();
-        };
-
-        template<typename C>
-        struct BoundUnaryFunction : IArgFunction<C>{
-            BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {}
-            virtual void set( C& obj, std::string const& stringValue ) const {
-                bool value;
-                convertInto( stringValue, value );
-                if( value )
-                    function( obj );
-            }
-            virtual void setFlag( C& p ) const {
-                function( p );
-            }
-            virtual bool takesArg() const { return false; }
-            virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
-            void (*function)( C& );
-        };
-
-        template<typename C, typename T>
-        struct BoundBinaryFunction : IArgFunction<C>{
-            BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {}
-            virtual void set( C& obj, std::string const& stringValue ) const {
-                typename RemoveConstRef<T>::type value;
-                convertInto( stringValue, value );
-                function( obj, value );
-            }
-            virtual void setFlag( C& obj ) const {
-                typename RemoveConstRef<T>::type value;
-                convertInto( true, value );
-                function( obj, value );
-            }
-            virtual bool takesArg() const { return !IsBool<T>::value; }
-            virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
-            void (*function)( C&, T );
-        };
-
-    } // namespace Detail
-
-    struct Parser {
-        Parser() : separators( " \t=:" ) {}
-
-        struct Token {
-            enum Type { Positional, ShortOpt, LongOpt };
-            Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {}
-            Type type;
-            std::string data;
-        };
-
-        void parseIntoTokens( int argc, char const * const * argv, std::vector<Parser::Token>& tokens ) const {
-            const std::string doubleDash = "--";
-            for( int i = 1; i < argc && argv[i] != doubleDash; ++i )
-                parseIntoTokens( argv[i] , tokens);
-        }
-        void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const {
-            while( !arg.empty() ) {
-                Parser::Token token( Parser::Token::Positional, arg );
-                arg = "";
-                if( token.data[0] == '-' ) {
-                    if( token.data.size() > 1 && token.data[1] == '-' ) {
-                        token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) );
-                    }
-                    else {
-                        token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) );
-                        if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) {
-                            arg = "-" + token.data.substr( 1 );
-                            token.data = token.data.substr( 0, 1 );
-                        }
-                    }
-                }
-                if( token.type != Parser::Token::Positional ) {
-                    std::size_t pos = token.data.find_first_of( separators );
-                    if( pos != std::string::npos ) {
-                        arg = token.data.substr( pos+1 );
-                        token.data = token.data.substr( 0, pos );
-                    }
-                }
-                tokens.push_back( token );
-            }
-        }
-        std::string separators;
-    };
-
-    template<typename ConfigT>
-    struct CommonArgProperties {
-        CommonArgProperties() {}
-        CommonArgProperties( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {}
-
-        Detail::BoundArgFunction<ConfigT> boundField;
-        std::string description;
-        std::string detail;
-        std::string placeholder; // Only value if boundField takes an arg
-
-        bool takesArg() const {
-            return !placeholder.empty();
-        }
-        void validate() const {
-            if( !boundField.isSet() )
-                throw std::logic_error( "option not bound" );
-        }
-    };
-    struct OptionArgProperties {
-        std::vector<std::string> shortNames;
-        std::string longName;
-
-        bool hasShortName( std::string const& shortName ) const {
-            return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end();
-        }
-        bool hasLongName( std::string const& _longName ) const {
-            return _longName == longName;
-        }
-    };
-    struct PositionalArgProperties {
-        PositionalArgProperties() : position( -1 ) {}
-        int position; // -1 means non-positional (floating)
-
-        bool isFixedPositional() const {
-            return position != -1;
-        }
-    };
-
-    template<typename ConfigT>
-    class CommandLine {
-
-        struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties {
-            Arg() {}
-            Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : CommonArgProperties<ConfigT>( _boundField ) {}
-
-            using CommonArgProperties<ConfigT>::placeholder; // !TBD
-
-            std::string dbgName() const {
-                if( !longName.empty() )
-                    return "--" + longName;
-                if( !shortNames.empty() )
-                    return "-" + shortNames[0];
-                return "positional args";
-            }
-            std::string commands() const {
-                std::ostringstream oss;
-                bool first = true;
-                std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end();
-                for(; it != itEnd; ++it ) {
-                    if( first )
-                        first = false;
-                    else
-                        oss << ", ";
-                    oss << "-" << *it;
-                }
-                if( !longName.empty() ) {
-                    if( !first )
-                        oss << ", ";
-                    oss << "--" << longName;
-                }
-                if( !placeholder.empty() )
-                    oss << " <" << placeholder << ">";
-                return oss.str();
-            }
-        };
-
-        // NOTE: std::auto_ptr is deprecated in c++11/c++0x
-#if defined(__cplusplus) && __cplusplus > 199711L
-        typedef std::unique_ptr<Arg> ArgAutoPtr;
-#else
-        typedef std::auto_ptr<Arg> ArgAutoPtr;
-#endif
-
-        friend void addOptName( Arg& arg, std::string const& optName )
-        {
-            if( optName.empty() )
-                return;
-            if( Detail::startsWith( optName, "--" ) ) {
-                if( !arg.longName.empty() )
-                    throw std::logic_error( "Only one long opt may be specified. '"
-                        + arg.longName
-                        + "' already specified, now attempting to add '"
-                        + optName + "'" );
-                arg.longName = optName.substr( 2 );
-            }
-            else if( Detail::startsWith( optName, "-" ) )
-                arg.shortNames.push_back( optName.substr( 1 ) );
-            else
-                throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" );
-        }
-        friend void setPositionalArg( Arg& arg, int position )
-        {
-            arg.position = position;
-        }
-
-        class ArgBuilder {
-        public:
-            ArgBuilder( Arg* arg ) : m_arg( arg ) {}
-
-            // Bind a non-boolean data member (requires placeholder string)
-            template<typename C, typename M>
-            void bind( M C::* field, std::string const& placeholder ) {
-                m_arg->boundField = new Detail::BoundDataMember<C,M>( field );
-                m_arg->placeholder = placeholder;
-            }
-            // Bind a boolean data member (no placeholder required)
-            template<typename C>
-            void bind( bool C::* field ) {
-                m_arg->boundField = new Detail::BoundDataMember<C,bool>( field );
-            }
-
-            // Bind a method taking a single, non-boolean argument (requires a placeholder string)
-            template<typename C, typename M>
-            void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) {
-                m_arg->boundField = new Detail::BoundUnaryMethod<C,M>( unaryMethod );
-                m_arg->placeholder = placeholder;
-            }
-
-            // Bind a method taking a single, boolean argument (no placeholder string required)
-            template<typename C>
-            void bind( void (C::* unaryMethod)( bool ) ) {
-                m_arg->boundField = new Detail::BoundUnaryMethod<C,bool>( unaryMethod );
-            }
-
-            // Bind a method that takes no arguments (will be called if opt is present)
-            template<typename C>
-            void bind( void (C::* nullaryMethod)() ) {
-                m_arg->boundField = new Detail::BoundNullaryMethod<C>( nullaryMethod );
-            }
-
-            // Bind a free function taking a single argument - the object to operate on (no placeholder string required)
-            template<typename C>
-            void bind( void (* unaryFunction)( C& ) ) {
-                m_arg->boundField = new Detail::BoundUnaryFunction<C>( unaryFunction );
-            }
-
-            // Bind a free function taking a single argument - the object to operate on (requires a placeholder string)
-            template<typename C, typename T>
-            void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) {
-                m_arg->boundField = new Detail::BoundBinaryFunction<C, T>( binaryFunction );
-                m_arg->placeholder = placeholder;
-            }
-
-            ArgBuilder& describe( std::string const& description ) {
-                m_arg->description = description;
-                return *this;
-            }
-            ArgBuilder& detail( std::string const& detail ) {
-                m_arg->detail = detail;
-                return *this;
-            }
-
-        protected:
-            Arg* m_arg;
-        };
-
-        class OptBuilder : public ArgBuilder {
-        public:
-            OptBuilder( Arg* arg ) : ArgBuilder( arg ) {}
-            OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {}
-
-            OptBuilder& operator[]( std::string const& optName ) {
-                addOptName( *ArgBuilder::m_arg, optName );
-                return *this;
-            }
-        };
-
-    public:
-
-        CommandLine()
-        :   m_boundProcessName( new Detail::NullBinder<ConfigT>() ),
-            m_highestSpecifiedArgPosition( 0 ),
-            m_throwOnUnrecognisedTokens( false )
-        {}
-        CommandLine( CommandLine const& other )
-        :   m_boundProcessName( other.m_boundProcessName ),
-            m_options ( other.m_options ),
-            m_positionalArgs( other.m_positionalArgs ),
-            m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ),
-            m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens )
-        {
-            if( other.m_floatingArg.get() )
-                m_floatingArg = ArgAutoPtr( new Arg( *other.m_floatingArg ) );
-        }
-
-        CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) {
-            m_throwOnUnrecognisedTokens = shouldThrow;
-            return *this;
-        }
-
-        OptBuilder operator[]( std::string const& optName ) {
-            m_options.push_back( Arg() );
-            addOptName( m_options.back(), optName );
-            OptBuilder builder( &m_options.back() );
-            return builder;
-        }
-
-        ArgBuilder operator[]( int position ) {
-            m_positionalArgs.insert( std::make_pair( position, Arg() ) );
-            if( position > m_highestSpecifiedArgPosition )
-                m_highestSpecifiedArgPosition = position;
-            setPositionalArg( m_positionalArgs[position], position );
-            ArgBuilder builder( &m_positionalArgs[position] );
-            return builder;
-        }
-
-        // Invoke this with the _ instance
-        ArgBuilder operator[]( UnpositionalTag ) {
-            if( m_floatingArg.get() )
-                throw std::logic_error( "Only one unpositional argument can be added" );
-            m_floatingArg = ArgAutoPtr( new Arg() );
-            ArgBuilder builder( m_floatingArg.get() );
-            return builder;
-        }
-
-        template<typename C, typename M>
-        void bindProcessName( M C::* field ) {
-            m_boundProcessName = new Detail::BoundDataMember<C,M>( field );
-        }
-        template<typename C, typename M>
-        void bindProcessName( void (C::*_unaryMethod)( M ) ) {
-            m_boundProcessName = new Detail::BoundUnaryMethod<C,M>( _unaryMethod );
-        }
-
-        void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const {
-            typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it;
-            std::size_t maxWidth = 0;
-            for( it = itBegin; it != itEnd; ++it )
-                maxWidth = (std::max)( maxWidth, it->commands().size() );
-
-            for( it = itBegin; it != itEnd; ++it ) {
-                Detail::Text usage( it->commands(), Detail::TextAttributes()
-                                                        .setWidth( maxWidth+indent )
-                                                        .setIndent( indent ) );
-                Detail::Text desc( it->description, Detail::TextAttributes()
-                                                        .setWidth( width - maxWidth - 3 ) );
-
-                for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) {
-                    std::string usageCol = i < usage.size() ? usage[i] : "";
-                    os << usageCol;
-
-                    if( i < desc.size() && !desc[i].empty() )
-                        os  << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' )
-                            << desc[i];
-                    os << "\n";
-                }
-            }
-        }
-        std::string optUsage() const {
-            std::ostringstream oss;
-            optUsage( oss );
-            return oss.str();
-        }
-
-        void argSynopsis( std::ostream& os ) const {
-            for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) {
-                if( i > 1 )
-                    os << " ";
-                typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i );
-                if( it != m_positionalArgs.end() )
-                    os << "<" << it->second.placeholder << ">";
-                else if( m_floatingArg.get() )
-                    os << "<" << m_floatingArg->placeholder << ">";
-                else
-                    throw std::logic_error( "non consecutive positional arguments with no floating args" );
-            }
-            // !TBD No indication of mandatory args
-            if( m_floatingArg.get() ) {
-                if( m_highestSpecifiedArgPosition > 1 )
-                    os << " ";
-                os << "[<" << m_floatingArg->placeholder << "> ...]";
-            }
-        }
-        std::string argSynopsis() const {
-            std::ostringstream oss;
-            argSynopsis( oss );
-            return oss.str();
-        }
-
-        void usage( std::ostream& os, std::string const& procName ) const {
-            validate();
-            os << "usage:\n  " << procName << " ";
-            argSynopsis( os );
-            if( !m_options.empty() ) {
-                os << " [options]\n\nwhere options are: \n";
-                optUsage( os, 2 );
-            }
-            os << "\n";
-        }
-        std::string usage( std::string const& procName ) const {
-            std::ostringstream oss;
-            usage( oss, procName );
-            return oss.str();
-        }
-
-        ConfigT parse( int argc, char const * const * argv ) const {
-            ConfigT config;
-            parseInto( argc, argv, config );
-            return config;
-        }
-
-        std::vector<Parser::Token> parseInto( int argc, char const * const * argv, ConfigT& config ) const {
-            std::string processName = argv[0];
-            std::size_t lastSlash = processName.find_last_of( "/\\" );
-            if( lastSlash != std::string::npos )
-                processName = processName.substr( lastSlash+1 );
-            m_boundProcessName.set( config, processName );
-            std::vector<Parser::Token> tokens;
-            Parser parser;
-            parser.parseIntoTokens( argc, argv, tokens );
-            return populate( tokens, config );
-        }
-
-        std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
-            validate();
-            std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config );
-            unusedTokens = populateFixedArgs( unusedTokens, config );
-            unusedTokens = populateFloatingArgs( unusedTokens, config );
-            return unusedTokens;
-        }
-
-        std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
-            std::vector<Parser::Token> unusedTokens;
-            std::vector<std::string> errors;
-            for( std::size_t i = 0; i < tokens.size(); ++i ) {
-                Parser::Token const& token = tokens[i];
-                typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end();
-                for(; it != itEnd; ++it ) {
-                    Arg const& arg = *it;
-
-                    try {
-                        if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) ||
-                            ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) {
-                            if( arg.takesArg() ) {
-                                if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional )
-                                    errors.push_back( "Expected argument to option: " + token.data );
-                                else
-                                    arg.boundField.set( config, tokens[++i].data );
-                            }
-                            else {
-                                arg.boundField.setFlag( config );
-                            }
-                            break;
-                        }
-                    }
-                    catch( std::exception& ex ) {
-                        errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" );
-                    }
-                }
-                if( it == itEnd ) {
-                    if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens )
-                        unusedTokens.push_back( token );
-                    else if( m_throwOnUnrecognisedTokens )
-                        errors.push_back( "unrecognised option: " + token.data );
-                }
-            }
-            if( !errors.empty() ) {
-                std::ostringstream oss;
-                for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end();
-                        it != itEnd;
-                        ++it ) {
-                    if( it != errors.begin() )
-                        oss << "\n";
-                    oss << *it;
-                }
-                throw std::runtime_error( oss.str() );
-            }
-            return unusedTokens;
-        }
-        std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
-            std::vector<Parser::Token> unusedTokens;
-            int position = 1;
-            for( std::size_t i = 0; i < tokens.size(); ++i ) {
-                Parser::Token const& token = tokens[i];
-                typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position );
-                if( it != m_positionalArgs.end() )
-                    it->second.boundField.set( config, token.data );
-                else
-                    unusedTokens.push_back( token );
-                if( token.type == Parser::Token::Positional )
-                    position++;
-            }
-            return unusedTokens;
-        }
-        std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
-            if( !m_floatingArg.get() )
-                return tokens;
-            std::vector<Parser::Token> unusedTokens;
-            for( std::size_t i = 0; i < tokens.size(); ++i ) {
-                Parser::Token const& token = tokens[i];
-                if( token.type == Parser::Token::Positional )
-                    m_floatingArg->boundField.set( config, token.data );
-                else
-                    unusedTokens.push_back( token );
-            }
-            return unusedTokens;
-        }
-
-        void validate() const
-        {
-            if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() )
-                throw std::logic_error( "No options or arguments specified" );
-
-            for( typename std::vector<Arg>::const_iterator  it = m_options.begin(),
-                                                            itEnd = m_options.end();
-                    it != itEnd; ++it )
-                it->validate();
-        }
-
-    private:
-        Detail::BoundArgFunction<ConfigT> m_boundProcessName;
-        std::vector<Arg> m_options;
-        std::map<int, Arg> m_positionalArgs;
-        ArgAutoPtr m_floatingArg;
-        int m_highestSpecifiedArgPosition;
-        bool m_throwOnUnrecognisedTokens;
-    };
-
-} // end namespace Clara
-
-STITCH_CLARA_CLOSE_NAMESPACE
-#undef STITCH_CLARA_OPEN_NAMESPACE
-#undef STITCH_CLARA_CLOSE_NAMESPACE
-
-#endif // TWOBLUECUBES_CLARA_H_INCLUDED
-#undef STITCH_CLARA_OPEN_NAMESPACE
-
-// Restore Clara's value for console width, if present
-#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
-#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
-#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
-#endif
-
-#include <fstream>
-
-namespace Catch {
-
-    inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; }
-    inline void abortAfterX( ConfigData& config, int x ) {
-        if( x < 1 )
-            throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" );
-        config.abortAfter = x;
-    }
-    inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
-
-    inline void addWarning( ConfigData& config, std::string const& _warning ) {
-        if( _warning == "NoAssertions" )
-            config.warnings = (WarnAbout::What)( config.warnings | WarnAbout::NoAssertions );
-        else
-            throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" );
-
-    }
-    inline void setVerbosity( ConfigData& config, int level ) {
-        // !TBD: accept strings?
-        config.verbosity = (Verbosity::Level)level;
-    }
-    inline void setShowDurations( ConfigData& config, bool _showDurations ) {
-        config.showDurations = _showDurations
-            ? ShowDurations::Always
-            : ShowDurations::Never;
-    }
-    inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) {
-        std::ifstream f( _filename.c_str() );
-        if( !f.is_open() )
-            throw std::domain_error( "Unable to load input file: " + _filename );
-
-        std::string line;
-        while( std::getline( f, line ) ) {
-            line = trim(line);
-            if( !line.empty() && !startsWith( line, "#" ) )
-                addTestOrTags( config, "\"" + line + "\"" );
-        }
-    }
-
-    inline Clara::CommandLine<ConfigData> makeCommandLineParser() {
-
-        using namespace Clara;
-        CommandLine<ConfigData> cli;
-
-        cli.bindProcessName( &ConfigData::processName );
-
-        cli["-?"]["-h"]["--help"]
-            .describe( "display usage information" )
-            .bind( &ConfigData::showHelp );
-
-        cli["-l"]["--list-tests"]
-            .describe( "list all/matching test cases" )
-            .bind( &ConfigData::listTests );
-
-        cli["-t"]["--list-tags"]
-            .describe( "list all/matching tags" )
-            .bind( &ConfigData::listTags );
-
-        cli["-s"]["--success"]
-            .describe( "include successful tests in output" )
-            .bind( &ConfigData::showSuccessfulTests );
-
-        cli["-b"]["--break"]
-            .describe( "break into debugger on failure" )
-            .bind( &ConfigData::shouldDebugBreak );
-
-        cli["-e"]["--nothrow"]
-            .describe( "skip exception tests" )
-            .bind( &ConfigData::noThrow );
-
-        cli["-i"]["--invisibles"]
-            .describe( "show invisibles (tabs, newlines)" )
-            .bind( &ConfigData::showInvisibles );
-
-        cli["-o"]["--out"]
-            .describe( "output filename" )
-            .bind( &ConfigData::outputFilename, "filename" );
-
-        cli["-r"]["--reporter"]
-//            .placeholder( "name[:filename]" )
-            .describe( "reporter to use (defaults to console)" )
-            .bind( &ConfigData::reporterName, "name" );
-
-        cli["-n"]["--name"]
-            .describe( "suite name" )
-            .bind( &ConfigData::name, "name" );
-
-        cli["-a"]["--abort"]
-            .describe( "abort at first failure" )
-            .bind( &abortAfterFirst );
-
-        cli["-x"]["--abortx"]
-            .describe( "abort after x failures" )
-            .bind( &abortAfterX, "no. failures" );
-
-        cli["-w"]["--warn"]
-            .describe( "enable warnings" )
-            .bind( &addWarning, "warning name" );
-
-// - needs updating if reinstated
-//        cli.into( &setVerbosity )
-//            .describe( "level of verbosity (0=no output)" )
-//            .shortOpt( "v")
-//            .longOpt( "verbosity" )
-//            .placeholder( "level" );
-
-        cli[_]
-            .describe( "which test or tests to use" )
-            .bind( &addTestOrTags, "test name, pattern or tags" );
-
-        cli["-d"]["--durations"]
-            .describe( "show test durations" )
-            .bind( &setShowDurations, "yes/no" );
-
-        cli["-f"]["--input-file"]
-            .describe( "load test names to run from a file" )
-            .bind( &loadTestNamesFromFile, "filename" );
-
-        // Less common commands which don't have a short form
-        cli["--list-test-names-only"]
-            .describe( "list all/matching test cases names only" )
-            .bind( &ConfigData::listTestNamesOnly );
-
-        cli["--list-reporters"]
-            .describe( "list all reporters" )
-            .bind( &ConfigData::listReporters );
-
-        return cli;
-    }
-
-} // end namespace Catch
-
-// #included from: internal/catch_list.hpp
-#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
-
-// #included from: catch_text.h
-#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED
-
-#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
-
-#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch
-// #included from: ../external/tbc_text_format.h
-// Only use header guard if we are not using an outer namespace
-#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
-#  ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
-#   define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
-#  endif
-# else
-#  define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
-# endif
-#endif
-#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
-#include <string>
-#include <vector>
-#include <sstream>
-
-// Use optional outer namespace
-#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
-#endif
-
-namespace Tbc {
-
-#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
-    const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
-#else
-    const unsigned int consoleWidth = 80;
-#endif
-
-    struct TextAttributes {
-        TextAttributes()
-        :   initialIndent( std::string::npos ),
-            indent( 0 ),
-            width( consoleWidth-1 ),
-            tabChar( '\t' )
-        {}
-
-        TextAttributes& setInitialIndent( std::size_t _value )  { initialIndent = _value; return *this; }
-        TextAttributes& setIndent( std::size_t _value )         { indent = _value; return *this; }
-        TextAttributes& setWidth( std::size_t _value )          { width = _value; return *this; }
-        TextAttributes& setTabChar( char _value )               { tabChar = _value; return *this; }
-
-        std::size_t initialIndent;  // indent of first line, or npos
-        std::size_t indent;         // indent of subsequent lines, or all if initialIndent is npos
-        std::size_t width;          // maximum width of text, including indent. Longer text will wrap
-        char tabChar;               // If this char is seen the indent is changed to current pos
-    };
-
-    class Text {
-    public:
-        Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
-        : attr( _attr )
-        {
-            std::string wrappableChars = " [({.,/|\\-";
-            std::size_t indent = _attr.initialIndent != std::string::npos
-                ? _attr.initialIndent
-                : _attr.indent;
-            std::string remainder = _str;
-
-            while( !remainder.empty() ) {
-                if( lines.size() >= 1000 ) {
-                    lines.push_back( "... message truncated due to excessive size" );
-                    return;
-                }
-                std::size_t tabPos = std::string::npos;
-                std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
-                std::size_t pos = remainder.find_first_of( '\n' );
-                if( pos <= width ) {
-                    width = pos;
-                }
-                pos = remainder.find_last_of( _attr.tabChar, width );
-                if( pos != std::string::npos ) {
-                    tabPos = pos;
-                    if( remainder[width] == '\n' )
-                        width--;
-                    remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
-                }
-
-                if( width == remainder.size() ) {
-                    spliceLine( indent, remainder, width );
-                }
-                else if( remainder[width] == '\n' ) {
-                    spliceLine( indent, remainder, width );
-                    if( width <= 1 || remainder.size() != 1 )
-                        remainder = remainder.substr( 1 );
-                    indent = _attr.indent;
-                }
-                else {
-                    pos = remainder.find_last_of( wrappableChars, width );
-                    if( pos != std::string::npos && pos > 0 ) {
-                        spliceLine( indent, remainder, pos );
-                        if( remainder[0] == ' ' )
-                            remainder = remainder.substr( 1 );
-                    }
-                    else {
-                        spliceLine( indent, remainder, width-1 );
-                        lines.back() += "-";
-                    }
-                    if( lines.size() == 1 )
-                        indent = _attr.indent;
-                    if( tabPos != std::string::npos )
-                        indent += tabPos;
-                }
-            }
-        }
-
-        void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
-            lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
-            _remainder = _remainder.substr( _pos );
-        }
-
-        typedef std::vector<std::string>::const_iterator const_iterator;
-
-        const_iterator begin() const { return lines.begin(); }
-        const_iterator end() const { return lines.end(); }
-        std::string const& last() const { return lines.back(); }
-        std::size_t size() const { return lines.size(); }
-        std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
-        std::string toString() const {
-            std::ostringstream oss;
-            oss << *this;
-            return oss.str();
-        }
-
-        inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
-            for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
-                it != itEnd; ++it ) {
-                if( it != _text.begin() )
-                    _stream << "\n";
-                _stream << *it;
-            }
-            return _stream;
-        }
-
-    private:
-        std::string str;
-        TextAttributes attr;
-        std::vector<std::string> lines;
-    };
-
-} // end namespace Tbc
-
-#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-} // end outer namespace
-#endif
-
-#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
-#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-
-namespace Catch {
-    using Tbc::Text;
-    using Tbc::TextAttributes;
-}
-
-// #included from: catch_console_colour.hpp
-#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED
-
-namespace Catch {
-
-    namespace Detail {
-        struct IColourImpl;
-    }
-
-    struct Colour {
-        enum Code {
-            None = 0,
-
-            White,
-            Red,
-            Green,
-            Blue,
-            Cyan,
-            Yellow,
-            Grey,
-
-            Bright = 0x10,
-
-            BrightRed = Bright | Red,
-            BrightGreen = Bright | Green,
-            LightGrey = Bright | Grey,
-            BrightWhite = Bright | White,
-
-            // By intention
-            FileName = LightGrey,
-            ResultError = BrightRed,
-            ResultSuccess = BrightGreen,
-
-            Error = BrightRed,
-            Success = Green,
-
-            OriginalExpression = Cyan,
-            ReconstructedExpression = Yellow,
-
-            SecondaryText = LightGrey,
-            Headers = White
-        };
-
-        // Use constructed object for RAII guard
-        Colour( Code _colourCode );
-        ~Colour();
-
-        // Use static method for one-shot changes
-        static void use( Code _colourCode );
-
-    private:
-        static Detail::IColourImpl* impl();
-    };
-
-} // end namespace Catch
-
-// #included from: catch_interfaces_reporter.h
-#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
-
-// #included from: catch_option.hpp
-#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED
-
-namespace Catch {
-
-    // An optional type
-    template<typename T>
-    class Option {
-    public:
-        Option() : nullableValue( NULL ) {}
-        Option( T const& _value )
-        : nullableValue( new( storage ) T( _value ) )
-        {}
-        Option( Option const& _other )
-        : nullableValue( _other ? new( storage ) T( *_other ) : NULL )
-        {}
-
-        ~Option() {
-            reset();
-        }
-
-        Option& operator= ( Option const& _other ) {
-            if( &_other != this ) {
-                reset();
-                if( _other )
-                    nullableValue = new( storage ) T( *_other );
-            }
-            return *this;
-        }
-        Option& operator = ( T const& _value ) {
-            reset();
-            nullableValue = new( storage ) T( _value );
-            return *this;
-        }
-
-        void reset() {
-            if( nullableValue )
-                nullableValue->~T();
-            nullableValue = NULL;
-        }
-
-        T& operator*() { return *nullableValue; }
-        T const& operator*() const { return *nullableValue; }
-        T* operator->() { return nullableValue; }
-        const T* operator->() const { return nullableValue; }
-
-        T valueOr( T const& defaultValue ) const {
-            return nullableValue ? *nullableValue : defaultValue;
-        }
-
-        bool some() const { return nullableValue != NULL; }
-        bool none() const { return nullableValue == NULL; }
-
-        bool operator !() const { return nullableValue == NULL; }
-        operator SafeBool::type() const {
-            return SafeBool::makeSafe( some() );
-        }
-
-    private:
-        T* nullableValue;
-        char storage[sizeof(T)];
-    };
-
-} // end namespace Catch
-
-#include <string>
-#include <ostream>
-#include <map>
-#include <assert.h>
-
-namespace Catch
-{
-    struct ReporterConfig {
-        explicit ReporterConfig( Ptr<IConfig> const& _fullConfig )
-        :   m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
-
-        ReporterConfig( Ptr<IConfig> const& _fullConfig, std::ostream& _stream )
-        :   m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
-
-        std::ostream& stream() const    { return *m_stream; }
-        Ptr<IConfig> fullConfig() const { return m_fullConfig; }
-
-    private:
-        std::ostream* m_stream;
-        Ptr<IConfig> m_fullConfig;
-    };
-
-    struct ReporterPreferences {
-        ReporterPreferences()
-        : shouldRedirectStdOut( false )
-        {}
-
-        bool shouldRedirectStdOut;
-    };
-
-    template<typename T>
-    struct LazyStat : Option<T> {
-        LazyStat() : used( false ) {}
-        LazyStat& operator=( T const& _value ) {
-            Option<T>::operator=( _value );
-            used = false;
-            return *this;
-        }
-        void reset() {
-            Option<T>::reset();
-            used = false;
-        }
-        bool used;
-    };
-
-    struct TestRunInfo {
-        TestRunInfo( std::string const& _name ) : name( _name ) {}
-        std::string name;
-    };
-    struct GroupInfo {
-        GroupInfo(  std::string const& _name,
-                    std::size_t _groupIndex,
-                    std::size_t _groupsCount )
-        :   name( _name ),
-            groupIndex( _groupIndex ),
-            groupsCounts( _groupsCount )
-        {}
-
-        std::string name;
-        std::size_t groupIndex;
-        std::size_t groupsCounts;
-    };
-
-    struct AssertionStats {
-        AssertionStats( AssertionResult const& _assertionResult,
-                        std::vector<MessageInfo> const& _infoMessages,
-                        Totals const& _totals )
-        :   assertionResult( _assertionResult ),
-            infoMessages( _infoMessages ),
-            totals( _totals )
-        {
-            if( assertionResult.hasMessage() ) {
-                // Copy message into messages list.
-                // !TBD This should have been done earlier, somewhere
-                MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
-                builder << assertionResult.getMessage();
-                builder.m_info.message = builder.m_stream.str();
-
-                infoMessages.push_back( builder.m_info );
-            }
-        }
-        virtual ~AssertionStats();
-
-#  ifdef CATCH_CPP11_OR_GREATER
-        AssertionStats( AssertionStats const& )              = default;
-        AssertionStats( AssertionStats && )                  = default;
-        AssertionStats& operator = ( AssertionStats const& ) = default;
-        AssertionStats& operator = ( AssertionStats && )     = default;
-#  endif
-
-        AssertionResult assertionResult;
-        std::vector<MessageInfo> infoMessages;
-        Totals totals;
-    };
-
-    struct SectionStats {
-        SectionStats(   SectionInfo const& _sectionInfo,
-                        Counts const& _assertions,
-                        double _durationInSeconds,
-                        bool _missingAssertions )
-        :   sectionInfo( _sectionInfo ),
-            assertions( _assertions ),
-            durationInSeconds( _durationInSeconds ),
-            missingAssertions( _missingAssertions )
-        {}
-        virtual ~SectionStats();
-#  ifdef CATCH_CPP11_OR_GREATER
-        SectionStats( SectionStats const& )              = default;
-        SectionStats( SectionStats && )                  = default;
-        SectionStats& operator = ( SectionStats const& ) = default;
-        SectionStats& operator = ( SectionStats && )     = default;
-#  endif
-
-        SectionInfo sectionInfo;
-        Counts assertions;
-        double durationInSeconds;
-        bool missingAssertions;
-    };
-
-    struct TestCaseStats {
-        TestCaseStats(  TestCaseInfo const& _testInfo,
-                        Totals const& _totals,
-                        std::string const& _stdOut,
-                        std::string const& _stdErr,
-                        bool _aborting )
-        : testInfo( _testInfo ),
-            totals( _totals ),
-            stdOut( _stdOut ),
-            stdErr( _stdErr ),
-            aborting( _aborting )
-        {}
-        virtual ~TestCaseStats();
-
-#  ifdef CATCH_CPP11_OR_GREATER
-        TestCaseStats( TestCaseStats const& )              = default;
-        TestCaseStats( TestCaseStats && )                  = default;
-        TestCaseStats& operator = ( TestCaseStats const& ) = default;
-        TestCaseStats& operator = ( TestCaseStats && )     = default;
-#  endif
-
-        TestCaseInfo testInfo;
-        Totals totals;
-        std::string stdOut;
-        std::string stdErr;
-        bool aborting;
-    };
-
-    struct TestGroupStats {
-        TestGroupStats( GroupInfo const& _groupInfo,
-                        Totals const& _totals,
-                        bool _aborting )
-        :   groupInfo( _groupInfo ),
-            totals( _totals ),
-            aborting( _aborting )
-        {}
-        TestGroupStats( GroupInfo const& _groupInfo )
-        :   groupInfo( _groupInfo ),
-            aborting( false )
-        {}
-        virtual ~TestGroupStats();
-
-#  ifdef CATCH_CPP11_OR_GREATER
-        TestGroupStats( TestGroupStats const& )              = default;
-        TestGroupStats( TestGroupStats && )                  = default;
-        TestGroupStats& operator = ( TestGroupStats const& ) = default;
-        TestGroupStats& operator = ( TestGroupStats && )     = default;
-#  endif
-
-        GroupInfo groupInfo;
-        Totals totals;
-        bool aborting;
-    };
-
-    struct TestRunStats {
-        TestRunStats(   TestRunInfo const& _runInfo,
-                        Totals const& _totals,
-                        bool _aborting )
-        :   runInfo( _runInfo ),
-            totals( _totals ),
-            aborting( _aborting )
-        {}
-        virtual ~TestRunStats();
-
-#  ifndef CATCH_CPP11_OR_GREATER
-        TestRunStats( TestRunStats const& _other )
-        :   runInfo( _other.runInfo ),
-            totals( _other.totals ),
-            aborting( _other.aborting )
-        {}
-#  else
-        TestRunStats( TestRunStats const& )              = default;
-        TestRunStats( TestRunStats && )                  = default;
-        TestRunStats& operator = ( TestRunStats const& ) = default;
-        TestRunStats& operator = ( TestRunStats && )     = default;
-#  endif
-
-        TestRunInfo runInfo;
-        Totals totals;
-        bool aborting;
-    };
-
-    struct IStreamingReporter : IShared {
-        virtual ~IStreamingReporter();
-
-        // Implementing class must also provide the following static method:
-        // static std::string getDescription();
-
-        virtual ReporterPreferences getPreferences() const = 0;
-
-        virtual void noMatchingTestCases( std::string const& spec ) = 0;
-
-        virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
-        virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
-
-        virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
-        virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
-
-        virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
-
-        virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
-        virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
-        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
-        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
-        virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
-    };
-
-    struct IReporterFactory {
-        virtual ~IReporterFactory();
-        virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0;
-        virtual std::string getDescription() const = 0;
-    };
-
-    struct IReporterRegistry {
-        typedef std::map<std::string, IReporterFactory*> FactoryMap;
-
-        virtual ~IReporterRegistry();
-        virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const = 0;
-        virtual FactoryMap const& getFactories() const = 0;
-    };
-
-}
-
-#include <limits>
-#include <algorithm>
-
-namespace Catch {
-
-    inline std::size_t listTests( Config const& config ) {
-
-        TestSpec testSpec = config.testSpec();
-        if( config.testSpec().hasFilters() )
-            std::cout << "Matching test cases:\n";
-        else {
-            std::cout << "All available test cases:\n";
-            testSpec = TestSpecParser().parse( "*" ).testSpec();
-        }
-
-        std::size_t matchedTests = 0;
-        TextAttributes nameAttr, tagsAttr;
-        nameAttr.setInitialIndent( 2 ).setIndent( 4 );
-        tagsAttr.setIndent( 6 );
-
-        std::vector<TestCase> matchedTestCases;
-        getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
-        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
-                it != itEnd;
-                ++it ) {
-            matchedTests++;
-            TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
-            Colour::Code colour = testCaseInfo.isHidden
-                ? Colour::SecondaryText
-                : Colour::None;
-            Colour colourGuard( colour );
-
-            std::cout << Text( testCaseInfo.name, nameAttr ) << std::endl;
-            if( !testCaseInfo.tags.empty() )
-                std::cout << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
-        }
-
-        if( !config.testSpec().hasFilters() )
-            std::cout << pluralise( matchedTests, "test case" ) << "\n" << std::endl;
-        else
-            std::cout << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl;
-        return matchedTests;
-    }
-
-    inline std::size_t listTestsNamesOnly( Config const& config ) {
-        TestSpec testSpec = config.testSpec();
-        if( !config.testSpec().hasFilters() )
-            testSpec = TestSpecParser().parse( "*" ).testSpec();
-        std::size_t matchedTests = 0;
-        std::vector<TestCase> matchedTestCases;
-        getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
-        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
-                it != itEnd;
-                ++it ) {
-            matchedTests++;
-            TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
-            std::cout << testCaseInfo.name << std::endl;
-        }
-        return matchedTests;
-    }
-
-    inline std::size_t listTags( Config const& config ) {
-        TestSpec testSpec = config.testSpec();
-        if( config.testSpec().hasFilters() )
-            std::cout << "Tags for matching test cases:\n";
-        else {
-            std::cout << "All available tags:\n";
-            testSpec = TestSpecParser().parse( "*" ).testSpec();
-        }
-
-        std::map<std::string, int> tagCounts;
-
-        std::vector<TestCase> matchedTestCases;
-        getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
-        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
-                it != itEnd;
-                ++it ) {
-            for( std::set<std::string>::const_iterator  tagIt = it->getTestCaseInfo().tags.begin(),
-                                                        tagItEnd = it->getTestCaseInfo().tags.end();
-                    tagIt != tagItEnd;
-                    ++tagIt ) {
-                std::string tagName = *tagIt;
-                std::map<std::string, int>::iterator countIt = tagCounts.find( tagName );
-                if( countIt == tagCounts.end() )
-                    tagCounts.insert( std::make_pair( tagName, 1 ) );
-                else
-                    countIt->second++;
-            }
-        }
-
-        for( std::map<std::string, int>::const_iterator countIt = tagCounts.begin(),
-                                                        countItEnd = tagCounts.end();
-                countIt != countItEnd;
-                ++countIt ) {
-            std::ostringstream oss;
-            oss << "  " << countIt->second << "  ";
-            Text wrapper( "[" + countIt->first + "]", TextAttributes()
-                                                        .setInitialIndent( 0 )
-                                                        .setIndent( oss.str().size() )
-                                                        .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
-            std::cout << oss.str() << wrapper << "\n";
-        }
-        std::cout << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl;
-        return tagCounts.size();
-    }
-
-    inline std::size_t listReporters( Config const& /*config*/ ) {
-        std::cout << "Available reports:\n";
-        IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
-        IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
-        std::size_t maxNameLen = 0;
-        for(it = itBegin; it != itEnd; ++it )
-            maxNameLen = (std::max)( maxNameLen, it->first.size() );
-
-        for(it = itBegin; it != itEnd; ++it ) {
-            Text wrapper( it->second->getDescription(), TextAttributes()
-                                                        .setInitialIndent( 0 )
-                                                        .setIndent( 7+maxNameLen )
-                                                        .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
-            std::cout << "  "
-                    << it->first
-                    << ":"
-                    << std::string( maxNameLen - it->first.size() + 2, ' ' )
-                    << wrapper << "\n";
-        }
-        std::cout << std::endl;
-        return factories.size();
-    }
-
-    inline Option<std::size_t> list( Config const& config ) {
-        Option<std::size_t> listedCount;
-        if( config.listTests() )
-            listedCount = listedCount.valueOr(0) + listTests( config );
-        if( config.listTestNamesOnly() )
-            listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
-        if( config.listTags() )
-            listedCount = listedCount.valueOr(0) + listTags( config );
-        if( config.listReporters() )
-            listedCount = listedCount.valueOr(0) + listReporters( config );
-        return listedCount;
-    }
-
-} // end namespace Catch
-
-// #included from: internal/catch_runner_impl.hpp
-#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
-
-// #included from: catch_test_case_tracker.hpp
-#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
-
-#include <map>
-#include <string>
-#include <assert.h>
-
-namespace Catch {
-namespace SectionTracking {
-
-    class TrackedSection {
-
-        typedef std::map<std::string, TrackedSection> TrackedSections;
-
-    public:
-        enum RunState {
-            NotStarted,
-            Executing,
-            ExecutingChildren,
-            Completed
-        };
-
-        TrackedSection( std::string const& name, TrackedSection* parent )
-        :   m_name( name ), m_runState( NotStarted ), m_parent( parent )
-        {}
-
-        RunState runState() const { return m_runState; }
-
-        TrackedSection* findChild( std::string const& childName ) {
-            TrackedSections::iterator it = m_children.find( childName );
-            return it != m_children.end()
-                ? &it->second
-                : NULL;
-        }
-        TrackedSection* acquireChild( std::string const& childName ) {
-            if( TrackedSection* child = findChild( childName ) )
-                return child;
-            m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) );
-            return findChild( childName );
-        }
-        void enter() {
-            if( m_runState == NotStarted )
-                m_runState = Executing;
-        }
-        void leave() {
-            for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end();
-                    it != itEnd;
-                    ++it )
-                if( it->second.runState() != Completed ) {
-                    m_runState = ExecutingChildren;
-                    return;
-                }
-            m_runState = Completed;
-        }
-        TrackedSection* getParent() {
-            return m_parent;
-        }
-        bool hasChildren() const {
-            return !m_children.empty();
-        }
-
-    private:
-        std::string m_name;
-        RunState m_runState;
-        TrackedSections m_children;
-        TrackedSection* m_parent;
-
-    };
-
-    class TestCaseTracker {
-    public:
-        TestCaseTracker( std::string const& testCaseName )
-        :   m_testCase( testCaseName, NULL ),
-            m_currentSection( &m_testCase ),
-            m_completedASectionThisRun( false )
-        {}
-
-        bool enterSection( std::string const& name ) {
-            TrackedSection* child = m_currentSection->acquireChild( name );
-            if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed )
-                return false;
-
-            m_currentSection = child;
-            m_currentSection->enter();
-            return true;
-        }
-        void leaveSection() {
-            m_currentSection->leave();
-            m_currentSection = m_currentSection->getParent();
-            assert( m_currentSection != NULL );
-            m_completedASectionThisRun = true;
-        }
-
-        bool currentSectionHasChildren() const {
-            return m_currentSection->hasChildren();
-        }
-        bool isCompleted() const {
-            return m_testCase.runState() == TrackedSection::Completed;
-        }
-
-        class Guard {
-        public:
-            Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) {
-                m_tracker.enterTestCase();
-            }
-            ~Guard() {
-                m_tracker.leaveTestCase();
-            }
-        private:
-            Guard( Guard const& );
-            void operator = ( Guard const& );
-            TestCaseTracker& m_tracker;
-        };
-
-    private:
-        void enterTestCase() {
-            m_currentSection = &m_testCase;
-            m_completedASectionThisRun = false;
-            m_testCase.enter();
-        }
-        void leaveTestCase() {
-            m_testCase.leave();
-        }
-
-        TrackedSection m_testCase;
-        TrackedSection* m_currentSection;
-        bool m_completedASectionThisRun;
-    };
-
-} // namespace SectionTracking
-
-using SectionTracking::TestCaseTracker;
-
-} // namespace Catch
-
-#include <set>
-#include <string>
-
-namespace Catch {
-
-    class StreamRedirect {
-
-    public:
-        StreamRedirect( std::ostream& stream, std::string& targetString )
-        :   m_stream( stream ),
-            m_prevBuf( stream.rdbuf() ),
-            m_targetString( targetString )
-        {
-            stream.rdbuf( m_oss.rdbuf() );
-        }
-
-        ~StreamRedirect() {
-            m_targetString += m_oss.str();
-            m_stream.rdbuf( m_prevBuf );
-        }
-
-    private:
-        std::ostream& m_stream;
-        std::streambuf* m_prevBuf;
-        std::ostringstream m_oss;
-        std::string& m_targetString;
-    };
-
-    ///////////////////////////////////////////////////////////////////////////
-
-    class RunContext : public IResultCapture, public IRunner {
-
-        RunContext( RunContext const& );
-        void operator =( RunContext const& );
-
-    public:
-
-        explicit RunContext( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> const& reporter )
-        :   m_runInfo( config->name() ),
-            m_context( getCurrentMutableContext() ),
-            m_activeTestCase( NULL ),
-            m_config( config ),
-            m_reporter( reporter ),
-            m_prevRunner( &m_context.getRunner() ),
-            m_prevResultCapture( &m_context.getResultCapture() ),
-            m_prevConfig( m_context.getConfig() )
-        {
-            m_context.setRunner( this );
-            m_context.setConfig( m_config );
-            m_context.setResultCapture( this );
-            m_reporter->testRunStarting( m_runInfo );
-        }
-
-        virtual ~RunContext() {
-            m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
-            m_context.setRunner( m_prevRunner );
-            m_context.setConfig( NULL );
-            m_context.setResultCapture( m_prevResultCapture );
-            m_context.setConfig( m_prevConfig );
-        }
-
-        void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
-            m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) );
-        }
-        void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) {
-            m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) );
-        }
-
-        Totals runTest( TestCase const& testCase ) {
-            Totals prevTotals = m_totals;
-
-            std::string redirectedCout;
-            std::string redirectedCerr;
-
-            TestCaseInfo testInfo = testCase.getTestCaseInfo();
-
-            m_reporter->testCaseStarting( testInfo );
-
-            m_activeTestCase = &testCase;
-            m_testCaseTracker = TestCaseTracker( testInfo.name );
-
-            do {
-                do {
-                    runCurrentTest( redirectedCout, redirectedCerr );
-                }
-                while( !m_testCaseTracker->isCompleted() && !aborting() );
-            }
-            while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
-
-            Totals deltaTotals = m_totals.delta( prevTotals );
-            m_totals.testCases += deltaTotals.testCases;
-            m_reporter->testCaseEnded( TestCaseStats(   testInfo,
-                                                        deltaTotals,
-                                                        redirectedCout,
-                                                        redirectedCerr,
-                                                        aborting() ) );
-
-            m_activeTestCase = NULL;
-            m_testCaseTracker.reset();
-
-            return deltaTotals;
-        }
-
-        Ptr<IConfig const> config() const {
-            return m_config;
-        }
-
-    private: // IResultCapture
-
-        virtual ResultAction::Value acceptExpression( ExpressionResultBuilder const& assertionResult, AssertionInfo const& assertionInfo ) {
-            m_lastAssertionInfo = assertionInfo;
-            return actOnCurrentResult( assertionResult.buildResult( assertionInfo ) );
-        }
-
-        virtual void assertionEnded( AssertionResult const& result ) {
-            if( result.getResultType() == ResultWas::Ok ) {
-                m_totals.assertions.passed++;
-            }
-            else if( !result.isOk() ) {
-                m_totals.assertions.failed++;
-            }
-
-            if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) )
-                m_messages.clear();
-
-            // Reset working state
-            m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
-        }
-
-        virtual bool sectionStarted (
-            SectionInfo const& sectionInfo,
-            Counts& assertions
-        )
-        {
-            std::ostringstream oss;
-            oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
-
-            if( !m_testCaseTracker->enterSection( oss.str() ) )
-                return false;
-
-            m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
-
-            m_reporter->sectionStarting( sectionInfo );
-
-            assertions = m_totals.assertions;
-
-            return true;
-        }
-        bool testForMissingAssertions( Counts& assertions ) {
-            if( assertions.total() != 0 ||
-                    !m_config->warnAboutMissingAssertions() ||
-                    m_testCaseTracker->currentSectionHasChildren() )
-                return false;
-            m_totals.assertions.failed++;
-            assertions.failed++;
-            return true;
-        }
-
-        virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) {
-            if( std::uncaught_exception() ) {
-                m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) );
-                return;
-            }
-
-            Counts assertions = m_totals.assertions - prevAssertions;
-            bool missingAssertions = testForMissingAssertions( assertions );
-
-            m_testCaseTracker->leaveSection();
-
-            m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) );
-            m_messages.clear();
-        }
-
-        virtual void pushScopedMessage( MessageInfo const& message ) {
-            m_messages.push_back( message );
-        }
-
-        virtual void popScopedMessage( MessageInfo const& message ) {
-            m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() );
-        }
-
-        virtual bool shouldDebugBreak() const {
-            return m_config->shouldDebugBreak();
-        }
-
-        virtual std::string getCurrentTestName() const {
-            return m_activeTestCase
-                ? m_activeTestCase->getTestCaseInfo().name
-                : "";
-        }
-
-        virtual const AssertionResult* getLastResult() const {
-            return &m_lastResult;
-        }
-
-    public:
-        // !TBD We need to do this another way!
-        bool aborting() const {
-            return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() );
-        }
-
-    private:
-
-        ResultAction::Value actOnCurrentResult( AssertionResult const& result ) {
-            m_lastResult = result;
-            assertionEnded( m_lastResult );
-
-            ResultAction::Value action = ResultAction::None;
-
-            if( !m_lastResult.isOk() ) {
-                action = ResultAction::Failed;
-                if( shouldDebugBreak() )
-                    action = (ResultAction::Value)( action | ResultAction::Debug );
-                if( aborting() )
-                    action = (ResultAction::Value)( action | ResultAction::Abort );
-            }
-            return action;
-        }
-
-        void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
-            TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
-            SectionInfo testCaseSection( testCaseInfo.name, testCaseInfo.description, testCaseInfo.lineInfo );
-            m_reporter->sectionStarting( testCaseSection );
-            Counts prevAssertions = m_totals.assertions;
-            double duration = 0;
-            try {
-                m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
-                TestCaseTracker::Guard guard( *m_testCaseTracker );
-
-                Timer timer;
-                timer.start();
-                if( m_reporter->getPreferences().shouldRedirectStdOut ) {
-                    StreamRedirect coutRedir( std::cout, redirectedCout );
-                    StreamRedirect cerrRedir( std::cerr, redirectedCerr );
-                    m_activeTestCase->invoke();
-                }
-                else {
-                    m_activeTestCase->invoke();
-                }
-                duration = timer.getElapsedSeconds();
-            }
-            catch( TestFailureException& ) {
-                // This just means the test was aborted due to failure
-            }
-            catch(...) {
-                ExpressionResultBuilder exResult( ResultWas::ThrewException );
-                exResult << translateActiveException();
-                actOnCurrentResult( exResult.buildResult( m_lastAssertionInfo )  );
-            }
-            // If sections ended prematurely due to an exception we stored their
-            // infos here so we can tear them down outside the unwind process.
-            for( std::vector<UnfinishedSections>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
-                        itEnd = m_unfinishedSections.rend();
-                    it != itEnd;
-                    ++it )
-                sectionEnded( it->info, it->prevAssertions, it->durationInSeconds );
-            m_unfinishedSections.clear();
-            m_messages.clear();
-
-            Counts assertions = m_totals.assertions - prevAssertions;
-            bool missingAssertions = testForMissingAssertions( assertions );
-
-            SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
-            m_reporter->sectionEnded( testCaseSectionStats );
-        }
-
-    private:
-        struct UnfinishedSections {
-            UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds )
-            : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
-            {}
-
-            SectionInfo info;
-            Counts prevAssertions;
-            double durationInSeconds;
-        };
-
-        TestRunInfo m_runInfo;
-        IMutableContext& m_context;
-        TestCase const* m_activeTestCase;
-        Option<TestCaseTracker> m_testCaseTracker;
-        AssertionResult m_lastResult;
-
-        Ptr<IConfig const> m_config;
-        Totals m_totals;
-        Ptr<IStreamingReporter> m_reporter;
-        std::vector<MessageInfo> m_messages;
-        IRunner* m_prevRunner;
-        IResultCapture* m_prevResultCapture;
-        Ptr<IConfig const> m_prevConfig;
-        AssertionInfo m_lastAssertionInfo;
-        std::vector<UnfinishedSections> m_unfinishedSections;
-    };
-
-} // end namespace Catch
-
-// #included from: internal/catch_version.h
-#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED
-
-namespace Catch {
-
-    // Versioning information
-    struct Version {
-        Version(    unsigned int _majorVersion,
-                    unsigned int _minorVersion,
-                    unsigned int _buildNumber,
-                    char const* const _branchName )
-        :   majorVersion( _majorVersion ),
-            minorVersion( _minorVersion ),
-            buildNumber( _buildNumber ),
-            branchName( _branchName )
-        {}
-
-        unsigned int const majorVersion;
-        unsigned int const minorVersion;
-        unsigned int const buildNumber;
-        char const* const branchName;
-
-    private:
-        void operator=( Version const& );
-    };
-
-    extern Version libraryVersion;
-}
-
-#include <fstream>
-#include <stdlib.h>
-#include <limits>
-
-namespace Catch {
-
-    class Runner {
-
-    public:
-        Runner( Ptr<Config> const& config )
-        :   m_config( config )
-        {
-            openStream();
-            makeReporter();
-        }
-
-        Totals runTests() {
-
-            RunContext context( m_config.get(), m_reporter );
-
-            Totals totals;
-
-            context.testGroupStarting( "", 1, 1 ); // deprecated?
-
-            TestSpec testSpec = m_config->testSpec();
-            if( !testSpec.hasFilters() )
-                testSpec = TestSpecParser().parse( "~[.]" ).testSpec(); // All not hidden tests
-
-            std::vector<TestCase> testCases;
-            getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases );
-
-            int testsRunForGroup = 0;
-            for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
-                    it != itEnd;
-                    ++it ) {
-                testsRunForGroup++;
-                if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) {
-
-                    if( context.aborting() )
-                        break;
-
-                    totals += context.runTest( *it );
-                    m_testsAlreadyRun.insert( *it );
-                }
-            }
-            context.testGroupEnded( "", totals, 1, 1 );
-            return totals;
-        }
-
-    private:
-        void openStream() {
-            // Open output file, if specified
-            if( !m_config->getFilename().empty() ) {
-                m_ofs.open( m_config->getFilename().c_str() );
-                if( m_ofs.fail() ) {
-                    std::ostringstream oss;
-                    oss << "Unable to open file: '" << m_config->getFilename() << "'";
-                    throw std::domain_error( oss.str() );
-                }
-                m_config->setStreamBuf( m_ofs.rdbuf() );
-            }
-        }
-        void makeReporter() {
-            std::string reporterName = m_config->getReporterName().empty()
-                ? "console"
-                : m_config->getReporterName();
-
-            m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() );
-            if( !m_reporter ) {
-                std::ostringstream oss;
-                oss << "No reporter registered with name: '" << reporterName << "'";
-                throw std::domain_error( oss.str() );
-            }
-        }
-
-    private:
-        Ptr<Config> m_config;
-        std::ofstream m_ofs;
-        Ptr<IStreamingReporter> m_reporter;
-        std::set<TestCase> m_testsAlreadyRun;
-    };
-
-    class Session {
-        static bool alreadyInstantiated;
-
-    public:
-
-        struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; };
-
-        Session()
-        : m_cli( makeCommandLineParser() ) {
-            if( alreadyInstantiated ) {
-                std::string msg = "Only one instance of Catch::Session can ever be used";
-                std::cerr << msg << std::endl;
-                throw std::logic_error( msg );
-            }
-            alreadyInstantiated = true;
-        }
-        ~Session() {
-            Catch::cleanUp();
-        }
-
-        void showHelp( std::string const& processName ) {
-            std::cout << "\nCatch v"    << libraryVersion.majorVersion << "."
-                                        << libraryVersion.minorVersion << " build "
-                                        << libraryVersion.buildNumber;
-            if( libraryVersion.branchName != std::string( "master" ) )
-                std::cout << " (" << libraryVersion.branchName << " branch)";
-            std::cout << "\n";
-
-            m_cli.usage( std::cout, processName );
-            std::cout << "For more detail usage please see the project docs\n" << std::endl;
-        }
-
-        int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
-            try {
-                m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
-                m_unusedTokens = m_cli.parseInto( argc, argv, m_configData );
-                if( m_configData.showHelp )
-                    showHelp( m_configData.processName );
-                m_config.reset();
-            }
-            catch( std::exception& ex ) {
-                {
-                    Colour colourGuard( Colour::Red );
-                    std::cerr   << "\nError(s) in input:\n"
-                                << Text( ex.what(), TextAttributes().setIndent(2) )
-                                << "\n\n";
-                }
-                m_cli.usage( std::cout, m_configData.processName );
-                return (std::numeric_limits<int>::max)();
-            }
-            return 0;
-        }
-
-        void useConfigData( ConfigData const& _configData ) {
-            m_configData = _configData;
-            m_config.reset();
-        }
-
-        int run( int argc, char* const argv[] ) {
-
-            int returnCode = applyCommandLine( argc, argv );
-            if( returnCode == 0 )
-                returnCode = run();
-            return returnCode;
-        }
-
-        int run() {
-            if( m_configData.showHelp )
-                return 0;
-
-            try
-            {
-                config(); // Force config to be constructed
-                Runner runner( m_config );
-
-                // Handle list request
-                if( Option<std::size_t> listed = list( config() ) )
-                    return static_cast<int>( *listed );
-
-                return static_cast<int>( runner.runTests().assertions.failed );
-            }
-            catch( std::exception& ex ) {
-                std::cerr << ex.what() << std::endl;
-                return (std::numeric_limits<int>::max)();
-            }
-        }
-
-        Clara::CommandLine<ConfigData> const& cli() const {
-            return m_cli;
-        }
-        std::vector<Clara::Parser::Token> const& unusedTokens() const {
-            return m_unusedTokens;
-        }
-        ConfigData& configData() {
-            return m_configData;
-        }
-        Config& config() {
-            if( !m_config )
-                m_config = new Config( m_configData );
-            return *m_config;
-        }
-
-    private:
-        Clara::CommandLine<ConfigData> m_cli;
-        std::vector<Clara::Parser::Token> m_unusedTokens;
-        ConfigData m_configData;
-        Ptr<Config> m_config;
-    };
-
-    bool Session::alreadyInstantiated = false;
-
-} // end namespace Catch
-
-// #included from: catch_registry_hub.hpp
-#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED
-
-// #included from: catch_test_case_registry_impl.hpp
-#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
-
-#include <vector>
-#include <set>
-#include <sstream>
-#include <iostream>
-
-namespace Catch {
-
-    class TestRegistry : public ITestCaseRegistry {
-    public:
-        TestRegistry() : m_unnamedCount( 0 ) {}
-        virtual ~TestRegistry();
-
-        virtual void registerTest( TestCase const& testCase ) {
-            std::string name = testCase.getTestCaseInfo().name;
-            if( name == "" ) {
-                std::ostringstream oss;
-                oss << "Anonymous test case " << ++m_unnamedCount;
-                return registerTest( testCase.withName( oss.str() ) );
-            }
-
-            if( m_functions.find( testCase ) == m_functions.end() ) {
-                m_functions.insert( testCase );
-                m_functionsInOrder.push_back( testCase );
-                if( !testCase.isHidden() )
-                    m_nonHiddenFunctions.push_back( testCase );
-            }
-            else {
-                TestCase const& prev = *m_functions.find( testCase );
-                {
-                    Colour colourGuard( Colour::Red );
-                    std::cerr   << "error: TEST_CASE( \"" << name << "\" ) already defined.\n"
-                                << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n"
-                                << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl;
-                }
-                exit(1);
-            }
-        }
-
-        virtual std::vector<TestCase> const& getAllTests() const {
-            return m_functionsInOrder;
-        }
-
-        virtual std::vector<TestCase> const& getAllNonHiddenTests() const {
-            return m_nonHiddenFunctions;
-        }
-
-        virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases ) const {
-            for( std::vector<TestCase>::const_iterator  it = m_functionsInOrder.begin(),
-                                                        itEnd = m_functionsInOrder.end();
-                    it != itEnd;
-                    ++it ) {
-                if( testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ) )
-                    matchingTestCases.push_back( *it );
-            }
-        }
-
-    private:
-
-        std::set<TestCase> m_functions;
-        std::vector<TestCase> m_functionsInOrder;
-        std::vector<TestCase> m_nonHiddenFunctions;
-        size_t m_unnamedCount;
-    };
-
-    ///////////////////////////////////////////////////////////////////////////
-
-    class FreeFunctionTestCase : public SharedImpl<ITestCase> {
-    public:
-
-        FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {}
-
-        virtual void invoke() const {
-            m_fun();
-        }
-
-    private:
-        virtual ~FreeFunctionTestCase();
-
-        TestFunction m_fun;
-    };
-
-    inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
-        std::string className = classOrQualifiedMethodName;
-        if( startsWith( className, "&" ) )
-        {
-            std::size_t lastColons = className.rfind( "::" );
-            std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
-            if( penultimateColons == std::string::npos )
-                penultimateColons = 1;
-            className = className.substr( penultimateColons, lastColons-penultimateColons );
-        }
-        return className;
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-
-    AutoReg::AutoReg(   TestFunction function,
-                        SourceLineInfo const& lineInfo,
-                        NameAndDesc const& nameAndDesc ) {
-        registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo );
-    }
-
-    AutoReg::~AutoReg() {}
-
-    void AutoReg::registerTestCase( ITestCase* testCase,
-                                    char const* classOrQualifiedMethodName,
-                                    NameAndDesc const& nameAndDesc,
-                                    SourceLineInfo const& lineInfo ) {
-
-        getMutableRegistryHub().registerTest
-            ( makeTestCase( testCase,
-                            extractClassName( classOrQualifiedMethodName ),
-                            nameAndDesc.name,
-                            nameAndDesc.description,
-                            lineInfo ) );
-    }
-
-} // end namespace Catch
-
-// #included from: catch_reporter_registry.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
-
-#include <map>
-
-namespace Catch {
-
-    class ReporterRegistry : public IReporterRegistry {
-
-    public:
-
-        virtual ~ReporterRegistry() {
-            deleteAllValues( m_factories );
-        }
-
-        virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const {
-            FactoryMap::const_iterator it =  m_factories.find( name );
-            if( it == m_factories.end() )
-                return NULL;
-            return it->second->create( ReporterConfig( config ) );
-        }
-
-        void registerReporter( std::string const& name, IReporterFactory* factory ) {
-            m_factories.insert( std::make_pair( name, factory ) );
-        }
-
-        FactoryMap const& getFactories() const {
-            return m_factories;
-        }
-
-    private:
-        FactoryMap m_factories;
-    };
-}
-
-// #included from: catch_exception_translator_registry.hpp
-#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
-
-#ifdef __OBJC__
-#import "Foundation/Foundation.h"
-#endif
-
-namespace Catch {
-
-    class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
-    public:
-        ~ExceptionTranslatorRegistry() {
-            deleteAll( m_translators );
-        }
-
-        virtual void registerTranslator( const IExceptionTranslator* translator ) {
-            m_translators.push_back( translator );
-        }
-
-        virtual std::string translateActiveException() const {
-            try {
-#ifdef __OBJC__
-                // In Objective-C try objective-c exceptions first
-                @try {
-                    throw;
-                }
-                @catch (NSException *exception) {
-                    return toString( [exception description] );
-                }
-#else
-                throw;
-#endif
-            }
-            catch( std::exception& ex ) {
-                return ex.what();
-            }
-            catch( std::string& msg ) {
-                return msg;
-            }
-            catch( const char* msg ) {
-                return msg;
-            }
-            catch(...) {
-                return tryTranslators( m_translators.begin() );
-            }
-        }
-
-        std::string tryTranslators( std::vector<const IExceptionTranslator*>::const_iterator it ) const {
-            if( it == m_translators.end() )
-                return "Unknown exception";
-
-            try {
-                return (*it)->translate();
-            }
-            catch(...) {
-                return tryTranslators( it+1 );
-            }
-        }
-
-    private:
-        std::vector<const IExceptionTranslator*> m_translators;
-    };
-}
-
-namespace Catch {
-
-    namespace {
-
-        class RegistryHub : public IRegistryHub, public IMutableRegistryHub {
-
-            RegistryHub( RegistryHub const& );
-            void operator=( RegistryHub const& );
-
-        public: // IRegistryHub
-            RegistryHub() {
-            }
-            virtual IReporterRegistry const& getReporterRegistry() const {
-                return m_reporterRegistry;
-            }
-            virtual ITestCaseRegistry const& getTestCaseRegistry() const {
-                return m_testCaseRegistry;
-            }
-            virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() {
-                return m_exceptionTranslatorRegistry;
-            }
-
-        public: // IMutableRegistryHub
-            virtual void registerReporter( std::string const& name, IReporterFactory* factory ) {
-                m_reporterRegistry.registerReporter( name, factory );
-            }
-            virtual void registerTest( TestCase const& testInfo ) {
-                m_testCaseRegistry.registerTest( testInfo );
-            }
-            virtual void registerTranslator( const IExceptionTranslator* translator ) {
-                m_exceptionTranslatorRegistry.registerTranslator( translator );
-            }
-
-        private:
-            TestRegistry m_testCaseRegistry;
-            ReporterRegistry m_reporterRegistry;
-            ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
-        };
-
-        // Single, global, instance
-        inline RegistryHub*& getTheRegistryHub() {
-            static RegistryHub* theRegistryHub = NULL;
-            if( !theRegistryHub )
-                theRegistryHub = new RegistryHub();
-            return theRegistryHub;
-        }
-    }
-
-    IRegistryHub& getRegistryHub() {
-        return *getTheRegistryHub();
-    }
-    IMutableRegistryHub& getMutableRegistryHub() {
-        return *getTheRegistryHub();
-    }
-    void cleanUp() {
-        delete getTheRegistryHub();
-        getTheRegistryHub() = NULL;
-        cleanUpContext();
-    }
-    std::string translateActiveException() {
-        return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
-    }
-
-} // end namespace Catch
-
-// #included from: catch_notimplemented_exception.hpp
-#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
-
-#include <ostream>
-
-namespace Catch {
-
-    NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo )
-    :   m_lineInfo( lineInfo ) {
-        std::ostringstream oss;
-        oss << lineInfo << ": function ";
-        oss << "not implemented";
-        m_what = oss.str();
-    }
-
-    const char* NotImplementedException::what() const CATCH_NOEXCEPT {
-        return m_what.c_str();
-    }
-
-} // end namespace Catch
-
-// #included from: catch_context_impl.hpp
-#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
-
-// #included from: catch_stream.hpp
-#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
-
-// #included from: catch_streambuf.h
-#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
-
-#include <streambuf>
-
-namespace Catch {
-
-    class StreamBufBase : public std::streambuf {
-    public:
-        virtual ~StreamBufBase() CATCH_NOEXCEPT;
-    };
-}
-
-#include <stdexcept>
-#include <cstdio>
-
-namespace Catch {
-
-    template<typename WriterF, size_t bufferSize=256>
-    class StreamBufImpl : public StreamBufBase {
-        char data[bufferSize];
-        WriterF m_writer;
-
-    public:
-        StreamBufImpl() {
-            setp( data, data + sizeof(data) );
-        }
-
-        ~StreamBufImpl() CATCH_NOEXCEPT {
-            sync();
-        }
-
-    private:
-        int overflow( int c ) {
-            sync();
-
-            if( c != EOF ) {
-                if( pbase() == epptr() )
-                    m_writer( std::string( 1, static_cast<char>( c ) ) );
-                else
-                    sputc( static_cast<char>( c ) );
-            }
-            return 0;
-        }
-
-        int sync() {
-            if( pbase() != pptr() ) {
-                m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
-                setp( pbase(), epptr() );
-            }
-            return 0;
-        }
-    };
-
-    ///////////////////////////////////////////////////////////////////////////
-
-    struct OutputDebugWriter {
-
-        void operator()( std::string const&str ) {
-            writeToDebugConsole( str );
-        }
-    };
-
-    Stream::Stream()
-    : streamBuf( NULL ), isOwned( false )
-    {}
-
-    Stream::Stream( std::streambuf* _streamBuf, bool _isOwned )
-    : streamBuf( _streamBuf ), isOwned( _isOwned )
-    {}
-
-    void Stream::release() {
-        if( isOwned ) {
-            delete streamBuf;
-            streamBuf = NULL;
-            isOwned = false;
-        }
-    }
-}
-
-namespace Catch {
-
-    class Context : public IMutableContext {
-
-        Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {}
-        Context( Context const& );
-        void operator=( Context const& );
-
-    public: // IContext
-        virtual IResultCapture& getResultCapture() {
-            return *m_resultCapture;
-        }
-        virtual IRunner& getRunner() {
-            return *m_runner;
-        }
-        virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) {
-            return getGeneratorsForCurrentTest()
-            .getGeneratorInfo( fileInfo, totalSize )
-            .getCurrentIndex();
-        }
-        virtual bool advanceGeneratorsForCurrentTest() {
-            IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
-            return generators && generators->moveNext();
-        }
-
-        virtual Ptr<IConfig const> getConfig() const {
-            return m_config;
-        }
-
-    public: // IMutableContext
-        virtual void setResultCapture( IResultCapture* resultCapture ) {
-            m_resultCapture = resultCapture;
-        }
-        virtual void setRunner( IRunner* runner ) {
-            m_runner = runner;
-        }
-        virtual void setConfig( Ptr<IConfig const> const& config ) {
-            m_config = config;
-        }
-
-        friend IMutableContext& getCurrentMutableContext();
-
-    private:
-        IGeneratorsForTest* findGeneratorsForCurrentTest() {
-            std::string testName = getResultCapture().getCurrentTestName();
-
-            std::map<std::string, IGeneratorsForTest*>::const_iterator it =
-            m_generatorsByTestName.find( testName );
-            return it != m_generatorsByTestName.end()
-                ? it->second
-                : NULL;
-        }
-
-        IGeneratorsForTest& getGeneratorsForCurrentTest() {
-            IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
-            if( !generators ) {
-                std::string testName = getResultCapture().getCurrentTestName();
-                generators = createGeneratorsForTest();
-                m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
-            }
-            return *generators;
-        }
-
-    private:
-        Ptr<IConfig const> m_config;
-        IRunner* m_runner;
-        IResultCapture* m_resultCapture;
-        std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
-    };
-
-    namespace {
-        Context* currentContext = NULL;
-    }
-    IMutableContext& getCurrentMutableContext() {
-        if( !currentContext )
-            currentContext = new Context();
-        return *currentContext;
-    }
-    IContext& getCurrentContext() {
-        return getCurrentMutableContext();
-    }
-
-    Stream createStream( std::string const& streamName ) {
-        if( streamName == "stdout" ) return Stream( std::cout.rdbuf(), false );
-        if( streamName == "stderr" ) return Stream( std::cerr.rdbuf(), false );
-        if( streamName == "debug" ) return Stream( new StreamBufImpl<OutputDebugWriter>, true );
-
-        throw std::domain_error( "Unknown stream: " + streamName );
-    }
-
-    void cleanUpContext() {
-        delete currentContext;
-        currentContext = NULL;
-    }
-}
-
-// #included from: catch_console_colour_impl.hpp
-#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
-
-namespace Catch { namespace Detail {
-    struct IColourImpl {
-        virtual ~IColourImpl() {}
-        virtual void use( Colour::Code _colourCode ) = 0;
-    };
-}}
-
-#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
-
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-
-#ifdef __AFXDLL
-#include <AfxWin.h>
-#else
-#include <windows.h>
-#endif
-
-namespace Catch {
-namespace {
-
-    class Win32ColourImpl : public Detail::IColourImpl {
-    public:
-        Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
-        {
-            CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
-            GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );
-            originalAttributes = csbiInfo.wAttributes;
-        }
-
-        virtual void use( Colour::Code _colourCode ) {
-            switch( _colourCode ) {
-                case Colour::None:      return setTextAttribute( originalAttributes );
-                case Colour::White:     return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
-                case Colour::Red:       return setTextAttribute( FOREGROUND_RED );
-                case Colour::Green:     return setTextAttribute( FOREGROUND_GREEN );
-                case Colour::Blue:      return setTextAttribute( FOREGROUND_BLUE );
-                case Colour::Cyan:      return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
-                case Colour::Yellow:    return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
-                case Colour::Grey:      return setTextAttribute( 0 );
-
-                case Colour::LightGrey:     return setTextAttribute( FOREGROUND_INTENSITY );
-                case Colour::BrightRed:     return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
-                case Colour::BrightGreen:   return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
-                case Colour::BrightWhite:   return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
-
-                case Colour::Bright: throw std::logic_error( "not a colour" );
-            }
-        }
-
-    private:
-        void setTextAttribute( WORD _textAttribute ) {
-            SetConsoleTextAttribute( stdoutHandle, _textAttribute );
-        }
-        HANDLE stdoutHandle;
-        WORD originalAttributes;
-    };
-
-    inline bool shouldUseColourForPlatform() {
-        return true;
-    }
-
-    static Detail::IColourImpl* platformColourInstance() {
-        static Win32ColourImpl s_instance;
-        return &s_instance;
-    }
-
-} // end anon namespace
-} // end namespace Catch
-
-#else // Not Windows - assumed to be POSIX compatible //////////////////////////
-
-#include <unistd.h>
-
-namespace Catch {
-namespace {
-
-    // use POSIX/ ANSI console terminal codes
-    // Thanks to Adam Strzelecki for original contribution
-    // (http://github.com/nanoant)
-    // https://github.com/philsquared/Catch/pull/131
-    class PosixColourImpl : public Detail::IColourImpl {
-    public:
-        virtual void use( Colour::Code _colourCode ) {
-            switch( _colourCode ) {
-                case Colour::None:
-                case Colour::White:     return setColour( "[0m" );
-                case Colour::Red:       return setColour( "[0;31m" );
-                case Colour::Green:     return setColour( "[0;32m" );
-                case Colour::Blue:      return setColour( "[0:34m" );
-                case Colour::Cyan:      return setColour( "[0;36m" );
-                case Colour::Yellow:    return setColour( "[0;33m" );
-                case Colour::Grey:      return setColour( "[1;30m" );
-
-                case Colour::LightGrey:     return setColour( "[0;37m" );
-                case Colour::BrightRed:     return setColour( "[1;31m" );
-                case Colour::BrightGreen:   return setColour( "[1;32m" );
-                case Colour::BrightWhite:   return setColour( "[1;37m" );
-
-                case Colour::Bright: throw std::logic_error( "not a colour" );
-            }
-        }
-    private:
-        void setColour( const char* _escapeCode ) {
-            std::cout << '\033' << _escapeCode;
-        }
-    };
-
-    inline bool shouldUseColourForPlatform() {
-        return isatty(STDOUT_FILENO);
-    }
-
-    static Detail::IColourImpl* platformColourInstance() {
-        static PosixColourImpl s_instance;
-        return &s_instance;
-    }
-
-} // end anon namespace
-} // end namespace Catch
-
-#endif // not Windows
-
-namespace Catch {
-
-    namespace {
-        struct NoColourImpl : Detail::IColourImpl {
-            void use( Colour::Code ) {}
-
-            static IColourImpl* instance() {
-                static NoColourImpl s_instance;
-                return &s_instance;
-            }
-        };
-        static bool shouldUseColour() {
-            return shouldUseColourForPlatform() && !isDebuggerActive();
-        }
-    }
-
-    Colour::Colour( Code _colourCode ){ use( _colourCode ); }
-    Colour::~Colour(){ use( None ); }
-    void Colour::use( Code _colourCode ) {
-        impl()->use( _colourCode );
-    }
-
-    Detail::IColourImpl* Colour::impl() {
-        return shouldUseColour()
-            ? platformColourInstance()
-            : NoColourImpl::instance();
-    }
-
-} // end namespace Catch
-
-// #included from: catch_generators_impl.hpp
-#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
-
-#include <vector>
-#include <string>
-#include <map>
-
-namespace Catch {
-
-    struct GeneratorInfo : IGeneratorInfo {
-
-        GeneratorInfo( std::size_t size )
-        :   m_size( size ),
-            m_currentIndex( 0 )
-        {}
-
-        bool moveNext() {
-            if( ++m_currentIndex == m_size ) {
-                m_currentIndex = 0;
-                return false;
-            }
-            return true;
-        }
-
-        std::size_t getCurrentIndex() const {
-            return m_currentIndex;
-        }
-
-        std::size_t m_size;
-        std::size_t m_currentIndex;
-    };
-
-    ///////////////////////////////////////////////////////////////////////////
-
-    class GeneratorsForTest : public IGeneratorsForTest {
-
-    public:
-        ~GeneratorsForTest() {
-            deleteAll( m_generatorsInOrder );
-        }
-
-        IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) {
-            std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo );
-            if( it == m_generatorsByName.end() ) {
-                IGeneratorInfo* info = new GeneratorInfo( size );
-                m_generatorsByName.insert( std::make_pair( fileInfo, info ) );
-                m_generatorsInOrder.push_back( info );
-                return *info;
-            }
-            return *it->second;
-        }
-
-        bool moveNext() {
-            std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
-            std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
-            for(; it != itEnd; ++it ) {
-                if( (*it)->moveNext() )
-                    return true;
-            }
-            return false;
-        }
-
-    private:
-        std::map<std::string, IGeneratorInfo*> m_generatorsByName;
-        std::vector<IGeneratorInfo*> m_generatorsInOrder;
-    };
-
-    IGeneratorsForTest* createGeneratorsForTest()
-    {
-        return new GeneratorsForTest();
-    }
-
-} // end namespace Catch
-
-// #included from: catch_assertionresult.hpp
-#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
-
-namespace Catch {
-
-    AssertionInfo::AssertionInfo(   std::string const& _macroName,
-                                    SourceLineInfo const& _lineInfo,
-                                    std::string const& _capturedExpression,
-                                    ResultDisposition::Flags _resultDisposition )
-    :   macroName( _macroName ),
-        lineInfo( _lineInfo ),
-        capturedExpression( _capturedExpression ),
-        resultDisposition( _resultDisposition )
-    {}
-
-    AssertionResult::AssertionResult() {}
-
-    AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
-    :   m_info( info ),
-        m_resultData( data )
-    {}
-
-    AssertionResult::~AssertionResult() {}
-
-    // Result was a success
-    bool AssertionResult::succeeded() const {
-        return Catch::isOk( m_resultData.resultType );
-    }
-
-    // Result was a success, or failure is suppressed
-    bool AssertionResult::isOk() const {
-        return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
-    }
-
-    ResultWas::OfType AssertionResult::getResultType() const {
-        return m_resultData.resultType;
-    }
-
-    bool AssertionResult::hasExpression() const {
-        return !m_info.capturedExpression.empty();
-    }
-
-    bool AssertionResult::hasMessage() const {
-        return !m_resultData.message.empty();
-    }
-
-    std::string AssertionResult::getExpression() const {
-        if( shouldNegate( m_info.resultDisposition ) )
-            return "!" + m_info.capturedExpression;
-        else
-            return m_info.capturedExpression;
-    }
-    std::string AssertionResult::getExpressionInMacro() const {
-        if( m_info.macroName.empty() )
-            return m_info.capturedExpression;
-        else
-            return m_info.macroName + "( " + m_info.capturedExpression + " )";
-    }
-
-    bool AssertionResult::hasExpandedExpression() const {
-        return hasExpression() && getExpandedExpression() != getExpression();
-    }
-
-    std::string AssertionResult::getExpandedExpression() const {
-        return m_resultData.reconstructedExpression;
-    }
-
-    std::string AssertionResult::getMessage() const {
-        return m_resultData.message;
-    }
-    SourceLineInfo AssertionResult::getSourceInfo() const {
-        return m_info.lineInfo;
-    }
-
-    std::string AssertionResult::getTestMacroName() const {
-        return m_info.macroName;
-    }
-
-} // end namespace Catch
-
-// #included from: catch_expressionresult_builder.hpp
-#define TWOBLUECUBES_CATCH_EXPRESSIONRESULT_BUILDER_HPP_INCLUDED
-
-#include <assert.h>
-
-namespace Catch {
-
-    ExpressionResultBuilder::ExpressionResultBuilder( ResultWas::OfType resultType ) {
-        m_data.resultType = resultType;
-    }
-    ExpressionResultBuilder::ExpressionResultBuilder( ExpressionResultBuilder const& other )
-    :   m_data( other.m_data ),
-        m_exprComponents( other.m_exprComponents )
-    {
-        m_stream << other.m_stream.str();
-    }
-    ExpressionResultBuilder& ExpressionResultBuilder::operator=(ExpressionResultBuilder const& other ) {
-        m_data = other.m_data;
-        m_exprComponents = other.m_exprComponents;
-        m_stream.str("");
-        m_stream << other.m_stream.str();
-        return *this;
-    }
-    ExpressionResultBuilder& ExpressionResultBuilder::setResultType( ResultWas::OfType result ) {
-        m_data.resultType = result;
-        return *this;
-    }
-    ExpressionResultBuilder& ExpressionResultBuilder::setResultType( bool result ) {
-        m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
-        return *this;
-    }
-    ExpressionResultBuilder& ExpressionResultBuilder::endExpression( ResultDisposition::Flags resultDisposition ) {
-        m_exprComponents.shouldNegate = shouldNegate( resultDisposition );
-        return *this;
-    }
-    ExpressionResultBuilder& ExpressionResultBuilder::setLhs( std::string const& lhs ) {
-        m_exprComponents.lhs = lhs;
-        return *this;
-    }
-    ExpressionResultBuilder& ExpressionResultBuilder::setRhs( std::string const& rhs ) {
-        m_exprComponents.rhs = rhs;
-        return *this;
-    }
-    ExpressionResultBuilder& ExpressionResultBuilder::setOp( std::string const& op ) {
-        m_exprComponents.op = op;
-        return *this;
-    }
-    AssertionResult ExpressionResultBuilder::buildResult( AssertionInfo const& info ) const
-    {
-        assert( m_data.resultType != ResultWas::Unknown );
-
-        AssertionResultData data = m_data;
-
-        // Flip bool results if shouldNegate is set
-        if( m_exprComponents.shouldNegate && data.resultType == ResultWas::Ok )
-            data.resultType = ResultWas::ExpressionFailed;
-        else if( m_exprComponents.shouldNegate && data.resultType == ResultWas::ExpressionFailed )
-            data.resultType = ResultWas::Ok;
-
-        data.message = m_stream.str();
-        data.reconstructedExpression = reconstructExpression( info );
-        if( m_exprComponents.shouldNegate ) {
-            if( m_exprComponents.op == "" )
-                data.reconstructedExpression = "!" + data.reconstructedExpression;
-            else
-                data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
-        }
-        return AssertionResult( info, data );
-    }
-    std::string ExpressionResultBuilder::reconstructExpression( AssertionInfo const& info ) const {
-        if( m_exprComponents.op == "" )
-            return m_exprComponents.lhs.empty() ? info.capturedExpression : m_exprComponents.op + m_exprComponents.lhs;
-        else if( m_exprComponents.op == "matches" )
-            return m_exprComponents.lhs + " " + m_exprComponents.rhs;
-        else if( m_exprComponents.op != "!" ) {
-            if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 &&
-                m_exprComponents.lhs.find("\n") == std::string::npos &&
-                m_exprComponents.rhs.find("\n") == std::string::npos )
-                return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs;
-            else
-                return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs;
-        }
-        else
-            return "{can't expand - use " + info.macroName + "_FALSE( " + info.capturedExpression.substr(1) + " ) instead of " + info.macroName + "( " + info.capturedExpression + " ) for better diagnostics}";
-    }
-
-} // end namespace Catch
-
-// #included from: catch_test_case_info.hpp
-#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
-
-namespace Catch {
-
-    inline bool isSpecialTag( std::string const& tag ) {
-        return  tag == "." ||
-                tag == "hide" ||
-                tag == "!hide" ||
-                tag == "!throws";
-    }
-    inline bool isReservedTag( std::string const& tag ) {
-        return !isSpecialTag( tag ) && tag.size() > 0 && !isalnum( tag[0] );
-    }
-    inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
-        if( isReservedTag( tag ) ) {
-            {
-                Colour colourGuard( Colour::Red );
-                std::cerr
-                    << "Tag name [" << tag << "] not allowed.\n"
-                    << "Tag names starting with non alpha-numeric characters are reserved\n";
-            }
-            {
-                Colour colourGuard( Colour::FileName );
-                std::cerr << _lineInfo << std::endl;
-            }
-            exit(1);
-        }
-    }
-
-    TestCase makeTestCase(  ITestCase* _testCase,
-                            std::string const& _className,
-                            std::string const& _name,
-                            std::string const& _descOrTags,
-                            SourceLineInfo const& _lineInfo )
-    {
-        bool isHidden( startsWith( _name, "./" ) ); // Legacy support
-
-        // Parse out tags
-        std::set<std::string> tags;
-        std::string desc, tag;
-        bool inTag = false;
-        for( std::size_t i = 0; i < _descOrTags.size(); ++i ) {
-            char c = _descOrTags[i];
-            if( !inTag ) {
-                if( c == '[' )
-                    inTag = true;
-                else
-                    desc += c;
-            }
-            else {
-                if( c == ']' ) {
-                    enforceNotReservedTag( tag, _lineInfo );
-
-                    inTag = false;
-                    if( tag == "hide" || tag == "." ) {
-                        tags.insert( "hide" );
-                        tags.insert( "." );
-                        isHidden = true;
-                    }
-                    else {
-                        tags.insert( tag );
-                    }
-                    tag.clear();
-                }
-                else
-                    tag += c;
-            }
-        }
-        TestCaseInfo info( _name, _className, desc, tags, isHidden, _lineInfo );
-        return TestCase( _testCase, info );
-    }
-
-    TestCaseInfo::TestCaseInfo( std::string const& _name,
-                                std::string const& _className,
-                                std::string const& _description,
-                                std::set<std::string> const& _tags,
-                                bool _isHidden,
-                                SourceLineInfo const& _lineInfo )
-    :   name( _name ),
-        className( _className ),
-        description( _description ),
-        tags( _tags ),
-        lineInfo( _lineInfo ),
-        isHidden( _isHidden ),
-        throws( false )
-    {
-        std::ostringstream oss;
-        for( std::set<std::string>::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) {
-            oss << "[" << *it << "]";
-            if( *it == "!throws" )
-                throws = true;
-        }
-        tagsAsString = oss.str();
-    }
-
-    TestCaseInfo::TestCaseInfo( TestCaseInfo const& other )
-    :   name( other.name ),
-        className( other.className ),
-        description( other.description ),
-        tags( other.tags ),
-        tagsAsString( other.tagsAsString ),
-        lineInfo( other.lineInfo ),
-        isHidden( other.isHidden ),
-        throws( other.throws )
-    {}
-
-    TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {}
-
-    TestCase::TestCase( TestCase const& other )
-    :   TestCaseInfo( other ),
-        test( other.test )
-    {}
-
-    TestCase TestCase::withName( std::string const& _newName ) const {
-        TestCase other( *this );
-        other.name = _newName;
-        return other;
-    }
-
-    void TestCase::invoke() const {
-        test->invoke();
-    }
-
-    bool TestCase::isHidden() const {
-        return TestCaseInfo::isHidden;
-    }
-    bool TestCase::throws() const {
-        return TestCaseInfo::throws;
-    }
-
-    void TestCase::swap( TestCase& other ) {
-        test.swap( other.test );
-        className.swap( other.className );
-        name.swap( other.name );
-        description.swap( other.description );
-        std::swap( lineInfo, other.lineInfo );
-    }
-
-    bool TestCase::operator == ( TestCase const& other ) const {
-        return  test.get() == other.test.get() &&
-                name == other.name &&
-                className == other.className;
-    }
-
-    bool TestCase::operator < ( TestCase const& other ) const {
-        return name < other.name;
-    }
-    TestCase& TestCase::operator = ( TestCase const& other ) {
-        TestCase temp( other );
-        swap( temp );
-        return *this;
-    }
-
-    TestCaseInfo const& TestCase::getTestCaseInfo() const
-    {
-        return *this;
-    }
-
-} // end namespace Catch
-
-// #included from: catch_version.hpp
-#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED
-
-namespace Catch {
-
-    // These numbers are maintained by a script
-    Version libraryVersion( 1, 0, 45, "master" );
-}
-
-// #included from: catch_message.hpp
-#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED
-
-namespace Catch {
-
-    MessageInfo::MessageInfo(   std::string const& _macroName,
-                                SourceLineInfo const& _lineInfo,
-                                ResultWas::OfType _type )
-    :   macroName( _macroName ),
-        lineInfo( _lineInfo ),
-        type( _type ),
-        sequence( ++globalCount )
-    {}
-
-    // This may need protecting if threading support is added
-    unsigned int MessageInfo::globalCount = 0;
-
-    ////////////////////////////////////////////////////////////////////////////
-
-    ScopedMessage::ScopedMessage( MessageBuilder const& builder )
-    : m_info( builder.m_info )
-    {
-        m_info.message = builder.m_stream.str();
-        getResultCapture().pushScopedMessage( m_info );
-    }
-    ScopedMessage::~ScopedMessage() {
-        getResultCapture().popScopedMessage( m_info );
-    }
-
-} // end namespace Catch
-
-// #included from: catch_legacy_reporter_adapter.hpp
-#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
-
-// #included from: catch_legacy_reporter_adapter.h
-#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
-
-namespace Catch
-{
-    // Deprecated
-    struct IReporter : IShared {
-        virtual ~IReporter();
-
-        virtual bool shouldRedirectStdout() const = 0;
-
-        virtual void StartTesting() = 0;
-        virtual void EndTesting( Totals const& totals ) = 0;
-        virtual void StartGroup( std::string const& groupName ) = 0;
-        virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0;
-        virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0;
-        virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0;
-        virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0;
-        virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0;
-        virtual void NoAssertionsInSection( std::string const& sectionName ) = 0;
-        virtual void NoAssertionsInTestCase( std::string const& testName ) = 0;
-        virtual void Aborted() = 0;
-        virtual void Result( AssertionResult const& result ) = 0;
-    };
-
-    class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
-    {
-    public:
-        LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter );
-        virtual ~LegacyReporterAdapter();
-
-        virtual ReporterPreferences getPreferences() const;
-        virtual void noMatchingTestCases( std::string const& );
-        virtual void testRunStarting( TestRunInfo const& );
-        virtual void testGroupStarting( GroupInfo const& groupInfo );
-        virtual void testCaseStarting( TestCaseInfo const& testInfo );
-        virtual void sectionStarting( SectionInfo const& sectionInfo );
-        virtual void assertionStarting( AssertionInfo const& );
-        virtual bool assertionEnded( AssertionStats const& assertionStats );
-        virtual void sectionEnded( SectionStats const& sectionStats );
-        virtual void testCaseEnded( TestCaseStats const& testCaseStats );
-        virtual void testGroupEnded( TestGroupStats const& testGroupStats );
-        virtual void testRunEnded( TestRunStats const& testRunStats );
-
-    private:
-        Ptr<IReporter> m_legacyReporter;
-    };
-}
-
-namespace Catch
-{
-    LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter )
-    :   m_legacyReporter( legacyReporter )
-    {}
-    LegacyReporterAdapter::~LegacyReporterAdapter() {}
-
-    ReporterPreferences LegacyReporterAdapter::getPreferences() const {
-        ReporterPreferences prefs;
-        prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout();
-        return prefs;
-    }
-
-    void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {}
-    void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) {
-        m_legacyReporter->StartTesting();
-    }
-    void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) {
-        m_legacyReporter->StartGroup( groupInfo.name );
-    }
-    void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) {
-        m_legacyReporter->StartTestCase( testInfo );
-    }
-    void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) {
-        m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description );
-    }
-    void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) {
-        // Not on legacy interface
-    }
-
-    bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) {
-        if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
-            for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
-                    it != itEnd;
-                    ++it ) {
-                if( it->type == ResultWas::Info ) {
-                    ExpressionResultBuilder expressionBuilder( it->type );
-                        expressionBuilder << it->message;
-                    AssertionInfo info( it->macroName, it->lineInfo, "", ResultDisposition::Normal );
-                    AssertionResult result = expressionBuilder.buildResult( info );
-                    m_legacyReporter->Result( result );
-                }
-            }
-        }
-        m_legacyReporter->Result( assertionStats.assertionResult );
-        return true;
-    }
-    void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) {
-        if( sectionStats.missingAssertions )
-            m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name );
-        m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions );
-    }
-    void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) {
-        m_legacyReporter->EndTestCase
-            (   testCaseStats.testInfo,
-                testCaseStats.totals,
-                testCaseStats.stdOut,
-                testCaseStats.stdErr );
-    }
-    void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) {
-        if( testGroupStats.aborting )
-            m_legacyReporter->Aborted();
-        m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals );
-    }
-    void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) {
-        m_legacyReporter->EndTesting( testRunStats.totals );
-    }
-}
-
-// #included from: catch_timer.hpp
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wc++11-long-long"
-#endif
-
-#ifdef CATCH_PLATFORM_WINDOWS
-#include <windows.h>
-#else
-#include <sys/time.h>
-#endif
-
-namespace Catch {
-
-    namespace {
-#ifdef CATCH_PLATFORM_WINDOWS
-        uint64_t getCurrentTicks() {
-            static uint64_t hz=0, hzo=0;
-            if (!hz) {
-                QueryPerformanceFrequency((LARGE_INTEGER*)&hz);
-                QueryPerformanceCounter((LARGE_INTEGER*)&hzo);
-            }
-            uint64_t t;
-            QueryPerformanceCounter((LARGE_INTEGER*)&t);
-            return ((t-hzo)*1000000)/hz;
-        }
-#else
-        uint64_t getCurrentTicks() {
-            timeval t;
-            gettimeofday(&t,NULL);
-            return (uint64_t)t.tv_sec * 1000000ull + (uint64_t)t.tv_usec;
-        }
-#endif
-    }
-
-    void Timer::start() {
-        m_ticks = getCurrentTicks();
-    }
-    unsigned int Timer::getElapsedNanoseconds() const {
-        return (unsigned int)(getCurrentTicks() - m_ticks);
-    }
-    unsigned int Timer::getElapsedMilliseconds() const {
-        return (unsigned int)((getCurrentTicks() - m_ticks)/1000);
-    }
-    double Timer::getElapsedSeconds() const {
-        return (getCurrentTicks() - m_ticks)/1000000.0;
-    }
-
-} // namespace Catch
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-// #included from: catch_common.hpp
-#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
-
-namespace Catch {
-
-    bool startsWith( std::string const& s, std::string const& prefix ) {
-        return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
-    }
-    bool endsWith( std::string const& s, std::string const& suffix ) {
-        return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
-    }
-    bool contains( std::string const& s, std::string const& infix ) {
-        return s.find( infix ) != std::string::npos;
-    }
-    void toLowerInPlace( std::string& s ) {
-        std::transform( s.begin(), s.end(), s.begin(), ::tolower );
-    }
-    std::string toLower( std::string const& s ) {
-        std::string lc = s;
-        toLowerInPlace( lc );
-        return lc;
-    }
-    std::string trim( std::string const& str ) {
-        static char const* whitespaceChars = "\n\r\t ";
-        std::string::size_type start = str.find_first_not_of( whitespaceChars );
-        std::string::size_type end = str.find_last_not_of( whitespaceChars );
-
-        return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
-    }
-
-    pluralise::pluralise( std::size_t count, std::string const& label )
-    :   m_count( count ),
-        m_label( label )
-    {}
-
-    std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
-        os << pluraliser.m_count << " " << pluraliser.m_label;
-        if( pluraliser.m_count != 1 )
-            os << "s";
-        return os;
-    }
-
-    SourceLineInfo::SourceLineInfo() : line( 0 ){}
-    SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line )
-    :   file( _file ),
-        line( _line )
-    {}
-    SourceLineInfo::SourceLineInfo( SourceLineInfo const& other )
-    :   file( other.file ),
-        line( other.line )
-    {}
-    bool SourceLineInfo::empty() const {
-        return file.empty();
-    }
-    bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
-        return line == other.line && file == other.file;
-    }
-
-    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
-#ifndef __GNUG__
-        os << info.file << "(" << info.line << ")";
-#else
-        os << info.file << ":" << info.line;
-#endif
-        return os;
-    }
-
-    void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
-        std::ostringstream oss;
-        oss << locationInfo << ": Internal Catch error: '" << message << "'";
-        if( isTrue( true ))
-            throw std::logic_error( oss.str() );
-    }
-}
-
-// #included from: catch_section.hpp
-#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
-
-namespace Catch {
-
-    Section::Section(   SourceLineInfo const& lineInfo,
-                        std::string const& name,
-                        std::string const& description )
-    :   m_info( name, description, lineInfo ),
-        m_sectionIncluded( getCurrentContext().getResultCapture().sectionStarted( m_info, m_assertions ) )
-    {
-        m_timer.start();
-    }
-
-    Section::~Section() {
-        if( m_sectionIncluded )
-            getCurrentContext().getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() );
-    }
-
-    // This indicates whether the section should be executed or not
-    Section::operator bool() {
-        return m_sectionIncluded;
-    }
-
-} // end namespace Catch
-
-// #included from: catch_debugger.hpp
-#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
-
-#include <iostream>
-
-#ifdef CATCH_PLATFORM_MAC
-
-    #include <assert.h>
-    #include <stdbool.h>
-    #include <sys/types.h>
-    #include <unistd.h>
-    #include <sys/sysctl.h>
-
-    namespace Catch{
-
-        // The following function is taken directly from the following technical note:
-        // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
-
-        // Returns true if the current process is being debugged (either
-        // running under the debugger or has a debugger attached post facto).
-        bool isDebuggerActive(){
-
-            int                 mib[4];
-            struct kinfo_proc   info;
-            size_t              size;
-
-            // Initialize the flags so that, if sysctl fails for some bizarre
-            // reason, we get a predictable result.
-
-            info.kp_proc.p_flag = 0;
-
-            // Initialize mib, which tells sysctl the info we want, in this case
-            // we're looking for information about a specific process ID.
-
-            mib[0] = CTL_KERN;
-            mib[1] = KERN_PROC;
-            mib[2] = KERN_PROC_PID;
-            mib[3] = getpid();
-
-            // Call sysctl.
-
-            size = sizeof(info);
-            if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) {
-                std::cerr << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
-                return false;
-            }
-
-            // We're being debugged if the P_TRACED flag is set.
-
-            return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
-        }
-    } // namespace Catch
-
-#elif defined(_MSC_VER)
-    extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
-    namespace Catch {
-        bool isDebuggerActive() {
-            return IsDebuggerPresent() != 0;
-        }
-    }
-#elif defined(__MINGW32__)
-    extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
-    namespace Catch {
-        bool isDebuggerActive() {
-            return IsDebuggerPresent() != 0;
-        }
-    }
-#else
-    namespace Catch {
-       inline bool isDebuggerActive() { return false; }
-    }
-#endif // Platform
-
-#ifdef CATCH_PLATFORM_WINDOWS
-    extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* );
-    namespace Catch {
-        void writeToDebugConsole( std::string const& text ) {
-            ::OutputDebugStringA( text.c_str() );
-        }
-    }
-#else
-    namespace Catch {
-        void writeToDebugConsole( std::string const& text ) {
-            // !TBD: Need a version for Mac/ XCode and other IDEs
-            std::cout << text;
-        }
-    }
-#endif // Platform
-
-// #included from: catch_tostring.hpp
-#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
-
-namespace Catch {
-
-std::string toString( std::string const& value ) {
-    std::string s = value;
-    if( getCurrentContext().getConfig()->showInvisibles() ) {
-        for(size_t i = 0; i < s.size(); ++i ) {
-            std::string subs;
-            switch( s[i] ) {
-            case '\n': subs = "\\n"; break;
-            case '\t': subs = "\\t"; break;
-            default: break;
-            }
-            if( !subs.empty() ) {
-                s = s.substr( 0, i ) + subs + s.substr( i+1 );
-                ++i;
-            }
-        }
-    }
-    return "\"" + s + "\"";
-}
-std::string toString( std::wstring const& value ) {
-
-    std::string s;
-    s.reserve( value.size() );
-    for(size_t i = 0; i < value.size(); ++i )
-        s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?';
-    return toString( s );
-}
-
-std::string toString( const char* const value ) {
-    return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" );
-}
-
-std::string toString( char* const value ) {
-    return Catch::toString( static_cast<const char*>( value ) );
-}
-
-std::string toString( int value ) {
-    std::ostringstream oss;
-    oss << value;
-    return oss.str();
-}
-
-std::string toString( unsigned long value ) {
-    std::ostringstream oss;
-    if( value > 8192 )
-        oss << "0x" << std::hex << value;
-    else
-        oss << value;
-    return oss.str();
-}
-
-std::string toString( unsigned int value ) {
-    return toString( static_cast<unsigned long>( value ) );
-}
-
-std::string toString( const double value ) {
-    std::ostringstream oss;
-    oss << std::setprecision( 10 )
-        << std::fixed
-        << value;
-    std::string d = oss.str();
-    std::size_t i = d.find_last_not_of( '0' );
-    if( i != std::string::npos && i != d.size()-1 ) {
-        if( d[i] == '.' )
-            i++;
-        d = d.substr( 0, i+1 );
-    }
-    return d;
-}
-
-std::string toString( bool value ) {
-    return value ? "true" : "false";
-}
-
-std::string toString( char value ) {
-    return value < ' '
-        ? toString( static_cast<unsigned int>( value ) )
-        : Detail::makeString( value );
-}
-
-std::string toString( signed char value ) {
-    return toString( static_cast<char>( value ) );
-}
-
-std::string toString( unsigned char value ) {
-    return toString( static_cast<char>( value ) );
-}
-
-#ifdef CATCH_CONFIG_CPP11_NULLPTR
-std::string toString( std::nullptr_t ) {
-    return "nullptr";
-}
-#endif
-
-#ifdef __OBJC__
-    std::string toString( NSString const * const& nsstring ) {
-        if( !nsstring )
-            return "nil";
-        return std::string( "@\"" ) + [nsstring UTF8String] + "\"";
-    }
-    std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) {
-        if( !nsstring )
-            return "nil";
-        return std::string( "@\"" ) + [nsstring UTF8String] + "\"";
-    }
-    std::string toString( NSObject* const& nsObject ) {
-        return toString( [nsObject description] );
-    }
-#endif
-
-} // end namespace Catch
-
-// #included from: ../reporters/catch_reporter_xml.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
-
-// #included from: catch_reporter_bases.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
-
-namespace Catch {
-
-    struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
-
-        StreamingReporterBase( ReporterConfig const& _config )
-        :   m_config( _config.fullConfig() ),
-            stream( _config.stream() )
-        {}
-
-        virtual ~StreamingReporterBase();
-
-        virtual void noMatchingTestCases( std::string const& ) {}
-
-        virtual void testRunStarting( TestRunInfo const& _testRunInfo ) {
-            currentTestRunInfo = _testRunInfo;
-        }
-        virtual void testGroupStarting( GroupInfo const& _groupInfo ) {
-            currentGroupInfo = _groupInfo;
-        }
-
-        virtual void testCaseStarting( TestCaseInfo const& _testInfo ) {
-            currentTestCaseInfo = _testInfo;
-        }
-        virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
-            m_sectionStack.push_back( _sectionInfo );
-        }
-
-        virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) {
-            m_sectionStack.pop_back();
-        }
-        virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) {
-            currentTestCaseInfo.reset();
-            assert( m_sectionStack.empty() );
-        }
-        virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) {
-            currentGroupInfo.reset();
-        }
-        virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) {
-            currentTestCaseInfo.reset();
-            currentGroupInfo.reset();
-            currentTestRunInfo.reset();
-        }
-
-        Ptr<IConfig> m_config;
-        std::ostream& stream;
-
-        LazyStat<TestRunInfo> currentTestRunInfo;
-        LazyStat<GroupInfo> currentGroupInfo;
-        LazyStat<TestCaseInfo> currentTestCaseInfo;
-
-        std::vector<SectionInfo> m_sectionStack;
-    };
-
-    struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
-        template<typename T, typename ChildNodeT>
-        struct Node : SharedImpl<> {
-            explicit Node( T const& _value ) : value( _value ) {}
-            virtual ~Node() {}
-
-            typedef std::vector<Ptr<ChildNodeT> > ChildNodes;
-            T value;
-            ChildNodes children;
-        };
-        struct SectionNode : SharedImpl<> {
-            explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {}
-            virtual ~SectionNode();
-
-            bool operator == ( SectionNode const& other ) const {
-                return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
-            }
-            bool operator == ( Ptr<SectionNode> const& other ) const {
-                return operator==( *other );
-            }
-
-            SectionStats stats;
-            typedef std::vector<Ptr<SectionNode> > ChildSections;
-            typedef std::vector<AssertionStats> Assertions;
-            ChildSections childSections;
-            Assertions assertions;
-            std::string stdOut;
-            std::string stdErr;
-        };
-
-        struct BySectionInfo {
-            BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
-            bool operator() ( Ptr<SectionNode> const& node ) const {
-                return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
-            }
-        private:
-            BySectionInfo& operator=( BySectionInfo const& other ); // = delete;
-
-            SectionInfo const& m_other;
-        };
-
-        typedef Node<TestCaseStats, SectionNode> TestCaseNode;
-        typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
-        typedef Node<TestRunStats, TestGroupNode> TestRunNode;
-
-        CumulativeReporterBase( ReporterConfig const& _config )
-        :   m_config( _config.fullConfig() ),
-            stream( _config.stream() )
-        {}
-        ~CumulativeReporterBase();
-
-        virtual void testRunStarting( TestRunInfo const& ) {}
-        virtual void testGroupStarting( GroupInfo const& ) {}
-
-        virtual void testCaseStarting( TestCaseInfo const& ) {}
-
-        virtual void sectionStarting( SectionInfo const& sectionInfo ) {
-            SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
-            Ptr<SectionNode> node;
-            if( m_sectionStack.empty() ) {
-                if( !m_rootSection )
-                    m_rootSection = new SectionNode( incompleteStats );
-                node = m_rootSection;
-            }
-            else {
-                SectionNode& parentNode = *m_sectionStack.back();
-                SectionNode::ChildSections::const_iterator it =
-                    std::find_if(   parentNode.childSections.begin(),
-                                    parentNode.childSections.end(),
-                                    BySectionInfo( sectionInfo ) );
-                if( it == parentNode.childSections.end() ) {
-                    node = new SectionNode( incompleteStats );
-                    parentNode.childSections.push_back( node );
-                }
-                else
-                    node = *it;
-            }
-            m_sectionStack.push_back( node );
-            m_deepestSection = node;
-        }
-
-        virtual void assertionStarting( AssertionInfo const& ) {}
-
-        virtual bool assertionEnded( AssertionStats const& assertionStats ) {
-            assert( !m_sectionStack.empty() );
-            SectionNode& sectionNode = *m_sectionStack.back();
-            sectionNode.assertions.push_back( assertionStats );
-            return true;
-        }
-        virtual void sectionEnded( SectionStats const& sectionStats ) {
-            assert( !m_sectionStack.empty() );
-            SectionNode& node = *m_sectionStack.back();
-            node.stats = sectionStats;
-            m_sectionStack.pop_back();
-        }
-        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
-            Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
-            assert( m_sectionStack.size() == 0 );
-            node->children.push_back( m_rootSection );
-            m_testCases.push_back( node );
-            m_rootSection.reset();
-
-            assert( m_deepestSection );
-            m_deepestSection->stdOut = testCaseStats.stdOut;
-            m_deepestSection->stdErr = testCaseStats.stdErr;
-        }
-        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
-            Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
-            node->children.swap( m_testCases );
-            m_testGroups.push_back( node );
-        }
-        virtual void testRunEnded( TestRunStats const& testRunStats ) {
-            Ptr<TestRunNode> node = new TestRunNode( testRunStats );
-            node->children.swap( m_testGroups );
-            m_testRuns.push_back( node );
-            testRunEndedCumulative();
-        }
-        virtual void testRunEndedCumulative() = 0;
-
-        Ptr<IConfig> m_config;
-        std::ostream& stream;
-        std::vector<AssertionStats> m_assertions;
-        std::vector<std::vector<Ptr<SectionNode> > > m_sections;
-        std::vector<Ptr<TestCaseNode> > m_testCases;
-        std::vector<Ptr<TestGroupNode> > m_testGroups;
-
-        std::vector<Ptr<TestRunNode> > m_testRuns;
-
-        Ptr<SectionNode> m_rootSection;
-        Ptr<SectionNode> m_deepestSection;
-        std::vector<Ptr<SectionNode> > m_sectionStack;
-
-    };
-
-} // end namespace Catch
-
-// #included from: ../internal/catch_reporter_registrars.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
-
-namespace Catch {
-
-    template<typename T>
-    class LegacyReporterRegistrar {
-
-        class ReporterFactory : public IReporterFactory {
-            virtual IStreamingReporter* create( ReporterConfig const& config ) const {
-                return new LegacyReporterAdapter( new T( config ) );
-            }
-
-            virtual std::string getDescription() const {
-                return T::getDescription();
-            }
-        };
-
-    public:
-
-        LegacyReporterRegistrar( std::string const& name ) {
-            getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
-        }
-    };
-
-    template<typename T>
-    class ReporterRegistrar {
-
-        class ReporterFactory : public IReporterFactory {
-
-            // *** Please Note ***:
-            // - If you end up here looking at a compiler error because it's trying to register
-            // your custom reporter class be aware that the native reporter interface has changed
-            // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via
-            // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter.
-            // However please consider updating to the new interface as the old one is now
-            // deprecated and will probably be removed quite soon!
-            // Please contact me via github if you have any questions at all about this.
-            // In fact, ideally, please contact me anyway to let me know you've hit this - as I have
-            // no idea who is actually using custom reporters at all (possibly no-one!).
-            // The new interface is designed to minimise exposure to interface changes in the future.
-            virtual IStreamingReporter* create( ReporterConfig const& config ) const {
-                return new T( config );
-            }
-
-            virtual std::string getDescription() const {
-                return T::getDescription();
-            }
-        };
-
-    public:
-
-        ReporterRegistrar( std::string const& name ) {
-            getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
-        }
-    };
-}
-
-#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \
-    namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
-#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
-    namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
-
-// #included from: ../internal/catch_xmlwriter.hpp
-#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
-
-#include <sstream>
-#include <iostream>
-#include <string>
-#include <vector>
-
-namespace Catch {
-
-    class XmlWriter {
-    public:
-
-        class ScopedElement {
-        public:
-            ScopedElement( XmlWriter* writer )
-            :   m_writer( writer )
-            {}
-
-            ScopedElement( ScopedElement const& other )
-            :   m_writer( other.m_writer ){
-                other.m_writer = NULL;
-            }
-
-            ~ScopedElement() {
-                if( m_writer )
-                    m_writer->endElement();
-            }
-
-            ScopedElement& writeText( std::string const& text, bool indent = true ) {
-                m_writer->writeText( text, indent );
-                return *this;
-            }
-
-            template<typename T>
-            ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
-                m_writer->writeAttribute( name, attribute );
-                return *this;
-            }
-
-        private:
-            mutable XmlWriter* m_writer;
-        };
-
-        XmlWriter()
-        :   m_tagIsOpen( false ),
-            m_needsNewline( false ),
-            m_os( &std::cout )
-        {}
-
-        XmlWriter( std::ostream& os )
-        :   m_tagIsOpen( false ),
-            m_needsNewline( false ),
-            m_os( &os )
-        {}
-
-        ~XmlWriter() {
-            while( !m_tags.empty() )
-                endElement();
-        }
-
-#  ifndef CATCH_CPP11_OR_GREATER
-        XmlWriter& operator = ( XmlWriter const& other ) {
-            XmlWriter temp( other );
-            swap( temp );
-            return *this;
-        }
-#  else
-        XmlWriter( XmlWriter const& )              = default;
-        XmlWriter( XmlWriter && )                  = default;
-        XmlWriter& operator = ( XmlWriter const& ) = default;
-        XmlWriter& operator = ( XmlWriter && )     = default;
-#  endif
-
-        void swap( XmlWriter& other ) {
-            std::swap( m_tagIsOpen, other.m_tagIsOpen );
-            std::swap( m_needsNewline, other.m_needsNewline );
-            std::swap( m_tags, other.m_tags );
-            std::swap( m_indent, other.m_indent );
-            std::swap( m_os, other.m_os );
-        }
-
-        XmlWriter& startElement( std::string const& name ) {
-            ensureTagClosed();
-            newlineIfNecessary();
-            stream() << m_indent << "<" << name;
-            m_tags.push_back( name );
-            m_indent += "  ";
-            m_tagIsOpen = true;
-            return *this;
-        }
-
-        ScopedElement scopedElement( std::string const& name ) {
-            ScopedElement scoped( this );
-            startElement( name );
-            return scoped;
-        }
-
-        XmlWriter& endElement() {
-            newlineIfNecessary();
-            m_indent = m_indent.substr( 0, m_indent.size()-2 );
-            if( m_tagIsOpen ) {
-                stream() << "/>\n";
-                m_tagIsOpen = false;
-            }
-            else {
-                stream() << m_indent << "</" << m_tags.back() << ">\n";
-            }
-            m_tags.pop_back();
-            return *this;
-        }
-
-        XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
-            if( !name.empty() && !attribute.empty() ) {
-                stream() << " " << name << "=\"";
-                writeEncodedText( attribute );
-                stream() << "\"";
-            }
-            return *this;
-        }
-
-        XmlWriter& writeAttribute( std::string const& name, bool attribute ) {
-            stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\"";
-            return *this;
-        }
-
-        template<typename T>
-        XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
-            if( !name.empty() )
-                stream() << " " << name << "=\"" << attribute << "\"";
-            return *this;
-        }
-
-        XmlWriter& writeText( std::string const& text, bool indent = true ) {
-            if( !text.empty() ){
-                bool tagWasOpen = m_tagIsOpen;
-                ensureTagClosed();
-                if( tagWasOpen && indent )
-                    stream() << m_indent;
-                writeEncodedText( text );
-                m_needsNewline = true;
-            }
-            return *this;
-        }
-
-        XmlWriter& writeComment( std::string const& text ) {
-            ensureTagClosed();
-            stream() << m_indent << "<!--" << text << "-->";
-            m_needsNewline = true;
-            return *this;
-        }
-
-        XmlWriter& writeBlankLine() {
-            ensureTagClosed();
-            stream() << "\n";
-            return *this;
-        }
-
-    private:
-
-        std::ostream& stream() {
-            return *m_os;
-        }
-
-        void ensureTagClosed() {
-            if( m_tagIsOpen ) {
-                stream() << ">\n";
-                m_tagIsOpen = false;
-            }
-        }
-
-        void newlineIfNecessary() {
-            if( m_needsNewline ) {
-                stream() << "\n";
-                m_needsNewline = false;
-            }
-        }
-
-        void writeEncodedText( std::string const& text ) {
-            static const char* charsToEncode = "<&\"";
-            std::string mtext = text;
-            std::string::size_type pos = mtext.find_first_of( charsToEncode );
-            while( pos != std::string::npos ) {
-                stream() << mtext.substr( 0, pos );
-
-                switch( mtext[pos] ) {
-                    case '<':
-                        stream() << "<";
-                        break;
-                    case '&':
-                        stream() << "&";
-                        break;
-                    case '\"':
-                        stream() << """;
-                        break;
-                }
-                mtext = mtext.substr( pos+1 );
-                pos = mtext.find_first_of( charsToEncode );
-            }
-            stream() << mtext;
-        }
-
-        bool m_tagIsOpen;
-        bool m_needsNewline;
-        std::vector<std::string> m_tags;
-        std::string m_indent;
-        std::ostream* m_os;
-    };
-
-}
-namespace Catch {
-    class XmlReporter : public SharedImpl<IReporter> {
-    public:
-        XmlReporter( ReporterConfig const& config ) : m_config( config ), m_sectionDepth( 0 ) {}
-
-        static std::string getDescription() {
-            return "Reports test results as an XML document";
-        }
-        virtual ~XmlReporter();
-
-    private: // IReporter
-
-        virtual bool shouldRedirectStdout() const {
-            return true;
-        }
-
-        virtual void StartTesting() {
-            m_xml = XmlWriter( m_config.stream() );
-            m_xml.startElement( "Catch" );
-            if( !m_config.fullConfig()->name().empty() )
-                m_xml.writeAttribute( "name", m_config.fullConfig()->name() );
-        }
-
-        virtual void EndTesting( const Totals& totals ) {
-            m_xml.scopedElement( "OverallResults" )
-                .writeAttribute( "successes", totals.assertions.passed )
-                .writeAttribute( "failures", totals.assertions.failed );
-            m_xml.endElement();
-        }
-
-        virtual void StartGroup( const std::string& groupName ) {
-            m_xml.startElement( "Group" )
-                .writeAttribute( "name", groupName );
-        }
-
-        virtual void EndGroup( const std::string&, const Totals& totals ) {
-            m_xml.scopedElement( "OverallResults" )
-                .writeAttribute( "successes", totals.assertions.passed )
-                .writeAttribute( "failures", totals.assertions.failed );
-            m_xml.endElement();
-        }
-
-        virtual void StartSection( const std::string& sectionName, const std::string& description ) {
-            if( m_sectionDepth++ > 0 ) {
-                m_xml.startElement( "Section" )
-                    .writeAttribute( "name", trim( sectionName ) )
-                    .writeAttribute( "description", description );
-            }
-        }
-        virtual void NoAssertionsInSection( const std::string& ) {}
-        virtual void NoAssertionsInTestCase( const std::string& ) {}
-
-        virtual void EndSection( const std::string& /*sectionName*/, const Counts& assertions ) {
-            if( --m_sectionDepth > 0 ) {
-                m_xml.scopedElement( "OverallResults" )
-                    .writeAttribute( "successes", assertions.passed )
-                    .writeAttribute( "failures", assertions.failed );
-                m_xml.endElement();
-            }
-        }
-
-        virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) {
-            m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) );
-            m_currentTestSuccess = true;
-        }
-
-        virtual void Result( const Catch::AssertionResult& assertionResult ) {
-            if( !m_config.fullConfig()->includeSuccessfulResults() && assertionResult.getResultType() == ResultWas::Ok )
-                return;
-
-            if( assertionResult.hasExpression() ) {
-                m_xml.startElement( "Expression" )
-                    .writeAttribute( "success", assertionResult.succeeded() )
-                    .writeAttribute( "filename", assertionResult.getSourceInfo().file )
-                    .writeAttribute( "line", assertionResult.getSourceInfo().line );
-
-                m_xml.scopedElement( "Original" )
-                    .writeText( assertionResult.getExpression() );
-                m_xml.scopedElement( "Expanded" )
-                    .writeText( assertionResult.getExpandedExpression() );
-                m_currentTestSuccess &= assertionResult.succeeded();
-            }
-
-            switch( assertionResult.getResultType() ) {
-                case ResultWas::ThrewException:
-                    m_xml.scopedElement( "Exception" )
-                        .writeAttribute( "filename", assertionResult.getSourceInfo().file )
-                        .writeAttribute( "line", assertionResult.getSourceInfo().line )
-                        .writeText( assertionResult.getMessage() );
-                    m_currentTestSuccess = false;
-                    break;
-                case ResultWas::Info:
-                    m_xml.scopedElement( "Info" )
-                        .writeText( assertionResult.getMessage() );
-                    break;
-                case ResultWas::Warning:
-                    m_xml.scopedElement( "Warning" )
-                        .writeText( assertionResult.getMessage() );
-                    break;
-                case ResultWas::ExplicitFailure:
-                    m_xml.scopedElement( "Failure" )
-                        .writeText( assertionResult.getMessage() );
-                    m_currentTestSuccess = false;
-                    break;
-                case ResultWas::Unknown:
-                case ResultWas::Ok:
-                case ResultWas::FailureBit:
-                case ResultWas::ExpressionFailed:
-                case ResultWas::Exception:
-                case ResultWas::DidntThrowException:
-                    break;
-            }
-            if( assertionResult.hasExpression() )
-                m_xml.endElement();
-        }
-
-        virtual void Aborted() {
-            // !TBD
-        }
-
-        virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) {
-            m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess );
-            m_xml.endElement();
-        }
-
-    private:
-        ReporterConfig m_config;
-        bool m_currentTestSuccess;
-        XmlWriter m_xml;
-        int m_sectionDepth;
-    };
-
-} // end namespace Catch
-
-// #included from: ../reporters/catch_reporter_junit.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
-
-#include <assert.h>
-
-namespace Catch {
-
-    class JunitReporter : public CumulativeReporterBase {
-    public:
-        JunitReporter( ReporterConfig const& _config )
-        :   CumulativeReporterBase( _config ),
-            xml( _config.stream() )
-        {}
-
-        ~JunitReporter();
-
-        static std::string getDescription() {
-            return "Reports test results in an XML format that looks like Ant's junitreport target";
-        }
-
-        virtual void noMatchingTestCases( std::string const& /*spec*/ ) {}
-
-        virtual ReporterPreferences getPreferences() const {
-            ReporterPreferences prefs;
-            prefs.shouldRedirectStdOut = true;
-            return prefs;
-        }
-
-        virtual void testRunStarting( TestRunInfo const& runInfo ) {
-            CumulativeReporterBase::testRunStarting( runInfo );
-            xml.startElement( "testsuites" );
-        }
-
-        virtual void testGroupStarting( GroupInfo const& groupInfo ) {
-            suiteTimer.start();
-            stdOutForSuite.str("");
-            stdErrForSuite.str("");
-            unexpectedExceptions = 0;
-            CumulativeReporterBase::testGroupStarting( groupInfo );
-        }
-
-        virtual bool assertionEnded( AssertionStats const& assertionStats ) {
-            if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException )
-                unexpectedExceptions++;
-            return CumulativeReporterBase::assertionEnded( assertionStats );
-        }
-
-        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
-            stdOutForSuite << testCaseStats.stdOut;
-            stdErrForSuite << testCaseStats.stdErr;
-            CumulativeReporterBase::testCaseEnded( testCaseStats );
-        }
-
-        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
-            double suiteTime = suiteTimer.getElapsedSeconds();
-            CumulativeReporterBase::testGroupEnded( testGroupStats );
-            writeGroup( *m_testGroups.back(), suiteTime );
-        }
-
-        virtual void testRunEndedCumulative() {
-            xml.endElement();
-        }
-
-        void writeGroup( TestGroupNode const& groupNode, double suiteTime ) {
-            XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
-            TestGroupStats const& stats = groupNode.value;
-            xml.writeAttribute( "name", stats.groupInfo.name );
-            xml.writeAttribute( "errors", unexpectedExceptions );
-            xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions );
-            xml.writeAttribute( "tests", stats.totals.assertions.total() );
-            xml.writeAttribute( "hostname", "tbd" ); // !TBD
-            if( m_config->showDurations() == ShowDurations::Never )
-                xml.writeAttribute( "time", "" );
-            else
-                xml.writeAttribute( "time", suiteTime );
-            xml.writeAttribute( "timestamp", "tbd" ); // !TBD
-
-            // Write test cases
-            for( TestGroupNode::ChildNodes::const_iterator
-                    it = groupNode.children.begin(), itEnd = groupNode.children.end();
-                    it != itEnd;
-                    ++it )
-                writeTestCase( **it );
-
-            xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false );
-            xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false );
-        }
-
-        void writeTestCase( TestCaseNode const& testCaseNode ) {
-            TestCaseStats const& stats = testCaseNode.value;
-
-            // All test cases have exactly one section - which represents the
-            // test case itself. That section may have 0-n nested sections
-            assert( testCaseNode.children.size() == 1 );
-            SectionNode const& rootSection = *testCaseNode.children.front();
-
-            std::string className = stats.testInfo.className;
-
-            if( className.empty() ) {
-                if( rootSection.childSections.empty() )
-                    className = "global";
-            }
-            writeSection( className, "", rootSection );
-        }
-
-        void writeSection(  std::string const& className,
-                            std::string const& rootName,
-                            SectionNode const& sectionNode ) {
-            std::string name = trim( sectionNode.stats.sectionInfo.name );
-            if( !rootName.empty() )
-                name = rootName + "/" + name;
-
-            if( !sectionNode.assertions.empty() ||
-                !sectionNode.stdOut.empty() ||
-                !sectionNode.stdErr.empty() ) {
-                XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
-                if( className.empty() ) {
-                    xml.writeAttribute( "classname", name );
-                    xml.writeAttribute( "name", "root" );
-                }
-                else {
-                    xml.writeAttribute( "classname", className );
-                    xml.writeAttribute( "name", name );
-                }
-                xml.writeAttribute( "time", toString( sectionNode.stats.durationInSeconds ) );
-
-                writeAssertions( sectionNode );
-
-                if( !sectionNode.stdOut.empty() )
-                    xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
-                if( !sectionNode.stdErr.empty() )
-                    xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
-            }
-            for( SectionNode::ChildSections::const_iterator
-                    it = sectionNode.childSections.begin(),
-                    itEnd = sectionNode.childSections.end();
-                    it != itEnd;
-                    ++it )
-                if( className.empty() )
-                    writeSection( name, "", **it );
-                else
-                    writeSection( className, name, **it );
-        }
-
-        void writeAssertions( SectionNode const& sectionNode ) {
-            for( SectionNode::Assertions::const_iterator
-                    it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end();
-                    it != itEnd;
-                    ++it )
-                writeAssertion( *it );
-        }
-        void writeAssertion( AssertionStats const& stats ) {
-            AssertionResult const& result = stats.assertionResult;
-            if( !result.isOk() ) {
-                std::string elementName;
-                switch( result.getResultType() ) {
-                    case ResultWas::ThrewException:
-                        elementName = "error";
-                        break;
-                    case ResultWas::ExplicitFailure:
-                        elementName = "failure";
-                        break;
-                    case ResultWas::ExpressionFailed:
-                        elementName = "failure";
-                        break;
-                    case ResultWas::DidntThrowException:
-                        elementName = "failure";
-                        break;
-
-                    // We should never see these here:
-                    case ResultWas::Info:
-                    case ResultWas::Warning:
-                    case ResultWas::Ok:
-                    case ResultWas::Unknown:
-                    case ResultWas::FailureBit:
-                    case ResultWas::Exception:
-                        elementName = "internalError";
-                        break;
-                }
-
-                XmlWriter::ScopedElement e = xml.scopedElement( elementName );
-
-                xml.writeAttribute( "message", result.getExpandedExpression() );
-                xml.writeAttribute( "type", result.getTestMacroName() );
-
-                std::ostringstream oss;
-                if( !result.getMessage().empty() )
-                    oss << result.getMessage() << "\n";
-                for( std::vector<MessageInfo>::const_iterator
-                        it = stats.infoMessages.begin(),
-                        itEnd = stats.infoMessages.end();
-                            it != itEnd;
-                            ++it )
-                    if( it->type == ResultWas::Info )
-                        oss << it->message << "\n";
-
-                oss << "at " << result.getSourceInfo();
-                xml.writeText( oss.str(), false );
-            }
-        }
-
-        XmlWriter xml;
-        Timer suiteTimer;
-        std::ostringstream stdOutForSuite;
-        std::ostringstream stdErrForSuite;
-        unsigned int unexpectedExceptions;
-    };
-
-    INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
-
-} // end namespace Catch
-
-// #included from: ../reporters/catch_reporter_console.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
-
-#include <cstring>
-
-namespace Catch {
-
-    struct ConsoleReporter : StreamingReporterBase {
-        ConsoleReporter( ReporterConfig const& _config )
-        :   StreamingReporterBase( _config ),
-            m_headerPrinted( false ),
-            m_atLeastOneTestCasePrinted( false )
-        {}
-
-        virtual ~ConsoleReporter();
-        static std::string getDescription() {
-            return "Reports test results as plain lines of text";
-        }
-        virtual ReporterPreferences getPreferences() const {
-            ReporterPreferences prefs;
-            prefs.shouldRedirectStdOut = false;
-            return prefs;
-        }
-
-        virtual void noMatchingTestCases( std::string const& spec ) {
-            stream << "No test cases matched '" << spec << "'" << std::endl;
-        }
-
-        virtual void assertionStarting( AssertionInfo const& ) {
-        }
-
-        virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
-            AssertionResult const& result = _assertionStats.assertionResult;
-
-            bool printInfoMessages = true;
-
-            // Drop out if result was successful and we're not printing those
-            if( !m_config->includeSuccessfulResults() && result.isOk() ) {
-                if( result.getResultType() != ResultWas::Warning )
-                    return false;
-                printInfoMessages = false;
-            }
-
-            lazyPrint();
-
-            AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
-            printer.print();
-            stream << std::endl;
-            return true;
-        }
-
-        virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
-            m_headerPrinted = false;
-            StreamingReporterBase::sectionStarting( _sectionInfo );
-        }
-        virtual void sectionEnded( SectionStats const& _sectionStats ) {
-            if( _sectionStats.missingAssertions ) {
-                lazyPrint();
-                Colour colour( Colour::ResultError );
-                if( m_sectionStack.size() > 1 )
-                    stream << "\nNo assertions in section";
-                else
-                    stream << "\nNo assertions in test case";
-                stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
-            }
-            if( m_headerPrinted ) {
-                if( m_config->showDurations() == ShowDurations::Always )
-                    stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
-                m_headerPrinted = false;
-            }
-            else {
-                if( m_config->showDurations() == ShowDurations::Always )
-                    stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
-            }
-            StreamingReporterBase::sectionEnded( _sectionStats );
-        }
-
-        virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) {
-            StreamingReporterBase::testCaseEnded( _testCaseStats );
-            m_headerPrinted = false;
-        }
-        virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) {
-            if( currentGroupInfo.used ) {
-                printSummaryDivider();
-                stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
-                printTotals( _testGroupStats.totals );
-                stream << "\n" << std::endl;
-            }
-            StreamingReporterBase::testGroupEnded( _testGroupStats );
-        }
-        virtual void testRunEnded( TestRunStats const& _testRunStats ) {
-            if( m_atLeastOneTestCasePrinted )
-                printTotalsDivider();
-            printTotals( _testRunStats.totals );
-            stream << "\n" << std::endl;
-            StreamingReporterBase::testRunEnded( _testRunStats );
-        }
-
-    private:
-
-        class AssertionPrinter {
-            void operator= ( AssertionPrinter const& );
-        public:
-            AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
-            :   stream( _stream ),
-                stats( _stats ),
-                result( _stats.assertionResult ),
-                colour( Colour::None ),
-                message( result.getMessage() ),
-                messages( _stats.infoMessages ),
-                printInfoMessages( _printInfoMessages )
-            {
-                switch( result.getResultType() ) {
-                    case ResultWas::Ok:
-                        colour = Colour::Success;
-                        passOrFail = "PASSED";
-                        //if( result.hasMessage() )
-                        if( _stats.infoMessages.size() == 1 )
-                            messageLabel = "with message";
-                        if( _stats.infoMessages.size() > 1 )
-                            messageLabel = "with messages";
-                        break;
-                    case ResultWas::ExpressionFailed:
-                        if( result.isOk() ) {
-                            colour = Colour::Success;
-                            passOrFail = "FAILED - but was ok";
-                        }
-                        else {
-                            colour = Colour::Error;
-                            passOrFail = "FAILED";
-                        }
-                        if( _stats.infoMessages.size() == 1 )
-                            messageLabel = "with message";
-                        if( _stats.infoMessages.size() > 1 )
-                            messageLabel = "with messages";
-                        break;
-                    case ResultWas::ThrewException:
-                        colour = Colour::Error;
-                        passOrFail = "FAILED";
-                        messageLabel = "due to unexpected exception with message";
-                        break;
-                    case ResultWas::DidntThrowException:
-                        colour = Colour::Error;
-                        passOrFail = "FAILED";
-                        messageLabel = "because no exception was thrown where one was expected";
-                        break;
-                    case ResultWas::Info:
-                        messageLabel = "info";
-                        break;
-                    case ResultWas::Warning:
-                        messageLabel = "warning";
-                        break;
-                    case ResultWas::ExplicitFailure:
-                        passOrFail = "FAILED";
-                        colour = Colour::Error;
-                        if( _stats.infoMessages.size() == 1 )
-                            messageLabel = "explicitly with message";
-                        if( _stats.infoMessages.size() > 1 )
-                            messageLabel = "explicitly with messages";
-                        break;
-                    // These cases are here to prevent compiler warnings
-                    case ResultWas::Unknown:
-                    case ResultWas::FailureBit:
-                    case ResultWas::Exception:
-                        passOrFail = "** internal error **";
-                        colour = Colour::Error;
-                        break;
-                }
-            }
-
-            void print() const {
-                printSourceInfo();
-                if( stats.totals.assertions.total() > 0 ) {
-                    if( result.isOk() )
-                        stream << "\n";
-                    printResultType();
-                    printOriginalExpression();
-                    printReconstructedExpression();
-                }
-                else {
-                    stream << "\n";
-                }
-                printMessage();
-            }
-
-        private:
-            void printResultType() const {
-                if( !passOrFail.empty() ) {
-                    Colour colourGuard( colour );
-                    stream << passOrFail << ":\n";
-                }
-            }
-            void printOriginalExpression() const {
-                if( result.hasExpression() ) {
-                    Colour colourGuard( Colour::OriginalExpression );
-                    stream  << "  ";
-                    stream << result.getExpressionInMacro();
-                    stream << "\n";
-                }
-            }
-            void printReconstructedExpression() const {
-                if( result.hasExpandedExpression() ) {
-                    stream << "with expansion:\n";
-                    Colour colourGuard( Colour::ReconstructedExpression );
-                    stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n";
-                }
-            }
-            void printMessage() const {
-                if( !messageLabel.empty() )
-                    stream << messageLabel << ":" << "\n";
-                for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
-                        it != itEnd;
-                        ++it ) {
-                    // If this assertion is a warning ignore any INFO messages
-                    if( printInfoMessages || it->type != ResultWas::Info )
-                        stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n";
-                }
-            }
-            void printSourceInfo() const {
-                Colour colourGuard( Colour::FileName );
-                stream << result.getSourceInfo() << ": ";
-            }
-
-            std::ostream& stream;
-            AssertionStats const& stats;
-            AssertionResult const& result;
-            Colour::Code colour;
-            std::string passOrFail;
-            std::string messageLabel;
-            std::string message;
-            std::vector<MessageInfo> messages;
-            bool printInfoMessages;
-        };
-
-        void lazyPrint() {
-
-            if( !currentTestRunInfo.used )
-                lazyPrintRunInfo();
-            if( !currentGroupInfo.used )
-                lazyPrintGroupInfo();
-
-            if( !m_headerPrinted ) {
-                printTestCaseAndSectionHeader();
-                m_headerPrinted = true;
-            }
-            m_atLeastOneTestCasePrinted = true;
-        }
-        void lazyPrintRunInfo() {
-            stream  << "\n" << getLineOfChars<'~'>() << "\n";
-            Colour colour( Colour::SecondaryText );
-            stream  << currentTestRunInfo->name
-                    << " is a Catch v"  << libraryVersion.majorVersion << "."
-                    << libraryVersion.minorVersion << " b"
-                    << libraryVersion.buildNumber;
-            if( libraryVersion.branchName != std::string( "master" ) )
-                stream << " (" << libraryVersion.branchName << ")";
-            stream  << " host application.\n"
-                    << "Run with -? for options\n\n";
-
-            currentTestRunInfo.used = true;
-        }
-        void lazyPrintGroupInfo() {
-            if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) {
-                printClosedHeader( "Group: " + currentGroupInfo->name );
-                currentGroupInfo.used = true;
-            }
-        }
-        void printTestCaseAndSectionHeader() {
-            assert( !m_sectionStack.empty() );
-            printOpenHeader( currentTestCaseInfo->name );
-
-            if( m_sectionStack.size() > 1 ) {
-                Colour colourGuard( Colour::Headers );
-
-                std::vector<SectionInfo>::const_iterator
-                    it = m_sectionStack.begin()+1, // Skip first section (test case)
-                    itEnd = m_sectionStack.end();
-                for( ; it != itEnd; ++it )
-                    printHeaderString( it->name, 2 );
-            }
-
-            SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
-
-            if( !lineInfo.empty() ){
-                stream << getLineOfChars<'-'>() << "\n";
-                Colour colourGuard( Colour::FileName );
-                stream << lineInfo << "\n";
-            }
-            stream << getLineOfChars<'.'>() << "\n" << std::endl;
-        }
-
-        void printClosedHeader( std::string const& _name ) {
-            printOpenHeader( _name );
-            stream << getLineOfChars<'.'>() << "\n";
-        }
-        void printOpenHeader( std::string const& _name ) {
-            stream  << getLineOfChars<'-'>() << "\n";
-            {
-                Colour colourGuard( Colour::Headers );
-                printHeaderString( _name );
-            }
-        }
-
-        // if string has a : in first line will set indent to follow it on
-        // subsequent lines
-        void printHeaderString( std::string const& _string, std::size_t indent = 0 ) {
-            std::size_t i = _string.find( ": " );
-            if( i != std::string::npos )
-                i+=2;
-            else
-                i = 0;
-            stream << Text( _string, TextAttributes()
-                                        .setIndent( indent+i)
-                                        .setInitialIndent( indent ) ) << "\n";
-        }
-
-        void printTotals( const Totals& totals ) {
-            if( totals.testCases.total() == 0 ) {
-                stream << "No tests ran";
-            }
-            else if( totals.assertions.total() == 0 ) {
-                Colour colour( Colour::Yellow );
-                printCounts( "test case", totals.testCases );
-                stream << " (no assertions)";
-            }
-            else if( totals.assertions.failed ) {
-                Colour colour( Colour::ResultError );
-                printCounts( "test case", totals.testCases );
-                if( totals.testCases.failed > 0 ) {
-                    stream << " (";
-                    printCounts( "assertion", totals.assertions );
-                    stream << ")";
-                }
-            }
-            else {
-                Colour colour( Colour::ResultSuccess );
-                stream << "All tests passed ("
-                        << pluralise( totals.assertions.passed, "assertion" ) << " in "
-                        << pluralise( totals.testCases.passed, "test case" ) << ")";
-            }
-        }
-        void printCounts( std::string const& label, Counts const& counts ) {
-            if( counts.total() == 1 ) {
-                stream << "1 " << label << " - ";
-                if( counts.failed )
-                    stream << "failed";
-                else
-                    stream << "passed";
-            }
-            else {
-                stream << counts.total() << " " << label << "s ";
-                if( counts.passed ) {
-                    if( counts.failed )
-                        stream << "- " << counts.failed << " failed";
-                    else if( counts.passed == 2 )
-                        stream << "- both passed";
-                    else
-                        stream << "- all passed";
-                }
-                else {
-                    if( counts.failed == 2 )
-                        stream << "- both failed";
-                    else
-                        stream << "- all failed";
-                }
-            }
-        }
-
-        void printTotalsDivider() {
-            stream << getLineOfChars<'='>() << "\n";
-        }
-        void printSummaryDivider() {
-            stream << getLineOfChars<'-'>() << "\n";
-        }
-        template<char C>
-        static char const* getLineOfChars() {
-            static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
-            if( !*line ) {
-                memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
-                line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
-            }
-            return line;
-        }
-
-    private:
-        bool m_headerPrinted;
-        bool m_atLeastOneTestCasePrinted;
-    };
-
-    INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter )
-
-} // end namespace Catch
-
-// #included from: ../reporters/catch_reporter_compact.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED
-
-namespace Catch {
-
-    struct CompactReporter : StreamingReporterBase {
-
-        CompactReporter( ReporterConfig const& _config )
-        : StreamingReporterBase( _config )
-        {}
-
-        virtual ~CompactReporter();
-
-        static std::string getDescription() {
-            return "Reports test results on a single line, suitable for IDEs";
-        }
-
-        virtual ReporterPreferences getPreferences() const {
-            ReporterPreferences prefs;
-            prefs.shouldRedirectStdOut = false;
-            return prefs;
-        }
-
-        virtual void noMatchingTestCases( std::string const& spec ) {
-            stream << "No test cases matched '" << spec << "'" << std::endl;
-        }
-
-        virtual void assertionStarting( AssertionInfo const& ) {
-        }
-
-        virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
-            AssertionResult const& result = _assertionStats.assertionResult;
-
-            bool printInfoMessages = true;
-
-            // Drop out if result was successful and we're not printing those
-            if( !m_config->includeSuccessfulResults() && result.isOk() ) {
-                if( result.getResultType() != ResultWas::Warning )
-                    return false;
-                printInfoMessages = false;
-            }
-
-            AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
-            printer.print();
-
-            stream << std::endl;
-            return true;
-        }
-
-        virtual void testRunEnded( TestRunStats const& _testRunStats ) {
-            printTotals( _testRunStats.totals );
-            stream << "\n" << std::endl;
-            StreamingReporterBase::testRunEnded( _testRunStats );
-        }
-
-    private:
-        class AssertionPrinter {
-            void operator= ( AssertionPrinter const& );
-        public:
-            AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
-            : stream( _stream )
-            , stats( _stats )
-            , result( _stats.assertionResult )
-            , messages( _stats.infoMessages )
-            , itMessage( _stats.infoMessages.begin() )
-            , printInfoMessages( _printInfoMessages )
-            {}
-
-            void print() {
-                printSourceInfo();
-
-                itMessage = messages.begin();
-
-                switch( result.getResultType() ) {
-                    case ResultWas::Ok:
-                        printResultType( Colour::ResultSuccess, passedString() );
-                        printOriginalExpression();
-                        printReconstructedExpression();
-                        if ( ! result.hasExpression() )
-                            printRemainingMessages( Colour::None );
-                        else
-                            printRemainingMessages();
-                        break;
-                    case ResultWas::ExpressionFailed:
-                        if( result.isOk() )
-                            printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) );
-                        else
-                            printResultType( Colour::Error, failedString() );
-                        printOriginalExpression();
-                        printReconstructedExpression();
-                        printRemainingMessages();
-                        break;
-                    case ResultWas::ThrewException:
-                        printResultType( Colour::Error, failedString() );
-                        printIssue( "unexpected exception with message:" );
-                        printMessage();
-                        printExpressionWas();
-                        printRemainingMessages();
-                        break;
-                    case ResultWas::DidntThrowException:
-                        printResultType( Colour::Error, failedString() );
-                        printIssue( "expected exception, got none" );
-                        printExpressionWas();
-                        printRemainingMessages();
-                        break;
-                    case ResultWas::Info:
-                        printResultType( Colour::None, "info" );
-                        printMessage();
-                        printRemainingMessages();
-                        break;
-                    case ResultWas::Warning:
-                        printResultType( Colour::None, "warning" );
-                        printMessage();
-                        printRemainingMessages();
-                        break;
-                    case ResultWas::ExplicitFailure:
-                        printResultType( Colour::Error, failedString() );
-                        printIssue( "explicitly" );
-                        printRemainingMessages( Colour::None );
-                        break;
-                    // These cases are here to prevent compiler warnings
-                    case ResultWas::Unknown:
-                    case ResultWas::FailureBit:
-                    case ResultWas::Exception:
-                        printResultType( Colour::Error, "** internal error **" );
-                        break;
-                }
-            }
-
-        private:
-            // Colour::LightGrey
-
-            static Colour dimColour() { return Colour::FileName; }
-
-#ifdef CATCH_PLATFORM_MAC
-            static const char* failedString() { return "FAILED"; }
-            static const char* passedString() { return "PASSED"; }
-#else
-            static const char* failedString() { return "failed"; }
-            static const char* passedString() { return "passed"; }
-#endif
-
-            void printSourceInfo() const {
-                Colour colourGuard( Colour::FileName );
-                stream << result.getSourceInfo() << ":";
-            }
-
-            void printResultType( Colour colour, std::string passOrFail ) const {
-                if( !passOrFail.empty() ) {
-                    {
-                        Colour colourGuard( colour );
-                        stream << " " << passOrFail;
-                    }
-                    stream << ":";
-                }
-            }
-
-            void printIssue( std::string issue ) const {
-                stream << " " << issue;
-            }
-
-            void printExpressionWas() {
-                if( result.hasExpression() ) {
-                    stream << ";";
-                    {
-                        Colour colour( dimColour() );
-                        stream << " expression was:";
-                    }
-                    printOriginalExpression();
-                }
-            }
-
-            void printOriginalExpression() const {
-                if( result.hasExpression() ) {
-                    stream << " " << result.getExpression();
-                }
-            }
-
-            void printReconstructedExpression() const {
-                if( result.hasExpandedExpression() ) {
-                    {
-                        Colour colour( dimColour() );
-                        stream << " for: ";
-                    }
-                    stream << result.getExpandedExpression();
-                }
-            }
-
-            void printMessage() {
-                if ( itMessage != messages.end() ) {
-                    stream << " '" << itMessage->message << "'";
-                    ++itMessage;
-                }
-            }
-
-            void printRemainingMessages( Colour colour = dimColour() ) {
-                if ( itMessage == messages.end() )
-                    return;
-
-                // using messages.end() directly yields compilation error:
-                std::vector<MessageInfo>::const_iterator itEnd = messages.end();
-                const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
-
-                {
-                    Colour colourGuard( colour );
-                    stream << " with " << pluralise( N, "message" ) << ":";
-                }
-
-                for(; itMessage != itEnd; ) {
-                    // If this assertion is a warning ignore any INFO messages
-                    if( printInfoMessages || itMessage->type != ResultWas::Info ) {
-                        stream << " '" << itMessage->message << "'";
-                        if ( ++itMessage != itEnd ) {
-                            Colour colourGuard( dimColour() );
-                            stream << " and";
-                        }
-                    }
-                }
-            }
-
-        private:
-            std::ostream& stream;
-            AssertionStats const& stats;
-            AssertionResult const& result;
-            std::vector<MessageInfo> messages;
-            std::vector<MessageInfo>::const_iterator itMessage;
-            bool printInfoMessages;
-        };
-
-        // Colour, message variants:
-        // - white: No tests ran.
-        // -   red: Failed [both/all] N test cases, failed [both/all] M assertions.
-        // - white: Passed [both/all] N test cases (no assertions).
-        // -   red: Failed N tests cases, failed M assertions.
-        // - green: Passed [both/all] N tests cases with M assertions.
-
-        std::string bothOrAll( std::size_t count ) const {
-            return count == 1 ? "" : count == 2 ? "both " : "all " ;
-        }
-
-        void printTotals( const Totals& totals ) const {
-            if( totals.testCases.total() == 0 ) {
-                stream << "No tests ran.";
-            }
-            else if( totals.testCases.failed == totals.testCases.total() ) {
-                Colour colour( Colour::ResultError );
-                const std::string qualify_assertions_failed =
-                    totals.assertions.failed == totals.assertions.total() ?
-                        bothOrAll( totals.assertions.failed ) : "";
-                stream <<
-                    "Failed " << bothOrAll( totals.testCases.failed )
-                              << pluralise( totals.testCases.failed, "test case"  ) << ", "
-                    "failed " << qualify_assertions_failed <<
-                                 pluralise( totals.assertions.failed, "assertion" ) << ".";
-            }
-            else if( totals.assertions.total() == 0 ) {
-                stream <<
-                    "Passed " << bothOrAll( totals.testCases.total() )
-                              << pluralise( totals.testCases.total(), "test case" )
-                              << " (no assertions).";
-            }
-            else if( totals.assertions.failed ) {
-                Colour colour( Colour::ResultError );
-                stream <<
-                    "Failed " << pluralise( totals.testCases.failed, "test case"  ) << ", "
-                    "failed " << pluralise( totals.assertions.failed, "assertion" ) << ".";
-            }
-            else {
-                Colour colour( Colour::ResultSuccess );
-                stream <<
-                    "Passed " << bothOrAll( totals.testCases.passed )
-                              << pluralise( totals.testCases.passed, "test case"  ) <<
-                    " with "  << pluralise( totals.assertions.passed, "assertion" ) << ".";
-            }
-        }
-    };
-
-    INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter )
-
-} // end namespace Catch
-
-namespace Catch {
-    NonCopyable::~NonCopyable() {}
-    IShared::~IShared() {}
-    StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
-    IContext::~IContext() {}
-    IResultCapture::~IResultCapture() {}
-    ITestCase::~ITestCase() {}
-    ITestCaseRegistry::~ITestCaseRegistry() {}
-    IRegistryHub::~IRegistryHub() {}
-    IMutableRegistryHub::~IMutableRegistryHub() {}
-    IExceptionTranslator::~IExceptionTranslator() {}
-    IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
-    IReporter::~IReporter() {}
-    IReporterFactory::~IReporterFactory() {}
-    IReporterRegistry::~IReporterRegistry() {}
-    IStreamingReporter::~IStreamingReporter() {}
-    AssertionStats::~AssertionStats() {}
-    SectionStats::~SectionStats() {}
-    TestCaseStats::~TestCaseStats() {}
-    TestGroupStats::~TestGroupStats() {}
-    TestRunStats::~TestRunStats() {}
-    CumulativeReporterBase::SectionNode::~SectionNode() {}
-    CumulativeReporterBase::~CumulativeReporterBase() {}
-
-    StreamingReporterBase::~StreamingReporterBase() {}
-    ConsoleReporter::~ConsoleReporter() {}
-    CompactReporter::~CompactReporter() {}
-    IRunner::~IRunner() {}
-    IMutableContext::~IMutableContext() {}
-    IConfig::~IConfig() {}
-    XmlReporter::~XmlReporter() {}
-    JunitReporter::~JunitReporter() {}
-    TestRegistry::~TestRegistry() {}
-    FreeFunctionTestCase::~FreeFunctionTestCase() {}
-    IGeneratorInfo::~IGeneratorInfo() {}
-    IGeneratorsForTest::~IGeneratorsForTest() {}
-    TestSpec::Pattern::~Pattern() {}
-    TestSpec::NamePattern::~NamePattern() {}
-    TestSpec::TagPattern::~TagPattern() {}
-    TestSpec::ExcludedPattern::~ExcludedPattern() {}
-
-    Matchers::Impl::StdString::Equals::~Equals() {}
-    Matchers::Impl::StdString::Contains::~Contains() {}
-    Matchers::Impl::StdString::StartsWith::~StartsWith() {}
-    Matchers::Impl::StdString::EndsWith::~EndsWith() {}
-
-    void Config::dummy() {}
-
-    INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "xml", XmlReporter )
-}
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-#endif
-
-#ifdef CATCH_CONFIG_MAIN
-// #included from: internal/catch_default_main.hpp
-#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
-
-#ifndef __OBJC__
-
-// Standard C/C++ main entry point
-int main (int argc, char * const argv[]) {
-    return Catch::Session().run( argc, argv );
-}
-
-#else // __OBJC__
-
-// Objective-C entry point
-int main (int argc, char * const argv[]) {
-#if !CATCH_ARC_ENABLED
-    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
-#endif
-
-    Catch::registerTestMethods();
-    int result = Catch::Session().run( argc, (char* const*)argv );
-
-#if !CATCH_ARC_ENABLED
-    [pool drain];
-#endif
-
-    return result;
-}
-
-#endif // __OBJC__
-
-#endif
-
-#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
-#  undef CLARA_CONFIG_MAIN
-#endif
-
-//////
-
-// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
-#ifdef CATCH_CONFIG_PREFIX_ALL
-
-#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" )
-#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::NegateResult, "CATCH_REQUIRE_FALSE" )
-
-#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, ..., Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" )
-#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" )
-#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" )
-
-#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" )
-#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::NegateResult, "CATCH_CHECK_FALSE" )
-#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" )
-#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" )
-#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" )
-
-#define CATCH_CHECK_THROWS( expr )  INTERNAL_CATCH_THROWS( expr, ..., Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" )
-#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" )
-#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" )
-
-#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" )
-#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" )
-
-#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
-#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg )
-#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
-#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
-#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
-
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
-    #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
-    #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
-    #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
-    #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
-    #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ )
-    #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ )
-#else
-    #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
-    #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
-    #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
-    #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
-    #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg )
-    #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg )
-#endif
-#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
-
-#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
-#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
-
-#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
-
-// "BDD-style" convenience wrappers
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
-#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
-#else
-#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags )
-#endif
-#define CATCH_GIVEN( desc )    CATCH_SECTION( "Given: " desc, "" )
-#define CATCH_WHEN( desc )     CATCH_SECTION( " When: " desc, "" )
-#define CATCH_AND_WHEN( desc ) CATCH_SECTION( "  And: " desc, "" )
-#define CATCH_THEN( desc )     CATCH_SECTION( " Then: " desc, "" )
-#define CATCH_AND_THEN( desc ) CATCH_SECTION( "  And: " desc, "" )
-
-// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
-#else
-
-#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
-#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::NegateResult, "REQUIRE_FALSE" )
-
-#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, ..., Catch::ResultDisposition::Normal, "REQUIRE_THROWS" )
-#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" )
-#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" )
-
-#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" )
-#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::NegateResult, "CHECK_FALSE" )
-#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" )
-#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" )
-#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" )
-
-#define CHECK_THROWS( expr )  INTERNAL_CATCH_THROWS( expr, ..., Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" )
-#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" )
-#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" )
-
-#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" )
-#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" )
-
-#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
-#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg )
-#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
-#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
-#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
-
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
-    #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
-    #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
-    #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
-    #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
-    #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ )
-    #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ )
-#else
-    #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
-    #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
-    #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
-    #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
-    #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg )
-    #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg )
-#endif
-#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
-
-#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
-#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
-
-#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
-
-#endif
-
-#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
-
-// "BDD-style" convenience wrappers
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
-#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
-#else
-#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags )
-#endif
-#define GIVEN( desc )    SECTION( "   Given: " desc, "" )
-#define WHEN( desc )     SECTION( "    When: " desc, "" )
-#define AND_WHEN( desc ) SECTION( "And when: " desc, "" )
-#define THEN( desc )     SECTION( "    Then: " desc, "" )
-#define AND_THEN( desc ) SECTION( "     And: " desc, "" )
-
-using Catch::Detail::Approx;
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
-
diff --git a/third_party/variant/test/compilation_failure/default_constructor.cpp b/third_party/variant/test/compilation_failure/default_constructor.cpp
new file mode 100644
index 0000000..c75a8c1
--- /dev/null
+++ b/third_party/variant/test/compilation_failure/default_constructor.cpp
@@ -0,0 +1,22 @@
+
+// @EXPECTED: First type in variant must be default constructible to allow default construction of variant
+
+#include <variant.hpp>
+
+// Checks that the first type in a variant must be default constructible to
+// make the variant default constructible.
+
+struct no_def_constructor
+{
+
+    int value;
+
+    no_def_constructor() = delete;
+
+    no_def_constructor(int v) : value(v) {}
+};
+
+int main()
+{
+    mapbox::util::variant<no_def_constructor> x;
+}
diff --git a/third_party/variant/test/compilation_failure/empty_typelist.cpp b/third_party/variant/test/compilation_failure/empty_typelist.cpp
new file mode 100644
index 0000000..69a631c
--- /dev/null
+++ b/third_party/variant/test/compilation_failure/empty_typelist.cpp
@@ -0,0 +1,11 @@
+
+// @EXPECTED: Template parameter type list of variant can not be empty
+
+#include <variant.hpp>
+
+// Empty type list should not work.
+
+int main()
+{
+    mapbox::util::variant<> x;
+}
diff --git a/third_party/variant/test/compilation_failure/equality.cpp b/third_party/variant/test/compilation_failure/equality.cpp
new file mode 100644
index 0000000..b99a308
--- /dev/null
+++ b/third_party/variant/test/compilation_failure/equality.cpp
@@ -0,0 +1,11 @@
+
+// @EXPECTED:
+
+#include <variant.hpp>
+
+int main()
+{
+    mapbox::util::variant<int> x;
+    mapbox::util::variant<double> y;
+    x == y;
+}
diff --git a/third_party/variant/test/compilation_failure/get_type.cpp b/third_party/variant/test/compilation_failure/get_type.cpp
new file mode 100644
index 0000000..5123eb1
--- /dev/null
+++ b/third_party/variant/test/compilation_failure/get_type.cpp
@@ -0,0 +1,10 @@
+
+// @EXPECTED: enable_if
+
+#include <variant.hpp>
+
+int main()
+{
+    mapbox::util::variant<int, double> x;
+    x.get<std::string>();
+}
diff --git a/third_party/variant/test/compilation_failure/is_type.cpp b/third_party/variant/test/compilation_failure/is_type.cpp
new file mode 100644
index 0000000..a79638e
--- /dev/null
+++ b/third_party/variant/test/compilation_failure/is_type.cpp
@@ -0,0 +1,10 @@
+
+// @EXPECTED: invalid type in T in `is<T>()` for this variant
+
+#include <variant.hpp>
+
+int main()
+{
+    mapbox::util::variant<int, double> x;
+    x.is<std::string>();
+}
diff --git a/third_party/variant/test/compilation_failure/mutating_visitor_on_const.cpp b/third_party/variant/test/compilation_failure/mutating_visitor_on_const.cpp
new file mode 100644
index 0000000..ee77b56
--- /dev/null
+++ b/third_party/variant/test/compilation_failure/mutating_visitor_on_const.cpp
@@ -0,0 +1,24 @@
+
+// @EXPECTED: const int
+
+#include <variant.hpp>
+
+struct mutating_visitor
+{
+    mutating_visitor(int val)
+        : val_(val) {}
+
+    void operator()(int& val) const
+    {
+        val = val_;
+    }
+
+    int val_;
+};
+
+int main()
+{
+    const mapbox::util::variant<int> var(123);
+    const mutating_visitor visitor(456);
+    mapbox::util::apply_visitor(visitor, var);
+}
diff --git a/third_party/variant/test/compilation_failure/no-reference.cpp b/third_party/variant/test/compilation_failure/no-reference.cpp
new file mode 100644
index 0000000..17123ce
--- /dev/null
+++ b/third_party/variant/test/compilation_failure/no-reference.cpp
@@ -0,0 +1,9 @@
+
+// @EXPECTED: Variant can not hold reference types
+
+#include <variant.hpp>
+
+int main()
+{
+    mapbox::util::variant<double, int&, long> x{mapbox::util::no_init()};
+}
diff --git a/third_party/variant/test/include/catch.hpp b/third_party/variant/test/include/catch.hpp
new file mode 100644
index 0000000..dd6e3ed
--- /dev/null
+++ b/third_party/variant/test/include/catch.hpp
@@ -0,0 +1,11613 @@
+/*
+ *  Catch v1.3.2
+ *  Generated: 2015-12-28 15:07:07.166291
+ *  ----------------------------------------------------------
+ *  This file has been merged from multiple headers. Please don't edit it directly
+ *  Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
+ *
+ *  Distributed under the Boost Software License, Version 1.0. (See accompanying
+ *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+
+#define TWOBLUECUBES_CATCH_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang system_header
+#elif defined __GNUC__
+#pragma GCC system_header
+#endif
+
+// #included from: internal/catch_suppress_warnings.h
+
+#ifdef __clang__
+#ifdef __ICC // icpc defines the __clang__ macro
+#pragma warning(push)
+#pragma warning(disable : 161 1682)
+#else // __ICC
+#pragma clang diagnostic ignored "-Wglobal-constructors"
+#pragma clang diagnostic ignored "-Wvariadic-macros"
+#pragma clang diagnostic ignored "-Wc99-extensions"
+#pragma clang diagnostic ignored "-Wunused-variable"
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#pragma clang diagnostic ignored "-Wc++98-compat"
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#pragma clang diagnostic ignored "-Wswitch-enum"
+#pragma clang diagnostic ignored "-Wcovered-switch-default"
+#endif
+#elif defined __GNUC__
+#pragma GCC diagnostic ignored "-Wvariadic-macros"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpadded"
+#endif
+#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
+#define CATCH_IMPL
+#endif
+
+#ifdef CATCH_IMPL
+#ifndef CLARA_CONFIG_MAIN
+#define CLARA_CONFIG_MAIN_NOT_DEFINED
+#define CLARA_CONFIG_MAIN
+#endif
+#endif
+
+// #included from: internal/catch_notimplemented_exception.h
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
+
+// #included from: catch_common.h
+#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
+
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE2(name, line) name##line
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE(name, line) INTERNAL_CATCH_UNIQUE_NAME_LINE2(name, line)
+#define INTERNAL_CATCH_UNIQUE_NAME(name) INTERNAL_CATCH_UNIQUE_NAME_LINE(name, __LINE__)
+
+#define INTERNAL_CATCH_STRINGIFY2(expr) #expr
+#define INTERNAL_CATCH_STRINGIFY(expr) INTERNAL_CATCH_STRINGIFY2(expr)
+
+#include <algorithm>
+#include <sstream>
+#include <stdexcept>
+
+// #included from: catch_compiler_capabilities.h
+#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
+
+// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
+// The following features are defined:
+//
+// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported?
+// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
+// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
+// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported?
+// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported
+// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported?
+// CATCH_CONFIG_CPP11_OVERRIDE : is override supported?
+// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
+
+// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
+
+// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported?
+
+// ****************
+// Note to maintainers: if new toggles are added please document them
+// in configuration.md, too
+// ****************
+
+// In general each macro has a _NO_<feature name> form
+// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
+// Many features, at point of detection, define an _INTERNAL_ macro, so they
+// can be combined, en-mass, with the _NO_ forms later.
+
+// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11
+
+#ifdef __clang__
+
+#if __has_feature(cxx_nullptr)
+#define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+#if __has_feature(cxx_noexcept)
+#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#endif
+
+#endif // __clang__
+
+////////////////////////////////////////////////////////////////////////////////
+// Borland
+#ifdef __BORLANDC__
+
+#endif // __BORLANDC__
+
+////////////////////////////////////////////////////////////////////////////////
+// EDG
+#ifdef __EDG_VERSION__
+
+#endif // __EDG_VERSION__
+
+////////////////////////////////////////////////////////////////////////////////
+// Digital Mars
+#ifdef __DMC__
+
+#endif // __DMC__
+
+////////////////////////////////////////////////////////////////////////////////
+// GCC
+#ifdef __GNUC__
+
+#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
+#define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+// - otherwise more recent versions define __cplusplus >= 201103L
+// and will get picked up below
+
+#endif // __GNUC__
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual C++
+#ifdef _MSC_VER
+
+#if (_MSC_VER >= 1600)
+#define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#if (_MSC_VER >= 1900) // (VC++ 13 (VS2015))
+#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#endif
+
+#endif // _MSC_VER
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Use variadic macros if the compiler supports them
+#if (defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
+    (defined __WAVE__ && __WAVE_HAS_VARIADICS) ||                 \
+    (defined __GNUC__ && __GNUC__ >= 3) ||                        \
+    (!defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L)
+
+#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// C++ language feature support
+
+// catch all support for C++11
+#if defined(__cplusplus) && __cplusplus >= 201103L
+
+#define CATCH_CPP11_OR_GREATER
+
+#if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR)
+#define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+#ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#endif
+
+#ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#endif
+
+#ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
+#define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
+#endif
+
+#ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE
+#define CATCH_INTERNAL_CONFIG_CPP11_TUPLE
+#endif
+
+#ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+#endif
+
+#if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG)
+#define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG
+#endif
+
+#if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE)
+#define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE
+#endif
+#if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
+#define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#endif // __cplusplus >= 201103L
+
+// Now set the actual defines based on the above + anything the user has configured
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_NULLPTR
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_NOEXCEPT
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_GENERATED_METHODS
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_IS_ENUM
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_TUPLE
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS)
+#define CATCH_CONFIG_VARIADIC_MACROS
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_LONG_LONG
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_OVERRIDE
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+// noexcept support:
+#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
+#define CATCH_NOEXCEPT noexcept
+#define CATCH_NOEXCEPT_IS(x) noexcept(x)
+#else
+#define CATCH_NOEXCEPT throw()
+#define CATCH_NOEXCEPT_IS(x)
+#endif
+
+// nullptr support
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+#define CATCH_NULL nullptr
+#else
+#define CATCH_NULL NULL
+#endif
+
+// override support
+#ifdef CATCH_CONFIG_CPP11_OVERRIDE
+#define CATCH_OVERRIDE override
+#else
+#define CATCH_OVERRIDE
+#endif
+
+// unique_ptr support
+#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR
+#define CATCH_AUTO_PTR(T) std::unique_ptr<T>
+#else
+#define CATCH_AUTO_PTR(T) std::auto_ptr<T>
+#endif
+
+namespace Catch {
+
+struct IConfig;
+
+struct CaseSensitive
+{
+    enum Choice
+    {
+        Yes,
+        No
+    };
+};
+
+class NonCopyable
+{
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+    NonCopyable(NonCopyable const&) = delete;
+    NonCopyable(NonCopyable&&) = delete;
+    NonCopyable& operator=(NonCopyable const&) = delete;
+    NonCopyable& operator=(NonCopyable&&) = delete;
+#else
+    NonCopyable(NonCopyable const& info);
+    NonCopyable& operator=(NonCopyable const&);
+#endif
+
+  protected:
+    NonCopyable() {}
+    virtual ~NonCopyable();
+};
+
+class SafeBool
+{
+  public:
+    typedef void (SafeBool::*type)() const;
+
+    static type makeSafe(bool value)
+    {
+        return value ? &SafeBool::trueValue : 0;
+    }
+
+  private:
+    void trueValue() const {}
+};
+
+template <typename ContainerT>
+inline void deleteAll(ContainerT& container)
+{
+    typename ContainerT::const_iterator it = container.begin();
+    typename ContainerT::const_iterator itEnd = container.end();
+    for (; it != itEnd; ++it)
+        delete *it;
+}
+template <typename AssociativeContainerT>
+inline void deleteAllValues(AssociativeContainerT& container)
+{
+    typename AssociativeContainerT::const_iterator it = container.begin();
+    typename AssociativeContainerT::const_iterator itEnd = container.end();
+    for (; it != itEnd; ++it)
+        delete it->second;
+}
+
+bool startsWith(std::string const& s, std::string const& prefix);
+bool endsWith(std::string const& s, std::string const& suffix);
+bool contains(std::string const& s, std::string const& infix);
+void toLowerInPlace(std::string& s);
+std::string toLower(std::string const& s);
+std::string trim(std::string const& str);
+bool replaceInPlace(std::string& str, std::string const& replaceThis, std::string const& withThis);
+
+struct pluralise
+{
+    pluralise(std::size_t count, std::string const& label);
+
+    friend std::ostream& operator<<(std::ostream& os, pluralise const& pluraliser);
+
+    std::size_t m_count;
+    std::string m_label;
+};
+
+struct SourceLineInfo
+{
+
+    SourceLineInfo();
+    SourceLineInfo(char const* _file, std::size_t _line);
+    SourceLineInfo(SourceLineInfo const& other);
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+    SourceLineInfo(SourceLineInfo&&) = default;
+    SourceLineInfo& operator=(SourceLineInfo const&) = default;
+    SourceLineInfo& operator=(SourceLineInfo&&) = default;
+#endif
+    bool empty() const;
+    bool operator==(SourceLineInfo const& other) const;
+    bool operator<(SourceLineInfo const& other) const;
+
+    std::string file;
+    std::size_t line;
+};
+
+std::ostream& operator<<(std::ostream& os, SourceLineInfo const& info);
+
+// This is just here to avoid compiler warnings with macro constants and boolean literals
+inline bool isTrue(bool value) { return value; }
+inline bool alwaysTrue() { return true; }
+inline bool alwaysFalse() { return false; }
+
+void throwLogicError(std::string const& message, SourceLineInfo const& locationInfo);
+
+void seedRng(IConfig const& config);
+unsigned int rngSeed();
+
+// Use this in variadic streaming macros to allow
+//    >> +StreamEndStop
+// as well as
+//    >> stuff +StreamEndStop
+struct StreamEndStop
+{
+    std::string operator+()
+    {
+        return std::string();
+    }
+};
+template <typename T>
+T const& operator+(T const& value, StreamEndStop)
+{
+    return value;
+}
+}
+
+#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo(__FILE__, static_cast<std::size_t>(__LINE__))
+#define CATCH_INTERNAL_ERROR(msg) ::Catch::throwLogicError(msg, CATCH_INTERNAL_LINEINFO);
+
+#include <ostream>
+
+namespace Catch {
+
+class NotImplementedException : public std::exception
+{
+  public:
+    NotImplementedException(SourceLineInfo const& lineInfo);
+    NotImplementedException(NotImplementedException const&) {}
+
+    virtual ~NotImplementedException() CATCH_NOEXCEPT {}
+
+    virtual const char* what() const CATCH_NOEXCEPT;
+
+  private:
+    std::string m_what;
+    SourceLineInfo m_lineInfo;
+};
+
+} // end namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException(CATCH_INTERNAL_LINEINFO)
+
+// #included from: internal/catch_context.h
+#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
+
+// #included from: catch_interfaces_generators.h
+#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+struct IGeneratorInfo
+{
+    virtual ~IGeneratorInfo();
+    virtual bool moveNext() = 0;
+    virtual std::size_t getCurrentIndex() const = 0;
+};
+
+struct IGeneratorsForTest
+{
+    virtual ~IGeneratorsForTest();
+
+    virtual IGeneratorInfo& getGeneratorInfo(std::string const& fileInfo, std::size_t size) = 0;
+    virtual bool moveNext() = 0;
+};
+
+IGeneratorsForTest* createGeneratorsForTest();
+
+} // end namespace Catch
+
+// #included from: catch_ptr.hpp
+#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+// An intrusive reference counting smart pointer.
+// T must implement addRef() and release() methods
+// typically implementing the IShared interface
+template <typename T>
+class Ptr
+{
+  public:
+    Ptr() : m_p(CATCH_NULL) {}
+    Ptr(T* p) : m_p(p)
+    {
+        if (m_p)
+            m_p->addRef();
+    }
+    Ptr(Ptr const& other) : m_p(other.m_p)
+    {
+        if (m_p)
+            m_p->addRef();
+    }
+    ~Ptr()
+    {
+        if (m_p)
+            m_p->release();
+    }
+    void reset()
+    {
+        if (m_p)
+            m_p->release();
+        m_p = CATCH_NULL;
+    }
+    Ptr& operator=(T* p)
+    {
+        Ptr temp(p);
+        swap(temp);
+        return *this;
+    }
+    Ptr& operator=(Ptr const& other)
+    {
+        Ptr temp(other);
+        swap(temp);
+        return *this;
+    }
+    void swap(Ptr& other) { std::swap(m_p, other.m_p); }
+    T* get() const { return m_p; }
+    T& operator*() const { return *m_p; }
+    T* operator->() const { return m_p; }
+    bool operator!() const { return m_p == CATCH_NULL; }
+    operator SafeBool::type() const { return SafeBool::makeSafe(m_p != CATCH_NULL); }
+
+  private:
+    T* m_p;
+};
+
+struct IShared : NonCopyable
+{
+    virtual ~IShared();
+    virtual void addRef() const = 0;
+    virtual void release() const = 0;
+};
+
+template <typename T = IShared>
+struct SharedImpl : T
+{
+
+    SharedImpl() : m_rc(0) {}
+
+    virtual void addRef() const
+    {
+        ++m_rc;
+    }
+    virtual void release() const
+    {
+        if (--m_rc == 0)
+            delete this;
+    }
+
+    mutable unsigned int m_rc;
+};
+
+} // end namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <memory>
+#include <stdlib.h>
+#include <vector>
+
+namespace Catch {
+
+class TestCase;
+class Stream;
+struct IResultCapture;
+struct IRunner;
+struct IGeneratorsForTest;
+struct IConfig;
+
+struct IContext
+{
+    virtual ~IContext();
+
+    virtual IResultCapture* getResultCapture() = 0;
+    virtual IRunner* getRunner() = 0;
+    virtual size_t getGeneratorIndex(std::string const& fileInfo, size_t totalSize) = 0;
+    virtual bool advanceGeneratorsForCurrentTest() = 0;
+    virtual Ptr<IConfig const> getConfig() const = 0;
+};
+
+struct IMutableContext : IContext
+{
+    virtual ~IMutableContext();
+    virtual void setResultCapture(IResultCapture* resultCapture) = 0;
+    virtual void setRunner(IRunner* runner) = 0;
+    virtual void setConfig(Ptr<IConfig const> const& config) = 0;
+};
+
+IContext& getCurrentContext();
+IMutableContext& getCurrentMutableContext();
+void cleanUpContext();
+Stream createStream(std::string const& streamName);
+}
+
+// #included from: internal/catch_test_registry.hpp
+#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
+
+// #included from: catch_interfaces_testcase.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
+
+#include <vector>
+
+namespace Catch {
+
+class TestSpec;
+
+struct ITestCase : IShared
+{
+    virtual void invoke() const = 0;
+
+  protected:
+    virtual ~ITestCase();
+};
+
+class TestCase;
+struct IConfig;
+
+struct ITestCaseRegistry
+{
+    virtual ~ITestCaseRegistry();
+    virtual std::vector<TestCase> const& getAllTests() const = 0;
+    virtual std::vector<TestCase> const& getAllTestsSorted(IConfig const& config) const = 0;
+};
+
+bool matchTest(TestCase const& testCase, TestSpec const& testSpec, IConfig const& config);
+std::vector<TestCase> filterTests(std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config);
+std::vector<TestCase> const& getAllTestCasesSorted(IConfig const& config);
+}
+
+namespace Catch {
+
+template <typename C>
+class MethodTestCase : public SharedImpl<ITestCase>
+{
+
+  public:
+    MethodTestCase(void (C::*method)()) : m_method(method) {}
+
+    virtual void invoke() const
+    {
+        C obj;
+        (obj.*m_method)();
+    }
+
+  private:
+    virtual ~MethodTestCase() {}
+
+    void (C::*m_method)();
+};
+
+typedef void (*TestFunction)();
+
+struct NameAndDesc
+{
+    NameAndDesc(const char* _name = "", const char* _description = "")
+        : name(_name), description(_description)
+    {
+    }
+
+    const char* name;
+    const char* description;
+};
+
+void registerTestCase(ITestCase* testCase,
+                      char const* className,
+                      NameAndDesc const& nameAndDesc,
+                      SourceLineInfo const& lineInfo);
+
+struct AutoReg
+{
+
+    AutoReg(TestFunction function,
+            SourceLineInfo const& lineInfo,
+            NameAndDesc const& nameAndDesc);
+
+    template <typename C>
+    AutoReg(void (C::*method)(),
+            char const* className,
+            NameAndDesc const& nameAndDesc,
+            SourceLineInfo const& lineInfo)
+    {
+
+        registerTestCase(new MethodTestCase<C>(method),
+                         className,
+                         nameAndDesc,
+                         lineInfo);
+    }
+
+    ~AutoReg();
+
+  private:
+    AutoReg(AutoReg const&);
+    void operator=(AutoReg const&);
+};
+
+void registerTestCaseFunction(TestFunction function,
+                              SourceLineInfo const& lineInfo,
+                              NameAndDesc const& nameAndDesc);
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TESTCASE(...)                                                                                                                                               \
+    static void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)();                                                                                                        \
+    namespace {                                                                                                                                                                    \
+    Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc(__VA_ARGS__)); \
+    }                                                                                                                                                                              \
+    static void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)()
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_METHOD_AS_TEST_CASE(QualifiedMethod, ...)                                                                                                \
+    namespace {                                                                                                                                                 \
+    Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc(__VA_ARGS__), CATCH_INTERNAL_LINEINFO); \
+    }
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST_CASE_METHOD(ClassName, ...)                                                                                                                                              \
+    namespace {                                                                                                                                                                                      \
+    struct INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____) : ClassName                                                                                                                      \
+    {                                                                                                                                                                                                \
+        void test();                                                                                                                                                                                 \
+    };                                                                                                                                                                                               \
+    Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)::test, #ClassName, Catch::NameAndDesc(__VA_ARGS__), CATCH_INTERNAL_LINEINFO); \
+    }                                                                                                                                                                                                \
+    void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)::test()
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_REGISTER_TESTCASE(Function, ...) \
+    Catch::AutoReg(Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc(__VA_ARGS__));
+
+#else
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TESTCASE(Name, Desc)                                                                                                                                       \
+    static void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)();                                                                                                       \
+    namespace {                                                                                                                                                                   \
+    Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc(Name, Desc)); \
+    }                                                                                                                                                                             \
+    static void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)()
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_METHOD_AS_TEST_CASE(QualifiedMethod, Name, Desc)                                                                                        \
+    namespace {                                                                                                                                                \
+    Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc(Name, Desc), CATCH_INTERNAL_LINEINFO); \
+    }
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST_CASE_METHOD(ClassName, TestName, Desc)                                                                                                                                      \
+    namespace {                                                                                                                                                                                         \
+    struct INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____) : ClassName                                                                                                                         \
+    {                                                                                                                                                                                                   \
+        void test();                                                                                                                                                                                    \
+    };                                                                                                                                                                                                  \
+    Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)::test, #ClassName, Catch::NameAndDesc(TestName, Desc), CATCH_INTERNAL_LINEINFO); \
+    }                                                                                                                                                                                                   \
+    void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)::test()
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_REGISTER_TESTCASE(Function, Name, Desc) \
+    Catch::AutoReg(Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc(Name, Desc));
+#endif
+
+// #included from: internal/catch_capture.hpp
+#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
+
+// #included from: catch_result_builder.h
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
+
+// #included from: catch_result_type.h
+#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
+
+namespace Catch {
+
+// ResultWas::OfType enum
+struct ResultWas
+{
+    enum OfType
+    {
+        Unknown = -1,
+        Ok = 0,
+        Info = 1,
+        Warning = 2,
+
+        FailureBit = 0x10,
+
+        ExpressionFailed = FailureBit | 1,
+        ExplicitFailure = FailureBit | 2,
+
+        Exception = 0x100 | FailureBit,
+
+        ThrewException = Exception | 1,
+        DidntThrowException = Exception | 2,
+
+        FatalErrorCondition = 0x200 | FailureBit
+
+    };
+};
+
+inline bool isOk(ResultWas::OfType resultType)
+{
+    return (resultType & ResultWas::FailureBit) == 0;
+}
+inline bool isJustInfo(int flags)
+{
+    return flags == ResultWas::Info;
+}
+
+// ResultDisposition::Flags enum
+struct ResultDisposition
+{
+    enum Flags
+    {
+        Normal = 0x01,
+
+        ContinueOnFailure = 0x02, // Failures fail test, but execution continues
+        FalseTest = 0x04,         // Prefix expression with !
+        SuppressFail = 0x08       // Failures are reported but do not fail the test
+    };
+};
+
+inline ResultDisposition::Flags operator|(ResultDisposition::Flags lhs, ResultDisposition::Flags rhs)
+{
+    return static_cast<ResultDisposition::Flags>(static_cast<int>(lhs) | static_cast<int>(rhs));
+}
+
+inline bool shouldContinueOnFailure(int flags) { return (flags & ResultDisposition::ContinueOnFailure) != 0; }
+inline bool isFalseTest(int flags) { return (flags & ResultDisposition::FalseTest) != 0; }
+inline bool shouldSuppressFailure(int flags) { return (flags & ResultDisposition::SuppressFail) != 0; }
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.h
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+struct AssertionInfo
+{
+    AssertionInfo() {}
+    AssertionInfo(std::string const& _macroName,
+                  SourceLineInfo const& _lineInfo,
+                  std::string const& _capturedExpression,
+                  ResultDisposition::Flags _resultDisposition);
+
+    std::string macroName;
+    SourceLineInfo lineInfo;
+    std::string capturedExpression;
+    ResultDisposition::Flags resultDisposition;
+};
+
+struct AssertionResultData
+{
+    AssertionResultData() : resultType(ResultWas::Unknown) {}
+
+    std::string reconstructedExpression;
+    std::string message;
+    ResultWas::OfType resultType;
+};
+
+class AssertionResult
+{
+  public:
+    AssertionResult();
+    AssertionResult(AssertionInfo const& info, AssertionResultData const& data);
+    ~AssertionResult();
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+    AssertionResult(AssertionResult const&) = default;
+    AssertionResult(AssertionResult&&) = default;
+    AssertionResult& operator=(AssertionResult const&) = default;
+    AssertionResult& operator=(AssertionResult&&) = default;
+#endif
+
+    bool isOk() const;
+    bool succeeded() const;
+    ResultWas::OfType getResultType() const;
+    bool hasExpression() const;
+    bool hasMessage() const;
+    std::string getExpression() const;
+    std::string getExpressionInMacro() const;
+    bool hasExpandedExpression() const;
+    std::string getExpandedExpression() const;
+    std::string getMessage() const;
+    SourceLineInfo getSourceInfo() const;
+    std::string getTestMacroName() const;
+
+  protected:
+    AssertionInfo m_info;
+    AssertionResultData m_resultData;
+};
+
+} // end namespace Catch
+
+// #included from: catch_matchers.hpp
+#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+namespace Impl {
+
+namespace Generic {
+template <typename ExpressionT>
+class AllOf;
+template <typename ExpressionT>
+class AnyOf;
+template <typename ExpressionT>
+class Not;
+}
+
+template <typename ExpressionT>
+struct Matcher : SharedImpl<IShared>
+{
+    typedef ExpressionT ExpressionType;
+
+    virtual ~Matcher() {}
+    virtual Ptr<Matcher> clone() const = 0;
+    virtual bool match(ExpressionT const& expr) const = 0;
+    virtual std::string toString() const = 0;
+
+    Generic::AllOf<ExpressionT> operator&&(Matcher<ExpressionT> const& other) const;
+    Generic::AnyOf<ExpressionT> operator||(Matcher<ExpressionT> const& other) const;
+    Generic::Not<ExpressionT> operator!() const;
+};
+
+template <typename DerivedT, typename ExpressionT>
+struct MatcherImpl : Matcher<ExpressionT>
+{
+
+    virtual Ptr<Matcher<ExpressionT>> clone() const
+    {
+        return Ptr<Matcher<ExpressionT>>(new DerivedT(static_cast<DerivedT const&>(*this)));
+    }
+};
+
+namespace Generic {
+template <typename ExpressionT>
+class Not : public MatcherImpl<Not<ExpressionT>, ExpressionT>
+{
+  public:
+    explicit Not(Matcher<ExpressionT> const& matcher) : m_matcher(matcher.clone()) {}
+    Not(Not const& other) : m_matcher(other.m_matcher) {}
+
+    virtual bool match(ExpressionT const& expr) const CATCH_OVERRIDE
+    {
+        return !m_matcher->match(expr);
+    }
+
+    virtual std::string toString() const CATCH_OVERRIDE
+    {
+        return "not " + m_matcher->toString();
+    }
+
+  private:
+    Ptr<Matcher<ExpressionT>> m_matcher;
+};
+
+template <typename ExpressionT>
+class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT>
+{
+  public:
+    AllOf() {}
+    AllOf(AllOf const& other) : m_matchers(other.m_matchers) {}
+
+    AllOf& add(Matcher<ExpressionT> const& matcher)
+    {
+        m_matchers.push_back(matcher.clone());
+        return *this;
+    }
+    virtual bool match(ExpressionT const& expr) const
+    {
+        for (std::size_t i = 0; i < m_matchers.size(); ++i)
+            if (!m_matchers[i]->match(expr))
+                return false;
+        return true;
+    }
+    virtual std::string toString() const
+    {
+        std::ostringstream oss;
+        oss << "( ";
+        for (std::size_t i = 0; i < m_matchers.size(); ++i)
+        {
+            if (i != 0)
+                oss << " and ";
+            oss << m_matchers[i]->toString();
+        }
+        oss << " )";
+        return oss.str();
+    }
+
+    AllOf operator&&(Matcher<ExpressionT> const& other) const
+    {
+        AllOf allOfExpr(*this);
+        allOfExpr.add(other);
+        return allOfExpr;
+    }
+
+  private:
+    std::vector<Ptr<Matcher<ExpressionT>>> m_matchers;
+};
+
+template <typename ExpressionT>
+class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT>
+{
+  public:
+    AnyOf() {}
+    AnyOf(AnyOf const& other) : m_matchers(other.m_matchers) {}
+
+    AnyOf& add(Matcher<ExpressionT> const& matcher)
+    {
+        m_matchers.push_back(matcher.clone());
+        return *this;
+    }
+    virtual bool match(ExpressionT const& expr) const
+    {
+        for (std::size_t i = 0; i < m_matchers.size(); ++i)
+            if (m_matchers[i]->match(expr))
+                return true;
+        return false;
+    }
+    virtual std::string toString() const
+    {
+        std::ostringstream oss;
+        oss << "( ";
+        for (std::size_t i = 0; i < m_matchers.size(); ++i)
+        {
+            if (i != 0)
+                oss << " or ";
+            oss << m_matchers[i]->toString();
+        }
+        oss << " )";
+        return oss.str();
+    }
+
+    AnyOf operator||(Matcher<ExpressionT> const& other) const
+    {
+        AnyOf anyOfExpr(*this);
+        anyOfExpr.add(other);
+        return anyOfExpr;
+    }
+
+  private:
+    std::vector<Ptr<Matcher<ExpressionT>>> m_matchers;
+};
+
+} // namespace Generic
+
+template <typename ExpressionT>
+Generic::AllOf<ExpressionT> Matcher<ExpressionT>::operator&&(Matcher<ExpressionT> const& other) const
+{
+    Generic::AllOf<ExpressionT> allOfExpr;
+    allOfExpr.add(*this);
+    allOfExpr.add(other);
+    return allOfExpr;
+}
+
+template <typename ExpressionT>
+Generic::AnyOf<ExpressionT> Matcher<ExpressionT>::operator||(Matcher<ExpressionT> const& other) const
+{
+    Generic::AnyOf<ExpressionT> anyOfExpr;
+    anyOfExpr.add(*this);
+    anyOfExpr.add(other);
+    return anyOfExpr;
+}
+
+template <typename ExpressionT>
+Generic::Not<ExpressionT> Matcher<ExpressionT>::operator!() const
+{
+    return Generic::Not<ExpressionT>(*this);
+}
+
+namespace StdString {
+
+inline std::string makeString(std::string const& str) { return str; }
+inline std::string makeString(const char* str) { return str ? std::string(str) : std::string(); }
+
+struct CasedString
+{
+    CasedString(std::string const& str, CaseSensitive::Choice caseSensitivity)
+        : m_caseSensitivity(caseSensitivity),
+          m_str(adjustString(str))
+    {
+    }
+    std::string adjustString(std::string const& str) const
+    {
+        return m_caseSensitivity == CaseSensitive::No
+                   ? toLower(str)
+                   : str;
+    }
+    std::string toStringSuffix() const
+    {
+        return m_caseSensitivity == CaseSensitive::No
+                   ? " (case insensitive)"
+                   : "";
+    }
+    CaseSensitive::Choice m_caseSensitivity;
+    std::string m_str;
+};
+
+struct Equals : MatcherImpl<Equals, std::string>
+{
+    Equals(std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+        : m_data(str, caseSensitivity)
+    {
+    }
+    Equals(Equals const& other) : m_data(other.m_data) {}
+
+    virtual ~Equals();
+
+    virtual bool match(std::string const& expr) const
+    {
+        return m_data.m_str == m_data.adjustString(expr);
+        ;
+    }
+    virtual std::string toString() const
+    {
+        return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+    }
+
+    CasedString m_data;
+};
+
+struct Contains : MatcherImpl<Contains, std::string>
+{
+    Contains(std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+        : m_data(substr, caseSensitivity) {}
+    Contains(Contains const& other) : m_data(other.m_data) {}
+
+    virtual ~Contains();
+
+    virtual bool match(std::string const& expr) const
+    {
+        return m_data.adjustString(expr).find(m_data.m_str) != std::string::npos;
+    }
+    virtual std::string toString() const
+    {
+        return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+    }
+
+    CasedString m_data;
+};
+
+struct StartsWith : MatcherImpl<StartsWith, std::string>
+{
+    StartsWith(std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+        : m_data(substr, caseSensitivity) {}
+
+    StartsWith(StartsWith const& other) : m_data(other.m_data) {}
+
+    virtual ~StartsWith();
+
+    virtual bool match(std::string const& expr) const
+    {
+        return m_data.adjustString(expr).find(m_data.m_str) == 0;
+    }
+    virtual std::string toString() const
+    {
+        return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+    }
+
+    CasedString m_data;
+};
+
+struct EndsWith : MatcherImpl<EndsWith, std::string>
+{
+    EndsWith(std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+        : m_data(substr, caseSensitivity) {}
+    EndsWith(EndsWith const& other) : m_data(other.m_data) {}
+
+    virtual ~EndsWith();
+
+    virtual bool match(std::string const& expr) const
+    {
+        return m_data.adjustString(expr).find(m_data.m_str) == expr.size() - m_data.m_str.size();
+    }
+    virtual std::string toString() const
+    {
+        return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+    }
+
+    CasedString m_data;
+};
+} // namespace StdString
+} // namespace Impl
+
+// The following functions create the actual matcher objects.
+// This allows the types to be inferred
+template <typename ExpressionT>
+inline Impl::Generic::Not<ExpressionT> Not(Impl::Matcher<ExpressionT> const& m)
+{
+    return Impl::Generic::Not<ExpressionT>(m);
+}
+
+template <typename ExpressionT>
+inline Impl::Generic::AllOf<ExpressionT> AllOf(Impl::Matcher<ExpressionT> const& m1,
+                                               Impl::Matcher<ExpressionT> const& m2)
+{
+    return Impl::Generic::AllOf<ExpressionT>().add(m1).add(m2);
+}
+template <typename ExpressionT>
+inline Impl::Generic::AllOf<ExpressionT> AllOf(Impl::Matcher<ExpressionT> const& m1,
+                                               Impl::Matcher<ExpressionT> const& m2,
+                                               Impl::Matcher<ExpressionT> const& m3)
+{
+    return Impl::Generic::AllOf<ExpressionT>().add(m1).add(m2).add(m3);
+}
+template <typename ExpressionT>
+inline Impl::Generic::AnyOf<ExpressionT> AnyOf(Impl::Matcher<ExpressionT> const& m1,
+                                               Impl::Matcher<ExpressionT> const& m2)
+{
+    return Impl::Generic::AnyOf<ExpressionT>().add(m1).add(m2);
+}
+template <typename ExpressionT>
+inline Impl::Generic::AnyOf<ExpressionT> AnyOf(Impl::Matcher<ExpressionT> const& m1,
+                                               Impl::Matcher<ExpressionT> const& m2,
+                                               Impl::Matcher<ExpressionT> const& m3)
+{
+    return Impl::Generic::AnyOf<ExpressionT>().add(m1).add(m2).add(m3);
+}
+
+inline Impl::StdString::Equals Equals(std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+{
+    return Impl::StdString::Equals(str, caseSensitivity);
+}
+inline Impl::StdString::Equals Equals(const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+{
+    return Impl::StdString::Equals(Impl::StdString::makeString(str), caseSensitivity);
+}
+inline Impl::StdString::Contains Contains(std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+{
+    return Impl::StdString::Contains(substr, caseSensitivity);
+}
+inline Impl::StdString::Contains Contains(const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+{
+    return Impl::StdString::Contains(Impl::StdString::makeString(substr), caseSensitivity);
+}
+inline Impl::StdString::StartsWith StartsWith(std::string const& substr)
+{
+    return Impl::StdString::StartsWith(substr);
+}
+inline Impl::StdString::StartsWith StartsWith(const char* substr)
+{
+    return Impl::StdString::StartsWith(Impl::StdString::makeString(substr));
+}
+inline Impl::StdString::EndsWith EndsWith(std::string const& substr)
+{
+    return Impl::StdString::EndsWith(substr);
+}
+inline Impl::StdString::EndsWith EndsWith(const char* substr)
+{
+    return Impl::StdString::EndsWith(Impl::StdString::makeString(substr));
+}
+
+} // namespace Matchers
+
+using namespace Matchers;
+
+} // namespace Catch
+
+namespace Catch {
+
+struct TestFailureException
+{
+};
+
+template <typename T>
+class ExpressionLhs;
+
+struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
+
+struct CopyableStream
+{
+    CopyableStream() {}
+    CopyableStream(CopyableStream const& other)
+    {
+        oss << other.oss.str();
+    }
+    CopyableStream& operator=(CopyableStream const& other)
+    {
+        oss.str("");
+        oss << other.oss.str();
+        return *this;
+    }
+    std::ostringstream oss;
+};
+
+class ResultBuilder
+{
+  public:
+    ResultBuilder(char const* macroName,
+                  SourceLineInfo const& lineInfo,
+                  char const* capturedExpression,
+                  ResultDisposition::Flags resultDisposition,
+                  char const* secondArg = "");
+
+    template <typename T>
+    ExpressionLhs<T const&> operator<=(T const& operand);
+    ExpressionLhs<bool> operator<=(bool value);
+
+    template <typename T>
+    ResultBuilder& operator<<(T const& value)
+    {
+        m_stream.oss << value;
+        return *this;
+    }
+
+    template <typename RhsT>
+    STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator&&(RhsT const&);
+    template <typename RhsT>
+    STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator||(RhsT const&);
+
+    ResultBuilder& setResultType(ResultWas::OfType result);
+    ResultBuilder& setResultType(bool result);
+    ResultBuilder& setLhs(std::string const& lhs);
+    ResultBuilder& setRhs(std::string const& rhs);
+    ResultBuilder& setOp(std::string const& op);
+
+    void endExpression();
+
+    std::string reconstructExpression() const;
+    AssertionResult build() const;
+
+    void useActiveException(ResultDisposition::Flags resultDisposition = ResultDisposition::Normal);
+    void captureResult(ResultWas::OfType resultType);
+    void captureExpression();
+    void captureExpectedException(std::string const& expectedMessage);
+    void captureExpectedException(Matchers::Impl::Matcher<std::string> const& matcher);
+    void handleResult(AssertionResult const& result);
+    void react();
+    bool shouldDebugBreak() const;
+    bool allowThrows() const;
+
+  private:
+    AssertionInfo m_assertionInfo;
+    AssertionResultData m_data;
+    struct ExprComponents
+    {
+        ExprComponents() : testFalse(false) {}
+        bool testFalse;
+        std::string lhs, rhs, op;
+    } m_exprComponents;
+    CopyableStream m_stream;
+
+    bool m_shouldDebugBreak;
+    bool m_shouldThrow;
+};
+
+} // namespace Catch
+
+// Include after due to circular dependency:
+// #included from: catch_expression_lhs.hpp
+#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
+
+// #included from: catch_evaluate.hpp
+#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4389) // '==' : signed/unsigned mismatch
+#endif
+
+#include <cstddef>
+
+namespace Catch {
+namespace Internal {
+
+enum Operator
+{
+    IsEqualTo,
+    IsNotEqualTo,
+    IsLessThan,
+    IsGreaterThan,
+    IsLessThanOrEqualTo,
+    IsGreaterThanOrEqualTo
+};
+
+template <Operator Op>
+struct OperatorTraits
+{
+    static const char* getName() { return "*error*"; }
+};
+template <>
+struct OperatorTraits<IsEqualTo>
+{
+    static const char* getName() { return "=="; }
+};
+template <>
+struct OperatorTraits<IsNotEqualTo>
+{
+    static const char* getName() { return "!="; }
+};
+template <>
+struct OperatorTraits<IsLessThan>
+{
+    static const char* getName() { return "<"; }
+};
+template <>
+struct OperatorTraits<IsGreaterThan>
+{
+    static const char* getName() { return ">"; }
+};
+template <>
+struct OperatorTraits<IsLessThanOrEqualTo>
+{
+    static const char* getName() { return "<="; }
+};
+template <>
+struct OperatorTraits<IsGreaterThanOrEqualTo>
+{
+    static const char* getName() { return ">="; }
+};
+
+template <typename T>
+inline T& opCast(T const& t)
+{
+    return const_cast<T&>(t);
+}
+
+// nullptr_t support based on pull request #154 from Konstantin Baumann
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+inline std::nullptr_t opCast(std::nullptr_t)
+{
+    return nullptr;
+}
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+// So the compare overloads can be operator agnostic we convey the operator as a template
+// enum, which is used to specialise an Evaluator for doing the comparison.
+template <typename T1, typename T2, Operator Op>
+class Evaluator
+{
+};
+
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsEqualTo>
+{
+    static bool evaluate(T1 const& lhs, T2 const& rhs)
+    {
+        return opCast(lhs) == opCast(rhs);
+    }
+};
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsNotEqualTo>
+{
+    static bool evaluate(T1 const& lhs, T2 const& rhs)
+    {
+        return opCast(lhs) != opCast(rhs);
+    }
+};
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsLessThan>
+{
+    static bool evaluate(T1 const& lhs, T2 const& rhs)
+    {
+        return opCast(lhs) < opCast(rhs);
+    }
+};
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsGreaterThan>
+{
+    static bool evaluate(T1 const& lhs, T2 const& rhs)
+    {
+        return opCast(lhs) > opCast(rhs);
+    }
+};
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsGreaterThanOrEqualTo>
+{
+    static bool evaluate(T1 const& lhs, T2 const& rhs)
+    {
+        return opCast(lhs) >= opCast(rhs);
+    }
+};
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsLessThanOrEqualTo>
+{
+    static bool evaluate(T1 const& lhs, T2 const& rhs)
+    {
+        return opCast(lhs) <= opCast(rhs);
+    }
+};
+
+template <Operator Op, typename T1, typename T2>
+bool applyEvaluator(T1 const& lhs, T2 const& rhs)
+{
+    return Evaluator<T1, T2, Op>::evaluate(lhs, rhs);
+}
+
+// This level of indirection allows us to specialise for integer types
+// to avoid signed/ unsigned warnings
+
+// "base" overload
+template <Operator Op, typename T1, typename T2>
+bool compare(T1 const& lhs, T2 const& rhs)
+{
+    return Evaluator<T1, T2, Op>::evaluate(lhs, rhs);
+}
+
+// unsigned X to int
+template <Operator Op>
+bool compare(unsigned int lhs, int rhs)
+{
+    return applyEvaluator<Op>(lhs, static_cast<unsigned int>(rhs));
+}
+template <Operator Op>
+bool compare(unsigned long lhs, int rhs)
+{
+    return applyEvaluator<Op>(lhs, static_cast<unsigned int>(rhs));
+}
+template <Operator Op>
+bool compare(unsigned char lhs, int rhs)
+{
+    return applyEvaluator<Op>(lhs, static_cast<unsigned int>(rhs));
+}
+
+// unsigned X to long
+template <Operator Op>
+bool compare(unsigned int lhs, long rhs)
+{
+    return applyEvaluator<Op>(lhs, static_cast<unsigned long>(rhs));
+}
+template <Operator Op>
+bool compare(unsigned long lhs, long rhs)
+{
+    return applyEvaluator<Op>(lhs, static_cast<unsigned long>(rhs));
+}
+template <Operator Op>
+bool compare(unsigned char lhs, long rhs)
+{
+    return applyEvaluator<Op>(lhs, static_cast<unsigned long>(rhs));
+}
+
+// int to unsigned X
+template <Operator Op>
+bool compare(int lhs, unsigned int rhs)
+{
+    return applyEvaluator<Op>(static_cast<unsigned int>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(int lhs, unsigned long rhs)
+{
+    return applyEvaluator<Op>(static_cast<unsigned int>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(int lhs, unsigned char rhs)
+{
+    return applyEvaluator<Op>(static_cast<unsigned int>(lhs), rhs);
+}
+
+// long to unsigned X
+template <Operator Op>
+bool compare(long lhs, unsigned int rhs)
+{
+    return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(long lhs, unsigned long rhs)
+{
+    return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(long lhs, unsigned char rhs)
+{
+    return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+
+// pointer to long (when comparing against NULL)
+template <Operator Op, typename T>
+bool compare(long lhs, T* rhs)
+{
+    return Evaluator<T*, T*, Op>::evaluate(reinterpret_cast<T*>(lhs), rhs);
+}
+template <Operator Op, typename T>
+bool compare(T* lhs, long rhs)
+{
+    return Evaluator<T*, T*, Op>::evaluate(lhs, reinterpret_cast<T*>(rhs));
+}
+
+// pointer to int (when comparing against NULL)
+template <Operator Op, typename T>
+bool compare(int lhs, T* rhs)
+{
+    return Evaluator<T*, T*, Op>::evaluate(reinterpret_cast<T*>(lhs), rhs);
+}
+template <Operator Op, typename T>
+bool compare(T* lhs, int rhs)
+{
+    return Evaluator<T*, T*, Op>::evaluate(lhs, reinterpret_cast<T*>(rhs));
+}
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+// long long to unsigned X
+template <Operator Op>
+bool compare(long long lhs, unsigned int rhs)
+{
+    return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(long long lhs, unsigned long rhs)
+{
+    return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(long long lhs, unsigned long long rhs)
+{
+    return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(long long lhs, unsigned char rhs)
+{
+    return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+
+// unsigned long long to X
+template <Operator Op>
+bool compare(unsigned long long lhs, int rhs)
+{
+    return applyEvaluator<Op>(static_cast<long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(unsigned long long lhs, long rhs)
+{
+    return applyEvaluator<Op>(static_cast<long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(unsigned long long lhs, long long rhs)
+{
+    return applyEvaluator<Op>(static_cast<long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(unsigned long long lhs, char rhs)
+{
+    return applyEvaluator<Op>(static_cast<long>(lhs), rhs);
+}
+
+// pointer to long long (when comparing against NULL)
+template <Operator Op, typename T>
+bool compare(long long lhs, T* rhs)
+{
+    return Evaluator<T*, T*, Op>::evaluate(reinterpret_cast<T*>(lhs), rhs);
+}
+template <Operator Op, typename T>
+bool compare(T* lhs, long long rhs)
+{
+    return Evaluator<T*, T*, Op>::evaluate(lhs, reinterpret_cast<T*>(rhs));
+}
+#endif // CATCH_CONFIG_CPP11_LONG_LONG
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+// pointer to nullptr_t (when comparing against nullptr)
+template <Operator Op, typename T>
+bool compare(std::nullptr_t, T* rhs)
+{
+    return Evaluator<T*, T*, Op>::evaluate(nullptr, rhs);
+}
+template <Operator Op, typename T>
+bool compare(T* lhs, std::nullptr_t)
+{
+    return Evaluator<T*, T*, Op>::evaluate(lhs, nullptr);
+}
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+} // end of namespace Internal
+} // end of namespace Catch
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+// #included from: catch_tostring.h
+#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
+
+#include <cstddef>
+#include <iomanip>
+#include <limits>
+#include <sstream>
+#include <vector>
+
+#ifdef __OBJC__
+// #included from: catch_objc_arc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED
+
+#import <Foundation/Foundation.h>
+
+#ifdef __has_feature
+#define CATCH_ARC_ENABLED __has_feature(objc_arc)
+#else
+#define CATCH_ARC_ENABLED 0
+#endif
+
+void arcSafeRelease(NSObject* obj);
+id performOptionalSelector(id obj, SEL sel);
+
+#if !CATCH_ARC_ENABLED
+inline void arcSafeRelease(NSObject* obj)
+{
+    [obj release];
+}
+inline id performOptionalSelector(id obj, SEL sel)
+{
+    if ([obj respondsToSelector:sel])
+        return [obj performSelector:sel];
+    return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED
+#define CATCH_ARC_STRONG
+#else
+inline void arcSafeRelease(NSObject*)
+{
+}
+inline id performOptionalSelector(id obj, SEL sel)
+{
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+#endif
+    if ([obj respondsToSelector:sel])
+        return [obj performSelector:sel];
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+    return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
+#define CATCH_ARC_STRONG __strong
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_TUPLE
+#include <tuple>
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_IS_ENUM
+#include <type_traits>
+#endif
+
+namespace Catch {
+
+// Why we're here.
+template <typename T>
+std::string toString(T const& value);
+
+// Built in overloads
+
+std::string toString(std::string const& value);
+std::string toString(std::wstring const& value);
+std::string toString(const char* const value);
+std::string toString(char* const value);
+std::string toString(const wchar_t* const value);
+std::string toString(wchar_t* const value);
+std::string toString(int value);
+std::string toString(unsigned long value);
+std::string toString(unsigned int value);
+std::string toString(const double value);
+std::string toString(const float value);
+std::string toString(bool value);
+std::string toString(char value);
+std::string toString(signed char value);
+std::string toString(unsigned char value);
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+std::string toString(long long value);
+std::string toString(unsigned long long value);
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString(std::nullptr_t);
+#endif
+
+#ifdef __OBJC__
+std::string toString(NSString const* const& nsstring);
+std::string toString(NSString* CATCH_ARC_STRONG const& nsstring);
+std::string toString(NSObject* const& nsObject);
+#endif
+
+namespace Detail {
+
+extern const std::string unprintableString;
+
+struct BorgType
+{
+    template <typename T>
+    BorgType(T const&);
+};
+
+struct TrueType
+{
+    char sizer[1];
+};
+struct FalseType
+{
+    char sizer[2];
+};
+
+TrueType& testStreamable(std::ostream&);
+FalseType testStreamable(FalseType);
+
+FalseType operator<<(std::ostream const&, BorgType const&);
+
+template <typename T>
+struct IsStreamInsertable
+{
+    static std::ostream& s;
+    static T const& t;
+    enum
+    {
+        value = sizeof(testStreamable(s << t)) == sizeof(TrueType)
+    };
+};
+
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
+template <typename T,
+          bool IsEnum = std::is_enum<T>::value>
+struct EnumStringMaker
+{
+    static std::string convert(T const&) { return unprintableString; }
+};
+
+template <typename T>
+struct EnumStringMaker<T, true>
+{
+    static std::string convert(T const& v)
+    {
+        return ::Catch::toString(
+            static_cast<typename std::underlying_type<T>::type>(v));
+    }
+};
+#endif
+template <bool C>
+struct StringMakerBase
+{
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
+    template <typename T>
+    static std::string convert(T const& v)
+    {
+        return EnumStringMaker<T>::convert(v);
+    }
+#else
+    template <typename T>
+    static std::string convert(T const&)
+    {
+        return unprintableString;
+    }
+#endif
+};
+
+template <>
+struct StringMakerBase<true>
+{
+    template <typename T>
+    static std::string convert(T const& _value)
+    {
+        std::ostringstream oss;
+        oss << _value;
+        return oss.str();
+    }
+};
+
+std::string rawMemoryToString(const void* object, std::size_t size);
+
+template <typename T>
+inline std::string rawMemoryToString(const T& object)
+{
+    return rawMemoryToString(&object, sizeof(object));
+}
+
+} // end namespace Detail
+
+template <typename T>
+struct StringMaker : Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value>
+{
+};
+
+template <typename T>
+struct StringMaker<T*>
+{
+    template <typename U>
+    static std::string convert(U* p)
+    {
+        if (!p)
+            return "NULL";
+        else
+            return Detail::rawMemoryToString(p);
+    }
+};
+
+template <typename R, typename C>
+struct StringMaker<R C::*>
+{
+    static std::string convert(R C::*p)
+    {
+        if (!p)
+            return "NULL";
+        else
+            return Detail::rawMemoryToString(p);
+    }
+};
+
+namespace Detail {
+template <typename InputIterator>
+std::string rangeToString(InputIterator first, InputIterator last);
+}
+
+//template<typename T, typename Allocator>
+//struct StringMaker<std::vector<T, Allocator> > {
+//    static std::string convert( std::vector<T,Allocator> const& v ) {
+//        return Detail::rangeToString( v.begin(), v.end() );
+//    }
+//};
+
+template <typename T, typename Allocator>
+std::string toString(std::vector<T, Allocator> const& v)
+{
+    return Detail::rangeToString(v.begin(), v.end());
+}
+
+#ifdef CATCH_CONFIG_CPP11_TUPLE
+
+// toString for tuples
+namespace TupleDetail {
+template <
+    typename Tuple,
+    std::size_t N = 0,
+    bool = (N < std::tuple_size<Tuple>::value)>
+struct ElementPrinter
+{
+    static void print(const Tuple& tuple, std::ostream& os)
+    {
+        os << (N ? ", " : " ")
+           << Catch::toString(std::get<N>(tuple));
+        ElementPrinter<Tuple, N + 1>::print(tuple, os);
+    }
+};
+
+template <
+    typename Tuple,
+    std::size_t N>
+struct ElementPrinter<Tuple, N, false>
+{
+    static void print(const Tuple&, std::ostream&) {}
+};
+}
+
+template <typename... Types>
+struct StringMaker<std::tuple<Types...>>
+{
+
+    static std::string convert(const std::tuple<Types...>& tuple)
+    {
+        std::ostringstream os;
+        os << '{';
+        TupleDetail::ElementPrinter<std::tuple<Types...>>::print(tuple, os);
+        os << " }";
+        return os.str();
+    }
+};
+#endif // CATCH_CONFIG_CPP11_TUPLE
+
+namespace Detail {
+template <typename T>
+std::string makeString(T const& value)
+{
+    return StringMaker<T>::convert(value);
+}
+} // end namespace Detail
+
+/// \brief converts any type to a string
+///
+/// The default template forwards on to ostringstream - except when an
+/// ostringstream overload does not exist - in which case it attempts to detect
+/// that and writes {?}.
+/// Overload (not specialise) this template for custom typs that you don't want
+/// to provide an ostream overload for.
+template <typename T>
+std::string toString(T const& value)
+{
+    return StringMaker<T>::convert(value);
+}
+
+namespace Detail {
+template <typename InputIterator>
+std::string rangeToString(InputIterator first, InputIterator last)
+{
+    std::ostringstream oss;
+    oss << "{ ";
+    if (first != last)
+    {
+        oss << Catch::toString(*first);
+        for (++first; first != last; ++first)
+            oss << ", " << Catch::toString(*first);
+    }
+    oss << " }";
+    return oss.str();
+}
+}
+
+} // end namespace Catch
+
+namespace Catch {
+
+// Wraps the LHS of an expression and captures the operator and RHS (if any) -
+// wrapping them all in a ResultBuilder object
+template <typename T>
+class ExpressionLhs
+{
+    ExpressionLhs& operator=(ExpressionLhs const&);
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+    ExpressionLhs& operator=(ExpressionLhs&&) = delete;
+#endif
+
+  public:
+    ExpressionLhs(ResultBuilder& rb, T lhs) : m_rb(rb), m_lhs(lhs) {}
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+    ExpressionLhs(ExpressionLhs const&) = default;
+    ExpressionLhs(ExpressionLhs&&) = default;
+#endif
+
+    template <typename RhsT>
+    ResultBuilder& operator==(RhsT const& rhs)
+    {
+        return captureExpression<Internal::IsEqualTo>(rhs);
+    }
+
+    template <typename RhsT>
+    ResultBuilder& operator!=(RhsT const& rhs)
+    {
+        return captureExpression<Internal::IsNotEqualTo>(rhs);
+    }
+
+    template <typename RhsT>
+    ResultBuilder& operator<(RhsT const& rhs)
+    {
+        return captureExpression<Internal::IsLessThan>(rhs);
+    }
+
+    template <typename RhsT>
+    ResultBuilder& operator>(RhsT const& rhs)
+    {
+        return captureExpression<Internal::IsGreaterThan>(rhs);
+    }
+
+    template <typename RhsT>
+    ResultBuilder& operator<=(RhsT const& rhs)
+    {
+        return captureExpression<Internal::IsLessThanOrEqualTo>(rhs);
+    }
+
+    template <typename RhsT>
+    ResultBuilder& operator>=(RhsT const& rhs)
+    {
+        return captureExpression<Internal::IsGreaterThanOrEqualTo>(rhs);
+    }
+
+    ResultBuilder& operator==(bool rhs)
+    {
+        return captureExpression<Internal::IsEqualTo>(rhs);
+    }
+
+    ResultBuilder& operator!=(bool rhs)
+    {
+        return captureExpression<Internal::IsNotEqualTo>(rhs);
+    }
+
+    void endExpression()
+    {
+        bool value = m_lhs ? true : false;
+        m_rb
+            .setLhs(Catch::toString(value))
+            .setResultType(value)
+            .endExpression();
+    }
+
+    // Only simple binary expressions are allowed on the LHS.
+    // If more complex compositions are required then place the sub expression in parentheses
+    template <typename RhsT>
+    STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator+(RhsT const&);
+    template <typename RhsT>
+    STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator-(RhsT const&);
+    template <typename RhsT>
+    STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator/(RhsT const&);
+    template <typename RhsT>
+    STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator*(RhsT const&);
+    template <typename RhsT>
+    STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator&&(RhsT const&);
+    template <typename RhsT>
+    STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator||(RhsT const&);
+
+  private:
+    template <Internal::Operator Op, typename RhsT>
+    ResultBuilder& captureExpression(RhsT const& rhs)
+    {
+        return m_rb
+            .setResultType(Internal::compare<Op>(m_lhs, rhs))
+            .setLhs(Catch::toString(m_lhs))
+            .setRhs(Catch::toString(rhs))
+            .setOp(Internal::OperatorTraits<Op>::getName());
+    }
+
+  private:
+    ResultBuilder& m_rb;
+    T m_lhs;
+};
+
+} // end namespace Catch
+
+namespace Catch {
+
+template <typename T>
+inline ExpressionLhs<T const&> ResultBuilder::operator<=(T const& operand)
+{
+    return ExpressionLhs<T const&>(*this, operand);
+}
+
+inline ExpressionLhs<bool> ResultBuilder::operator<=(bool value)
+{
+    return ExpressionLhs<bool>(*this, value);
+}
+
+} // namespace Catch
+
+// #included from: catch_message.h
+#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+struct MessageInfo
+{
+    MessageInfo(std::string const& _macroName,
+                SourceLineInfo const& _lineInfo,
+                ResultWas::OfType _type);
+
+    std::string macroName;
+    SourceLineInfo lineInfo;
+    ResultWas::OfType type;
+    std::string message;
+    unsigned int sequence;
+
+    bool operator==(MessageInfo const& other) const
+    {
+        return sequence == other.sequence;
+    }
+    bool operator<(MessageInfo const& other) const
+    {
+        return sequence < other.sequence;
+    }
+
+  private:
+    static unsigned int globalCount;
+};
+
+struct MessageBuilder
+{
+    MessageBuilder(std::string const& macroName,
+                   SourceLineInfo const& lineInfo,
+                   ResultWas::OfType type)
+        : m_info(macroName, lineInfo, type)
+    {
+    }
+
+    template <typename T>
+    MessageBuilder& operator<<(T const& value)
+    {
+        m_stream << value;
+        return *this;
+    }
+
+    MessageInfo m_info;
+    std::ostringstream m_stream;
+};
+
+class ScopedMessage
+{
+  public:
+    ScopedMessage(MessageBuilder const& builder);
+    ScopedMessage(ScopedMessage const& other);
+    ~ScopedMessage();
+
+    MessageInfo m_info;
+};
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_capture.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+class TestCase;
+class AssertionResult;
+struct AssertionInfo;
+struct SectionInfo;
+struct SectionEndInfo;
+struct MessageInfo;
+class ScopedMessageBuilder;
+struct Counts;
+
+struct IResultCapture
+{
+
+    virtual ~IResultCapture();
+
+    virtual void assertionEnded(AssertionResult const& result) = 0;
+    virtual bool sectionStarted(SectionInfo const& sectionInfo,
+                                Counts& assertions) = 0;
+    virtual void sectionEnded(SectionEndInfo const& endInfo) = 0;
+    virtual void sectionEndedEarly(SectionEndInfo const& endInfo) = 0;
+    virtual void pushScopedMessage(MessageInfo const& message) = 0;
+    virtual void popScopedMessage(MessageInfo const& message) = 0;
+
+    virtual std::string getCurrentTestName() const = 0;
+    virtual const AssertionResult* getLastResult() const = 0;
+
+    virtual void handleFatalErrorCondition(std::string const& message) = 0;
+};
+
+IResultCapture& getResultCapture();
+}
+
+// #included from: catch_debugger.h
+#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
+
+// #included from: catch_platform.h
+#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
+
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+#define CATCH_PLATFORM_MAC
+#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+#define CATCH_PLATFORM_IPHONE
+#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
+#define CATCH_PLATFORM_WINDOWS
+#endif
+
+#include <string>
+
+namespace Catch {
+
+bool isDebuggerActive();
+void writeToDebugConsole(std::string const& text);
+}
+
+#ifdef CATCH_PLATFORM_MAC
+
+// The following code snippet based on:
+// http://cocoawithlove.com/2008/03/break-into-debugger.html
+#ifdef DEBUG
+#if defined(__ppc64__) || defined(__ppc__)
+#define CATCH_BREAK_INTO_DEBUGGER()                                  \
+    if (Catch::isDebuggerActive())                                   \
+    {                                                                \
+        __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
+                :                                                    \
+                :                                                    \
+                : "memory", "r0", "r3", "r4");                       \
+    }
+#else
+#define CATCH_BREAK_INTO_DEBUGGER() \
+    if (Catch::isDebuggerActive())  \
+    {                               \
+        __asm__("int $3\n"          \
+                :                   \
+                :);                 \
+    }
+#endif
+#endif
+
+#elif defined(_MSC_VER)
+#define CATCH_BREAK_INTO_DEBUGGER() \
+    if (Catch::isDebuggerActive())  \
+    {                               \
+        __debugbreak();             \
+    }
+#elif defined(__MINGW32__)
+extern "C" __declspec(dllimport) void __stdcall DebugBreak();
+#define CATCH_BREAK_INTO_DEBUGGER() \
+    if (Catch::isDebuggerActive())  \
+    {                               \
+        DebugBreak();               \
+    }
+#endif
+
+#ifndef CATCH_BREAK_INTO_DEBUGGER
+#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
+#endif
+
+// #included from: catch_interfaces_runner.h
+#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
+
+namespace Catch {
+class TestCase;
+
+struct IRunner
+{
+    virtual ~IRunner();
+    virtual bool aborting() const = 0;
+};
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// In the event of a failure works out if the debugger needs to be invoked
+// and/or an exception thrown and takes appropriate action.
+// This needs to be done as a macro so the debugger will stop in the user
+// source code rather than in Catch library code
+#define INTERNAL_CATCH_REACT(resultBuilder)                            \
+    if (resultBuilder.shouldDebugBreak()) CATCH_BREAK_INTO_DEBUGGER(); \
+    resultBuilder.react();
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST(expr, resultDisposition, macroName)                                           \
+    do                                                                                                    \
+    {                                                                                                     \
+        Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition); \
+        try                                                                                               \
+        {                                                                                                 \
+            (__catchResult <= expr).endExpression();                                                      \
+        }                                                                                                 \
+        catch (...)                                                                                       \
+        {                                                                                                 \
+            __catchResult.useActiveException(Catch::ResultDisposition::Normal);                           \
+        }                                                                                                 \
+        INTERNAL_CATCH_REACT(__catchResult)                                                               \
+    } while (Catch::isTrue(false && (expr))) // expr here is never evaluated at runtime but it forces the compiler to give it a look
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_IF(expr, resultDisposition, macroName) \
+    INTERNAL_CATCH_TEST(expr, resultDisposition, macroName);  \
+    if (Catch::getResultCapture().getLastResult()->succeeded())
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_ELSE(expr, resultDisposition, macroName) \
+    INTERNAL_CATCH_TEST(expr, resultDisposition, macroName);    \
+    if (!Catch::getResultCapture().getLastResult()->succeeded())
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_NO_THROW(expr, resultDisposition, macroName)                                       \
+    do                                                                                                    \
+    {                                                                                                     \
+        Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition); \
+        try                                                                                               \
+        {                                                                                                 \
+            expr;                                                                                         \
+            __catchResult.captureResult(Catch::ResultWas::Ok);                                            \
+        }                                                                                                 \
+        catch (...)                                                                                       \
+        {                                                                                                 \
+            __catchResult.useActiveException(resultDisposition);                                          \
+        }                                                                                                 \
+        INTERNAL_CATCH_REACT(__catchResult)                                                               \
+    } while (Catch::alwaysFalse())
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS(expr, resultDisposition, matcher, macroName)                                          \
+    do                                                                                                              \
+    {                                                                                                               \
+        Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher); \
+        if (__catchResult.allowThrows())                                                                            \
+            try                                                                                                     \
+            {                                                                                                       \
+                expr;                                                                                               \
+                __catchResult.captureResult(Catch::ResultWas::DidntThrowException);                                 \
+            }                                                                                                       \
+            catch (...)                                                                                             \
+            {                                                                                                       \
+                __catchResult.captureExpectedException(matcher);                                                    \
+            }                                                                                                       \
+        else                                                                                                        \
+            __catchResult.captureResult(Catch::ResultWas::Ok);                                                      \
+        INTERNAL_CATCH_REACT(__catchResult)                                                                         \
+    } while (Catch::alwaysFalse())
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS_AS(expr, exceptionType, resultDisposition, macroName)                       \
+    do                                                                                                    \
+    {                                                                                                     \
+        Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition); \
+        if (__catchResult.allowThrows())                                                                  \
+            try                                                                                           \
+            {                                                                                             \
+                expr;                                                                                     \
+                __catchResult.captureResult(Catch::ResultWas::DidntThrowException);                       \
+            }                                                                                             \
+            catch (exceptionType)                                                                         \
+            {                                                                                             \
+                __catchResult.captureResult(Catch::ResultWas::Ok);                                        \
+            }                                                                                             \
+            catch (...)                                                                                   \
+            {                                                                                             \
+                __catchResult.useActiveException(resultDisposition);                                      \
+            }                                                                                             \
+        else                                                                                              \
+            __catchResult.captureResult(Catch::ResultWas::Ok);                                            \
+        INTERNAL_CATCH_REACT(__catchResult)                                                               \
+    } while (Catch::alwaysFalse())
+
+///////////////////////////////////////////////////////////////////////////////
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define INTERNAL_CATCH_MSG(messageType, resultDisposition, macroName, ...)                             \
+    do                                                                                                 \
+    {                                                                                                  \
+        Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition); \
+        __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop();                                       \
+        __catchResult.captureResult(messageType);                                                      \
+        INTERNAL_CATCH_REACT(__catchResult)                                                            \
+    } while (Catch::alwaysFalse())
+#else
+#define INTERNAL_CATCH_MSG(messageType, resultDisposition, macroName, log)                             \
+    do                                                                                                 \
+    {                                                                                                  \
+        Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition); \
+        __catchResult << log + ::Catch::StreamEndStop();                                               \
+        __catchResult.captureResult(messageType);                                                      \
+        INTERNAL_CATCH_REACT(__catchResult)                                                            \
+    } while (Catch::alwaysFalse())
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_INFO(log, macroName) \
+    Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME(scopedMessage) = Catch::MessageBuilder(macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info) << log;
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CHECK_THAT(arg, matcher, resultDisposition, macroName)                                                \
+    do                                                                                                                 \
+    {                                                                                                                  \
+        Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition); \
+        try                                                                                                            \
+        {                                                                                                              \
+            std::string matcherAsString = (matcher).toString();                                                        \
+            __catchResult                                                                                              \
+                .setLhs(Catch::toString(arg))                                                                          \
+                .setRhs(matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString)              \
+                .setOp("matches")                                                                                      \
+                .setResultType((matcher).match(arg));                                                                  \
+            __catchResult.captureExpression();                                                                         \
+        }                                                                                                              \
+        catch (...)                                                                                                    \
+        {                                                                                                              \
+            __catchResult.useActiveException(resultDisposition | Catch::ResultDisposition::ContinueOnFailure);         \
+        }                                                                                                              \
+        INTERNAL_CATCH_REACT(__catchResult)                                                                            \
+    } while (Catch::alwaysFalse())
+
+// #included from: internal/catch_section.h
+#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
+
+// #included from: catch_section_info.h
+#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
+
+// #included from: catch_totals.hpp
+#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
+
+#include <cstddef>
+
+namespace Catch {
+
+struct Counts
+{
+    Counts() : passed(0), failed(0), failedButOk(0) {}
+
+    Counts operator-(Counts const& other) const
+    {
+        Counts diff;
+        diff.passed = passed - other.passed;
+        diff.failed = failed - other.failed;
+        diff.failedButOk = failedButOk - other.failedButOk;
+        return diff;
+    }
+    Counts& operator+=(Counts const& other)
+    {
+        passed += other.passed;
+        failed += other.failed;
+        failedButOk += other.failedButOk;
+        return *this;
+    }
+
+    std::size_t total() const
+    {
+        return passed + failed + failedButOk;
+    }
+    bool allPassed() const
+    {
+        return failed == 0 && failedButOk == 0;
+    }
+    bool allOk() const
+    {
+        return failed == 0;
+    }
+
+    std::size_t passed;
+    std::size_t failed;
+    std::size_t failedButOk;
+};
+
+struct Totals
+{
+
+    Totals operator-(Totals const& other) const
+    {
+        Totals diff;
+        diff.assertions = assertions - other.assertions;
+        diff.testCases = testCases - other.testCases;
+        return diff;
+    }
+
+    Totals delta(Totals const& prevTotals) const
+    {
+        Totals diff = *this - prevTotals;
+        if (diff.assertions.failed > 0)
+            ++diff.testCases.failed;
+        else if (diff.assertions.failedButOk > 0)
+            ++diff.testCases.failedButOk;
+        else
+            ++diff.testCases.passed;
+        return diff;
+    }
+
+    Totals& operator+=(Totals const& other)
+    {
+        assertions += other.assertions;
+        testCases += other.testCases;
+        return *this;
+    }
+
+    Counts assertions;
+    Counts testCases;
+};
+}
+
+namespace Catch {
+
+struct SectionInfo
+{
+    SectionInfo(SourceLineInfo const& _lineInfo,
+                std::string const& _name,
+                std::string const& _description = std::string());
+
+    std::string name;
+    std::string description;
+    SourceLineInfo lineInfo;
+};
+
+struct SectionEndInfo
+{
+    SectionEndInfo(SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds)
+        : sectionInfo(_sectionInfo), prevAssertions(_prevAssertions), durationInSeconds(_durationInSeconds)
+    {
+    }
+
+    SectionInfo sectionInfo;
+    Counts prevAssertions;
+    double durationInSeconds;
+};
+
+} // end namespace Catch
+
+// #included from: catch_timer.h
+#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
+
+#ifdef CATCH_PLATFORM_WINDOWS
+typedef unsigned long long uint64_t;
+#else
+#include <stdint.h>
+#endif
+
+namespace Catch {
+
+class Timer
+{
+  public:
+    Timer() : m_ticks(0) {}
+    void start();
+    unsigned int getElapsedMicroseconds() const;
+    unsigned int getElapsedMilliseconds() const;
+    double getElapsedSeconds() const;
+
+  private:
+    uint64_t m_ticks;
+};
+
+} // namespace Catch
+
+#include <string>
+
+namespace Catch {
+
+class Section : NonCopyable
+{
+  public:
+    Section(SectionInfo const& info);
+    ~Section();
+
+    // This indicates whether the section should be executed or not
+    operator bool() const;
+
+  private:
+    SectionInfo m_info;
+
+    std::string m_name;
+    Counts m_assertions;
+    bool m_sectionIncluded;
+    Timer m_timer;
+};
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define INTERNAL_CATCH_SECTION(...) \
+    if (Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME(catch_internal_Section) = Catch::SectionInfo(CATCH_INTERNAL_LINEINFO, __VA_ARGS__))
+#else
+#define INTERNAL_CATCH_SECTION(name, desc) \
+    if (Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME(catch_internal_Section) = Catch::SectionInfo(CATCH_INTERNAL_LINEINFO, name, desc))
+#endif
+
+// #included from: internal/catch_generators.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
+
+#include <iterator>
+#include <stdlib.h>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+template <typename T>
+struct IGenerator
+{
+    virtual ~IGenerator() {}
+    virtual T getValue(std::size_t index) const = 0;
+    virtual std::size_t size() const = 0;
+};
+
+template <typename T>
+class BetweenGenerator : public IGenerator<T>
+{
+  public:
+    BetweenGenerator(T from, T to) : m_from(from), m_to(to) {}
+
+    virtual T getValue(std::size_t index) const
+    {
+        return m_from + static_cast<int>(index);
+    }
+
+    virtual std::size_t size() const
+    {
+        return static_cast<std::size_t>(1 + m_to - m_from);
+    }
+
+  private:
+    T m_from;
+    T m_to;
+};
+
+template <typename T>
+class ValuesGenerator : public IGenerator<T>
+{
+  public:
+    ValuesGenerator() {}
+
+    void add(T value)
+    {
+        m_values.push_back(value);
+    }
+
+    virtual T getValue(std::size_t index) const
+    {
+        return m_values[index];
+    }
+
+    virtual std::size_t size() const
+    {
+        return m_values.size();
+    }
+
+  private:
+    std::vector<T> m_values;
+};
+
+template <typename T>
+class CompositeGenerator
+{
+  public:
+    CompositeGenerator() : m_totalSize(0) {}
+
+    // *** Move semantics, similar to auto_ptr ***
+    CompositeGenerator(CompositeGenerator& other)
+        : m_fileInfo(other.m_fileInfo),
+          m_totalSize(0)
+    {
+        move(other);
+    }
+
+    CompositeGenerator& setFileInfo(const char* fileInfo)
+    {
+        m_fileInfo = fileInfo;
+        return *this;
+    }
+
+    ~CompositeGenerator()
+    {
+        deleteAll(m_composed);
+    }
+
+    operator T() const
+    {
+        size_t overallIndex = getCurrentContext().getGeneratorIndex(m_fileInfo, m_totalSize);
+
+        typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
+        typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
+        for (size_t index = 0; it != itEnd; ++it)
+        {
+            const IGenerator<T>* generator = *it;
+            if (overallIndex >= index && overallIndex < index + generator->size())
+            {
+                return generator->getValue(overallIndex - index);
+            }
+            index += generator->size();
+        }
+        CATCH_INTERNAL_ERROR("Indexed past end of generated range");
+        return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
+    }
+
+    void add(const IGenerator<T>* generator)
+    {
+        m_totalSize += generator->size();
+        m_composed.push_back(generator);
+    }
+
+    CompositeGenerator& then(CompositeGenerator& other)
+    {
+        move(other);
+        return *this;
+    }
+
+    CompositeGenerator& then(T value)
+    {
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add(value);
+        add(valuesGen);
+        return *this;
+    }
+
+  private:
+    void move(CompositeGenerator& other)
+    {
+        std::copy(other.m_composed.begin(), other.m_composed.end(), std::back_inserter(m_composed));
+        m_totalSize += other.m_totalSize;
+        other.m_composed.clear();
+    }
+
+    std::vector<const IGenerator<T>*> m_composed;
+    std::string m_fileInfo;
+    size_t m_totalSize;
+};
+
+namespace Generators {
+template <typename T>
+CompositeGenerator<T> between(T from, T to)
+{
+    CompositeGenerator<T> generators;
+    generators.add(new BetweenGenerator<T>(from, to));
+    return generators;
+}
+
+template <typename T>
+CompositeGenerator<T> values(T val1, T val2)
+{
+    CompositeGenerator<T> generators;
+    ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+    valuesGen->add(val1);
+    valuesGen->add(val2);
+    generators.add(valuesGen);
+    return generators;
+}
+
+template <typename T>
+CompositeGenerator<T> values(T val1, T val2, T val3)
+{
+    CompositeGenerator<T> generators;
+    ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+    valuesGen->add(val1);
+    valuesGen->add(val2);
+    valuesGen->add(val3);
+    generators.add(valuesGen);
+    return generators;
+}
+
+template <typename T>
+CompositeGenerator<T> values(T val1, T val2, T val3, T val4)
+{
+    CompositeGenerator<T> generators;
+    ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+    valuesGen->add(val1);
+    valuesGen->add(val2);
+    valuesGen->add(val3);
+    valuesGen->add(val4);
+    generators.add(valuesGen);
+    return generators;
+}
+
+} // end namespace Generators
+
+using namespace Generators;
+
+} // end namespace Catch
+
+#define INTERNAL_CATCH_LINESTR2(line) #line
+#define INTERNAL_CATCH_LINESTR(line) INTERNAL_CATCH_LINESTR2(line)
+
+#define INTERNAL_CATCH_GENERATE(expr) expr.setFileInfo(__FILE__ "(" INTERNAL_CATCH_LINESTR(__LINE__) ")")
+
+// #included from: internal/catch_interfaces_exception.h
+#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
+
+#include <string>
+#include <vector>
+
+// #included from: catch_interfaces_registry_hub.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+class TestCase;
+struct ITestCaseRegistry;
+struct IExceptionTranslatorRegistry;
+struct IExceptionTranslator;
+struct IReporterRegistry;
+struct IReporterFactory;
+
+struct IRegistryHub
+{
+    virtual ~IRegistryHub();
+
+    virtual IReporterRegistry const& getReporterRegistry() const = 0;
+    virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
+    virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
+};
+
+struct IMutableRegistryHub
+{
+    virtual ~IMutableRegistryHub();
+    virtual void registerReporter(std::string const& name, Ptr<IReporterFactory> const& factory) = 0;
+    virtual void registerListener(Ptr<IReporterFactory> const& factory) = 0;
+    virtual void registerTest(TestCase const& testInfo) = 0;
+    virtual void registerTranslator(const IExceptionTranslator* translator) = 0;
+};
+
+IRegistryHub& getRegistryHub();
+IMutableRegistryHub& getMutableRegistryHub();
+void cleanUp();
+std::string translateActiveException();
+}
+
+namespace Catch {
+
+typedef std::string (*exceptionTranslateFunction)();
+
+struct IExceptionTranslator;
+typedef std::vector<const IExceptionTranslator*> ExceptionTranslators;
+
+struct IExceptionTranslator
+{
+    virtual ~IExceptionTranslator();
+    virtual std::string translate(ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd) const = 0;
+};
+
+struct IExceptionTranslatorRegistry
+{
+    virtual ~IExceptionTranslatorRegistry();
+
+    virtual std::string translateActiveException() const = 0;
+};
+
+class ExceptionTranslatorRegistrar
+{
+    template <typename T>
+    class ExceptionTranslator : public IExceptionTranslator
+    {
+      public:
+        ExceptionTranslator(std::string (*translateFunction)(T&))
+            : m_translateFunction(translateFunction)
+        {
+        }
+
+        virtual std::string translate(ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd) const CATCH_OVERRIDE
+        {
+            try
+            {
+                if (it == itEnd)
+                    throw;
+                else
+                    return (*it)->translate(it + 1, itEnd);
+            }
+            catch (T& ex)
+            {
+                return m_translateFunction(ex);
+            }
+        }
+
+      protected:
+        std::string (*m_translateFunction)(T&);
+    };
+
+  public:
+    template <typename T>
+    ExceptionTranslatorRegistrar(std::string (*translateFunction)(T&))
+    {
+        getMutableRegistryHub().registerTranslator(new ExceptionTranslator<T>(translateFunction));
+    }
+};
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION(signature)                                                                                                                   \
+    static std::string INTERNAL_CATCH_UNIQUE_NAME(catch_internal_ExceptionTranslator)(signature);                                                                       \
+    namespace {                                                                                                                                                         \
+    Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME(catch_internal_ExceptionRegistrar)(&INTERNAL_CATCH_UNIQUE_NAME(catch_internal_ExceptionTranslator)); \
+    }                                                                                                                                                                   \
+    static std::string INTERNAL_CATCH_UNIQUE_NAME(catch_internal_ExceptionTranslator)(signature)
+
+// #included from: internal/catch_approx.hpp
+#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
+
+#include <cmath>
+#include <limits>
+
+namespace Catch {
+namespace Detail {
+
+class Approx
+{
+  public:
+    explicit Approx(double value)
+        : m_epsilon(std::numeric_limits<float>::epsilon() * 100),
+          m_scale(1.0),
+          m_value(value)
+    {
+    }
+
+    Approx(Approx const& other)
+        : m_epsilon(other.m_epsilon),
+          m_scale(other.m_scale),
+          m_value(other.m_value)
+    {
+    }
+
+    static Approx custom()
+    {
+        return Approx(0);
+    }
+
+    Approx operator()(double value)
+    {
+        Approx approx(value);
+        approx.epsilon(m_epsilon);
+        approx.scale(m_scale);
+        return approx;
+    }
+
+    friend bool operator==(double lhs, Approx const& rhs)
+    {
+        // Thanks to Richard Harris for his help refining this formula
+        return fabs(lhs - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(fabs(lhs), fabs(rhs.m_value)));
+    }
+
+    friend bool operator==(Approx const& lhs, double rhs)
+    {
+        return operator==(rhs, lhs);
+    }
+
+    friend bool operator!=(double lhs, Approx const& rhs)
+    {
+        return !operator==(lhs, rhs);
+    }
+
+    friend bool operator!=(Approx const& lhs, double rhs)
+    {
+        return !operator==(rhs, lhs);
+    }
+
+    Approx& epsilon(double newEpsilon)
+    {
+        m_epsilon = newEpsilon;
+        return *this;
+    }
+
+    Approx& scale(double newScale)
+    {
+        m_scale = newScale;
+        return *this;
+    }
+
+    std::string toString() const
+    {
+        std::ostringstream oss;
+        oss << "Approx( " << Catch::toString(m_value) << " )";
+        return oss.str();
+    }
+
+  private:
+    double m_epsilon;
+    double m_scale;
+    double m_value;
+};
+}
+
+template <>
+inline std::string toString<Detail::Approx>(Detail::Approx const& value)
+{
+    return value.toString();
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_interfaces_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+// #included from: catch_tag_alias.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+struct TagAlias
+{
+    TagAlias(std::string _tag, SourceLineInfo _lineInfo) : tag(_tag), lineInfo(_lineInfo) {}
+
+    std::string tag;
+    SourceLineInfo lineInfo;
+};
+
+struct RegistrarForTagAliases
+{
+    RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo);
+};
+
+} // end namespace Catch
+
+#define CATCH_REGISTER_TAG_ALIAS(alias, spec)                                                                             \
+    namespace {                                                                                                           \
+    Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME(AutoRegisterTagAlias)(alias, spec, CATCH_INTERNAL_LINEINFO); \
+    }
+// #included from: catch_option.hpp
+#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED
+
+namespace Catch {
+
+// An optional type
+template <typename T>
+class Option
+{
+  public:
+    Option() : nullableValue(CATCH_NULL) {}
+    Option(T const& _value)
+        : nullableValue(new (storage) T(_value))
+    {
+    }
+    Option(Option const& _other)
+        : nullableValue(_other ? new (storage) T(*_other) : CATCH_NULL)
+    {
+    }
+
+    ~Option()
+    {
+        reset();
+    }
+
+    Option& operator=(Option const& _other)
+    {
+        if (&_other != this)
+        {
+            reset();
+            if (_other)
+                nullableValue = new (storage) T(*_other);
+        }
+        return *this;
+    }
+    Option& operator=(T const& _value)
+    {
+        reset();
+        nullableValue = new (storage) T(_value);
+        return *this;
+    }
+
+    void reset()
+    {
+        if (nullableValue)
+            nullableValue->~T();
+        nullableValue = CATCH_NULL;
+    }
+
+    T& operator*() { return *nullableValue; }
+    T const& operator*() const { return *nullableValue; }
+    T* operator->() { return nullableValue; }
+    const T* operator->() const { return nullableValue; }
+
+    T valueOr(T const& defaultValue) const
+    {
+        return nullableValue ? *nullableValue : defaultValue;
+    }
+
+    bool some() const { return nullableValue != CATCH_NULL; }
+    bool none() const { return nullableValue == CATCH_NULL; }
+
+    bool operator!() const { return nullableValue == CATCH_NULL; }
+    operator SafeBool::type() const
+    {
+        return SafeBool::makeSafe(some());
+    }
+
+  private:
+    T* nullableValue;
+    char storage[sizeof(T)];
+};
+
+} // end namespace Catch
+
+namespace Catch {
+
+struct ITagAliasRegistry
+{
+    virtual ~ITagAliasRegistry();
+    virtual Option<TagAlias> find(std::string const& alias) const = 0;
+    virtual std::string expandAliases(std::string const& unexpandedTestSpec) const = 0;
+
+    static ITagAliasRegistry const& get();
+};
+
+} // end namespace Catch
+
+// These files are included here so the single_include script doesn't put them
+// in the conditionally compiled sections
+// #included from: internal/catch_test_case_info.h
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
+
+#include <set>
+#include <string>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+struct ITestCase;
+
+struct TestCaseInfo
+{
+    enum SpecialProperties
+    {
+        None = 0,
+        IsHidden = 1 << 1,
+        ShouldFail = 1 << 2,
+        MayFail = 1 << 3,
+        Throws = 1 << 4
+    };
+
+    TestCaseInfo(std::string const& _name,
+                 std::string const& _className,
+                 std::string const& _description,
+                 std::set<std::string> const& _tags,
+                 SourceLineInfo const& _lineInfo);
+
+    TestCaseInfo(TestCaseInfo const& other);
+
+    friend void setTags(TestCaseInfo& testCaseInfo, std::set<std::string> const& tags);
+
+    bool isHidden() const;
+    bool throws() const;
+    bool okToFail() const;
+    bool expectedToFail() const;
+
+    std::string name;
+    std::string className;
+    std::string description;
+    std::set<std::string> tags;
+    std::set<std::string> lcaseTags;
+    std::string tagsAsString;
+    SourceLineInfo lineInfo;
+    SpecialProperties properties;
+};
+
+class TestCase : public TestCaseInfo
+{
+  public:
+    TestCase(ITestCase* testCase, TestCaseInfo const& info);
+    TestCase(TestCase const& other);
+
+    TestCase withName(std::string const& _newName) const;
+
+    void invoke() const;
+
+    TestCaseInfo const& getTestCaseInfo() const;
+
+    void swap(TestCase& other);
+    bool operator==(TestCase const& other) const;
+    bool operator<(TestCase const& other) const;
+    TestCase& operator=(TestCase const& other);
+
+  private:
+    Ptr<ITestCase> test;
+};
+
+TestCase makeTestCase(ITestCase* testCase,
+                      std::string const& className,
+                      std::string const& name,
+                      std::string const& description,
+                      SourceLineInfo const& lineInfo);
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#ifdef __OBJC__
+// #included from: internal/catch_objc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
+
+#import <objc/runtime.h>
+
+#include <string>
+
+// NB. Any general catch headers included here must be included
+// in catch.hpp first to make sure they are included by the single
+// header for non obj-usage
+
+///////////////////////////////////////////////////////////////////////////////
+// This protocol is really only here for (self) documenting purposes, since
+// all its methods are optional.
+ at protocol OcFixture
+
+ at optional
+
+- (void)setUp;
+- (void)tearDown;
+
+ at end
+
+namespace Catch {
+
+class OcMethod : public SharedImpl<ITestCase>
+{
+
+  public:
+    OcMethod(Class cls, SEL sel) : m_cls(cls), m_sel(sel) {}
+
+    virtual void invoke() const
+    {
+        id obj = [[m_cls alloc] init];
+
+        performOptionalSelector(obj, @selector(setUp));
+        performOptionalSelector(obj, m_sel);
+        performOptionalSelector(obj, @selector(tearDown));
+
+        arcSafeRelease(obj);
+    }
+
+  private:
+    virtual ~OcMethod() {}
+
+    Class m_cls;
+    SEL m_sel;
+};
+
+namespace Detail {
+
+inline std::string getAnnotation(Class cls,
+                                 std::string const& annotationName,
+                                 std::string const& testCaseName)
+{
+    NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
+    SEL sel = NSSelectorFromString(selStr);
+    arcSafeRelease(selStr);
+    id value = performOptionalSelector(cls, sel);
+    if (value)
+        return [(NSString*)value UTF8String];
+    return "";
+}
+}
+
+inline size_t registerTestMethods()
+{
+    size_t noTestMethods = 0;
+    int noClasses = objc_getClassList(CATCH_NULL, 0);
+
+    Class* classes = (CATCH_UNSAFE_UNRETAINED Class*)malloc(sizeof(Class) * noClasses);
+    objc_getClassList(classes, noClasses);
+
+    for (int c = 0; c < noClasses; c++)
+    {
+        Class cls = classes[c];
+        {
+            u_int count;
+            Method* methods = class_copyMethodList(cls, &count);
+            for (u_int m = 0; m < count; m++)
+            {
+                SEL selector = method_getName(methods[m]);
+                std::string methodName = sel_getName(selector);
+                if (startsWith(methodName, "Catch_TestCase_"))
+                {
+                    std::string testCaseName = methodName.substr(15);
+                    std::string name = Detail::getAnnotation(cls, "Name", testCaseName);
+                    std::string desc = Detail::getAnnotation(cls, "Description", testCaseName);
+                    const char* className = class_getName(cls);
+
+                    getMutableRegistryHub().registerTest(makeTestCase(new OcMethod(cls, selector), className, name.c_str(), desc.c_str(), SourceLineInfo()));
+                    noTestMethods++;
+                }
+            }
+            free(methods);
+        }
+    }
+    return noTestMethods;
+}
+
+namespace Matchers {
+namespace Impl {
+namespace NSStringMatchers {
+
+template <typename MatcherT>
+struct StringHolder : MatcherImpl<MatcherT, NSString*>
+{
+    StringHolder(NSString* substr) : m_substr([substr copy]) {}
+    StringHolder(StringHolder const& other) : m_substr([other.m_substr copy]) {}
+    StringHolder()
+    {
+        arcSafeRelease(m_substr);
+    }
+
+    NSString* m_substr;
+};
+
+struct Equals : StringHolder<Equals>
+{
+    Equals(NSString* substr) : StringHolder(substr) {}
+
+    virtual bool match(ExpressionType const& str) const
+    {
+        return (str != nil || m_substr == nil) &&
+               [str isEqualToString:m_substr];
+    }
+
+    virtual std::string toString() const
+    {
+        return "equals string: " + Catch::toString(m_substr);
+    }
+};
+
+struct Contains : StringHolder<Contains>
+{
+    Contains(NSString* substr) : StringHolder(substr) {}
+
+    virtual bool match(ExpressionType const& str) const
+    {
+        return (str != nil || m_substr == nil) &&
+               [str rangeOfString:m_substr].location != NSNotFound;
+    }
+
+    virtual std::string toString() const
+    {
+        return "contains string: " + Catch::toString(m_substr);
+    }
+};
+
+struct StartsWith : StringHolder<StartsWith>
+{
+    StartsWith(NSString* substr) : StringHolder(substr) {}
+
+    virtual bool match(ExpressionType const& str) const
+    {
+        return (str != nil || m_substr == nil) &&
+               [str rangeOfString:m_substr].location == 0;
+    }
+
+    virtual std::string toString() const
+    {
+        return "starts with: " + Catch::toString(m_substr);
+    }
+};
+struct EndsWith : StringHolder<EndsWith>
+{
+    EndsWith(NSString* substr) : StringHolder(substr) {}
+
+    virtual bool match(ExpressionType const& str) const
+    {
+        return (str != nil || m_substr == nil) &&
+               [str rangeOfString:m_substr].location == [str length] - [m_substr length];
+    }
+
+    virtual std::string toString() const
+    {
+        return "ends with: " + Catch::toString(m_substr);
+    }
+};
+
+} // namespace NSStringMatchers
+} // namespace Impl
+
+inline Impl::NSStringMatchers::Equals
+Equals(NSString* substr) { return Impl::NSStringMatchers::Equals(substr); }
+
+inline Impl::NSStringMatchers::Contains
+Contains(NSString* substr) { return Impl::NSStringMatchers::Contains(substr); }
+
+inline Impl::NSStringMatchers::StartsWith
+StartsWith(NSString* substr) { return Impl::NSStringMatchers::StartsWith(substr); }
+
+inline Impl::NSStringMatchers::EndsWith
+EndsWith(NSString* substr) { return Impl::NSStringMatchers::EndsWith(substr); }
+
+} // namespace Matchers
+
+using namespace Matchers;
+
+} // namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define OC_TEST_CASE(name, desc)                                   \
+    +(NSString*)INTERNAL_CATCH_UNIQUE_NAME(Catch_Name_test)        \
+    {                                                              \
+        return @name;                                              \
+    }                                                              \
+    +(NSString*)INTERNAL_CATCH_UNIQUE_NAME(Catch_Description_test) \
+    {                                                              \
+        return @desc;                                              \
+    }                                                              \
+    -(void)INTERNAL_CATCH_UNIQUE_NAME(Catch_TestCase_test)
+
+#endif
+
+#ifdef CATCH_IMPL
+// #included from: internal/catch_impl.hpp
+#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
+
+// Collect all the implementation files together here
+// These are the equivalent of what would usually be cpp files
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
+// #included from: ../catch_session.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
+
+// #included from: internal/catch_commandline.hpp
+#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
+
+// #included from: catch_config.hpp
+#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
+
+// #included from: catch_test_spec_parser.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// #included from: catch_test_spec.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// #included from: catch_wildcard_pattern.hpp
+#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED
+
+namespace Catch {
+class WildcardPattern
+{
+    enum WildcardPosition
+    {
+        NoWildcard = 0,
+        WildcardAtStart = 1,
+        WildcardAtEnd = 2,
+        WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
+    };
+
+  public:
+    WildcardPattern(std::string const& pattern, CaseSensitive::Choice caseSensitivity)
+        : m_caseSensitivity(caseSensitivity),
+          m_wildcard(NoWildcard),
+          m_pattern(adjustCase(pattern))
+    {
+        if (startsWith(m_pattern, "*"))
+        {
+            m_pattern = m_pattern.substr(1);
+            m_wildcard = WildcardAtStart;
+        }
+        if (endsWith(m_pattern, "*"))
+        {
+            m_pattern = m_pattern.substr(0, m_pattern.size() - 1);
+            m_wildcard = static_cast<WildcardPosition>(m_wildcard | WildcardAtEnd);
+        }
+    }
+    virtual ~WildcardPattern();
+    virtual bool matches(std::string const& str) const
+    {
+        switch (m_wildcard)
+        {
+        case NoWildcard:
+            return m_pattern == adjustCase(str);
+        case WildcardAtStart:
+            return endsWith(adjustCase(str), m_pattern);
+        case WildcardAtEnd:
+            return startsWith(adjustCase(str), m_pattern);
+        case WildcardAtBothEnds:
+            return contains(adjustCase(str), m_pattern);
+        }
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+        throw std::logic_error("Unknown enum");
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+    }
+
+  private:
+    std::string adjustCase(std::string const& str) const
+    {
+        return m_caseSensitivity == CaseSensitive::No ? toLower(str) : str;
+    }
+    CaseSensitive::Choice m_caseSensitivity;
+    WildcardPosition m_wildcard;
+    std::string m_pattern;
+};
+}
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+class TestSpec
+{
+    struct Pattern : SharedImpl<>
+    {
+        virtual ~Pattern();
+        virtual bool matches(TestCaseInfo const& testCase) const = 0;
+    };
+    class NamePattern : public Pattern
+    {
+      public:
+        NamePattern(std::string const& name)
+            : m_wildcardPattern(toLower(name), CaseSensitive::No)
+        {
+        }
+        virtual ~NamePattern();
+        virtual bool matches(TestCaseInfo const& testCase) const
+        {
+            return m_wildcardPattern.matches(toLower(testCase.name));
+        }
+
+      private:
+        WildcardPattern m_wildcardPattern;
+    };
+
+    class TagPattern : public Pattern
+    {
+      public:
+        TagPattern(std::string const& tag) : m_tag(toLower(tag)) {}
+        virtual ~TagPattern();
+        virtual bool matches(TestCaseInfo const& testCase) const
+        {
+            return testCase.lcaseTags.find(m_tag) != testCase.lcaseTags.end();
+        }
+
+      private:
+        std::string m_tag;
+    };
+
+    class ExcludedPattern : public Pattern
+    {
+      public:
+        ExcludedPattern(Ptr<Pattern> const& underlyingPattern) : m_underlyingPattern(underlyingPattern) {}
+        virtual ~ExcludedPattern();
+        virtual bool matches(TestCaseInfo const& testCase) const { return !m_underlyingPattern->matches(testCase); }
+      private:
+        Ptr<Pattern> m_underlyingPattern;
+    };
+
+    struct Filter
+    {
+        std::vector<Ptr<Pattern>> m_patterns;
+
+        bool matches(TestCaseInfo const& testCase) const
+        {
+            // All patterns in a filter must match for the filter to be a match
+            for (std::vector<Ptr<Pattern>>::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it)
+                if (!(*it)->matches(testCase))
+                    return false;
+            return true;
+        }
+    };
+
+  public:
+    bool hasFilters() const
+    {
+        return !m_filters.empty();
+    }
+    bool matches(TestCaseInfo const& testCase) const
+    {
+        // A TestSpec matches if any filter matches
+        for (std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it)
+            if (it->matches(testCase))
+                return true;
+        return false;
+    }
+
+  private:
+    std::vector<Filter> m_filters;
+
+    friend class TestSpecParser;
+};
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace Catch {
+
+class TestSpecParser
+{
+    enum Mode
+    {
+        None,
+        Name,
+        QuotedName,
+        Tag
+    };
+    Mode m_mode;
+    bool m_exclusion;
+    std::size_t m_start, m_pos;
+    std::string m_arg;
+    TestSpec::Filter m_currentFilter;
+    TestSpec m_testSpec;
+    ITagAliasRegistry const* m_tagAliases;
+
+  public:
+    TestSpecParser(ITagAliasRegistry const& tagAliases) : m_tagAliases(&tagAliases) {}
+
+    TestSpecParser& parse(std::string const& arg)
+    {
+        m_mode = None;
+        m_exclusion = false;
+        m_start = std::string::npos;
+        m_arg = m_tagAliases->expandAliases(arg);
+        for (m_pos = 0; m_pos < m_arg.size(); ++m_pos)
+            visitChar(m_arg[m_pos]);
+        if (m_mode == Name)
+            addPattern<TestSpec::NamePattern>();
+        return *this;
+    }
+    TestSpec testSpec()
+    {
+        addFilter();
+        return m_testSpec;
+    }
+
+  private:
+    void visitChar(char c)
+    {
+        if (m_mode == None)
+        {
+            switch (c)
+            {
+            case ' ':
+                return;
+            case '~':
+                m_exclusion = true;
+                return;
+            case '[':
+                return startNewMode(Tag, ++m_pos);
+            case '"':
+                return startNewMode(QuotedName, ++m_pos);
+            default:
+                startNewMode(Name, m_pos);
+                break;
+            }
+        }
+        if (m_mode == Name)
+        {
+            if (c == ',')
+            {
+                addPattern<TestSpec::NamePattern>();
+                addFilter();
+            }
+            else if (c == '[')
+            {
+                if (subString() == "exclude:")
+                    m_exclusion = true;
+                else
+                    addPattern<TestSpec::NamePattern>();
+                startNewMode(Tag, ++m_pos);
+            }
+        }
+        else if (m_mode == QuotedName && c == '"')
+            addPattern<TestSpec::NamePattern>();
+        else if (m_mode == Tag && c == ']')
+            addPattern<TestSpec::TagPattern>();
+    }
+    void startNewMode(Mode mode, std::size_t start)
+    {
+        m_mode = mode;
+        m_start = start;
+    }
+    std::string subString() const { return m_arg.substr(m_start, m_pos - m_start); }
+    template <typename T>
+    void addPattern()
+    {
+        std::string token = subString();
+        if (startsWith(token, "exclude:"))
+        {
+            m_exclusion = true;
+            token = token.substr(8);
+        }
+        if (!token.empty())
+        {
+            Ptr<TestSpec::Pattern> pattern = new T(token);
+            if (m_exclusion)
+                pattern = new TestSpec::ExcludedPattern(pattern);
+            m_currentFilter.m_patterns.push_back(pattern);
+        }
+        m_exclusion = false;
+        m_mode = None;
+    }
+    void addFilter()
+    {
+        if (!m_currentFilter.m_patterns.empty())
+        {
+            m_testSpec.m_filters.push_back(m_currentFilter);
+            m_currentFilter = TestSpec::Filter();
+        }
+    }
+};
+inline TestSpec parseTestSpec(std::string const& arg)
+{
+    return TestSpecParser(ITagAliasRegistry::get()).parse(arg).testSpec();
+}
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// #included from: catch_interfaces_config.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+struct Verbosity
+{
+    enum Level
+    {
+        NoOutput = 0,
+        Quiet,
+        Normal
+    };
+};
+
+struct WarnAbout
+{
+    enum What
+    {
+        Nothing = 0x00,
+        NoAssertions = 0x01
+    };
+};
+
+struct ShowDurations
+{
+    enum OrNot
+    {
+        DefaultForReporter,
+        Always,
+        Never
+    };
+};
+struct RunTests
+{
+    enum InWhatOrder
+    {
+        InDeclarationOrder,
+        InLexicographicalOrder,
+        InRandomOrder
+    };
+};
+
+class TestSpec;
+
+struct IConfig : IShared
+{
+
+    virtual ~IConfig();
+
+    virtual bool allowThrows() const = 0;
+    virtual std::ostream& stream() const = 0;
+    virtual std::string name() const = 0;
+    virtual bool includeSuccessfulResults() const = 0;
+    virtual bool shouldDebugBreak() const = 0;
+    virtual bool warnAboutMissingAssertions() const = 0;
+    virtual int abortAfter() const = 0;
+    virtual bool showInvisibles() const = 0;
+    virtual ShowDurations::OrNot showDurations() const = 0;
+    virtual TestSpec const& testSpec() const = 0;
+    virtual RunTests::InWhatOrder runOrder() const = 0;
+    virtual unsigned int rngSeed() const = 0;
+    virtual bool forceColour() const = 0;
+};
+}
+
+// #included from: catch_stream.h
+#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
+
+// #included from: catch_streambuf.h
+#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
+
+#include <streambuf>
+
+namespace Catch {
+
+class StreamBufBase : public std::streambuf
+{
+  public:
+    virtual ~StreamBufBase() CATCH_NOEXCEPT;
+};
+}
+
+#include <fstream>
+#include <ostream>
+#include <streambuf>
+
+namespace Catch {
+
+std::ostream& cout();
+std::ostream& cerr();
+
+struct IStream
+{
+    virtual ~IStream() CATCH_NOEXCEPT;
+    virtual std::ostream& stream() const = 0;
+};
+
+class FileStream : public IStream
+{
+    mutable std::ofstream m_ofs;
+
+  public:
+    FileStream(std::string const& filename);
+    virtual ~FileStream() CATCH_NOEXCEPT;
+
+  public: // IStream
+    virtual std::ostream& stream() const CATCH_OVERRIDE;
+};
+
+class CoutStream : public IStream
+{
+    mutable std::ostream m_os;
+
+  public:
+    CoutStream();
+    virtual ~CoutStream() CATCH_NOEXCEPT;
+
+  public: // IStream
+    virtual std::ostream& stream() const CATCH_OVERRIDE;
+};
+
+class DebugOutStream : public IStream
+{
+    std::auto_ptr<StreamBufBase> m_streamBuf;
+    mutable std::ostream m_os;
+
+  public:
+    DebugOutStream();
+    virtual ~DebugOutStream() CATCH_NOEXCEPT;
+
+  public: // IStream
+    virtual std::ostream& stream() const CATCH_OVERRIDE;
+};
+}
+
+#include <ctime>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <vector>
+
+#ifndef CATCH_CONFIG_CONSOLE_WIDTH
+#define CATCH_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+namespace Catch {
+
+struct ConfigData
+{
+
+    ConfigData()
+        : listTests(false),
+          listTags(false),
+          listReporters(false),
+          listTestNamesOnly(false),
+          showSuccessfulTests(false),
+          shouldDebugBreak(false),
+          noThrow(false),
+          showHelp(false),
+          showInvisibles(false),
+          forceColour(false),
+          filenamesAsTags(false),
+          abortAfter(-1),
+          rngSeed(0),
+          verbosity(Verbosity::Normal),
+          warnings(WarnAbout::Nothing),
+          showDurations(ShowDurations::DefaultForReporter),
+          runOrder(RunTests::InDeclarationOrder)
+    {
+    }
+
+    bool listTests;
+    bool listTags;
+    bool listReporters;
+    bool listTestNamesOnly;
+
+    bool showSuccessfulTests;
+    bool shouldDebugBreak;
+    bool noThrow;
+    bool showHelp;
+    bool showInvisibles;
+    bool forceColour;
+    bool filenamesAsTags;
+
+    int abortAfter;
+    unsigned int rngSeed;
+
+    Verbosity::Level verbosity;
+    WarnAbout::What warnings;
+    ShowDurations::OrNot showDurations;
+    RunTests::InWhatOrder runOrder;
+
+    std::string outputFilename;
+    std::string name;
+    std::string processName;
+
+    std::vector<std::string> reporterNames;
+    std::vector<std::string> testsOrTags;
+};
+
+class Config : public SharedImpl<IConfig>
+{
+  private:
+    Config(Config const& other);
+    Config& operator=(Config const& other);
+    virtual void dummy();
+
+  public:
+    Config()
+    {
+    }
+
+    Config(ConfigData const& data)
+        : m_data(data),
+          m_stream(openStream())
+    {
+        if (!data.testsOrTags.empty())
+        {
+            TestSpecParser parser(ITagAliasRegistry::get());
+            for (std::size_t i = 0; i < data.testsOrTags.size(); ++i)
+                parser.parse(data.testsOrTags[i]);
+            m_testSpec = parser.testSpec();
+        }
+    }
+
+    virtual ~Config()
+    {
+    }
+
+    std::string const& getFilename() const
+    {
+        return m_data.outputFilename;
+    }
+
+    bool listTests() const { return m_data.listTests; }
+    bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
+    bool listTags() const { return m_data.listTags; }
+    bool listReporters() const { return m_data.listReporters; }
+
+    std::string getProcessName() const { return m_data.processName; }
+
+    bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
+
+    std::vector<std::string> getReporterNames() const { return m_data.reporterNames; }
+
+    int abortAfter() const { return m_data.abortAfter; }
+
+    TestSpec const& testSpec() const { return m_testSpec; }
+
+    bool showHelp() const { return m_data.showHelp; }
+    bool showInvisibles() const { return m_data.showInvisibles; }
+
+    // IConfig interface
+    virtual bool allowThrows() const { return !m_data.noThrow; }
+    virtual std::ostream& stream() const { return m_stream->stream(); }
+    virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
+    virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
+    virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
+    virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; }
+    virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; }
+    virtual unsigned int rngSeed() const { return m_data.rngSeed; }
+    virtual bool forceColour() const { return m_data.forceColour; }
+
+  private:
+    IStream const* openStream()
+    {
+        if (m_data.outputFilename.empty())
+            return new CoutStream();
+        else if (m_data.outputFilename[0] == '%')
+        {
+            if (m_data.outputFilename == "%debug")
+                return new DebugOutStream();
+            else
+                throw std::domain_error("Unrecognised stream: " + m_data.outputFilename);
+        }
+        else
+            return new FileStream(m_data.outputFilename);
+    }
+    ConfigData m_data;
+
+    std::auto_ptr<IStream const> m_stream;
+    TestSpec m_testSpec;
+};
+
+} // end namespace Catch
+
+// #included from: catch_clara.h
+#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED
+
+// Use Catch's value for console width (store Clara's off to the side, if present)
+#ifdef CLARA_CONFIG_CONSOLE_WIDTH
+#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
+#undef CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+// Declare Clara inside the Catch namespace
+#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
+// #included from: ../external/clara.h
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
+
+#ifndef STITCH_CLARA_OPEN_NAMESPACE
+#define TWOBLUECUBES_CLARA_H_INCLUDED
+#define STITCH_CLARA_OPEN_NAMESPACE
+#define STITCH_CLARA_CLOSE_NAMESPACE
+#else
+#define STITCH_CLARA_CLOSE_NAMESPACE }
+#endif
+
+#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
+
+// ----------- #included from tbc_text_format.h -----------
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE)
+#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+#define TBC_TEXT_FORMAT_H_INCLUDED
+#endif
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+// Use optional outer namespace
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+const unsigned int consoleWidth = 80;
+#endif
+
+struct TextAttributes
+{
+    TextAttributes()
+        : initialIndent(std::string::npos),
+          indent(0),
+          width(consoleWidth - 1),
+          tabChar('\t')
+    {
+    }
+
+    TextAttributes& setInitialIndent(std::size_t _value)
+    {
+        initialIndent = _value;
+        return *this;
+    }
+    TextAttributes& setIndent(std::size_t _value)
+    {
+        indent = _value;
+        return *this;
+    }
+    TextAttributes& setWidth(std::size_t _value)
+    {
+        width = _value;
+        return *this;
+    }
+    TextAttributes& setTabChar(char _value)
+    {
+        tabChar = _value;
+        return *this;
+    }
+
+    std::size_t initialIndent; // indent of first line, or npos
+    std::size_t indent;        // indent of subsequent lines, or all if initialIndent is npos
+    std::size_t width;         // maximum width of text, including indent. Longer text will wrap
+    char tabChar;              // If this char is seen the indent is changed to current pos
+};
+
+class Text
+{
+  public:
+    Text(std::string const& _str, TextAttributes const& _attr = TextAttributes())
+        : attr(_attr)
+    {
+        std::string wrappableChars = " [({.,/|\\-";
+        std::size_t indent = _attr.initialIndent != std::string::npos
+                                 ? _attr.initialIndent
+                                 : _attr.indent;
+        std::string remainder = _str;
+
+        while (!remainder.empty())
+        {
+            if (lines.size() >= 1000)
+            {
+                lines.push_back("... message truncated due to excessive size");
+                return;
+            }
+            std::size_t tabPos = std::string::npos;
+            std::size_t width = (std::min)(remainder.size(), _attr.width - indent);
+            std::size_t pos = remainder.find_first_of('\n');
+            if (pos <= width)
+            {
+                width = pos;
+            }
+            pos = remainder.find_last_of(_attr.tabChar, width);
+            if (pos != std::string::npos)
+            {
+                tabPos = pos;
+                if (remainder[width] == '\n')
+                    width--;
+                remainder = remainder.substr(0, tabPos) + remainder.substr(tabPos + 1);
+            }
+
+            if (width == remainder.size())
+            {
+                spliceLine(indent, remainder, width);
+            }
+            else if (remainder[width] == '\n')
+            {
+                spliceLine(indent, remainder, width);
+                if (width <= 1 || remainder.size() != 1)
+                    remainder = remainder.substr(1);
+                indent = _attr.indent;
+            }
+            else
+            {
+                pos = remainder.find_last_of(wrappableChars, width);
+                if (pos != std::string::npos && pos > 0)
+                {
+                    spliceLine(indent, remainder, pos);
+                    if (remainder[0] == ' ')
+                        remainder = remainder.substr(1);
+                }
+                else
+                {
+                    spliceLine(indent, remainder, width - 1);
+                    lines.back() += "-";
+                }
+                if (lines.size() == 1)
+                    indent = _attr.indent;
+                if (tabPos != std::string::npos)
+                    indent += tabPos;
+            }
+        }
+    }
+
+    void spliceLine(std::size_t _indent, std::string& _remainder, std::size_t _pos)
+    {
+        lines.push_back(std::string(_indent, ' ') + _remainder.substr(0, _pos));
+        _remainder = _remainder.substr(_pos);
+    }
+
+    typedef std::vector<std::string>::const_iterator const_iterator;
+
+    const_iterator begin() const { return lines.begin(); }
+    const_iterator end() const { return lines.end(); }
+    std::string const& last() const { return lines.back(); }
+    std::size_t size() const { return lines.size(); }
+    std::string const& operator[](std::size_t _index) const { return lines[_index]; }
+    std::string toString() const
+    {
+        std::ostringstream oss;
+        oss << *this;
+        return oss.str();
+    }
+
+    inline friend std::ostream& operator<<(std::ostream& _stream, Text const& _text)
+    {
+        for (Text::const_iterator it = _text.begin(), itEnd = _text.end();
+             it != itEnd; ++it)
+        {
+            if (it != _text.begin())
+                _stream << "\n";
+            _stream << *it;
+        }
+        return _stream;
+    }
+
+  private:
+    std::string str;
+    TextAttributes attr;
+    std::vector<std::string> lines;
+};
+
+} // end namespace Tbc
+
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TBC_TEXT_FORMAT_H_INCLUDED
+
+// ----------- end of #include from tbc_text_format.h -----------
+// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h
+
+#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <stdexcept>
+
+// Use optional outer namespace
+#ifdef STITCH_CLARA_OPEN_NAMESPACE
+STITCH_CLARA_OPEN_NAMESPACE
+#endif
+
+namespace Clara {
+
+struct UnpositionalTag
+{
+};
+
+extern UnpositionalTag _;
+
+#ifdef CLARA_CONFIG_MAIN
+UnpositionalTag _;
+#endif
+
+namespace Detail {
+
+#ifdef CLARA_CONSOLE_WIDTH
+const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
+#else
+const unsigned int consoleWidth = 80;
+#endif
+
+using namespace Tbc;
+
+inline bool startsWith(std::string const& str, std::string const& prefix)
+{
+    return str.size() >= prefix.size() && str.substr(0, prefix.size()) == prefix;
+}
+
+template <typename T>
+struct RemoveConstRef
+{
+    typedef T type;
+};
+template <typename T>
+struct RemoveConstRef<T&>
+{
+    typedef T type;
+};
+template <typename T>
+struct RemoveConstRef<T const&>
+{
+    typedef T type;
+};
+template <typename T>
+struct RemoveConstRef<T const>
+{
+    typedef T type;
+};
+
+template <typename T>
+struct IsBool
+{
+    static const bool value = false;
+};
+template <>
+struct IsBool<bool>
+{
+    static const bool value = true;
+};
+
+template <typename T>
+void convertInto(std::string const& _source, T& _dest)
+{
+    std::stringstream ss;
+    ss << _source;
+    ss >> _dest;
+    if (ss.fail())
+        throw std::runtime_error("Unable to convert " + _source + " to destination type");
+}
+inline void convertInto(std::string const& _source, std::string& _dest)
+{
+    _dest = _source;
+}
+inline void convertInto(std::string const& _source, bool& _dest)
+{
+    std::string sourceLC = _source;
+    std::transform(sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower);
+    if (sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on")
+        _dest = true;
+    else if (sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off")
+        _dest = false;
+    else
+        throw std::runtime_error("Expected a boolean value but did not recognise:\n  '" + _source + "'");
+}
+inline void convertInto(bool _source, bool& _dest)
+{
+    _dest = _source;
+}
+template <typename T>
+inline void convertInto(bool, T&)
+{
+    throw std::runtime_error("Invalid conversion");
+}
+
+template <typename ConfigT>
+struct IArgFunction
+{
+    virtual ~IArgFunction() {}
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+    IArgFunction() = default;
+    IArgFunction(IArgFunction const&) = default;
+#endif
+    virtual void set(ConfigT& config, std::string const& value) const = 0;
+    virtual void setFlag(ConfigT& config) const = 0;
+    virtual bool takesArg() const = 0;
+    virtual IArgFunction* clone() const = 0;
+};
+
+template <typename ConfigT>
+class BoundArgFunction
+{
+  public:
+    BoundArgFunction() : functionObj(CATCH_NULL) {}
+    BoundArgFunction(IArgFunction<ConfigT>* _functionObj) : functionObj(_functionObj) {}
+    BoundArgFunction(BoundArgFunction const& other) : functionObj(other.functionObj ? other.functionObj->clone() : CATCH_NULL) {}
+    BoundArgFunction& operator=(BoundArgFunction const& other)
+    {
+        IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CATCH_NULL;
+        delete functionObj;
+        functionObj = newFunctionObj;
+        return *this;
+    }
+    ~BoundArgFunction() { delete functionObj; }
+
+    void set(ConfigT& config, std::string const& value) const
+    {
+        functionObj->set(config, value);
+    }
+    void setFlag(ConfigT& config) const
+    {
+        functionObj->setFlag(config);
+    }
+    bool takesArg() const { return functionObj->takesArg(); }
+
+    bool isSet() const
+    {
+        return functionObj != CATCH_NULL;
+    }
+
+  private:
+    IArgFunction<ConfigT>* functionObj;
+};
+
+template <typename C>
+struct NullBinder : IArgFunction<C>
+{
+    virtual void set(C&, std::string const&) const {}
+    virtual void setFlag(C&) const {}
+    virtual bool takesArg() const { return true; }
+    virtual IArgFunction<C>* clone() const { return new NullBinder(*this); }
+};
+
+template <typename C, typename M>
+struct BoundDataMember : IArgFunction<C>
+{
+    BoundDataMember(M C::*_member) : member(_member) {}
+    virtual void set(C& p, std::string const& stringValue) const
+    {
+        convertInto(stringValue, p.*member);
+    }
+    virtual void setFlag(C& p) const
+    {
+        convertInto(true, p.*member);
+    }
+    virtual bool takesArg() const { return !IsBool<M>::value; }
+    virtual IArgFunction<C>* clone() const { return new BoundDataMember(*this); }
+    M C::*member;
+};
+template <typename C, typename M>
+struct BoundUnaryMethod : IArgFunction<C>
+{
+    BoundUnaryMethod(void (C::*_member)(M)) : member(_member) {}
+    virtual void set(C& p, std::string const& stringValue) const
+    {
+        typename RemoveConstRef<M>::type value;
+        convertInto(stringValue, value);
+        (p.*member)(value);
+    }
+    virtual void setFlag(C& p) const
+    {
+        typename RemoveConstRef<M>::type value;
+        convertInto(true, value);
+        (p.*member)(value);
+    }
+    virtual bool takesArg() const { return !IsBool<M>::value; }
+    virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod(*this); }
+    void (C::*member)(M);
+};
+template <typename C>
+struct BoundNullaryMethod : IArgFunction<C>
+{
+    BoundNullaryMethod(void (C::*_member)()) : member(_member) {}
+    virtual void set(C& p, std::string const& stringValue) const
+    {
+        bool value;
+        convertInto(stringValue, value);
+        if (value)
+            (p.*member)();
+    }
+    virtual void setFlag(C& p) const
+    {
+        (p.*member)();
+    }
+    virtual bool takesArg() const { return false; }
+    virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod(*this); }
+    void (C::*member)();
+};
+
+template <typename C>
+struct BoundUnaryFunction : IArgFunction<C>
+{
+    BoundUnaryFunction(void (*_function)(C&)) : function(_function) {}
+    virtual void set(C& obj, std::string const& stringValue) const
+    {
+        bool value;
+        convertInto(stringValue, value);
+        if (value)
+            function(obj);
+    }
+    virtual void setFlag(C& p) const
+    {
+        function(p);
+    }
+    virtual bool takesArg() const { return false; }
+    virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction(*this); }
+    void (*function)(C&);
+};
+
+template <typename C, typename T>
+struct BoundBinaryFunction : IArgFunction<C>
+{
+    BoundBinaryFunction(void (*_function)(C&, T)) : function(_function) {}
+    virtual void set(C& obj, std::string const& stringValue) const
+    {
+        typename RemoveConstRef<T>::type value;
+        convertInto(stringValue, value);
+        function(obj, value);
+    }
+    virtual void setFlag(C& obj) const
+    {
+        typename RemoveConstRef<T>::type value;
+        convertInto(true, value);
+        function(obj, value);
+    }
+    virtual bool takesArg() const { return !IsBool<T>::value; }
+    virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction(*this); }
+    void (*function)(C&, T);
+};
+
+} // namespace Detail
+
+struct Parser
+{
+    Parser() : separators(" \t=:") {}
+
+    struct Token
+    {
+        enum Type
+        {
+            Positional,
+            ShortOpt,
+            LongOpt
+        };
+        Token(Type _type, std::string const& _data) : type(_type), data(_data) {}
+        Type type;
+        std::string data;
+    };
+
+    void parseIntoTokens(int argc, char const* const* argv, std::vector<Parser::Token>& tokens) const
+    {
+        const std::string doubleDash = "--";
+        for (int i = 1; i < argc && argv[i] != doubleDash; ++i)
+            parseIntoTokens(argv[i], tokens);
+    }
+    void parseIntoTokens(std::string arg, std::vector<Parser::Token>& tokens) const
+    {
+        while (!arg.empty())
+        {
+            Parser::Token token(Parser::Token::Positional, arg);
+            arg = "";
+            if (token.data[0] == '-')
+            {
+                if (token.data.size() > 1 && token.data[1] == '-')
+                {
+                    token = Parser::Token(Parser::Token::LongOpt, token.data.substr(2));
+                }
+                else
+                {
+                    token = Parser::Token(Parser::Token::ShortOpt, token.data.substr(1));
+                    if (token.data.size() > 1 && separators.find(token.data[1]) == std::string::npos)
+                    {
+                        arg = "-" + token.data.substr(1);
+                        token.data = token.data.substr(0, 1);
+                    }
+                }
+            }
+            if (token.type != Parser::Token::Positional)
+            {
+                std::size_t pos = token.data.find_first_of(separators);
+                if (pos != std::string::npos)
+                {
+                    arg = token.data.substr(pos + 1);
+                    token.data = token.data.substr(0, pos);
+                }
+            }
+            tokens.push_back(token);
+        }
+    }
+    std::string separators;
+};
+
+template <typename ConfigT>
+struct CommonArgProperties
+{
+    CommonArgProperties() {}
+    CommonArgProperties(Detail::BoundArgFunction<ConfigT> const& _boundField) : boundField(_boundField) {}
+
+    Detail::BoundArgFunction<ConfigT> boundField;
+    std::string description;
+    std::string detail;
+    std::string placeholder; // Only value if boundField takes an arg
+
+    bool takesArg() const
+    {
+        return !placeholder.empty();
+    }
+    void validate() const
+    {
+        if (!boundField.isSet())
+            throw std::logic_error("option not bound");
+    }
+};
+struct OptionArgProperties
+{
+    std::vector<std::string> shortNames;
+    std::string longName;
+
+    bool hasShortName(std::string const& shortName) const
+    {
+        return std::find(shortNames.begin(), shortNames.end(), shortName) != shortNames.end();
+    }
+    bool hasLongName(std::string const& _longName) const
+    {
+        return _longName == longName;
+    }
+};
+struct PositionalArgProperties
+{
+    PositionalArgProperties() : position(-1) {}
+    int position; // -1 means non-positional (floating)
+
+    bool isFixedPositional() const
+    {
+        return position != -1;
+    }
+};
+
+template <typename ConfigT>
+class CommandLine
+{
+
+    struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties
+    {
+        Arg() {}
+        Arg(Detail::BoundArgFunction<ConfigT> const& _boundField) : CommonArgProperties<ConfigT>(_boundField) {}
+
+        using CommonArgProperties<ConfigT>::placeholder; // !TBD
+
+        std::string dbgName() const
+        {
+            if (!longName.empty())
+                return "--" + longName;
+            if (!shortNames.empty())
+                return "-" + shortNames[0];
+            return "positional args";
+        }
+        std::string commands() const
+        {
+            std::ostringstream oss;
+            bool first = true;
+            std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end();
+            for (; it != itEnd; ++it)
+            {
+                if (first)
+                    first = false;
+                else
+                    oss << ", ";
+                oss << "-" << *it;
+            }
+            if (!longName.empty())
+            {
+                if (!first)
+                    oss << ", ";
+                oss << "--" << longName;
+            }
+            if (!placeholder.empty())
+                oss << " <" << placeholder << ">";
+            return oss.str();
+        }
+    };
+
+    typedef CATCH_AUTO_PTR(Arg) ArgAutoPtr;
+
+    friend void addOptName(Arg& arg, std::string const& optName)
+    {
+        if (optName.empty())
+            return;
+        if (Detail::startsWith(optName, "--"))
+        {
+            if (!arg.longName.empty())
+                throw std::logic_error("Only one long opt may be specified. '" + arg.longName + "' already specified, now attempting to add '" + optName + "'");
+            arg.longName = optName.substr(2);
+        }
+        else if (Detail::startsWith(optName, "-"))
+            arg.shortNames.push_back(optName.substr(1));
+        else
+            throw std::logic_error("option must begin with - or --. Option was: '" + optName + "'");
+    }
+    friend void setPositionalArg(Arg& arg, int position)
+    {
+        arg.position = position;
+    }
+
+    class ArgBuilder
+    {
+      public:
+        ArgBuilder(Arg* arg) : m_arg(arg) {}
+
+        // Bind a non-boolean data member (requires placeholder string)
+        template <typename C, typename M>
+        void bind(M C::*field, std::string const& placeholder)
+        {
+            m_arg->boundField = new Detail::BoundDataMember<C, M>(field);
+            m_arg->placeholder = placeholder;
+        }
+        // Bind a boolean data member (no placeholder required)
+        template <typename C>
+        void bind(bool C::*field)
+        {
+            m_arg->boundField = new Detail::BoundDataMember<C, bool>(field);
+        }
+
+        // Bind a method taking a single, non-boolean argument (requires a placeholder string)
+        template <typename C, typename M>
+        void bind(void (C::*unaryMethod)(M), std::string const& placeholder)
+        {
+            m_arg->boundField = new Detail::BoundUnaryMethod<C, M>(unaryMethod);
+            m_arg->placeholder = placeholder;
+        }
+
+        // Bind a method taking a single, boolean argument (no placeholder string required)
+        template <typename C>
+        void bind(void (C::*unaryMethod)(bool))
+        {
+            m_arg->boundField = new Detail::BoundUnaryMethod<C, bool>(unaryMethod);
+        }
+
+        // Bind a method that takes no arguments (will be called if opt is present)
+        template <typename C>
+        void bind(void (C::*nullaryMethod)())
+        {
+            m_arg->boundField = new Detail::BoundNullaryMethod<C>(nullaryMethod);
+        }
+
+        // Bind a free function taking a single argument - the object to operate on (no placeholder string required)
+        template <typename C>
+        void bind(void (*unaryFunction)(C&))
+        {
+            m_arg->boundField = new Detail::BoundUnaryFunction<C>(unaryFunction);
+        }
+
+        // Bind a free function taking a single argument - the object to operate on (requires a placeholder string)
+        template <typename C, typename T>
+        void bind(void (*binaryFunction)(C&, T), std::string const& placeholder)
+        {
+            m_arg->boundField = new Detail::BoundBinaryFunction<C, T>(binaryFunction);
+            m_arg->placeholder = placeholder;
+        }
+
+        ArgBuilder& describe(std::string const& description)
+        {
+            m_arg->description = description;
+            return *this;
+        }
+        ArgBuilder& detail(std::string const& _detail)
+        {
+            m_arg->detail = _detail;
+            return *this;
+        }
+
+      protected:
+        Arg* m_arg;
+    };
+
+    class OptBuilder : public ArgBuilder
+    {
+      public:
+        OptBuilder(Arg* arg) : ArgBuilder(arg) {}
+        OptBuilder(OptBuilder& other) : ArgBuilder(other) {}
+
+        OptBuilder& operator[](std::string const& optName)
+        {
+            addOptName(*ArgBuilder::m_arg, optName);
+            return *this;
+        }
+    };
+
+  public:
+    CommandLine()
+        : m_boundProcessName(new Detail::NullBinder<ConfigT>()),
+          m_highestSpecifiedArgPosition(0),
+          m_throwOnUnrecognisedTokens(false)
+    {
+    }
+    CommandLine(CommandLine const& other)
+        : m_boundProcessName(other.m_boundProcessName),
+          m_options(other.m_options),
+          m_positionalArgs(other.m_positionalArgs),
+          m_highestSpecifiedArgPosition(other.m_highestSpecifiedArgPosition),
+          m_throwOnUnrecognisedTokens(other.m_throwOnUnrecognisedTokens)
+    {
+        if (other.m_floatingArg.get())
+            m_floatingArg.reset(new Arg(*other.m_floatingArg));
+    }
+
+    CommandLine& setThrowOnUnrecognisedTokens(bool shouldThrow = true)
+    {
+        m_throwOnUnrecognisedTokens = shouldThrow;
+        return *this;
+    }
+
+    OptBuilder operator[](std::string const& optName)
+    {
+        m_options.push_back(Arg());
+        addOptName(m_options.back(), optName);
+        OptBuilder builder(&m_options.back());
+        return builder;
+    }
+
+    ArgBuilder operator[](int position)
+    {
+        m_positionalArgs.insert(std::make_pair(position, Arg()));
+        if (position > m_highestSpecifiedArgPosition)
+            m_highestSpecifiedArgPosition = position;
+        setPositionalArg(m_positionalArgs[position], position);
+        ArgBuilder builder(&m_positionalArgs[position]);
+        return builder;
+    }
+
+    // Invoke this with the _ instance
+    ArgBuilder operator[](UnpositionalTag)
+    {
+        if (m_floatingArg.get())
+            throw std::logic_error("Only one unpositional argument can be added");
+        m_floatingArg.reset(new Arg());
+        ArgBuilder builder(m_floatingArg.get());
+        return builder;
+    }
+
+    template <typename C, typename M>
+    void bindProcessName(M C::*field)
+    {
+        m_boundProcessName = new Detail::BoundDataMember<C, M>(field);
+    }
+    template <typename C, typename M>
+    void bindProcessName(void (C::*_unaryMethod)(M))
+    {
+        m_boundProcessName = new Detail::BoundUnaryMethod<C, M>(_unaryMethod);
+    }
+
+    void optUsage(std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth) const
+    {
+        typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it;
+        std::size_t maxWidth = 0;
+        for (it = itBegin; it != itEnd; ++it)
+            maxWidth = (std::max)(maxWidth, it->commands().size());
+
+        for (it = itBegin; it != itEnd; ++it)
+        {
+            Detail::Text usageText(it->commands(), Detail::TextAttributes()
+                                                       .setWidth(maxWidth + indent)
+                                                       .setIndent(indent));
+            Detail::Text desc(it->description, Detail::TextAttributes()
+                                                   .setWidth(width - maxWidth - 3));
+
+            for (std::size_t i = 0; i < (std::max)(usageText.size(), desc.size()); ++i)
+            {
+                std::string usageCol = i < usageText.size() ? usageText[i] : "";
+                os << usageCol;
+
+                if (i < desc.size() && !desc[i].empty())
+                    os << std::string(indent + 2 + maxWidth - usageCol.size(), ' ')
+                       << desc[i];
+                os << "\n";
+            }
+        }
+    }
+    std::string optUsage() const
+    {
+        std::ostringstream oss;
+        optUsage(oss);
+        return oss.str();
+    }
+
+    void argSynopsis(std::ostream& os) const
+    {
+        for (int i = 1; i <= m_highestSpecifiedArgPosition; ++i)
+        {
+            if (i > 1)
+                os << " ";
+            typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find(i);
+            if (it != m_positionalArgs.end())
+                os << "<" << it->second.placeholder << ">";
+            else if (m_floatingArg.get())
+                os << "<" << m_floatingArg->placeholder << ">";
+            else
+                throw std::logic_error("non consecutive positional arguments with no floating args");
+        }
+        // !TBD No indication of mandatory args
+        if (m_floatingArg.get())
+        {
+            if (m_highestSpecifiedArgPosition > 1)
+                os << " ";
+            os << "[<" << m_floatingArg->placeholder << "> ...]";
+        }
+    }
+    std::string argSynopsis() const
+    {
+        std::ostringstream oss;
+        argSynopsis(oss);
+        return oss.str();
+    }
+
+    void usage(std::ostream& os, std::string const& procName) const
+    {
+        validate();
+        os << "usage:\n  " << procName << " ";
+        argSynopsis(os);
+        if (!m_options.empty())
+        {
+            os << " [options]\n\nwhere options are: \n";
+            optUsage(os, 2);
+        }
+        os << "\n";
+    }
+    std::string usage(std::string const& procName) const
+    {
+        std::ostringstream oss;
+        usage(oss, procName);
+        return oss.str();
+    }
+
+    ConfigT parse(int argc, char const* const* argv) const
+    {
+        ConfigT config;
+        parseInto(argc, argv, config);
+        return config;
+    }
+
+    std::vector<Parser::Token> parseInto(int argc, char const* const* argv, ConfigT& config) const
+    {
+        std::string processName = argv[0];
+        std::size_t lastSlash = processName.find_last_of("/\\");
+        if (lastSlash != std::string::npos)
+            processName = processName.substr(lastSlash + 1);
+        m_boundProcessName.set(config, processName);
+        std::vector<Parser::Token> tokens;
+        Parser parser;
+        parser.parseIntoTokens(argc, argv, tokens);
+        return populate(tokens, config);
+    }
+
+    std::vector<Parser::Token> populate(std::vector<Parser::Token> const& tokens, ConfigT& config) const
+    {
+        validate();
+        std::vector<Parser::Token> unusedTokens = populateOptions(tokens, config);
+        unusedTokens = populateFixedArgs(unusedTokens, config);
+        unusedTokens = populateFloatingArgs(unusedTokens, config);
+        return unusedTokens;
+    }
+
+    std::vector<Parser::Token> populateOptions(std::vector<Parser::Token> const& tokens, ConfigT& config) const
+    {
+        std::vector<Parser::Token> unusedTokens;
+        std::vector<std::string> errors;
+        for (std::size_t i = 0; i < tokens.size(); ++i)
+        {
+            Parser::Token const& token = tokens[i];
+            typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end();
+            for (; it != itEnd; ++it)
+            {
+                Arg const& arg = *it;
+
+                try
+                {
+                    if ((token.type == Parser::Token::ShortOpt && arg.hasShortName(token.data)) ||
+                        (token.type == Parser::Token::LongOpt && arg.hasLongName(token.data)))
+                    {
+                        if (arg.takesArg())
+                        {
+                            if (i == tokens.size() - 1 || tokens[i + 1].type != Parser::Token::Positional)
+                                errors.push_back("Expected argument to option: " + token.data);
+                            else
+                                arg.boundField.set(config, tokens[++i].data);
+                        }
+                        else
+                        {
+                            arg.boundField.setFlag(config);
+                        }
+                        break;
+                    }
+                }
+                catch (std::exception& ex)
+                {
+                    errors.push_back(std::string(ex.what()) + "\n- while parsing: (" + arg.commands() + ")");
+                }
+            }
+            if (it == itEnd)
+            {
+                if (token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens)
+                    unusedTokens.push_back(token);
+                else if (errors.empty() && m_throwOnUnrecognisedTokens)
+                    errors.push_back("unrecognised option: " + token.data);
+            }
+        }
+        if (!errors.empty())
+        {
+            std::ostringstream oss;
+            for (std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end();
+                 it != itEnd;
+                 ++it)
+            {
+                if (it != errors.begin())
+                    oss << "\n";
+                oss << *it;
+            }
+            throw std::runtime_error(oss.str());
+        }
+        return unusedTokens;
+    }
+    std::vector<Parser::Token> populateFixedArgs(std::vector<Parser::Token> const& tokens, ConfigT& config) const
+    {
+        std::vector<Parser::Token> unusedTokens;
+        int position = 1;
+        for (std::size_t i = 0; i < tokens.size(); ++i)
+        {
+            Parser::Token const& token = tokens[i];
+            typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find(position);
+            if (it != m_positionalArgs.end())
+                it->second.boundField.set(config, token.data);
+            else
+                unusedTokens.push_back(token);
+            if (token.type == Parser::Token::Positional)
+                position++;
+        }
+        return unusedTokens;
+    }
+    std::vector<Parser::Token> populateFloatingArgs(std::vector<Parser::Token> const& tokens, ConfigT& config) const
+    {
+        if (!m_floatingArg.get())
+            return tokens;
+        std::vector<Parser::Token> unusedTokens;
+        for (std::size_t i = 0; i < tokens.size(); ++i)
+        {
+            Parser::Token const& token = tokens[i];
+            if (token.type == Parser::Token::Positional)
+                m_floatingArg->boundField.set(config, token.data);
+            else
+                unusedTokens.push_back(token);
+        }
+        return unusedTokens;
+    }
+
+    void validate() const
+    {
+        if (m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get())
+            throw std::logic_error("No options or arguments specified");
+
+        for (typename std::vector<Arg>::const_iterator it = m_options.begin(),
+                                                       itEnd = m_options.end();
+             it != itEnd; ++it)
+            it->validate();
+    }
+
+  private:
+    Detail::BoundArgFunction<ConfigT> m_boundProcessName;
+    std::vector<Arg> m_options;
+    std::map<int, Arg> m_positionalArgs;
+    ArgAutoPtr m_floatingArg;
+    int m_highestSpecifiedArgPosition;
+    bool m_throwOnUnrecognisedTokens;
+};
+
+} // end namespace Clara
+
+STITCH_CLARA_CLOSE_NAMESPACE
+#undef STITCH_CLARA_OPEN_NAMESPACE
+#undef STITCH_CLARA_CLOSE_NAMESPACE
+
+#endif // TWOBLUECUBES_CLARA_H_INCLUDED
+#undef STITCH_CLARA_OPEN_NAMESPACE
+
+// Restore Clara's value for console width, if present
+#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+
+#include <fstream>
+
+namespace Catch {
+
+inline void abortAfterFirst(ConfigData& config) { config.abortAfter = 1; }
+inline void abortAfterX(ConfigData& config, int x)
+{
+    if (x < 1)
+        throw std::runtime_error("Value after -x or --abortAfter must be greater than zero");
+    config.abortAfter = x;
+}
+inline void addTestOrTags(ConfigData& config, std::string const& _testSpec) { config.testsOrTags.push_back(_testSpec); }
+inline void addReporterName(ConfigData& config, std::string const& _reporterName) { config.reporterNames.push_back(_reporterName); }
+
+inline void addWarning(ConfigData& config, std::string const& _warning)
+{
+    if (_warning == "NoAssertions")
+        config.warnings = static_cast<WarnAbout::What>(config.warnings | WarnAbout::NoAssertions);
+    else
+        throw std::runtime_error("Unrecognised warning: '" + _warning + "'");
+}
+inline void setOrder(ConfigData& config, std::string const& order)
+{
+    if (startsWith("declared", order))
+        config.runOrder = RunTests::InDeclarationOrder;
+    else if (startsWith("lexical", order))
+        config.runOrder = RunTests::InLexicographicalOrder;
+    else if (startsWith("random", order))
+        config.runOrder = RunTests::InRandomOrder;
+    else
+        throw std::runtime_error("Unrecognised ordering: '" + order + "'");
+}
+inline void setRngSeed(ConfigData& config, std::string const& seed)
+{
+    if (seed == "time")
+    {
+        config.rngSeed = static_cast<unsigned int>(std::time(0));
+    }
+    else
+    {
+        std::stringstream ss;
+        ss << seed;
+        ss >> config.rngSeed;
+        if (ss.fail())
+            throw std::runtime_error("Argment to --rng-seed should be the word 'time' or a number");
+    }
+}
+inline void setVerbosity(ConfigData& config, int level)
+{
+    // !TBD: accept strings?
+    config.verbosity = static_cast<Verbosity::Level>(level);
+}
+inline void setShowDurations(ConfigData& config, bool _showDurations)
+{
+    config.showDurations = _showDurations
+                               ? ShowDurations::Always
+                               : ShowDurations::Never;
+}
+inline void loadTestNamesFromFile(ConfigData& config, std::string const& _filename)
+{
+    std::ifstream f(_filename.c_str());
+    if (!f.is_open())
+        throw std::domain_error("Unable to load input file: " + _filename);
+
+    std::string line;
+    while (std::getline(f, line))
+    {
+        line = trim(line);
+        if (!line.empty() && !startsWith(line, "#"))
+            addTestOrTags(config, "\"" + line + "\",");
+    }
+}
+
+inline Clara::CommandLine<ConfigData> makeCommandLineParser()
+{
+
+    using namespace Clara;
+    CommandLine<ConfigData> cli;
+
+    cli.bindProcessName(&ConfigData::processName);
+
+    cli["-?"]["-h"]["--help"]
+        .describe("display usage information")
+        .bind(&ConfigData::showHelp);
+
+    cli["-l"]["--list-tests"]
+        .describe("list all/matching test cases")
+        .bind(&ConfigData::listTests);
+
+    cli["-t"]["--list-tags"]
+        .describe("list all/matching tags")
+        .bind(&ConfigData::listTags);
+
+    cli["-s"]["--success"]
+        .describe("include successful tests in output")
+        .bind(&ConfigData::showSuccessfulTests);
+
+    cli["-b"]["--break"]
+        .describe("break into debugger on failure")
+        .bind(&ConfigData::shouldDebugBreak);
+
+    cli["-e"]["--nothrow"]
+        .describe("skip exception tests")
+        .bind(&ConfigData::noThrow);
+
+    cli["-i"]["--invisibles"]
+        .describe("show invisibles (tabs, newlines)")
+        .bind(&ConfigData::showInvisibles);
+
+    cli["-o"]["--out"]
+        .describe("output filename")
+        .bind(&ConfigData::outputFilename, "filename");
+
+    cli["-r"]["--reporter"]
+        //            .placeholder( "name[:filename]" )
+        .describe("reporter to use (defaults to console)")
+        .bind(&addReporterName, "name");
+
+    cli["-n"]["--name"]
+        .describe("suite name")
+        .bind(&ConfigData::name, "name");
+
+    cli["-a"]["--abort"]
+        .describe("abort at first failure")
+        .bind(&abortAfterFirst);
+
+    cli["-x"]["--abortx"]
+        .describe("abort after x failures")
+        .bind(&abortAfterX, "no. failures");
+
+    cli["-w"]["--warn"]
+        .describe("enable warnings")
+        .bind(&addWarning, "warning name");
+
+    // - needs updating if reinstated
+    //        cli.into( &setVerbosity )
+    //            .describe( "level of verbosity (0=no output)" )
+    //            .shortOpt( "v")
+    //            .longOpt( "verbosity" )
+    //            .placeholder( "level" );
+
+    cli[_]
+        .describe("which test or tests to use")
+        .bind(&addTestOrTags, "test name, pattern or tags");
+
+    cli["-d"]["--durations"]
+        .describe("show test durations")
+        .bind(&setShowDurations, "yes/no");
+
+    cli["-f"]["--input-file"]
+        .describe("load test names to run from a file")
+        .bind(&loadTestNamesFromFile, "filename");
+
+    cli["-#"]["--filenames-as-tags"]
+        .describe("adds a tag for the filename")
+        .bind(&ConfigData::filenamesAsTags);
+
+    // Less common commands which don't have a short form
+    cli["--list-test-names-only"]
+        .describe("list all/matching test cases names only")
+        .bind(&ConfigData::listTestNamesOnly);
+
+    cli["--list-reporters"]
+        .describe("list all reporters")
+        .bind(&ConfigData::listReporters);
+
+    cli["--order"]
+        .describe("test case order (defaults to decl)")
+        .bind(&setOrder, "decl|lex|rand");
+
+    cli["--rng-seed"]
+        .describe("set a specific seed for random numbers")
+        .bind(&setRngSeed, "'time'|number");
+
+    cli["--force-colour"]
+        .describe("force colourised output")
+        .bind(&ConfigData::forceColour);
+
+    return cli;
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_list.hpp
+#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
+
+// #included from: catch_text.h
+#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED
+
+#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch
+// #included from: ../external/tbc_text_format.h
+// Only use header guard if we are not using an outer namespace
+#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+#ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#endif
+#else
+#define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+#endif
+#endif
+#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#include <sstream>
+#include <string>
+#include <vector>
+
+// Use optional outer namespace
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+const unsigned int consoleWidth = 80;
+#endif
+
+struct TextAttributes
+{
+    TextAttributes()
+        : initialIndent(std::string::npos),
+          indent(0),
+          width(consoleWidth - 1),
+          tabChar('\t')
+    {
+    }
+
+    TextAttributes& setInitialIndent(std::size_t _value)
+    {
+        initialIndent = _value;
+        return *this;
+    }
+    TextAttributes& setIndent(std::size_t _value)
+    {
+        indent = _value;
+        return *this;
+    }
+    TextAttributes& setWidth(std::size_t _value)
+    {
+        width = _value;
+        return *this;
+    }
+    TextAttributes& setTabChar(char _value)
+    {
+        tabChar = _value;
+        return *this;
+    }
+
+    std::size_t initialIndent; // indent of first line, or npos
+    std::size_t indent;        // indent of subsequent lines, or all if initialIndent is npos
+    std::size_t width;         // maximum width of text, including indent. Longer text will wrap
+    char tabChar;              // If this char is seen the indent is changed to current pos
+};
+
+class Text
+{
+  public:
+    Text(std::string const& _str, TextAttributes const& _attr = TextAttributes())
+        : attr(_attr)
+    {
+        std::string wrappableChars = " [({.,/|\\-";
+        std::size_t indent = _attr.initialIndent != std::string::npos
+                                 ? _attr.initialIndent
+                                 : _attr.indent;
+        std::string remainder = _str;
+
+        while (!remainder.empty())
+        {
+            if (lines.size() >= 1000)
+            {
+                lines.push_back("... message truncated due to excessive size");
+                return;
+            }
+            std::size_t tabPos = std::string::npos;
+            std::size_t width = (std::min)(remainder.size(), _attr.width - indent);
+            std::size_t pos = remainder.find_first_of('\n');
+            if (pos <= width)
+            {
+                width = pos;
+            }
+            pos = remainder.find_last_of(_attr.tabChar, width);
+            if (pos != std::string::npos)
+            {
+                tabPos = pos;
+                if (remainder[width] == '\n')
+                    width--;
+                remainder = remainder.substr(0, tabPos) + remainder.substr(tabPos + 1);
+            }
+
+            if (width == remainder.size())
+            {
+                spliceLine(indent, remainder, width);
+            }
+            else if (remainder[width] == '\n')
+            {
+                spliceLine(indent, remainder, width);
+                if (width <= 1 || remainder.size() != 1)
+                    remainder = remainder.substr(1);
+                indent = _attr.indent;
+            }
+            else
+            {
+                pos = remainder.find_last_of(wrappableChars, width);
+                if (pos != std::string::npos && pos > 0)
+                {
+                    spliceLine(indent, remainder, pos);
+                    if (remainder[0] == ' ')
+                        remainder = remainder.substr(1);
+                }
+                else
+                {
+                    spliceLine(indent, remainder, width - 1);
+                    lines.back() += "-";
+                }
+                if (lines.size() == 1)
+                    indent = _attr.indent;
+                if (tabPos != std::string::npos)
+                    indent += tabPos;
+            }
+        }
+    }
+
+    void spliceLine(std::size_t _indent, std::string& _remainder, std::size_t _pos)
+    {
+        lines.push_back(std::string(_indent, ' ') + _remainder.substr(0, _pos));
+        _remainder = _remainder.substr(_pos);
+    }
+
+    typedef std::vector<std::string>::const_iterator const_iterator;
+
+    const_iterator begin() const { return lines.begin(); }
+    const_iterator end() const { return lines.end(); }
+    std::string const& last() const { return lines.back(); }
+    std::size_t size() const { return lines.size(); }
+    std::string const& operator[](std::size_t _index) const { return lines[_index]; }
+    std::string toString() const
+    {
+        std::ostringstream oss;
+        oss << *this;
+        return oss.str();
+    }
+
+    inline friend std::ostream& operator<<(std::ostream& _stream, Text const& _text)
+    {
+        for (Text::const_iterator it = _text.begin(), itEnd = _text.end();
+             it != itEnd; ++it)
+        {
+            if (it != _text.begin())
+                _stream << "\n";
+            _stream << *it;
+        }
+        return _stream;
+    }
+
+  private:
+    std::string str;
+    TextAttributes attr;
+    std::vector<std::string> lines;
+};
+
+} // end namespace Tbc
+
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+
+namespace Catch {
+using Tbc::Text;
+using Tbc::TextAttributes;
+}
+
+// #included from: catch_console_colour.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED
+
+namespace Catch {
+
+struct Colour
+{
+    enum Code
+    {
+        None = 0,
+
+        White,
+        Red,
+        Green,
+        Blue,
+        Cyan,
+        Yellow,
+        Grey,
+
+        Bright = 0x10,
+
+        BrightRed = Bright | Red,
+        BrightGreen = Bright | Green,
+        LightGrey = Bright | Grey,
+        BrightWhite = Bright | White,
+
+        // By intention
+        FileName = LightGrey,
+        Warning = Yellow,
+        ResultError = BrightRed,
+        ResultSuccess = BrightGreen,
+        ResultExpectedFailure = Warning,
+
+        Error = BrightRed,
+        Success = Green,
+
+        OriginalExpression = Cyan,
+        ReconstructedExpression = Yellow,
+
+        SecondaryText = LightGrey,
+        Headers = White
+    };
+
+    // Use constructed object for RAII guard
+    Colour(Code _colourCode);
+    Colour(Colour const& other);
+    ~Colour();
+
+    // Use static method for one-shot changes
+    static void use(Code _colourCode);
+
+  private:
+    bool m_moved;
+};
+
+inline std::ostream& operator<<(std::ostream& os, Colour const&) { return os; }
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_reporter.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
+
+#include <assert.h>
+#include <map>
+#include <ostream>
+#include <string>
+
+namespace Catch {
+struct ReporterConfig
+{
+    explicit ReporterConfig(Ptr<IConfig const> const& _fullConfig)
+        : m_stream(&_fullConfig->stream()), m_fullConfig(_fullConfig) {}
+
+    ReporterConfig(Ptr<IConfig const> const& _fullConfig, std::ostream& _stream)
+        : m_stream(&_stream), m_fullConfig(_fullConfig) {}
+
+    std::ostream& stream() const { return *m_stream; }
+    Ptr<IConfig const> fullConfig() const { return m_fullConfig; }
+
+  private:
+    std::ostream* m_stream;
+    Ptr<IConfig const> m_fullConfig;
+};
+
+struct ReporterPreferences
+{
+    ReporterPreferences()
+        : shouldRedirectStdOut(false)
+    {
+    }
+
+    bool shouldRedirectStdOut;
+};
+
+template <typename T>
+struct LazyStat : Option<T>
+{
+    LazyStat() : used(false) {}
+    LazyStat& operator=(T const& _value)
+    {
+        Option<T>::operator=(_value);
+        used = false;
+        return *this;
+    }
+    void reset()
+    {
+        Option<T>::reset();
+        used = false;
+    }
+    bool used;
+};
+
+struct TestRunInfo
+{
+    TestRunInfo(std::string const& _name) : name(_name) {}
+    std::string name;
+};
+struct GroupInfo
+{
+    GroupInfo(std::string const& _name,
+              std::size_t _groupIndex,
+              std::size_t _groupsCount)
+        : name(_name),
+          groupIndex(_groupIndex),
+          groupsCounts(_groupsCount)
+    {
+    }
+
+    std::string name;
+    std::size_t groupIndex;
+    std::size_t groupsCounts;
+};
+
+struct AssertionStats
+{
+    AssertionStats(AssertionResult const& _assertionResult,
+                   std::vector<MessageInfo> const& _infoMessages,
+                   Totals const& _totals)
+        : assertionResult(_assertionResult),
+          infoMessages(_infoMessages),
+          totals(_totals)
+    {
+        if (assertionResult.hasMessage())
+        {
+            // Copy message into messages list.
+            // !TBD This should have been done earlier, somewhere
+            MessageBuilder builder(assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType());
+            builder << assertionResult.getMessage();
+            builder.m_info.message = builder.m_stream.str();
+
+            infoMessages.push_back(builder.m_info);
+        }
+    }
+    virtual ~AssertionStats();
+
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+    AssertionStats(AssertionStats const&) = default;
+    AssertionStats(AssertionStats&&) = default;
+    AssertionStats& operator=(AssertionStats const&) = default;
+    AssertionStats& operator=(AssertionStats&&) = default;
+#endif
+
+    AssertionResult assertionResult;
+    std::vector<MessageInfo> infoMessages;
+    Totals totals;
+};
+
+struct SectionStats
+{
+    SectionStats(SectionInfo const& _sectionInfo,
+                 Counts const& _assertions,
+                 double _durationInSeconds,
+                 bool _missingAssertions)
+        : sectionInfo(_sectionInfo),
+          assertions(_assertions),
+          durationInSeconds(_durationInSeconds),
+          missingAssertions(_missingAssertions)
+    {
+    }
+    virtual ~SectionStats();
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+    SectionStats(SectionStats const&) = default;
+    SectionStats(SectionStats&&) = default;
+    SectionStats& operator=(SectionStats const&) = default;
+    SectionStats& operator=(SectionStats&&) = default;
+#endif
+
+    SectionInfo sectionInfo;
+    Counts assertions;
+    double durationInSeconds;
+    bool missingAssertions;
+};
+
+struct TestCaseStats
+{
+    TestCaseStats(TestCaseInfo const& _testInfo,
+                  Totals const& _totals,
+                  std::string const& _stdOut,
+                  std::string const& _stdErr,
+                  bool _aborting)
+        : testInfo(_testInfo),
+          totals(_totals),
+          stdOut(_stdOut),
+          stdErr(_stdErr),
+          aborting(_aborting)
+    {
+    }
+    virtual ~TestCaseStats();
+
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+    TestCaseStats(TestCaseStats const&) = default;
+    TestCaseStats(TestCaseStats&&) = default;
+    TestCaseStats& operator=(TestCaseStats const&) = default;
+    TestCaseStats& operator=(TestCaseStats&&) = default;
+#endif
+
+    TestCaseInfo testInfo;
+    Totals totals;
+    std::string stdOut;
+    std::string stdErr;
+    bool aborting;
+};
+
+struct TestGroupStats
+{
+    TestGroupStats(GroupInfo const& _groupInfo,
+                   Totals const& _totals,
+                   bool _aborting)
+        : groupInfo(_groupInfo),
+          totals(_totals),
+          aborting(_aborting)
+    {
+    }
+    TestGroupStats(GroupInfo const& _groupInfo)
+        : groupInfo(_groupInfo),
+          aborting(false)
+    {
+    }
+    virtual ~TestGroupStats();
+
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+    TestGroupStats(TestGroupStats const&) = default;
+    TestGroupStats(TestGroupStats&&) = default;
+    TestGroupStats& operator=(TestGroupStats const&) = default;
+    TestGroupStats& operator=(TestGroupStats&&) = default;
+#endif
+
+    GroupInfo groupInfo;
+    Totals totals;
+    bool aborting;
+};
+
+struct TestRunStats
+{
+    TestRunStats(TestRunInfo const& _runInfo,
+                 Totals const& _totals,
+                 bool _aborting)
+        : runInfo(_runInfo),
+          totals(_totals),
+          aborting(_aborting)
+    {
+    }
+    virtual ~TestRunStats();
+
+#ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS
+    TestRunStats(TestRunStats const& _other)
+        : runInfo(_other.runInfo),
+          totals(_other.totals),
+          aborting(_other.aborting)
+    {
+    }
+#else
+    TestRunStats(TestRunStats const&) = default;
+    TestRunStats(TestRunStats&&) = default;
+    TestRunStats& operator=(TestRunStats const&) = default;
+    TestRunStats& operator=(TestRunStats&&) = default;
+#endif
+
+    TestRunInfo runInfo;
+    Totals totals;
+    bool aborting;
+};
+
+struct IStreamingReporter : IShared
+{
+    virtual ~IStreamingReporter();
+
+    // Implementing class must also provide the following static method:
+    // static std::string getDescription();
+
+    virtual ReporterPreferences getPreferences() const = 0;
+
+    virtual void noMatchingTestCases(std::string const& spec) = 0;
+
+    virtual void testRunStarting(TestRunInfo const& testRunInfo) = 0;
+    virtual void testGroupStarting(GroupInfo const& groupInfo) = 0;
+
+    virtual void testCaseStarting(TestCaseInfo const& testInfo) = 0;
+    virtual void sectionStarting(SectionInfo const& sectionInfo) = 0;
+
+    virtual void assertionStarting(AssertionInfo const& assertionInfo) = 0;
+
+    // The return value indicates if the messages buffer should be cleared:
+    virtual bool assertionEnded(AssertionStats const& assertionStats) = 0;
+
+    virtual void sectionEnded(SectionStats const& sectionStats) = 0;
+    virtual void testCaseEnded(TestCaseStats const& testCaseStats) = 0;
+    virtual void testGroupEnded(TestGroupStats const& testGroupStats) = 0;
+    virtual void testRunEnded(TestRunStats const& testRunStats) = 0;
+
+    virtual void skipTest(TestCaseInfo const& testInfo) = 0;
+};
+
+struct IReporterFactory : IShared
+{
+    virtual ~IReporterFactory();
+    virtual IStreamingReporter* create(ReporterConfig const& config) const = 0;
+    virtual std::string getDescription() const = 0;
+};
+
+struct IReporterRegistry
+{
+    typedef std::map<std::string, Ptr<IReporterFactory>> FactoryMap;
+    typedef std::vector<Ptr<IReporterFactory>> Listeners;
+
+    virtual ~IReporterRegistry();
+    virtual IStreamingReporter* create(std::string const& name, Ptr<IConfig const> const& config) const = 0;
+    virtual FactoryMap const& getFactories() const = 0;
+    virtual Listeners const& getListeners() const = 0;
+};
+
+Ptr<IStreamingReporter> addReporter(Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter);
+}
+
+#include <algorithm>
+#include <limits>
+
+namespace Catch {
+
+inline std::size_t listTests(Config const& config)
+{
+
+    TestSpec testSpec = config.testSpec();
+    if (config.testSpec().hasFilters())
+        Catch::cout() << "Matching test cases:\n";
+    else
+    {
+        Catch::cout() << "All available test cases:\n";
+        testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("*").testSpec();
+    }
+
+    std::size_t matchedTests = 0;
+    TextAttributes nameAttr, tagsAttr;
+    nameAttr.setInitialIndent(2).setIndent(4);
+    tagsAttr.setIndent(6);
+
+    std::vector<TestCase> matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
+    for (std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+         it != itEnd;
+         ++it)
+    {
+        matchedTests++;
+        TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+        Colour::Code colour = testCaseInfo.isHidden()
+                                  ? Colour::SecondaryText
+                                  : Colour::None;
+        Colour colourGuard(colour);
+
+        Catch::cout() << Text(testCaseInfo.name, nameAttr) << std::endl;
+        if (!testCaseInfo.tags.empty())
+            Catch::cout() << Text(testCaseInfo.tagsAsString, tagsAttr) << std::endl;
+    }
+
+    if (!config.testSpec().hasFilters())
+        Catch::cout() << pluralise(matchedTests, "test case") << "\n"
+                      << std::endl;
+    else
+        Catch::cout() << pluralise(matchedTests, "matching test case") << "\n"
+                      << std::endl;
+    return matchedTests;
+}
+
+inline std::size_t listTestsNamesOnly(Config const& config)
+{
+    TestSpec testSpec = config.testSpec();
+    if (!config.testSpec().hasFilters())
+        testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("*").testSpec();
+    std::size_t matchedTests = 0;
+    std::vector<TestCase> matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
+    for (std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+         it != itEnd;
+         ++it)
+    {
+        matchedTests++;
+        TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+        Catch::cout() << testCaseInfo.name << std::endl;
+    }
+    return matchedTests;
+}
+
+struct TagInfo
+{
+    TagInfo() : count(0) {}
+    void add(std::string const& spelling)
+    {
+        ++count;
+        spellings.insert(spelling);
+    }
+    std::string all() const
+    {
+        std::string out;
+        for (std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end();
+             it != itEnd;
+             ++it)
+            out += "[" + *it + "]";
+        return out;
+    }
+    std::set<std::string> spellings;
+    std::size_t count;
+};
+
+inline std::size_t listTags(Config const& config)
+{
+    TestSpec testSpec = config.testSpec();
+    if (config.testSpec().hasFilters())
+        Catch::cout() << "Tags for matching test cases:\n";
+    else
+    {
+        Catch::cout() << "All available tags:\n";
+        testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("*").testSpec();
+    }
+
+    std::map<std::string, TagInfo> tagCounts;
+
+    std::vector<TestCase> matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
+    for (std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+         it != itEnd;
+         ++it)
+    {
+        for (std::set<std::string>::const_iterator tagIt = it->getTestCaseInfo().tags.begin(),
+                                                   tagItEnd = it->getTestCaseInfo().tags.end();
+             tagIt != tagItEnd;
+             ++tagIt)
+        {
+            std::string tagName = *tagIt;
+            std::string lcaseTagName = toLower(tagName);
+            std::map<std::string, TagInfo>::iterator countIt = tagCounts.find(lcaseTagName);
+            if (countIt == tagCounts.end())
+                countIt = tagCounts.insert(std::make_pair(lcaseTagName, TagInfo())).first;
+            countIt->second.add(tagName);
+        }
+    }
+
+    for (std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(),
+                                                        countItEnd = tagCounts.end();
+         countIt != countItEnd;
+         ++countIt)
+    {
+        std::ostringstream oss;
+        oss << "  " << std::setw(2) << countIt->second.count << "  ";
+        Text wrapper(countIt->second.all(), TextAttributes()
+                                                .setInitialIndent(0)
+                                                .setIndent(oss.str().size())
+                                                .setWidth(CATCH_CONFIG_CONSOLE_WIDTH - 10));
+        Catch::cout() << oss.str() << wrapper << "\n";
+    }
+    Catch::cout() << pluralise(tagCounts.size(), "tag") << "\n"
+                  << std::endl;
+    return tagCounts.size();
+}
+
+inline std::size_t listReporters(Config const& /*config*/)
+{
+    Catch::cout() << "Available reporters:\n";
+    IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
+    IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
+    std::size_t maxNameLen = 0;
+    for (it = itBegin; it != itEnd; ++it)
+        maxNameLen = (std::max)(maxNameLen, it->first.size());
+
+    for (it = itBegin; it != itEnd; ++it)
+    {
+        Text wrapper(it->second->getDescription(), TextAttributes()
+                                                       .setInitialIndent(0)
+                                                       .setIndent(7 + maxNameLen)
+                                                       .setWidth(CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8));
+        Catch::cout() << "  "
+                      << it->first
+                      << ":"
+                      << std::string(maxNameLen - it->first.size() + 2, ' ')
+                      << wrapper << "\n";
+    }
+    Catch::cout() << std::endl;
+    return factories.size();
+}
+
+inline Option<std::size_t> list(Config const& config)
+{
+    Option<std::size_t> listedCount;
+    if (config.listTests())
+        listedCount = listedCount.valueOr(0) + listTests(config);
+    if (config.listTestNamesOnly())
+        listedCount = listedCount.valueOr(0) + listTestsNamesOnly(config);
+    if (config.listTags())
+        listedCount = listedCount.valueOr(0) + listTags(config);
+    if (config.listReporters())
+        listedCount = listedCount.valueOr(0) + listReporters(config);
+    return listedCount;
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_run_context.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
+
+// #included from: catch_test_case_tracker.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
+
+#include <assert.h>
+#include <map>
+#include <string>
+#include <vector>
+
+namespace Catch {
+namespace TestCaseTracking {
+
+struct ITracker : SharedImpl<>
+{
+    virtual ~ITracker();
+
+    // static queries
+    virtual std::string name() const = 0;
+
+    // dynamic queries
+    virtual bool isComplete() const = 0; // Successfully completed or failed
+    virtual bool isSuccessfullyCompleted() const = 0;
+    virtual bool isOpen() const = 0; // Started but not complete
+    virtual bool hasChildren() const = 0;
+
+    virtual ITracker& parent() = 0;
+
+    // actions
+    virtual void close() = 0; // Successfully complete
+    virtual void fail() = 0;
+    virtual void markAsNeedingAnotherRun() = 0;
+
+    virtual void addChild(Ptr<ITracker> const& child) = 0;
+    virtual ITracker* findChild(std::string const& name) = 0;
+    virtual void openChild() = 0;
+};
+
+class TrackerContext
+{
+
+    enum RunState
+    {
+        NotStarted,
+        Executing,
+        CompletedCycle
+    };
+
+    Ptr<ITracker> m_rootTracker;
+    ITracker* m_currentTracker;
+    RunState m_runState;
+
+  public:
+    static TrackerContext& instance()
+    {
+        static TrackerContext s_instance;
+        return s_instance;
+    }
+
+    TrackerContext()
+        : m_currentTracker(CATCH_NULL),
+          m_runState(NotStarted)
+    {
+    }
+
+    ITracker& startRun();
+
+    void endRun()
+    {
+        m_rootTracker.reset();
+        m_currentTracker = CATCH_NULL;
+        m_runState = NotStarted;
+    }
+
+    void startCycle()
+    {
+        m_currentTracker = m_rootTracker.get();
+        m_runState = Executing;
+    }
+    void completeCycle()
+    {
+        m_runState = CompletedCycle;
+    }
+
+    bool completedCycle() const
+    {
+        return m_runState == CompletedCycle;
+    }
+    ITracker& currentTracker()
+    {
+        return *m_currentTracker;
+    }
+    void setCurrentTracker(ITracker* tracker)
+    {
+        m_currentTracker = tracker;
+    }
+};
+
+class TrackerBase : public ITracker
+{
+  protected:
+    enum CycleState
+    {
+        NotStarted,
+        Executing,
+        ExecutingChildren,
+        NeedsAnotherRun,
+        CompletedSuccessfully,
+        Failed
+    };
+    class TrackerHasName
+    {
+        std::string m_name;
+
+      public:
+        TrackerHasName(std::string const& name) : m_name(name) {}
+        bool operator()(Ptr<ITracker> const& tracker)
+        {
+            return tracker->name() == m_name;
+        }
+    };
+    typedef std::vector<Ptr<ITracker>> Children;
+    std::string m_name;
+    TrackerContext& m_ctx;
+    ITracker* m_parent;
+    Children m_children;
+    CycleState m_runState;
+
+  public:
+    TrackerBase(std::string const& name, TrackerContext& ctx, ITracker* parent)
+        : m_name(name),
+          m_ctx(ctx),
+          m_parent(parent),
+          m_runState(NotStarted)
+    {
+    }
+    virtual ~TrackerBase();
+
+    virtual std::string name() const CATCH_OVERRIDE
+    {
+        return m_name;
+    }
+    virtual bool isComplete() const CATCH_OVERRIDE
+    {
+        return m_runState == CompletedSuccessfully || m_runState == Failed;
+    }
+    virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE
+    {
+        return m_runState == CompletedSuccessfully;
+    }
+    virtual bool isOpen() const CATCH_OVERRIDE
+    {
+        return m_runState != NotStarted && !isComplete();
+    }
+    virtual bool hasChildren() const CATCH_OVERRIDE
+    {
+        return !m_children.empty();
+    }
+
+    virtual void addChild(Ptr<ITracker> const& child) CATCH_OVERRIDE
+    {
+        m_children.push_back(child);
+    }
+
+    virtual ITracker* findChild(std::string const& name) CATCH_OVERRIDE
+    {
+        Children::const_iterator it = std::find_if(m_children.begin(), m_children.end(), TrackerHasName(name));
+        return (it != m_children.end())
+                   ? it->get()
+                   : CATCH_NULL;
+    }
+    virtual ITracker& parent() CATCH_OVERRIDE
+    {
+        assert(m_parent); // Should always be non-null except for root
+        return *m_parent;
+    }
+
+    virtual void openChild() CATCH_OVERRIDE
+    {
+        if (m_runState != ExecutingChildren)
+        {
+            m_runState = ExecutingChildren;
+            if (m_parent)
+                m_parent->openChild();
+        }
+    }
+    void open()
+    {
+        m_runState = Executing;
+        moveToThis();
+        if (m_parent)
+            m_parent->openChild();
+    }
+
+    virtual void close() CATCH_OVERRIDE
+    {
+
+        // Close any still open children (e.g. generators)
+        while (&m_ctx.currentTracker() != this)
+            m_ctx.currentTracker().close();
+
+        switch (m_runState)
+        {
+        case NotStarted:
+        case CompletedSuccessfully:
+        case Failed:
+            throw std::logic_error("Illogical state");
+
+        case NeedsAnotherRun:
+            break;
+            ;
+
+        case Executing:
+            m_runState = CompletedSuccessfully;
+            break;
+        case ExecutingChildren:
+            if (m_children.empty() || m_children.back()->isComplete())
+                m_runState = CompletedSuccessfully;
+            break;
+
+        default:
+            throw std::logic_error("Unexpected state");
+        }
+        moveToParent();
+        m_ctx.completeCycle();
+    }
+    virtual void fail() CATCH_OVERRIDE
+    {
+        m_runState = Failed;
+        if (m_parent)
+            m_parent->markAsNeedingAnotherRun();
+        moveToParent();
+        m_ctx.completeCycle();
+    }
+    virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE
+    {
+        m_runState = NeedsAnotherRun;
+    }
+
+  private:
+    void moveToParent()
+    {
+        assert(m_parent);
+        m_ctx.setCurrentTracker(m_parent);
+    }
+    void moveToThis()
+    {
+        m_ctx.setCurrentTracker(this);
+    }
+};
+
+class SectionTracker : public TrackerBase
+{
+  public:
+    SectionTracker(std::string const& name, TrackerContext& ctx, ITracker* parent)
+        : TrackerBase(name, ctx, parent)
+    {
+    }
+    virtual ~SectionTracker();
+
+    static SectionTracker& acquire(TrackerContext& ctx, std::string const& name)
+    {
+        SectionTracker* section = CATCH_NULL;
+
+        ITracker& currentTracker = ctx.currentTracker();
+        if (ITracker* childTracker = currentTracker.findChild(name))
+        {
+            section = dynamic_cast<SectionTracker*>(childTracker);
+            assert(section);
+        }
+        else
+        {
+            section = new SectionTracker(name, ctx, &currentTracker);
+            currentTracker.addChild(section);
+        }
+        if (!ctx.completedCycle() && !section->isComplete())
+        {
+
+            section->open();
+        }
+        return *section;
+    }
+};
+
+class IndexTracker : public TrackerBase
+{
+    int m_size;
+    int m_index;
+
+  public:
+    IndexTracker(std::string const& name, TrackerContext& ctx, ITracker* parent, int size)
+        : TrackerBase(name, ctx, parent),
+          m_size(size),
+          m_index(-1)
+    {
+    }
+    virtual ~IndexTracker();
+
+    static IndexTracker& acquire(TrackerContext& ctx, std::string const& name, int size)
+    {
+        IndexTracker* tracker = CATCH_NULL;
+
+        ITracker& currentTracker = ctx.currentTracker();
+        if (ITracker* childTracker = currentTracker.findChild(name))
+        {
+            tracker = dynamic_cast<IndexTracker*>(childTracker);
+            assert(tracker);
+        }
+        else
+        {
+            tracker = new IndexTracker(name, ctx, &currentTracker, size);
+            currentTracker.addChild(tracker);
+        }
+
+        if (!ctx.completedCycle() && !tracker->isComplete())
+        {
+            if (tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun)
+                tracker->moveNext();
+            tracker->open();
+        }
+
+        return *tracker;
+    }
+
+    int index() const { return m_index; }
+
+    void moveNext()
+    {
+        m_index++;
+        m_children.clear();
+    }
+
+    virtual void close() CATCH_OVERRIDE
+    {
+        TrackerBase::close();
+        if (m_runState == CompletedSuccessfully && m_index < m_size - 1)
+            m_runState = Executing;
+    }
+};
+
+inline ITracker& TrackerContext::startRun()
+{
+    m_rootTracker = new SectionTracker("{root}", *this, CATCH_NULL);
+    m_currentTracker = CATCH_NULL;
+    m_runState = Executing;
+    return *m_rootTracker;
+}
+
+} // namespace TestCaseTracking
+
+using TestCaseTracking::ITracker;
+using TestCaseTracking::TrackerContext;
+using TestCaseTracking::SectionTracker;
+using TestCaseTracking::IndexTracker;
+
+} // namespace Catch
+
+// #included from: catch_fatal_condition.hpp
+#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
+
+namespace Catch {
+
+// Report the error condition then exit the process
+inline void fatal(std::string const& message, int exitCode)
+{
+    IContext& context = Catch::getCurrentContext();
+    IResultCapture* resultCapture = context.getResultCapture();
+    resultCapture->handleFatalErrorCondition(message);
+
+    if (Catch::alwaysTrue()) // avoids "no return" warnings
+        exit(exitCode);
+}
+
+} // namespace Catch
+
+#if defined(CATCH_PLATFORM_WINDOWS) /////////////////////////////////////////
+
+namespace Catch {
+
+struct FatalConditionHandler
+{
+    void reset() {}
+};
+
+} // namespace Catch
+
+#else // Not Windows - assumed to be POSIX compatible //////////////////////////
+
+#include <signal.h>
+
+namespace Catch {
+
+struct SignalDefs
+{
+    int id;
+    const char* name;
+};
+extern SignalDefs signalDefs[];
+SignalDefs signalDefs[] = {
+    {SIGINT, "SIGINT - Terminal interrupt signal"},
+    {SIGILL, "SIGILL - Illegal instruction signal"},
+    {SIGFPE, "SIGFPE - Floating point error signal"},
+    {SIGSEGV, "SIGSEGV - Segmentation violation signal"},
+    {SIGTERM, "SIGTERM - Termination request signal"},
+    {SIGABRT, "SIGABRT - Abort (abnormal termination) signal"}};
+
+struct FatalConditionHandler
+{
+
+    static void handleSignal(int sig)
+    {
+        for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i)
+            if (sig == signalDefs[i].id)
+                fatal(signalDefs[i].name, -sig);
+        fatal("<unknown signal>", -sig);
+    }
+
+    FatalConditionHandler() : m_isSet(true)
+    {
+        for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i)
+            signal(signalDefs[i].id, handleSignal);
+    }
+    ~FatalConditionHandler()
+    {
+        reset();
+    }
+    void reset()
+    {
+        if (m_isSet)
+        {
+            for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i)
+                signal(signalDefs[i].id, SIG_DFL);
+            m_isSet = false;
+        }
+    }
+
+    bool m_isSet;
+};
+
+} // namespace Catch
+
+#endif // not Windows
+
+#include <set>
+#include <string>
+
+namespace Catch {
+
+class StreamRedirect
+{
+
+  public:
+    StreamRedirect(std::ostream& stream, std::string& targetString)
+        : m_stream(stream),
+          m_prevBuf(stream.rdbuf()),
+          m_targetString(targetString)
+    {
+        stream.rdbuf(m_oss.rdbuf());
+    }
+
+    ~StreamRedirect()
+    {
+        m_targetString += m_oss.str();
+        m_stream.rdbuf(m_prevBuf);
+    }
+
+  private:
+    std::ostream& m_stream;
+    std::streambuf* m_prevBuf;
+    std::ostringstream m_oss;
+    std::string& m_targetString;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+class RunContext : public IResultCapture, public IRunner
+{
+
+    RunContext(RunContext const&);
+    void operator=(RunContext const&);
+
+  public:
+    explicit RunContext(Ptr<IConfig const> const& _config, Ptr<IStreamingReporter> const& reporter)
+        : m_runInfo(_config->name()),
+          m_context(getCurrentMutableContext()),
+          m_activeTestCase(CATCH_NULL),
+          m_config(_config),
+          m_reporter(reporter)
+    {
+        m_context.setRunner(this);
+        m_context.setConfig(m_config);
+        m_context.setResultCapture(this);
+        m_reporter->testRunStarting(m_runInfo);
+    }
+
+    virtual ~RunContext()
+    {
+        m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));
+    }
+
+    void testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount)
+    {
+        m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount));
+    }
+    void testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount)
+    {
+        m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting()));
+    }
+
+    Totals runTest(TestCase const& testCase)
+    {
+        Totals prevTotals = m_totals;
+
+        std::string redirectedCout;
+        std::string redirectedCerr;
+
+        TestCaseInfo testInfo = testCase.getTestCaseInfo();
+
+        m_reporter->testCaseStarting(testInfo);
+
+        m_activeTestCase = &testCase;
+
+        do
+        {
+            m_trackerContext.startRun();
+            do
+            {
+                m_trackerContext.startCycle();
+                m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, testInfo.name);
+                runCurrentTest(redirectedCout, redirectedCerr);
+            } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());
+        }
+        // !TBD: deprecated - this will be replaced by indexed trackers
+        while (getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting());
+
+        Totals deltaTotals = m_totals.delta(prevTotals);
+        m_totals.testCases += deltaTotals.testCases;
+        m_reporter->testCaseEnded(TestCaseStats(testInfo,
+                                                deltaTotals,
+                                                redirectedCout,
+                                                redirectedCerr,
+                                                aborting()));
+
+        m_activeTestCase = CATCH_NULL;
+        m_testCaseTracker = CATCH_NULL;
+
+        return deltaTotals;
+    }
+
+    Ptr<IConfig const> config() const
+    {
+        return m_config;
+    }
+
+  private: // IResultCapture
+    virtual void assertionEnded(AssertionResult const& result)
+    {
+        if (result.getResultType() == ResultWas::Ok)
+        {
+            m_totals.assertions.passed++;
+        }
+        else if (!result.isOk())
+        {
+            m_totals.assertions.failed++;
+        }
+
+        if (m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)))
+            m_messages.clear();
+
+        // Reset working state
+        m_lastAssertionInfo = AssertionInfo("", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}", m_lastAssertionInfo.resultDisposition);
+        m_lastResult = result;
+    }
+
+    virtual bool sectionStarted(
+        SectionInfo const& sectionInfo,
+        Counts& assertions)
+    {
+        std::ostringstream oss;
+        oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
+
+        ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, oss.str());
+        if (!sectionTracker.isOpen())
+            return false;
+        m_activeSections.push_back(&sectionTracker);
+
+        m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
+
+        m_reporter->sectionStarting(sectionInfo);
+
+        assertions = m_totals.assertions;
+
+        return true;
+    }
+    bool testForMissingAssertions(Counts& assertions)
+    {
+        if (assertions.total() != 0)
+            return false;
+        if (!m_config->warnAboutMissingAssertions())
+            return false;
+        if (m_trackerContext.currentTracker().hasChildren())
+            return false;
+        m_totals.assertions.failed++;
+        assertions.failed++;
+        return true;
+    }
+
+    virtual void sectionEnded(SectionEndInfo const& endInfo)
+    {
+        Counts assertions = m_totals.assertions - endInfo.prevAssertions;
+        bool missingAssertions = testForMissingAssertions(assertions);
+
+        if (!m_activeSections.empty())
+        {
+            m_activeSections.back()->close();
+            m_activeSections.pop_back();
+        }
+
+        m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
+        m_messages.clear();
+    }
+
+    virtual void sectionEndedEarly(SectionEndInfo const& endInfo)
+    {
+        if (m_unfinishedSections.empty())
+            m_activeSections.back()->fail();
+        else
+            m_activeSections.back()->close();
+        m_activeSections.pop_back();
+
+        m_unfinishedSections.push_back(endInfo);
+    }
+
+    virtual void pushScopedMessage(MessageInfo const& message)
+    {
+        m_messages.push_back(message);
+    }
+
+    virtual void popScopedMessage(MessageInfo const& message)
+    {
+        m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
+    }
+
+    virtual std::string getCurrentTestName() const
+    {
+        return m_activeTestCase
+                   ? m_activeTestCase->getTestCaseInfo().name
+                   : "";
+    }
+
+    virtual const AssertionResult* getLastResult() const
+    {
+        return &m_lastResult;
+    }
+
+    virtual void handleFatalErrorCondition(std::string const& message)
+    {
+        ResultBuilder resultBuilder = makeUnexpectedResultBuilder();
+        resultBuilder.setResultType(ResultWas::FatalErrorCondition);
+        resultBuilder << message;
+        resultBuilder.captureExpression();
+
+        handleUnfinishedSections();
+
+        // Recreate section for test case (as we will lose the one that was in scope)
+        TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+        SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description);
+
+        Counts assertions;
+        assertions.failed = 1;
+        SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false);
+        m_reporter->sectionEnded(testCaseSectionStats);
+
+        TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo();
+
+        Totals deltaTotals;
+        deltaTotals.testCases.failed = 1;
+        m_reporter->testCaseEnded(TestCaseStats(testInfo,
+                                                deltaTotals,
+                                                "",
+                                                "",
+                                                false));
+        m_totals.testCases.failed++;
+        testGroupEnded("", m_totals, 1, 1);
+        m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
+    }
+
+  public:
+    // !TBD We need to do this another way!
+    bool aborting() const
+    {
+        return m_totals.assertions.failed == static_cast<std::size_t>(m_config->abortAfter());
+    }
+
+  private:
+    void runCurrentTest(std::string& redirectedCout, std::string& redirectedCerr)
+    {
+        TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+        SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description);
+        m_reporter->sectionStarting(testCaseSection);
+        Counts prevAssertions = m_totals.assertions;
+        double duration = 0;
+        try
+        {
+            m_lastAssertionInfo = AssertionInfo("TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal);
+
+            seedRng(*m_config);
+
+            Timer timer;
+            timer.start();
+            if (m_reporter->getPreferences().shouldRedirectStdOut)
+            {
+                StreamRedirect coutRedir(Catch::cout(), redirectedCout);
+                StreamRedirect cerrRedir(Catch::cerr(), redirectedCerr);
+                invokeActiveTestCase();
+            }
+            else
+            {
+                invokeActiveTestCase();
+            }
+            duration = timer.getElapsedSeconds();
+        }
+        catch (TestFailureException&)
+        {
+            // This just means the test was aborted due to failure
+        }
+        catch (...)
+        {
+            makeUnexpectedResultBuilder().useActiveException();
+        }
+        m_testCaseTracker->close();
+        handleUnfinishedSections();
+        m_messages.clear();
+
+        Counts assertions = m_totals.assertions - prevAssertions;
+        bool missingAssertions = testForMissingAssertions(assertions);
+
+        if (testCaseInfo.okToFail())
+        {
+            std::swap(assertions.failedButOk, assertions.failed);
+            m_totals.assertions.failed -= assertions.failedButOk;
+            m_totals.assertions.failedButOk += assertions.failedButOk;
+        }
+
+        SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
+        m_reporter->sectionEnded(testCaseSectionStats);
+    }
+
+    void invokeActiveTestCase()
+    {
+        FatalConditionHandler fatalConditionHandler; // Handle signals
+        m_activeTestCase->invoke();
+        fatalConditionHandler.reset();
+    }
+
+  private:
+    ResultBuilder makeUnexpectedResultBuilder() const
+    {
+        return ResultBuilder(m_lastAssertionInfo.macroName.c_str(),
+                             m_lastAssertionInfo.lineInfo,
+                             m_lastAssertionInfo.capturedExpression.c_str(),
+                             m_lastAssertionInfo.resultDisposition);
+    }
+
+    void handleUnfinishedSections()
+    {
+        // If sections ended prematurely due to an exception we stored their
+        // infos here so we can tear them down outside the unwind process.
+        for (std::vector<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
+                                                                 itEnd = m_unfinishedSections.rend();
+             it != itEnd;
+             ++it)
+            sectionEnded(*it);
+        m_unfinishedSections.clear();
+    }
+
+    TestRunInfo m_runInfo;
+    IMutableContext& m_context;
+    TestCase const* m_activeTestCase;
+    ITracker* m_testCaseTracker;
+    ITracker* m_currentSectionTracker;
+    AssertionResult m_lastResult;
+
+    Ptr<IConfig const> m_config;
+    Totals m_totals;
+    Ptr<IStreamingReporter> m_reporter;
+    std::vector<MessageInfo> m_messages;
+    AssertionInfo m_lastAssertionInfo;
+    std::vector<SectionEndInfo> m_unfinishedSections;
+    std::vector<ITracker*> m_activeSections;
+    TrackerContext m_trackerContext;
+};
+
+IResultCapture& getResultCapture()
+{
+    if (IResultCapture* capture = getCurrentContext().getResultCapture())
+        return *capture;
+    else
+        throw std::logic_error("No result capture instance");
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_version.h
+#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED
+
+namespace Catch {
+
+// Versioning information
+struct Version
+{
+    Version(unsigned int _majorVersion,
+            unsigned int _minorVersion,
+            unsigned int _patchNumber,
+            std::string const& _branchName,
+            unsigned int _buildNumber);
+
+    unsigned int const majorVersion;
+    unsigned int const minorVersion;
+    unsigned int const patchNumber;
+
+    // buildNumber is only used if branchName is not null
+    std::string const branchName;
+    unsigned int const buildNumber;
+
+    friend std::ostream& operator<<(std::ostream& os, Version const& version);
+
+  private:
+    void operator=(Version const&);
+};
+
+extern Version libraryVersion;
+}
+
+#include <fstream>
+#include <limits>
+#include <stdlib.h>
+
+namespace Catch {
+
+Ptr<IStreamingReporter> createReporter(std::string const& reporterName, Ptr<Config> const& config)
+{
+    Ptr<IStreamingReporter> reporter = getRegistryHub().getReporterRegistry().create(reporterName, config.get());
+    if (!reporter)
+    {
+        std::ostringstream oss;
+        oss << "No reporter registered with name: '" << reporterName << "'";
+        throw std::domain_error(oss.str());
+    }
+    return reporter;
+}
+
+Ptr<IStreamingReporter> makeReporter(Ptr<Config> const& config)
+{
+    std::vector<std::string> reporters = config->getReporterNames();
+    if (reporters.empty())
+        reporters.push_back("console");
+
+    Ptr<IStreamingReporter> reporter;
+    for (std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end();
+         it != itEnd;
+         ++it)
+        reporter = addReporter(reporter, createReporter(*it, config));
+    return reporter;
+}
+Ptr<IStreamingReporter> addListeners(Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters)
+{
+    IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners();
+    for (IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end();
+         it != itEnd;
+         ++it)
+        reporters = addReporter(reporters, (*it)->create(ReporterConfig(config)));
+    return reporters;
+}
+
+Totals runTests(Ptr<Config> const& config)
+{
+
+    Ptr<IConfig const> iconfig = config.get();
+
+    Ptr<IStreamingReporter> reporter = makeReporter(config);
+    reporter = addListeners(iconfig, reporter);
+
+    RunContext context(iconfig, reporter);
+
+    Totals totals;
+
+    context.testGroupStarting(config->name(), 1, 1);
+
+    TestSpec testSpec = config->testSpec();
+    if (!testSpec.hasFilters())
+        testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("~[.]").testSpec(); // All not hidden tests
+
+    std::vector<TestCase> const& allTestCases = getAllTestCasesSorted(*iconfig);
+    for (std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end();
+         it != itEnd;
+         ++it)
+    {
+        if (!context.aborting() && matchTest(*it, testSpec, *iconfig))
+            totals += context.runTest(*it);
+        else
+            reporter->skipTest(*it);
+    }
+
+    context.testGroupEnded(iconfig->name(), totals, 1, 1);
+    return totals;
+}
+
+void applyFilenamesAsTags(IConfig const& config)
+{
+    std::vector<TestCase> const& tests = getAllTestCasesSorted(config);
+    for (std::size_t i = 0; i < tests.size(); ++i)
+    {
+        TestCase& test = const_cast<TestCase&>(tests[i]);
+        std::set<std::string> tags = test.tags;
+
+        std::string filename = test.lineInfo.file;
+        std::string::size_type lastSlash = filename.find_last_of("\\/");
+        if (lastSlash != std::string::npos)
+            filename = filename.substr(lastSlash + 1);
+
+        std::string::size_type lastDot = filename.find_last_of(".");
+        if (lastDot != std::string::npos)
+            filename = filename.substr(0, lastDot);
+
+        tags.insert("#" + filename);
+        setTags(test, tags);
+    }
+}
+
+class Session : NonCopyable
+{
+    static bool alreadyInstantiated;
+
+  public:
+    struct OnUnusedOptions
+    {
+        enum DoWhat
+        {
+            Ignore,
+            Fail
+        };
+    };
+
+    Session()
+        : m_cli(makeCommandLineParser())
+    {
+        if (alreadyInstantiated)
+        {
+            std::string msg = "Only one instance of Catch::Session can ever be used";
+            Catch::cerr() << msg << std::endl;
+            throw std::logic_error(msg);
+        }
+        alreadyInstantiated = true;
+    }
+    ~Session()
+    {
+        Catch::cleanUp();
+    }
+
+    void showHelp(std::string const& processName)
+    {
+        Catch::cout() << "\nCatch v" << libraryVersion << "\n";
+
+        m_cli.usage(Catch::cout(), processName);
+        Catch::cout() << "For more detail usage please see the project docs\n"
+                      << std::endl;
+    }
+
+    int applyCommandLine(int argc, char const* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail)
+    {
+        try
+        {
+            m_cli.setThrowOnUnrecognisedTokens(unusedOptionBehaviour == OnUnusedOptions::Fail);
+            m_unusedTokens = m_cli.parseInto(argc, argv, m_configData);
+            if (m_configData.showHelp)
+                showHelp(m_configData.processName);
+            m_config.reset();
+        }
+        catch (std::exception& ex)
+        {
+            {
+                Colour colourGuard(Colour::Red);
+                Catch::cerr()
+                    << "\nError(s) in input:\n"
+                    << Text(ex.what(), TextAttributes().setIndent(2))
+                    << "\n\n";
+            }
+            m_cli.usage(Catch::cout(), m_configData.processName);
+            return (std::numeric_limits<int>::max)();
+        }
+        return 0;
+    }
+
+    void useConfigData(ConfigData const& _configData)
+    {
+        m_configData = _configData;
+        m_config.reset();
+    }
+
+    int run(int argc, char const* const argv[])
+    {
+
+        int returnCode = applyCommandLine(argc, argv);
+        if (returnCode == 0)
+            returnCode = run();
+        return returnCode;
+    }
+
+    int run()
+    {
+        if (m_configData.showHelp)
+            return 0;
+
+        try
+        {
+            config(); // Force config to be constructed
+
+            seedRng(*m_config);
+
+            if (m_configData.filenamesAsTags)
+                applyFilenamesAsTags(*m_config);
+
+            // Handle list request
+            if (Option<std::size_t> listed = list(config()))
+                return static_cast<int>(*listed);
+
+            return static_cast<int>(runTests(m_config).assertions.failed);
+        }
+        catch (std::exception& ex)
+        {
+            Catch::cerr() << ex.what() << std::endl;
+            return (std::numeric_limits<int>::max)();
+        }
+    }
+
+    Clara::CommandLine<ConfigData> const& cli() const
+    {
+        return m_cli;
+    }
+    std::vector<Clara::Parser::Token> const& unusedTokens() const
+    {
+        return m_unusedTokens;
+    }
+    ConfigData& configData()
+    {
+        return m_configData;
+    }
+    Config& config()
+    {
+        if (!m_config)
+            m_config = new Config(m_configData);
+        return *m_config;
+    }
+
+  private:
+    Clara::CommandLine<ConfigData> m_cli;
+    std::vector<Clara::Parser::Token> m_unusedTokens;
+    ConfigData m_configData;
+    Ptr<Config> m_config;
+};
+
+bool Session::alreadyInstantiated = false;
+
+} // end namespace Catch
+
+// #included from: catch_registry_hub.hpp
+#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED
+
+// #included from: catch_test_case_registry_impl.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
+
+#include <algorithm>
+#include <iostream>
+#include <set>
+#include <sstream>
+#include <vector>
+
+namespace Catch {
+
+struct LexSort
+{
+    bool operator()(TestCase i, TestCase j) const { return (i < j); }
+};
+struct RandomNumberGenerator
+{
+    int operator()(int n) const { return std::rand() % n; }
+};
+
+inline std::vector<TestCase> sortTests(IConfig const& config, std::vector<TestCase> const& unsortedTestCases)
+{
+
+    std::vector<TestCase> sorted = unsortedTestCases;
+
+    switch (config.runOrder())
+    {
+    case RunTests::InLexicographicalOrder:
+        std::sort(sorted.begin(), sorted.end(), LexSort());
+        break;
+    case RunTests::InRandomOrder:
+    {
+        seedRng(config);
+
+        RandomNumberGenerator rng;
+        std::random_shuffle(sorted.begin(), sorted.end(), rng);
+    }
+    break;
+    case RunTests::InDeclarationOrder:
+        // already in declaration order
+        break;
+    }
+    return sorted;
+}
+bool matchTest(TestCase const& testCase, TestSpec const& testSpec, IConfig const& config)
+{
+    return testSpec.matches(testCase) && (config.allowThrows() || !testCase.throws());
+}
+
+void enforceNoDuplicateTestCases(std::vector<TestCase> const& functions)
+{
+    std::set<TestCase> seenFunctions;
+    for (std::vector<TestCase>::const_iterator it = functions.begin(), itEnd = functions.end();
+         it != itEnd;
+         ++it)
+    {
+        std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert(*it);
+        if (!prev.second)
+        {
+            Catch::cerr()
+                << Colour(Colour::Red)
+                << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
+                << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
+                << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
+            exit(1);
+        }
+    }
+}
+
+std::vector<TestCase> filterTests(std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config)
+{
+    std::vector<TestCase> filtered;
+    filtered.reserve(testCases.size());
+    for (std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
+         it != itEnd;
+         ++it)
+        if (matchTest(*it, testSpec, config))
+            filtered.push_back(*it);
+    return filtered;
+}
+std::vector<TestCase> const& getAllTestCasesSorted(IConfig const& config)
+{
+    return getRegistryHub().getTestCaseRegistry().getAllTestsSorted(config);
+}
+
+class TestRegistry : public ITestCaseRegistry
+{
+  public:
+    TestRegistry()
+        : m_currentSortOrder(RunTests::InDeclarationOrder),
+          m_unnamedCount(0)
+    {
+    }
+    virtual ~TestRegistry();
+
+    virtual void registerTest(TestCase const& testCase)
+    {
+        std::string name = testCase.getTestCaseInfo().name;
+        if (name == "")
+        {
+            std::ostringstream oss;
+            oss << "Anonymous test case " << ++m_unnamedCount;
+            return registerTest(testCase.withName(oss.str()));
+        }
+        m_functions.push_back(testCase);
+    }
+
+    virtual std::vector<TestCase> const& getAllTests() const
+    {
+        return m_functions;
+    }
+    virtual std::vector<TestCase> const& getAllTestsSorted(IConfig const& config) const
+    {
+        if (m_sortedFunctions.empty())
+            enforceNoDuplicateTestCases(m_functions);
+
+        if (m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty())
+        {
+            m_sortedFunctions = sortTests(config, m_functions);
+            m_currentSortOrder = config.runOrder();
+        }
+        return m_sortedFunctions;
+    }
+
+  private:
+    std::vector<TestCase> m_functions;
+    mutable RunTests::InWhatOrder m_currentSortOrder;
+    mutable std::vector<TestCase> m_sortedFunctions;
+    size_t m_unnamedCount;
+    std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+class FreeFunctionTestCase : public SharedImpl<ITestCase>
+{
+  public:
+    FreeFunctionTestCase(TestFunction fun) : m_fun(fun) {}
+
+    virtual void invoke() const
+    {
+        m_fun();
+    }
+
+  private:
+    virtual ~FreeFunctionTestCase();
+
+    TestFunction m_fun;
+};
+
+inline std::string extractClassName(std::string const& classOrQualifiedMethodName)
+{
+    std::string className = classOrQualifiedMethodName;
+    if (startsWith(className, "&"))
+    {
+        std::size_t lastColons = className.rfind("::");
+        std::size_t penultimateColons = className.rfind("::", lastColons - 1);
+        if (penultimateColons == std::string::npos)
+            penultimateColons = 1;
+        className = className.substr(penultimateColons, lastColons - penultimateColons);
+    }
+    return className;
+}
+
+void registerTestCase(ITestCase* testCase,
+                      char const* classOrQualifiedMethodName,
+                      NameAndDesc const& nameAndDesc,
+                      SourceLineInfo const& lineInfo)
+{
+
+    getMutableRegistryHub().registerTest(makeTestCase(testCase,
+                                                      extractClassName(classOrQualifiedMethodName),
+                                                      nameAndDesc.name,
+                                                      nameAndDesc.description,
+                                                      lineInfo));
+}
+void registerTestCaseFunction(TestFunction function,
+                              SourceLineInfo const& lineInfo,
+                              NameAndDesc const& nameAndDesc)
+{
+    registerTestCase(new FreeFunctionTestCase(function), "", nameAndDesc, lineInfo);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+AutoReg::AutoReg(TestFunction function,
+                 SourceLineInfo const& lineInfo,
+                 NameAndDesc const& nameAndDesc)
+{
+    registerTestCaseFunction(function, lineInfo, nameAndDesc);
+}
+
+AutoReg::~AutoReg() {}
+
+} // end namespace Catch
+
+// #included from: catch_reporter_registry.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+class ReporterRegistry : public IReporterRegistry
+{
+
+  public:
+    virtual ~ReporterRegistry() CATCH_OVERRIDE {}
+
+    virtual IStreamingReporter* create(std::string const& name, Ptr<IConfig const> const& config) const CATCH_OVERRIDE
+    {
+        FactoryMap::const_iterator it = m_factories.find(name);
+        if (it == m_factories.end())
+            return CATCH_NULL;
+        return it->second->create(ReporterConfig(config));
+    }
+
+    void registerReporter(std::string const& name, Ptr<IReporterFactory> const& factory)
+    {
+        m_factories.insert(std::make_pair(name, factory));
+    }
+    void registerListener(Ptr<IReporterFactory> const& factory)
+    {
+        m_listeners.push_back(factory);
+    }
+
+    virtual FactoryMap const& getFactories() const CATCH_OVERRIDE
+    {
+        return m_factories;
+    }
+    virtual Listeners const& getListeners() const CATCH_OVERRIDE
+    {
+        return m_listeners;
+    }
+
+  private:
+    FactoryMap m_factories;
+    Listeners m_listeners;
+};
+}
+
+// #included from: catch_exception_translator_registry.hpp
+#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
+
+#ifdef __OBJC__
+#import "Foundation/Foundation.h"
+#endif
+
+namespace Catch {
+
+class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry
+{
+  public:
+    ~ExceptionTranslatorRegistry()
+    {
+        deleteAll(m_translators);
+    }
+
+    virtual void registerTranslator(const IExceptionTranslator* translator)
+    {
+        m_translators.push_back(translator);
+    }
+
+    virtual std::string translateActiveException() const
+    {
+        try
+        {
+#ifdef __OBJC__
+            // In Objective-C try objective-c exceptions first
+            @try
+            {
+                return tryTranslators();
+            }
+            @catch (NSException* exception)
+            {
+                return Catch::toString([exception description]);
+            }
+#else
+            return tryTranslators();
+#endif
+        }
+        catch (TestFailureException&)
+        {
+            throw;
+        }
+        catch (std::exception& ex)
+        {
+            return ex.what();
+        }
+        catch (std::string& msg)
+        {
+            return msg;
+        }
+        catch (const char* msg)
+        {
+            return msg;
+        }
+        catch (...)
+        {
+            return "Unknown exception";
+        }
+    }
+
+    std::string tryTranslators() const
+    {
+        if (m_translators.empty())
+            throw;
+        else
+            return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end());
+    }
+
+  private:
+    std::vector<const IExceptionTranslator*> m_translators;
+};
+}
+
+namespace Catch {
+
+namespace {
+
+class RegistryHub : public IRegistryHub, public IMutableRegistryHub
+{
+
+    RegistryHub(RegistryHub const&);
+    void operator=(RegistryHub const&);
+
+  public: // IRegistryHub
+    RegistryHub()
+    {
+    }
+    virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE
+    {
+        return m_reporterRegistry;
+    }
+    virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE
+    {
+        return m_testCaseRegistry;
+    }
+    virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE
+    {
+        return m_exceptionTranslatorRegistry;
+    }
+
+  public: // IMutableRegistryHub
+    virtual void registerReporter(std::string const& name, Ptr<IReporterFactory> const& factory) CATCH_OVERRIDE
+    {
+        m_reporterRegistry.registerReporter(name, factory);
+    }
+    virtual void registerListener(Ptr<IReporterFactory> const& factory) CATCH_OVERRIDE
+    {
+        m_reporterRegistry.registerListener(factory);
+    }
+    virtual void registerTest(TestCase const& testInfo) CATCH_OVERRIDE
+    {
+        m_testCaseRegistry.registerTest(testInfo);
+    }
+    virtual void registerTranslator(const IExceptionTranslator* translator) CATCH_OVERRIDE
+    {
+        m_exceptionTranslatorRegistry.registerTranslator(translator);
+    }
+
+  private:
+    TestRegistry m_testCaseRegistry;
+    ReporterRegistry m_reporterRegistry;
+    ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
+};
+
+// Single, global, instance
+inline RegistryHub*& getTheRegistryHub()
+{
+    static RegistryHub* theRegistryHub = CATCH_NULL;
+    if (!theRegistryHub)
+        theRegistryHub = new RegistryHub();
+    return theRegistryHub;
+}
+}
+
+IRegistryHub& getRegistryHub()
+{
+    return *getTheRegistryHub();
+}
+IMutableRegistryHub& getMutableRegistryHub()
+{
+    return *getTheRegistryHub();
+}
+void cleanUp()
+{
+    delete getTheRegistryHub();
+    getTheRegistryHub() = CATCH_NULL;
+    cleanUpContext();
+}
+std::string translateActiveException()
+{
+    return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
+}
+
+} // end namespace Catch
+
+// #included from: catch_notimplemented_exception.hpp
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
+
+#include <ostream>
+
+namespace Catch {
+
+NotImplementedException::NotImplementedException(SourceLineInfo const& lineInfo)
+    : m_lineInfo(lineInfo)
+{
+    std::ostringstream oss;
+    oss << lineInfo << ": function ";
+    oss << "not implemented";
+    m_what = oss.str();
+}
+
+const char* NotImplementedException::what() const CATCH_NOEXCEPT
+{
+    return m_what.c_str();
+}
+
+} // end namespace Catch
+
+// #included from: catch_context_impl.hpp
+#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
+
+// #included from: catch_stream.hpp
+#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
+
+#include <cstdio>
+#include <iostream>
+#include <stdexcept>
+
+namespace Catch {
+
+template <typename WriterF, size_t bufferSize = 256>
+class StreamBufImpl : public StreamBufBase
+{
+    char data[bufferSize];
+    WriterF m_writer;
+
+  public:
+    StreamBufImpl()
+    {
+        setp(data, data + sizeof(data));
+    }
+
+    ~StreamBufImpl() CATCH_NOEXCEPT
+    {
+        sync();
+    }
+
+  private:
+    int overflow(int c)
+    {
+        sync();
+
+        if (c != EOF)
+        {
+            if (pbase() == epptr())
+                m_writer(std::string(1, static_cast<char>(c)));
+            else
+                sputc(static_cast<char>(c));
+        }
+        return 0;
+    }
+
+    int sync()
+    {
+        if (pbase() != pptr())
+        {
+            m_writer(std::string(pbase(), static_cast<std::string::size_type>(pptr() - pbase())));
+            setp(pbase(), epptr());
+        }
+        return 0;
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+FileStream::FileStream(std::string const& filename)
+{
+    m_ofs.open(filename.c_str());
+    if (m_ofs.fail())
+    {
+        std::ostringstream oss;
+        oss << "Unable to open file: '" << filename << "'";
+        throw std::domain_error(oss.str());
+    }
+}
+
+std::ostream& FileStream::stream() const
+{
+    return m_ofs;
+}
+
+struct OutputDebugWriter
+{
+
+    void operator()(std::string const& str)
+    {
+        writeToDebugConsole(str);
+    }
+};
+
+DebugOutStream::DebugOutStream()
+    : m_streamBuf(new StreamBufImpl<OutputDebugWriter>()),
+      m_os(m_streamBuf.get())
+{
+}
+
+std::ostream& DebugOutStream::stream() const
+{
+    return m_os;
+}
+
+// Store the streambuf from cout up-front because
+// cout may get redirected when running tests
+CoutStream::CoutStream()
+    : m_os(Catch::cout().rdbuf())
+{
+}
+
+std::ostream& CoutStream::stream() const
+{
+    return m_os;
+}
+
+#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions
+std::ostream& cout()
+{
+    return std::cout;
+}
+std::ostream& cerr()
+{
+    return std::cerr;
+}
+#endif
+}
+
+namespace Catch {
+
+class Context : public IMutableContext
+{
+
+    Context() : m_config(CATCH_NULL), m_runner(CATCH_NULL), m_resultCapture(CATCH_NULL) {}
+    Context(Context const&);
+    void operator=(Context const&);
+
+  public: // IContext
+    virtual IResultCapture* getResultCapture()
+    {
+        return m_resultCapture;
+    }
+    virtual IRunner* getRunner()
+    {
+        return m_runner;
+    }
+    virtual size_t getGeneratorIndex(std::string const& fileInfo, size_t totalSize)
+    {
+        return getGeneratorsForCurrentTest()
+            .getGeneratorInfo(fileInfo, totalSize)
+            .getCurrentIndex();
+    }
+    virtual bool advanceGeneratorsForCurrentTest()
+    {
+        IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+        return generators && generators->moveNext();
+    }
+
+    virtual Ptr<IConfig const> getConfig() const
+    {
+        return m_config;
+    }
+
+  public: // IMutableContext
+    virtual void setResultCapture(IResultCapture* resultCapture)
+    {
+        m_resultCapture = resultCapture;
+    }
+    virtual void setRunner(IRunner* runner)
+    {
+        m_runner = runner;
+    }
+    virtual void setConfig(Ptr<IConfig const> const& config)
+    {
+        m_config = config;
+    }
+
+    friend IMutableContext& getCurrentMutableContext();
+
+  private:
+    IGeneratorsForTest* findGeneratorsForCurrentTest()
+    {
+        std::string testName = getResultCapture()->getCurrentTestName();
+
+        std::map<std::string, IGeneratorsForTest*>::const_iterator it =
+            m_generatorsByTestName.find(testName);
+        return it != m_generatorsByTestName.end()
+                   ? it->second
+                   : CATCH_NULL;
+    }
+
+    IGeneratorsForTest& getGeneratorsForCurrentTest()
+    {
+        IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+        if (!generators)
+        {
+            std::string testName = getResultCapture()->getCurrentTestName();
+            generators = createGeneratorsForTest();
+            m_generatorsByTestName.insert(std::make_pair(testName, generators));
+        }
+        return *generators;
+    }
+
+  private:
+    Ptr<IConfig const> m_config;
+    IRunner* m_runner;
+    IResultCapture* m_resultCapture;
+    std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
+};
+
+namespace {
+Context* currentContext = CATCH_NULL;
+}
+IMutableContext& getCurrentMutableContext()
+{
+    if (!currentContext)
+        currentContext = new Context();
+    return *currentContext;
+}
+IContext& getCurrentContext()
+{
+    return getCurrentMutableContext();
+}
+
+void cleanUpContext()
+{
+    delete currentContext;
+    currentContext = CATCH_NULL;
+}
+}
+
+// #included from: catch_console_colour_impl.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
+
+namespace Catch {
+namespace {
+
+struct IColourImpl
+{
+    virtual ~IColourImpl() {}
+    virtual void use(Colour::Code _colourCode) = 0;
+};
+
+struct NoColourImpl : IColourImpl
+{
+    void use(Colour::Code) {}
+
+    static IColourImpl* instance()
+    {
+        static NoColourImpl s_instance;
+        return &s_instance;
+    }
+};
+
+} // anon namespace
+} // namespace Catch
+
+#if !defined(CATCH_CONFIG_COLOUR_NONE) && !defined(CATCH_CONFIG_COLOUR_WINDOWS) && !defined(CATCH_CONFIG_COLOUR_ANSI)
+#ifdef CATCH_PLATFORM_WINDOWS
+#define CATCH_CONFIG_COLOUR_WINDOWS
+#else
+#define CATCH_CONFIG_COLOUR_ANSI
+#endif
+#endif
+
+#if defined(CATCH_CONFIG_COLOUR_WINDOWS) /////////////////////////////////////////
+
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+#ifdef __AFXDLL
+#include <AfxWin.h>
+#else
+#include <windows.h>
+#endif
+
+namespace Catch {
+namespace {
+
+class Win32ColourImpl : public IColourImpl
+{
+  public:
+    Win32ColourImpl() : stdoutHandle(GetStdHandle(STD_OUTPUT_HANDLE))
+    {
+        CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
+        GetConsoleScreenBufferInfo(stdoutHandle, &csbiInfo);
+        originalForegroundAttributes = csbiInfo.wAttributes & ~(BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
+        originalBackgroundAttributes = csbiInfo.wAttributes & ~(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
+    }
+
+    virtual void use(Colour::Code _colourCode)
+    {
+        switch (_colourCode)
+        {
+        case Colour::None:
+            return setTextAttribute(originalForegroundAttributes);
+        case Colour::White:
+            return setTextAttribute(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE);
+        case Colour::Red:
+            return setTextAttribute(FOREGROUND_RED);
+        case Colour::Green:
+            return setTextAttribute(FOREGROUND_GREEN);
+        case Colour::Blue:
+            return setTextAttribute(FOREGROUND_BLUE);
+        case Colour::Cyan:
+            return setTextAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN);
+        case Colour::Yellow:
+            return setTextAttribute(FOREGROUND_RED | FOREGROUND_GREEN);
+        case Colour::Grey:
+            return setTextAttribute(0);
+
+        case Colour::LightGrey:
+            return setTextAttribute(FOREGROUND_INTENSITY);
+        case Colour::BrightRed:
+            return setTextAttribute(FOREGROUND_INTENSITY | FOREGROUND_RED);
+        case Colour::BrightGreen:
+            return setTextAttribute(FOREGROUND_INTENSITY | FOREGROUND_GREEN);
+        case Colour::BrightWhite:
+            return setTextAttribute(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE);
+
+        case Colour::Bright:
+            throw std::logic_error("not a colour");
+        }
+    }
+
+  private:
+    void setTextAttribute(WORD _textAttribute)
+    {
+        SetConsoleTextAttribute(stdoutHandle, _textAttribute | originalBackgroundAttributes);
+    }
+    HANDLE stdoutHandle;
+    WORD originalForegroundAttributes;
+    WORD originalBackgroundAttributes;
+};
+
+IColourImpl* platformColourInstance()
+{
+    static Win32ColourImpl s_instance;
+    return &s_instance;
+}
+
+} // end anon namespace
+} // end namespace Catch
+
+#elif defined(CATCH_CONFIG_COLOUR_ANSI) //////////////////////////////////////
+
+#include <unistd.h>
+
+namespace Catch {
+namespace {
+
+// use POSIX/ ANSI console terminal codes
+// Thanks to Adam Strzelecki for original contribution
+// (http://github.com/nanoant)
+// https://github.com/philsquared/Catch/pull/131
+class PosixColourImpl : public IColourImpl
+{
+  public:
+    virtual void use(Colour::Code _colourCode)
+    {
+        switch (_colourCode)
+        {
+        case Colour::None:
+        case Colour::White:
+            return setColour("[0m");
+        case Colour::Red:
+            return setColour("[0;31m");
+        case Colour::Green:
+            return setColour("[0;32m");
+        case Colour::Blue:
+            return setColour("[0:34m");
+        case Colour::Cyan:
+            return setColour("[0;36m");
+        case Colour::Yellow:
+            return setColour("[0;33m");
+        case Colour::Grey:
+            return setColour("[1;30m");
+
+        case Colour::LightGrey:
+            return setColour("[0;37m");
+        case Colour::BrightRed:
+            return setColour("[1;31m");
+        case Colour::BrightGreen:
+            return setColour("[1;32m");
+        case Colour::BrightWhite:
+            return setColour("[1;37m");
+
+        case Colour::Bright:
+            throw std::logic_error("not a colour");
+        }
+    }
+    static IColourImpl* instance()
+    {
+        static PosixColourImpl s_instance;
+        return &s_instance;
+    }
+
+  private:
+    void setColour(const char* _escapeCode)
+    {
+        Catch::cout() << '\033' << _escapeCode;
+    }
+};
+
+IColourImpl* platformColourInstance()
+{
+    Ptr<IConfig const> config = getCurrentContext().getConfig();
+    return (config && config->forceColour()) || isatty(STDOUT_FILENO)
+               ? PosixColourImpl::instance()
+               : NoColourImpl::instance();
+}
+
+} // end anon namespace
+} // end namespace Catch
+
+#else // not Windows or ANSI ///////////////////////////////////////////////
+
+namespace Catch {
+
+static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); }
+
+} // end namespace Catch
+
+#endif // Windows/ ANSI/ None
+
+namespace Catch {
+
+Colour::Colour(Code _colourCode) : m_moved(false) { use(_colourCode); }
+Colour::Colour(Colour const& _other) : m_moved(false) { const_cast<Colour&>(_other).m_moved = true; }
+Colour::~Colour()
+{
+    if (!m_moved) use(None);
+}
+
+void Colour::use(Code _colourCode)
+{
+    static IColourImpl* impl = isDebuggerActive()
+                                   ? NoColourImpl::instance()
+                                   : platformColourInstance();
+    impl->use(_colourCode);
+}
+
+} // end namespace Catch
+
+// #included from: catch_generators_impl.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+struct GeneratorInfo : IGeneratorInfo
+{
+
+    GeneratorInfo(std::size_t size)
+        : m_size(size),
+          m_currentIndex(0)
+    {
+    }
+
+    bool moveNext()
+    {
+        if (++m_currentIndex == m_size)
+        {
+            m_currentIndex = 0;
+            return false;
+        }
+        return true;
+    }
+
+    std::size_t getCurrentIndex() const
+    {
+        return m_currentIndex;
+    }
+
+    std::size_t m_size;
+    std::size_t m_currentIndex;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+class GeneratorsForTest : public IGeneratorsForTest
+{
+
+  public:
+    ~GeneratorsForTest()
+    {
+        deleteAll(m_generatorsInOrder);
+    }
+
+    IGeneratorInfo& getGeneratorInfo(std::string const& fileInfo, std::size_t size)
+    {
+        std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find(fileInfo);
+        if (it == m_generatorsByName.end())
+        {
+            IGeneratorInfo* info = new GeneratorInfo(size);
+            m_generatorsByName.insert(std::make_pair(fileInfo, info));
+            m_generatorsInOrder.push_back(info);
+            return *info;
+        }
+        return *it->second;
+    }
+
+    bool moveNext()
+    {
+        std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
+        std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
+        for (; it != itEnd; ++it)
+        {
+            if ((*it)->moveNext())
+                return true;
+        }
+        return false;
+    }
+
+  private:
+    std::map<std::string, IGeneratorInfo*> m_generatorsByName;
+    std::vector<IGeneratorInfo*> m_generatorsInOrder;
+};
+
+IGeneratorsForTest* createGeneratorsForTest()
+{
+    return new GeneratorsForTest();
+}
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.hpp
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
+
+namespace Catch {
+
+AssertionInfo::AssertionInfo(std::string const& _macroName,
+                             SourceLineInfo const& _lineInfo,
+                             std::string const& _capturedExpression,
+                             ResultDisposition::Flags _resultDisposition)
+    : macroName(_macroName),
+      lineInfo(_lineInfo),
+      capturedExpression(_capturedExpression),
+      resultDisposition(_resultDisposition)
+{
+}
+
+AssertionResult::AssertionResult() {}
+
+AssertionResult::AssertionResult(AssertionInfo const& info, AssertionResultData const& data)
+    : m_info(info),
+      m_resultData(data)
+{
+}
+
+AssertionResult::~AssertionResult() {}
+
+// Result was a success
+bool AssertionResult::succeeded() const
+{
+    return Catch::isOk(m_resultData.resultType);
+}
+
+// Result was a success, or failure is suppressed
+bool AssertionResult::isOk() const
+{
+    return Catch::isOk(m_resultData.resultType) || shouldSuppressFailure(m_info.resultDisposition);
+}
+
+ResultWas::OfType AssertionResult::getResultType() const
+{
+    return m_resultData.resultType;
+}
+
+bool AssertionResult::hasExpression() const
+{
+    return !m_info.capturedExpression.empty();
+}
+
+bool AssertionResult::hasMessage() const
+{
+    return !m_resultData.message.empty();
+}
+
+std::string AssertionResult::getExpression() const
+{
+    if (isFalseTest(m_info.resultDisposition))
+        return "!" + m_info.capturedExpression;
+    else
+        return m_info.capturedExpression;
+}
+std::string AssertionResult::getExpressionInMacro() const
+{
+    if (m_info.macroName.empty())
+        return m_info.capturedExpression;
+    else
+        return m_info.macroName + "( " + m_info.capturedExpression + " )";
+}
+
+bool AssertionResult::hasExpandedExpression() const
+{
+    return hasExpression() && getExpandedExpression() != getExpression();
+}
+
+std::string AssertionResult::getExpandedExpression() const
+{
+    return m_resultData.reconstructedExpression;
+}
+
+std::string AssertionResult::getMessage() const
+{
+    return m_resultData.message;
+}
+SourceLineInfo AssertionResult::getSourceInfo() const
+{
+    return m_info.lineInfo;
+}
+
+std::string AssertionResult::getTestMacroName() const
+{
+    return m_info.macroName;
+}
+
+} // end namespace Catch
+
+// #included from: catch_test_case_info.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
+
+namespace Catch {
+
+inline TestCaseInfo::SpecialProperties parseSpecialTag(std::string const& tag)
+{
+    if (startsWith(tag, ".") ||
+        tag == "hide" ||
+        tag == "!hide")
+        return TestCaseInfo::IsHidden;
+    else if (tag == "!throws")
+        return TestCaseInfo::Throws;
+    else if (tag == "!shouldfail")
+        return TestCaseInfo::ShouldFail;
+    else if (tag == "!mayfail")
+        return TestCaseInfo::MayFail;
+    else
+        return TestCaseInfo::None;
+}
+inline bool isReservedTag(std::string const& tag)
+{
+    return parseSpecialTag(tag) == TestCaseInfo::None && tag.size() > 0 && !isalnum(tag[0]);
+}
+inline void enforceNotReservedTag(std::string const& tag, SourceLineInfo const& _lineInfo)
+{
+    if (isReservedTag(tag))
+    {
+        {
+            Colour colourGuard(Colour::Red);
+            Catch::cerr()
+                << "Tag name [" << tag << "] not allowed.\n"
+                << "Tag names starting with non alpha-numeric characters are reserved\n";
+        }
+        {
+            Colour colourGuard(Colour::FileName);
+            Catch::cerr() << _lineInfo << std::endl;
+        }
+        exit(1);
+    }
+}
+
+TestCase makeTestCase(ITestCase* _testCase,
+                      std::string const& _className,
+                      std::string const& _name,
+                      std::string const& _descOrTags,
+                      SourceLineInfo const& _lineInfo)
+{
+    bool isHidden(startsWith(_name, "./")); // Legacy support
+
+    // Parse out tags
+    std::set<std::string> tags;
+    std::string desc, tag;
+    bool inTag = false;
+    for (std::size_t i = 0; i < _descOrTags.size(); ++i)
+    {
+        char c = _descOrTags[i];
+        if (!inTag)
+        {
+            if (c == '[')
+                inTag = true;
+            else
+                desc += c;
+        }
+        else
+        {
+            if (c == ']')
+            {
+                TestCaseInfo::SpecialProperties prop = parseSpecialTag(tag);
+                if (prop == TestCaseInfo::IsHidden)
+                    isHidden = true;
+                else if (prop == TestCaseInfo::None)
+                    enforceNotReservedTag(tag, _lineInfo);
+
+                tags.insert(tag);
+                tag.clear();
+                inTag = false;
+            }
+            else
+                tag += c;
+        }
+    }
+    if (isHidden)
+    {
+        tags.insert("hide");
+        tags.insert(".");
+    }
+
+    TestCaseInfo info(_name, _className, desc, tags, _lineInfo);
+    return TestCase(_testCase, info);
+}
+
+void setTags(TestCaseInfo& testCaseInfo, std::set<std::string> const& tags)
+{
+    testCaseInfo.tags = tags;
+    testCaseInfo.lcaseTags.clear();
+
+    std::ostringstream oss;
+    for (std::set<std::string>::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it)
+    {
+        oss << "[" << *it << "]";
+        std::string lcaseTag = toLower(*it);
+        testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>(testCaseInfo.properties | parseSpecialTag(lcaseTag));
+        testCaseInfo.lcaseTags.insert(lcaseTag);
+    }
+    testCaseInfo.tagsAsString = oss.str();
+}
+
+TestCaseInfo::TestCaseInfo(std::string const& _name,
+                           std::string const& _className,
+                           std::string const& _description,
+                           std::set<std::string> const& _tags,
+                           SourceLineInfo const& _lineInfo)
+    : name(_name),
+      className(_className),
+      description(_description),
+      lineInfo(_lineInfo),
+      properties(None)
+{
+    setTags(*this, _tags);
+}
+
+TestCaseInfo::TestCaseInfo(TestCaseInfo const& other)
+    : name(other.name),
+      className(other.className),
+      description(other.description),
+      tags(other.tags),
+      lcaseTags(other.lcaseTags),
+      tagsAsString(other.tagsAsString),
+      lineInfo(other.lineInfo),
+      properties(other.properties)
+{
+}
+
+bool TestCaseInfo::isHidden() const
+{
+    return (properties & IsHidden) != 0;
+}
+bool TestCaseInfo::throws() const
+{
+    return (properties & Throws) != 0;
+}
+bool TestCaseInfo::okToFail() const
+{
+    return (properties & (ShouldFail | MayFail)) != 0;
+}
+bool TestCaseInfo::expectedToFail() const
+{
+    return (properties & (ShouldFail)) != 0;
+}
+
+TestCase::TestCase(ITestCase* testCase, TestCaseInfo const& info) : TestCaseInfo(info), test(testCase) {}
+
+TestCase::TestCase(TestCase const& other)
+    : TestCaseInfo(other),
+      test(other.test)
+{
+}
+
+TestCase TestCase::withName(std::string const& _newName) const
+{
+    TestCase other(*this);
+    other.name = _newName;
+    return other;
+}
+
+void TestCase::swap(TestCase& other)
+{
+    test.swap(other.test);
+    name.swap(other.name);
+    className.swap(other.className);
+    description.swap(other.description);
+    tags.swap(other.tags);
+    lcaseTags.swap(other.lcaseTags);
+    tagsAsString.swap(other.tagsAsString);
+    std::swap(TestCaseInfo::properties, static_cast<TestCaseInfo&>(other).properties);
+    std::swap(lineInfo, other.lineInfo);
+}
+
+void TestCase::invoke() const
+{
+    test->invoke();
+}
+
+bool TestCase::operator==(TestCase const& other) const
+{
+    return test.get() == other.test.get() &&
+           name == other.name &&
+           className == other.className;
+}
+
+bool TestCase::operator<(TestCase const& other) const
+{
+    return name < other.name;
+}
+TestCase& TestCase::operator=(TestCase const& other)
+{
+    TestCase temp(other);
+    swap(temp);
+    return *this;
+}
+
+TestCaseInfo const& TestCase::getTestCaseInfo() const
+{
+    return *this;
+}
+
+} // end namespace Catch
+
+// #included from: catch_version.hpp
+#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED
+
+namespace Catch {
+
+Version::Version(unsigned int _majorVersion,
+                 unsigned int _minorVersion,
+                 unsigned int _patchNumber,
+                 std::string const& _branchName,
+                 unsigned int _buildNumber)
+    : majorVersion(_majorVersion),
+      minorVersion(_minorVersion),
+      patchNumber(_patchNumber),
+      branchName(_branchName),
+      buildNumber(_buildNumber)
+{
+}
+
+std::ostream& operator<<(std::ostream& os, Version const& version)
+{
+    os << version.majorVersion << "."
+       << version.minorVersion << "."
+       << version.patchNumber;
+
+    if (!version.branchName.empty())
+    {
+        os << "-" << version.branchName
+           << "." << version.buildNumber;
+    }
+    return os;
+}
+
+Version libraryVersion(1, 3, 2, "", 0);
+}
+
+// #included from: catch_message.hpp
+#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED
+
+namespace Catch {
+
+MessageInfo::MessageInfo(std::string const& _macroName,
+                         SourceLineInfo const& _lineInfo,
+                         ResultWas::OfType _type)
+    : macroName(_macroName),
+      lineInfo(_lineInfo),
+      type(_type),
+      sequence(++globalCount)
+{
+}
+
+// This may need protecting if threading support is added
+unsigned int MessageInfo::globalCount = 0;
+
+////////////////////////////////////////////////////////////////////////////
+
+ScopedMessage::ScopedMessage(MessageBuilder const& builder)
+    : m_info(builder.m_info)
+{
+    m_info.message = builder.m_stream.str();
+    getResultCapture().pushScopedMessage(m_info);
+}
+ScopedMessage::ScopedMessage(ScopedMessage const& other)
+    : m_info(other.m_info)
+{
+}
+
+ScopedMessage::~ScopedMessage()
+{
+    getResultCapture().popScopedMessage(m_info);
+}
+
+} // end namespace Catch
+
+// #included from: catch_legacy_reporter_adapter.hpp
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
+
+// #included from: catch_legacy_reporter_adapter.h
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
+
+namespace Catch {
+// Deprecated
+struct IReporter : IShared
+{
+    virtual ~IReporter();
+
+    virtual bool shouldRedirectStdout() const = 0;
+
+    virtual void StartTesting() = 0;
+    virtual void EndTesting(Totals const& totals) = 0;
+    virtual void StartGroup(std::string const& groupName) = 0;
+    virtual void EndGroup(std::string const& groupName, Totals const& totals) = 0;
+    virtual void StartTestCase(TestCaseInfo const& testInfo) = 0;
+    virtual void EndTestCase(TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr) = 0;
+    virtual void StartSection(std::string const& sectionName, std::string const& description) = 0;
+    virtual void EndSection(std::string const& sectionName, Counts const& assertions) = 0;
+    virtual void NoAssertionsInSection(std::string const& sectionName) = 0;
+    virtual void NoAssertionsInTestCase(std::string const& testName) = 0;
+    virtual void Aborted() = 0;
+    virtual void Result(AssertionResult const& result) = 0;
+};
+
+class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
+{
+  public:
+    LegacyReporterAdapter(Ptr<IReporter> const& legacyReporter);
+    virtual ~LegacyReporterAdapter();
+
+    virtual ReporterPreferences getPreferences() const;
+    virtual void noMatchingTestCases(std::string const&);
+    virtual void testRunStarting(TestRunInfo const&);
+    virtual void testGroupStarting(GroupInfo const& groupInfo);
+    virtual void testCaseStarting(TestCaseInfo const& testInfo);
+    virtual void sectionStarting(SectionInfo const& sectionInfo);
+    virtual void assertionStarting(AssertionInfo const&);
+    virtual bool assertionEnded(AssertionStats const& assertionStats);
+    virtual void sectionEnded(SectionStats const& sectionStats);
+    virtual void testCaseEnded(TestCaseStats const& testCaseStats);
+    virtual void testGroupEnded(TestGroupStats const& testGroupStats);
+    virtual void testRunEnded(TestRunStats const& testRunStats);
+    virtual void skipTest(TestCaseInfo const&);
+
+  private:
+    Ptr<IReporter> m_legacyReporter;
+};
+}
+
+namespace Catch {
+LegacyReporterAdapter::LegacyReporterAdapter(Ptr<IReporter> const& legacyReporter)
+    : m_legacyReporter(legacyReporter)
+{
+}
+LegacyReporterAdapter::~LegacyReporterAdapter() {}
+
+ReporterPreferences LegacyReporterAdapter::getPreferences() const
+{
+    ReporterPreferences prefs;
+    prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout();
+    return prefs;
+}
+
+void LegacyReporterAdapter::noMatchingTestCases(std::string const&) {}
+void LegacyReporterAdapter::testRunStarting(TestRunInfo const&)
+{
+    m_legacyReporter->StartTesting();
+}
+void LegacyReporterAdapter::testGroupStarting(GroupInfo const& groupInfo)
+{
+    m_legacyReporter->StartGroup(groupInfo.name);
+}
+void LegacyReporterAdapter::testCaseStarting(TestCaseInfo const& testInfo)
+{
+    m_legacyReporter->StartTestCase(testInfo);
+}
+void LegacyReporterAdapter::sectionStarting(SectionInfo const& sectionInfo)
+{
+    m_legacyReporter->StartSection(sectionInfo.name, sectionInfo.description);
+}
+void LegacyReporterAdapter::assertionStarting(AssertionInfo const&)
+{
+    // Not on legacy interface
+}
+
+bool LegacyReporterAdapter::assertionEnded(AssertionStats const& assertionStats)
+{
+    if (assertionStats.assertionResult.getResultType() != ResultWas::Ok)
+    {
+        for (std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+             it != itEnd;
+             ++it)
+        {
+            if (it->type == ResultWas::Info)
+            {
+                ResultBuilder rb(it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal);
+                rb << it->message;
+                rb.setResultType(ResultWas::Info);
+                AssertionResult result = rb.build();
+                m_legacyReporter->Result(result);
+            }
+        }
+    }
+    m_legacyReporter->Result(assertionStats.assertionResult);
+    return true;
+}
+void LegacyReporterAdapter::sectionEnded(SectionStats const& sectionStats)
+{
+    if (sectionStats.missingAssertions)
+        m_legacyReporter->NoAssertionsInSection(sectionStats.sectionInfo.name);
+    m_legacyReporter->EndSection(sectionStats.sectionInfo.name, sectionStats.assertions);
+}
+void LegacyReporterAdapter::testCaseEnded(TestCaseStats const& testCaseStats)
+{
+    m_legacyReporter->EndTestCase(testCaseStats.testInfo,
+                                  testCaseStats.totals,
+                                  testCaseStats.stdOut,
+                                  testCaseStats.stdErr);
+}
+void LegacyReporterAdapter::testGroupEnded(TestGroupStats const& testGroupStats)
+{
+    if (testGroupStats.aborting)
+        m_legacyReporter->Aborted();
+    m_legacyReporter->EndGroup(testGroupStats.groupInfo.name, testGroupStats.totals);
+}
+void LegacyReporterAdapter::testRunEnded(TestRunStats const& testRunStats)
+{
+    m_legacyReporter->EndTesting(testRunStats.totals);
+}
+void LegacyReporterAdapter::skipTest(TestCaseInfo const&)
+{
+}
+}
+
+// #included from: catch_timer.hpp
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++11-long-long"
+#endif
+
+#ifdef CATCH_PLATFORM_WINDOWS
+#include <windows.h>
+#else
+#include <sys/time.h>
+#endif
+
+namespace Catch {
+
+namespace {
+#ifdef CATCH_PLATFORM_WINDOWS
+uint64_t getCurrentTicks()
+{
+    static uint64_t hz = 0, hzo = 0;
+    if (!hz)
+    {
+        QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(&hz));
+        QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&hzo));
+    }
+    uint64_t t;
+    QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&t));
+    return ((t - hzo) * 1000000) / hz;
+}
+#else
+uint64_t getCurrentTicks()
+{
+    timeval t;
+    gettimeofday(&t, CATCH_NULL);
+    return static_cast<uint64_t>(t.tv_sec) * 1000000ull + static_cast<uint64_t>(t.tv_usec);
+}
+#endif
+}
+
+void Timer::start()
+{
+    m_ticks = getCurrentTicks();
+}
+unsigned int Timer::getElapsedMicroseconds() const
+{
+    return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
+}
+unsigned int Timer::getElapsedMilliseconds() const
+{
+    return static_cast<unsigned int>(getElapsedMicroseconds() / 1000);
+}
+double Timer::getElapsedSeconds() const
+{
+    return getElapsedMicroseconds() / 1000000.0;
+}
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+// #included from: catch_common.hpp
+#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
+
+namespace Catch {
+
+bool startsWith(std::string const& s, std::string const& prefix)
+{
+    return s.size() >= prefix.size() && s.substr(0, prefix.size()) == prefix;
+}
+bool endsWith(std::string const& s, std::string const& suffix)
+{
+    return s.size() >= suffix.size() && s.substr(s.size() - suffix.size(), suffix.size()) == suffix;
+}
+bool contains(std::string const& s, std::string const& infix)
+{
+    return s.find(infix) != std::string::npos;
+}
+void toLowerInPlace(std::string& s)
+{
+    std::transform(s.begin(), s.end(), s.begin(), ::tolower);
+}
+std::string toLower(std::string const& s)
+{
+    std::string lc = s;
+    toLowerInPlace(lc);
+    return lc;
+}
+std::string trim(std::string const& str)
+{
+    static char const* whitespaceChars = "\n\r\t ";
+    std::string::size_type start = str.find_first_not_of(whitespaceChars);
+    std::string::size_type end = str.find_last_not_of(whitespaceChars);
+
+    return start != std::string::npos ? str.substr(start, 1 + end - start) : "";
+}
+
+bool replaceInPlace(std::string& str, std::string const& replaceThis, std::string const& withThis)
+{
+    bool replaced = false;
+    std::size_t i = str.find(replaceThis);
+    while (i != std::string::npos)
+    {
+        replaced = true;
+        str = str.substr(0, i) + withThis + str.substr(i + replaceThis.size());
+        if (i < str.size() - withThis.size())
+            i = str.find(replaceThis, i + withThis.size());
+        else
+            i = std::string::npos;
+    }
+    return replaced;
+}
+
+pluralise::pluralise(std::size_t count, std::string const& label)
+    : m_count(count),
+      m_label(label)
+{
+}
+
+std::ostream& operator<<(std::ostream& os, pluralise const& pluraliser)
+{
+    os << pluraliser.m_count << " " << pluraliser.m_label;
+    if (pluraliser.m_count != 1)
+        os << "s";
+    return os;
+}
+
+SourceLineInfo::SourceLineInfo() : line(0) {}
+SourceLineInfo::SourceLineInfo(char const* _file, std::size_t _line)
+    : file(_file),
+      line(_line)
+{
+}
+SourceLineInfo::SourceLineInfo(SourceLineInfo const& other)
+    : file(other.file),
+      line(other.line)
+{
+}
+bool SourceLineInfo::empty() const
+{
+    return file.empty();
+}
+bool SourceLineInfo::operator==(SourceLineInfo const& other) const
+{
+    return line == other.line && file == other.file;
+}
+bool SourceLineInfo::operator<(SourceLineInfo const& other) const
+{
+    return line < other.line || (line == other.line && file < other.file);
+}
+
+void seedRng(IConfig const& config)
+{
+    if (config.rngSeed() != 0)
+        std::srand(config.rngSeed());
+}
+unsigned int rngSeed()
+{
+    return getCurrentContext().getConfig()->rngSeed();
+}
+
+std::ostream& operator<<(std::ostream& os, SourceLineInfo const& info)
+{
+#ifndef __GNUG__
+    os << info.file << "(" << info.line << ")";
+#else
+    os << info.file << ":" << info.line;
+#endif
+    return os;
+}
+
+void throwLogicError(std::string const& message, SourceLineInfo const& locationInfo)
+{
+    std::ostringstream oss;
+    oss << locationInfo << ": Internal Catch error: '" << message << "'";
+    if (alwaysTrue())
+        throw std::logic_error(oss.str());
+}
+}
+
+// #included from: catch_section.hpp
+#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
+
+namespace Catch {
+
+SectionInfo::SectionInfo(SourceLineInfo const& _lineInfo,
+                         std::string const& _name,
+                         std::string const& _description)
+    : name(_name),
+      description(_description),
+      lineInfo(_lineInfo)
+{
+}
+
+Section::Section(SectionInfo const& info)
+    : m_info(info),
+      m_sectionIncluded(getResultCapture().sectionStarted(m_info, m_assertions))
+{
+    m_timer.start();
+}
+
+Section::~Section()
+{
+    if (m_sectionIncluded)
+    {
+        SectionEndInfo endInfo(m_info, m_assertions, m_timer.getElapsedSeconds());
+        if (std::uncaught_exception())
+            getResultCapture().sectionEndedEarly(endInfo);
+        else
+            getResultCapture().sectionEnded(endInfo);
+    }
+}
+
+// This indicates whether the section should be executed or not
+Section::operator bool() const
+{
+    return m_sectionIncluded;
+}
+
+} // end namespace Catch
+
+// #included from: catch_debugger.hpp
+#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
+
+#include <iostream>
+
+#ifdef CATCH_PLATFORM_MAC
+
+#include <assert.h>
+#include <stdbool.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace Catch {
+
+// The following function is taken directly from the following technical note:
+// http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
+
+// Returns true if the current process is being debugged (either
+// running under the debugger or has a debugger attached post facto).
+bool isDebuggerActive()
+{
+
+    int mib[4];
+    struct kinfo_proc info;
+    size_t size;
+
+    // Initialize the flags so that, if sysctl fails for some bizarre
+    // reason, we get a predictable result.
+
+    info.kp_proc.p_flag = 0;
+
+    // Initialize mib, which tells sysctl the info we want, in this case
+    // we're looking for information about a specific process ID.
+
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_PROC;
+    mib[2] = KERN_PROC_PID;
+    mib[3] = getpid();
+
+    // Call sysctl.
+
+    size = sizeof(info);
+    if (sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0)
+    {
+        Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n"
+                      << std::endl;
+        return false;
+    }
+
+    // We're being debugged if the P_TRACED flag is set.
+
+    return ((info.kp_proc.p_flag & P_TRACED) != 0);
+}
+} // namespace Catch
+
+#elif defined(_MSC_VER)
+extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+namespace Catch {
+bool isDebuggerActive()
+{
+    return IsDebuggerPresent() != 0;
+}
+}
+#elif defined(__MINGW32__)
+extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+namespace Catch {
+bool isDebuggerActive()
+{
+    return IsDebuggerPresent() != 0;
+}
+}
+#else
+namespace Catch {
+inline bool isDebuggerActive() { return false; }
+}
+#endif // Platform
+
+#ifdef CATCH_PLATFORM_WINDOWS
+extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char*);
+namespace Catch {
+void writeToDebugConsole(std::string const& text)
+{
+    ::OutputDebugStringA(text.c_str());
+}
+}
+#else
+namespace Catch {
+void writeToDebugConsole(std::string const& text)
+{
+    // !TBD: Need a version for Mac/ XCode and other IDEs
+    Catch::cout() << text;
+}
+}
+#endif // Platform
+
+// #included from: catch_tostring.hpp
+#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
+
+namespace Catch {
+
+namespace Detail {
+
+const std::string unprintableString = "{?}";
+
+namespace {
+const int hexThreshold = 255;
+
+struct Endianness
+{
+    enum Arch
+    {
+        Big,
+        Little
+    };
+
+    static Arch which()
+    {
+        union _
+        {
+            int asInt;
+            char asChar[sizeof(int)];
+        } u;
+
+        u.asInt = 1;
+        return (u.asChar[sizeof(int) - 1] == 1) ? Big : Little;
+    }
+};
+}
+
+std::string rawMemoryToString(const void* object, std::size_t size)
+{
+    // Reverse order for little endian architectures
+    int i = 0, end = static_cast<int>(size), inc = 1;
+    if (Endianness::which() == Endianness::Little)
+    {
+        i = end - 1;
+        end = inc = -1;
+    }
+
+    unsigned char const* bytes = static_cast<unsigned char const*>(object);
+    std::ostringstream os;
+    os << "0x" << std::setfill('0') << std::hex;
+    for (; i != end; i += inc)
+        os << std::setw(2) << static_cast<unsigned>(bytes[i]);
+    return os.str();
+}
+}
+
+std::string toString(std::string const& value)
+{
+    std::string s = value;
+    if (getCurrentContext().getConfig()->showInvisibles())
+    {
+        for (size_t i = 0; i < s.size(); ++i)
+        {
+            std::string subs;
+            switch (s[i])
+            {
+            case '\n':
+                subs = "\\n";
+                break;
+            case '\t':
+                subs = "\\t";
+                break;
+            default:
+                break;
+            }
+            if (!subs.empty())
+            {
+                s = s.substr(0, i) + subs + s.substr(i + 1);
+                ++i;
+            }
+        }
+    }
+    return "\"" + s + "\"";
+}
+std::string toString(std::wstring const& value)
+{
+
+    std::string s;
+    s.reserve(value.size());
+    for (size_t i = 0; i < value.size(); ++i)
+        s += value[i] <= 0xff ? static_cast<char>(value[i]) : '?';
+    return Catch::toString(s);
+}
+
+std::string toString(const char* const value)
+{
+    return value ? Catch::toString(std::string(value)) : std::string("{null string}");
+}
+
+std::string toString(char* const value)
+{
+    return Catch::toString(static_cast<const char*>(value));
+}
+
+std::string toString(const wchar_t* const value)
+{
+    return value ? Catch::toString(std::wstring(value)) : std::string("{null string}");
+}
+
+std::string toString(wchar_t* const value)
+{
+    return Catch::toString(static_cast<const wchar_t*>(value));
+}
+
+std::string toString(int value)
+{
+    std::ostringstream oss;
+    oss << value;
+    if (value > Detail::hexThreshold)
+        oss << " (0x" << std::hex << value << ")";
+    return oss.str();
+}
+
+std::string toString(unsigned long value)
+{
+    std::ostringstream oss;
+    oss << value;
+    if (value > Detail::hexThreshold)
+        oss << " (0x" << std::hex << value << ")";
+    return oss.str();
+}
+
+std::string toString(unsigned int value)
+{
+    return Catch::toString(static_cast<unsigned long>(value));
+}
+
+template <typename T>
+std::string fpToString(T value, int precision)
+{
+    std::ostringstream oss;
+    oss << std::setprecision(precision)
+        << std::fixed
+        << value;
+    std::string d = oss.str();
+    std::size_t i = d.find_last_not_of('0');
+    if (i != std::string::npos && i != d.size() - 1)
+    {
+        if (d[i] == '.')
+            i++;
+        d = d.substr(0, i + 1);
+    }
+    return d;
+}
+
+std::string toString(const double value)
+{
+    return fpToString(value, 10);
+}
+std::string toString(const float value)
+{
+    return fpToString(value, 5) + "f";
+}
+
+std::string toString(bool value)
+{
+    return value ? "true" : "false";
+}
+
+std::string toString(char value)
+{
+    return value < ' '
+               ? toString(static_cast<unsigned int>(value))
+               : Detail::makeString(value);
+}
+
+std::string toString(signed char value)
+{
+    return toString(static_cast<char>(value));
+}
+
+std::string toString(unsigned char value)
+{
+    return toString(static_cast<char>(value));
+}
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+std::string toString(long long value)
+{
+    std::ostringstream oss;
+    oss << value;
+    if (value > Detail::hexThreshold)
+        oss << " (0x" << std::hex << value << ")";
+    return oss.str();
+}
+std::string toString(unsigned long long value)
+{
+    std::ostringstream oss;
+    oss << value;
+    if (value > Detail::hexThreshold)
+        oss << " (0x" << std::hex << value << ")";
+    return oss.str();
+}
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString(std::nullptr_t)
+{
+    return "nullptr";
+}
+#endif
+
+#ifdef __OBJC__
+std::string toString(NSString const* const& nsstring)
+{
+    if (!nsstring)
+        return "nil";
+    return "@" + toString([nsstring UTF8String]);
+}
+std::string toString(NSString* CATCH_ARC_STRONG const& nsstring)
+{
+    if (!nsstring)
+        return "nil";
+    return "@" + toString([nsstring UTF8String]);
+}
+std::string toString(NSObject* const& nsObject)
+{
+    return toString([nsObject description]);
+}
+#endif
+
+} // end namespace Catch
+
+// #included from: catch_result_builder.hpp
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED
+
+namespace Catch {
+
+std::string capturedExpressionWithSecondArgument(std::string const& capturedExpression, std::string const& secondArg)
+{
+    return secondArg.empty() || secondArg == "\"\""
+               ? capturedExpression
+               : capturedExpression + ", " + secondArg;
+}
+ResultBuilder::ResultBuilder(char const* macroName,
+                             SourceLineInfo const& lineInfo,
+                             char const* capturedExpression,
+                             ResultDisposition::Flags resultDisposition,
+                             char const* secondArg)
+    : m_assertionInfo(macroName, lineInfo, capturedExpressionWithSecondArgument(capturedExpression, secondArg), resultDisposition),
+      m_shouldDebugBreak(false),
+      m_shouldThrow(false)
+{
+}
+
+ResultBuilder& ResultBuilder::setResultType(ResultWas::OfType result)
+{
+    m_data.resultType = result;
+    return *this;
+}
+ResultBuilder& ResultBuilder::setResultType(bool result)
+{
+    m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
+    return *this;
+}
+ResultBuilder& ResultBuilder::setLhs(std::string const& lhs)
+{
+    m_exprComponents.lhs = lhs;
+    return *this;
+}
+ResultBuilder& ResultBuilder::setRhs(std::string const& rhs)
+{
+    m_exprComponents.rhs = rhs;
+    return *this;
+}
+ResultBuilder& ResultBuilder::setOp(std::string const& op)
+{
+    m_exprComponents.op = op;
+    return *this;
+}
+
+void ResultBuilder::endExpression()
+{
+    m_exprComponents.testFalse = isFalseTest(m_assertionInfo.resultDisposition);
+    captureExpression();
+}
+
+void ResultBuilder::useActiveException(ResultDisposition::Flags resultDisposition)
+{
+    m_assertionInfo.resultDisposition = resultDisposition;
+    m_stream.oss << Catch::translateActiveException();
+    captureResult(ResultWas::ThrewException);
+}
+
+void ResultBuilder::captureResult(ResultWas::OfType resultType)
+{
+    setResultType(resultType);
+    captureExpression();
+}
+void ResultBuilder::captureExpectedException(std::string const& expectedMessage)
+{
+    if (expectedMessage.empty())
+        captureExpectedException(Matchers::Impl::Generic::AllOf<std::string>());
+    else
+        captureExpectedException(Matchers::Equals(expectedMessage));
+}
+
+void ResultBuilder::captureExpectedException(Matchers::Impl::Matcher<std::string> const& matcher)
+{
+
+    assert(m_exprComponents.testFalse == false);
+    AssertionResultData data = m_data;
+    data.resultType = ResultWas::Ok;
+    data.reconstructedExpression = m_assertionInfo.capturedExpression;
+
+    std::string actualMessage = Catch::translateActiveException();
+    if (!matcher.match(actualMessage))
+    {
+        data.resultType = ResultWas::ExpressionFailed;
+        data.reconstructedExpression = actualMessage;
+    }
+    AssertionResult result(m_assertionInfo, data);
+    handleResult(result);
+}
+
+void ResultBuilder::captureExpression()
+{
+    AssertionResult result = build();
+    handleResult(result);
+}
+void ResultBuilder::handleResult(AssertionResult const& result)
+{
+    getResultCapture().assertionEnded(result);
+
+    if (!result.isOk())
+    {
+        if (getCurrentContext().getConfig()->shouldDebugBreak())
+            m_shouldDebugBreak = true;
+        if (getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal))
+            m_shouldThrow = true;
+    }
+}
+void ResultBuilder::react()
+{
+    if (m_shouldThrow)
+        throw Catch::TestFailureException();
+}
+
+bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; }
+bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); }
+
+AssertionResult ResultBuilder::build() const
+{
+    assert(m_data.resultType != ResultWas::Unknown);
+
+    AssertionResultData data = m_data;
+
+    // Flip bool results if testFalse is set
+    if (m_exprComponents.testFalse)
+    {
+        if (data.resultType == ResultWas::Ok)
+            data.resultType = ResultWas::ExpressionFailed;
+        else if (data.resultType == ResultWas::ExpressionFailed)
+            data.resultType = ResultWas::Ok;
+    }
+
+    data.message = m_stream.oss.str();
+    data.reconstructedExpression = reconstructExpression();
+    if (m_exprComponents.testFalse)
+    {
+        if (m_exprComponents.op == "")
+            data.reconstructedExpression = "!" + data.reconstructedExpression;
+        else
+            data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
+    }
+    return AssertionResult(m_assertionInfo, data);
+}
+std::string ResultBuilder::reconstructExpression() const
+{
+    if (m_exprComponents.op == "")
+        return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs;
+    else if (m_exprComponents.op == "matches")
+        return m_exprComponents.lhs + " " + m_exprComponents.rhs;
+    else if (m_exprComponents.op != "!")
+    {
+        if (m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 &&
+            m_exprComponents.lhs.find("\n") == std::string::npos &&
+            m_exprComponents.rhs.find("\n") == std::string::npos)
+            return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs;
+        else
+            return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs;
+    }
+    else
+        return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}";
+}
+
+} // end namespace Catch
+
+// #included from: catch_tag_alias_registry.hpp
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
+
+// #included from: catch_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+class TagAliasRegistry : public ITagAliasRegistry
+{
+  public:
+    virtual ~TagAliasRegistry();
+    virtual Option<TagAlias> find(std::string const& alias) const;
+    virtual std::string expandAliases(std::string const& unexpandedTestSpec) const;
+    void add(char const* alias, char const* tag, SourceLineInfo const& lineInfo);
+    static TagAliasRegistry& get();
+
+  private:
+    std::map<std::string, TagAlias> m_registry;
+};
+
+} // end namespace Catch
+
+#include <iostream>
+#include <map>
+
+namespace Catch {
+
+TagAliasRegistry::~TagAliasRegistry() {}
+
+Option<TagAlias> TagAliasRegistry::find(std::string const& alias) const
+{
+    std::map<std::string, TagAlias>::const_iterator it = m_registry.find(alias);
+    if (it != m_registry.end())
+        return it->second;
+    else
+        return Option<TagAlias>();
+}
+
+std::string TagAliasRegistry::expandAliases(std::string const& unexpandedTestSpec) const
+{
+    std::string expandedTestSpec = unexpandedTestSpec;
+    for (std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end();
+         it != itEnd;
+         ++it)
+    {
+        std::size_t pos = expandedTestSpec.find(it->first);
+        if (pos != std::string::npos)
+        {
+            expandedTestSpec = expandedTestSpec.substr(0, pos) +
+                               it->second.tag +
+                               expandedTestSpec.substr(pos + it->first.size());
+        }
+    }
+    return expandedTestSpec;
+}
+
+void TagAliasRegistry::add(char const* alias, char const* tag, SourceLineInfo const& lineInfo)
+{
+
+    if (!startsWith(alias, "[@") || !endsWith(alias, "]"))
+    {
+        std::ostringstream oss;
+        oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n"
+            << lineInfo;
+        throw std::domain_error(oss.str().c_str());
+    }
+    if (!m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second)
+    {
+        std::ostringstream oss;
+        oss << "error: tag alias, \"" << alias << "\" already registered.\n"
+            << "\tFirst seen at " << find(alias)->lineInfo << "\n"
+            << "\tRedefined at " << lineInfo;
+        throw std::domain_error(oss.str().c_str());
+    }
+}
+
+TagAliasRegistry& TagAliasRegistry::get()
+{
+    static TagAliasRegistry instance;
+    return instance;
+}
+
+ITagAliasRegistry::~ITagAliasRegistry() {}
+ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); }
+
+RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo)
+{
+    try
+    {
+        TagAliasRegistry::get().add(alias, tag, lineInfo);
+    }
+    catch (std::exception& ex)
+    {
+        Colour colourGuard(Colour::Red);
+        Catch::cerr() << ex.what() << std::endl;
+        exit(1);
+    }
+}
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_multi.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED
+
+namespace Catch {
+
+class MultipleReporters : public SharedImpl<IStreamingReporter>
+{
+    typedef std::vector<Ptr<IStreamingReporter>> Reporters;
+    Reporters m_reporters;
+
+  public:
+    void add(Ptr<IStreamingReporter> const& reporter)
+    {
+        m_reporters.push_back(reporter);
+    }
+
+  public: // IStreamingReporter
+    virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE
+    {
+        return m_reporters[0]->getPreferences();
+    }
+
+    virtual void noMatchingTestCases(std::string const& spec) CATCH_OVERRIDE
+    {
+        for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+             it != itEnd;
+             ++it)
+            (*it)->noMatchingTestCases(spec);
+    }
+
+    virtual void testRunStarting(TestRunInfo const& testRunInfo) CATCH_OVERRIDE
+    {
+        for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+             it != itEnd;
+             ++it)
+            (*it)->testRunStarting(testRunInfo);
+    }
+
+    virtual void testGroupStarting(GroupInfo const& groupInfo) CATCH_OVERRIDE
+    {
+        for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+             it != itEnd;
+             ++it)
+            (*it)->testGroupStarting(groupInfo);
+    }
+
+    virtual void testCaseStarting(TestCaseInfo const& testInfo) CATCH_OVERRIDE
+    {
+        for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+             it != itEnd;
+             ++it)
+            (*it)->testCaseStarting(testInfo);
+    }
+
+    virtual void sectionStarting(SectionInfo const& sectionInfo) CATCH_OVERRIDE
+    {
+        for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+             it != itEnd;
+             ++it)
+            (*it)->sectionStarting(sectionInfo);
+    }
+
+    virtual void assertionStarting(AssertionInfo const& assertionInfo) CATCH_OVERRIDE
+    {
+        for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+             it != itEnd;
+             ++it)
+            (*it)->assertionStarting(assertionInfo);
+    }
+
+    // The return value indicates if the messages buffer should be cleared:
+    virtual bool assertionEnded(AssertionStats const& assertionStats) CATCH_OVERRIDE
+    {
+        bool clearBuffer = false;
+        for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+             it != itEnd;
+             ++it)
+            clearBuffer |= (*it)->assertionEnded(assertionStats);
+        return clearBuffer;
+    }
+
+    virtual void sectionEnded(SectionStats const& sectionStats) CATCH_OVERRIDE
+    {
+        for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+             it != itEnd;
+             ++it)
+            (*it)->sectionEnded(sectionStats);
+    }
+
+    virtual void testCaseEnded(TestCaseStats const& testCaseStats) CATCH_OVERRIDE
+    {
+        for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+             it != itEnd;
+             ++it)
+            (*it)->testCaseEnded(testCaseStats);
+    }
+
+    virtual void testGroupEnded(TestGroupStats const& testGroupStats) CATCH_OVERRIDE
+    {
+        for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+             it != itEnd;
+             ++it)
+            (*it)->testGroupEnded(testGroupStats);
+    }
+
+    virtual void testRunEnded(TestRunStats const& testRunStats) CATCH_OVERRIDE
+    {
+        for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+             it != itEnd;
+             ++it)
+            (*it)->testRunEnded(testRunStats);
+    }
+
+    virtual void skipTest(TestCaseInfo const& testInfo) CATCH_OVERRIDE
+    {
+        for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+             it != itEnd;
+             ++it)
+            (*it)->skipTest(testInfo);
+    }
+};
+
+Ptr<IStreamingReporter> addReporter(Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter)
+{
+    Ptr<IStreamingReporter> resultingReporter;
+
+    if (existingReporter)
+    {
+        MultipleReporters* multi = dynamic_cast<MultipleReporters*>(existingReporter.get());
+        if (!multi)
+        {
+            multi = new MultipleReporters;
+            resultingReporter = Ptr<IStreamingReporter>(multi);
+            if (existingReporter)
+                multi->add(existingReporter);
+        }
+        else
+            resultingReporter = existingReporter;
+        multi->add(additionalReporter);
+    }
+    else
+        resultingReporter = additionalReporter;
+
+    return resultingReporter;
+}
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_xml.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
+
+// #included from: catch_reporter_bases.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
+
+#include <cstring>
+
+namespace Catch {
+
+struct StreamingReporterBase : SharedImpl<IStreamingReporter>
+{
+
+    StreamingReporterBase(ReporterConfig const& _config)
+        : m_config(_config.fullConfig()),
+          stream(_config.stream())
+    {
+        m_reporterPrefs.shouldRedirectStdOut = false;
+    }
+
+    virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE
+    {
+        return m_reporterPrefs;
+    }
+
+    virtual ~StreamingReporterBase() CATCH_OVERRIDE;
+
+    virtual void noMatchingTestCases(std::string const&) CATCH_OVERRIDE {}
+
+    virtual void testRunStarting(TestRunInfo const& _testRunInfo) CATCH_OVERRIDE
+    {
+        currentTestRunInfo = _testRunInfo;
+    }
+    virtual void testGroupStarting(GroupInfo const& _groupInfo) CATCH_OVERRIDE
+    {
+        currentGroupInfo = _groupInfo;
+    }
+
+    virtual void testCaseStarting(TestCaseInfo const& _testInfo) CATCH_OVERRIDE
+    {
+        currentTestCaseInfo = _testInfo;
+    }
+    virtual void sectionStarting(SectionInfo const& _sectionInfo) CATCH_OVERRIDE
+    {
+        m_sectionStack.push_back(_sectionInfo);
+    }
+
+    virtual void sectionEnded(SectionStats const& /* _sectionStats */) CATCH_OVERRIDE
+    {
+        m_sectionStack.pop_back();
+    }
+    virtual void testCaseEnded(TestCaseStats const& /* _testCaseStats */) CATCH_OVERRIDE
+    {
+        currentTestCaseInfo.reset();
+    }
+    virtual void testGroupEnded(TestGroupStats const& /* _testGroupStats */) CATCH_OVERRIDE
+    {
+        currentGroupInfo.reset();
+    }
+    virtual void testRunEnded(TestRunStats const& /* _testRunStats */) CATCH_OVERRIDE
+    {
+        currentTestCaseInfo.reset();
+        currentGroupInfo.reset();
+        currentTestRunInfo.reset();
+    }
+
+    virtual void skipTest(TestCaseInfo const&) CATCH_OVERRIDE
+    {
+        // Don't do anything with this by default.
+        // It can optionally be overridden in the derived class.
+    }
+
+    Ptr<IConfig const> m_config;
+    std::ostream& stream;
+
+    LazyStat<TestRunInfo> currentTestRunInfo;
+    LazyStat<GroupInfo> currentGroupInfo;
+    LazyStat<TestCaseInfo> currentTestCaseInfo;
+
+    std::vector<SectionInfo> m_sectionStack;
+    ReporterPreferences m_reporterPrefs;
+};
+
+struct CumulativeReporterBase : SharedImpl<IStreamingReporter>
+{
+    template <typename T, typename ChildNodeT>
+    struct Node : SharedImpl<>
+    {
+        explicit Node(T const& _value) : value(_value) {}
+        virtual ~Node() {}
+
+        typedef std::vector<Ptr<ChildNodeT>> ChildNodes;
+        T value;
+        ChildNodes children;
+    };
+    struct SectionNode : SharedImpl<>
+    {
+        explicit SectionNode(SectionStats const& _stats) : stats(_stats) {}
+        virtual ~SectionNode();
+
+        bool operator==(SectionNode const& other) const
+        {
+            return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
+        }
+        bool operator==(Ptr<SectionNode> const& other) const
+        {
+            return operator==(*other);
+        }
+
+        SectionStats stats;
+        typedef std::vector<Ptr<SectionNode>> ChildSections;
+        typedef std::vector<AssertionStats> Assertions;
+        ChildSections childSections;
+        Assertions assertions;
+        std::string stdOut;
+        std::string stdErr;
+    };
+
+    struct BySectionInfo
+    {
+        BySectionInfo(SectionInfo const& other) : m_other(other) {}
+        BySectionInfo(BySectionInfo const& other) : m_other(other.m_other) {}
+        bool operator()(Ptr<SectionNode> const& node) const
+        {
+            return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
+        }
+
+      private:
+        void operator=(BySectionInfo const&);
+        SectionInfo const& m_other;
+    };
+
+    typedef Node<TestCaseStats, SectionNode> TestCaseNode;
+    typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
+    typedef Node<TestRunStats, TestGroupNode> TestRunNode;
+
+    CumulativeReporterBase(ReporterConfig const& _config)
+        : m_config(_config.fullConfig()),
+          stream(_config.stream())
+    {
+        m_reporterPrefs.shouldRedirectStdOut = false;
+    }
+    ~CumulativeReporterBase();
+
+    virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE
+    {
+        return m_reporterPrefs;
+    }
+
+    virtual void testRunStarting(TestRunInfo const&) CATCH_OVERRIDE {}
+    virtual void testGroupStarting(GroupInfo const&) CATCH_OVERRIDE {}
+
+    virtual void testCaseStarting(TestCaseInfo const&) CATCH_OVERRIDE {}
+
+    virtual void sectionStarting(SectionInfo const& sectionInfo) CATCH_OVERRIDE
+    {
+        SectionStats incompleteStats(sectionInfo, Counts(), 0, false);
+        Ptr<SectionNode> node;
+        if (m_sectionStack.empty())
+        {
+            if (!m_rootSection)
+                m_rootSection = new SectionNode(incompleteStats);
+            node = m_rootSection;
+        }
+        else
+        {
+            SectionNode& parentNode = *m_sectionStack.back();
+            SectionNode::ChildSections::const_iterator it =
+                std::find_if(parentNode.childSections.begin(),
+                             parentNode.childSections.end(),
+                             BySectionInfo(sectionInfo));
+            if (it == parentNode.childSections.end())
+            {
+                node = new SectionNode(incompleteStats);
+                parentNode.childSections.push_back(node);
+            }
+            else
+                node = *it;
+        }
+        m_sectionStack.push_back(node);
+        m_deepestSection = node;
+    }
+
+    virtual void assertionStarting(AssertionInfo const&) CATCH_OVERRIDE {}
+
+    virtual bool assertionEnded(AssertionStats const& assertionStats)
+    {
+        assert(!m_sectionStack.empty());
+        SectionNode& sectionNode = *m_sectionStack.back();
+        sectionNode.assertions.push_back(assertionStats);
+        return true;
+    }
+    virtual void sectionEnded(SectionStats const& sectionStats) CATCH_OVERRIDE
+    {
+        assert(!m_sectionStack.empty());
+        SectionNode& node = *m_sectionStack.back();
+        node.stats = sectionStats;
+        m_sectionStack.pop_back();
+    }
+    virtual void testCaseEnded(TestCaseStats const& testCaseStats) CATCH_OVERRIDE
+    {
+        Ptr<TestCaseNode> node = new TestCaseNode(testCaseStats);
+        assert(m_sectionStack.size() == 0);
+        node->children.push_back(m_rootSection);
+        m_testCases.push_back(node);
+        m_rootSection.reset();
+
+        assert(m_deepestSection);
+        m_deepestSection->stdOut = testCaseStats.stdOut;
+        m_deepestSection->stdErr = testCaseStats.stdErr;
+    }
+    virtual void testGroupEnded(TestGroupStats const& testGroupStats) CATCH_OVERRIDE
+    {
+        Ptr<TestGroupNode> node = new TestGroupNode(testGroupStats);
+        node->children.swap(m_testCases);
+        m_testGroups.push_back(node);
+    }
+    virtual void testRunEnded(TestRunStats const& testRunStats) CATCH_OVERRIDE
+    {
+        Ptr<TestRunNode> node = new TestRunNode(testRunStats);
+        node->children.swap(m_testGroups);
+        m_testRuns.push_back(node);
+        testRunEndedCumulative();
+    }
+    virtual void testRunEndedCumulative() = 0;
+
+    virtual void skipTest(TestCaseInfo const&) CATCH_OVERRIDE {}
+
+    Ptr<IConfig const> m_config;
+    std::ostream& stream;
+    std::vector<AssertionStats> m_assertions;
+    std::vector<std::vector<Ptr<SectionNode>>> m_sections;
+    std::vector<Ptr<TestCaseNode>> m_testCases;
+    std::vector<Ptr<TestGroupNode>> m_testGroups;
+
+    std::vector<Ptr<TestRunNode>> m_testRuns;
+
+    Ptr<SectionNode> m_rootSection;
+    Ptr<SectionNode> m_deepestSection;
+    std::vector<Ptr<SectionNode>> m_sectionStack;
+    ReporterPreferences m_reporterPrefs;
+};
+
+template <char C>
+char const* getLineOfChars()
+{
+    static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
+    if (!*line)
+    {
+        memset(line, C, CATCH_CONFIG_CONSOLE_WIDTH - 1);
+        line[CATCH_CONFIG_CONSOLE_WIDTH - 1] = 0;
+    }
+    return line;
+}
+
+struct TestEventListenerBase : StreamingReporterBase
+{
+    TestEventListenerBase(ReporterConfig const& _config)
+        : StreamingReporterBase(_config)
+    {
+    }
+
+    virtual void assertionStarting(AssertionInfo const&) CATCH_OVERRIDE {}
+    virtual bool assertionEnded(AssertionStats const&) CATCH_OVERRIDE
+    {
+        return false;
+    }
+};
+
+} // end namespace Catch
+
+// #included from: ../internal/catch_reporter_registrars.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
+
+namespace Catch {
+
+template <typename T>
+class LegacyReporterRegistrar
+{
+
+    class ReporterFactory : public IReporterFactory
+    {
+        virtual IStreamingReporter* create(ReporterConfig const& config) const
+        {
+            return new LegacyReporterAdapter(new T(config));
+        }
+
+        virtual std::string getDescription() const
+        {
+            return T::getDescription();
+        }
+    };
+
+  public:
+    LegacyReporterRegistrar(std::string const& name)
+    {
+        getMutableRegistryHub().registerReporter(name, new ReporterFactory());
+    }
+};
+
+template <typename T>
+class ReporterRegistrar
+{
+
+    class ReporterFactory : public SharedImpl<IReporterFactory>
+    {
+
+        // *** Please Note ***:
+        // - If you end up here looking at a compiler error because it's trying to register
+        // your custom reporter class be aware that the native reporter interface has changed
+        // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via
+        // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter.
+        // However please consider updating to the new interface as the old one is now
+        // deprecated and will probably be removed quite soon!
+        // Please contact me via github if you have any questions at all about this.
+        // In fact, ideally, please contact me anyway to let me know you've hit this - as I have
+        // no idea who is actually using custom reporters at all (possibly no-one!).
+        // The new interface is designed to minimise exposure to interface changes in the future.
+        virtual IStreamingReporter* create(ReporterConfig const& config) const
+        {
+            return new T(config);
+        }
+
+        virtual std::string getDescription() const
+        {
+            return T::getDescription();
+        }
+    };
+
+  public:
+    ReporterRegistrar(std::string const& name)
+    {
+        getMutableRegistryHub().registerReporter(name, new ReporterFactory());
+    }
+};
+
+template <typename T>
+class ListenerRegistrar
+{
+
+    class ListenerFactory : public SharedImpl<IReporterFactory>
+    {
+
+        virtual IStreamingReporter* create(ReporterConfig const& config) const
+        {
+            return new T(config);
+        }
+        virtual std::string getDescription() const
+        {
+            return "";
+        }
+    };
+
+  public:
+    ListenerRegistrar()
+    {
+        getMutableRegistryHub().registerListener(new ListenerFactory());
+    }
+};
+}
+
+#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER(name, reporterType)                               \
+    namespace {                                                                                   \
+    Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType(name); \
+    }
+
+#define INTERNAL_CATCH_REGISTER_REPORTER(name, reporterType)                                \
+    namespace {                                                                             \
+    Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType(name); \
+    }
+
+#define INTERNAL_CATCH_REGISTER_LISTENER(listenerType)                                \
+    namespace {                                                                       \
+    Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; \
+    }
+
+// #included from: ../internal/catch_xmlwriter.hpp
+#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
+
+#include <iomanip>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+class XmlEncode
+{
+  public:
+    enum ForWhat
+    {
+        ForTextNodes,
+        ForAttributes
+    };
+
+    XmlEncode(std::string const& str, ForWhat forWhat = ForTextNodes)
+        : m_str(str),
+          m_forWhat(forWhat)
+    {
+    }
+
+    void encodeTo(std::ostream& os) const
+    {
+
+        // Apostrophe escaping not necessary if we always use " to write attributes
+        // (see: http://www.w3.org/TR/xml/#syntax)
+
+        for (std::size_t i = 0; i < m_str.size(); ++i)
+        {
+            char c = m_str[i];
+            switch (c)
+            {
+            case '<':
+                os << "<";
+                break;
+            case '&':
+                os << "&";
+                break;
+
+            case '>':
+                // See: http://www.w3.org/TR/xml/#syntax
+                if (i > 2 && m_str[i - 1] == ']' && m_str[i - 2] == ']')
+                    os << ">";
+                else
+                    os << c;
+                break;
+
+            case '\"':
+                if (m_forWhat == ForAttributes)
+                    os << """;
+                else
+                    os << c;
+                break;
+
+            default:
+                // Escape control chars - based on contribution by @espenalb in PR #465
+                if ((c < '\x09') || (c > '\x0D' && c < '\x20') || c == '\x7F')
+                    os << "&#x" << std::uppercase << std::hex << static_cast<int>(c);
+                else
+                    os << c;
+            }
+        }
+    }
+
+    friend std::ostream& operator<<(std::ostream& os, XmlEncode const& xmlEncode)
+    {
+        xmlEncode.encodeTo(os);
+        return os;
+    }
+
+  private:
+    std::string m_str;
+    ForWhat m_forWhat;
+};
+
+class XmlWriter
+{
+  public:
+    class ScopedElement
+    {
+      public:
+        ScopedElement(XmlWriter* writer)
+            : m_writer(writer)
+        {
+        }
+
+        ScopedElement(ScopedElement const& other)
+            : m_writer(other.m_writer)
+        {
+            other.m_writer = CATCH_NULL;
+        }
+
+        ~ScopedElement()
+        {
+            if (m_writer)
+                m_writer->endElement();
+        }
+
+        ScopedElement& writeText(std::string const& text, bool indent = true)
+        {
+            m_writer->writeText(text, indent);
+            return *this;
+        }
+
+        template <typename T>
+        ScopedElement& writeAttribute(std::string const& name, T const& attribute)
+        {
+            m_writer->writeAttribute(name, attribute);
+            return *this;
+        }
+
+      private:
+        mutable XmlWriter* m_writer;
+    };
+
+    XmlWriter()
+        : m_tagIsOpen(false),
+          m_needsNewline(false),
+          m_os(&Catch::cout())
+    {
+    }
+
+    XmlWriter(std::ostream& os)
+        : m_tagIsOpen(false),
+          m_needsNewline(false),
+          m_os(&os)
+    {
+    }
+
+    ~XmlWriter()
+    {
+        while (!m_tags.empty())
+            endElement();
+    }
+
+    XmlWriter& startElement(std::string const& name)
+    {
+        ensureTagClosed();
+        newlineIfNecessary();
+        stream() << m_indent << "<" << name;
+        m_tags.push_back(name);
+        m_indent += "  ";
+        m_tagIsOpen = true;
+        return *this;
+    }
+
+    ScopedElement scopedElement(std::string const& name)
+    {
+        ScopedElement scoped(this);
+        startElement(name);
+        return scoped;
+    }
+
+    XmlWriter& endElement()
+    {
+        newlineIfNecessary();
+        m_indent = m_indent.substr(0, m_indent.size() - 2);
+        if (m_tagIsOpen)
+        {
+            stream() << "/>\n";
+            m_tagIsOpen = false;
+        }
+        else
+        {
+            stream() << m_indent << "</" << m_tags.back() << ">\n";
+        }
+        m_tags.pop_back();
+        return *this;
+    }
+
+    XmlWriter& writeAttribute(std::string const& name, std::string const& attribute)
+    {
+        if (!name.empty() && !attribute.empty())
+            stream() << " " << name << "=\"" << XmlEncode(attribute, XmlEncode::ForAttributes) << "\"";
+        return *this;
+    }
+
+    XmlWriter& writeAttribute(std::string const& name, bool attribute)
+    {
+        stream() << " " << name << "=\"" << (attribute ? "true" : "false") << "\"";
+        return *this;
+    }
+
+    template <typename T>
+    XmlWriter& writeAttribute(std::string const& name, T const& attribute)
+    {
+        std::ostringstream oss;
+        oss << attribute;
+        return writeAttribute(name, oss.str());
+    }
+
+    XmlWriter& writeText(std::string const& text, bool indent = true)
+    {
+        if (!text.empty())
+        {
+            bool tagWasOpen = m_tagIsOpen;
+            ensureTagClosed();
+            if (tagWasOpen && indent)
+                stream() << m_indent;
+            stream() << XmlEncode(text);
+            m_needsNewline = true;
+        }
+        return *this;
+    }
+
+    XmlWriter& writeComment(std::string const& text)
+    {
+        ensureTagClosed();
+        stream() << m_indent << "<!--" << text << "-->";
+        m_needsNewline = true;
+        return *this;
+    }
+
+    XmlWriter& writeBlankLine()
+    {
+        ensureTagClosed();
+        stream() << "\n";
+        return *this;
+    }
+
+    void setStream(std::ostream& os)
+    {
+        m_os = &os;
+    }
+
+  private:
+    XmlWriter(XmlWriter const&);
+    void operator=(XmlWriter const&);
+
+    std::ostream& stream()
+    {
+        return *m_os;
+    }
+
+    void ensureTagClosed()
+    {
+        if (m_tagIsOpen)
+        {
+            stream() << ">\n";
+            m_tagIsOpen = false;
+        }
+    }
+
+    void newlineIfNecessary()
+    {
+        if (m_needsNewline)
+        {
+            stream() << "\n";
+            m_needsNewline = false;
+        }
+    }
+
+    bool m_tagIsOpen;
+    bool m_needsNewline;
+    std::vector<std::string> m_tags;
+    std::string m_indent;
+    std::ostream* m_os;
+};
+}
+// #included from: catch_reenable_warnings.h
+
+#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
+
+#ifdef __clang__
+#ifdef __ICC // icpc defines the __clang__ macro
+#pragma warning(pop)
+#else
+#pragma clang diagnostic pop
+#endif
+#elif defined __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+namespace Catch {
+class XmlReporter : public StreamingReporterBase
+{
+  public:
+    XmlReporter(ReporterConfig const& _config)
+        : StreamingReporterBase(_config),
+          m_sectionDepth(0)
+    {
+        m_reporterPrefs.shouldRedirectStdOut = true;
+    }
+
+    virtual ~XmlReporter() CATCH_OVERRIDE;
+
+    static std::string getDescription()
+    {
+        return "Reports test results as an XML document";
+    }
+
+  public: // StreamingReporterBase
+    virtual void noMatchingTestCases(std::string const& s) CATCH_OVERRIDE
+    {
+        StreamingReporterBase::noMatchingTestCases(s);
+    }
+
+    virtual void testRunStarting(TestRunInfo const& testInfo) CATCH_OVERRIDE
+    {
+        StreamingReporterBase::testRunStarting(testInfo);
+        m_xml.setStream(stream);
+        m_xml.startElement("Catch");
+        if (!m_config->name().empty())
+            m_xml.writeAttribute("name", m_config->name());
+    }
+
+    virtual void testGroupStarting(GroupInfo const& groupInfo) CATCH_OVERRIDE
+    {
+        StreamingReporterBase::testGroupStarting(groupInfo);
+        m_xml.startElement("Group")
+            .writeAttribute("name", groupInfo.name);
+    }
+
+    virtual void testCaseStarting(TestCaseInfo const& testInfo) CATCH_OVERRIDE
+    {
+        StreamingReporterBase::testCaseStarting(testInfo);
+        m_xml.startElement("TestCase").writeAttribute("name", trim(testInfo.name));
+
+        if (m_config->showDurations() == ShowDurations::Always)
+            m_testCaseTimer.start();
+    }
+
+    virtual void sectionStarting(SectionInfo const& sectionInfo) CATCH_OVERRIDE
+    {
+        StreamingReporterBase::sectionStarting(sectionInfo);
+        if (m_sectionDepth++ > 0)
+        {
+            m_xml.startElement("Section")
+                .writeAttribute("name", trim(sectionInfo.name))
+                .writeAttribute("description", sectionInfo.description);
+        }
+    }
+
+    virtual void assertionStarting(AssertionInfo const&) CATCH_OVERRIDE {}
+
+    virtual bool assertionEnded(AssertionStats const& assertionStats) CATCH_OVERRIDE
+    {
+        const AssertionResult& assertionResult = assertionStats.assertionResult;
+
+        // Print any info messages in <Info> tags.
+        if (assertionStats.assertionResult.getResultType() != ResultWas::Ok)
+        {
+            for (std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+                 it != itEnd;
+                 ++it)
+            {
+                if (it->type == ResultWas::Info)
+                {
+                    m_xml.scopedElement("Info")
+                        .writeText(it->message);
+                }
+                else if (it->type == ResultWas::Warning)
+                {
+                    m_xml.scopedElement("Warning")
+                        .writeText(it->message);
+                }
+            }
+        }
+
+        // Drop out if result was successful but we're not printing them.
+        if (!m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()))
+            return true;
+
+        // Print the expression if there is one.
+        if (assertionResult.hasExpression())
+        {
+            m_xml.startElement("Expression")
+                .writeAttribute("success", assertionResult.succeeded())
+                .writeAttribute("type", assertionResult.getTestMacroName())
+                .writeAttribute("filename", assertionResult.getSourceInfo().file)
+                .writeAttribute("line", assertionResult.getSourceInfo().line);
+
+            m_xml.scopedElement("Original")
+                .writeText(assertionResult.getExpression());
+            m_xml.scopedElement("Expanded")
+                .writeText(assertionResult.getExpandedExpression());
+        }
+
+        // And... Print a result applicable to each result type.
+        switch (assertionResult.getResultType())
+        {
+        case ResultWas::ThrewException:
+            m_xml.scopedElement("Exception")
+                .writeAttribute("filename", assertionResult.getSourceInfo().file)
+                .writeAttribute("line", assertionResult.getSourceInfo().line)
+                .writeText(assertionResult.getMessage());
+            break;
+        case ResultWas::FatalErrorCondition:
+            m_xml.scopedElement("Fatal Error Condition")
+                .writeAttribute("filename", assertionResult.getSourceInfo().file)
+                .writeAttribute("line", assertionResult.getSourceInfo().line)
+                .writeText(assertionResult.getMessage());
+            break;
+        case ResultWas::Info:
+            m_xml.scopedElement("Info")
+                .writeText(assertionResult.getMessage());
+            break;
+        case ResultWas::Warning:
+            // Warning will already have been written
+            break;
+        case ResultWas::ExplicitFailure:
+            m_xml.scopedElement("Failure")
+                .writeText(assertionResult.getMessage());
+            break;
+        default:
+            break;
+        }
+
+        if (assertionResult.hasExpression())
+            m_xml.endElement();
+
+        return true;
+    }
+
+    virtual void sectionEnded(SectionStats const& sectionStats) CATCH_OVERRIDE
+    {
+        StreamingReporterBase::sectionEnded(sectionStats);
+        if (--m_sectionDepth > 0)
+        {
+            XmlWriter::ScopedElement e = m_xml.scopedElement("OverallResults");
+            e.writeAttribute("successes", sectionStats.assertions.passed);
+            e.writeAttribute("failures", sectionStats.assertions.failed);
+            e.writeAttribute("expectedFailures", sectionStats.assertions.failedButOk);
+
+            if (m_config->showDurations() == ShowDurations::Always)
+                e.writeAttribute("durationInSeconds", sectionStats.durationInSeconds);
+
+            m_xml.endElement();
+        }
+    }
+
+    virtual void testCaseEnded(TestCaseStats const& testCaseStats) CATCH_OVERRIDE
+    {
+        StreamingReporterBase::testCaseEnded(testCaseStats);
+        XmlWriter::ScopedElement e = m_xml.scopedElement("OverallResult");
+        e.writeAttribute("success", testCaseStats.totals.assertions.allOk());
+
+        if (m_config->showDurations() == ShowDurations::Always)
+            e.writeAttribute("durationInSeconds", m_testCaseTimer.getElapsedSeconds());
+
+        m_xml.endElement();
+    }
+
+    virtual void testGroupEnded(TestGroupStats const& testGroupStats) CATCH_OVERRIDE
+    {
+        StreamingReporterBase::testGroupEnded(testGroupStats);
+        // TODO: Check testGroupStats.aborting and act accordingly.
+        m_xml.scopedElement("OverallResults")
+            .writeAttribute("successes", testGroupStats.totals.assertions.passed)
+            .writeAttribute("failures", testGroupStats.totals.assertions.failed)
+            .writeAttribute("expectedFailures", testGroupStats.totals.assertions.failedButOk);
+        m_xml.endElement();
+    }
+
+    virtual void testRunEnded(TestRunStats const& testRunStats) CATCH_OVERRIDE
+    {
+        StreamingReporterBase::testRunEnded(testRunStats);
+        m_xml.scopedElement("OverallResults")
+            .writeAttribute("successes", testRunStats.totals.assertions.passed)
+            .writeAttribute("failures", testRunStats.totals.assertions.failed)
+            .writeAttribute("expectedFailures", testRunStats.totals.assertions.failedButOk);
+        m_xml.endElement();
+    }
+
+  private:
+    Timer m_testCaseTimer;
+    XmlWriter m_xml;
+    int m_sectionDepth;
+};
+
+INTERNAL_CATCH_REGISTER_REPORTER("xml", XmlReporter)
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_junit.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
+
+#include <assert.h>
+
+namespace Catch {
+
+class JunitReporter : public CumulativeReporterBase
+{
+  public:
+    JunitReporter(ReporterConfig const& _config)
+        : CumulativeReporterBase(_config),
+          xml(_config.stream())
+    {
+        m_reporterPrefs.shouldRedirectStdOut = true;
+    }
+
+    virtual ~JunitReporter() CATCH_OVERRIDE;
+
+    static std::string getDescription()
+    {
+        return "Reports test results in an XML format that looks like Ant's junitreport target";
+    }
+
+    virtual void noMatchingTestCases(std::string const& /*spec*/) CATCH_OVERRIDE {}
+
+    virtual void testRunStarting(TestRunInfo const& runInfo) CATCH_OVERRIDE
+    {
+        CumulativeReporterBase::testRunStarting(runInfo);
+        xml.startElement("testsuites");
+    }
+
+    virtual void testGroupStarting(GroupInfo const& groupInfo) CATCH_OVERRIDE
+    {
+        suiteTimer.start();
+        stdOutForSuite.str("");
+        stdErrForSuite.str("");
+        unexpectedExceptions = 0;
+        CumulativeReporterBase::testGroupStarting(groupInfo);
+    }
+
+    virtual bool assertionEnded(AssertionStats const& assertionStats) CATCH_OVERRIDE
+    {
+        if (assertionStats.assertionResult.getResultType() == ResultWas::ThrewException)
+            unexpectedExceptions++;
+        return CumulativeReporterBase::assertionEnded(assertionStats);
+    }
+
+    virtual void testCaseEnded(TestCaseStats const& testCaseStats) CATCH_OVERRIDE
+    {
+        stdOutForSuite << testCaseStats.stdOut;
+        stdErrForSuite << testCaseStats.stdErr;
+        CumulativeReporterBase::testCaseEnded(testCaseStats);
+    }
+
+    virtual void testGroupEnded(TestGroupStats const& testGroupStats) CATCH_OVERRIDE
+    {
+        double suiteTime = suiteTimer.getElapsedSeconds();
+        CumulativeReporterBase::testGroupEnded(testGroupStats);
+        writeGroup(*m_testGroups.back(), suiteTime);
+    }
+
+    virtual void testRunEndedCumulative() CATCH_OVERRIDE
+    {
+        xml.endElement();
+    }
+
+    void writeGroup(TestGroupNode const& groupNode, double suiteTime)
+    {
+        XmlWriter::ScopedElement e = xml.scopedElement("testsuite");
+        TestGroupStats const& stats = groupNode.value;
+        xml.writeAttribute("name", stats.groupInfo.name);
+        xml.writeAttribute("errors", unexpectedExceptions);
+        xml.writeAttribute("failures", stats.totals.assertions.failed - unexpectedExceptions);
+        xml.writeAttribute("tests", stats.totals.assertions.total());
+        xml.writeAttribute("hostname", "tbd"); // !TBD
+        if (m_config->showDurations() == ShowDurations::Never)
+            xml.writeAttribute("time", "");
+        else
+            xml.writeAttribute("time", suiteTime);
+        xml.writeAttribute("timestamp", "tbd"); // !TBD
+
+        // Write test cases
+        for (TestGroupNode::ChildNodes::const_iterator
+                 it = groupNode.children.begin(),
+                 itEnd = groupNode.children.end();
+             it != itEnd;
+             ++it)
+            writeTestCase(**it);
+
+        xml.scopedElement("system-out").writeText(trim(stdOutForSuite.str()), false);
+        xml.scopedElement("system-err").writeText(trim(stdErrForSuite.str()), false);
+    }
+
+    void writeTestCase(TestCaseNode const& testCaseNode)
+    {
+        TestCaseStats const& stats = testCaseNode.value;
+
+        // All test cases have exactly one section - which represents the
+        // test case itself. That section may have 0-n nested sections
+        assert(testCaseNode.children.size() == 1);
+        SectionNode const& rootSection = *testCaseNode.children.front();
+
+        std::string className = stats.testInfo.className;
+
+        if (className.empty())
+        {
+            if (rootSection.childSections.empty())
+                className = "global";
+        }
+        writeSection(className, "", rootSection);
+    }
+
+    void writeSection(std::string const& className,
+                      std::string const& rootName,
+                      SectionNode const& sectionNode)
+    {
+        std::string name = trim(sectionNode.stats.sectionInfo.name);
+        if (!rootName.empty())
+            name = rootName + "/" + name;
+
+        if (!sectionNode.assertions.empty() ||
+            !sectionNode.stdOut.empty() ||
+            !sectionNode.stdErr.empty())
+        {
+            XmlWriter::ScopedElement e = xml.scopedElement("testcase");
+            if (className.empty())
+            {
+                xml.writeAttribute("classname", name);
+                xml.writeAttribute("name", "root");
+            }
+            else
+            {
+                xml.writeAttribute("classname", className);
+                xml.writeAttribute("name", name);
+            }
+            xml.writeAttribute("time", Catch::toString(sectionNode.stats.durationInSeconds));
+
+            writeAssertions(sectionNode);
+
+            if (!sectionNode.stdOut.empty())
+                xml.scopedElement("system-out").writeText(trim(sectionNode.stdOut), false);
+            if (!sectionNode.stdErr.empty())
+                xml.scopedElement("system-err").writeText(trim(sectionNode.stdErr), false);
+        }
+        for (SectionNode::ChildSections::const_iterator
+                 it = sectionNode.childSections.begin(),
+                 itEnd = sectionNode.childSections.end();
+             it != itEnd;
+             ++it)
+            if (className.empty())
+                writeSection(name, "", **it);
+            else
+                writeSection(className, name, **it);
+    }
+
+    void writeAssertions(SectionNode const& sectionNode)
+    {
+        for (SectionNode::Assertions::const_iterator
+                 it = sectionNode.assertions.begin(),
+                 itEnd = sectionNode.assertions.end();
+             it != itEnd;
+             ++it)
+            writeAssertion(*it);
+    }
+    void writeAssertion(AssertionStats const& stats)
+    {
+        AssertionResult const& result = stats.assertionResult;
+        if (!result.isOk())
+        {
+            std::string elementName;
+            switch (result.getResultType())
+            {
+            case ResultWas::ThrewException:
+            case ResultWas::FatalErrorCondition:
+                elementName = "error";
+                break;
+            case ResultWas::ExplicitFailure:
+                elementName = "failure";
+                break;
+            case ResultWas::ExpressionFailed:
+                elementName = "failure";
+                break;
+            case ResultWas::DidntThrowException:
+                elementName = "failure";
+                break;
+
+            // We should never see these here:
+            case ResultWas::Info:
+            case ResultWas::Warning:
+            case ResultWas::Ok:
+            case ResultWas::Unknown:
+            case ResultWas::FailureBit:
+            case ResultWas::Exception:
+                elementName = "internalError";
+                break;
+            }
+
+            XmlWriter::ScopedElement e = xml.scopedElement(elementName);
+
+            xml.writeAttribute("message", result.getExpandedExpression());
+            xml.writeAttribute("type", result.getTestMacroName());
+
+            std::ostringstream oss;
+            if (!result.getMessage().empty())
+                oss << result.getMessage() << "\n";
+            for (std::vector<MessageInfo>::const_iterator
+                     it = stats.infoMessages.begin(),
+                     itEnd = stats.infoMessages.end();
+                 it != itEnd;
+                 ++it)
+                if (it->type == ResultWas::Info)
+                    oss << it->message << "\n";
+
+            oss << "at " << result.getSourceInfo();
+            xml.writeText(oss.str(), false);
+        }
+    }
+
+    XmlWriter xml;
+    Timer suiteTimer;
+    std::ostringstream stdOutForSuite;
+    std::ostringstream stdErrForSuite;
+    unsigned int unexpectedExceptions;
+};
+
+INTERNAL_CATCH_REGISTER_REPORTER("junit", JunitReporter)
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_console.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
+
+namespace Catch {
+
+struct ConsoleReporter : StreamingReporterBase
+{
+    ConsoleReporter(ReporterConfig const& _config)
+        : StreamingReporterBase(_config),
+          m_headerPrinted(false)
+    {
+    }
+
+    virtual ~ConsoleReporter() CATCH_OVERRIDE;
+    static std::string getDescription()
+    {
+        return "Reports test results as plain lines of text";
+    }
+
+    virtual void noMatchingTestCases(std::string const& spec) CATCH_OVERRIDE
+    {
+        stream << "No test cases matched '" << spec << "'" << std::endl;
+    }
+
+    virtual void assertionStarting(AssertionInfo const&) CATCH_OVERRIDE
+    {
+    }
+
+    virtual bool assertionEnded(AssertionStats const& _assertionStats) CATCH_OVERRIDE
+    {
+        AssertionResult const& result = _assertionStats.assertionResult;
+
+        bool printInfoMessages = true;
+
+        // Drop out if result was successful and we're not printing those
+        if (!m_config->includeSuccessfulResults() && result.isOk())
+        {
+            if (result.getResultType() != ResultWas::Warning)
+                return false;
+            printInfoMessages = false;
+        }
+
+        lazyPrint();
+
+        AssertionPrinter printer(stream, _assertionStats, printInfoMessages);
+        printer.print();
+        stream << std::endl;
+        return true;
+    }
+
+    virtual void sectionStarting(SectionInfo const& _sectionInfo) CATCH_OVERRIDE
+    {
+        m_headerPrinted = false;
+        StreamingReporterBase::sectionStarting(_sectionInfo);
+    }
+    virtual void sectionEnded(SectionStats const& _sectionStats) CATCH_OVERRIDE
+    {
+        if (_sectionStats.missingAssertions)
+        {
+            lazyPrint();
+            Colour colour(Colour::ResultError);
+            if (m_sectionStack.size() > 1)
+                stream << "\nNo assertions in section";
+            else
+                stream << "\nNo assertions in test case";
+            stream << " '" << _sectionStats.sectionInfo.name << "'\n"
+                   << std::endl;
+        }
+        if (m_headerPrinted)
+        {
+            if (m_config->showDurations() == ShowDurations::Always)
+                stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
+            m_headerPrinted = false;
+        }
+        else
+        {
+            if (m_config->showDurations() == ShowDurations::Always)
+                stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
+        }
+        StreamingReporterBase::sectionEnded(_sectionStats);
+    }
+
+    virtual void testCaseEnded(TestCaseStats const& _testCaseStats) CATCH_OVERRIDE
+    {
+        StreamingReporterBase::testCaseEnded(_testCaseStats);
+        m_headerPrinted = false;
+    }
+    virtual void testGroupEnded(TestGroupStats const& _testGroupStats) CATCH_OVERRIDE
+    {
+        if (currentGroupInfo.used)
+        {
+            printSummaryDivider();
+            stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
+            printTotals(_testGroupStats.totals);
+            stream << "\n"
+                   << std::endl;
+        }
+        StreamingReporterBase::testGroupEnded(_testGroupStats);
+    }
+    virtual void testRunEnded(TestRunStats const& _testRunStats) CATCH_OVERRIDE
+    {
+        printTotalsDivider(_testRunStats.totals);
+        printTotals(_testRunStats.totals);
+        stream << std::endl;
+        StreamingReporterBase::testRunEnded(_testRunStats);
+    }
+
+  private:
+    class AssertionPrinter
+    {
+        void operator=(AssertionPrinter const&);
+
+      public:
+        AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)
+            : stream(_stream),
+              stats(_stats),
+              result(_stats.assertionResult),
+              colour(Colour::None),
+              message(result.getMessage()),
+              messages(_stats.infoMessages),
+              printInfoMessages(_printInfoMessages)
+        {
+            switch (result.getResultType())
+            {
+            case ResultWas::Ok:
+                colour = Colour::Success;
+                passOrFail = "PASSED";
+                //if( result.hasMessage() )
+                if (_stats.infoMessages.size() == 1)
+                    messageLabel = "with message";
+                if (_stats.infoMessages.size() > 1)
+                    messageLabel = "with messages";
+                break;
+            case ResultWas::ExpressionFailed:
+                if (result.isOk())
+                {
+                    colour = Colour::Success;
+                    passOrFail = "FAILED - but was ok";
+                }
+                else
+                {
+                    colour = Colour::Error;
+                    passOrFail = "FAILED";
+                }
+                if (_stats.infoMessages.size() == 1)
+                    messageLabel = "with message";
+                if (_stats.infoMessages.size() > 1)
+                    messageLabel = "with messages";
+                break;
+            case ResultWas::ThrewException:
+                colour = Colour::Error;
+                passOrFail = "FAILED";
+                messageLabel = "due to unexpected exception with message";
+                break;
+            case ResultWas::FatalErrorCondition:
+                colour = Colour::Error;
+                passOrFail = "FAILED";
+                messageLabel = "due to a fatal error condition";
+                break;
+            case ResultWas::DidntThrowException:
+                colour = Colour::Error;
+                passOrFail = "FAILED";
+                messageLabel = "because no exception was thrown where one was expected";
+                break;
+            case ResultWas::Info:
+                messageLabel = "info";
+                break;
+            case ResultWas::Warning:
+                messageLabel = "warning";
+                break;
+            case ResultWas::ExplicitFailure:
+                passOrFail = "FAILED";
+                colour = Colour::Error;
+                if (_stats.infoMessages.size() == 1)
+                    messageLabel = "explicitly with message";
+                if (_stats.infoMessages.size() > 1)
+                    messageLabel = "explicitly with messages";
+                break;
+            // These cases are here to prevent compiler warnings
+            case ResultWas::Unknown:
+            case ResultWas::FailureBit:
+            case ResultWas::Exception:
+                passOrFail = "** internal error **";
+                colour = Colour::Error;
+                break;
+            }
+        }
+
+        void print() const
+        {
+            printSourceInfo();
+            if (stats.totals.assertions.total() > 0)
+            {
+                if (result.isOk())
+                    stream << "\n";
+                printResultType();
+                printOriginalExpression();
+                printReconstructedExpression();
+            }
+            else
+            {
+                stream << "\n";
+            }
+            printMessage();
+        }
+
+      private:
+        void printResultType() const
+        {
+            if (!passOrFail.empty())
+            {
+                Colour colourGuard(colour);
+                stream << passOrFail << ":\n";
+            }
+        }
+        void printOriginalExpression() const
+        {
+            if (result.hasExpression())
+            {
+                Colour colourGuard(Colour::OriginalExpression);
+                stream << "  ";
+                stream << result.getExpressionInMacro();
+                stream << "\n";
+            }
+        }
+        void printReconstructedExpression() const
+        {
+            if (result.hasExpandedExpression())
+            {
+                stream << "with expansion:\n";
+                Colour colourGuard(Colour::ReconstructedExpression);
+                stream << Text(result.getExpandedExpression(), TextAttributes().setIndent(2)) << "\n";
+            }
+        }
+        void printMessage() const
+        {
+            if (!messageLabel.empty())
+                stream << messageLabel << ":"
+                       << "\n";
+            for (std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
+                 it != itEnd;
+                 ++it)
+            {
+                // If this assertion is a warning ignore any INFO messages
+                if (printInfoMessages || it->type != ResultWas::Info)
+                    stream << Text(it->message, TextAttributes().setIndent(2)) << "\n";
+            }
+        }
+        void printSourceInfo() const
+        {
+            Colour colourGuard(Colour::FileName);
+            stream << result.getSourceInfo() << ": ";
+        }
+
+        std::ostream& stream;
+        AssertionStats const& stats;
+        AssertionResult const& result;
+        Colour::Code colour;
+        std::string passOrFail;
+        std::string messageLabel;
+        std::string message;
+        std::vector<MessageInfo> messages;
+        bool printInfoMessages;
+    };
+
+    void lazyPrint()
+    {
+
+        if (!currentTestRunInfo.used)
+            lazyPrintRunInfo();
+        if (!currentGroupInfo.used)
+            lazyPrintGroupInfo();
+
+        if (!m_headerPrinted)
+        {
+            printTestCaseAndSectionHeader();
+            m_headerPrinted = true;
+        }
+    }
+    void lazyPrintRunInfo()
+    {
+        stream << "\n"
+               << getLineOfChars<'~'>() << "\n";
+        Colour colour(Colour::SecondaryText);
+        stream << currentTestRunInfo->name
+               << " is a Catch v" << libraryVersion << " host application.\n"
+               << "Run with -? for options\n\n";
+
+        if (m_config->rngSeed() != 0)
+            stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
+
+        currentTestRunInfo.used = true;
+    }
+    void lazyPrintGroupInfo()
+    {
+        if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1)
+        {
+            printClosedHeader("Group: " + currentGroupInfo->name);
+            currentGroupInfo.used = true;
+        }
+    }
+    void printTestCaseAndSectionHeader()
+    {
+        assert(!m_sectionStack.empty());
+        printOpenHeader(currentTestCaseInfo->name);
+
+        if (m_sectionStack.size() > 1)
+        {
+            Colour colourGuard(Colour::Headers);
+
+            std::vector<SectionInfo>::const_iterator
+                it = m_sectionStack.begin() + 1, // Skip first section (test case)
+                itEnd = m_sectionStack.end();
+            for (; it != itEnd; ++it)
+                printHeaderString(it->name, 2);
+        }
+
+        SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
+
+        if (!lineInfo.empty())
+        {
+            stream << getLineOfChars<'-'>() << "\n";
+            Colour colourGuard(Colour::FileName);
+            stream << lineInfo << "\n";
+        }
+        stream << getLineOfChars<'.'>() << "\n"
+               << std::endl;
+    }
+
+    void printClosedHeader(std::string const& _name)
+    {
+        printOpenHeader(_name);
+        stream << getLineOfChars<'.'>() << "\n";
+    }
+    void printOpenHeader(std::string const& _name)
+    {
+        stream << getLineOfChars<'-'>() << "\n";
+        {
+            Colour colourGuard(Colour::Headers);
+            printHeaderString(_name);
+        }
+    }
+
+    // if string has a : in first line will set indent to follow it on
+    // subsequent lines
+    void printHeaderString(std::string const& _string, std::size_t indent = 0)
+    {
+        std::size_t i = _string.find(": ");
+        if (i != std::string::npos)
+            i += 2;
+        else
+            i = 0;
+        stream << Text(_string, TextAttributes()
+                                    .setIndent(indent + i)
+                                    .setInitialIndent(indent))
+               << "\n";
+    }
+
+    struct SummaryColumn
+    {
+
+        SummaryColumn(std::string const& _label, Colour::Code _colour)
+            : label(_label),
+              colour(_colour)
+        {
+        }
+        SummaryColumn addRow(std::size_t count)
+        {
+            std::ostringstream oss;
+            oss << count;
+            std::string row = oss.str();
+            for (std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it)
+            {
+                while (it->size() < row.size())
+                    *it = " " + *it;
+                while (it->size() > row.size())
+                    row = " " + row;
+            }
+            rows.push_back(row);
+            return *this;
+        }
+
+        std::string label;
+        Colour::Code colour;
+        std::vector<std::string> rows;
+    };
+
+    void printTotals(Totals const& totals)
+    {
+        if (totals.testCases.total() == 0)
+        {
+            stream << Colour(Colour::Warning) << "No tests ran\n";
+        }
+        else if (totals.assertions.total() > 0 && totals.assertions.allPassed())
+        {
+            stream << Colour(Colour::ResultSuccess) << "All tests passed";
+            stream << " ("
+                   << pluralise(totals.assertions.passed, "assertion") << " in "
+                   << pluralise(totals.testCases.passed, "test case") << ")"
+                   << "\n";
+        }
+        else
+        {
+
+            std::vector<SummaryColumn> columns;
+            columns.push_back(SummaryColumn("", Colour::None)
+                                  .addRow(totals.testCases.total())
+                                  .addRow(totals.assertions.total()));
+            columns.push_back(SummaryColumn("passed", Colour::Success)
+                                  .addRow(totals.testCases.passed)
+                                  .addRow(totals.assertions.passed));
+            columns.push_back(SummaryColumn("failed", Colour::ResultError)
+                                  .addRow(totals.testCases.failed)
+                                  .addRow(totals.assertions.failed));
+            columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure)
+                                  .addRow(totals.testCases.failedButOk)
+                                  .addRow(totals.assertions.failedButOk));
+
+            printSummaryRow("test cases", columns, 0);
+            printSummaryRow("assertions", columns, 1);
+        }
+    }
+    void printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row)
+    {
+        for (std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it)
+        {
+            std::string value = it->rows[row];
+            if (it->label.empty())
+            {
+                stream << label << ": ";
+                if (value != "0")
+                    stream << value;
+                else
+                    stream << Colour(Colour::Warning) << "- none -";
+            }
+            else if (value != "0")
+            {
+                stream << Colour(Colour::LightGrey) << " | ";
+                stream << Colour(it->colour)
+                       << value << " " << it->label;
+            }
+        }
+        stream << "\n";
+    }
+
+    static std::size_t makeRatio(std::size_t number, std::size_t total)
+    {
+        std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0;
+        return (ratio == 0 && number > 0) ? 1 : ratio;
+    }
+    static std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k)
+    {
+        if (i > j && i > k)
+            return i;
+        else if (j > k)
+            return j;
+        else
+            return k;
+    }
+
+    void printTotalsDivider(Totals const& totals)
+    {
+        if (totals.testCases.total() > 0)
+        {
+            std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());
+            std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());
+            std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total());
+            while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1)
+                findMax(failedRatio, failedButOkRatio, passedRatio)++;
+            while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1)
+                findMax(failedRatio, failedButOkRatio, passedRatio)--;
+
+            stream << Colour(Colour::Error) << std::string(failedRatio, '=');
+            stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '=');
+            if (totals.testCases.allPassed())
+                stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '=');
+            else
+                stream << Colour(Colour::Success) << std::string(passedRatio, '=');
+        }
+        else
+        {
+            stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '=');
+        }
+        stream << "\n";
+    }
+    void printSummaryDivider()
+    {
+        stream << getLineOfChars<'-'>() << "\n";
+    }
+
+  private:
+    bool m_headerPrinted;
+};
+
+INTERNAL_CATCH_REGISTER_REPORTER("console", ConsoleReporter)
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_compact.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED
+
+namespace Catch {
+
+struct CompactReporter : StreamingReporterBase
+{
+
+    CompactReporter(ReporterConfig const& _config)
+        : StreamingReporterBase(_config)
+    {
+    }
+
+    virtual ~CompactReporter();
+
+    static std::string getDescription()
+    {
+        return "Reports test results on a single line, suitable for IDEs";
+    }
+
+    virtual ReporterPreferences getPreferences() const
+    {
+        ReporterPreferences prefs;
+        prefs.shouldRedirectStdOut = false;
+        return prefs;
+    }
+
+    virtual void noMatchingTestCases(std::string const& spec)
+    {
+        stream << "No test cases matched '" << spec << "'" << std::endl;
+    }
+
+    virtual void assertionStarting(AssertionInfo const&)
+    {
+    }
+
+    virtual bool assertionEnded(AssertionStats const& _assertionStats)
+    {
+        AssertionResult const& result = _assertionStats.assertionResult;
+
+        bool printInfoMessages = true;
+
+        // Drop out if result was successful and we're not printing those
+        if (!m_config->includeSuccessfulResults() && result.isOk())
+        {
+            if (result.getResultType() != ResultWas::Warning)
+                return false;
+            printInfoMessages = false;
+        }
+
+        AssertionPrinter printer(stream, _assertionStats, printInfoMessages);
+        printer.print();
+
+        stream << std::endl;
+        return true;
+    }
+
+    virtual void testRunEnded(TestRunStats const& _testRunStats)
+    {
+        printTotals(_testRunStats.totals);
+        stream << "\n"
+               << std::endl;
+        StreamingReporterBase::testRunEnded(_testRunStats);
+    }
+
+  private:
+    class AssertionPrinter
+    {
+        void operator=(AssertionPrinter const&);
+
+      public:
+        AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)
+            : stream(_stream), stats(_stats), result(_stats.assertionResult), messages(_stats.infoMessages), itMessage(_stats.infoMessages.begin()), printInfoMessages(_printInfoMessages)
+        {
+        }
+
+        void print()
+        {
+            printSourceInfo();
+
+            itMessage = messages.begin();
+
+            switch (result.getResultType())
+            {
+            case ResultWas::Ok:
+                printResultType(Colour::ResultSuccess, passedString());
+                printOriginalExpression();
+                printReconstructedExpression();
+                if (!result.hasExpression())
+                    printRemainingMessages(Colour::None);
+                else
+                    printRemainingMessages();
+                break;
+            case ResultWas::ExpressionFailed:
+                if (result.isOk())
+                    printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok"));
+                else
+                    printResultType(Colour::Error, failedString());
+                printOriginalExpression();
+                printReconstructedExpression();
+                printRemainingMessages();
+                break;
+            case ResultWas::ThrewException:
+                printResultType(Colour::Error, failedString());
+                printIssue("unexpected exception with message:");
+                printMessage();
+                printExpressionWas();
+                printRemainingMessages();
+                break;
+            case ResultWas::FatalErrorCondition:
+                printResultType(Colour::Error, failedString());
+                printIssue("fatal error condition with message:");
+                printMessage();
+                printExpressionWas();
+                printRemainingMessages();
+                break;
+            case ResultWas::DidntThrowException:
+                printResultType(Colour::Error, failedString());
+                printIssue("expected exception, got none");
+                printExpressionWas();
+                printRemainingMessages();
+                break;
+            case ResultWas::Info:
+                printResultType(Colour::None, "info");
+                printMessage();
+                printRemainingMessages();
+                break;
+            case ResultWas::Warning:
+                printResultType(Colour::None, "warning");
+                printMessage();
+                printRemainingMessages();
+                break;
+            case ResultWas::ExplicitFailure:
+                printResultType(Colour::Error, failedString());
+                printIssue("explicitly");
+                printRemainingMessages(Colour::None);
+                break;
+            // These cases are here to prevent compiler warnings
+            case ResultWas::Unknown:
+            case ResultWas::FailureBit:
+            case ResultWas::Exception:
+                printResultType(Colour::Error, "** internal error **");
+                break;
+            }
+        }
+
+      private:
+        // Colour::LightGrey
+
+        static Colour::Code dimColour() { return Colour::FileName; }
+
+#ifdef CATCH_PLATFORM_MAC
+        static const char* failedString()
+        {
+            return "FAILED";
+        }
+        static const char* passedString() { return "PASSED"; }
+#else
+        static const char* failedString()
+        {
+            return "failed";
+        }
+        static const char* passedString() { return "passed"; }
+#endif
+
+        void printSourceInfo() const
+        {
+            Colour colourGuard(Colour::FileName);
+            stream << result.getSourceInfo() << ":";
+        }
+
+        void printResultType(Colour::Code colour, std::string passOrFail) const
+        {
+            if (!passOrFail.empty())
+            {
+                {
+                    Colour colourGuard(colour);
+                    stream << " " << passOrFail;
+                }
+                stream << ":";
+            }
+        }
+
+        void printIssue(std::string issue) const
+        {
+            stream << " " << issue;
+        }
+
+        void printExpressionWas()
+        {
+            if (result.hasExpression())
+            {
+                stream << ";";
+                {
+                    Colour colour(dimColour());
+                    stream << " expression was:";
+                }
+                printOriginalExpression();
+            }
+        }
+
+        void printOriginalExpression() const
+        {
+            if (result.hasExpression())
+            {
+                stream << " " << result.getExpression();
+            }
+        }
+
+        void printReconstructedExpression() const
+        {
+            if (result.hasExpandedExpression())
+            {
+                {
+                    Colour colour(dimColour());
+                    stream << " for: ";
+                }
+                stream << result.getExpandedExpression();
+            }
+        }
+
+        void printMessage()
+        {
+            if (itMessage != messages.end())
+            {
+                stream << " '" << itMessage->message << "'";
+                ++itMessage;
+            }
+        }
+
+        void printRemainingMessages(Colour::Code colour = dimColour())
+        {
+            if (itMessage == messages.end())
+                return;
+
+            // using messages.end() directly yields compilation error:
+            std::vector<MessageInfo>::const_iterator itEnd = messages.end();
+            const std::size_t N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
+
+            {
+                Colour colourGuard(colour);
+                stream << " with " << pluralise(N, "message") << ":";
+            }
+
+            for (; itMessage != itEnd;)
+            {
+                // If this assertion is a warning ignore any INFO messages
+                if (printInfoMessages || itMessage->type != ResultWas::Info)
+                {
+                    stream << " '" << itMessage->message << "'";
+                    if (++itMessage != itEnd)
+                    {
+                        Colour colourGuard(dimColour());
+                        stream << " and";
+                    }
+                }
+            }
+        }
+
+      private:
+        std::ostream& stream;
+        AssertionStats const& stats;
+        AssertionResult const& result;
+        std::vector<MessageInfo> messages;
+        std::vector<MessageInfo>::const_iterator itMessage;
+        bool printInfoMessages;
+    };
+
+    // Colour, message variants:
+    // - white: No tests ran.
+    // -   red: Failed [both/all] N test cases, failed [both/all] M assertions.
+    // - white: Passed [both/all] N test cases (no assertions).
+    // -   red: Failed N tests cases, failed M assertions.
+    // - green: Passed [both/all] N tests cases with M assertions.
+
+    std::string bothOrAll(std::size_t count) const
+    {
+        return count == 1 ? "" : count == 2 ? "both " : "all ";
+    }
+
+    void printTotals(const Totals& totals) const
+    {
+        if (totals.testCases.total() == 0)
+        {
+            stream << "No tests ran.";
+        }
+        else if (totals.testCases.failed == totals.testCases.total())
+        {
+            Colour colour(Colour::ResultError);
+            const std::string qualify_assertions_failed =
+                totals.assertions.failed == totals.assertions.total() ? bothOrAll(totals.assertions.failed) : "";
+            stream << "Failed " << bothOrAll(totals.testCases.failed)
+                   << pluralise(totals.testCases.failed, "test case") << ", "
+                                                                         "failed "
+                   << qualify_assertions_failed << pluralise(totals.assertions.failed, "assertion") << ".";
+        }
+        else if (totals.assertions.total() == 0)
+        {
+            stream << "Passed " << bothOrAll(totals.testCases.total())
+                   << pluralise(totals.testCases.total(), "test case")
+                   << " (no assertions).";
+        }
+        else if (totals.assertions.failed)
+        {
+            Colour colour(Colour::ResultError);
+            stream << "Failed " << pluralise(totals.testCases.failed, "test case") << ", "
+                                                                                      "failed "
+                   << pluralise(totals.assertions.failed, "assertion") << ".";
+        }
+        else
+        {
+            Colour colour(Colour::ResultSuccess);
+            stream << "Passed " << bothOrAll(totals.testCases.passed)
+                   << pluralise(totals.testCases.passed, "test case") << " with " << pluralise(totals.assertions.passed, "assertion") << ".";
+        }
+    }
+};
+
+INTERNAL_CATCH_REGISTER_REPORTER("compact", CompactReporter)
+
+} // end namespace Catch
+
+namespace Catch {
+// These are all here to avoid warnings about not having any out of line
+// virtual methods
+NonCopyable::~NonCopyable() {}
+IShared::~IShared() {}
+IStream::~IStream() CATCH_NOEXCEPT {}
+FileStream::~FileStream() CATCH_NOEXCEPT {}
+CoutStream::~CoutStream() CATCH_NOEXCEPT {}
+DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {}
+StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
+IContext::~IContext() {}
+IResultCapture::~IResultCapture() {}
+ITestCase::~ITestCase() {}
+ITestCaseRegistry::~ITestCaseRegistry() {}
+IRegistryHub::~IRegistryHub() {}
+IMutableRegistryHub::~IMutableRegistryHub() {}
+IExceptionTranslator::~IExceptionTranslator() {}
+IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
+IReporter::~IReporter() {}
+IReporterFactory::~IReporterFactory() {}
+IReporterRegistry::~IReporterRegistry() {}
+IStreamingReporter::~IStreamingReporter() {}
+AssertionStats::~AssertionStats() {}
+SectionStats::~SectionStats() {}
+TestCaseStats::~TestCaseStats() {}
+TestGroupStats::~TestGroupStats() {}
+TestRunStats::~TestRunStats() {}
+CumulativeReporterBase::SectionNode::~SectionNode() {}
+CumulativeReporterBase::~CumulativeReporterBase() {}
+
+StreamingReporterBase::~StreamingReporterBase() {}
+ConsoleReporter::~ConsoleReporter() {}
+CompactReporter::~CompactReporter() {}
+IRunner::~IRunner() {}
+IMutableContext::~IMutableContext() {}
+IConfig::~IConfig() {}
+XmlReporter::~XmlReporter() {}
+JunitReporter::~JunitReporter() {}
+TestRegistry::~TestRegistry() {}
+FreeFunctionTestCase::~FreeFunctionTestCase() {}
+IGeneratorInfo::~IGeneratorInfo() {}
+IGeneratorsForTest::~IGeneratorsForTest() {}
+WildcardPattern::~WildcardPattern() {}
+TestSpec::Pattern::~Pattern() {}
+TestSpec::NamePattern::~NamePattern() {}
+TestSpec::TagPattern::~TagPattern() {}
+TestSpec::ExcludedPattern::~ExcludedPattern() {}
+
+Matchers::Impl::StdString::Equals::~Equals() {}
+Matchers::Impl::StdString::Contains::~Contains() {}
+Matchers::Impl::StdString::StartsWith::~StartsWith() {}
+Matchers::Impl::StdString::EndsWith::~EndsWith() {}
+
+void Config::dummy() {}
+
+namespace TestCaseTracking {
+ITracker::~ITracker() {}
+TrackerBase::~TrackerBase() {}
+SectionTracker::~SectionTracker() {}
+IndexTracker::~IndexTracker() {}
+}
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_MAIN
+// #included from: internal/catch_default_main.hpp
+#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
+
+#ifndef __OBJC__
+
+// Standard C/C++ main entry point
+int main(int argc, char* argv[])
+{
+    return Catch::Session().run(argc, argv);
+}
+
+#else // __OBJC__
+
+// Objective-C entry point
+int main(int argc, char* const argv[])
+{
+#if !CATCH_ARC_ENABLED
+    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+#endif
+
+    Catch::registerTestMethods();
+    int result = Catch::Session().run(argc, (char* const*)argv);
+
+#if !CATCH_ARC_ENABLED
+    [pool drain];
+#endif
+
+    return result;
+}
+
+#endif // __OBJC__
+
+#endif
+
+#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
+#undef CLARA_CONFIG_MAIN
+#endif
+
+//////
+
+// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
+#ifdef CATCH_CONFIG_PREFIX_ALL
+
+#define CATCH_REQUIRE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE")
+#define CATCH_REQUIRE_FALSE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE")
+
+#define CATCH_REQUIRE_THROWS(expr) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS")
+#define CATCH_REQUIRE_THROWS_AS(expr, exceptionType) INTERNAL_CATCH_THROWS_AS(expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS")
+#define CATCH_REQUIRE_THROWS_WITH(expr, matcher) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH")
+#define CATCH_REQUIRE_NOTHROW(expr) INTERNAL_CATCH_NO_THROW(expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW")
+
+#define CATCH_CHECK(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK")
+#define CATCH_CHECK_FALSE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE")
+#define CATCH_CHECKED_IF(expr) INTERNAL_CATCH_IF(expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF")
+#define CATCH_CHECKED_ELSE(expr) INTERNAL_CATCH_ELSE(expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE")
+#define CATCH_CHECK_NOFAIL(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL")
+
+#define CATCH_CHECK_THROWS(expr) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS")
+#define CATCH_CHECK_THROWS_AS(expr, exceptionType) INTERNAL_CATCH_THROWS_AS(expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS")
+#define CATCH_CHECK_THROWS_WITH(expr, matcher) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH")
+#define CATCH_CHECK_NOTHROW(expr) INTERNAL_CATCH_NO_THROW(expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW")
+
+#define CHECK_THAT(arg, matcher) INTERNAL_CHECK_THAT(arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT")
+#define CATCH_REQUIRE_THAT(arg, matcher) INTERNAL_CHECK_THAT(arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT")
+
+#define CATCH_INFO(msg) INTERNAL_CATCH_INFO(msg, "CATCH_INFO")
+#define CATCH_WARN(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg)
+#define CATCH_SCOPED_INFO(msg) INTERNAL_CATCH_INFO(msg, "CATCH_INFO")
+#define CATCH_CAPTURE(msg) INTERNAL_CATCH_INFO(#msg " := " << msg, "CATCH_CAPTURE")
+#define CATCH_SCOPED_CAPTURE(msg) INTERNAL_CATCH_INFO(#msg " := " << msg, "CATCH_CAPTURE")
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define CATCH_TEST_CASE(...) INTERNAL_CATCH_TESTCASE(__VA_ARGS__)
+#define CATCH_TEST_CASE_METHOD(className, ...) INTERNAL_CATCH_TEST_CASE_METHOD(className, __VA_ARGS__)
+#define CATCH_METHOD_AS_TEST_CASE(method, ...) INTERNAL_CATCH_METHOD_AS_TEST_CASE(method, __VA_ARGS__)
+#define CATCH_REGISTER_TEST_CASE(...) INTERNAL_CATCH_REGISTER_TESTCASE(__VA_ARGS__)
+#define CATCH_SECTION(...) INTERNAL_CATCH_SECTION(__VA_ARGS__)
+#define CATCH_FAIL(...) INTERNAL_CATCH_MSG(Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__)
+#define CATCH_SUCCEED(...) INTERNAL_CATCH_MSG(Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__)
+#else
+#define CATCH_TEST_CASE(name, description) INTERNAL_CATCH_TESTCASE(name, description)
+#define CATCH_TEST_CASE_METHOD(className, name, description) INTERNAL_CATCH_TEST_CASE_METHOD(className, name, description)
+#define CATCH_METHOD_AS_TEST_CASE(method, name, description) INTERNAL_CATCH_METHOD_AS_TEST_CASE(method, name, description)
+#define CATCH_REGISTER_TEST_CASE(function, name, description) INTERNAL_CATCH_REGISTER_TESTCASE(function, name, description)
+#define CATCH_SECTION(name, description) INTERNAL_CATCH_SECTION(name, description)
+#define CATCH_FAIL(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg)
+#define CATCH_SUCCEED(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg)
+#endif
+#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE("", "")
+
+#define CATCH_REGISTER_REPORTER(name, reporterType) INTERNAL_CATCH_REGISTER_REPORTER(name, reporterType)
+#define CATCH_REGISTER_LEGACY_REPORTER(name, reporterType) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER(name, reporterType)
+
+#define CATCH_GENERATE(expr) INTERNAL_CATCH_GENERATE(expr)
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define CATCH_SCENARIO(...) CATCH_TEST_CASE("Scenario: " __VA_ARGS__)
+#define CATCH_SCENARIO_METHOD(className, ...) INTERNAL_CATCH_TEST_CASE_METHOD(className, "Scenario: " __VA_ARGS__)
+#else
+#define CATCH_SCENARIO(name, tags) CATCH_TEST_CASE("Scenario: " name, tags)
+#define CATCH_SCENARIO_METHOD(className, name, tags) INTERNAL_CATCH_TEST_CASE_METHOD(className, "Scenario: " name, tags)
+#endif
+#define CATCH_GIVEN(desc) CATCH_SECTION(std::string("Given: ") + desc, "")
+#define CATCH_WHEN(desc) CATCH_SECTION(std::string(" When: ") + desc, "")
+#define CATCH_AND_WHEN(desc) CATCH_SECTION(std::string("  And: ") + desc, "")
+#define CATCH_THEN(desc) CATCH_SECTION(std::string(" Then: ") + desc, "")
+#define CATCH_AND_THEN(desc) CATCH_SECTION(std::string("  And: ") + desc, "")
+
+// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
+#else
+
+#define REQUIRE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::Normal, "REQUIRE")
+#define REQUIRE_FALSE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE")
+
+#define REQUIRE_THROWS(expr) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS")
+#define REQUIRE_THROWS_AS(expr, exceptionType) INTERNAL_CATCH_THROWS_AS(expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS")
+#define REQUIRE_THROWS_WITH(expr, matcher) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH")
+#define REQUIRE_NOTHROW(expr) INTERNAL_CATCH_NO_THROW(expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW")
+
+#define CHECK(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK")
+#define CHECK_FALSE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE")
+#define CHECKED_IF(expr) INTERNAL_CATCH_IF(expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF")
+#define CHECKED_ELSE(expr) INTERNAL_CATCH_ELSE(expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE")
+#define CHECK_NOFAIL(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL")
+
+#define CHECK_THROWS(expr) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS")
+#define CHECK_THROWS_AS(expr, exceptionType) INTERNAL_CATCH_THROWS_AS(expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS")
+#define CHECK_THROWS_WITH(expr, matcher) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH")
+#define CHECK_NOTHROW(expr) INTERNAL_CATCH_NO_THROW(expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW")
+
+#define CHECK_THAT(arg, matcher) INTERNAL_CHECK_THAT(arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT")
+#define REQUIRE_THAT(arg, matcher) INTERNAL_CHECK_THAT(arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT")
+
+#define INFO(msg) INTERNAL_CATCH_INFO(msg, "INFO")
+#define WARN(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg)
+#define SCOPED_INFO(msg) INTERNAL_CATCH_INFO(msg, "INFO")
+#define CAPTURE(msg) INTERNAL_CATCH_INFO(#msg " := " << msg, "CAPTURE")
+#define SCOPED_CAPTURE(msg) INTERNAL_CATCH_INFO(#msg " := " << msg, "CAPTURE")
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define TEST_CASE(...) INTERNAL_CATCH_TESTCASE(__VA_ARGS__)
+#define TEST_CASE_METHOD(className, ...) INTERNAL_CATCH_TEST_CASE_METHOD(className, __VA_ARGS__)
+#define METHOD_AS_TEST_CASE(method, ...) INTERNAL_CATCH_METHOD_AS_TEST_CASE(method, __VA_ARGS__)
+#define REGISTER_TEST_CASE(...) INTERNAL_CATCH_REGISTER_TESTCASE(__VA_ARGS__)
+#define SECTION(...) INTERNAL_CATCH_SECTION(__VA_ARGS__)
+#define FAIL(...) INTERNAL_CATCH_MSG(Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__)
+#define SUCCEED(...) INTERNAL_CATCH_MSG(Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__)
+#else
+#define TEST_CASE(name, description) INTERNAL_CATCH_TESTCASE(name, description)
+#define TEST_CASE_METHOD(className, name, description) INTERNAL_CATCH_TEST_CASE_METHOD(className, name, description)
+#define METHOD_AS_TEST_CASE(method, name, description) INTERNAL_CATCH_METHOD_AS_TEST_CASE(method, name, description)
+#define REGISTER_TEST_CASE(method, name, description) INTERNAL_CATCH_REGISTER_TESTCASE(method, name, description)
+#define SECTION(name, description) INTERNAL_CATCH_SECTION(name, description)
+#define FAIL(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg)
+#define SUCCEED(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg)
+#endif
+#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE("", "")
+
+#define REGISTER_REPORTER(name, reporterType) INTERNAL_CATCH_REGISTER_REPORTER(name, reporterType)
+#define REGISTER_LEGACY_REPORTER(name, reporterType) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER(name, reporterType)
+
+#define GENERATE(expr) INTERNAL_CATCH_GENERATE(expr)
+
+#endif
+
+#define CATCH_TRANSLATE_EXCEPTION(signature) INTERNAL_CATCH_TRANSLATE_EXCEPTION(signature)
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define SCENARIO(...) TEST_CASE("Scenario: " __VA_ARGS__)
+#define SCENARIO_METHOD(className, ...) INTERNAL_CATCH_TEST_CASE_METHOD(className, "Scenario: " __VA_ARGS__)
+#else
+#define SCENARIO(name, tags) TEST_CASE("Scenario: " name, tags)
+#define SCENARIO_METHOD(className, name, tags) INTERNAL_CATCH_TEST_CASE_METHOD(className, "Scenario: " name, tags)
+#endif
+#define GIVEN(desc) SECTION(std::string("   Given: ") + desc, "")
+#define WHEN(desc) SECTION(std::string("    When: ") + desc, "")
+#define AND_WHEN(desc) SECTION(std::string("And when: ") + desc, "")
+#define THEN(desc) SECTION(std::string("    Then: ") + desc, "")
+#define AND_THEN(desc) SECTION(std::string("     And: ") + desc, "")
+
+using Catch::Detail::Approx;
+
+#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
diff --git a/third_party/variant/test/optional_unit.cpp b/third_party/variant/test/optional_unit.cpp
deleted file mode 100644
index a6573ca..0000000
--- a/third_party/variant/test/optional_unit.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-#define CATCH_CONFIG_RUNNER
-#include "catch.hpp"
-
-#include "optional.hpp"
-
-using namespace mapbox;
-
-struct dummy {
-    dummy(int _m_1, int _m_2) : m_1(_m_1), m_2(_m_2) {}
-    int m_1;
-    int m_2;
-
-};
-
-int main (int argc, char* const argv[])
-{
-    int result = Catch::Session().run(argc, argv);
-    if (!result) printf("\x1b[1;32m ✓ \x1b[0m\n");
-    return result;
-}
-
-TEST_CASE( "optional can be instantiated with a POD type", "[optiona]" ) {
-    mapbox::util::optional<double> dbl_opt;
-
-    REQUIRE(!dbl_opt);
-    dbl_opt = 3.1415;
-    REQUIRE(dbl_opt);
-
-    REQUIRE(dbl_opt.get() == 3.1415);
-    REQUIRE(*dbl_opt == 3.1415);
-}
-
-TEST_CASE( "copy c'tor", "[optiona]" ) {
-    mapbox::util::optional<double> dbl_opt;
-
-    REQUIRE(!dbl_opt);
-    dbl_opt = 3.1415;
-    REQUIRE(dbl_opt);
-
-    mapbox::util::optional<double> other = dbl_opt;
-
-    REQUIRE(other.get() == 3.1415);
-    REQUIRE(*other == 3.1415);
-}
-
-TEST_CASE( "const operator*, const get()", "[optiona]" ) {
-    mapbox::util::optional<double> dbl_opt = 3.1415;
-
-    REQUIRE(dbl_opt);
-
-    const double pi1 = dbl_opt.get();
-    const double pi2 = *dbl_opt;
-
-    REQUIRE(pi1 == 3.1415);
-    REQUIRE(pi2 == 3.1415);
-}
-
-TEST_CASE( "emplace initialization, reset", "[optional]" ) {
-    mapbox::util::optional<dummy> dummy_opt;
-    REQUIRE(!dummy_opt);
-
-    // rvalues, baby!
-    dummy_opt.emplace(1, 2);
-    REQUIRE(dummy_opt);
-    REQUIRE(dummy_opt.get().m_1 == 1);
-    REQUIRE((*dummy_opt).m_2 == 2);
-
-    dummy_opt.reset();
-    REQUIRE(!dummy_opt);
-}
-
-TEST_CASE( "assignment", "[optional]") {
-    mapbox::util::optional<int> a;
-    mapbox::util::optional<int> b;
-
-    a = 1; b = 3;
-    REQUIRE(a.get() == 1);
-    REQUIRE(b.get() == 3);
-    b = a;
-    REQUIRE(a.get() == b.get());
-    REQUIRE(b.get() == 1);
-}
diff --git a/third_party/variant/test/our_variant_hello_world.cpp b/third_party/variant/test/our_variant_hello_world.cpp
new file mode 100644
index 0000000..be5996b
--- /dev/null
+++ b/third_party/variant/test/our_variant_hello_world.cpp
@@ -0,0 +1,20 @@
+#include "variant.hpp"
+
+#include <stdexcept>
+
+struct check
+{
+    template <typename T>
+    void operator()(T const& val) const
+    {
+        if (val != 0) throw std::runtime_error("invalid");
+    }
+};
+
+int main()
+{
+    typedef mapbox::util::variant<bool, int, double> variant_type;
+    variant_type v(0);
+    mapbox::util::apply_visitor(check(), v);
+    return 0;
+}
diff --git a/third_party/variant/test/recursive_wrapper_test.cpp b/third_party/variant/test/recursive_wrapper_test.cpp
index 3cd79b5..0492af4 100644
--- a/third_party/variant/test/recursive_wrapper_test.cpp
+++ b/third_party/variant/test/recursive_wrapper_test.cpp
@@ -1,11 +1,12 @@
+
+#include <cstdlib>
 #include <iostream>
-#include <vector>
-#include <thread>
 #include <string>
-#include <sstream>
+#include <typeinfo>
 #include <utility>
-#include <type_traits>
+
 #include <boost/timer/timer.hpp>
+
 #include "variant.hpp"
 
 using namespace mapbox;
@@ -14,48 +15,48 @@ namespace test {
 
 struct add;
 struct sub;
-template <typename OpTag> struct binary_op;
 
-typedef util::variant<int ,
+template <typename OpTag>
+struct binary_op;
+
+typedef util::variant<int,
                       util::recursive_wrapper<binary_op<add>>,
-                      util::recursive_wrapper<binary_op<sub>>
-                      > expression;
+                      util::recursive_wrapper<binary_op<sub>>>
+    expression;
 
 template <typename Op>
 struct binary_op
 {
-    expression left;  // variant instantiated here...
+    expression left; // variant instantiated here...
     expression right;
 
-    binary_op(expression && lhs, expression && rhs)
+    binary_op(expression&& lhs, expression&& rhs)
         : left(std::move(lhs)), right(std::move(rhs))
     {
     }
 };
 
-struct print : util::static_visitor<void>
+struct print
 {
     template <typename T>
-    void operator() (T const& val) const
+    void operator()(T const& val) const
     {
         std::cerr << val << ":" << typeid(T).name() << std::endl;
     }
 };
 
-
-struct test : util::static_visitor<std::string>
+struct test
 {
     template <typename T>
-    std::string operator() (T const& obj) const
+    std::string operator()(T const& obj) const
     {
         return std::string("TYPE_ID=") + typeid(obj).name();
     }
 };
 
-struct calculator : public util::static_visitor<int>
+struct calculator
 {
-public:
-
+  public:
     int operator()(int value) const
     {
         return value;
@@ -63,21 +64,18 @@ public:
 
     int operator()(binary_op<add> const& binary) const
     {
-        return util::apply_visitor(calculator(), binary.left)
-            + util::apply_visitor(calculator(), binary.right);
+        return util::apply_visitor(calculator(), binary.left) + util::apply_visitor(calculator(), binary.right);
     }
 
     int operator()(binary_op<sub> const& binary) const
     {
-        return util::apply_visitor(calculator(), binary.left)
-            - util::apply_visitor(calculator(), binary.right);
+        return util::apply_visitor(calculator(), binary.left) - util::apply_visitor(calculator(), binary.right);
     }
 };
 
-struct to_string : public util::static_visitor<std::string>
+struct to_string
 {
-public:
-
+  public:
     std::string operator()(int value) const
     {
         return std::to_string(value);
@@ -85,23 +83,19 @@ public:
 
     std::string operator()(binary_op<add> const& binary) const
     {
-        return util::apply_visitor(to_string(), binary.left) + std::string("+")
-            + util::apply_visitor(to_string(), binary.right);
+        return util::apply_visitor(to_string(), binary.left) + std::string("+") + util::apply_visitor(to_string(), binary.right);
     }
 
     std::string operator()(binary_op<sub> const& binary) const
     {
-        return util::apply_visitor(to_string(), binary.left) + std::string("-")
-            + util::apply_visitor(to_string(), binary.right);
+        return util::apply_visitor(to_string(), binary.left) + std::string("-") + util::apply_visitor(to_string(), binary.right);
     }
-
 };
 
 } // namespace test
 
-int main (int argc, char** argv)
+int main(int argc, char** argv)
 {
-
     if (argc != 2)
     {
         std::cerr << "Usage" << argv[0] << " <num-iter>" << std::endl;
@@ -110,21 +104,20 @@ int main (int argc, char** argv)
 
     const std::size_t NUM_ITER = static_cast<std::size_t>(std::stol(argv[1]));
 
-    test::expression result(
-        test::binary_op<test::sub>(
-            test::binary_op<test::add>(2, 3), 4));
+    test::expression sum(test::binary_op<test::add>(2, 3));
+    test::expression result(test::binary_op<test::sub>(std::move(sum), 4));
 
     std::cerr << "TYPE OF RESULT-> " << util::apply_visitor(test::test(), result) << std::endl;
 
+    int total = 0;
     {
         boost::timer::auto_cpu_timer t;
-        int total = 0;
         for (std::size_t i = 0; i < NUM_ITER; ++i)
         {
             total += util::apply_visitor(test::calculator(), result);
         }
-        std::cerr << "total=" << total << std::endl;
     }
+    std::cerr << "total=" << total << std::endl;
 
     std::cerr << util::apply_visitor(test::to_string(), result) << "=" << util::apply_visitor(test::calculator(), result) << std::endl;
 
diff --git a/third_party/variant/test/reference_wrapper_test.cpp b/third_party/variant/test/reference_wrapper_test.cpp
index 2abf027..dc1209f 100644
--- a/third_party/variant/test/reference_wrapper_test.cpp
+++ b/third_party/variant/test/reference_wrapper_test.cpp
@@ -1,11 +1,11 @@
+#include <cstdlib>
+#include <functional>
 #include <iostream>
-#include <vector>
-#include <thread>
-#include <string>
-#include <sstream>
-#include <utility>
 #include <type_traits>
-#include <boost/timer/timer.hpp>
+#include <typeinfo>
+#include <utility>
+#include <vector>
+
 #include "variant.hpp"
 
 using namespace mapbox;
@@ -14,15 +14,19 @@ namespace test {
 
 struct point
 {
-public:
-    point (double x_, double y_)
+  public:
+    point(double x_, double y_)
         : x(x_), y(y_) {}
     double x;
     double y;
 };
 
-struct line_string : std::vector<point> {};
-struct polygon : std::vector<line_string> {};
+struct line_string : std::vector<point>
+{
+};
+struct polygon : std::vector<line_string>
+{
+};
 using variant = util::variant<std::reference_wrapper<const point>,
                               std::reference_wrapper<const line_string>,
                               std::reference_wrapper<const polygon>>;
@@ -30,11 +34,11 @@ using variant = util::variant<std::reference_wrapper<const point>,
 struct print
 {
     using result_type = void;
-    void operator() (point const& pt) const
+    void operator()(point const& pt) const
     {
         std::cerr << "Point(" << pt.x << "," << pt.y << ")" << std::endl;
     }
-    void operator() (line_string const& line) const
+    void operator()(line_string const& line) const
     {
         std::cerr << "Line(";
         for (auto const& pt : line)
@@ -44,27 +48,25 @@ struct print
         std::cerr << ")" << std::endl;
     }
     template <typename T>
-    void operator() (T const& val) const
+    void operator()(T const& val) const
     {
         std::cerr << typeid(T).name() << std::endl;
     }
 };
-
-
 }
 
-int main (int argc, char** argv)
+int main()
 {
     std::cerr << sizeof(test::polygon) << std::endl;
     std::cerr << sizeof(test::variant) << std::endl;
-    test::point pt(123,456);
-    test::variant var = std::move(std::cref(pt));
+    test::point pt(123, 456);
+    test::variant var = std::cref(pt);
     util::apply_visitor(test::print(), var);
     test::line_string line;
     line.push_back(pt);
     line.push_back(pt);
-    line.push_back(test::point(999,333));
-    var = std::move(std::cref(line));
+    line.push_back(test::point(999, 333));
+    var = std::cref(line);
     util::apply_visitor(test::print(), var);
     std::cerr << "Is line (cref) ? " << var.is<std::reference_wrapper<test::line_string const>>() << std::endl;
     auto const& line2 = var.get<test::line_string>(); // accessing underlying type of std::reference_wrapper<T>
diff --git a/third_party/variant/test/t/binary_visitor_1.cpp b/third_party/variant/test/t/binary_visitor_1.cpp
new file mode 100644
index 0000000..298a40b
--- /dev/null
+++ b/third_party/variant/test/t/binary_visitor_1.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " i-d"
+using variant_type = mapbox::util::variant<int, double>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/third_party/variant/test/t/binary_visitor_2.cpp b/third_party/variant/test/t/binary_visitor_2.cpp
new file mode 100644
index 0000000..33768b6
--- /dev/null
+++ b/third_party/variant/test/t/binary_visitor_2.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " b-i-d"
+using variant_type = mapbox::util::variant<bool, int, double>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/third_party/variant/test/t/binary_visitor_3.cpp b/third_party/variant/test/t/binary_visitor_3.cpp
new file mode 100644
index 0000000..d35af4e
--- /dev/null
+++ b/third_party/variant/test/t/binary_visitor_3.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " i-d-b"
+using variant_type = mapbox::util::variant<int, double, bool>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/third_party/variant/test/t/binary_visitor_4.cpp b/third_party/variant/test/t/binary_visitor_4.cpp
new file mode 100644
index 0000000..daacc1b
--- /dev/null
+++ b/third_party/variant/test/t/binary_visitor_4.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " b-i-d-c"
+using variant_type = mapbox::util::variant<bool, int, double, char>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/third_party/variant/test/t/binary_visitor_5.cpp b/third_party/variant/test/t/binary_visitor_5.cpp
new file mode 100644
index 0000000..28669be
--- /dev/null
+++ b/third_party/variant/test/t/binary_visitor_5.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " b-i-c-d-i"
+using variant_type = mapbox::util::variant<bool, int, char, double, int>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/third_party/variant/test/t/binary_visitor_6.cpp b/third_party/variant/test/t/binary_visitor_6.cpp
new file mode 100644
index 0000000..c881b0f
--- /dev/null
+++ b/third_party/variant/test/t/binary_visitor_6.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " b-i-i-d-c-u"
+using variant_type = mapbox::util::variant<bool, int, int, double, char, short int>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/third_party/variant/test/t/binary_visitor_impl.hpp b/third_party/variant/test/t/binary_visitor_impl.hpp
new file mode 100644
index 0000000..4d9a43f
--- /dev/null
+++ b/third_party/variant/test/t/binary_visitor_impl.hpp
@@ -0,0 +1,204 @@
+
+#include <type_traits>
+
+#include "catch.hpp"
+
+#include "variant_io.hpp"
+
+struct add_visitor
+{
+    add_visitor() {}
+
+    template <typename A, typename B>
+    double operator()(A a, B b) const
+    {
+        return a + b;
+    }
+};
+
+TEST_CASE("const binary visitor works on const variants" NAME_EXT, "[visitor][binary visitor]")
+{
+    const variant_type a{7};
+    const variant_type b = 3;
+    const variant_type c{7.1};
+    const variant_type d = 2.9;
+
+    const add_visitor v;
+
+    REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(14.1));
+    REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(9.9));
+
+    REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(14.1));
+    REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(9.9));
+}
+
+TEST_CASE("non-const binary visitor works on const variants" NAME_EXT, "[visitor][binary visitor]")
+{
+    const variant_type a = 7;
+    const variant_type b = 3;
+    const variant_type c = 7.1;
+    const variant_type d = 2.9;
+
+    add_visitor v;
+
+    REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(14.1));
+    REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(9.9));
+
+    REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(14.1));
+    REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(9.9));
+}
+
+TEST_CASE("const binary visitor works on non-const variants" NAME_EXT, "[visitor][binary visitor]")
+{
+    variant_type a = 7;
+    variant_type b = 3;
+    variant_type c = 7.1;
+    variant_type d = 2.9;
+
+    const add_visitor v;
+
+    REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(14.1));
+    REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(9.9));
+
+    REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(14.1));
+    REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(9.9));
+}
+
+TEST_CASE("non-const binary visitor works on non-const variants" NAME_EXT, "[visitor][binary visitor]")
+{
+    variant_type a = 7;
+    variant_type b = 3;
+    variant_type c = 7.1;
+    variant_type d = 2.9;
+
+    add_visitor v;
+
+    REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(14.1));
+    REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(9.9));
+
+    REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(14.1));
+    REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(9.9));
+}
+
+TEST_CASE("rvalue binary visitor works on const variants" NAME_EXT, "[visitor][binary visitor]")
+{
+    const variant_type a = 7;
+    const variant_type b = 3;
+    const variant_type c = 7.1;
+    const variant_type d = 2.9;
+
+    REQUIRE(mapbox::util::apply_visitor(add_visitor{}, a, b) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(add_visitor{}, c, d) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(add_visitor{}, a, c) == Approx(14.1));
+    REQUIRE(mapbox::util::apply_visitor(add_visitor{}, a, d) == Approx(9.9));
+
+    REQUIRE(mapbox::util::apply_visitor(add_visitor{}, b, a) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(add_visitor{}, d, c) == Approx(10));
+    REQUIRE(mapbox::util::apply_visitor(add_visitor{}, c, a) == Approx(14.1));
+    REQUIRE(mapbox::util::apply_visitor(add_visitor{}, d, a) == Approx(9.9));
+}
+
+struct sum_mul_visitor
+{
+    double sum;
+
+    sum_mul_visitor() : sum(0.0) {}
+
+    template <typename A, typename B>
+    double operator()(A a, B b)
+    {
+        double m = a * b;
+        sum += m;
+        return m;
+    }
+};
+
+TEST_CASE("mutable binary visitor works" NAME_EXT, "[visitor][binary visitor]")
+{
+    const variant_type a = 2;
+    const variant_type b = 3;
+    const variant_type c = 0.1;
+    const variant_type d = 0.2;
+
+    sum_mul_visitor v;
+
+    REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(6));
+    REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(0.02));
+    REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(0.2));
+    REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(0.4));
+
+    REQUIRE(v.sum == Approx(6.62));
+
+    REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(6));
+    REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(0.02));
+    REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(0.2));
+    REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(0.4));
+}
+
+struct swap_visitor
+{
+    swap_visitor(){};
+
+    template <typename A, typename B>
+    void operator()(A& a, B& b) const
+    {
+        using T = typename std::common_type<A, B>::type;
+        T tmp = a;
+        a = b;
+        b = tmp;
+    }
+};
+
+TEST_CASE("static mutating visitor on mutable variants works" NAME_EXT, "[visitor][binary visitor]")
+{
+    variant_type a = 2;
+    variant_type b = 3;
+    variant_type c = 0.1;
+    variant_type d = 0.2;
+
+    const swap_visitor v;
+
+    SECTION("swap a and b")
+    {
+        mapbox::util::apply_visitor(v, a, b);
+        REQUIRE(a.get<int>() == 3);
+        REQUIRE(b.get<int>() == 2);
+    }
+
+    SECTION("swap c and d")
+    {
+        mapbox::util::apply_visitor(v, c, d);
+        REQUIRE(c.get<double>() == Approx(0.2));
+        REQUIRE(d.get<double>() == Approx(0.1));
+    }
+
+    SECTION("swap a and c")
+    {
+        mapbox::util::apply_visitor(v, a, c);
+        REQUIRE(a.get<int>() == 0);
+        REQUIRE(c.get<double>() == Approx(2.0));
+    }
+
+    SECTION("swap c and a")
+    {
+        mapbox::util::apply_visitor(v, c, a);
+        REQUIRE(a.get<int>() == 0);
+        REQUIRE(c.get<double>() == Approx(2.0));
+    }
+}
diff --git a/third_party/variant/test/t/issue21.cpp b/third_party/variant/test/t/issue21.cpp
new file mode 100644
index 0000000..b952313
--- /dev/null
+++ b/third_party/variant/test/t/issue21.cpp
@@ -0,0 +1,48 @@
+
+#include "catch.hpp"
+
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+// https://github.com/mapbox/variant/issues/21
+
+static int count;
+
+struct t1
+{
+    int value;
+    t1(int v) : value(v)
+    {
+        ++count;
+    }
+    ~t1()
+    {
+        --count;
+    }
+};
+
+struct t2
+{
+    int value;
+    t2(int v) : value(v)
+    { // constructor fails
+        throw std::runtime_error("fail");
+    }
+};
+
+TEST_CASE("set() works cleanly even if the constructor throws ", "[variant]")
+{
+
+    using variant_type = mapbox::util::variant<t1, t2>;
+
+    count = 0;
+    {
+        variant_type v{42};
+        REQUIRE(v.is<t1>());
+        REQUIRE(v.get<t1>().value == 42);
+        REQUIRE_THROWS({
+            v.set<t2>(13);
+        });
+    }
+    REQUIRE(count == 0);
+}
diff --git a/third_party/variant/test/t/mutating_visitor.cpp b/third_party/variant/test/t/mutating_visitor.cpp
new file mode 100644
index 0000000..f07afb8
--- /dev/null
+++ b/third_party/variant/test/t/mutating_visitor.cpp
@@ -0,0 +1,36 @@
+
+#include "catch.hpp"
+
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+#include <string>
+
+template <typename T>
+struct mutating_visitor
+{
+    mutating_visitor(T& val)
+        : val_(val) {}
+
+    void operator()(T& val) const
+    {
+        val = val_;
+    }
+
+    template <typename T1>
+    void operator()(T1&) const
+    {
+    } // no-op
+
+    T& val_;
+};
+
+TEST_CASE("variant visitation", "[visitor][unary visitor]")
+{
+    mapbox::util::variant<int, double, std::string> var(123);
+    REQUIRE(var.get<int>() == 123);
+    int val = 456;
+    const mutating_visitor<int> visitor(val);
+    mapbox::util::apply_visitor(visitor, var);
+    REQUIRE(var.get<int>() == 456);
+}
diff --git a/third_party/variant/test/t/optional.cpp b/third_party/variant/test/t/optional.cpp
new file mode 100644
index 0000000..b77beda
--- /dev/null
+++ b/third_party/variant/test/t/optional.cpp
@@ -0,0 +1,102 @@
+
+#include "catch.hpp"
+
+#include "optional.hpp"
+
+struct dummy
+{
+    dummy(int _m_1, int _m_2) : m_1(_m_1), m_2(_m_2) {}
+    int m_1;
+    int m_2;
+};
+
+TEST_CASE("optional can be instantiated with a POD type", "[optional]")
+{
+    mapbox::util::optional<int> dbl_opt;
+
+    REQUIRE(!dbl_opt);
+    dbl_opt = 3;
+    REQUIRE(dbl_opt);
+
+    REQUIRE(dbl_opt.get() == 3);
+    REQUIRE(*dbl_opt == 3);
+}
+
+TEST_CASE("copy c'tor", "[optional]")
+{
+    mapbox::util::optional<int> dbl_opt;
+
+    REQUIRE(!dbl_opt);
+    dbl_opt = 3;
+    REQUIRE(dbl_opt);
+
+    mapbox::util::optional<int> other = dbl_opt;
+
+    REQUIRE(other.get() == 3);
+    REQUIRE(*other == 3);
+}
+
+TEST_CASE("const operator*, const get()", "[optional]")
+{
+    const mapbox::util::optional<int> dbl_opt = 3;
+
+    REQUIRE(dbl_opt);
+
+    auto pi1 = dbl_opt.get();
+    auto pi2 = *dbl_opt;
+
+    REQUIRE(pi1 == 3);
+    REQUIRE(pi2 == 3);
+}
+
+TEST_CASE("non-const operator*, non-const get()", "[optional]")
+{
+    mapbox::util::optional<int> dbl_opt = 3;
+
+    REQUIRE(dbl_opt);
+
+    auto pi1 = dbl_opt.get();
+    auto pi2 = *dbl_opt;
+
+    REQUIRE(pi1 == 3);
+    REQUIRE(pi2 == 3);
+}
+
+TEST_CASE("emplace initialization, reset", "[optional]")
+{
+    mapbox::util::optional<dummy> dummy_opt;
+    REQUIRE(!dummy_opt);
+
+    // rvalues, baby!
+    dummy_opt.emplace(1, 2);
+    REQUIRE(dummy_opt);
+    REQUIRE(dummy_opt.get().m_1 == 1);
+    REQUIRE((*dummy_opt).m_2 == 2);
+
+    dummy_opt.reset();
+    REQUIRE(!dummy_opt);
+}
+
+TEST_CASE("assignment", "[optional]")
+{
+    mapbox::util::optional<int> a;
+    mapbox::util::optional<int> b;
+
+    a = 1;
+    b = 3;
+    REQUIRE(a.get() == 1);
+    REQUIRE(b.get() == 3);
+    b = a;
+    REQUIRE(a.get() == b.get());
+    REQUIRE(b.get() == 1);
+}
+
+TEST_CASE("self assignment", "[optional]")
+{
+    mapbox::util::optional<int> a;
+
+    a = 1;
+    REQUIRE(a.get() == 1);
+    a = a;
+    REQUIRE(a.get() == 1);
+}
diff --git a/third_party/variant/test/t/recursive_wrapper.cpp b/third_party/variant/test/t/recursive_wrapper.cpp
new file mode 100644
index 0000000..b2dec45
--- /dev/null
+++ b/third_party/variant/test/t/recursive_wrapper.cpp
@@ -0,0 +1,158 @@
+
+#include "catch.hpp"
+
+#include "recursive_wrapper.hpp"
+
+#include <type_traits>
+#include <utility>
+
+using rwi = mapbox::util::recursive_wrapper<int>;
+using rwp = mapbox::util::recursive_wrapper<std::pair<int, int>>;
+
+static_assert(std::is_same<rwi::type, int>::value, "type check failed");
+
+TEST_CASE("recursive wrapper of int")
+{
+
+    SECTION("construct with value")
+    {
+        rwi a{7};
+
+        REQUIRE(a.get() == 7);
+        REQUIRE(*a.get_pointer() == 7);
+
+        a = 8;
+        REQUIRE(a.get() == 8);
+
+        rwi b{a};
+        REQUIRE(b.get() == 8);
+
+        rwi c;
+        c = b;
+        REQUIRE(b.get() == 8);
+        REQUIRE(c.get() == 8);
+
+        c = 9;
+        REQUIRE(c.get() == 9);
+
+        int x = 10;
+        c = x;
+        REQUIRE(c.get() == 10);
+
+        b = std::move(c);
+        REQUIRE(b.get() == 10);
+    }
+
+    SECTION("construct with const reference")
+    {
+        int i = 7;
+        rwi a{i};
+
+        REQUIRE(a.get() == 7);
+    }
+
+    SECTION("implicit conversion to reference of underlying type")
+    {
+
+        SECTION("const")
+        {
+            rwi const a{7};
+            REQUIRE(a.get() == 7);
+            REQUIRE(*a.get_pointer() == 7);
+
+            rwi::type const& underlying = a;
+            REQUIRE(underlying == 7);
+        }
+
+        SECTION("non const")
+        {
+            rwi a{7};
+            REQUIRE(a.get() == 7);
+            REQUIRE(*a.get_pointer() == 7);
+
+            rwi::type& underlying = a;
+            REQUIRE(underlying == 7);
+            a = 8;
+            REQUIRE(underlying == 8);
+        }
+    }
+}
+
+TEST_CASE("move of recursive wrapper")
+{
+    rwi a{1};
+
+    SECTION("move constructor")
+    {
+        rwi b{std::move(a)};
+        REQUIRE(b.get() == 1);
+    }
+
+    SECTION("operator= on rvalue")
+    {
+        rwi b{2};
+        b = std::move(a);
+        REQUIRE(b.get() == 1);
+    }
+}
+
+TEST_CASE("swap")
+{
+    rwi a{1};
+    rwi b{2};
+
+    REQUIRE(a.get() == 1);
+    REQUIRE(b.get() == 2);
+
+    using std::swap;
+    swap(a, b);
+
+    REQUIRE(a.get() == 2);
+    REQUIRE(b.get() == 1);
+}
+
+TEST_CASE("recursive wrapper of pair<int, int>")
+{
+
+    SECTION("default constructed")
+    {
+        rwp a;
+        REQUIRE(a.get().first == 0);
+        REQUIRE(a.get().second == 0);
+    }
+
+    SECTION("construct with value")
+    {
+        rwp a{std::make_pair(1, 2)};
+
+        REQUIRE(a.get().first == 1);
+        REQUIRE(a.get().second == 2);
+
+        REQUIRE(a.get_pointer()->first == 1);
+        REQUIRE(a.get_pointer()->second == 2);
+
+        a = {3, 4};
+        REQUIRE(a.get().first == 3);
+        REQUIRE(a.get().second == 4);
+
+        rwp b{a};
+        REQUIRE(b.get().first == 3);
+        REQUIRE(b.get().second == 4);
+
+        rwp c;
+        c = b;
+        REQUIRE(b.get().first == 3);
+        REQUIRE(b.get().second == 4);
+        REQUIRE(c.get().first == 3);
+        REQUIRE(c.get().second == 4);
+
+        c = {5, 6};
+        REQUIRE(c.get().first == 5);
+        REQUIRE(c.get().second == 6);
+
+        b = std::move(c);
+        REQUIRE(b.get().first == 5);
+        REQUIRE(b.get().second == 6);
+        //        REQUIRE(c.get_pointer() == nullptr);
+    }
+}
diff --git a/third_party/variant/test/t/sizeof.cpp b/third_party/variant/test/t/sizeof.cpp
new file mode 100644
index 0000000..0e74ce5
--- /dev/null
+++ b/third_party/variant/test/t/sizeof.cpp
@@ -0,0 +1,52 @@
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+
+#include "catch.hpp"
+
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+struct some_struct
+{
+    int a;
+    bool b;
+    std::string c;
+};
+
+using variant_internal_index_type = size_t;
+
+TEST_CASE("size of variants")
+{
+    constexpr const auto min_overhead = sizeof(variant_internal_index_type);
+
+    using namespace std; // workaround for bug in GCC <= 4.8 where max_align_t is not in std
+    constexpr const auto max_overhead = alignof(max_align_t) + min_overhead;
+
+    using v1 = mapbox::util::variant<int>;
+    using v2 = mapbox::util::variant<int, bool, int64_t>;
+    using v3 = mapbox::util::variant<int, std::string>;
+    using v4 = mapbox::util::variant<std::string, std::string>;
+    using v5 = mapbox::util::variant<some_struct>;
+
+    constexpr const auto si = sizeof(int);
+    constexpr const auto sb = sizeof(bool);
+    constexpr const auto si64 = sizeof(int64_t);
+    constexpr const auto sd = sizeof(double);
+    constexpr const auto sstr = sizeof(std::string);
+    constexpr const auto spi = sizeof(std::pair<int, int>);
+    constexpr const auto ss = sizeof(some_struct);
+
+    REQUIRE(sizeof(v1) <= max_overhead + si);
+    REQUIRE(sizeof(v2) <= max_overhead + std::max({si, sb, si64}));
+    REQUIRE(sizeof(v3) <= max_overhead + std::max({si, sstr}));
+    REQUIRE(sizeof(v4) <= max_overhead + sstr);
+    REQUIRE(sizeof(v5) <= max_overhead + ss);
+
+    REQUIRE(sizeof(v1) >= min_overhead + si);
+    REQUIRE(sizeof(v2) >= min_overhead + std::max({si, sb, si64}));
+    REQUIRE(sizeof(v3) >= min_overhead + std::max({si, sstr}));
+    REQUIRE(sizeof(v4) >= min_overhead + sstr);
+    REQUIRE(sizeof(v5) >= min_overhead + ss);
+}
diff --git a/third_party/variant/test/t/unary_visitor.cpp b/third_party/variant/test/t/unary_visitor.cpp
new file mode 100644
index 0000000..8df6110
--- /dev/null
+++ b/third_party/variant/test/t/unary_visitor.cpp
@@ -0,0 +1,127 @@
+
+#include "catch.hpp"
+
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+#include <string>
+
+struct some_visitor
+{
+    int var_;
+
+    some_visitor(int init)
+        : var_(init) {}
+
+    int operator()(int val) const
+    {
+        return var_ + val;
+    }
+
+    int operator()(double val) const
+    {
+        return var_ + int(val);
+    }
+
+    int operator()(const std::string&) const
+    {
+        return 0;
+    }
+};
+
+TEST_CASE("non-const visitor works on const variants", "[visitor][unary visitor]")
+{
+    using variant_type = const mapbox::util::variant<int, double, std::string>;
+    variant_type var1(123);
+    variant_type var2(3.2);
+    variant_type var3("foo");
+    REQUIRE(var1.get<int>() == 123);
+    REQUIRE(var2.get<double>() == Approx(3.2));
+    REQUIRE(var3.get<std::string>() == "foo");
+
+    some_visitor visitor{1};
+
+    REQUIRE(mapbox::util::apply_visitor(visitor, var1) == 124);
+    REQUIRE(mapbox::util::apply_visitor(visitor, var2) == 4);
+    REQUIRE(mapbox::util::apply_visitor(visitor, var3) == 0);
+}
+
+TEST_CASE("const visitor works on const variants", "[visitor][unary visitor]")
+{
+    using variant_type = const mapbox::util::variant<int, double, std::string>;
+    variant_type var1(123);
+    variant_type var2(3.2);
+    variant_type var3("foo");
+    REQUIRE(var1.get<int>() == 123);
+    REQUIRE(var2.get<double>() == Approx(3.2));
+    REQUIRE(var3.get<std::string>() == "foo");
+
+    const some_visitor visitor{1};
+
+    REQUIRE(mapbox::util::apply_visitor(visitor, var1) == 124);
+    REQUIRE(mapbox::util::apply_visitor(visitor, var2) == 4);
+    REQUIRE(mapbox::util::apply_visitor(visitor, var3) == 0);
+}
+
+TEST_CASE("rvalue visitor works on const variants", "[visitor][unary visitor]")
+{
+    using variant_type = const mapbox::util::variant<int, double, std::string>;
+    variant_type var1(123);
+    variant_type var2(3.2);
+    variant_type var3("foo");
+    REQUIRE(var1.get<int>() == 123);
+    REQUIRE(var2.get<double>() == Approx(3.2));
+    REQUIRE(var3.get<std::string>() == "foo");
+
+    REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, var1) == 124);
+    REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, var2) == 4);
+    REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, var3) == 0);
+}
+
+TEST_CASE("visitor works on rvalue variants", "[visitor][unary visitor]")
+{
+    using variant_type = const mapbox::util::variant<int, double, std::string>;
+
+    REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, variant_type{123}) == 124);
+    REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, variant_type{3.2}) == 4);
+    REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, variant_type{"foo"}) == 0);
+}
+
+struct total_sizeof
+{
+    total_sizeof() : total_(0) {}
+
+    template <class Value>
+    int operator()(const Value&) const
+    {
+        total_ += int(sizeof(Value));
+        return total_;
+    }
+
+    int result() const
+    {
+        return total_;
+    }
+
+    mutable int total_;
+
+}; // total_sizeof
+
+TEST_CASE("changes in visitor should be visible", "[visitor][unary visitor]")
+{
+    using variant_type = mapbox::util::variant<int, std::string, double>;
+    variant_type v;
+    total_sizeof ts;
+    v = 5.9;
+    REQUIRE(mapbox::util::apply_visitor(ts, v) == sizeof(double));
+    REQUIRE(ts.result() == sizeof(double));
+}
+
+TEST_CASE("changes in const visitor (with mutable internals) should be visible", "[visitor][unary visitor]")
+{
+    using variant_type = const mapbox::util::variant<int, std::string, double>;
+    variant_type v{"foo"};
+    const total_sizeof ts;
+    REQUIRE(mapbox::util::apply_visitor(ts, v) == sizeof(std::string));
+    REQUIRE(ts.result() == sizeof(std::string));
+}
diff --git a/third_party/variant/test/t/variant.cpp b/third_party/variant/test/t/variant.cpp
new file mode 100644
index 0000000..36655a5
--- /dev/null
+++ b/third_party/variant/test/t/variant.cpp
@@ -0,0 +1,570 @@
+#include "catch.hpp"
+
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+#include <algorithm>
+#include <cstdint>
+#include <functional>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <ostream>
+#include <sstream>
+#include <string>
+
+// Hack to make nullptr work with Catch
+namespace std {
+
+template <class C, class T>
+std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& os, std::nullptr_t)
+{
+    return os << (void*)nullptr;
+}
+}
+
+TEST_CASE("variant can be moved into vector", "[variant]")
+{
+    using variant_type = mapbox::util::variant<bool, std::string>;
+    variant_type v(std::string("test"));
+    std::vector<variant_type> vec;
+    vec.emplace_back(std::move(v));
+    REQUIRE(v.get<std::string>() != std::string("test"));
+    REQUIRE(vec.at(0).get<std::string>() == std::string("test"));
+}
+
+TEST_CASE("variant should support built-in types", "[variant]")
+{
+    SECTION("bool")
+    {
+        mapbox::util::variant<bool> v(true);
+        REQUIRE(v.valid());
+        REQUIRE(v.is<bool>());
+        REQUIRE(v.which() == 0);
+        REQUIRE(v.get<bool>() == true);
+        v.set<bool>(false);
+        REQUIRE(v.get<bool>() == false);
+        v = true;
+        REQUIRE(v == mapbox::util::variant<bool>(true));
+    }
+    SECTION("nullptr")
+    {
+        using value_type = std::nullptr_t;
+        mapbox::util::variant<value_type> v(nullptr);
+        REQUIRE(v.valid());
+        REQUIRE(v.is<value_type>());
+        REQUIRE(v.which() == 0);
+        REQUIRE(v.get<value_type>() == nullptr);
+        REQUIRE(v == mapbox::util::variant<value_type>(nullptr));
+    }
+    SECTION("unique_ptr")
+    {
+        using value_type = std::unique_ptr<std::string>;
+        mapbox::util::variant<value_type> v(value_type(new std::string("hello")));
+        REQUIRE(v.valid());
+        REQUIRE(v.is<value_type>());
+        REQUIRE(v.which() == 0);
+        REQUIRE(*v.get<value_type>().get() == *value_type(new std::string("hello")).get());
+        REQUIRE(*v.get<value_type>() == "hello");
+    }
+    SECTION("string")
+    {
+        using value_type = std::string;
+        mapbox::util::variant<value_type> v(value_type("hello"));
+        REQUIRE(v.valid());
+        REQUIRE(v.is<value_type>());
+        REQUIRE(v.which() == 0);
+        REQUIRE(v.get<value_type>() == value_type("hello"));
+        v.set<value_type>(value_type("there"));
+        REQUIRE(v.get<value_type>() == value_type("there"));
+        v = value_type("variant");
+        REQUIRE(v == mapbox::util::variant<value_type>(value_type("variant")));
+    }
+    SECTION("size_t")
+    {
+        using value_type = std::size_t;
+        mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
+        REQUIRE(v.valid());
+        REQUIRE(v.is<value_type>());
+        REQUIRE(v.which() == 0);
+        REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
+        v.set<value_type>(value_type(0));
+        REQUIRE(v.get<value_type>() == value_type(0));
+        v = value_type(1);
+        REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
+    }
+    SECTION("int8_t")
+    {
+        using value_type = std::int8_t;
+        mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
+        REQUIRE(v.valid());
+        REQUIRE(v.is<value_type>());
+        REQUIRE(v.which() == 0);
+        REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
+        v.set<value_type>(0);
+        REQUIRE(v.get<value_type>() == value_type(0));
+        v = value_type(1);
+        REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
+    }
+    SECTION("int16_t")
+    {
+        using value_type = std::int16_t;
+        mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
+        REQUIRE(v.valid());
+        REQUIRE(v.is<value_type>());
+        REQUIRE(v.which() == 0);
+        REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
+        v.set<value_type>(0);
+        REQUIRE(v.get<value_type>() == value_type(0));
+        v = value_type(1);
+        REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
+    }
+    SECTION("int32_t")
+    {
+        using value_type = std::int32_t;
+        mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
+        REQUIRE(v.valid());
+        REQUIRE(v.is<value_type>());
+        REQUIRE(v.which() == 0);
+        REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
+        v.set<value_type>(0);
+        REQUIRE(v.get<value_type>() == value_type(0));
+        v = value_type(1);
+        REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
+    }
+    SECTION("int64_t")
+    {
+        using value_type = std::int64_t;
+        mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
+        REQUIRE(v.valid());
+        REQUIRE(v.is<value_type>());
+        REQUIRE(v.which() == 0);
+        REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
+        v.set<value_type>(0);
+        REQUIRE(v.get<value_type>() == value_type(0));
+        v = value_type(1);
+        REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
+    }
+}
+
+struct MissionInteger
+{
+    using value_type = uint64_t;
+    value_type val_;
+
+  public:
+    MissionInteger(uint64_t val) : val_(val) {}
+
+    bool operator==(MissionInteger const& rhs) const
+    {
+        return (val_ == rhs.get());
+    }
+
+    uint64_t get() const
+    {
+        return val_;
+    }
+};
+
+std::ostream& operator<<(std::ostream& os, MissionInteger const& rhs)
+{
+    os << rhs.get();
+    return os;
+}
+
+TEST_CASE("variant should support custom types", "[variant]")
+{
+    // http://www.missionintegers.com/integer/34838300
+    mapbox::util::variant<MissionInteger> v(MissionInteger(34838300));
+    REQUIRE(v.valid());
+    REQUIRE(v.is<MissionInteger>());
+    REQUIRE(v.which() == 0);
+    REQUIRE(v.get<MissionInteger>() == MissionInteger(34838300));
+    REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(34838300));
+    // TODO: should both of the set usages below compile?
+    v.set<MissionInteger>(MissionInteger::value_type(0));
+    v.set<MissionInteger>(MissionInteger(0));
+    REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(0));
+    v = MissionInteger(1);
+    REQUIRE(v == mapbox::util::variant<MissionInteger>(MissionInteger(1)));
+}
+
+TEST_CASE("variant::which() returns zero based index of stored type", "[variant]")
+{
+    using variant_type = mapbox::util::variant<bool, std::string, std::uint64_t, std::int64_t, double, float>;
+    // which() returns index in forward order
+    REQUIRE(0 == variant_type(true).which());
+    REQUIRE(1 == variant_type(std::string("test")).which());
+    REQUIRE(2 == variant_type(std::uint64_t(0)).which());
+    REQUIRE(3 == variant_type(std::int64_t(0)).which());
+    REQUIRE(4 == variant_type(double(0.0)).which());
+    REQUIRE(5 == variant_type(float(0.0)).which());
+}
+
+TEST_CASE("get with wrong type (here: double) should throw", "[variant]")
+{
+    using variant_type = mapbox::util::variant<int, double>;
+    variant_type var = 5;
+    REQUIRE(var.is<int>());
+    REQUIRE_FALSE(var.is<double>());
+    REQUIRE(var.get<int>() == 5);
+    REQUIRE_THROWS_AS({
+        var.get<double>();
+    },
+                      mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("get with wrong type (here: int) should throw", "[variant]")
+{
+    using variant_type = mapbox::util::variant<int, double>;
+    variant_type var = 5.0;
+    REQUIRE(var.is<double>());
+    REQUIRE_FALSE(var.is<int>());
+    REQUIRE(var.get<double>() == 5.0);
+    REQUIRE(mapbox::util::get<double>(var) == 5.0);
+    REQUIRE_THROWS_AS({
+        var.get<int>();
+    },
+                      mapbox::util::bad_variant_access&);
+    REQUIRE_THROWS_AS({
+        mapbox::util::get<int>(var);
+    },
+                      mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("get on const varint with wrong type (here: int) should throw", "[variant]")
+{
+    using variant_type = mapbox::util::variant<int, double>;
+    const variant_type var = 5.0;
+    REQUIRE(var.is<double>());
+    REQUIRE_FALSE(var.is<int>());
+    REQUIRE(var.get<double>() == 5.0);
+    REQUIRE(mapbox::util::get<double>(var) == 5.0);
+    REQUIRE_THROWS_AS({
+        var.get<int>();
+    },
+                      mapbox::util::bad_variant_access&);
+    REQUIRE_THROWS_AS({
+        mapbox::util::get<int>(var);
+    },
+                      mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("get with any type should throw if not initialized", "[variant]")
+{
+    mapbox::util::variant<int, double> var{mapbox::util::no_init()};
+    REQUIRE_THROWS_AS({
+        var.get<int>();
+    },
+                      mapbox::util::bad_variant_access&);
+    REQUIRE_THROWS_AS({
+        var.get<double>();
+    },
+                      mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("no_init variant can be copied and moved from", "[variant]")
+{
+    using variant_type = mapbox::util::variant<int, double>;
+
+    variant_type v1{mapbox::util::no_init()};
+    variant_type v2{42};
+    variant_type v3{23};
+
+    REQUIRE(v2.get<int>() == 42);
+    v2 = v1;
+    REQUIRE_THROWS_AS({
+        v2.get<int>();
+    },
+                      mapbox::util::bad_variant_access&);
+
+    REQUIRE(v3.get<int>() == 23);
+    v3 = std::move(v1);
+    REQUIRE_THROWS_AS({
+        v3.get<int>();
+    },
+                      mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("no_init variant can be copied and moved to", "[variant]")
+{
+    using variant_type = mapbox::util::variant<int, double>;
+
+    variant_type v1{42};
+    variant_type v2{mapbox::util::no_init()};
+    variant_type v3{mapbox::util::no_init()};
+
+    REQUIRE_THROWS_AS({
+        v2.get<int>();
+    },
+                      mapbox::util::bad_variant_access&);
+
+    REQUIRE(v1.get<int>() == 42);
+    v2 = v1;
+    REQUIRE(v2.get<int>() == 42);
+    REQUIRE(v1.get<int>() == 42);
+
+    REQUIRE_THROWS_AS({
+        v3.get<int>();
+    },
+                      mapbox::util::bad_variant_access&);
+
+    v3 = std::move(v1);
+    REQUIRE(v3.get<int>() == 42);
+}
+
+TEST_CASE("implicit conversion", "[variant][implicit conversion]")
+{
+    using variant_type = mapbox::util::variant<int>;
+    variant_type var(5.0); // converted to int
+    REQUIRE(var.get<int>() == 5);
+    var = 6.0; // works for operator=, too
+    REQUIRE(var.get<int>() == 6);
+}
+
+TEST_CASE("implicit conversion to first type in variant type list", "[variant][implicit conversion]")
+{
+    using variant_type = mapbox::util::variant<long, char>;
+    variant_type var = 5.0; // converted to long
+    REQUIRE(var.get<long>() == 5);
+    REQUIRE_THROWS_AS({
+        var.get<char>();
+    },
+                      mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("implicit conversion to unsigned char", "[variant][implicit conversion]")
+{
+    using variant_type = mapbox::util::variant<unsigned char>;
+    variant_type var = 100.0;
+    CHECK(var.get<unsigned char>() == static_cast<unsigned char>(100.0));
+    CHECK(var.get<unsigned char>() == static_cast<unsigned char>(static_cast<unsigned int>(100.0)));
+}
+
+struct dummy
+{
+};
+
+TEST_CASE("implicit conversion to a suitable type", "[variant][implicit conversion]")
+{
+    using mapbox::util::variant;
+    CHECK_NOTHROW((variant<dummy, float, std::string>(123)).get<float>());
+    CHECK_NOTHROW((variant<dummy, float, std::string>("foo")).get<std::string>());
+}
+
+TEST_CASE("value_traits for non-convertible type", "[variant::detail]")
+{
+    namespace detail = mapbox::util::detail;
+    using target_type = detail::value_traits<dummy, int>::target_type;
+    CHECK((std::is_same<target_type, void>::value) == true);
+}
+
+TEST_CASE("Type indexing should work with variants with duplicated types", "[variant::detail]")
+{
+    // Index is in reverse order
+    REQUIRE((mapbox::util::detail::value_traits<bool, bool, int, double, std::string>::index == 3));
+    REQUIRE((mapbox::util::detail::value_traits<bool, bool, int, double, int>::index == 3));
+    REQUIRE((mapbox::util::detail::value_traits<int, bool, int, double, std::string>::index == 2));
+    REQUIRE((mapbox::util::detail::value_traits<int, bool, int, double, int>::index == 2));
+    REQUIRE((mapbox::util::detail::value_traits<double, bool, int, double, std::string>::index == 1));
+    REQUIRE((mapbox::util::detail::value_traits<bool, bool, int, bool, std::string>::index == 3));
+    REQUIRE((mapbox::util::detail::value_traits<std::string, bool, int, double, std::string>::index == 0));
+    REQUIRE((mapbox::util::detail::value_traits<dummy, bool, int, double, std::string>::index == mapbox::util::detail::invalid_value));
+    REQUIRE((mapbox::util::detail::value_traits<std::vector<int>, bool, int, double, std::string>::index == mapbox::util::detail::invalid_value));
+}
+
+TEST_CASE("variant default constructor", "[variant][default constructor]")
+{
+    // By default variant is initialised with (default constructed) first type in template parameters pack
+    // As a result first type in Types... must be default constructable
+    // NOTE: index in reverse order -> index = N - 1
+    using variant_type = mapbox::util::variant<int, double, std::string>;
+    REQUIRE(variant_type{}.which() == 0);
+    REQUIRE(variant_type{}.valid());
+    REQUIRE_FALSE(variant_type{mapbox::util::no_init()}.valid());
+}
+
+TEST_CASE("variant printer", "[visitor][unary visitor][printer]")
+{
+    using variant_type = mapbox::util::variant<int, double, std::string>;
+    std::vector<variant_type> var = {2.1, 123, "foo", 456};
+    std::stringstream out;
+    std::copy(var.begin(), var.end(), std::ostream_iterator<variant_type>(out, ","));
+    out << var[2];
+    REQUIRE(out.str() == "2.1,123,foo,456,foo");
+}
+
+TEST_CASE("swapping variants should do the right thing", "[variant]")
+{
+    using variant_type = mapbox::util::variant<int, double, std::string>;
+    variant_type a = 7;
+    variant_type b = 3;
+    variant_type c = 3.141;
+    variant_type d = "foo";
+    variant_type e = "a long string that is longer than small string optimization";
+
+    using std::swap;
+    swap(a, b);
+    REQUIRE(a.get<int>() == 3);
+    REQUIRE(a.which() == 0);
+    REQUIRE(b.get<int>() == 7);
+    REQUIRE(b.which() == 0);
+
+    swap(b, c);
+    REQUIRE(b.get<double>() == Approx(3.141));
+    REQUIRE(b.which() == 1);
+    REQUIRE(c.get<int>() == 7);
+    REQUIRE(c.which() == 0);
+
+    swap(b, d);
+    REQUIRE(b.get<std::string>() == "foo");
+    REQUIRE(b.which() == 2);
+    REQUIRE(d.get<double>() == Approx(3.141));
+    REQUIRE(d.which() == 1);
+
+    swap(b, e);
+    REQUIRE(b.get<std::string>() == "a long string that is longer than small string optimization");
+    REQUIRE(b.which() == 2);
+    REQUIRE(e.get<std::string>() == "foo");
+    REQUIRE(e.which() == 2);
+}
+
+TEST_CASE("variant should work with equality operators")
+{
+    using variant_type = mapbox::util::variant<int, std::string>;
+
+    variant_type a{1};
+    variant_type b{1};
+    variant_type c{2};
+    variant_type s{"foo"};
+
+    REQUIRE(a == a);
+    REQUIRE(a == b);
+    REQUIRE_FALSE(a == c);
+    REQUIRE_FALSE(a == s);
+    REQUIRE_FALSE(c == s);
+
+    REQUIRE_FALSE(a != a);
+    REQUIRE_FALSE(a != b);
+    REQUIRE(a != c);
+    REQUIRE(a != s);
+    REQUIRE(c != s);
+}
+
+TEST_CASE("variant should work with comparison operators")
+{
+    using variant_type = mapbox::util::variant<int, std::string>;
+
+    variant_type a{1};
+    variant_type b{1};
+    variant_type c{2};
+    variant_type s{"foo"};
+    variant_type t{"bar"};
+
+    REQUIRE_FALSE(a < a);
+    REQUIRE_FALSE(a < b);
+    REQUIRE(a < c);
+    REQUIRE(a < s);
+    REQUIRE(c < s);
+    REQUIRE(t < s);
+
+    REQUIRE_FALSE(a > a);
+    REQUIRE_FALSE(a > b);
+    REQUIRE_FALSE(a > c);
+    REQUIRE_FALSE(a > s);
+    REQUIRE_FALSE(c > s);
+    REQUIRE_FALSE(t > s);
+
+    REQUIRE(a <= a);
+    REQUIRE(a <= b);
+    REQUIRE(a <= c);
+    REQUIRE(a <= s);
+    REQUIRE(c <= s);
+    REQUIRE(t <= s);
+
+    REQUIRE(a >= a);
+    REQUIRE(a >= b);
+    REQUIRE_FALSE(a >= c);
+    REQUIRE_FALSE(a >= s);
+    REQUIRE_FALSE(c >= s);
+    REQUIRE_FALSE(t >= s);
+}
+
+TEST_CASE("storing reference wrappers works")
+{
+    using variant_type = mapbox::util::variant<std::reference_wrapper<int>, std::reference_wrapper<double>>;
+
+    int a = 1;
+    variant_type v{std::ref(a)};
+    REQUIRE(v.get<int>() == 1);
+    REQUIRE(mapbox::util::get<int>(v) == 1);
+    REQUIRE_THROWS_AS({
+        v.get<double>();
+    },
+                      mapbox::util::bad_variant_access&);
+    REQUIRE_THROWS_AS({
+        mapbox::util::get<double>(v);
+    },
+                      mapbox::util::bad_variant_access&);
+    a = 2;
+    REQUIRE(v.get<int>() == 2);
+    v.get<int>() = 3;
+    REQUIRE(a == 3);
+
+    double b = 3.141;
+    v = std::ref(b);
+    REQUIRE(v.get<double>() == Approx(3.141));
+    REQUIRE(mapbox::util::get<double>(v) == Approx(3.141));
+    REQUIRE_THROWS_AS({
+        v.get<int>();
+    },
+                      mapbox::util::bad_variant_access&);
+    REQUIRE_THROWS_AS({
+        mapbox::util::get<int>(v);
+    },
+                      mapbox::util::bad_variant_access&);
+    b = 2.718;
+    REQUIRE(v.get<double>() == Approx(2.718));
+    a = 3;
+    REQUIRE(v.get<double>() == Approx(2.718));
+    v.get<double>() = 4.1;
+    REQUIRE(b == Approx(4.1));
+
+    REQUIRE_THROWS_AS({
+        v.get<int>() = 4;
+    },
+                      mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("storing reference wrappers to consts works")
+{
+    using variant_type = mapbox::util::variant<std::reference_wrapper<int const>, std::reference_wrapper<double const>>;
+
+    int a = 1;
+    variant_type v{std::cref(a)};
+    REQUIRE(v.get<int const>() == 1);
+    REQUIRE(v.get<int>() == 1); // this works (see #82)
+    REQUIRE(mapbox::util::get<int const>(v) == 1);
+    //    REQUIRE(mapbox::util::get<int>(v) == 1); // this doesn't work (see #82)
+    REQUIRE_THROWS_AS({
+        v.get<double const>();
+    },
+                      mapbox::util::bad_variant_access&);
+    REQUIRE_THROWS_AS({
+        mapbox::util::get<double const>(v);
+    },
+                      mapbox::util::bad_variant_access&);
+
+    double b = 3.141;
+    v = std::cref(b);
+    REQUIRE(v.get<double const>() == Approx(3.141));
+    REQUIRE(mapbox::util::get<double const>(v) == Approx(3.141));
+    REQUIRE_THROWS_AS({
+        v.get<int const>();
+    },
+                      mapbox::util::bad_variant_access&);
+    REQUIRE_THROWS_AS({
+        mapbox::util::get<int const>(v);
+    },
+                      mapbox::util::bad_variant_access&);
+}
diff --git a/third_party/variant/test/unique_ptr_test.cpp b/third_party/variant/test/unique_ptr_test.cpp
index 2a51efe..6578991 100644
--- a/third_party/variant/test/unique_ptr_test.cpp
+++ b/third_party/variant/test/unique_ptr_test.cpp
@@ -1,12 +1,13 @@
+
+#include <cstdlib>
 #include <iostream>
-#include <vector>
-#include <thread>
+#include <memory>
 #include <string>
-#include <sstream>
+#include <typeinfo>
 #include <utility>
-#include <type_traits>
-#include <boost/variant.hpp>
+
 #include <boost/timer/timer.hpp>
+
 #include "variant.hpp"
 
 using namespace mapbox;
@@ -15,46 +16,48 @@ namespace test {
 
 struct add;
 struct sub;
-template <typename OpTag> struct binary_op;
 
-typedef util::variant<int ,
+template <typename OpTag>
+struct binary_op;
+
+typedef util::variant<int,
                       std::unique_ptr<binary_op<add>>,
-                      std::unique_ptr<binary_op<sub>>
-                      > expression;
+                      std::unique_ptr<binary_op<sub>>>
+    expression;
 
 template <typename Op>
 struct binary_op
 {
-    expression left;  // variant instantiated here...
+    expression left; // variant instantiated here...
     expression right;
 
-    binary_op(expression && lhs, expression && rhs)
-        : left(std::move(lhs)), right(std::move(rhs)) {}
+    binary_op(expression&& lhs, expression&& rhs)
+        : left(std::move(lhs)), right(std::move(rhs))
+    {
+    }
 };
 
-struct print : util::static_visitor<void>
+struct print
 {
     template <typename T>
-    void operator() (T const& val) const
+    void operator()(T const& val) const
     {
         std::cerr << val << ":" << typeid(T).name() << std::endl;
     }
 };
 
-
-struct test : util::static_visitor<std::string>
+struct test
 {
     template <typename T>
-    std::string operator() (T const& obj) const
+    std::string operator()(T const& obj) const
     {
         return std::string("TYPE_ID=") + typeid(obj).name();
     }
 };
 
-struct calculator : public util::static_visitor<int>
+struct calculator
 {
-public:
-
+  public:
     int operator()(int value) const
     {
         return value;
@@ -62,21 +65,18 @@ public:
 
     int operator()(std::unique_ptr<binary_op<add>> const& binary) const
     {
-        return util::apply_visitor(calculator(), binary->left)
-            + util::apply_visitor(calculator(), binary->right);
+        return util::apply_visitor(calculator(), binary->left) + util::apply_visitor(calculator(), binary->right);
     }
 
     int operator()(std::unique_ptr<binary_op<sub>> const& binary) const
     {
-        return util::apply_visitor(calculator(), binary->left)
-            - util::apply_visitor(calculator(), binary->right);
+        return util::apply_visitor(calculator(), binary->left) - util::apply_visitor(calculator(), binary->right);
     }
 };
 
-struct to_string : public util::static_visitor<std::string>
+struct to_string
 {
-public:
-
+  public:
     std::string operator()(int value) const
     {
         return std::to_string(value);
@@ -84,21 +84,18 @@ public:
 
     std::string operator()(std::unique_ptr<binary_op<add>> const& binary) const
     {
-        return util::apply_visitor(to_string(), binary->left) + std::string("+")
-            + util::apply_visitor(to_string(), binary->right);
+        return util::apply_visitor(to_string(), binary->left) + std::string("+") + util::apply_visitor(to_string(), binary->right);
     }
 
     std::string operator()(std::unique_ptr<binary_op<sub>> const& binary) const
     {
-        return util::apply_visitor(to_string(), binary->left) + std::string("-")
-            + util::apply_visitor(to_string(), binary->right);
+        return util::apply_visitor(to_string(), binary->left) + std::string("-") + util::apply_visitor(to_string(), binary->right);
     }
-
 };
 
 } // namespace test
 
-int main (int argc, char** argv)
+int main(int argc, char** argv)
 {
     if (argc != 2)
     {
@@ -110,17 +107,18 @@ int main (int argc, char** argv)
 
     test::expression sum(std::unique_ptr<test::binary_op<test::add>>(new test::binary_op<test::add>(2, 3)));
     test::expression result(std::unique_ptr<test::binary_op<test::sub>>(new test::binary_op<test::sub>(std::move(sum), 4)));
+
     std::cerr << "TYPE OF RESULT-> " << util::apply_visitor(test::test(), result) << std::endl;
 
+    int total = 0;
     {
         boost::timer::auto_cpu_timer t;
-        int total = 0;
         for (std::size_t i = 0; i < NUM_ITER; ++i)
         {
             total += util::apply_visitor(test::calculator(), result);
         }
-        std::cerr << "total=" << total << std::endl;
     }
+    std::cerr << "total=" << total << std::endl;
 
     std::cerr << util::apply_visitor(test::to_string(), result) << "=" << util::apply_visitor(test::calculator(), result) << std::endl;
 
diff --git a/third_party/variant/test/unit.cpp b/third_party/variant/test/unit.cpp
index 9b874c7..0c7c351 100644
--- a/third_party/variant/test/unit.cpp
+++ b/third_party/variant/test/unit.cpp
@@ -1,314 +1,2 @@
-#define CATCH_CONFIG_RUNNER
+#define CATCH_CONFIG_MAIN
 #include "catch.hpp"
-
-#include "variant.hpp"
-#include "variant_io.hpp"
-#include <algorithm>
-#include <cstdint>
-#include <iterator>
-#include <limits>
-#include <memory>
-#include <ostream>
-#include <sstream>
-#include <string>
-
-using namespace mapbox;
-
-template <typename T>
-struct mutating_visitor
-{
-    mutating_visitor(T & val)
-        : val_(val) {}
-
-    void operator() (T & val) const
-    {
-        val = val_;
-    }
-
-    template <typename T1>
-    void operator() (T1& ) const {} // no-op
-
-    T & val_;
-};
-
-
-
-TEST_CASE( "variant version", "[variant]" ) {
-    unsigned int version = VARIANT_VERSION;
-    REQUIRE(version == 100);
-    #if VARIANT_VERSION == 100
-        REQUIRE(true);
-    #else
-        REQUIRE(false);
-    #endif
-}
-
-TEST_CASE( "variant can be moved into vector", "[variant]" ) {
-    typedef util::variant<bool,std::string> variant_type;
-    variant_type v(std::string("test"));
-    std::vector<variant_type> vec;
-    vec.emplace_back(std::move(v));
-    REQUIRE(v.get<std::string>() != std::string("test"));
-    REQUIRE(vec.at(0).get<std::string>() == std::string("test"));
-}
-
-TEST_CASE( "variant should support built-in types", "[variant]" ) {
-    SECTION( "bool" ) {
-        util::variant<bool> v(true);
-        REQUIRE(v.valid());
-        REQUIRE(v.is<bool>());
-        REQUIRE(v.get_type_index() == 0);
-        REQUIRE(v.get<bool>() == true);
-        v.set<bool>(false);
-        REQUIRE(v.get<bool>() == false);
-        v = true;
-        REQUIRE(v == util::variant<bool>(true));
-    }
-    SECTION( "nullptr" ) {
-        typedef std::nullptr_t value_type;
-        util::variant<value_type> v(nullptr);
-        REQUIRE(v.valid());
-        REQUIRE(v.is<value_type>());
-        REQUIRE(v.get_type_index() == 0);
-        // TODO: commented since it breaks on windows: 'operator << is ambiguous'
-        //REQUIRE(v.get<value_type>() == nullptr);
-        // FIXME: does not compile: ./variant.hpp:340:14: error: use of overloaded operator '<<' is ambiguous (with operand types 'std::__1::basic_ostream<char>' and 'const nullptr_t')
-        // https://github.com/mapbox/variant/issues/14
-        //REQUIRE(v == util::variant<value_type>(nullptr));
-    }
-    SECTION( "unique_ptr" ) {
-        typedef std::unique_ptr<std::string> value_type;
-        util::variant<value_type> v(value_type(new std::string("hello")));
-        REQUIRE(v.valid());
-        REQUIRE(v.is<value_type>());
-        REQUIRE(v.get_type_index() == 0);
-        REQUIRE(*v.get<value_type>().get() == *value_type(new std::string("hello")).get());
-    }
-    SECTION( "string" ) {
-        typedef std::string value_type;
-        util::variant<value_type> v(value_type("hello"));
-        REQUIRE(v.valid());
-        REQUIRE(v.is<value_type>());
-        REQUIRE(v.get_type_index() == 0);
-        REQUIRE(v.get<value_type>() == value_type("hello"));
-        v.set<value_type>(value_type("there"));
-        REQUIRE(v.get<value_type>() == value_type("there"));
-        v = value_type("variant");
-        REQUIRE(v == util::variant<value_type>(value_type("variant")));
-    }
-    SECTION( "size_t" ) {
-        typedef std::size_t value_type;
-        util::variant<value_type> v(std::numeric_limits<value_type>::max());
-        REQUIRE(v.valid());
-        REQUIRE(v.is<value_type>());
-        REQUIRE(v.get_type_index() == 0);
-        REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
-        v.set<value_type>(value_type(0));
-        REQUIRE(v.get<value_type>() == value_type(0));
-        v = value_type(1);
-        REQUIRE(v == util::variant<value_type>(value_type(1)));
-    }
-    SECTION( "int8_t" ) {
-        typedef std::int8_t value_type;
-        util::variant<value_type> v(std::numeric_limits<value_type>::max());
-        REQUIRE(v.valid());
-        REQUIRE(v.is<value_type>());
-        REQUIRE(v.get_type_index() == 0);
-        REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
-        v.set<value_type>(0);
-        REQUIRE(v.get<value_type>() == value_type(0));
-        v = value_type(1);
-        REQUIRE(v == util::variant<value_type>(value_type(1)));
-    }
-    SECTION( "int16_t" ) {
-        typedef std::int16_t value_type;
-        util::variant<value_type> v(std::numeric_limits<value_type>::max());
-        REQUIRE(v.valid());
-        REQUIRE(v.is<value_type>());
-        REQUIRE(v.get_type_index() == 0);
-        REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
-        v.set<value_type>(0);
-        REQUIRE(v.get<value_type>() == value_type(0));
-        v = value_type(1);
-        REQUIRE(v == util::variant<value_type>(value_type(1)));
-    }
-    SECTION( "int32_t" ) {
-        typedef std::int32_t value_type;
-        util::variant<value_type> v(std::numeric_limits<value_type>::max());
-        REQUIRE(v.valid());
-        REQUIRE(v.is<value_type>());
-        REQUIRE(v.get_type_index() == 0);
-        REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
-        v.set<value_type>(0);
-        REQUIRE(v.get<value_type>() == value_type(0));
-        v = value_type(1);
-        REQUIRE(v == util::variant<value_type>(value_type(1)));
-    }
-    SECTION( "int64_t" ) {
-        typedef std::int64_t value_type;
-        util::variant<value_type> v(std::numeric_limits<value_type>::max());
-        REQUIRE(v.valid());
-        REQUIRE(v.is<value_type>());
-        REQUIRE(v.get_type_index() == 0);
-        REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
-        v.set<value_type>(0);
-        REQUIRE(v.get<value_type>() == value_type(0));
-        v = value_type(1);
-        REQUIRE(v == util::variant<value_type>(value_type(1)));
-    }
-}
-
-struct MissionInteger
-{
-    typedef uint64_t value_type;
-    value_type val_;
-    public:
-      MissionInteger(uint64_t val) :
-       val_(val) {}
-
-    bool operator==(MissionInteger const& rhs) const
-    {
-        return (val_ == rhs.get());
-    }
-
-    uint64_t get() const
-    {
-        return val_;
-    }
-};
-
-// TODO - remove after https://github.com/mapbox/variant/issues/14
-std::ostream& operator<<(std::ostream& os, MissionInteger const& rhs)
-{
-    os << rhs.get();
-    return os;
-}
-
-TEST_CASE( "variant should support custom types", "[variant]" ) {
-    // http://www.missionintegers.com/integer/34838300
-    util::variant<MissionInteger> v(MissionInteger(34838300));
-    REQUIRE(v.valid());
-    REQUIRE(v.is<MissionInteger>());
-    REQUIRE(v.get_type_index() == 0);
-    REQUIRE(v.get<MissionInteger>() == MissionInteger(34838300));
-    REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(34838300));
-    // TODO: should both of the set usages below compile?
-    v.set<MissionInteger>(MissionInteger::value_type(0));
-    v.set<MissionInteger>(MissionInteger(0));
-    REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(0));
-    v = MissionInteger(1);
-    REQUIRE(v == util::variant<MissionInteger>(MissionInteger(1)));
-}
-
-// Test internal api
-TEST_CASE( "variant should correctly index types", "[variant]" ) {
-    typedef util::variant<bool,std::string,std::uint64_t,std::int64_t,double,float> variant_type;
-    // Index is in reverse order
-    REQUIRE(variant_type(true).get_type_index() == 5);
-    REQUIRE(variant_type(std::string("test")).get_type_index() == 4);
-    REQUIRE(variant_type(std::uint64_t(0)).get_type_index() == 3);
-    REQUIRE(variant_type(std::int64_t(0)).get_type_index() == 2);
-    REQUIRE(variant_type(double(0.0)).get_type_index() == 1);
-    REQUIRE(variant_type(float(0.0)).get_type_index() == 0);
-}
-
-// Test internal api
-TEST_CASE( "variant::which() returns zero based index of stored type", "[variant]" ) {
-    typedef util::variant<bool,std::string,std::uint64_t,std::int64_t,double,float> variant_type;
-    // Index is in reverse order
-    REQUIRE(variant_type(true).which() == 0);
-    REQUIRE(variant_type(std::string("test")).which() == 1);
-    REQUIRE(variant_type(std::uint64_t(0)).which() == 2);
-    REQUIRE(variant_type(std::int64_t(0)).which() == 3);
-    REQUIRE(variant_type(double(0.0)).which() == 4);
-    REQUIRE(variant_type(float(0.0)).which() == 5);
-}
-
-TEST_CASE( "get with type not in variant type list should throw", "[variant]" ) {
-    typedef util::variant<int> variant_type;
-    variant_type var = 5;
-    REQUIRE(var.get<int>() == 5);
-}
-
-TEST_CASE( "get with wrong type (here: double) should throw", "[variant]" ) {
-    typedef util::variant<int, double> variant_type;
-    variant_type var = 5;
-    REQUIRE(var.get<int>() == 5);
-    REQUIRE_THROWS(var.get<double>());
-}
-
-TEST_CASE( "get with wrong type (here: int) should throw", "[variant]" ) {
-    typedef util::variant<int, double> variant_type;
-    variant_type var = 5.0;
-    REQUIRE(var.get<double>() == 5.0);
-    REQUIRE_THROWS(var.get<int>());
-}
-
-TEST_CASE( "implicit conversion", "[variant][implicit conversion]" ) {
-    typedef util::variant<int> variant_type;
-    variant_type var(5.0); // converted to int
-    REQUIRE(var.get<int>() == 5);
-    var = 6.0; // works for operator=, too
-    REQUIRE(var.get<int>() == 6);
-}
-
-TEST_CASE( "implicit conversion to first type in variant type list", "[variant][implicit conversion]" ) {
-    typedef util::variant<long, char> variant_type;
-    variant_type var = 5.0; // converted to long
-    REQUIRE(var.get<long>() == 5);
-    REQUIRE_THROWS(var.get<char>());
-}
-
-TEST_CASE( "implicit conversion to unsigned char", "[variant][implicit conversion]" ) {
-    typedef util::variant<unsigned char> variant_type;
-    variant_type var = 100.0;
-    CHECK(var.get<unsigned char>() == static_cast<unsigned char>(100.0));
-    CHECK(var.get<unsigned char>() == static_cast<unsigned char>(static_cast<unsigned int>(100.0)));
-}
-
-struct dummy {};
-
-TEST_CASE( "variant value traits", "[variant::detail]" ) {
-    // Users should not create variants with duplicated types
-    // however our type indexing should still work
-    // Index is in reverse order
-    REQUIRE((util::detail::value_traits<bool, bool, int, double, std::string>::index == 3));
-    REQUIRE((util::detail::value_traits<int, bool, int, double, std::string>::index == 2));
-    REQUIRE((util::detail::value_traits<double, bool, int, double, std::string>::index == 1));
-    REQUIRE((util::detail::value_traits<std::string, bool, int, double, std::string>::index == 0));
-    REQUIRE((util::detail::value_traits<dummy, bool, int, double, std::string>::index == util::detail::invalid_value));
-    REQUIRE((util::detail::value_traits<std::vector<int>, bool, int, double, std::string>::index == util::detail::invalid_value));
-}
-
-TEST_CASE( "variant default constructor", "[variant][default constructor]" ) {
-    // By default variant is initialised with (default constructed) first type in template parameters pack
-    // As a result first type in Types... must be default constructable
-    // NOTE: index in reverse order -> index = N - 1
-    REQUIRE((util::variant<int, double, std::string>().get_type_index() == 2));
-    REQUIRE((util::variant<int, double, std::string>(util::no_init()).get_type_index() == util::detail::invalid_value));
-}
-
-TEST_CASE( "variant visitation", "[visitor][unary visitor]" ) {
-    util::variant<int, double, std::string> var(123);
-    REQUIRE(var.get<int>() == 123);
-    int val = 456;
-    mutating_visitor<int> visitor(val);
-    util::apply_visitor(visitor, var);
-    REQUIRE(var.get<int>() == 456);
-}
-
-TEST_CASE( "variant printer", "[visitor][unary visitor][printer]" ) {
-    typedef util::variant<int, double, std::string> variant_type;
-    std::vector<variant_type> var = {2.1, 123, "foo", 456};
-    std::stringstream out;
-    std::copy(var.begin(), var.end(), std::ostream_iterator<variant_type>(out, ","));
-    out << var[2];
-    REQUIRE(out.str() == "2.1,123,foo,456,foo");
-}
-
-int main (int argc, char* const argv[])
-{
-    int result = Catch::Session().run(argc, argv);
-    if (!result) printf("\x1b[1;32m ✓ \x1b[0m\n");
-    return result;
-}
diff --git a/third_party/variant/test/variant_hello_world.cpp b/third_party/variant/test/variant_hello_world.cpp
deleted file mode 100644
index b445fdb..0000000
--- a/third_party/variant/test/variant_hello_world.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#include "variant.hpp"
-#include <cstdint>
-#include <stdexcept>
-
-using namespace mapbox;
-
-struct check : util::static_visitor<>
-{
-    template <typename T>
-    void operator() (T const& val) const
-    {
-        if (val != 0) throw std::runtime_error("invalid");
-    }
-};
-
-
-int main() {
-    typedef util::variant<bool, int, double> variant_type;
-    variant_type v(0);
-    util::apply_visitor(check(), v);
-    return 0;
-}
diff --git a/third_party/variant/variant.gyp b/third_party/variant/variant.gyp
index 712cafe..b1f3801 100644
--- a/third_party/variant/variant.gyp
+++ b/third_party/variant/variant.gyp
@@ -7,15 +7,29 @@
       "target_name": "tests",
       "type": "executable",
       "sources": [
-        "test/unit.cpp"
+        "test/unit.cpp",
+        "test/t/binary_visitor_1.cpp",
+        "test/t/binary_visitor_2.cpp",
+        "test/t/binary_visitor_3.cpp",
+        "test/t/binary_visitor_4.cpp",
+        "test/t/binary_visitor_5.cpp",
+        "test/t/binary_visitor_6.cpp",
+        "test/t/issue21.cpp",
+        "test/t/mutating_visitor.cpp",
+        "test/t/optional.cpp",
+        "test/t/recursive_wrapper.cpp",
+        "test/t/sizeof.cpp",
+        "test/t/unary_visitor.cpp",
+        "test/t/variant.cpp"
       ],
       "xcode_settings": {
         "SDKROOT": "macosx",
         "SUPPORTED_PLATFORMS":["macosx"]
       },
       "include_dirs": [
-          "./"
+          "./",
+          "test/include"
       ]
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/third_party/variant/variant.hpp b/third_party/variant/variant.hpp
index 90aacae..db5d3c8 100644
--- a/third_party/variant/variant.hpp
+++ b/third_party/variant/variant.hpp
@@ -1,19 +1,35 @@
 #ifndef MAPBOX_UTIL_VARIANT_HPP
 #define MAPBOX_UTIL_VARIANT_HPP
 
-#include <utility>
-#include <typeinfo>
-#include <type_traits>
+#include <cassert>
+#include <cstddef>   // size_t
+#include <new>       // operator new
 #include <stdexcept> // runtime_error
-#include <new> // operator new
-#include <cstddef> // size_t
-#include <iosfwd>
 #include <string>
+#include <tuple>
+#include <type_traits>
+#include <typeinfo>
+#include <utility>
 
 #include "recursive_wrapper.hpp"
 
+// clang-format off
+// [[deprecated]] is only available in C++14, use this for the time being
+#if __cplusplus <= 201103L
+# ifdef __GNUC__
+#  define MAPBOX_VARIANT_DEPRECATED __attribute__((deprecated))
+# elif defined(_MSC_VER)
+#  define MAPBOX_VARIANT_DEPRECATED __declspec(deprecated)
+# else
+#  define MAPBOX_VARIANT_DEPRECATED
+# endif
+#else
+#  define MAPBOX_VARIANT_DEPRECATED [[deprecated]]
+#endif
+
+
 #ifdef _MSC_VER
- // http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx
+ // https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx
  #ifdef NDEBUG
   #define VARIANT_INLINE __forceinline
  #else
@@ -26,22 +42,37 @@
   #define VARIANT_INLINE __attribute__((noinline))
  #endif
 #endif
+// clang-format on
 
-#define VARIANT_MAJOR_VERSION 0
+#define VARIANT_MAJOR_VERSION 1
 #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)
+#define VARIANT_VERSION (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + (VARIANT_PATCH_VERSION)
+
+namespace mapbox {
+namespace util {
+
+// XXX This should derive from std::logic_error instead of std::runtime_error.
+//     See https://github.com/mapbox/variant/issues/48 for details.
+class bad_variant_access : public std::runtime_error
+{
+
+  public:
+    explicit bad_variant_access(const std::string& what_arg)
+        : runtime_error(what_arg) {}
 
-namespace mapbox { namespace util {
+    explicit bad_variant_access(const char* what_arg)
+        : runtime_error(what_arg) {}
+
+}; // class bad_variant_access
 
-// static visitor
 template <typename R = void>
-struct static_visitor
+struct MAPBOX_VARIANT_DEPRECATED static_visitor
 {
     using result_type = R;
-protected:
+
+  protected:
     static_visitor() {}
     ~static_visitor() {}
 };
@@ -50,14 +81,15 @@ namespace detail {
 
 static constexpr std::size_t invalid_value = std::size_t(-1);
 
-template <typename T, typename...Types>
+template <typename T, typename... Types>
 struct direct_type;
 
-template <typename T, typename First, typename...Types>
+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;
+                                             ? sizeof...(Types)
+                                             : direct_type<T, Types...>::index;
 };
 
 template <typename T>
@@ -66,14 +98,15 @@ struct direct_type<T>
     static constexpr std::size_t index = invalid_value;
 };
 
-template <typename T, typename...Types>
+template <typename T, typename... Types>
 struct convertible_type;
 
-template <typename T, typename First, typename...Types>
+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;
+                                             ? sizeof...(Types)
+                                             : convertible_type<T, Types...>::index;
 };
 
 template <typename T>
@@ -82,64 +115,53 @@ struct convertible_type<T>
     static constexpr std::size_t index = invalid_value;
 };
 
-template <typename T, typename...Types>
+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;
+    using value_type = typename std::remove_reference<T>::type;
+    static constexpr std::size_t direct_index = direct_type<value_type, Types...>::index;
+    static constexpr bool is_direct = direct_index != invalid_value;
+    static constexpr std::size_t index = is_direct ? direct_index : convertible_type<value_type, Types...>::index;
+    static constexpr bool is_valid = index != invalid_value;
+    static constexpr std::size_t tindex = is_valid ? sizeof...(Types)-index : 0;
+    using target_type = typename std::tuple_element<tindex, std::tuple<void, Types...>>::type;
 };
 
 // check if T is in Types...
-template <typename T, typename...Types>
+template <typename T, typename... Types>
 struct has_type;
 
 template <typename T, typename First, typename... Types>
 struct has_type<T, First, Types...>
 {
-    static constexpr bool value = std::is_same<T, First>::value
-        || has_type<T, Types...>::value;
+    static constexpr bool value = std::is_same<T, First>::value || has_type<T, Types...>::value;
 };
 
 template <typename T>
-struct has_type<T> : std::false_type {};
-//
+struct has_type<T> : std::false_type
+{
+};
 
-template <typename T, typename...Types>
+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;
+    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
+struct is_valid_type<T> : std::false_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...>
+template <typename T, typename R = void>
+struct enable_if_type
 {
-    using type = T;
+    using type = R;
 };
 
-
-template <typename T, typename R = void>
-struct enable_if_type { using type = R; };
-
 template <typename F, typename V, typename Enable = void>
 struct result_of_unary_visit
 {
@@ -147,29 +169,24 @@ struct result_of_unary_visit
 };
 
 template <typename F, typename V>
-struct result_of_unary_visit<F, V, typename enable_if_type<typename F::result_type>::type >
+struct result_of_unary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
 {
     using type = typename F::result_type;
 };
 
-template <typename F, typename V, class Enable = void>
+template <typename F, typename V, typename Enable = void>
 struct result_of_binary_visit
 {
-    using type = typename std::result_of<F(V&,V&)>::type;
+    using type = typename std::result_of<F(V&, V&)>::type;
 };
 
-
 template <typename F, typename V>
-struct result_of_binary_visit<F, V, typename enable_if_type<typename F::result_type>::type >
+struct result_of_binary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
 {
     using type = typename F::result_type;
 };
 
-
-} // namespace detail
-
-
-template <std::size_t arg1, std::size_t ... others>
+template <std::size_t arg1, std::size_t... others>
 struct static_max;
 
 template <std::size_t arg>
@@ -178,326 +195,305 @@ struct static_max<arg>
     static const std::size_t value = arg;
 };
 
-template <std::size_t arg1, std::size_t arg2, std::size_t ... others>
+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;
+    static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value : static_max<arg2, others...>::value;
 };
 
-template<typename... Types>
+template <typename... Types>
 struct variant_helper;
 
-template<typename T, typename... Types>
+template <typename T, typename... Types>
 struct variant_helper<T, Types...>
 {
-    VARIANT_INLINE static void destroy(const std::size_t id, void * data)
+    VARIANT_INLINE static void destroy(const std::size_t type_index, void* data)
     {
-        if (id == sizeof...(Types))
+        if (type_index == sizeof...(Types))
         {
             reinterpret_cast<T*>(data)->~T();
         }
         else
         {
-            variant_helper<Types...>::destroy(id, data);
+            variant_helper<Types...>::destroy(type_index, data);
         }
     }
 
-    VARIANT_INLINE static void move(const std::size_t old_id, void * old_value, void * new_value)
+    VARIANT_INLINE static void move(const std::size_t old_type_index, void* old_value, void* new_value)
     {
-        if (old_id == sizeof...(Types))
+        if (old_type_index == 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_helper<Types...>::move(old_type_index, old_value, new_value);
         }
     }
 
-    VARIANT_INLINE static void copy(const std::size_t old_id, const void * old_value, void * new_value)
+    VARIANT_INLINE static void copy(const std::size_t old_type_index, const void* old_value, void* new_value)
     {
-        if (old_id == sizeof...(Types))
+        if (old_type_index == sizeof...(Types))
         {
             new (new_value) T(*reinterpret_cast<const T*>(old_value));
         }
         else
         {
-            variant_helper<Types...>::copy(old_id, old_value, new_value);
-        }
-    }
-
-    VARIANT_INLINE static void direct_swap(const std::size_t id, void * lhs, void * rhs)
-    {
-        using std::swap; //enable ADL
-        if (id == sizeof...(Types))
-        {
-            // both lhs and rhs hold T
-            swap(*reinterpret_cast<T*>(lhs), *reinterpret_cast<T*>(rhs));
-        }
-        else
-        {
-            variant_helper<Types...>::direct_swap(id, lhs, rhs);
+            variant_helper<Types...>::copy(old_type_index, old_value, new_value);
         }
     }
 };
 
-template<> struct variant_helper<>
+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 *) {}
-    VARIANT_INLINE static void direct_swap(const std::size_t, void *, void *) {}
+    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;
-    }
+    static T const& apply_const(T const& obj) { return obj; }
+    static T& apply(T& obj) { return obj; }
 };
 
-
 template <typename T>
 struct unwrapper<recursive_wrapper<T>>
 {
-    auto operator() (recursive_wrapper<T> const& obj) const
+    static auto apply_const(recursive_wrapper<T> const& obj)
         -> typename recursive_wrapper<T>::type const&
     {
         return obj.get();
     }
+    static auto apply(recursive_wrapper<T>& obj)
+        -> typename recursive_wrapper<T>::type&
+    {
+        return obj.get();
+    }
 };
 
 template <typename T>
 struct unwrapper<std::reference_wrapper<T>>
 {
-    auto operator() (std::reference_wrapper<T> const& obj) const
+    static auto apply_const(std::reference_wrapper<T> const& obj)
         -> typename std::reference_wrapper<T>::type const&
     {
         return obj.get();
     }
-
+    static auto apply(std::reference_wrapper<T>& obj)
+        -> typename std::reference_wrapper<T>::type&
+    {
+        return obj.get();
+    }
 };
 
-
-template <typename F, typename V, typename R, typename...Types>
+template <typename F, typename V, typename R, typename... Types>
 struct dispatcher;
 
-template <typename F, typename V, typename R, typename T, typename...Types>
+template <typename F, typename V, typename R, typename T, typename... Types>
 struct dispatcher<F, V, R, T, Types...>
 {
-    using result_type = R;
-    VARIANT_INLINE static result_type apply_const(V const& v, F f)
+    VARIANT_INLINE static R apply_const(V const& v, F&& f)
     {
-        if (v.get_type_index() == sizeof...(Types))
+        if (v.template is<T>())
         {
-            return f(unwrapper<T>()(v. template get<T>()));
+            return f(unwrapper<T>::apply_const(v.template get<T>()));
         }
         else
         {
-            return dispatcher<F, V, R, Types...>::apply_const(v, f);
+            return dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
         }
     }
 
-    VARIANT_INLINE static result_type apply(V & v, F f)
+    VARIANT_INLINE static R apply(V& v, F&& f)
     {
-        if (v.get_type_index() == sizeof...(Types))
+        if (v.template is<T>())
         {
-            return f(unwrapper<T>()(v. template get<T>()));
+            return f(unwrapper<T>::apply(v.template get<T>()));
         }
         else
         {
-            return dispatcher<F, V, R, Types...>::apply(v, f);
+            return dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
         }
     }
 };
 
-template<typename F, typename V, typename R>
-struct dispatcher<F, V, R>
+template <typename F, typename V, typename R, typename T>
+struct dispatcher<F, V, R, T>
 {
-    using result_type = R;
-    VARIANT_INLINE static result_type apply_const(V const&, F)
+    VARIANT_INLINE static R apply_const(V const& v, F&& f)
     {
-        throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
+        return f(unwrapper<T>::apply_const(v.template get<T>()));
     }
 
-    VARIANT_INLINE static result_type apply(V &, F)
+    VARIANT_INLINE static R apply(V& v, F&& f)
     {
-        throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
+        return f(unwrapper<T>::apply(v.template get<T>()));
     }
 };
 
-
-template <typename F, typename V, typename R, typename T, typename...Types>
+template <typename F, typename V, typename R, typename T, typename... Types>
 struct binary_dispatcher_rhs;
 
-template <typename F, typename V, typename R, typename T0, typename T1, typename...Types>
+template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
 struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
 {
-    using result_type = R;
-    VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
+    VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
     {
-        if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
+        if (rhs.template is<T1>()) // call binary functor
         {
-            return f(unwrapper<T0>()(lhs. template get<T0>()),
-                     unwrapper<T1>()(rhs. template get<T1>()));
+            return f(unwrapper<T0>::apply_const(lhs.template get<T0>()),
+                     unwrapper<T1>::apply_const(rhs.template get<T1>()));
         }
         else
         {
-            return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, f);
+            return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
         }
     }
 
-    VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f)
+    VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
     {
-        if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
+        if (rhs.template is<T1>()) // call binary functor
         {
-            return f(unwrapper<T0>()(lhs. template get<T0>()),
-                     unwrapper<T1>()(rhs. template get<T1>()));
+            return f(unwrapper<T0>::apply(lhs.template get<T0>()),
+                     unwrapper<T1>::apply(rhs.template get<T1>()));
         }
         else
         {
-            return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, f);
+            return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
         }
     }
-
 };
 
-template<typename F, typename V, typename R, typename T>
-struct binary_dispatcher_rhs<F, V, R, T>
+template <typename F, typename V, typename R, typename T0, typename T1>
+struct binary_dispatcher_rhs<F, V, R, T0, T1>
 {
-    using result_type = R;
-    VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
+    VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
     {
-        throw std::runtime_error("binary dispatch: FAIL");
+        return f(unwrapper<T0>::apply_const(lhs.template get<T0>()),
+                 unwrapper<T1>::apply_const(rhs.template get<T1>()));
     }
-    VARIANT_INLINE static result_type apply(V &, V &, F)
+
+    VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
     {
-        throw std::runtime_error("binary dispatch: FAIL");
+        return f(unwrapper<T0>::apply(lhs.template get<T0>()),
+                 unwrapper<T1>::apply(rhs.template get<T1>()));
     }
 };
 
-
-template <typename F, typename V, typename R,  typename T, typename...Types>
+template <typename F, typename V, typename R, typename T, typename... Types>
 struct binary_dispatcher_lhs;
 
-template <typename F, typename V, typename R, typename T0, typename T1, typename...Types>
+template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
 struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
 {
-    using result_type = R;
-    VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
+    VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
     {
-        if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
+        if (lhs.template is<T1>()) // call binary functor
         {
-            return f(lhs. template get<T1>(), rhs. template get<T0>());
+            return f(unwrapper<T1>::apply_const(lhs.template get<T1>()),
+                     unwrapper<T0>::apply_const(rhs.template get<T0>()));
         }
         else
         {
-            return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, f);
+            return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
         }
     }
 
-    VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f)
+    VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
     {
-        if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
+        if (lhs.template is<T1>()) // call binary functor
         {
-            return f(lhs. template get<T1>(), rhs. template get<T0>());
+            return f(unwrapper<T1>::apply(lhs.template get<T1>()),
+                     unwrapper<T0>::apply(rhs.template get<T0>()));
         }
         else
         {
-            return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, f);
+            return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
         }
     }
-
 };
 
-template<typename F, typename V, typename R, typename T>
-struct binary_dispatcher_lhs<F, V, R, T>
+template <typename F, typename V, typename R, typename T0, typename T1>
+struct binary_dispatcher_lhs<F, V, R, T0, T1>
 {
-    using result_type = R;
-    VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
+    VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
     {
-        throw std::runtime_error("binary dispatch: FAIL");
+        return f(unwrapper<T1>::apply_const(lhs.template get<T1>()),
+                 unwrapper<T0>::apply_const(rhs.template get<T0>()));
     }
 
-    VARIANT_INLINE static result_type apply(V &, V &, F)
+    VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
     {
-        throw std::runtime_error("binary dispatch: FAIL");
+        return f(unwrapper<T1>::apply(lhs.template get<T1>()),
+                 unwrapper<T0>::apply(rhs.template get<T0>()));
     }
 };
 
-template <typename F, typename V, typename R, typename...Types>
+template <typename F, typename V, typename R, typename... Types>
 struct binary_dispatcher;
 
-template <typename F, typename V, typename R, typename T, typename...Types>
+template <typename F, typename V, typename R, typename T, typename... Types>
 struct binary_dispatcher<F, V, R, T, Types...>
 {
-    using result_type = R;
-    VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f)
+    VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
     {
-        if (v0.get_type_index() == sizeof...(Types))
+        if (v0.template is<T>())
         {
-            if (v0.get_type_index() == v1.get_type_index())
+            if (v1.template is<T>())
             {
-                return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
+                return f(unwrapper<T>::apply_const(v0.template get<T>()),
+                         unwrapper<T>::apply_const(v1.template get<T>())); // call binary functor
             }
             else
             {
-                return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, f);
+                return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
             }
         }
-        else if (v1.get_type_index() == sizeof...(Types))
+        else if (v1.template is<T>())
         {
-            return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, f);
+            return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
         }
-        return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, f);
+        return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
     }
 
-    VARIANT_INLINE static result_type apply(V & v0, V & v1, F f)
+    VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
     {
-        if (v0.get_type_index() == sizeof...(Types))
+        if (v0.template is<T>())
         {
-            if (v0.get_type_index() == v1.get_type_index())
+            if (v1.template is<T>())
             {
-                return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
+                return f(unwrapper<T>::apply(v0.template get<T>()),
+                         unwrapper<T>::apply(v1.template get<T>())); // call binary functor
             }
             else
             {
-                return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, f);
+                return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
             }
         }
-        else if (v1.get_type_index() == sizeof...(Types))
+        else if (v1.template is<T>())
         {
-            return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, f);
+            return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
         }
-        return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, f);
+        return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
     }
 };
 
-template<typename F, typename V, typename R>
-struct binary_dispatcher<F, V, R>
+template <typename F, typename V, typename R, typename T>
+struct binary_dispatcher<F, V, R, T>
 {
-    using result_type = R;
-    VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
+    VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
     {
-        throw std::runtime_error("binary dispatch: FAIL");
+        return f(unwrapper<T>::apply_const(v0.template get<T>()),
+                 unwrapper<T>::apply_const(v1.template get<T>())); // call binary functor
     }
 
-    VARIANT_INLINE static result_type apply(V &, V &, F)
+    VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
     {
-        throw std::runtime_error("binary dispatch: FAIL");
+        return f(unwrapper<T>::apply(v0.template get<T>()),
+                 unwrapper<T>::apply(v1.template get<T>())); // call binary functor
     }
 };
 
@@ -523,60 +519,77 @@ struct less_comp
 template <typename Variant, typename Comp>
 class comparer
 {
-public:
+  public:
     explicit comparer(Variant const& lhs) noexcept
         : lhs_(lhs) {}
     comparer& operator=(comparer const&) = delete;
     // visitor
-    template<typename T>
+    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:
+
+  private:
     Variant const& lhs_;
 };
 
+// True if Predicate matches for all of the types Ts
+template <template <typename> class Predicate, typename... Ts>
+struct static_all_of : std::is_same<std::tuple<std::true_type, typename Predicate<Ts>::type...>,
+                                    std::tuple<typename Predicate<Ts>::type..., std::true_type>>
+{
+};
+
+// True if Predicate matches for none of the types Ts
+template <template <typename> class Predicate, typename... Ts>
+struct static_none_of : std::is_same<std::tuple<std::false_type, typename Predicate<Ts>::type...>,
+                                     std::tuple<typename Predicate<Ts>::type..., std::false_type>>
+{
+};
 
 } // namespace detail
 
-struct no_init {};
+struct no_init
+{
+};
 
-template<typename... Types>
+template <typename... Types>
 class variant
 {
-private:
+    static_assert(sizeof...(Types) > 0, "Template parameter type list of variant can not be empty");
+    static_assert(detail::static_none_of<std::is_reference, Types...>::value, "Variant can not hold reference types. Maybe use std::reference?");
 
-    static const std::size_t data_size = static_max<sizeof(Types)...>::value;
-    static const std::size_t data_align = static_max<alignof(Types)...>::value;
+  private:
+    static const std::size_t data_size = detail::static_max<sizeof(Types)...>::value;
+    static const std::size_t data_align = detail::static_max<alignof(Types)...>::value;
 
+    using first_type = typename std::tuple_element<0, std::tuple<Types...>>::type;
     using data_type = typename std::aligned_storage<data_size, data_align>::type;
-    using helper_type = variant_helper<Types...>;
+    using helper_type = detail::variant_helper<Types...>;
 
     std::size_t type_index;
     data_type data;
 
-public:
-
-    VARIANT_INLINE variant()
-        : type_index(sizeof...(Types) - 1)
+  public:
+    VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible<first_type>::value)
+        : type_index(sizeof...(Types)-1)
     {
-        new (&data) typename detail::select_type<0, Types...>::type();
+        static_assert(std::is_default_constructible<first_type>::value, "First type in variant must be default constructible to allow default construction of variant");
+        new (&data) first_type();
     }
 
-    VARIANT_INLINE variant(no_init)
+    VARIANT_INLINE variant(no_init) noexcept
         : 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)
+    template <typename T, typename Traits = detail::value_traits<T, Types...>,
+              typename Enable = typename std::enable_if<Traits::is_valid>::type>
+    VARIANT_INLINE variant(T&& val) noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value)
+        : type_index(Traits::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
+        new (&data) typename Traits::target_type(std::forward<T>(val));
     }
 
     VARIANT_INLINE variant(variant<Types...> const& old)
@@ -585,13 +598,13 @@ public:
         helper_type::copy(old.type_index, &old.data, &data);
     }
 
-    VARIANT_INLINE variant(variant<Types...>&& old) noexcept
+    VARIANT_INLINE variant(variant<Types...>&& old) noexcept(std::is_nothrow_move_constructible<std::tuple<Types...>>::value)
         : type_index(old.type_index)
     {
         helper_type::move(old.type_index, &old.data, &data);
     }
 
-private:
+  private:
     VARIANT_INLINE void copy_assign(variant<Types...> const& rhs)
     {
         helper_type::destroy(type_index, &data);
@@ -600,7 +613,7 @@ private:
         type_index = rhs.type_index;
     }
 
-    VARIANT_INLINE void move_assign(variant<Types...> && rhs)
+    VARIANT_INLINE void move_assign(variant<Types...>&& rhs)
     {
         helper_type::destroy(type_index, &data);
         type_index = detail::invalid_value;
@@ -608,8 +621,8 @@ private:
         type_index = rhs.type_index;
     }
 
-public:
-    VARIANT_INLINE variant<Types...>& operator=(variant<Types...> &&  other)
+  public:
+    VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other)
     {
         move_assign(std::move(other));
         return *this;
@@ -624,7 +637,7 @@ public:
     // conversions
     // move-assign
     template <typename T>
-    VARIANT_INLINE variant<Types...>& operator=(T && rhs) noexcept
+    VARIANT_INLINE variant<Types...>& operator=(T&& rhs) noexcept
     {
         variant<Types...> temp(std::forward<T>(rhs));
         move_assign(std::move(temp));
@@ -640,30 +653,30 @@ public:
         return *this;
     }
 
-    template<typename T>
+    template <typename T>
     VARIANT_INLINE bool is() const
     {
         static_assert(detail::has_type<T, Types...>::value, "invalid type in T in `is<T>()` for this variant");
-        return (type_index == detail::direct_type<T, Types...>::index);
+        return type_index == detail::direct_type<T, Types...>::index;
     }
 
     VARIANT_INLINE bool valid() const
     {
-        return (type_index != detail::invalid_value);
+        return type_index != detail::invalid_value;
     }
 
-    template<typename T, typename... Args>
+    template <typename T, typename... Args>
     VARIANT_INLINE void set(Args&&... args)
     {
         helper_type::destroy(type_index, &data);
+        type_index = detail::invalid_value;
         new (&data) T(std::forward<Args>(args)...);
         type_index = detail::direct_type<T, Types...>::index;
     }
 
     // get<T>()
-    template<typename T, typename std::enable_if<
-                         (detail::direct_type<T, Types...>::index != detail::invalid_value)
-                         >::type* = nullptr>
+    template <typename T, typename std::enable_if<
+                              (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
     VARIANT_INLINE T& get()
     {
         if (type_index == detail::direct_type<T, Types...>::index)
@@ -672,13 +685,12 @@ public:
         }
         else
         {
-            throw std::runtime_error("in get<T>()");
+            throw bad_variant_access("in get<T>()");
         }
     }
 
     template <typename T, typename std::enable_if<
-                          (detail::direct_type<T, Types...>::index != detail::invalid_value)
-                          >::type* = nullptr>
+                              (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
     VARIANT_INLINE T const& get() const
     {
         if (type_index == detail::direct_type<T, Types...>::index)
@@ -687,14 +699,13 @@ public:
         }
         else
         {
-            throw std::runtime_error("in get<T>()");
+            throw bad_variant_access("in get<T>()");
         }
     }
 
     // get<T>() - T stored as recursive_wrapper<T>
     template <typename T, typename std::enable_if<
-                          (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)
-                          >::type* = nullptr>
+                              (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
     VARIANT_INLINE T& get()
     {
         if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
@@ -703,13 +714,12 @@ public:
         }
         else
         {
-            throw std::runtime_error("in get<T>()");
+            throw bad_variant_access("in get<T>()");
         }
     }
 
-    template <typename T,typename std::enable_if<
-                         (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)
-                         >::type* = nullptr>
+    template <typename T, typename std::enable_if<
+                              (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
     VARIANT_INLINE T const& get() const
     {
         if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
@@ -718,14 +728,13 @@ public:
         }
         else
         {
-            throw std::runtime_error("in get<T>()");
+            throw bad_variant_access("in get<T>()");
         }
     }
 
     // get<T>() - T stored as std::reference_wrapper<T>
     template <typename T, typename std::enable_if<
-                          (detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)
-                          >::type* = nullptr>
+                              (detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
     VARIANT_INLINE T& get()
     {
         if (type_index == detail::direct_type<std::reference_wrapper<T>, Types...>::index)
@@ -734,13 +743,12 @@ public:
         }
         else
         {
-            throw std::runtime_error("in get<T>()");
+            throw bad_variant_access("in get<T>()");
         }
     }
 
-    template <typename T,typename std::enable_if<
-                         (detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)
-                         >::type* = nullptr>
+    template <typename T, typename std::enable_if<
+                              (detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
     VARIANT_INLINE T const& get() const
     {
         if (type_index == detail::direct_type<std::reference_wrapper<T const>, Types...>::index)
@@ -749,69 +757,55 @@ public:
         }
         else
         {
-            throw std::runtime_error("in get<T>()");
+            throw bad_variant_access("in get<T>()");
         }
     }
 
-    VARIANT_INLINE std::size_t get_type_index() const
+    // This function is deprecated because it returns an internal index field.
+    // Use which() instead.
+    MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE std::size_t get_type_index() const
     {
         return type_index;
     }
 
     VARIANT_INLINE int which() const noexcept
     {
-        return static_cast<int>(sizeof...(Types) - type_index - 1);
+        return static_cast<int>(sizeof...(Types)-type_index - 1);
     }
 
     // visitor
     // unary
-    template <typename F, typename V>
-    auto VARIANT_INLINE
-    static visit(V const& v, F f)
-        -> decltype(detail::dispatcher<F, V,
-                    typename detail::result_of_unary_visit<F,
-                    typename detail::select_type<0, Types...>::type>::type, Types...>::apply_const(v, f))
+    template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
+    auto VARIANT_INLINE static visit(V const& v, F&& f)
+        -> decltype(detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f)))
     {
-        using R = typename detail::result_of_unary_visit<F, typename detail::select_type<0, Types...>::type>::type;
-        return detail::dispatcher<F, V, R, Types...>::apply_const(v, f);
+        return detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
     }
     // non-const
-    template <typename F, typename V>
-    auto VARIANT_INLINE
-    static visit(V & v, F f)
-        -> decltype(detail::dispatcher<F, V,
-                    typename detail::result_of_unary_visit<F,
-                    typename detail::select_type<0, Types...>::type>::type, Types...>::apply(v, f))
+    template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
+    auto VARIANT_INLINE static visit(V& v, F&& f)
+        -> decltype(detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)))
     {
-        using R = typename detail::result_of_unary_visit<F, typename detail::select_type<0, Types...>::type>::type;
-        return detail::dispatcher<F, V, R, Types...>::apply(v, f);
+        return detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(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,
-                    typename detail::result_of_binary_visit<F,
-                    typename detail::select_type<0, Types...>::type>::type, Types...>::apply_const(v0, v1, f))
+    template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
+    auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f)
+        -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f)))
     {
-        using R = typename detail::result_of_binary_visit<F,typename detail::select_type<0, Types...>::type>::type;
-        return detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, f);
+        return detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(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,
-                    typename detail::result_of_binary_visit<F,
-                    typename detail::select_type<0, Types...>::type>::type, Types...>::apply(v0, v1, f))
+    template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
+    auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f)
+        -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f)))
     {
-        using R = typename detail::result_of_binary_visit<F,typename detail::select_type<0, Types...>::type>::type;
-        return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, f);
+        return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
     }
 
-    ~variant() noexcept
+    ~variant() noexcept // no-throw destructor
     {
         helper_type::destroy(type_index, &data);
     }
@@ -820,67 +814,88 @@ public:
     // equality
     VARIANT_INLINE bool operator==(variant const& rhs) const
     {
-        if (this->get_type_index() != rhs.get_type_index())
+        assert(valid() && rhs.valid());
+        if (this->which() != rhs.which())
+        {
             return false;
+        }
         detail::comparer<variant, detail::equal_comp> visitor(*this);
         return visit(rhs, visitor);
     }
+
+    VARIANT_INLINE bool operator!=(variant const& rhs) const
+    {
+        return !(*this == rhs);
+    }
+
     // less than
     VARIANT_INLINE bool operator<(variant const& rhs) const
     {
-        if (this->get_type_index() != rhs.get_type_index())
+        assert(valid() && rhs.valid());
+        if (this->which() != rhs.which())
         {
-            return this->get_type_index() < rhs.get_type_index();
-            // ^^ borrowed from boost::variant
+            return this->which() < rhs.which();
         }
         detail::comparer<variant, detail::less_comp> visitor(*this);
         return visit(rhs, visitor);
     }
+    VARIANT_INLINE bool operator>(variant const& rhs) const
+    {
+        return rhs < *this;
+    }
+    VARIANT_INLINE bool operator<=(variant const& rhs) const
+    {
+        return !(*this > rhs);
+    }
+    VARIANT_INLINE bool operator>=(variant const& rhs) const
+    {
+        return !(*this < rhs);
+    }
 };
 
 // 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))
+template <typename F, typename V>
+auto VARIANT_INLINE apply_visitor(F&& f, V const& v) -> decltype(V::visit(v, std::forward<F>(f)))
 {
-    return V::visit(v, f);
+    return V::visit(v, std::forward<F>(f));
 }
+
 // non-const
-template <typename V, typename F>
-auto VARIANT_INLINE static apply_visitor(F f, V & v) -> decltype(V::visit(v, f))
+template <typename F, typename V>
+auto VARIANT_INLINE apply_visitor(F&& f, V& v) -> decltype(V::visit(v, std::forward<F>(f)))
 {
-    return V::visit(v, f);
+    return V::visit(v, std::forward<F>(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))
+template <typename F, typename V>
+auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
 {
-    return V::binary_visit(v0, v1, f);
+    return V::binary_visit(v0, v1, std::forward<F>(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))
+template <typename F, typename V>
+auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
 {
-    return V::binary_visit(v0, v1, f);
+    return V::binary_visit(v0, v1, std::forward<F>(f));
 }
 
 // getter interface
-template<typename ResultType, typename T>
-ResultType & get(T & var)
+template <typename ResultType, typename T>
+ResultType& get(T& var)
 {
     return var.template get<ResultType>();
 }
 
-template<typename ResultType, typename T>
+template <typename ResultType, typename T>
 ResultType const& get(T const& var)
 {
     return var.template get<ResultType>();
 }
+} // namespace util
+} // namespace mapbox
 
-
-}}
-
-#endif  // MAPBOX_UTIL_VARIANT_HPP
+#endif // MAPBOX_UTIL_VARIANT_HPP
diff --git a/third_party/variant/variant_io.hpp b/third_party/variant/variant_io.hpp
index 8b0c137..e64cbad 100644
--- a/third_party/variant/variant_io.hpp
+++ b/third_party/variant/variant_io.hpp
@@ -1,39 +1,45 @@
 #ifndef MAPBOX_UTIL_VARIANT_IO_HPP
 #define MAPBOX_UTIL_VARIANT_IO_HPP
 
-namespace mapbox { namespace util {
+#include <iosfwd>
+
+#include "variant.hpp"
+
+namespace mapbox {
+namespace util {
 
 namespace detail {
 // operator<< helper
 template <typename Out>
 class printer
 {
-public:
-    explicit printer(Out & out)
+  public:
+    explicit printer(Out& out)
         : out_(out) {}
     printer& operator=(printer const&) = delete;
 
-// visitor
+    // visitor
     template <typename T>
     void operator()(T const& operand) const
     {
         out_ << operand;
     }
-private:
-    Out & out_;
+
+  private:
+    Out& out_;
 };
 }
 
 // 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)
+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);
+    detail::printer<std::basic_ostream<CharT, Traits>> visitor(out);
     apply_visitor(visitor, rhs);
     return out;
 }
+} // namespace util
+} // namespace mapbox
 
-}}
-
-#endif //MAPBOX_UTIL_VARIANT_IO_HPP
+#endif // MAPBOX_UTIL_VARIANT_IO_HPP
diff --git a/third_party/variant/vcbuild.bat b/third_party/variant/vcbuild.bat
deleted file mode 100644
index 21489a1..0000000
--- a/third_party/variant/vcbuild.bat
+++ /dev/null
@@ -1,8 +0,0 @@
-SET configuration=Debug
-IF NOT EXIST deps\gyp\ git clone --depth 1 https://chromium.googlesource.com/external/gyp.git deps/gyp
-IF EXIST %configuration% rd /s /q %configuration%
-del variant.sln
-del tests.vcxproj
-C:\Python27\python.exe deps/gyp/gyp_main.py variant.gyp --depth=. -f msvs -G msvs_version=2013
-msbuild variant.sln /nologo /p:Configuration=%configuration%;Platform=Win32
-.\"%configuration%"\tests.exe
\ No newline at end of file
diff --git a/tools/check-hsgr.cpp b/tools/check-hsgr.cpp
deleted file mode 100644
index 2418a47..0000000
--- a/tools/check-hsgr.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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
deleted file mode 100644
index db0e526..0000000
--- a/tools/components.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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/tarjan_scc.hpp"
-#include "../algorithms/coordinate_calculation.hpp"
-#include "../data_structures/dynamic_graph.hpp"
-#include "../data_structures/static_graph.hpp"
-#include "../util/fingerprint.hpp"
-#include "../util/graph_loader.hpp"
-#include "../util/make_unique.hpp"
-#include "../util/osrm_exception.hpp"
-#include "../util/simple_logger.hpp"
-
-#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.hpp>
-
-#include <fstream>
-#include <memory>
-#include <string>
-#include <vector>
-
-namespace
-{
-
-struct TarjanEdgeData
-{
-    TarjanEdgeData() : distance(INVALID_EDGE_WEIGHT), name_id(INVALID_NAMEID) {}
-    TarjanEdgeData(unsigned distance, unsigned name_id) : distance(distance), name_id(name_id) {}
-    unsigned distance;
-    unsigned name_id;
-};
-
-using TarjanGraph = StaticGraph<TarjanEdgeData>;
-using TarjanEdge = TarjanGraph::InputEdge;
-
-void DeleteFileIfExists(const std::string &file_name)
-{
-    if (boost::filesystem::exists(file_name))
-    {
-        boost::filesystem::remove(file_name);
-    }
-}
-}
-
-std::size_t LoadGraph(const char *path,
-                      std::vector<QueryNode> &coordinate_list,
-                      std::vector<TarjanEdge> &graph_edge_list)
-{
-    std::ifstream input_stream(path, std::ifstream::in | std::ifstream::binary);
-    if (!input_stream.is_open())
-    {
-        throw osrm::exception("Cannot open osrm file");
-    }
-
-    // load graph data
-    std::vector<NodeBasedEdge> edge_list;
-    std::vector<NodeID> traffic_light_node_list;
-    std::vector<NodeID> barrier_node_list;
-
-    auto number_of_nodes = loadNodesFromFile(input_stream, barrier_node_list,
-                                             traffic_light_node_list, coordinate_list);
-
-    loadEdgesFromFile(input_stream, edge_list);
-
-    traffic_light_node_list.clear();
-    traffic_light_node_list.shrink_to_fit();
-
-    // Building an node-based graph
-    for (const auto &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)(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)(input_edge.weight, 1), input_edge.name_id);
-        }
-    }
-
-    return number_of_nodes;
-}
-
-int main(int argc, char *argv[])
-{
-    std::vector<QueryNode> coordinate_list;
-
-    LogPolicy::GetInstance().Unmute();
-    try
-    {
-        // enable logging
-        if (argc < 2)
-        {
-            SimpleLogger().Write(logWARNING) << "usage:\n" << argv[0] << " <osrm>";
-            return -1;
-        }
-
-        std::vector<TarjanEdge> graph_edge_list;
-        auto number_of_nodes = LoadGraph(argv[1], coordinate_list, graph_edge_list);
-
-        tbb::parallel_sort(graph_edge_list.begin(), graph_edge_list.end());
-        const auto graph = std::make_shared<TarjanGraph>(number_of_nodes, graph_edge_list);
-        graph_edge_list.clear();
-        graph_edge_list.shrink_to_fit();
-
-        SimpleLogger().Write() << "Starting SCC graph traversal";
-
-        auto tarjan = osrm::make_unique<TarjanSCC<TarjanGraph>>(graph);
-        tarjan->run();
-        SimpleLogger().Write() << "identified: " << tarjan->get_number_of_components()
-                               << " many components";
-        SimpleLogger().Write() << "identified " << tarjan->get_size_one_count() << " size 1 SCCs";
-
-        // output
-        TIMER_START(SCC_RUN_SETUP);
-
-        // remove files from previous run if exist
-        DeleteFileIfExists("component.dbf");
-        DeleteFileIfExists("component.shx");
-        DeleteFileIfExists("component.shp");
-
-        Percent percentage(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_length = 0;
-        percentage.reinit(graph->GetNumberOfNodes());
-        TIMER_START(SCC_OUTPUT);
-        for (const NodeID source : osrm::irange(0u, graph->GetNumberOfNodes()))
-        {
-            percentage.printIncrement();
-            for (const auto current_edge : graph->GetAdjacentEdgeRange(source))
-            {
-                const TarjanGraph::NodeIterator target = graph->GetTarget(current_edge);
-
-                if (source < target || SPECIAL_EDGEID == graph->FindEdge(target, source))
-                {
-                    total_network_length +=
-                        100 * coordinate_calculation::great_circle_distance(
-                                  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(tarjan->get_component_id(source)),
-                                 tarjan->get_component_size(tarjan->get_component_id(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: "
-                               << static_cast<uint64_t>(total_network_length / 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
deleted file mode 100644
index 41e41b2..0000000
--- a/tools/io-benchmark.cpp
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "util/version.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 <fcntl.h>
-#ifdef __linux__
-#include <malloc.h>
-#endif
-
-#include <algorithm>
-#include <chrono>
-#include <iomanip>
-#include <numeric>
-#include <random>
-#include <vector>
-
-const unsigned number_of_elements = 268435456;
-
-struct Statistics
-{
-    double min, max, med, mean, dev;
-};
-
-void RunStatistics(std::vector<double> &timings_vector, Statistics &stats)
-{
-    std::sort(timings_vector.begin(), timings_vector.end());
-    stats.min = timings_vector.front();
-    stats.max = timings_vector.back();
-    stats.med = timings_vector[timings_vector.size() / 2];
-    double primary_sum = std::accumulate(timings_vector.begin(), timings_vector.end(), 0.0);
-    stats.mean = primary_sum / timings_vector.size();
-
-    double primary_sq_sum = std::inner_product(timings_vector.begin(), timings_vector.end(),
-                                               timings_vector.begin(), 0.0);
-    stats.dev = std::sqrt(primary_sq_sum / timings_vector.size() - (stats.mean * stats.mean));
-}
-
-int main(int argc, char *argv[])
-{
-
-#ifdef __FreeBSD__
-    SimpleLogger().Write() << "Not supported on FreeBSD";
-    return 0;
-#endif
-#ifdef _WIN32
-    SimpleLogger().Write() << "Not supported on Windows";
-    return 0;
-#else
-
-    LogPolicy::GetInstance().Unmute();
-    boost::filesystem::path test_path;
-    try
-    {
-        SimpleLogger().Write() << "starting up engines, " << OSRM_VERSION;
-
-        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();
-
-        // create files for testing
-        if (2 == argc)
-        {
-            // create file to test
-            if (boost::filesystem::exists(test_path))
-            {
-                throw osrm::exception("Data file already exists");
-            }
-
-            int *random_array = new int[number_of_elements];
-            std::generate(random_array, random_array + number_of_elements, std::rand);
-#ifdef __APPLE__
-            FILE *fd = fopen(test_path.string().c_str(), "w");
-            fcntl(fileno(fd), F_NOCACHE, 1);
-            fcntl(fileno(fd), F_RDAHEAD, 0);
-            TIMER_START(write_1gb);
-            write(fileno(fd), (char *)random_array, number_of_elements * sizeof(unsigned));
-            TIMER_STOP(write_1gb);
-            fclose(fd);
-#endif
-#ifdef __linux__
-            int file_desc =
-                open(test_path.string().c_str(), O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, S_IRWXU);
-            if (-1 == file_desc)
-            {
-                throw osrm::exception("Could not open random data file");
-            }
-            TIMER_START(write_1gb);
-            int ret = write(file_desc, random_array, number_of_elements * sizeof(unsigned));
-            if (0 > ret)
-            {
-                throw osrm::exception("could not write random data file");
-            }
-            TIMER_STOP(write_1gb);
-            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";
-
-            SimpleLogger().Write(logDEBUG)
-                << "finished creation of random data. Flush disk cache now!";
-        }
-        else
-        {
-            // Run Non-Cached I/O benchmarks
-            if (!boost::filesystem::exists(test_path))
-            {
-                throw osrm::exception("data file does not exist");
-            }
-
-            // volatiles do not get optimized
-            Statistics stats;
-
-#ifdef __APPLE__
-            volatile unsigned single_block[1024];
-            char *raw_array = new char[number_of_elements * sizeof(unsigned)];
-            FILE *fd = fopen(test_path.string().c_str(), "r");
-            fcntl(fileno(fd), F_NOCACHE, 1);
-            fcntl(fileno(fd), F_RDAHEAD, 0);
-#endif
-#ifdef __linux__
-            char *single_block = (char *)memalign(512, 1024 * sizeof(unsigned));
-
-            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;
-            }
-            char *raw_array = (char *)memalign(512, number_of_elements * sizeof(unsigned));
-#endif
-            TIMER_START(read_1gb);
-#ifdef __APPLE__
-            read(fileno(fd), raw_array, number_of_elements * sizeof(unsigned));
-            close(fileno(fd));
-            fd = fopen(test_path.string().c_str(), "r");
-#endif
-#ifdef __linux__
-            int ret = read(file_desc, raw_array, number_of_elements * sizeof(unsigned));
-            SimpleLogger().Write(logDEBUG) << "read " << ret
-                                           << " bytes, error: " << strerror(errno);
-            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() << "raw read performance: " << std::setprecision(5) << std::fixed
-                                   << 1024 * 1024 / TIMER_SEC(read_1gb) << "MB/sec";
-
-            std::vector<double> timing_results_raw_random;
-            SimpleLogger().Write(logDEBUG) << "running 1000 random I/Os of 4KB";
-
-#ifdef __APPLE__
-            fseek(fd, 0, SEEK_SET);
-#endif
-#ifdef __linux__
-            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 = uniform_dist(e1);
-                off_t current_offset = block_to_read * 4096;
-                TIMER_START(random_access);
-#ifdef __APPLE__
-                int ret1 = fseek(fd, current_offset, SEEK_SET);
-                int ret2 = read(fileno(fd), (char *)&single_block[0], 4096);
-#endif
-
-#ifdef __FreeBSD__
-                int ret1 = 0;
-                int ret2 = 0;
-#endif
-
-#ifdef __linux__
-                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)
-                {
-                    SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
-                    SimpleLogger().Write(logWARNING) << "seek error " << strerror(errno);
-                    throw osrm::exception("seek error");
-                }
-                if (-1 == ret2)
-                {
-                    SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
-                    SimpleLogger().Write(logWARNING) << "read error " << strerror(errno);
-                    throw osrm::exception("read error");
-                }
-                timing_results_raw_random.push_back(TIMER_SEC(random_access));
-            }
-
-            // Do statistics
-            SimpleLogger().Write(logDEBUG) << "running raw random I/O statistics";
-            std::ofstream random_csv("random.csv", std::ios::trunc);
-            for (unsigned i = 0; i < timing_results_raw_random.size(); ++i)
-            {
-                random_csv << i << ", " << timing_results_raw_random[i] << std::endl;
-            }
-            random_csv.close();
-            RunStatistics(timing_results_raw_random, stats);
-
-            SimpleLogger().Write() << "raw random I/O: " << std::setprecision(5) << std::fixed
-                                   << "min: " << stats.min << "ms, "
-                                   << "mean: " << stats.mean << "ms, "
-                                   << "med: " << stats.med << "ms, "
-                                   << "max: " << stats.max << "ms, "
-                                   << "dev: " << stats.dev << "ms";
-
-            std::vector<double> timing_results_raw_seq;
-#ifdef __APPLE__
-            fseek(fd, 0, SEEK_SET);
-#endif
-#ifdef __linux__
-            lseek(file_desc, 0, SEEK_SET);
-#endif
-
-            // read every 100th block
-            for (unsigned i = 0; i < 1000; ++i)
-            {
-                off_t current_offset = i * 4096;
-                TIMER_START(read_every_100);
-#ifdef __APPLE__
-                int ret1 = fseek(fd, current_offset, SEEK_SET);
-                int ret2 = read(fileno(fd), (char *)&single_block, 4096);
-#endif
-
-#ifdef __FreeBSD__
-                int ret1 = 0;
-                int ret2 = 0;
-#endif
-
-#ifdef __linux__
-                int ret1 = lseek(file_desc, current_offset, SEEK_SET);
-
-                int ret2 = read(file_desc, (char *)single_block, 4096);
-#endif
-                TIMER_STOP(read_every_100);
-                if (((off_t)-1) == ret1)
-                {
-                    SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
-                    SimpleLogger().Write(logWARNING) << "seek error " << strerror(errno);
-                    throw osrm::exception("seek error");
-                }
-                if (-1 == ret2)
-                {
-                    SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
-                    SimpleLogger().Write(logWARNING) << "read error " << strerror(errno);
-                    throw osrm::exception("read error");
-                }
-                timing_results_raw_seq.push_back(TIMER_SEC(read_every_100));
-            }
-#ifdef __APPLE__
-            fclose(fd);
-            // free(single_element);
-            free(raw_array);
-// free(single_block);
-#endif
-#ifdef __linux__
-            close(file_desc);
-#endif
-            // Do statistics
-            SimpleLogger().Write(logDEBUG) << "running sequential I/O statistics";
-            // print simple statistics: min, max, median, variance
-            std::ofstream seq_csv("sequential.csv", std::ios::trunc);
-            for (unsigned i = 0; i < timing_results_raw_seq.size(); ++i)
-            {
-                seq_csv << i << ", " << timing_results_raw_seq[i] << std::endl;
-            }
-            seq_csv.close();
-            RunStatistics(timing_results_raw_seq, stats);
-            SimpleLogger().Write() << "raw sequential I/O: " << std::setprecision(5) << std::fixed
-                                   << "min: " << stats.min << "ms, "
-                                   << "mean: " << stats.mean << "ms, "
-                                   << "med: " << stats.med << "ms, "
-                                   << "max: " << stats.max << "ms, "
-                                   << "dev: " << stats.dev << "ms";
-
-            if (boost::filesystem::exists(test_path))
-            {
-                boost::filesystem::remove(test_path);
-                SimpleLogger().Write(logDEBUG) << "removing temporary files";
-            }
-        }
-    }
-    catch (const std::exception &e)
-    {
-        SimpleLogger().Write(logWARNING) << "caught exception: " << e.what();
-        SimpleLogger().Write(logWARNING) << "cleaning up, and exiting";
-        if (boost::filesystem::exists(test_path))
-        {
-            boost::filesystem::remove(test_path);
-            SimpleLogger().Write(logWARNING) << "removing temporary files";
-        }
-        return -1;
-    }
-    return 0;
-#endif
-}
diff --git a/tools/simpleclient.cpp b/tools/simpleclient.cpp
deleted file mode 100644
index 17058a6..0000000
--- a/tools/simpleclient.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "util/version.hpp"
-#include "../util/json_renderer.hpp"
-#include "../util/routed_options.hpp"
-#include "../util/simple_logger.hpp"
-
-#include <osrm/json_container.hpp>
-#include <osrm/libosrm_config.hpp>
-#include <osrm/route_parameters.hpp>
-#include <osrm/osrm.hpp>
-
-#include <string>
-
-int main(int argc, const char *argv[])
-{
-    LogPolicy::GetInstance().Unmute();
-    try
-    {
-        std::string ip_address;
-        int ip_port, requested_thread_num;
-        bool trial_run = false;
-        LibOSRMConfig lib_config;
-        const unsigned init_result = GenerateServerProgramOptions(
-            argc, argv, lib_config.server_paths, ip_address, ip_port, requested_thread_num,
-            lib_config.use_shared_memory, trial_run, lib_config.max_locations_trip,
-            lib_config.max_locations_viaroute, lib_config.max_locations_distance_table,
-            lib_config.max_locations_map_matching);
-
-        if (init_result == INIT_OK_DO_NOT_START_ENGINE)
-        {
-            return 0;
-        }
-        if (init_result == INIT_FAILED)
-        {
-            return 1;
-        }
-        SimpleLogger().Write() << "starting up engines, " << OSRM_VERSION;
-
-        OSRM routing_machine(lib_config);
-
-        RouteParameters route_parameters;
-        route_parameters.zoom_level = 18;           // no generalization
-        route_parameters.print_instructions = true; // turn by turn instructions
-        route_parameters.alternate_route = true;    // get an alternate route, too
-        route_parameters.geometry = true;           // retrieve geometry of route
-        route_parameters.compression = true;        // polyline encoding
-        route_parameters.check_sum = -1;            // see wiki
-        route_parameters.service = "viaroute";      // that's routing
-        route_parameters.output_format = "json";
-        route_parameters.jsonp_parameter = ""; // set for jsonp wrapping
-        route_parameters.language = "";        // unused atm
-        // route_parameters.hints.push_back(); // see wiki, saves I/O if done properly
-
-        // start_coordinate
-        route_parameters.coordinates.emplace_back(52.519930 * COORDINATE_PRECISION,
-                                                  13.438640 * COORDINATE_PRECISION);
-        // target_coordinate
-        route_parameters.coordinates.emplace_back(52.513191 * COORDINATE_PRECISION,
-                                                  13.415852 * COORDINATE_PRECISION);
-        osrm::json::Object json_result;
-        const int result_code = routing_machine.RunQuery(route_parameters, json_result);
-        SimpleLogger().Write() << "http code: " << result_code;
-        osrm::json::render(SimpleLogger().Write(), json_result);
-    }
-    catch (std::exception &current_exception)
-    {
-        SimpleLogger().Write(logWARNING) << "caught exception: " << current_exception.what();
-        return -1;
-    }
-    return 0;
-}
diff --git a/tools/springclean.cpp b/tools/springclean.cpp
deleted file mode 100644
index 18e5711..0000000
--- a/tools/springclean.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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/data_structures/shared_datatype.hpp"
-#include "util/version.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, " << OSRM_VERSION << "\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
deleted file mode 100644
index 953254b..0000000
--- a/tools/unlock_all_mutexes.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "util/version.hpp"
-#include "../util/simple_logger.hpp"
-#include "../server/data_structures/shared_barriers.hpp"
-
-#include <iostream>
-
-int main()
-{
-    LogPolicy::GetInstance().Unmute();
-    try
-    {
-        SimpleLogger().Write() << "starting up engines, " << OSRM_VERSION;
-        SimpleLogger().Write() << "Releasing all locks";
-        SharedBarriers barrier;
-        barrier.pending_update_mutex.unlock();
-        barrier.query_mutex.unlock();
-        barrier.update_mutex.unlock();
-    }
-    catch (const std::exception &e)
-    {
-        SimpleLogger().Write(logWARNING) << "[excpetion] " << e.what();
-    }
-    return 0;
-}
diff --git a/unit_tests/algorithms/douglas_peucker.cpp b/unit_tests/algorithms/douglas_peucker.cpp
deleted file mode 100644
index 8a39209..0000000
--- a/unit_tests/algorithms/douglas_peucker.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 <boost/test/unit_test.hpp>
-#include <boost/test/test_case_template.hpp>
-
-#include <osrm/coordinate.hpp>
-
-#include <vector>
-
-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/unit_tests/algorithms/duration_parsing.cpp b/unit_tests/algorithms/duration_parsing.cpp
deleted file mode 100644
index e3035dc..0000000
--- a/unit_tests/algorithms/duration_parsing.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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/extraction_helper_functions.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <boost/test/test_case_template.hpp>
-
-BOOST_AUTO_TEST_SUITE(durations_are_valid)
-
-BOOST_AUTO_TEST_CASE(all_necessary_test)
-{
-    BOOST_CHECK_EQUAL(durationIsValid("00:01"), true);
-    BOOST_CHECK_EQUAL(durationIsValid("00:01:01"), true);
-    BOOST_CHECK_EQUAL(durationIsValid("PT15M"), true);
-}
-
-BOOST_AUTO_TEST_CASE(common_durations_get_translated)
-{
-    BOOST_CHECK_EQUAL(parseDuration("00:01"), 60);
-    BOOST_CHECK_EQUAL(parseDuration("00:01:01"), 61);
-    BOOST_CHECK_EQUAL(parseDuration("01:01"), 3660);
-
-    // check all combinations of iso duration tokens
-    BOOST_CHECK_EQUAL(parseDuration("PT1M1S"), 61);
-    BOOST_CHECK_EQUAL(parseDuration("PT1H1S"), 3601);
-    BOOST_CHECK_EQUAL(parseDuration("PT15M"), 900);
-    BOOST_CHECK_EQUAL(parseDuration("PT15S"), 15);
-    BOOST_CHECK_EQUAL(parseDuration("PT15H"), 54000);
-    BOOST_CHECK_EQUAL(parseDuration("PT1H15M"), 4500);
-    BOOST_CHECK_EQUAL(parseDuration("PT1H15M1S"), 4501);
-}
-
-BOOST_AUTO_TEST_CASE(iso_8601_durations_case_insensitive)
-{
-    BOOST_CHECK_EQUAL(parseDuration("PT15m"), 900);
-    BOOST_CHECK_EQUAL(parseDuration("PT1h15m"), 4500);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/algorithms/geometry_string.cpp b/unit_tests/algorithms/geometry_string.cpp
deleted file mode 100644
index ab9f357..0000000
--- a/unit_tests/algorithms/geometry_string.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 <boost/test/floating_point_comparison.hpp>
-#include <boost/test/unit_test.hpp>
-
-#include "../../algorithms/polyline_compressor.hpp"
-#include "../../algorithms/coordinate_calculation.hpp"
-
-#include <osrm/coordinate.hpp>
-
-#include <cmath>
-#include <vector>
-
-BOOST_AUTO_TEST_CASE(geometry_string)
-{
-    // Polyline string for the 5 coordinates
-    const std::string polyline = "_gjaR_gjaR_pR_ibE_pR_ibE_pR_ibE_pR_ibE";
-    PolylineCompressor pc;
-    std::vector<FixedPointCoordinate> coords = pc.decode_string(polyline);
-
-    // Test coordinates; these would be the coordinates we give the loc parameter,
-    // e.g. loc=10.00,10.0&loc=10.01,10.1...
-    FixedPointCoordinate coord1(10.00 * COORDINATE_PRECISION, 10.0 * COORDINATE_PRECISION);
-    FixedPointCoordinate coord2(10.01 * COORDINATE_PRECISION, 10.1 * COORDINATE_PRECISION);
-    FixedPointCoordinate coord3(10.02 * COORDINATE_PRECISION, 10.2 * COORDINATE_PRECISION);
-    FixedPointCoordinate coord4(10.03 * COORDINATE_PRECISION, 10.3 * COORDINATE_PRECISION);
-    FixedPointCoordinate coord5(10.04 * COORDINATE_PRECISION, 10.4 * COORDINATE_PRECISION);
-    
-    // Put the test coordinates into the vector for comparison
-    std::vector<FixedPointCoordinate> cmp_coords;
-    cmp_coords.emplace_back(coord1);
-    cmp_coords.emplace_back(coord2);
-    cmp_coords.emplace_back(coord3);
-    cmp_coords.emplace_back(coord4);
-    cmp_coords.emplace_back(coord5);
-
-    BOOST_CHECK_EQUAL(cmp_coords.size(), coords.size());
-
-    for(unsigned i = 0; i < cmp_coords.size(); ++i)
-    {
-	const double cmp1_lat = coords.at(i).lat;
-	const double cmp2_lat = cmp_coords.at(i).lat;
-        BOOST_CHECK_CLOSE(cmp1_lat, cmp2_lat, 0.0001);
-	
-	const double cmp1_lon = coords.at(i).lon;
-	const double cmp2_lon = cmp_coords.at(i).lon;
-        BOOST_CHECK_CLOSE(cmp1_lon, cmp2_lon, 0.0001);
-    }
-}
diff --git a/unit_tests/algorithms/string_util.cpp b/unit_tests/algorithms/string_util.cpp
deleted file mode 100644
index cf82eba..0000000
--- a/unit_tests/algorithms/string_util.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 "../../util/string_util.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <boost/test/test_case_template.hpp>
-
-#include <iostream>
-
-BOOST_AUTO_TEST_SUITE(string_util)
-
-BOOST_AUTO_TEST_CASE(json_escaping)
-{
-    std::string input{"\b\\"};
-    std::string output{escape_JSON(input)};
-
-    BOOST_CHECK_EQUAL(output, "\\b\\\\");
-
-    input = "Aleja \"Solidarnosci\"";
-    output = escape_JSON(input);
-    BOOST_CHECK_EQUAL(output, "Aleja \\\"Solidarnosci\\\"");
-}
-
-BOOST_AUTO_TEST_CASE(print_int)
-{
-    const std::string input{"\b\\"};
-    char buffer[12];
-    buffer[11] = 0; // zero termination
-    std::string output = printInt<11, 8>(buffer, 314158976);
-    BOOST_CHECK_EQUAL(output, "3.14158976");
-
-    buffer[11] = 0;
-    output = printInt<11, 8>(buffer, 0);
-    BOOST_CHECK_EQUAL(output, "0.00000000");
-
-    output = printInt<11, 8>(buffer, -314158976);
-    BOOST_CHECK_EQUAL(output, "-3.14158976");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/data_structures/coordinate.cpp b/unit_tests/data_structures/coordinate.cpp
deleted file mode 100644
index e820976..0000000
--- a/unit_tests/data_structures/coordinate.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 <boost/test/unit_test.hpp>
-
-#include "../../algorithms/coordinate_calculation.hpp"
-
-#include <osrm/coordinate.hpp>
-
-#include <cmath>
-
-// Regression test for bug captured in #1347
-BOOST_AUTO_TEST_CASE(regression_test_1347)
-{
-    FixedPointCoordinate u(10 * COORDINATE_PRECISION, -100 * COORDINATE_PRECISION);
-    FixedPointCoordinate v(10.001 * COORDINATE_PRECISION, -100.002 * COORDINATE_PRECISION);
-    FixedPointCoordinate q(10.002 * COORDINATE_PRECISION, -100.001 * COORDINATE_PRECISION);
-
-    float d1 = coordinate_calculation::perpendicular_distance(u, v, q);
-
-    float ratio;
-    FixedPointCoordinate nearest_location;
-    float d2 = coordinate_calculation::perpendicular_distance(u, v, q, nearest_location, ratio);
-
-    BOOST_CHECK_LE(std::abs(d1 - d2), 0.01f);
-}
diff --git a/unit_tests/data_structures/dynamic_graph.cpp b/unit_tests/data_structures/dynamic_graph.cpp
deleted file mode 100644
index df8eb21..0000000
--- a/unit_tests/data_structures/dynamic_graph.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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/dynamic_graph.hpp"
-#include "../../typedefs.h"
-
-#include <boost/test/unit_test.hpp>
-#include <boost/test/test_case_template.hpp>
-
-#include <vector>
-
-BOOST_AUTO_TEST_SUITE(dynamic_graph)
-
-struct TestData
-{
-    EdgeID id;
-};
-
-typedef DynamicGraph<TestData> TestDynamicGraph;
-typedef TestDynamicGraph::InputEdge TestInputEdge;
-
-BOOST_AUTO_TEST_CASE(find_test)
-{
-    /*
-     *  (0) -1-> (1)
-     *  ^ ^
-     *  2 5
-     *  | |
-     *  (3) -3-> (4)
-     *      <-4-
-     */
-    std::vector<TestInputEdge> input_edges = {
-        TestInputEdge{0, 1, TestData{1}},
-        TestInputEdge{3, 0, TestData{2}},
-        TestInputEdge{3, 0, TestData{5}},
-        TestInputEdge{3, 4, TestData{3}},
-        TestInputEdge{4, 3, TestData{4}}
-    };
-    TestDynamicGraph simple_graph(5, input_edges);
-
-    auto eit = simple_graph.FindEdge(0, 1);
-    BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 1);
-
-    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, 1);
-
-    bool reverse = false;
-    eit = simple_graph.FindEdgeIndicateIfReverse(1, 0, reverse);
-    BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 1);
-    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, 3);
-    eit = simple_graph.FindEdgeInEitherDirection(3, 4);
-    BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 3);
-
-    eit = simple_graph.FindEdge(3, 0);
-    BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 2);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/data_structures/static_rtree.cpp b/unit_tests/data_structures/static_rtree.cpp
deleted file mode 100644
index 2539d5f..0000000
--- a/unit_tests/data_structures/static_rtree.cpp
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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/coordinate_calculation.hpp"
-#include "../../algorithms/geospatial_query.hpp"
-#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 <boost/functional/hash.hpp>
-#include <boost/test/unit_test.hpp>
-#include <boost/test/test_case_template.hpp>
-
-#include <osrm/coordinate.hpp>
-
-#include <cstdint>
-#include <cmath>
-
-#include <algorithm>
-#include <memory>
-#include <random>
-#include <string>
-#include <utility>
-#include <unordered_set>
-#include <vector>
-
-BOOST_AUTO_TEST_SUITE(static_rtree)
-
-constexpr uint32_t TEST_BRANCHING_FACTOR = 8;
-constexpr uint32_t TEST_LEAF_NODE_SIZE = 64;
-
-typedef EdgeBasedNode TestData;
-using TestStaticRTree = StaticRTree<TestData,
-                                    std::vector<FixedPointCoordinate>,
-                                    false,
-                                    TEST_BRANCHING_FACTOR,
-                                    TEST_LEAF_NODE_SIZE>;
-using MiniStaticRTree = StaticRTree<TestData, std::vector<FixedPointCoordinate>, false, 2, 3>;
-
-// 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;
-
-template <typename DataT> class LinearSearchNN
-{
-  public:
-    LinearSearchNN(const std::shared_ptr<std::vector<FixedPointCoordinate>> &coords,
-                   const std::vector<DataT> &edges)
-        : coords(coords), edges(edges)
-    {
-    }
-
-    std::vector<DataT> Nearest(const FixedPointCoordinate &input_coordinate,
-                               const unsigned num_results)
-    {
-        std::vector<DataT> local_edges(edges);
-
-        std::nth_element(
-            local_edges.begin(), local_edges.begin() + num_results, local_edges.end(),
-            [this, &input_coordinate](const DataT &lhs, const DataT &rhs)
-            {
-                float current_ratio = 0.;
-                FixedPointCoordinate nearest;
-                const float lhs_dist = coordinate_calculation::perpendicular_distance(
-                    coords->at(lhs.u), coords->at(lhs.v), input_coordinate, nearest, current_ratio);
-                const float rhs_dist = coordinate_calculation::perpendicular_distance(
-                    coords->at(rhs.u), coords->at(rhs.v), input_coordinate, nearest, current_ratio);
-                return lhs_dist < rhs_dist;
-            });
-        local_edges.resize(num_results);
-
-        return local_edges;
-    }
-
-  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, OSMNodeID(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, OSMNodeID(i)));
-        }
-
-        for (const auto &pair : input_edges)
-        {
-            TestData d;
-            d.u = pair.first;
-            d.v = pair.second;
-            // We set the forward nodes to the target node-based-node IDs, just
-            // so we have something to test against.  Because this isn't a real
-            // graph, the actual values aren't important, we just need something
-            // to examine during tests.
-            d.forward_edge_based_node_id = pair.second;
-            d.reverse_edge_based_node_id = pair.first;
-            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)
-    {
-        const FixedPointCoordinate &pu = coords->at(e.u);
-        const FixedPointCoordinate &pv = coords->at(e.v);
-        auto result_u = rtree.Nearest(pu, 1);
-        auto result_v = rtree.Nearest(pv, 1);
-        BOOST_CHECK(result_u.size() == 1 && result_v.size() == 1);
-        BOOST_CHECK(result_u.front().u == e.u || result_u.front().v == e.u);
-        BOOST_CHECK(result_v.front().u == e.v || result_v.front().v == e.v);
-    }
-}
-
-template <typename RTreeT>
-void sampling_verify_rtree(RTreeT &rtree, LinearSearchNN<TestData> &lsnn, const std::vector<FixedPointCoordinate>& coords, 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)
-    {
-        auto result_rtree = rtree.Nearest(q, 1);
-        auto result_lsnn = lsnn.Nearest(q, 1);
-        BOOST_CHECK(result_rtree.size() == 1);
-        BOOST_CHECK(result_lsnn.size() == 1);
-        auto rtree_u = result_rtree.back().u;
-        auto rtree_v = result_rtree.back().v;
-        auto lsnn_u = result_lsnn.back().u;
-        auto lsnn_v = result_lsnn.back().v;
-
-        float current_ratio = 0.;
-        FixedPointCoordinate nearest;
-        const float rtree_dist = coordinate_calculation::perpendicular_distance(
-            coords[rtree_u], coords[rtree_v], q, nearest, current_ratio);
-        const float lsnn_dist = coordinate_calculation::perpendicular_distance(
-            coords[lsnn_u], coords[lsnn_v], q, nearest, current_ratio);
-        BOOST_CHECK_LE(std::abs(rtree_dist - lsnn_dist), std::numeric_limits<float>::epsilon());
-    }
-}
-
-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 auto num_nodes = static_cast<unsigned>(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<TestData> lsnn(fixture->coords, fixture->edges);
-
-    simple_verify_rtree(rtree, fixture->coords, fixture->edges);
-    sampling_verify_rtree(rtree, lsnn, *fixture->coords, 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)
-{
-    using Coord = std::pair<float, float>;
-    using Edge = std::pair<unsigned, unsigned>;
-    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)});
-
-    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);
-    LinearSearchNN<TestData> lsnn(fixture.coords, fixture.edges);
-
-    // query a node just right of the center of the gap
-    FixedPointCoordinate input(20.0 * COORDINATE_PRECISION, 55.1 * COORDINATE_PRECISION);
-    auto result_rtree = rtree.Nearest(input, 1);
-    auto result_ls = lsnn.Nearest(input, 1);
-
-    BOOST_CHECK(result_rtree.size() == 1);
-    BOOST_CHECK(result_ls.size() == 1);
-
-    BOOST_CHECK_EQUAL(result_ls.front().u, result_rtree.front().u);
-    BOOST_CHECK_EQUAL(result_ls.front().v, result_rtree.front().v);
-}
-
-void TestRectangle(double width, double height, double center_lat, double center_lon)
-{
-    FixedPointCoordinate center(center_lat * COORDINATE_PRECISION,
-                                center_lon * COORDINATE_PRECISION);
-
-    TestStaticRTree::Rectangle 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),
-                      coordinate_calculation::great_circle_distance(
-                          north, FixedPointCoordinate(rect.max_lat, north.lon)));
-    BOOST_CHECK_EQUAL(rect.GetMinDist(south),
-                      coordinate_calculation::great_circle_distance(
-                          south, FixedPointCoordinate(rect.min_lat, south.lon)));
-    BOOST_CHECK_EQUAL(rect.GetMinDist(west),
-                      coordinate_calculation::great_circle_distance(
-                          west, FixedPointCoordinate(west.lat, rect.min_lon)));
-    BOOST_CHECK_EQUAL(rect.GetMinDist(east),
-                      coordinate_calculation::great_circle_distance(
-                          east, FixedPointCoordinate(east.lat, rect.max_lon)));
-
-    /* Distance to corner points */
-    BOOST_CHECK_EQUAL(rect.GetMinDist(north_east),
-                      coordinate_calculation::great_circle_distance(
-                          north_east, FixedPointCoordinate(rect.max_lat, rect.max_lon)));
-    BOOST_CHECK_EQUAL(rect.GetMinDist(north_west),
-                      coordinate_calculation::great_circle_distance(
-                          north_west, FixedPointCoordinate(rect.max_lat, rect.min_lon)));
-    BOOST_CHECK_EQUAL(rect.GetMinDist(south_east),
-                      coordinate_calculation::great_circle_distance(
-                          south_east, FixedPointCoordinate(rect.min_lat, rect.max_lon)));
-    BOOST_CHECK_EQUAL(rect.GetMinDist(south_west),
-                      coordinate_calculation::great_circle_distance(
-                          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_CASE(bearing_tests)
-{
-    using Coord = std::pair<float, float>;
-    using Edge = std::pair<unsigned, unsigned>;
-    GraphFixture fixture(
-        {
-            Coord(0.0, 0.0), Coord(10.0, 10.0),
-        },
-        {Edge(0, 1), Edge(1, 0)});
-
-    std::string leaves_path;
-    std::string nodes_path;
-    build_rtree<GraphFixture, MiniStaticRTree>("test_bearing", &fixture, leaves_path, nodes_path);
-    MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords);
-    GeospatialQuery<MiniStaticRTree> query(rtree, fixture.coords);
-
-    FixedPointCoordinate input(5.0 * COORDINATE_PRECISION, 5.1 * COORDINATE_PRECISION);
-
-    {
-        auto results = query.NearestPhantomNodes(input, 5);
-        BOOST_CHECK_EQUAL(results.size(), 2);
-        BOOST_CHECK_EQUAL(results.back().phantom_node.forward_node_id, 0);
-        BOOST_CHECK_EQUAL(results.back().phantom_node.reverse_node_id, 1);
-    }
-
-    {
-        auto results = query.NearestPhantomNodes(input, 5, 270, 10);
-        BOOST_CHECK_EQUAL(results.size(), 0);
-    }
-
-    {
-        auto results = query.NearestPhantomNodes(input, 5, 45, 10);
-        BOOST_CHECK_EQUAL(results.size(), 2);
-        BOOST_CHECK_EQUAL(results[0].phantom_node.forward_node_id, 1);
-        BOOST_CHECK_EQUAL(results[0].phantom_node.reverse_node_id, SPECIAL_NODEID);
-        BOOST_CHECK_EQUAL(results[1].phantom_node.forward_node_id, SPECIAL_NODEID);
-        BOOST_CHECK_EQUAL(results[1].phantom_node.reverse_node_id, 1);
-    }
-
-    {
-        auto results = query.NearestPhantomNodesInRange(input, 11000);
-        BOOST_CHECK_EQUAL(results.size(), 2);
-    }
-
-    {
-        auto results = query.NearestPhantomNodesInRange(input, 11000, 270, 10);
-        BOOST_CHECK_EQUAL(results.size(), 0);
-    }
-
-    {
-        auto results = query.NearestPhantomNodesInRange(input, 11000, 45, 10);
-        BOOST_CHECK_EQUAL(results.size(), 2);
-        BOOST_CHECK_EQUAL(results[0].phantom_node.forward_node_id, 1);
-        BOOST_CHECK_EQUAL(results[0].phantom_node.reverse_node_id, SPECIAL_NODEID);
-        BOOST_CHECK_EQUAL(results[1].phantom_node.forward_node_id, SPECIAL_NODEID);
-        BOOST_CHECK_EQUAL(results[1].phantom_node.reverse_node_id, 1);
-    }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/engine/base64.cpp b/unit_tests/engine/base64.cpp
new file mode 100644
index 0000000..4896965
--- /dev/null
+++ b/unit_tests/engine/base64.cpp
@@ -0,0 +1,80 @@
+#include "engine/base64.hpp"
+#include "engine/hint.hpp"
+#include "mocks/mock_datafacade.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include <iostream>
+#include <algorithm>
+
+// RFC 4648 "The Base16, Base32, and Base64 Data Encodings"
+BOOST_AUTO_TEST_SUITE(base64)
+
+// For test vectors see section 10: https://tools.ietf.org/html/rfc4648#section-10
+BOOST_AUTO_TEST_CASE(rfc4648_test_vectors)
+{
+    using namespace osrm::engine;
+
+    BOOST_CHECK_EQUAL(encodeBase64(""), "");
+    BOOST_CHECK_EQUAL(encodeBase64("f"), "Zg==");
+    BOOST_CHECK_EQUAL(encodeBase64("fo"), "Zm8=");
+    BOOST_CHECK_EQUAL(encodeBase64("foo"), "Zm9v");
+    BOOST_CHECK_EQUAL(encodeBase64("foob"), "Zm9vYg==");
+    BOOST_CHECK_EQUAL(encodeBase64("fooba"), "Zm9vYmE=");
+    BOOST_CHECK_EQUAL(encodeBase64("foobar"), "Zm9vYmFy");
+}
+
+BOOST_AUTO_TEST_CASE(rfc4648_test_vectors_roundtrip)
+{
+    using namespace osrm::engine;
+
+    BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("")), "");
+    BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("f")), "f");
+    BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("fo")), "fo");
+    BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("foo")), "foo");
+    BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("foob")), "foob");
+    BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("fooba")), "fooba");
+    BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("foobar")), "foobar");
+}
+
+BOOST_AUTO_TEST_CASE(hint_encoding_decoding_roundtrip)
+{
+    using namespace osrm::engine;
+    using namespace osrm::util;
+
+    const Coordinate coordinate;
+    const PhantomNode phantom;
+    const osrm::test::MockDataFacade facade{};
+
+    const Hint hint{phantom, facade.GetCheckSum()};
+
+    const auto base64 = hint.ToBase64();
+
+    BOOST_CHECK(0 == std::count(begin(base64), end(base64), '+'));
+    BOOST_CHECK(0 == std::count(begin(base64), end(base64), '/'));
+
+    const auto decoded = Hint::FromBase64(base64);
+
+    BOOST_CHECK_EQUAL(hint, decoded);
+}
+
+BOOST_AUTO_TEST_CASE(hint_encoding_decoding_roundtrip_bytewise)
+{
+    using namespace osrm::engine;
+    using namespace osrm::util;
+
+    const Coordinate coordinate;
+    const PhantomNode phantom;
+    const osrm::test::MockDataFacade facade{};
+
+    const Hint hint{phantom, facade.GetCheckSum()};
+
+    const auto decoded = Hint::FromBase64(hint.ToBase64());
+
+    BOOST_CHECK(std::equal(reinterpret_cast<const unsigned char *>(&hint),
+                           reinterpret_cast<const unsigned char *>(&hint) + sizeof(Hint),
+                           reinterpret_cast<const unsigned char *>(&decoded)));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/engine/douglas_peucker.cpp b/unit_tests/engine/douglas_peucker.cpp
new file mode 100644
index 0000000..b280c13
--- /dev/null
+++ b/unit_tests/engine/douglas_peucker.cpp
@@ -0,0 +1,109 @@
+#include "engine/douglas_peucker.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include <osrm/coordinate.hpp>
+
+#include <vector>
+
+BOOST_AUTO_TEST_SUITE(douglas_peucker_simplification)
+
+using namespace osrm;
+using namespace osrm::engine;
+
+BOOST_AUTO_TEST_CASE(removed_middle_test)
+{
+    /*
+            x
+           / \
+          x   \
+         /     \
+        x       x
+    */
+    std::vector<util::Coordinate> coordinates = {
+        util::Coordinate(util::FloatLongitude(5), util::FloatLatitude(5)),
+        util::Coordinate(util::FloatLongitude(5.995715), util::FloatLatitude(6)),
+        util::Coordinate(util::FloatLongitude(10), util::FloatLatitude(10)),
+        util::Coordinate(util::FloatLongitude(15), util::FloatLatitude(5))};
+
+    for (unsigned z = 0; z < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE; z++)
+    {
+        auto result = douglasPeucker(coordinates, z);
+        BOOST_CHECK_EQUAL(result.size(), 3);
+        BOOST_CHECK_EQUAL(result[0], coordinates[0]);
+        BOOST_CHECK_EQUAL(result[1], coordinates[2]);
+        BOOST_CHECK_EQUAL(result[2], coordinates[3]);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(removed_middle_test_zoom_sensitive)
+{
+    /*
+            x
+           / \
+          x   \
+         /     \
+        x       x
+    */
+    std::vector<util::Coordinate> coordinates = {
+        util::Coordinate(util::FloatLongitude(5), util::FloatLatitude(5)),
+        util::Coordinate(util::FloatLongitude(6), util::FloatLatitude(6)),
+        util::Coordinate(util::FloatLongitude(10), util::FloatLatitude(10)),
+        util::Coordinate(util::FloatLongitude(15), util::FloatLatitude(5))};
+
+    // Coordinate 6,6 should start getting included at Z12 and higher
+    // Note that 5,5->6,6->10,10 is *not* a straight line on the surface
+    // of the earth
+    for (unsigned z = 0; z < 11; z++)
+    {
+        auto result = douglasPeucker(coordinates, z);
+        BOOST_CHECK_EQUAL(result.size(), 3);
+    }
+    // From 12 to max zoom, we should get all coordinates
+    for (unsigned z = 12; z < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE; z++)
+    {
+        auto result = douglasPeucker(coordinates, z);
+        BOOST_CHECK_EQUAL(result.size(), 4);
+    }
+}
+
+
+BOOST_AUTO_TEST_CASE(remove_second_node_test)
+{
+    for (unsigned z = 0; z < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE; z++)
+    {
+        /*
+             x--x
+             |   \
+           x-x    x
+                  |
+                  x
+        */
+        std::vector<util::Coordinate> input = {
+            util::Coordinate(util::FixedLongitude(5 * COORDINATE_PRECISION),
+                             util::FixedLatitude(5 * COORDINATE_PRECISION)),
+            util::Coordinate(util::FixedLongitude(5 * COORDINATE_PRECISION),
+                             util::FixedLatitude(5 * COORDINATE_PRECISION +
+                                                 detail::DOUGLAS_PEUCKER_THRESHOLDS[z])),
+            util::Coordinate(util::FixedLongitude(10 * COORDINATE_PRECISION),
+                             util::FixedLatitude(10 * COORDINATE_PRECISION)),
+            util::Coordinate(util::FixedLongitude(10 * COORDINATE_PRECISION),
+                             util::FixedLatitude(10 + COORDINATE_PRECISION +
+                                                 detail::DOUGLAS_PEUCKER_THRESHOLDS[z] * 2)),
+            util::Coordinate(util::FixedLongitude(5 * COORDINATE_PRECISION),
+                             util::FixedLatitude(15 * COORDINATE_PRECISION)),
+            util::Coordinate(util::FixedLongitude(5 * COORDINATE_PRECISION +
+                                                  detail::DOUGLAS_PEUCKER_THRESHOLDS[z]),
+                             util::FixedLatitude(15 * COORDINATE_PRECISION))};
+        BOOST_TEST_MESSAGE("Threshold (" << z << "): " << detail::DOUGLAS_PEUCKER_THRESHOLDS[z]);
+        auto result = douglasPeucker(input, z);
+        BOOST_CHECK_EQUAL(result.size(), 4);
+        BOOST_CHECK_EQUAL(input[0], result[0]);
+        BOOST_CHECK_EQUAL(input[2], result[1]);
+        BOOST_CHECK_EQUAL(input[3], result[2]);
+        BOOST_CHECK_EQUAL(input[5], result[3]);
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/engine/geometry_string.cpp b/unit_tests/engine/geometry_string.cpp
new file mode 100644
index 0000000..5209460
--- /dev/null
+++ b/unit_tests/engine/geometry_string.cpp
@@ -0,0 +1,45 @@
+#include <boost/test/floating_point_comparison.hpp>
+#include <boost/test/unit_test.hpp>
+
+#include "engine/polyline_compressor.hpp"
+#include "util/coordinate_calculation.hpp"
+
+#include <osrm/coordinate.hpp>
+
+#include <cmath>
+#include <vector>
+
+BOOST_AUTO_TEST_SUITE(polyline)
+
+using namespace osrm;
+using namespace osrm::engine;
+
+BOOST_AUTO_TEST_CASE(decode)
+{
+    // Polyline string for the 5 coordinates
+    const std::string polyline = "_c`|@_c`|@o}@_pRo}@_pRo}@_pRo}@_pR";
+    const auto coords = decodePolyline(polyline);
+
+    // Test coordinates; these would be the coordinates we give the loc parameter,
+    // e.g. loc=10.00,10.0&loc=10.01,10.1...
+    util::Coordinate coord1(util::FloatLongitude(10.0), util::FloatLatitude(10.00));
+    util::Coordinate coord2(util::FloatLongitude(10.1), util::FloatLatitude(10.01));
+    util::Coordinate coord3(util::FloatLongitude(10.2), util::FloatLatitude(10.02));
+    util::Coordinate coord4(util::FloatLongitude(10.3), util::FloatLatitude(10.03));
+    util::Coordinate coord5(util::FloatLongitude(10.4), util::FloatLatitude(10.04));
+
+    // Put the test coordinates into the vector for comparison
+    std::vector<util::Coordinate> cmp_coords = {coord1, coord2, coord3, coord4, coord5};
+
+    BOOST_CHECK_EQUAL(cmp_coords.size(), coords.size());
+
+    for (unsigned i = 0; i < cmp_coords.size(); ++i)
+    {
+        BOOST_CHECK_CLOSE(static_cast<double>(util::toFloating(coords[i].lat)),
+                          static_cast<double>(util::toFloating(cmp_coords[i].lat)), 0.0001);
+        BOOST_CHECK_CLOSE(static_cast<double>(util::toFloating(coords[i].lon)),
+                          static_cast<double>(util::toFloating(cmp_coords[i].lon)), 0.0001);
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/engine/guidance_assembly.cpp b/unit_tests/engine/guidance_assembly.cpp
new file mode 100644
index 0000000..6f50529
--- /dev/null
+++ b/unit_tests/engine/guidance_assembly.cpp
@@ -0,0 +1,20 @@
+#include "engine/guidance/assemble_overview.hpp"
+#include "engine/guidance/assemble_geometry.hpp"
+#include "engine/guidance/assemble_steps.hpp"
+#include "engine/guidance/assemble_route.hpp"
+#include "engine/guidance/assemble_leg.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+BOOST_AUTO_TEST_SUITE(guidance_assembly)
+
+BOOST_AUTO_TEST_CASE(rfc4648_test_vectors)
+{
+    using namespace osrm::engine::guidance;
+    using namespace osrm::engine;
+
+    // TODO(daniel-j-h):
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/engine_tests.cpp b/unit_tests/engine_tests.cpp
new file mode 100644
index 0000000..8154f03
--- /dev/null
+++ b/unit_tests/engine_tests.cpp
@@ -0,0 +1,7 @@
+#define BOOST_TEST_MODULE engine tests
+
+#include <boost/test/unit_test.hpp>
+
+/*
+ * This file will contain an automatically generated main function.
+ */
diff --git a/unit_tests/data_structures/compressed_edge_container.cpp b/unit_tests/extractor/compressed_edge_container.cpp
similarity index 95%
rename from unit_tests/data_structures/compressed_edge_container.cpp
rename to unit_tests/extractor/compressed_edge_container.cpp
index 12d9d3f..593ec59 100644
--- a/unit_tests/data_structures/compressed_edge_container.cpp
+++ b/unit_tests/extractor/compressed_edge_container.cpp
@@ -1,11 +1,14 @@
-#include "../../data_structures/compressed_edge_container.hpp"
-#include "../../typedefs.h"
+#include "extractor/compressed_edge_container.hpp"
+#include "util/typedefs.hpp"
 
 #include <boost/test/unit_test.hpp>
 #include <boost/test/test_case_template.hpp>
 
 BOOST_AUTO_TEST_SUITE(compressed_edge_container)
 
+using namespace osrm;
+using namespace osrm::extractor;
+
 BOOST_AUTO_TEST_CASE(long_road_test)
 {
     //   0   1    2    3
diff --git a/unit_tests/algorithms/graph_compressor.cpp b/unit_tests/extractor/graph_compressor.cpp
similarity index 71%
rename from unit_tests/algorithms/graph_compressor.cpp
rename to unit_tests/extractor/graph_compressor.cpp
index a3407c0..7a6da7a 100644
--- a/unit_tests/algorithms/graph_compressor.cpp
+++ b/unit_tests/extractor/graph_compressor.cpp
@@ -1,9 +1,8 @@
-#include "../../algorithms/graph_compressor.hpp"
-#include "../../data_structures/compressed_edge_container.hpp"
-#include "../../data_structures/restriction_map.hpp"
-#include "../../data_structures/node_based_graph.hpp"
-#include "../../extractor/speed_profile.hpp"
-#include "../../typedefs.h"
+#include "extractor/graph_compressor.hpp"
+#include "extractor/compressed_edge_container.hpp"
+#include "extractor/restriction_map.hpp"
+#include "util/node_based_graph.hpp"
+#include "util/typedefs.hpp"
 
 #include <boost/test/unit_test.hpp>
 #include <boost/test/test_case_template.hpp>
@@ -12,37 +11,39 @@
 
 BOOST_AUTO_TEST_SUITE(graph_compressor)
 
+using namespace osrm;
+using namespace osrm::extractor;
+using InputEdge = util::NodeBasedDynamicGraph::InputEdge;
+using Graph = util::NodeBasedDynamicGraph;
+
 BOOST_AUTO_TEST_CASE(long_road_test)
 {
     //
     // 0---1---2---3---4
     //
-    SpeedProfileProperties speed_profile;
-    GraphCompressor compressor(speed_profile);
+    GraphCompressor compressor;
 
     std::unordered_set<NodeID> barrier_nodes;
     std::unordered_set<NodeID> traffic_lights;
     RestrictionMap map;
     CompressedEdgeContainer container;
 
-    using InputEdge = NodeBasedDynamicGraph::InputEdge;
     std::vector<InputEdge> edges = {
-        // source, target, distance, edge_id, name_id, access_restricted, reversed, roundabout, travel_mode
-        {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {2, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {3, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {3, 4, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {4, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT}
-    };
+        // src, tgt, dist, edge_id, name_id, access_restricted, fwd, bkwd, roundabout, travel_mode
+        {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {2, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {3, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {3, 4, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {4, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE}};
 
     BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[2].data));
     BOOST_ASSERT(edges[2].data.IsCompatibleTo(edges[4].data));
     BOOST_ASSERT(edges[4].data.IsCompatibleTo(edges[6].data));
 
-    NodeBasedDynamicGraph graph(5, edges);
+    Graph graph(5, edges);
     compressor.Compress(barrier_nodes, traffic_lights, map, graph, container);
 
     BOOST_CHECK_EQUAL(graph.FindEdge(0, 1), SPECIAL_EDGEID);
@@ -59,29 +60,27 @@ BOOST_AUTO_TEST_CASE(loop_test)
     // |       |
     // 5---4---3
     //
-    SpeedProfileProperties speed_profile;
-    GraphCompressor compressor(speed_profile);
+    GraphCompressor compressor;
 
     std::unordered_set<NodeID> barrier_nodes;
     std::unordered_set<NodeID> traffic_lights;
     RestrictionMap map;
     CompressedEdgeContainer container;
 
-    using InputEdge = NodeBasedDynamicGraph::InputEdge;
     std::vector<InputEdge> edges = {
-        // source, target, distance, edge_id, name_id, access_restricted, forward, backward, roundabout, travel_mode
-        {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {0, 5, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {2, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {3, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {3, 4, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {4, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {4, 5, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {5, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {5, 4, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
+        // src, tgt, dist, edge_id, name_id, access_restricted, fwd, bkwd, roundabout, travel_mode
+        {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {0, 5, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {2, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {3, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {3, 4, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {4, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {4, 5, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {5, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {5, 4, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
     };
 
     BOOST_ASSERT(edges.size() == 12);
@@ -97,7 +96,7 @@ BOOST_AUTO_TEST_CASE(loop_test)
     BOOST_ASSERT(edges[9].data.IsCompatibleTo(edges[10].data));
     BOOST_ASSERT(edges[10].data.IsCompatibleTo(edges[11].data));
 
-    NodeBasedDynamicGraph graph(6, edges);
+    Graph graph(6, edges);
     compressor.Compress(barrier_nodes, traffic_lights, map, graph, container);
 
     BOOST_CHECK_EQUAL(graph.FindEdge(5, 0), SPECIAL_EDGEID);
@@ -116,23 +115,21 @@ BOOST_AUTO_TEST_CASE(t_intersection)
     //     |
     //     3
     //
-    SpeedProfileProperties speed_profile;
-    GraphCompressor compressor(speed_profile);
+    GraphCompressor compressor;
 
     std::unordered_set<NodeID> barrier_nodes;
     std::unordered_set<NodeID> traffic_lights;
     RestrictionMap map;
     CompressedEdgeContainer container;
 
-    using InputEdge = NodeBasedDynamicGraph::InputEdge;
     std::vector<InputEdge> edges = {
-        // source, target, distance, edge_id, name_id, access_restricted, reversed, roundabout, travel_mode
-        {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {1, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {3, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
+        // src, tgt, dist, edge_id, name_id, access_restricted, fwd, bkwd, roundabout, travel_mode
+        {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {1, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {3, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
     };
 
     BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[1].data));
@@ -141,7 +138,7 @@ BOOST_AUTO_TEST_CASE(t_intersection)
     BOOST_ASSERT(edges[3].data.IsCompatibleTo(edges[4].data));
     BOOST_ASSERT(edges[4].data.IsCompatibleTo(edges[5].data));
 
-    NodeBasedDynamicGraph graph(4, edges);
+    Graph graph(4, edges);
     compressor.Compress(barrier_nodes, traffic_lights, map, graph, container);
 
     BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
@@ -154,27 +151,25 @@ BOOST_AUTO_TEST_CASE(street_name_changes)
     //
     // 0---1---2
     //
-    SpeedProfileProperties speed_profile;
-    GraphCompressor compressor(speed_profile);
+    GraphCompressor compressor;
 
     std::unordered_set<NodeID> barrier_nodes;
     std::unordered_set<NodeID> traffic_lights;
     RestrictionMap map;
     CompressedEdgeContainer container;
 
-    using InputEdge = NodeBasedDynamicGraph::InputEdge;
     std::vector<InputEdge> edges = {
-        // source, target, distance, edge_id, name_id, access_restricted, forward, backward, roundabout, travel_mode
-        {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {1, 2, 1, SPECIAL_EDGEID, 1, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {2, 1, 1, SPECIAL_EDGEID, 1, false, false, false, true, TRAVEL_MODE_DEFAULT},
+        // src, tgt, dist, edge_id, name_id, access_restricted, fwd, bkwd, roundabout, travel_mode
+        {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {1, 2, 1, SPECIAL_EDGEID, 1, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {2, 1, 1, SPECIAL_EDGEID, 1, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
     };
 
     BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[1].data));
     BOOST_ASSERT(edges[2].data.IsCompatibleTo(edges[3].data));
 
-    NodeBasedDynamicGraph graph(5, edges);
+    Graph graph(5, edges);
     compressor.Compress(barrier_nodes, traffic_lights, map, graph, container);
 
     BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
@@ -186,24 +181,22 @@ BOOST_AUTO_TEST_CASE(direction_changes)
     //
     // 0-->1---2
     //
-    SpeedProfileProperties speed_profile;
-    GraphCompressor compressor(speed_profile);
+    GraphCompressor compressor;
 
     std::unordered_set<NodeID> barrier_nodes;
     std::unordered_set<NodeID> traffic_lights;
     RestrictionMap map;
     CompressedEdgeContainer container;
 
-    using InputEdge = NodeBasedDynamicGraph::InputEdge;
     std::vector<InputEdge> edges = {
-        // source, target, distance, edge_id, name_id, access_restricted, reverse, roundabout, travel_mode
-        {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {1, 0, 1, SPECIAL_EDGEID, 0, false, true,  false, true, TRAVEL_MODE_DEFAULT},
-        {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
-        {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
+        // src, tgt, dist, edge_id, name_id, access_restricted, fwd, bkwd, roundabout, travel_mode
+        {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {1, 0, 1, SPECIAL_EDGEID, 0, false, true, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+        {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
     };
 
-    NodeBasedDynamicGraph graph(5, edges);
+    Graph graph(5, edges);
     compressor.Compress(barrier_nodes, traffic_lights, map, graph, container);
 
     BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
diff --git a/unit_tests/data_structures/raster_source.cpp b/unit_tests/extractor/raster_source.cpp
similarity index 63%
rename from unit_tests/data_structures/raster_source.cpp
rename to unit_tests/extractor/raster_source.cpp
index 691cba1..1c66f12 100644
--- a/unit_tests/data_structures/raster_source.cpp
+++ b/unit_tests/extractor/raster_source.cpp
@@ -1,33 +1,6 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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/raster_source.hpp"
-#include "../../typedefs.h"
-#include "../../util/osrm_exception.hpp"
+#include "extractor/raster_source.hpp"
+#include "util/typedefs.hpp"
+#include "util/exception.hpp"
 
 #include <osrm/coordinate.hpp>
 
@@ -36,16 +9,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 BOOST_AUTO_TEST_SUITE(raster_source)
 
+using namespace osrm;
+using namespace osrm::extractor;
+
 int normalize(double coord) { return static_cast<int>(coord * COORDINATE_PRECISION); }
 
 #define CHECK_QUERY(source_id, lon, lat, expected)                                                 \
     BOOST_CHECK_EQUAL(                                                                             \
-        sources.getRasterDataFromSource(source_id, normalize(lon), normalize(lat)).datum,          \
+        sources.getRasterDataFromSource(source_id, lon, lat).datum,          \
         expected)
 
 #define CHECK_INTERPOLATE(source_id, lon, lat, expected)                                           \
     BOOST_CHECK_EQUAL(                                                                             \
-        sources.getRasterInterpolateFromSource(source_id, normalize(lon), normalize(lat)).datum,   \
+        sources.getRasterInterpolateFromSource(source_id, lon, lat).datum,   \
         expected)
 
 BOOST_AUTO_TEST_CASE(raster_test)
@@ -100,11 +76,11 @@ BOOST_AUTO_TEST_CASE(raster_test)
 
     BOOST_CHECK_EQUAL(source_already_loaded_id, 0);
     BOOST_CHECK_THROW(sources.getRasterDataFromSource(1, normalize(0.02), normalize(0.02)),
-                      osrm::exception);
+                      util::exception);
 
     BOOST_CHECK_THROW(
         sources.loadRasterSource("../unit_tests/fixtures/nonexistent.asc", 0, 0.1, 0, 0.1, 7, 7),
-        osrm::exception);
+        util::exception);
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/extractor_tests.cpp b/unit_tests/extractor_tests.cpp
new file mode 100644
index 0000000..f2b4745
--- /dev/null
+++ b/unit_tests/extractor_tests.cpp
@@ -0,0 +1,7 @@
+#define BOOST_TEST_MODULE extractor tests
+
+#include <boost/test/unit_test.hpp>
+
+/*
+ * This file will contain an automatically generated main function.
+ */
diff --git a/unit_tests/library/args.hpp b/unit_tests/library/args.hpp
new file mode 100644
index 0000000..b595e32
--- /dev/null
+++ b/unit_tests/library/args.hpp
@@ -0,0 +1,16 @@
+#ifndef OSRM_UNIT_TEST_ARGS
+#define OSRM_UNIT_TEST_ARGS
+
+#include <vector>
+#include <string>
+
+inline std::vector<std::string> get_args()
+{
+    // Split off argv[0], store actual positional arguments in args
+    const auto argc = boost::unit_test::framework::master_test_suite().argc - 1;
+    const auto argv = boost::unit_test::framework::master_test_suite().argv + 1;
+
+    return {argv, argv + argc};
+}
+
+#endif
diff --git a/unit_tests/library/coordinates.hpp b/unit_tests/library/coordinates.hpp
new file mode 100644
index 0000000..2ccc689
--- /dev/null
+++ b/unit_tests/library/coordinates.hpp
@@ -0,0 +1,28 @@
+#ifndef OSRM_UNIT_TEST_COORDINATES
+#define OSRM_UNIT_TEST_COORDINATES
+
+#include "osrm/coordinate.hpp"
+
+#include <vector>
+
+// Somewhere in 2b8dd9343d5e615afc9c67bcc7028a63 Monaco
+
+// Convenience aliases
+using Longitude = osrm::util::FloatLongitude;
+using Latitude = osrm::util::FloatLatitude;
+using Location = osrm::util::Coordinate;
+using Locations = std::vector<Location>;
+
+inline Location get_dummy_location()
+{
+    return {osrm::util::FloatLongitude{7.437069}, osrm::util::FloatLatitude{43.749249}};
+}
+
+inline Locations get_locations_in_small_component()
+{
+    return {{Longitude{7.438023}, Latitude{43.746465}},
+            {Longitude{7.439263}, Latitude{43.746543}},
+            {Longitude{7.438190}, Latitude{43.747560}}};
+}
+
+#endif
diff --git a/unit_tests/library/equal_json.hpp b/unit_tests/library/equal_json.hpp
new file mode 100644
index 0000000..8e2f9ac
--- /dev/null
+++ b/unit_tests/library/equal_json.hpp
@@ -0,0 +1,27 @@
+#ifndef UNIT_TESTS_JSON_EQUAL
+#define UNIT_TESTS_JSON_EQUAL
+
+#include <boost/test/included/unit_test.hpp>
+
+#include "util/json_deep_compare.hpp"
+
+boost::test_tools::predicate_result compareJSON(const osrm::util::json::Value &reference,
+                                                  const osrm::util::json::Value &result)
+{
+    std::string reason;
+    auto is_same = osrm::util::json::compare(reference, result, reason);
+    if (!is_same)
+    {
+        boost::test_tools::predicate_result res(false);
+
+        res.message() << reason;
+
+        return res;
+    }
+
+    return true;
+}
+
+#define CHECK_EQUAL_JSON(reference, result) BOOST_CHECK(compareJSON(reference, result));
+
+#endif
diff --git a/unit_tests/library/fixture.hpp b/unit_tests/library/fixture.hpp
new file mode 100644
index 0000000..568593d
--- /dev/null
+++ b/unit_tests/library/fixture.hpp
@@ -0,0 +1,21 @@
+#ifndef OSRM_LIBRARY_TEST_FIXTURE
+#define OSRM_LIBRARY_TEST_FIXTURE
+
+#include "osrm/engine_config.hpp"
+#include "osrm/osrm.hpp"
+
+#include <string>
+
+// I couldn't get Boost.UnitTest to provide a test suite level fixture with custom
+// arguments per test suite (osrm base path from argv), so this has to suffice.
+
+inline osrm::OSRM getOSRM(const std::string &base_path)
+{
+    osrm::EngineConfig config;
+    config.storage_config = {base_path};
+    config.use_shared_memory = false;
+
+    return osrm::OSRM{config};
+}
+
+#endif
diff --git a/unit_tests/library/limits.cpp b/unit_tests/library/limits.cpp
new file mode 100644
index 0000000..8632171
--- /dev/null
+++ b/unit_tests/library/limits.cpp
@@ -0,0 +1,139 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include "args.hpp"
+
+#include "osrm/trip_parameters.hpp"
+#include "osrm/route_parameters.hpp"
+#include "osrm/table_parameters.hpp"
+#include "osrm/match_parameters.hpp"
+
+#include "osrm/coordinate.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/json_container.hpp"
+#include "osrm/status.hpp"
+#include "osrm/osrm.hpp"
+
+BOOST_AUTO_TEST_SUITE(limits)
+
+BOOST_AUTO_TEST_CASE(test_trip_limits)
+{
+    const auto args = get_args();
+    BOOST_REQUIRE_EQUAL(args.size(), 1);
+
+    using namespace osrm;
+
+    EngineConfig config;
+    config.storage_config = {args[0]};
+    config.use_shared_memory = false;
+    config.max_locations_trip = 2;
+
+    OSRM osrm{config};
+
+    TripParameters params;
+    params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+    params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+    params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+
+    json::Object result;
+
+    const auto rc = osrm.Trip(params, result);
+
+    BOOST_CHECK(rc == Status::Error);
+
+    // Make sure we're not accidentally hitting a guard code path before
+    const auto code = result.values["code"].get<json::String>().value;
+    BOOST_CHECK(code == "TooBig"); // per the New-Server API spec
+}
+
+BOOST_AUTO_TEST_CASE(test_route_limits)
+{
+    const auto args = get_args();
+    BOOST_REQUIRE_EQUAL(args.size(), 1);
+
+    using namespace osrm;
+
+    EngineConfig config;
+    config.storage_config = {args[0]};
+    config.use_shared_memory = false;
+    config.max_locations_viaroute = 2;
+
+    OSRM osrm{config};
+
+    RouteParameters params;
+    params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+    params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+    params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+
+    json::Object result;
+
+    const auto rc = osrm.Route(params, result);
+
+    BOOST_CHECK(rc == Status::Error);
+
+    // Make sure we're not accidentally hitting a guard code path before
+    const auto code = result.values["code"].get<json::String>().value;
+    BOOST_CHECK(code == "TooBig"); // per the New-Server API spec
+}
+
+BOOST_AUTO_TEST_CASE(test_table_limits)
+{
+    const auto args = get_args();
+    BOOST_REQUIRE_EQUAL(args.size(), 1);
+
+    using namespace osrm;
+
+    EngineConfig config;
+    config.storage_config = {args[0]};
+    config.use_shared_memory = false;
+    config.max_locations_distance_table = 2;
+
+    OSRM osrm{config};
+
+    TableParameters params;
+    params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+    params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+    params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+
+    json::Object result;
+
+    const auto rc = osrm.Table(params, result);
+
+    BOOST_CHECK(rc == Status::Error);
+
+    // Make sure we're not accidentally hitting a guard code path before
+    const auto code = result.values["code"].get<json::String>().value;
+    BOOST_CHECK(code == "TooBig"); // per the New-Server API spec
+}
+
+BOOST_AUTO_TEST_CASE(test_match_limits)
+{
+    const auto args = get_args();
+    BOOST_REQUIRE_EQUAL(args.size(), 1);
+
+    using namespace osrm;
+
+    EngineConfig config;
+    config.storage_config = {args[0]};
+    config.use_shared_memory = false;
+    config.max_locations_map_matching = 2;
+
+    OSRM osrm{config};
+
+    MatchParameters params;
+    params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+    params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+    params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+
+    json::Object result;
+
+    const auto rc = osrm.Match(params, result);
+
+    BOOST_CHECK(rc == Status::Error);
+
+    // Make sure we're not accidentally hitting a guard code path before
+    const auto code = result.values["code"].get<json::String>().value;
+    BOOST_CHECK(code == "TooBig"); // per the New-Server API spec
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/library/match.cpp b/unit_tests/library/match.cpp
new file mode 100644
index 0000000..5cd2739
--- /dev/null
+++ b/unit_tests/library/match.cpp
@@ -0,0 +1,37 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include "args.hpp"
+#include "fixture.hpp"
+
+#include "osrm/match_parameters.hpp"
+
+#include "osrm/coordinate.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/json_container.hpp"
+#include "osrm/status.hpp"
+#include "osrm/osrm.hpp"
+
+BOOST_AUTO_TEST_SUITE(match)
+
+BOOST_AUTO_TEST_CASE(test_match)
+{
+    const auto args = get_args();
+    BOOST_REQUIRE_EQUAL(args.size(), 1);
+
+    using namespace osrm;
+
+    auto osrm = getOSRM(args[0]);
+
+    /*
+    MatchParameters params;
+
+    json::Object result;
+
+    const auto rc = osrm.Match(params, result);
+
+    BOOST_CHECK(rc == Status::Ok || rc == Status::Error);
+    */
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/library/nearest.cpp b/unit_tests/library/nearest.cpp
new file mode 100644
index 0000000..b56f0f7
--- /dev/null
+++ b/unit_tests/library/nearest.cpp
@@ -0,0 +1,116 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include "args.hpp"
+#include "fixture.hpp"
+#include "coordinates.hpp"
+
+#include "osrm/nearest_parameters.hpp"
+
+#include "osrm/coordinate.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/json_container.hpp"
+#include "osrm/status.hpp"
+#include "osrm/osrm.hpp"
+
+BOOST_AUTO_TEST_SUITE(nearest)
+
+BOOST_AUTO_TEST_CASE(test_nearest_response)
+{
+    const auto args = get_args();
+    auto osrm = getOSRM(args.at(0));
+
+    using namespace osrm;
+
+    NearestParameters params;
+    params.coordinates.push_back(get_dummy_location());
+
+    json::Object result;
+    const auto rc = osrm.Nearest(params, result);
+    BOOST_REQUIRE(rc == Status::Ok);
+
+    const auto code = result.values.at("code").get<json::String>().value;
+    BOOST_CHECK_EQUAL(code, "ok");
+
+    const auto &waypoints = result.values.at("waypoints").get<json::Array>().values;
+    BOOST_CHECK(!waypoints.empty()); // the dataset has at least one nearest coordinate
+
+    for (const auto &waypoint : waypoints)
+    {
+        const auto &waypoint_object = waypoint.get<json::Object>();
+        const auto distance = waypoint_object.values.at("distance").get<json::Number>().value;
+        BOOST_CHECK(distance >= 0);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(test_nearest_response_no_coordinates)
+{
+    const auto args = get_args();
+    auto osrm = getOSRM(args.at(0));
+
+    using namespace osrm;
+
+    NearestParameters params;
+
+    json::Object result;
+    const auto rc = osrm.Nearest(params, result);
+    BOOST_REQUIRE(rc == Status::Error);
+
+    const auto code = result.values.at("code").get<json::String>().value;
+    BOOST_CHECK_EQUAL(code, "InvalidOptions");
+}
+
+BOOST_AUTO_TEST_CASE(test_nearest_response_multiple_coordinates)
+{
+    const auto args = get_args();
+    auto osrm = getOSRM(args.at(0));
+
+    using namespace osrm;
+
+    NearestParameters params;
+    params.coordinates.push_back(get_dummy_location());
+    params.coordinates.push_back(get_dummy_location());
+
+    json::Object result;
+    const auto rc = osrm.Nearest(params, result);
+    BOOST_REQUIRE(rc == Status::Error);
+
+    const auto code = result.values.at("code").get<json::String>().value;
+    BOOST_CHECK_EQUAL(code, "InvalidOptions");
+}
+
+BOOST_AUTO_TEST_CASE(test_nearest_response_for_location_in_small_component)
+{
+    const auto args = get_args();
+    auto osrm = getOSRM(args.at(0));
+
+    using namespace osrm;
+
+    const auto locations = get_locations_in_small_component();
+
+    NearestParameters params;
+    params.coordinates.push_back(locations.at(0));
+    params.number_of_results = 3;
+
+    json::Object result;
+    const auto rc = osrm.Nearest(params, result);
+    BOOST_REQUIRE(rc == Status::Ok);
+
+    const auto code = result.values.at("code").get<json::String>().value;
+    BOOST_CHECK_EQUAL(code, "ok");
+
+    const auto &waypoints = result.values.at("waypoints").get<json::Array>().values;
+    BOOST_CHECK(!waypoints.empty());
+
+    for (const auto &waypoint : waypoints)
+    {
+        const auto &waypoint_object = waypoint.get<json::Object>();
+
+        // Everything within ~20m (actually more) is still in small component.
+        // Nearest service should snap to road network without considering components.
+        const auto distance = waypoint_object.values.at("distance").get<json::Number>().value;
+        BOOST_CHECK_LT(distance, 20);
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/library/route.cpp b/unit_tests/library/route.cpp
new file mode 100644
index 0000000..e93ceba
--- /dev/null
+++ b/unit_tests/library/route.cpp
@@ -0,0 +1,232 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include "args.hpp"
+#include "fixture.hpp"
+#include "equal_json.hpp"
+#include "coordinates.hpp"
+
+#include "osrm/route_parameters.hpp"
+
+#include "osrm/coordinate.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/json_container.hpp"
+#include "osrm/status.hpp"
+#include "osrm/osrm.hpp"
+
+BOOST_AUTO_TEST_SUITE(route)
+
+BOOST_AUTO_TEST_CASE(test_route_same_coordinates_fixture)
+{
+    const auto args = get_args();
+    auto osrm = getOSRM(args.at(0));
+
+    using namespace osrm;
+
+    RouteParameters params;
+    params.coordinates.push_back(get_dummy_location());
+    params.coordinates.push_back(get_dummy_location());
+
+    json::Object result;
+    const auto rc = osrm.Route(params, result);
+    BOOST_CHECK(rc == Status::Ok);
+
+    json::Object reference{
+        {{"code", "ok"},
+         {"waypoints",
+          json::Array{{json::Object{{{"name", ""}, {"location", json::Array{}}, {"hint", ""}}},
+                       json::Object{{{"name", ""}, {"location", json::Array{}}, {"hint", ""}}}}}},
+         {"routes", json::Array{{json::Object{
+                        {{"distance", 0.},
+                         {"duration", 0.},
+                         {"geometry", ""},
+                         {"legs", json::Array{{json::Object{
+                                      {{"distance", 0.},
+                                       {"duration", 0.},
+                                       {"summary", ""},
+                                       {"steps", json::Array{{json::Object{
+                                                     {{"duration", 0.},
+                                                      {"distance", 0.},
+                                                      {"geometry", ""},
+                                                      {"name", ""},
+                                                      {"mode", "driving"},
+                                                      {"maneuver", json::Object{{
+                                                                       {"type", "depart"},
+                                                                       {"location", json::Array{}},
+                                                                       {"modifier", ""},
+                                                                       {"bearing_before", 0.},
+                                                                       {"bearing_after", 0.},
+                                                                       {"exit", 0},
+                                                                   }}}}}}}}}}}}}}}}}}}};
+
+    CHECK_EQUAL_JSON(reference, result);
+}
+
+BOOST_AUTO_TEST_CASE(test_route_same_coordinates)
+{
+    const auto args = get_args();
+    auto osrm = getOSRM(args.at(0));
+
+    using namespace osrm;
+
+    RouteParameters params;
+    params.coordinates.push_back(get_dummy_location());
+    params.coordinates.push_back(get_dummy_location());
+    params.coordinates.push_back(get_dummy_location());
+
+    json::Object result;
+    const auto rc = osrm.Route(params, result);
+    BOOST_CHECK(rc == Status::Ok);
+
+    const auto code = result.values.at("code").get<json::String>().value;
+    BOOST_CHECK_EQUAL(code, "ok");
+
+    const auto &waypoints = result.values.at("waypoints").get<json::Array>().values;
+    BOOST_CHECK(waypoints.size() == params.coordinates.size());
+
+    for (const auto &waypoint : waypoints)
+    {
+        const auto &waypoint_object = waypoint.get<json::Object>();
+
+        // nothing can be said about name, empty or contains name of the street
+        const auto name = waypoint_object.values.at("name").get<json::String>().value;
+        BOOST_CHECK(((void)name, true));
+
+        const auto location = waypoint_object.values.at("location").get<json::Array>().values;
+        const auto longitude = location[0].get<json::Number>().value;
+        const auto latitude = location[1].get<json::Number>().value;
+        BOOST_CHECK(longitude >= -180. && longitude <= 180.);
+        BOOST_CHECK(latitude >= -90. && latitude <= 90.);
+
+        const auto hint = waypoint_object.values.at("hint").get<json::String>().value;
+        BOOST_CHECK(!hint.empty());
+    }
+
+    // alternative=true by default
+    const auto &routes = result.values.at("routes").get<json::Array>().values;
+    BOOST_CHECK(!routes.empty());
+    BOOST_CHECK(routes.size() > 1);
+
+    for (const auto &route : routes)
+    {
+        const auto &route_object = route.get<json::Object>();
+
+        const auto distance = route_object.values.at("distance").get<json::Number>().value;
+        BOOST_CHECK_EQUAL(distance, 0);
+
+        const auto duration = route_object.values.at("duration").get<json::Number>().value;
+        BOOST_CHECK_EQUAL(duration, 0);
+
+        // geometries=polyline by default
+        const auto geometry = route_object.values.at("geometry").get<json::String>().value;
+        BOOST_CHECK(!geometry.empty());
+
+        const auto &legs = route_object.values.at("legs").get<json::Array>().values;
+        BOOST_CHECK(!legs.empty());
+
+        for (const auto &leg : legs)
+        {
+            const auto &leg_object = leg.get<json::Object>();
+
+            const auto distance = leg_object.values.at("distance").get<json::Number>().value;
+            BOOST_CHECK_EQUAL(distance, 0);
+
+            const auto duration = leg_object.values.at("duration").get<json::Number>().value;
+            BOOST_CHECK_EQUAL(duration, 0);
+
+            // nothing can be said about summary, empty or contains human readable summary
+            const auto summary = leg_object.values.at("summary").get<json::String>().value;
+            BOOST_CHECK(((void)summary, true));
+
+            // steps=true by default
+            const auto &steps = leg_object.values.at("steps").get<json::Array>().values;
+            BOOST_CHECK(!steps.empty());
+
+            for (const auto &step : steps)
+            {
+                const auto &step_object = step.get<json::Object>();
+
+                const auto distance = step_object.values.at("distance").get<json::Number>().value;
+                BOOST_CHECK_EQUAL(distance, 0);
+
+                const auto duration = step_object.values.at("duration").get<json::Number>().value;
+                BOOST_CHECK_EQUAL(duration, 0);
+
+                // geometries=polyline by default
+                const auto geometry = step_object.values.at("geometry").get<json::String>().value;
+                BOOST_CHECK(!geometry.empty());
+
+                // nothing can be said about name, empty or contains way name
+                const auto name = step_object.values.at("name").get<json::String>().value;
+                BOOST_CHECK(((void)name, true));
+
+                // nothing can be said about mode, contains mode of transportation
+                const auto mode = step_object.values.at("mode").get<json::String>().value;
+                BOOST_CHECK(!name.empty());
+
+                const auto &maneuver = step_object.values.at("maneuver").get<json::Object>().values;
+
+                const auto location = maneuver.at("location").get<json::Array>().values;
+                const auto longitude = location[0].get<json::Number>().value;
+                const auto latitude = location[1].get<json::Number>().value;
+                BOOST_CHECK(longitude >= -180. && longitude <= 180.);
+                BOOST_CHECK(latitude >= -90. && latitude <= 90.);
+
+                const auto bearing_before = maneuver.at("bearing_before").get<json::Number>().value;
+                const auto bearing_after = maneuver.at("bearing_after").get<json::Number>().value;
+                BOOST_CHECK(bearing_before >= 0. && bearing_before <= 360.);
+                BOOST_CHECK(bearing_after >= 0. && bearing_after <= 360.);
+
+                const auto type = maneuver.at("type").get<json::String>().value;
+                BOOST_CHECK(!type.empty());
+
+                // modifier is optional
+                // TODO(daniel-j-h):
+
+                // exit is optional
+                // TODO(daniel-j-h):
+            }
+        }
+    }
+}
+
+BOOST_AUTO_TEST_CASE(test_route_response_for_locations_in_small_component)
+{
+    const auto args = get_args();
+    auto osrm = getOSRM(args.at(0));
+
+    using namespace osrm;
+
+    const auto locations = get_locations_in_small_component();
+
+    RouteParameters params;
+    params.coordinates.push_back(locations.at(0));
+    params.coordinates.push_back(locations.at(1));
+    params.coordinates.push_back(locations.at(2));
+
+    json::Object result;
+    const auto rc = osrm.Route(params, result);
+    BOOST_CHECK(rc == Status::Ok);
+
+    const auto code = result.values.at("code").get<json::String>().value;
+    BOOST_CHECK_EQUAL(code, "ok");
+
+    const auto &waypoints = result.values.at("waypoints").get<json::Array>().values;
+    BOOST_CHECK_EQUAL(waypoints.size(), params.coordinates.size());
+
+    for (const auto &waypoint : waypoints)
+    {
+        const auto &waypoint_object = waypoint.get<json::Object>();
+
+        const auto location = waypoint_object.values.at("location").get<json::Array>().values;
+        const auto longitude = location[0].get<json::Number>().value;
+        const auto latitude = location[1].get<json::Number>().value;
+        BOOST_CHECK(longitude >= -180. && longitude <= 180.);
+        BOOST_CHECK(latitude >= -90. && latitude <= 90.);
+
+        // TODO(daniel-j-h): we could do a Nearest request for each waypoint, verifying
+        // that we did indeed not snap to the input locations inside the small component.
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/library/table.cpp b/unit_tests/library/table.cpp
new file mode 100644
index 0000000..bab5312
--- /dev/null
+++ b/unit_tests/library/table.cpp
@@ -0,0 +1,37 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include "args.hpp"
+#include "fixture.hpp"
+
+#include "osrm/table_parameters.hpp"
+
+#include "osrm/coordinate.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/json_container.hpp"
+#include "osrm/status.hpp"
+#include "osrm/osrm.hpp"
+
+BOOST_AUTO_TEST_SUITE(table)
+
+BOOST_AUTO_TEST_CASE(test_table)
+{
+    const auto args = get_args();
+    BOOST_REQUIRE_EQUAL(args.size(), 1);
+
+    using namespace osrm;
+
+    auto osrm = getOSRM(args[0]);
+
+    /*
+    TableParameters params;
+
+    json::Object result;
+
+    const auto rc = osrm.Table(params, result);
+
+    BOOST_CHECK(rc == Status::Ok || rc == Status::Error);
+    */
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/library/tile.cpp b/unit_tests/library/tile.cpp
new file mode 100644
index 0000000..2ca674b
--- /dev/null
+++ b/unit_tests/library/tile.cpp
@@ -0,0 +1,31 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include "args.hpp"
+#include "fixture.hpp"
+
+#include "osrm/tile_parameters.hpp"
+
+#include "osrm/coordinate.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/json_container.hpp"
+#include "osrm/status.hpp"
+#include "osrm/osrm.hpp"
+
+BOOST_AUTO_TEST_SUITE(tile)
+
+BOOST_AUTO_TEST_CASE(test_tile)
+{
+    const auto args = get_args();
+    auto osrm = getOSRM(args.at(0));
+
+    using namespace osrm;
+
+    TileParameters params{0, 0, 1};
+
+    std::string result;
+    const auto rc = osrm.Tile(params, result);
+    BOOST_CHECK(rc == Status::Ok);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/library/trip.cpp b/unit_tests/library/trip.cpp
new file mode 100644
index 0000000..7bfd1c2
--- /dev/null
+++ b/unit_tests/library/trip.cpp
@@ -0,0 +1,37 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include "args.hpp"
+#include "fixture.hpp"
+
+#include "osrm/trip_parameters.hpp"
+
+#include "osrm/coordinate.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/json_container.hpp"
+#include "osrm/status.hpp"
+#include "osrm/osrm.hpp"
+
+BOOST_AUTO_TEST_SUITE(trip)
+
+BOOST_AUTO_TEST_CASE(test_trip)
+{
+    const auto args = get_args();
+    BOOST_REQUIRE_EQUAL(args.size(), 1);
+
+    using namespace osrm;
+
+    auto osrm = getOSRM(args[0]);
+
+    /*
+    TripParameters params;
+
+    json::Object result;
+
+    const auto rc = osrm.Trip(params, result);
+
+    BOOST_CHECK(rc == Status::Ok || rc == Status::Error);
+    */
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/library_tests.cpp b/unit_tests/library_tests.cpp
new file mode 100644
index 0000000..6f75356
--- /dev/null
+++ b/unit_tests/library_tests.cpp
@@ -0,0 +1,7 @@
+#define BOOST_TEST_MODULE library tests
+
+#include <boost/test/unit_test.hpp>
+
+/*
+ * This file will contain an automatically generated main function.
+ */
diff --git a/unit_tests/mocks/mock_datafacade.hpp b/unit_tests/mocks/mock_datafacade.hpp
new file mode 100644
index 0000000..cb05a94
--- /dev/null
+++ b/unit_tests/mocks/mock_datafacade.hpp
@@ -0,0 +1,178 @@
+#ifndef MOCK_DATAFACADE_HPP
+#define MOCK_DATAFACADE_HPP
+
+// implements all data storage when shared memory _IS_ used
+
+#include "extractor/guidance/turn_instruction.hpp"
+#include "engine/datafacade/datafacade_base.hpp"
+#include "contractor/query_edge.hpp"
+
+namespace osrm
+{
+namespace test
+{
+
+class MockDataFacade final : public engine::datafacade::BaseDataFacade
+{
+  private:
+    EdgeData foo;
+
+  public:
+    unsigned GetNumberOfNodes() const override { return 0; }
+    unsigned GetNumberOfEdges() const override { return 0; }
+    unsigned GetOutDegree(const NodeID /* n */) const override { return 0; }
+    NodeID GetTarget(const EdgeID /* e */) const override { return SPECIAL_NODEID; }
+    const EdgeData &GetEdgeData(const EdgeID /* e */) const override { return foo; }
+    EdgeID BeginEdges(const NodeID /* n */) const override { return SPECIAL_EDGEID; }
+    EdgeID EndEdges(const NodeID /* n */) const override { return SPECIAL_EDGEID; }
+    osrm::engine::datafacade::EdgeRange GetAdjacentEdgeRange(const NodeID /* node */) const override
+    {
+        return util::irange(static_cast<EdgeID>(0), static_cast<EdgeID>(0));
+    }
+    EdgeID FindEdge(const NodeID /* from */, const NodeID /* to */) const override
+    {
+        return SPECIAL_EDGEID;
+    }
+    EdgeID FindEdgeInEitherDirection(const NodeID /* from */, const NodeID /* to */) const override
+    {
+        return SPECIAL_EDGEID;
+    }
+    EdgeID FindEdgeIndicateIfReverse(const NodeID /* from */,
+                                     const NodeID /* to */,
+                                     bool & /* result */) const override
+    {
+        return SPECIAL_EDGEID;
+    }
+    util::Coordinate GetCoordinateOfNode(const unsigned /* id */) const override
+    {
+        return {util::FixedLongitude{0}, util::FixedLatitude{0}};
+    }
+    bool EdgeIsCompressed(const unsigned /* id */) const { return false; }
+    unsigned GetGeometryIndexForEdgeID(const unsigned /* id */) const override
+    {
+        return SPECIAL_NODEID;
+    }
+    void GetUncompressedGeometry(const EdgeID /* id */,
+                                 std::vector<NodeID> & /* result_nodes */) const override
+    {
+    }
+    void GetUncompressedWeights(const EdgeID /* id */,
+                                std::vector<EdgeWeight> & /* result_weights */) const override
+    {
+    }
+    void GetUncompressedDatasources(const EdgeID /*id*/,
+                                    std::vector<uint8_t> & /*data_sources*/) const override
+    {
+    }
+    std::string GetDatasourceName(const uint8_t /*datasource_name_id*/) const override
+    {
+        return "";
+    }
+    extractor::guidance::TurnInstruction
+    GetTurnInstructionForEdgeID(const unsigned /* id */) const override
+    {
+        return extractor::guidance::TurnInstruction::NO_TURN();
+    }
+    extractor::TravelMode GetTravelModeForEdgeID(const unsigned /* id */) const override
+    {
+        return TRAVEL_MODE_INACCESSIBLE;
+    }
+    std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate /* south_west */,
+                                         const util::Coordinate /*north_east */) override
+    {
+        return {};
+    }
+
+    std::vector<engine::PhantomNodeWithDistance>
+    NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
+                               const float /*max_distance*/,
+                               const int /*bearing*/,
+                               const int /*bearing_range*/) override
+    {
+        return {};
+    }
+
+    std::vector<engine::PhantomNodeWithDistance>
+    NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
+                               const float /*max_distance*/) override
+    {
+        return {};
+    }
+
+    std::vector<engine::PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
+                        const unsigned /*max_results*/,
+                        const double /*max_distance*/,
+                        const int /*bearing*/,
+                        const int /*bearing_range*/) override
+    {
+        return {};
+    }
+
+    std::vector<engine::PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
+                        const unsigned /*max_results*/,
+                        const int /*bearing*/,
+                        const int /*bearing_range*/) override
+    {
+        return {};
+    }
+
+    std::vector<engine::PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
+                        const unsigned /*max_results*/) override
+    {
+        return {};
+    }
+
+    std::vector<engine::PhantomNodeWithDistance>
+    NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
+                        const unsigned /*max_results*/,
+                        const double /*max_distance*/) override
+    {
+        return {};
+    }
+
+    std::pair<engine::PhantomNode, engine::PhantomNode>
+    NearestPhantomNodeWithAlternativeFromBigComponent(
+        const util::Coordinate /*input_coordinate*/) override
+    {
+        return {};
+    }
+
+    std::pair<engine::PhantomNode, engine::PhantomNode>
+    NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
+                                                      const double /*max_distance*/) override
+    {
+        return {};
+    }
+
+    std::pair<engine::PhantomNode, engine::PhantomNode>
+    NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
+                                                      const double /*max_distance*/,
+                                                      const int /*bearing*/,
+                                                      const int /*bearing_range*/) override
+    {
+        return {};
+    }
+
+    std::pair<engine::PhantomNode, engine::PhantomNode>
+    NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
+                                                      const int /*bearing*/,
+                                                      const int /*bearing_range*/) override
+    {
+        return {};
+    };
+
+    unsigned GetCheckSum() const override { return 0; }
+    bool IsCoreNode(const NodeID /* id */) const override { return false; }
+    unsigned GetNameIndexFromEdgeID(const unsigned /* id */) const override { return 0; }
+    std::string GetNameForID(const unsigned /* name_id */) const override { return ""; }
+    std::size_t GetCoreSize() const override { return 0; }
+    std::string GetTimestamp() const override { return ""; }
+    bool GetUTurnsDefault() const override { return true; }
+};
+} // ns test
+} // ns osrm
+
+#endif // MOCK_DATAFACADE_HPP
diff --git a/unit_tests/server/parameters_parser.cpp b/unit_tests/server/parameters_parser.cpp
new file mode 100644
index 0000000..e6f2d82
--- /dev/null
+++ b/unit_tests/server/parameters_parser.cpp
@@ -0,0 +1,330 @@
+#include "server/api/parameters_parser.hpp"
+
+#include "engine/api/base_parameters.hpp"
+#include "engine/api/route_parameters.hpp"
+#include "engine/api/table_parameters.hpp"
+#include "engine/api/match_parameters.hpp"
+#include "engine/api/trip_parameters.hpp"
+#include "engine/api/tile_parameters.hpp"
+#include "engine/api/nearest_parameters.hpp"
+
+#include <fstream>
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+std::ostream &operator<<(std::ostream &out, api::RouteParameters::GeometriesType geometries)
+{
+    switch (geometries)
+    {
+    case api::RouteParameters::GeometriesType::GeoJSON:
+        out << "GeoJSON";
+        break;
+    case api::RouteParameters::GeometriesType::Polyline:
+        out << "Polyline";
+        break;
+    default:
+        BOOST_ASSERT_MSG(false, "GeometriesType not fully captured");
+    }
+    return out;
+}
+std::ostream &operator<<(std::ostream &out, api::RouteParameters::OverviewType overview)
+{
+    switch (overview)
+    {
+    case api::RouteParameters::OverviewType::False:
+        out << "False";
+        break;
+    case api::RouteParameters::OverviewType::Full:
+        out << "Full";
+        break;
+    case api::RouteParameters::OverviewType::Simplified:
+        out << "Simplified";
+        break;
+    default:
+        BOOST_ASSERT_MSG(false, "OverviewType not fully captured");
+    }
+    return out;
+}
+}
+std::ostream &operator<<(std::ostream &out, Bearing bearing)
+{
+    out << bearing.bearing << "," << bearing.range;
+    return out;
+}
+}
+}
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+#include <boost/optional/optional_io.hpp>
+
+#define CHECK_EQUAL_RANGE(R1, R2)                                                                  \
+    BOOST_CHECK_EQUAL_COLLECTIONS(R1.begin(), R1.end(), R2.begin(), R2.end());
+
+BOOST_AUTO_TEST_SUITE(api_parameters_parser)
+
+using namespace osrm;
+using namespace osrm::server;
+
+// returns distance to front
+template <typename ParameterT> std::size_t testInvalidOptions(std::string options)
+{
+    auto iter = options.begin();
+    auto result = api::parseParameters<ParameterT>(iter, options.end());
+    BOOST_CHECK(!result);
+    return std::distance(options.begin(), iter);
+}
+
+BOOST_AUTO_TEST_CASE(invalid_route_urls)
+{
+    BOOST_CHECK_EQUAL(
+        testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&bla=foo"), 22UL);
+    BOOST_CHECK_EQUAL(
+        testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&bearings=foo"),
+        32UL);
+    BOOST_CHECK_EQUAL(
+        testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&uturns=foo"),
+        30UL);
+    BOOST_CHECK_EQUAL(
+        testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&radiuses=foo"),
+        32UL);
+    BOOST_CHECK_EQUAL(
+        testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&hints=foo"), 22UL);
+    BOOST_CHECK_EQUAL(
+        testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&geometries=foo"),
+        22UL);
+    BOOST_CHECK_EQUAL(
+        testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&overview=foo"),
+        22L);
+    BOOST_CHECK_EQUAL(
+        testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&alternatives=foo"),
+        22UL);
+}
+
+BOOST_AUTO_TEST_CASE(invalid_table_urls)
+{
+    BOOST_CHECK_EQUAL(testInvalidOptions<engine::api::TableParameters>("1,2;3,4?sources=1&bla=foo"),
+                      17UL);
+    BOOST_CHECK_EQUAL(
+        testInvalidOptions<engine::api::TableParameters>("1,2;3,4?destinations=1&bla=foo"), 22UL);
+    BOOST_CHECK_EQUAL(testInvalidOptions<engine::api::TableParameters>(
+                          "1,2;3,4?sources=1&destinations=1&bla=foo"),
+                      32UL);
+    BOOST_CHECK_EQUAL(testInvalidOptions<engine::api::TableParameters>("1,2;3,4?sources=foo"), 7UL);
+    BOOST_CHECK_EQUAL(testInvalidOptions<engine::api::TableParameters>("1,2;3,4?destinations=foo"),
+                      7UL);
+}
+
+BOOST_AUTO_TEST_CASE(valid_route_urls)
+{
+    std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude(1), util::FloatLatitude(2)},
+                                              {util::FloatLongitude(3), util::FloatLatitude(4)}};
+
+    engine::api::RouteParameters reference_1{};
+    reference_1.coordinates = coords_1;
+    auto result_1 = api::parseParameters<engine::api::RouteParameters>("1,2;3,4");
+    BOOST_CHECK(result_1);
+    BOOST_CHECK_EQUAL(reference_1.steps, result_1->steps);
+    BOOST_CHECK_EQUAL(reference_1.alternatives, result_1->alternatives);
+    BOOST_CHECK_EQUAL(reference_1.geometries, result_1->geometries);
+    BOOST_CHECK_EQUAL(reference_1.overview, result_1->overview);
+    BOOST_CHECK_EQUAL(reference_1.uturns, result_1->uturns);
+    CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
+    CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
+    CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
+
+    engine::api::RouteParameters reference_2{};
+    reference_2.coordinates = coords_1;
+    auto result_2 = api::parseParameters<engine::api::RouteParameters>(
+        "1,2;3,4?steps=true&alternatives=true&geometries=polyline&overview=simplified");
+    BOOST_CHECK(result_2);
+    BOOST_CHECK_EQUAL(reference_2.steps, result_2->steps);
+    BOOST_CHECK_EQUAL(reference_2.alternatives, result_2->alternatives);
+    BOOST_CHECK_EQUAL(reference_2.geometries, result_2->geometries);
+    BOOST_CHECK_EQUAL(reference_2.overview, result_2->overview);
+    BOOST_CHECK_EQUAL(reference_2.uturns, result_2->uturns);
+    CHECK_EQUAL_RANGE(reference_2.bearings, result_2->bearings);
+    CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
+    CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
+
+    engine::api::RouteParameters reference_3{false,
+                                             false,
+                                             engine::api::RouteParameters::GeometriesType::GeoJSON,
+                                             engine::api::RouteParameters::OverviewType::False,
+                                             true};
+    reference_3.coordinates = coords_1;
+    auto result_3 = api::parseParameters<engine::api::RouteParameters>(
+        "1,2;3,4?steps=false&alternatives=false&geometries=geojson&overview=false&uturns=true"
+        "false;");
+    BOOST_CHECK(result_3);
+    BOOST_CHECK_EQUAL(reference_3.steps, result_3->steps);
+    BOOST_CHECK_EQUAL(reference_3.alternatives, result_3->alternatives);
+    BOOST_CHECK_EQUAL(reference_3.geometries, result_3->geometries);
+    BOOST_CHECK_EQUAL(reference_3.overview, result_3->overview);
+    BOOST_CHECK_EQUAL(reference_3.uturns, result_3->uturns);
+    CHECK_EQUAL_RANGE(reference_3.bearings, result_3->bearings);
+    CHECK_EQUAL_RANGE(reference_3.radiuses, result_3->radiuses);
+    CHECK_EQUAL_RANGE(reference_3.coordinates, result_3->coordinates);
+
+    std::vector<boost::optional<engine::Hint>> hints_4 = {
+        engine::Hint::FromBase64(
+            "rVghAzxMzABMAwAA5h4CAKMIAAAQAAAAGAAAAAYAAAAAAAAAch8BAJ4AAACpWCED_0vMAAEAAQGLSzmR"),
+        engine::Hint::FromBase64(
+            "_4ghA4JuzAD_IAAAo28BAOYAAAAzAAAAAgAAAEwAAAAAAAAAdIwAAJ4AAAAXiSEDfm7MAAEAAQGLSzmR"),
+        engine::Hint::FromBase64(
+            "03AhA0vnzAA_SAAA_____3wEAAAYAAAAQAAAAB4AAABAAAAAoUYBAJ4AAADlcCEDSefMAAMAAQGLSzmR")};
+    engine::api::RouteParameters reference_4{false,
+                                             true,
+                                             engine::api::RouteParameters::GeometriesType::Polyline,
+                                             engine::api::RouteParameters::OverviewType::Simplified,
+                                             boost::optional<bool>{},
+                                             coords_1,
+                                             hints_4,
+                                             std::vector<boost::optional<double>>{},
+                                             std::vector<boost::optional<engine::Bearing>>{}};
+    auto result_4 = api::parseParameters<engine::api::RouteParameters>(
+        "1,2;3,4?steps=false&hints="
+        "rVghAzxMzABMAwAA5h4CAKMIAAAQAAAAGAAAAAYAAAAAAAAAch8BAJ4AAACpWCED_"
+        "0vMAAEAAQGLSzmR;_4ghA4JuzAD_"
+        "IAAAo28BAOYAAAAzAAAAAgAAAEwAAAAAAAAAdIwAAJ4AAAAXiSEDfm7MAAEAAQGLSzmR;03AhA0vnzAA_SAAA_____"
+        "3wEAAAYAAAAQAAAAB4AAABAAAAAoUYBAJ4AAADlcCEDSefMAAMAAQGLSzmR");
+    BOOST_CHECK(result_4);
+    BOOST_CHECK_EQUAL(reference_4.steps, result_4->steps);
+    BOOST_CHECK_EQUAL(reference_4.alternatives, result_4->alternatives);
+    BOOST_CHECK_EQUAL(reference_4.geometries, result_4->geometries);
+    BOOST_CHECK_EQUAL(reference_4.overview, result_4->overview);
+    BOOST_CHECK_EQUAL(reference_4.uturns, result_4->uturns);
+    CHECK_EQUAL_RANGE(reference_4.bearings, result_4->bearings);
+    CHECK_EQUAL_RANGE(reference_4.radiuses, result_4->radiuses);
+    CHECK_EQUAL_RANGE(reference_4.coordinates, result_4->coordinates);
+
+    std::vector<boost::optional<engine::Bearing>> bearings_4 = {
+        boost::none, engine::Bearing{200, 10}, engine::Bearing{100, 5},
+    };
+    engine::api::RouteParameters reference_5{false,
+                                             true,
+                                             engine::api::RouteParameters::GeometriesType::Polyline,
+                                             engine::api::RouteParameters::OverviewType::Simplified,
+                                             boost::optional<bool>{},
+                                             coords_1,
+                                             std::vector<boost::optional<engine::Hint>>{},
+                                             std::vector<boost::optional<double>>{},
+                                             bearings_4};
+    auto result_5 = api::parseParameters<engine::api::RouteParameters>(
+        "1,2;3,4?steps=false&bearings=;200,10;100,5");
+    BOOST_CHECK(result_5);
+    BOOST_CHECK_EQUAL(reference_5.steps, result_5->steps);
+    BOOST_CHECK_EQUAL(reference_5.alternatives, result_5->alternatives);
+    BOOST_CHECK_EQUAL(reference_5.geometries, result_5->geometries);
+    BOOST_CHECK_EQUAL(reference_5.overview, result_5->overview);
+    BOOST_CHECK_EQUAL(reference_5.uturns, result_5->uturns);
+    CHECK_EQUAL_RANGE(reference_5.bearings, result_5->bearings);
+    CHECK_EQUAL_RANGE(reference_5.radiuses, result_5->radiuses);
+    CHECK_EQUAL_RANGE(reference_5.coordinates, result_5->coordinates);
+
+    std::vector<util::Coordinate> coords_2 = {{util::FloatLongitude(0), util::FloatLatitude(1)},
+                                              {util::FloatLongitude(2), util::FloatLatitude(3)},
+                                              {util::FloatLongitude(4), util::FloatLatitude(5)}};
+
+    engine::api::RouteParameters reference_6{};
+    reference_6.coordinates = coords_2;
+    auto result_6 =
+        api::parseParameters<engine::api::RouteParameters>("polyline(_ibE?_seK_seK_seK_seK)");
+    BOOST_CHECK(result_6);
+    BOOST_CHECK_EQUAL(reference_6.steps, result_6->steps);
+    BOOST_CHECK_EQUAL(reference_6.alternatives, result_6->alternatives);
+    BOOST_CHECK_EQUAL(reference_6.geometries, result_6->geometries);
+    BOOST_CHECK_EQUAL(reference_6.overview, result_6->overview);
+    BOOST_CHECK_EQUAL(reference_6.uturns, result_6->uturns);
+    CHECK_EQUAL_RANGE(reference_6.bearings, result_6->bearings);
+    CHECK_EQUAL_RANGE(reference_6.radiuses, result_6->radiuses);
+    CHECK_EQUAL_RANGE(reference_6.coordinates, result_6->coordinates);
+}
+
+BOOST_AUTO_TEST_CASE(valid_table_urls)
+{
+    std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude(1), util::FloatLatitude(2)},
+                                              {util::FloatLongitude(3), util::FloatLatitude(4)}};
+
+    engine::api::TableParameters reference_1{};
+    reference_1.coordinates = coords_1;
+    auto result_1 = api::parseParameters<engine::api::TableParameters>("1,2;3,4");
+    BOOST_CHECK(result_1);
+    CHECK_EQUAL_RANGE(reference_1.sources, result_1->sources);
+    CHECK_EQUAL_RANGE(reference_1.destinations, result_1->destinations);
+    CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
+    CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
+    CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
+
+    std::vector<std::size_t> sources_2 = {1, 2, 3};
+    std::vector<std::size_t> destinations_2 = {4, 5};
+    engine::api::TableParameters reference_2{sources_2, destinations_2};
+    reference_2.coordinates = coords_1;
+    auto result_2 = api::parseParameters<engine::api::TableParameters>(
+        "1,2;3,4?sources=1;2;3&destinations=4;5");
+    BOOST_CHECK(result_2);
+    CHECK_EQUAL_RANGE(reference_2.sources, result_2->sources);
+    CHECK_EQUAL_RANGE(reference_2.destinations, result_2->destinations);
+    CHECK_EQUAL_RANGE(reference_2.bearings, result_2->bearings);
+    CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
+    CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
+}
+
+BOOST_AUTO_TEST_CASE(valid_match_urls)
+{
+    std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude(1), util::FloatLatitude(2)},
+                                              {util::FloatLongitude(3), util::FloatLatitude(4)}};
+
+    engine::api::MatchParameters reference_1{};
+    reference_1.coordinates = coords_1;
+    auto result_1 = api::parseParameters<engine::api::MatchParameters>("1,2;3,4");
+    BOOST_CHECK(result_1);
+    CHECK_EQUAL_RANGE(reference_1.timestamps, result_1->timestamps);
+    CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
+    CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
+    CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
+}
+
+BOOST_AUTO_TEST_CASE(valid_nearest_urls)
+{
+    std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude(1), util::FloatLatitude(2)}};
+
+    engine::api::NearestParameters reference_1{};
+    reference_1.coordinates = coords_1;
+    auto result_1 = api::parseParameters<engine::api::NearestParameters>("1,2");
+    BOOST_CHECK(result_1);
+    BOOST_CHECK_EQUAL(reference_1.number_of_results, result_1->number_of_results);
+    CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
+    CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
+    CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
+}
+
+BOOST_AUTO_TEST_CASE(valid_tile_urls)
+{
+    engine::api::TileParameters reference_1{1, 2, 3};
+    auto result_1 = api::parseParameters<engine::api::TileParameters>("tile(1,2,3).mvt");
+    BOOST_CHECK(result_1);
+    BOOST_CHECK_EQUAL(reference_1.x, result_1->x);
+    BOOST_CHECK_EQUAL(reference_1.y, result_1->y);
+    BOOST_CHECK_EQUAL(reference_1.z, result_1->z);
+}
+
+BOOST_AUTO_TEST_CASE(valid_trip_urls)
+{
+    std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude(1), util::FloatLatitude(2)},
+                                              {util::FloatLongitude(3), util::FloatLatitude(4)}};
+
+    engine::api::TripParameters reference_1{};
+    reference_1.coordinates = coords_1;
+    auto result_1 = api::parseParameters<engine::api::TripParameters>("1,2;3,4");
+    BOOST_CHECK(result_1);
+    CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
+    CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
+    CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/server/url_parser.cpp b/unit_tests/server/url_parser.cpp
new file mode 100644
index 0000000..1405674
--- /dev/null
+++ b/unit_tests/server/url_parser.cpp
@@ -0,0 +1,102 @@
+#include "server/api/url_parser.hpp"
+
+#include <fstream>
+
+// needed for BOOST_CHECK_EQUAL
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+std::ostream &operator<<(std::ostream &out, const osrm::server::api::ParsedURL &url)
+{
+    out << url.service << ", " << url.version << ", " << url.profile << ", " << url.query;
+
+    return out;
+}
+}
+}
+}
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+
+#define CHECK_EQUAL_RANGE(R1, R2)                                                                  \
+    BOOST_CHECK_EQUAL_COLLECTIONS(R1.begin(), R1.end(), R2.begin(), R2.end());
+
+BOOST_AUTO_TEST_SUITE(api_url_parser)
+
+using namespace osrm;
+using namespace osrm::server;
+
+// returns distance to front
+std::size_t testInvalidURL(std::string url)
+{
+    auto iter = url.begin();
+    auto result = api::parseURL(iter, url.end());
+    BOOST_CHECK(!result);
+    return std::distance(url.begin(), iter);
+}
+
+BOOST_AUTO_TEST_CASE(invalid_urls)
+{
+    BOOST_CHECK_EQUAL(testInvalidURL("/route/"), 0UL);
+    BOOST_CHECK_EQUAL(testInvalidURL("/route/bla"), 0UL);
+    BOOST_CHECK_EQUAL(testInvalidURL("/route/1/1,2;3;4"), 0UL);
+    BOOST_CHECK_EQUAL(testInvalidURL("/route/v1/pro_file/1,2;3,4"), 0UL);
+    BOOST_CHECK_EQUAL(testInvalidURL("/route/v1/profile"), 0UL);
+    BOOST_CHECK_EQUAL(testInvalidURL("/route/v1/profile/"), 0UL);
+}
+
+BOOST_AUTO_TEST_CASE(valid_urls)
+{
+    api::ParsedURL reference_1{"route", 1, "profile", "0,1;2,3;4,5?options=value&foo=bar"};
+    auto result_1 = api::parseURL("/route/v1/profile/0,1;2,3;4,5?options=value&foo=bar");
+    BOOST_CHECK(result_1);
+    BOOST_CHECK_EQUAL(reference_1.service, result_1->service);
+    BOOST_CHECK_EQUAL(reference_1.version, result_1->version);
+    BOOST_CHECK_EQUAL(reference_1.profile, result_1->profile);
+    CHECK_EQUAL_RANGE(reference_1.query, result_1->query);
+
+    // no options
+    api::ParsedURL reference_2{"route", 1, "profile", "0,1;2,3;4,5"};
+    auto result_2 = api::parseURL("/route/v1/profile/0,1;2,3;4,5");
+    BOOST_CHECK(result_2);
+    BOOST_CHECK_EQUAL(reference_2.service, result_2->service);
+    BOOST_CHECK_EQUAL(reference_2.version, result_2->version);
+    BOOST_CHECK_EQUAL(reference_2.profile, result_2->profile);
+    CHECK_EQUAL_RANGE(reference_2.query, result_2->query);
+
+    // one coordinate
+    std::vector<util::Coordinate> coords_3 = {
+        util::Coordinate(util::FloatLongitude(0), util::FloatLatitude(1)),
+    };
+    api::ParsedURL reference_3{"route", 1, "profile", "0,1"};
+    auto result_3 = api::parseURL("/route/v1/profile/0,1");
+    BOOST_CHECK(result_3);
+    BOOST_CHECK_EQUAL(reference_3.service, result_3->service);
+    BOOST_CHECK_EQUAL(reference_3.version, result_3->version);
+    BOOST_CHECK_EQUAL(reference_3.profile, result_3->profile);
+    CHECK_EQUAL_RANGE(reference_3.query, result_3->query);
+
+    // polyline
+    api::ParsedURL reference_5{"route", 1, "profile", "polyline(_ibE?_seK_seK_seK_seK)?"};
+    auto result_5 = api::parseURL("/route/v1/profile/polyline(_ibE?_seK_seK_seK_seK)?");
+    BOOST_CHECK(result_5);
+    BOOST_CHECK_EQUAL(reference_5.service, result_5->service);
+    BOOST_CHECK_EQUAL(reference_5.version, result_5->version);
+    BOOST_CHECK_EQUAL(reference_5.profile, result_5->profile);
+    CHECK_EQUAL_RANGE(reference_5.query, result_5->query);
+
+    // tile
+    api::ParsedURL reference_6{"route", 1, "profile", "tile(1,2,3).mvt"};
+    auto result_6 = api::parseURL("/route/v1/profile/tile(1,2,3).mvt");
+    BOOST_CHECK(result_5);
+    BOOST_CHECK_EQUAL(reference_6.service, result_6->service);
+    BOOST_CHECK_EQUAL(reference_6.version, result_6->version);
+    BOOST_CHECK_EQUAL(reference_6.profile, result_6->profile);
+    CHECK_EQUAL_RANGE(reference_6.query, result_6->query);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/server_tests.cpp b/unit_tests/server_tests.cpp
new file mode 100644
index 0000000..c1edf06
--- /dev/null
+++ b/unit_tests/server_tests.cpp
@@ -0,0 +1,7 @@
+#define BOOST_TEST_MODULE server tests
+
+#include <boost/test/unit_test.hpp>
+
+/*
+ * This file will contain an automatically generated main function.
+ */
diff --git a/unit_tests/util/bearing.cpp b/unit_tests/util/bearing.cpp
index f0866de..77e2ede 100644
--- a/unit_tests/util/bearing.cpp
+++ b/unit_tests/util/bearing.cpp
@@ -1,38 +1,14 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "../../util/bearing.hpp"
-#include "../../typedefs.h"
+#include "util/bearing.hpp"
+#include "util/typedefs.hpp"
 
 #include <boost/functional/hash.hpp>
 #include <boost/test/unit_test.hpp>
 #include <boost/test/test_case_template.hpp>
 
-BOOST_AUTO_TEST_SUITE(bearing)
+BOOST_AUTO_TEST_SUITE(bearing_test)
+
+using namespace osrm;
+using namespace osrm::util;
 
 // Verify that the bearing-bounds checking function behaves as expected
 BOOST_AUTO_TEST_CASE(bearing_range_test)
@@ -56,7 +32,6 @@ BOOST_AUTO_TEST_CASE(bearing_range_test)
     BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(354, 5, 10));
     BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(16, 5, 10));
 
-
     // Checking other cases of wraparound
     BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(359, -5, 10));
     BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(344, -5, 10));
diff --git a/unit_tests/data_structures/binary_heap.cpp b/unit_tests/util/binary_heap.cpp
similarity index 74%
rename from unit_tests/data_structures/binary_heap.cpp
rename to unit_tests/util/binary_heap.cpp
index ee22a1f..44aef13 100644
--- a/unit_tests/data_structures/binary_heap.cpp
+++ b/unit_tests/util/binary_heap.cpp
@@ -1,32 +1,5 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 "util/binary_heap.hpp"
+#include "util/typedefs.hpp"
 
 #include <boost/test/unit_test.hpp>
 #include <boost/test/test_case_template.hpp>
@@ -39,6 +12,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 BOOST_AUTO_TEST_SUITE(binary_heap)
 
+using namespace osrm;
+using namespace osrm::util;
+
 struct TestData
 {
     unsigned value;
diff --git a/unit_tests/util/coordinate_calculation.cpp b/unit_tests/util/coordinate_calculation.cpp
new file mode 100644
index 0000000..d159441
--- /dev/null
+++ b/unit_tests/util/coordinate_calculation.cpp
@@ -0,0 +1,191 @@
+#include <boost/test/unit_test.hpp>
+
+#include "util/coordinate_calculation.hpp"
+
+#include <osrm/coordinate.hpp>
+
+#include <cmath>
+
+using namespace osrm;
+using namespace osrm::util;
+
+BOOST_AUTO_TEST_SUITE(coordinate_calculation_tests)
+
+// Regression test for bug captured in #1347
+BOOST_AUTO_TEST_CASE(regression_test_1347)
+{
+    Coordinate u(FloatLongitude(-100), FloatLatitude(10));
+    Coordinate v(FloatLongitude(-100.002), FloatLatitude(10.001));
+    Coordinate q(FloatLongitude(-100.001), FloatLatitude(10.002));
+
+    double d1 = coordinate_calculation::perpendicularDistance(u, v, q);
+
+    double ratio;
+    Coordinate nearest_location;
+    double d2 = coordinate_calculation::perpendicularDistance(u, v, q, nearest_location, ratio);
+
+    BOOST_CHECK_LE(std::abs(d1 - d2), 0.01);
+}
+
+BOOST_AUTO_TEST_CASE(lon_to_pixel)
+{
+    using namespace coordinate_calculation;
+    BOOST_CHECK_CLOSE(7.416042 * mercator::DEGREE_TO_PX, 825550.019142, 0.1);
+    BOOST_CHECK_CLOSE(7.415892 * mercator::DEGREE_TO_PX, 825533.321218, 0.1);
+    BOOST_CHECK_CLOSE(7.416016 * mercator::DEGREE_TO_PX, 825547.124835, 0.1);
+    BOOST_CHECK_CLOSE(7.41577 * mercator::DEGREE_TO_PX, 825519.74024, 0.1);
+    BOOST_CHECK_CLOSE(7.415808 * mercator::DEGREE_TO_PX, 825523.970381, 0.1);
+}
+
+BOOST_AUTO_TEST_CASE(lat_to_pixel)
+{
+    using namespace coordinate_calculation;
+    BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733947)) * mercator::DEGREE_TO_PX,
+                      5424361.75863, 0.1);
+    BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733799)) * mercator::DEGREE_TO_PX,
+                      5424338.95731, 0.1);
+    BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733922)) * mercator::DEGREE_TO_PX,
+                      5424357.90705, 0.1);
+    BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733697)) * mercator::DEGREE_TO_PX,
+                      5424323.24293, 0.1);
+    BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733729)) * mercator::DEGREE_TO_PX,
+                      5424328.17293, 0.1);
+}
+
+BOOST_AUTO_TEST_CASE(xyz_to_wgs84)
+{
+    using namespace coordinate_calculation;
+
+    double minx_1;
+    double miny_1;
+    double maxx_1;
+    double maxy_1;
+    mercator::xyzToWGS84(2, 2, 1, minx_1, miny_1, maxx_1, maxy_1);
+    BOOST_CHECK_CLOSE(minx_1, 180, 0.0001);
+    BOOST_CHECK_CLOSE(miny_1, -85.0511, 0.0001);
+    BOOST_CHECK_CLOSE(maxx_1, 360, 0.0001);
+    BOOST_CHECK_CLOSE(maxy_1, -85.0511, 0.0001);
+
+    double minx_2;
+    double miny_2;
+    double maxx_2;
+    double maxy_2;
+    mercator::xyzToWGS84(100, 0, 13, minx_2, miny_2, maxx_2, maxy_2);
+    BOOST_CHECK_CLOSE(minx_2, -175.6054, 0.0001);
+    BOOST_CHECK_CLOSE(miny_2, 85.0473, 0.0001);
+    BOOST_CHECK_CLOSE(maxx_2, -175.5615, 0.0001);
+    BOOST_CHECK_CLOSE(maxy_2, 85.0511, 0.0001);
+}
+
+BOOST_AUTO_TEST_CASE(xyz_to_mercator)
+{
+    using namespace coordinate_calculation;
+
+    double minx;
+    double miny;
+    double maxx;
+    double maxy;
+    mercator::xyzToMercator(100, 0, 13, minx, miny, maxx, maxy);
+
+    BOOST_CHECK_CLOSE(minx, -19548311.361764118075, 0.0001);
+    BOOST_CHECK_CLOSE(miny, 20032616.372979003936, 0.0001);
+    BOOST_CHECK_CLOSE(maxx, -19543419.391953866929, 0.0001);
+    BOOST_CHECK_CLOSE(maxy, 20037508.342789277434, 0.0001);
+}
+
+BOOST_AUTO_TEST_CASE(regression_point_on_segment)
+{
+    //  ^
+    //  |               t
+    //  |
+    //  |                 i
+    //  |
+    //  |---|---|---|---|---|---|---|--->
+    //  |
+    //  |
+    //  |
+    //  |
+    //  |
+    //  |
+    //  |
+    //  |
+    //  |                           s
+    FloatCoordinate input{FloatLongitude{55.995715}, FloatLatitude{48.332711}};
+    FloatCoordinate start{FloatLongitude{74.140427}, FloatLatitude{-180}};
+    FloatCoordinate target{FloatLongitude{53.041084}, FloatLatitude{77.21011}};
+
+    FloatCoordinate nearest;
+    double ratio;
+    std::tie(ratio, nearest) = coordinate_calculation::projectPointOnSegment(start, target, input);
+
+    FloatCoordinate diff{target.lon - start.lon, target.lat - start.lat};
+
+    BOOST_CHECK_CLOSE(static_cast<double>(start.lon + FloatLongitude(ratio) * diff.lon), static_cast<double>(nearest.lon), 0.1);
+    BOOST_CHECK_CLOSE(static_cast<double>(start.lat + FloatLatitude(ratio) * diff.lat), static_cast<double>(nearest.lat), 0.1);
+}
+
+BOOST_AUTO_TEST_CASE(point_on_segment)
+{
+    //  t
+    //  |
+    //  |---- i
+    //  |
+    //  s
+    auto result_1 = coordinate_calculation::projectPointOnSegment(
+        {FloatLongitude{0}, FloatLatitude{0}}, {FloatLongitude{0}, FloatLatitude{2}},
+        {FloatLongitude{2}, FloatLatitude{1}});
+    auto reference_ratio_1 = 0.5;
+    auto reference_point_1 = FloatCoordinate{FloatLongitude{0}, FloatLatitude{1}};
+    BOOST_CHECK_EQUAL(result_1.first, reference_ratio_1);
+    BOOST_CHECK_EQUAL(result_1.second.lon, reference_point_1.lon);
+    BOOST_CHECK_EQUAL(result_1.second.lat, reference_point_1.lat);
+
+    //  i
+    //  :
+    //  t
+    //  |
+    //  |
+    //  |
+    //  s
+    auto result_2 = coordinate_calculation::projectPointOnSegment(
+        {FloatLongitude{0.}, FloatLatitude{0.}}, {FloatLongitude{0}, FloatLatitude{2}},
+        {FloatLongitude{0}, FloatLatitude{3}});
+    auto reference_ratio_2 = 1.;
+    auto reference_point_2 = FloatCoordinate{FloatLongitude{0}, FloatLatitude{2}};
+    BOOST_CHECK_EQUAL(result_2.first, reference_ratio_2);
+    BOOST_CHECK_EQUAL(result_2.second.lon, reference_point_2.lon);
+    BOOST_CHECK_EQUAL(result_2.second.lat, reference_point_2.lat);
+
+    //  t
+    //  |
+    //  |
+    //  |
+    //  s
+    //  :
+    //  i
+    auto result_3 = coordinate_calculation::projectPointOnSegment(
+        {FloatLongitude{0.}, FloatLatitude{0.}}, {FloatLongitude{0}, FloatLatitude{2}},
+        {FloatLongitude{0}, FloatLatitude{-1}});
+    auto reference_ratio_3 = 0.;
+    auto reference_point_3 = FloatCoordinate{FloatLongitude{0}, FloatLatitude{0}};
+    BOOST_CHECK_EQUAL(result_3.first, reference_ratio_3);
+    BOOST_CHECK_EQUAL(result_3.second.lon, reference_point_3.lon);
+    BOOST_CHECK_EQUAL(result_3.second.lat, reference_point_3.lat);
+
+    //     t
+    //    /
+    //   /.
+    //  /  i
+    // s
+    //
+    auto result_4 = coordinate_calculation::projectPointOnSegment(
+        {FloatLongitude{0}, FloatLatitude{0}}, {FloatLongitude{1}, FloatLatitude{1}},
+        {FloatLongitude{0.5 + 0.1}, FloatLatitude{0.5 - 0.1}});
+    auto reference_ratio_4 = 0.5;
+    auto reference_point_4 = FloatCoordinate{FloatLongitude{0.5}, FloatLatitude{0.5}};
+    BOOST_CHECK_EQUAL(result_4.first, reference_ratio_4);
+    BOOST_CHECK_EQUAL(result_4.second.lon, reference_point_4.lon);
+    BOOST_CHECK_EQUAL(result_4.second.lat, reference_point_4.lat);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/util/duration_parsing.cpp b/unit_tests/util/duration_parsing.cpp
new file mode 100644
index 0000000..72a5b63
--- /dev/null
+++ b/unit_tests/util/duration_parsing.cpp
@@ -0,0 +1,40 @@
+#include "extractor/extraction_helper_functions.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+BOOST_AUTO_TEST_SUITE(durations_are_valid)
+
+using namespace osrm;
+using namespace osrm::util;
+
+BOOST_AUTO_TEST_CASE(all_necessary_test)
+{
+    BOOST_CHECK_EQUAL(extractor::durationIsValid("00:01"), true);
+    BOOST_CHECK_EQUAL(extractor::durationIsValid("00:01:01"), true);
+    BOOST_CHECK_EQUAL(extractor::durationIsValid("PT15M"), true);
+}
+
+BOOST_AUTO_TEST_CASE(common_durations_get_translated)
+{
+    BOOST_CHECK_EQUAL(extractor::parseDuration("00:01"), 60);
+    BOOST_CHECK_EQUAL(extractor::parseDuration("00:01:01"), 61);
+    BOOST_CHECK_EQUAL(extractor::parseDuration("01:01"), 3660);
+
+    // check all combinations of iso duration tokens
+    BOOST_CHECK_EQUAL(extractor::parseDuration("PT1M1S"), 61);
+    BOOST_CHECK_EQUAL(extractor::parseDuration("PT1H1S"), 3601);
+    BOOST_CHECK_EQUAL(extractor::parseDuration("PT15M"), 900);
+    BOOST_CHECK_EQUAL(extractor::parseDuration("PT15S"), 15);
+    BOOST_CHECK_EQUAL(extractor::parseDuration("PT15H"), 54000);
+    BOOST_CHECK_EQUAL(extractor::parseDuration("PT1H15M"), 4500);
+    BOOST_CHECK_EQUAL(extractor::parseDuration("PT1H15M1S"), 4501);
+}
+
+BOOST_AUTO_TEST_CASE(iso_8601_durations_case_insensitive)
+{
+    BOOST_CHECK_EQUAL(extractor::parseDuration("PT15m"), 900);
+    BOOST_CHECK_EQUAL(extractor::parseDuration("PT1h15m"), 4500);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/util/dynamic_graph.cpp b/unit_tests/util/dynamic_graph.cpp
new file mode 100644
index 0000000..263b60c
--- /dev/null
+++ b/unit_tests/util/dynamic_graph.cpp
@@ -0,0 +1,66 @@
+#include "util/dynamic_graph.hpp"
+#include "util/typedefs.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include <vector>
+
+BOOST_AUTO_TEST_SUITE(dynamic_graph)
+
+using namespace osrm;
+using namespace osrm::util;
+
+struct TestData
+{
+    EdgeID id;
+};
+
+typedef DynamicGraph<TestData> TestDynamicGraph;
+typedef TestDynamicGraph::InputEdge TestInputEdge;
+
+BOOST_AUTO_TEST_CASE(find_test)
+{
+    /*
+     *  (0) -1-> (1)
+     *  ^ ^
+     *  2 5
+     *  | |
+     *  (3) -3-> (4)
+     *      <-4-
+     */
+    std::vector<TestInputEdge> input_edges = {
+        TestInputEdge{0, 1, TestData{1}}, TestInputEdge{3, 0, TestData{2}},
+        TestInputEdge{3, 0, TestData{5}}, TestInputEdge{3, 4, TestData{3}},
+        TestInputEdge{4, 3, TestData{4}}};
+    TestDynamicGraph simple_graph(5, input_edges);
+
+    auto eit = simple_graph.FindEdge(0, 1);
+    BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 1);
+
+    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, 1);
+
+    bool reverse = false;
+    eit = simple_graph.FindEdgeIndicateIfReverse(1, 0, reverse);
+    BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 1);
+    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, 3);
+    eit = simple_graph.FindEdgeInEitherDirection(3, 4);
+    BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 3);
+
+    eit = simple_graph.FindEdge(3, 0);
+    BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 2);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/util/io.cpp b/unit_tests/util/io.cpp
new file mode 100644
index 0000000..e37fa13
--- /dev/null
+++ b/unit_tests/util/io.cpp
@@ -0,0 +1,42 @@
+#include "util/io.hpp"
+#include "util/typedefs.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include <string>
+
+const static std::string IO_TMP_FILE = "test_io.tmp";
+
+BOOST_AUTO_TEST_SUITE(osrm_io)
+
+BOOST_AUTO_TEST_CASE(io_flags)
+{
+    std::vector<bool> flags_in, flags_out;
+    flags_in.resize(53);
+    for (std::size_t i = 0; i < flags_in.size(); ++i)
+        flags_in[i] = ((i % 2) == 1);
+
+    osrm::util::serializeFlags(IO_TMP_FILE, flags_in);
+    osrm::util::deserializeFlags(IO_TMP_FILE, flags_out);
+
+    BOOST_REQUIRE_EQUAL(flags_in.size(), flags_out.size());
+    BOOST_CHECK_EQUAL_COLLECTIONS(flags_out.begin(), flags_out.end(), flags_in.begin(),
+                                  flags_in.end());
+}
+
+BOOST_AUTO_TEST_CASE(io_data)
+{
+    std::vector<int> data_in, data_out;
+    data_in.resize(53);
+    for (std::size_t i = 0; i < data_in.size(); ++i)
+        data_in[i] = i;
+
+    osrm::util::serializeVector(IO_TMP_FILE, data_in);
+    osrm::util::deserializeVector(IO_TMP_FILE, data_out);
+
+    BOOST_REQUIRE_EQUAL(data_in.size(), data_out.size());
+    BOOST_CHECK_EQUAL_COLLECTIONS(data_out.begin(), data_out.end(), data_in.begin(), data_in.end());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/data_structures/range_table.cpp b/unit_tests/util/range_table.cpp
similarity index 72%
rename from unit_tests/data_structures/range_table.cpp
rename to unit_tests/util/range_table.cpp
index 065840b..a5db4c5 100644
--- a/unit_tests/data_structures/range_table.cpp
+++ b/unit_tests/util/range_table.cpp
@@ -1,32 +1,5 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 "util/range_table.hpp"
+#include "util/typedefs.hpp"
 
 #include <boost/test/unit_test.hpp>
 #include <boost/test/test_case_template.hpp>
@@ -34,11 +7,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <numeric>
 #include <stxxl/vector>
 
+BOOST_AUTO_TEST_SUITE(range_table)
+
+using namespace osrm;
+using namespace osrm::util;
+
 constexpr unsigned BLOCK_SIZE = 16;
 typedef RangeTable<BLOCK_SIZE, false> TestRangeTable;
 
-BOOST_AUTO_TEST_SUITE(range_table)
-
 void ConstructionTest(stxxl::vector<unsigned> lengths, std::vector<unsigned> offsets)
 {
     BOOST_ASSERT(lengths.size() == offsets.size() - 1);
diff --git a/unit_tests/util/rectangle.cpp b/unit_tests/util/rectangle.cpp
new file mode 100644
index 0000000..f85d073
--- /dev/null
+++ b/unit_tests/util/rectangle.cpp
@@ -0,0 +1,107 @@
+#include "util/rectangle.hpp"
+#include "util/typedefs.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+BOOST_AUTO_TEST_SUITE(rectangle_test)
+
+using namespace osrm;
+using namespace osrm::util;
+
+// Verify that the bearing-bounds checking function behaves as expected
+BOOST_AUTO_TEST_CASE(get_min_dist_test)
+{
+    //           ^
+    //           |
+    //           +- 80
+    //           |
+    //           |
+    //           +- 10
+    //           |
+    //--|-----|--+--|-----|-->
+    // -100  -10 |  10    100
+    //           +- -10
+    //           |
+    //           |
+    //           +- -80
+    //           |
+    RectangleInt2D ne{FloatLongitude(10), FloatLongitude(100), FloatLatitude(10),
+                      FloatLatitude(80)};
+    RectangleInt2D nw{FloatLongitude(-100), FloatLongitude(-10), FloatLatitude(10),
+                      FloatLatitude(80)};
+    RectangleInt2D se{FloatLongitude(10), FloatLongitude(100), FloatLatitude(-80),
+                      FloatLatitude(-10)};
+    RectangleInt2D sw{FloatLongitude(-100), FloatLongitude(-10), FloatLatitude(-80),
+                      FloatLatitude(-10)};
+
+    Coordinate nw_sw{FloatLongitude(-100.1), FloatLatitude(9.9)};
+    Coordinate nw_se{FloatLongitude(-9.9), FloatLatitude(9.9)};
+    Coordinate nw_ne{FloatLongitude(-9.9), FloatLatitude(80.1)};
+    Coordinate nw_nw{FloatLongitude(-100.1), FloatLatitude(80.1)};
+    Coordinate nw_s{FloatLongitude(-55), FloatLatitude(9.9)};
+    Coordinate nw_e{FloatLongitude(-9.9), FloatLatitude(45.0)};
+    Coordinate nw_w{FloatLongitude(-100.1), FloatLatitude(45.0)};
+    Coordinate nw_n{FloatLongitude(-55), FloatLatitude(80.1)};
+    BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_sw), 0.02, 0.1);
+    BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_se), 0.02, 0.1);
+    BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_ne), 0.02, 0.1);
+    BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_nw), 0.02, 0.1);
+    BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_s),  0.01, 0.1);
+    BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_e),  0.01, 0.1);
+    BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_w),  0.01, 0.1);
+    BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_n),  0.01, 0.1);
+
+    Coordinate ne_sw{FloatLongitude(9.9), FloatLatitude(9.9)};
+    Coordinate ne_se{FloatLongitude(100.1), FloatLatitude(9.9)};
+    Coordinate ne_ne{FloatLongitude(100.1), FloatLatitude(80.1)};
+    Coordinate ne_nw{FloatLongitude(9.9), FloatLatitude(80.1)};
+    Coordinate ne_s{FloatLongitude(55), FloatLatitude(9.9)};
+    Coordinate ne_e{FloatLongitude(100.1), FloatLatitude(45.0)};
+    Coordinate ne_w{FloatLongitude(9.9), FloatLatitude(45.0)};
+    Coordinate ne_n{FloatLongitude(55), FloatLatitude(80.1)};
+    BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_sw), 0.02, 0.1);
+    BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_se), 0.02, 0.1);
+    BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_ne), 0.02, 0.1);
+    BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_nw), 0.02, 0.1);
+    BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_s),  0.01, 0.1);
+    BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_e),  0.01, 0.1);
+    BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_w),  0.01, 0.1);
+    BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_n),  0.01, 0.1);
+
+    Coordinate se_ne{FloatLongitude(100.1), FloatLatitude(-9.9)};
+    Coordinate se_nw{FloatLongitude(9.9), FloatLatitude(-9.9)};
+    Coordinate se_sw{FloatLongitude(9.9), FloatLatitude(-80.1)};
+    Coordinate se_se{FloatLongitude(100.1), FloatLatitude(-80.1)};
+    Coordinate se_n{FloatLongitude(55), FloatLatitude(-9.9)};
+    Coordinate se_w{FloatLongitude(9.9), FloatLatitude(-45.0)};
+    Coordinate se_e{FloatLongitude(100.1), FloatLatitude(-45.0)};
+    Coordinate se_s{FloatLongitude(55), FloatLatitude(-80.1)};
+    BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_sw), 0.02, 0.1);
+    BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_se), 0.02, 0.1);
+    BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_ne), 0.02, 0.1);
+    BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_nw), 0.02, 0.1);
+    BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_s),  0.01, 0.1);
+    BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_e),  0.01, 0.1);
+    BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_w),  0.01, 0.1);
+    BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_n),  0.01, 0.1);
+
+    Coordinate sw_ne{FloatLongitude(-9.9), FloatLatitude(-9.9)};
+    Coordinate sw_nw{FloatLongitude(-100.1), FloatLatitude(-9.9)};
+    Coordinate sw_sw{FloatLongitude(-100.1), FloatLatitude(-80.1)};
+    Coordinate sw_se{FloatLongitude(-9.9), FloatLatitude(-80.1)};
+    Coordinate sw_n{FloatLongitude(-55), FloatLatitude(-9.9)};
+    Coordinate sw_w{FloatLongitude(-100.1), FloatLatitude(-45.0)};
+    Coordinate sw_e{FloatLongitude(-9.9), FloatLatitude(-45.0)};
+    Coordinate sw_s{FloatLongitude(-55), FloatLatitude(-80.1)};
+    BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_sw), 0.02, 0.1);
+    BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_se), 0.02, 0.1);
+    BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_ne), 0.02, 0.1);
+    BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_nw), 0.02, 0.1);
+    BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_s),  0.01, 0.1);
+    BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_e),  0.01, 0.1);
+    BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_w),  0.01, 0.1);
+    BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_n),  0.01, 0.1);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/data_structures/static_graph.cpp b/unit_tests/util/static_graph.cpp
similarity index 71%
rename from unit_tests/data_structures/static_graph.cpp
rename to unit_tests/util/static_graph.cpp
index ddadd7f..c975401 100644
--- a/unit_tests/data_structures/static_graph.cpp
+++ b/unit_tests/util/static_graph.cpp
@@ -1,32 +1,5 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 "util/static_graph.hpp"
+#include "util/typedefs.hpp"
 
 #include <boost/test/unit_test.hpp>
 #include <boost/test/test_case_template.hpp>
@@ -37,6 +10,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 BOOST_AUTO_TEST_SUITE(static_graph)
 
+using namespace osrm;
+using namespace osrm::util;
+
 struct TestData
 {
     EdgeID id;
@@ -118,6 +94,16 @@ BOOST_FIXTURE_TEST_CASE(array_test, TestRandomArrayEntryFixture)
     }
 }
 
+BOOST_AUTO_TEST_CASE(target_test)
+{
+    std::vector<TestInputEdge> input_edges = {TestInputEdge{0, 1, TestData{1}},
+                                              TestInputEdge{3, 0, TestData{2}}};
+    TestStaticGraph simple_graph = TestStaticGraph(4, input_edges);
+
+    auto target = simple_graph.GetTarget(simple_graph.FindEdge(3, 0));
+    BOOST_CHECK_EQUAL(target, 0);
+}
+
 BOOST_AUTO_TEST_CASE(find_test)
 {
     /*
@@ -129,12 +115,9 @@ BOOST_AUTO_TEST_CASE(find_test)
      *      <-4-
      */
     std::vector<TestInputEdge> input_edges = {
-        TestInputEdge{0, 1, TestData{1}},
-        TestInputEdge{3, 0, TestData{2}},
-        TestInputEdge{3, 0, TestData{5}},
-        TestInputEdge{3, 4, TestData{3}},
-        TestInputEdge{4, 3, TestData{4}}
-    };
+        TestInputEdge{0, 1, TestData{1}}, TestInputEdge{3, 0, TestData{2}},
+        TestInputEdge{3, 0, TestData{5}}, TestInputEdge{3, 4, TestData{3}},
+        TestInputEdge{4, 3, TestData{4}}};
     TestStaticGraph simple_graph(5, input_edges);
 
     auto eit = simple_graph.FindEdge(0, 1);
diff --git a/unit_tests/util/static_rtree.cpp b/unit_tests/util/static_rtree.cpp
new file mode 100644
index 0000000..a9170be
--- /dev/null
+++ b/unit_tests/util/static_rtree.cpp
@@ -0,0 +1,456 @@
+#include "extractor/edge_based_node.hpp"
+#include "engine/geospatial_query.hpp"
+#include "util/typedefs.hpp"
+#include "util/rectangle.hpp"
+#include "util/exception.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/coordinate.hpp"
+#include "util/static_rtree.hpp"
+
+#include "mocks/mock_datafacade.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/functional/hash.hpp>
+
+#include <cstdint>
+#include <cmath>
+
+#include <algorithm>
+#include <memory>
+#include <random>
+#include <string>
+#include <utility>
+#include <unordered_set>
+#include <vector>
+
+BOOST_AUTO_TEST_SUITE(static_rtree)
+
+using namespace osrm;
+using namespace osrm::util;
+using namespace osrm::test;
+
+constexpr uint32_t TEST_BRANCHING_FACTOR = 8;
+constexpr uint32_t TEST_LEAF_NODE_SIZE = 64;
+
+using TestData = extractor::EdgeBasedNode;
+using TestStaticRTree = StaticRTree<TestData,
+                                    std::vector<Coordinate>,
+                                    false,
+                                    TEST_BRANCHING_FACTOR,
+                                    TEST_LEAF_NODE_SIZE>;
+using MiniStaticRTree = StaticRTree<TestData, std::vector<Coordinate>, false, 2, 3>;
+
+// Choosen by a fair W20 dice roll (this value is completely arbitrary)
+constexpr unsigned RANDOM_SEED = 42;
+static const int32_t WORLD_MIN_LAT = -85 * COORDINATE_PRECISION;
+static const int32_t WORLD_MAX_LAT = 85 * COORDINATE_PRECISION;
+static const int32_t WORLD_MIN_LON = -180 * COORDINATE_PRECISION;
+static const int32_t WORLD_MAX_LON = 180 * COORDINATE_PRECISION;
+
+template <typename DataT> class LinearSearchNN
+{
+  public:
+    LinearSearchNN(const std::shared_ptr<std::vector<Coordinate>> &coords,
+                   const std::vector<DataT> &edges)
+        : coords(coords), edges(edges)
+    {
+    }
+
+    std::vector<DataT> Nearest(const Coordinate &input_coordinate, const unsigned num_results)
+    {
+        std::vector<DataT> local_edges(edges);
+
+        auto projected_input = coordinate_calculation::mercator::fromWGS84(input_coordinate);
+        const auto segment_comparator = [this, &projected_input](const DataT &lhs, const DataT &rhs)
+        {
+            using coordinate_calculation::mercator::fromWGS84;
+            const auto lhs_result = coordinate_calculation::projectPointOnSegment(
+                fromWGS84(coords->at(lhs.u)), fromWGS84(coords->at(lhs.v)), projected_input);
+            const auto rhs_result = coordinate_calculation::projectPointOnSegment(
+                fromWGS84(coords->at(rhs.u)), fromWGS84(coords->at(rhs.v)), projected_input);
+            const auto lhs_squared_dist = coordinate_calculation::squaredEuclideanDistance(
+                lhs_result.second, projected_input);
+            const auto rhs_squared_dist = coordinate_calculation::squaredEuclideanDistance(
+                rhs_result.second, projected_input);
+            return lhs_squared_dist < rhs_squared_dist;
+        };
+
+        std::nth_element(local_edges.begin(), local_edges.begin() + num_results, local_edges.end(),
+                         segment_comparator);
+        local_edges.resize(num_results);
+
+        return local_edges;
+    }
+
+  private:
+    const std::shared_ptr<std::vector<Coordinate>> &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<Coordinate>>())
+    {
+        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 lon = lon_udist(g);
+            int lat = lat_udist(g);
+            coords->emplace_back(Coordinate(FixedLongitude(lon), FixedLatitude(lat)));
+        }
+
+        std::uniform_int_distribution<> edge_udist(0, coords->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::shared_ptr<std::vector<Coordinate>> coords;
+    std::vector<TestData> edges;
+};
+
+struct GraphFixture
+{
+    GraphFixture(const std::vector<std::pair<FloatLongitude, FloatLatitude>> &input_coords,
+                 const std::vector<std::pair<unsigned, unsigned>> &input_edges)
+        : coords(std::make_shared<std::vector<Coordinate>>())
+    {
+
+        for (unsigned i = 0; i < input_coords.size(); i++)
+        {
+            coords->emplace_back(input_coords[i].first, input_coords[i].second);
+        }
+
+        for (const auto &pair : input_edges)
+        {
+            TestData d;
+            d.u = pair.first;
+            d.v = pair.second;
+            // We set the forward nodes to the target node-based-node IDs, just
+            // so we have something to test against.  Because this isn't a real
+            // graph, the actual values aren't important, we just need something
+            // to examine during tests.
+            d.forward_segment_id = {pair.second, true};
+            d.reverse_segment_id = {pair.first, true};
+            edges.emplace_back(d);
+        }
+    }
+
+    std::shared_ptr<std::vector<Coordinate>> 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;
+typedef RandomGraphFixture<10, 30> TestRandomGraphFixture_10_30;
+
+template <typename RTreeT>
+void simple_verify_rtree(RTreeT &rtree,
+                         const std::shared_ptr<std::vector<Coordinate>> &coords,
+                         const std::vector<TestData> &edges)
+{
+    for (const auto &e : edges)
+    {
+        const Coordinate &pu = coords->at(e.u);
+        const Coordinate &pv = coords->at(e.v);
+        auto result_u = rtree.Nearest(pu, 1);
+        auto result_v = rtree.Nearest(pv, 1);
+        BOOST_CHECK(result_u.size() == 1 && result_v.size() == 1);
+        BOOST_CHECK(result_u.front().u == e.u || result_u.front().v == e.u);
+        BOOST_CHECK(result_v.front().u == e.v || result_v.front().v == e.v);
+    }
+}
+
+template <typename RTreeT>
+void sampling_verify_rtree(RTreeT &rtree,
+                           LinearSearchNN<TestData> &lsnn,
+                           const std::vector<Coordinate> &coords,
+                           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<Coordinate> queries;
+    for (unsigned i = 0; i < num_samples; i++)
+    {
+        queries.emplace_back(FixedLongitude(lon_udist(g)), FixedLatitude(lat_udist(g)));
+    }
+
+    for (const auto &q : queries)
+    {
+        auto result_rtree = rtree.Nearest(q, 1);
+        auto result_lsnn = lsnn.Nearest(q, 1);
+        BOOST_CHECK(result_rtree.size() == 1);
+        BOOST_CHECK(result_lsnn.size() == 1);
+        auto rtree_u = result_rtree.back().u;
+        auto rtree_v = result_rtree.back().v;
+        auto lsnn_u = result_lsnn.back().u;
+        auto lsnn_v = result_lsnn.back().v;
+
+        Coordinate rtree_nearest;
+        Coordinate lsnn_nearest;
+        double ratio;
+        const double rtree_dist = coordinate_calculation::perpendicularDistance(
+            coords[rtree_u], coords[rtree_v], q, rtree_nearest, ratio);
+        const double lsnn_dist = coordinate_calculation::perpendicularDistance(
+            coords[lsnn_u], coords[lsnn_v], q, lsnn_nearest, ratio);
+
+        BOOST_CHECK_CLOSE(rtree_dist, lsnn_dist, 0.0001);
+    }
+}
+
+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";
+
+    RTreeT r(fixture->edges, nodes_path, leaves_path, *fixture->coords);
+}
+
+template <typename RTreeT = TestStaticRTree, typename FixtureT>
+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<TestData> lsnn(fixture->coords, fixture->edges);
+
+    simple_verify_rtree(rtree, fixture->coords, fixture->edges);
+    sampling_verify_rtree(rtree, lsnn, *fixture->coords, 100);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_tiny, TestRandomGraphFixture_10_30)
+{
+    using TinyTestTree = StaticRTree<TestData, std::vector<Coordinate>, false, 2, 1>;
+    construction_test<TinyTestTree>("test_tiny", this);
+}
+
+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)
+{
+    using Coord = std::pair<FloatLongitude, FloatLatitude>;
+    using Edge = std::pair<unsigned, unsigned>;
+    GraphFixture fixture(
+        {
+            Coord{FloatLongitude{0.0}, FloatLatitude{40.0}},   //
+            Coord{FloatLongitude{5.0}, FloatLatitude{35.0}},   //
+            Coord{FloatLongitude{5.0}, FloatLatitude{5.0}},    //
+            Coord{FloatLongitude{10.0}, FloatLatitude{0.0}},   //
+            Coord{FloatLongitude{10.0}, FloatLatitude{20.0}},  //
+            Coord{FloatLongitude{5.0}, FloatLatitude{20.0}},   //
+            Coord{FloatLongitude{100.0}, FloatLatitude{40.0}}, //
+            Coord{FloatLongitude{105.0}, FloatLatitude{35.0}}, //
+            Coord{FloatLongitude{105.0}, FloatLatitude{5.0}},  //
+            Coord{FloatLongitude{110.0}, FloatLatitude{0.0}},  //
+        },
+        {Edge(0, 1), Edge(2, 3), Edge(4, 5), Edge(6, 7), Edge(8, 9)});
+
+    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);
+    LinearSearchNN<TestData> lsnn(fixture.coords, fixture.edges);
+
+    // query a node just right of the center of the gap
+    Coordinate input(FloatLongitude(55.1), FloatLatitude(20.0));
+    auto result_rtree = rtree.Nearest(input, 1);
+    auto result_ls = lsnn.Nearest(input, 1);
+
+    auto distance_rtree = coordinate_calculation::perpendicularDistance(
+        fixture.coords->at(result_rtree.front().u), fixture.coords->at(result_rtree.front().v),
+        input);
+
+    auto distance_lsnn = coordinate_calculation::perpendicularDistance(
+        fixture.coords->at(result_ls.front().u), fixture.coords->at(result_ls.front().v), input);
+
+    BOOST_CHECK(result_rtree.size() == 1);
+    BOOST_CHECK(result_ls.size() == 1);
+
+    BOOST_CHECK_EQUAL(result_ls.front().u, result_rtree.front().u);
+    BOOST_CHECK_EQUAL(result_ls.front().v, result_rtree.front().v);
+}
+
+BOOST_AUTO_TEST_CASE(bearing_tests)
+{
+    using Coord = std::pair<FloatLongitude, FloatLatitude>;
+    using Edge = std::pair<unsigned, unsigned>;
+    GraphFixture fixture(
+        {
+            Coord(FloatLongitude(0.0), FloatLatitude(0.0)),
+            Coord(FloatLongitude(10.0), FloatLatitude(10.0)),
+        },
+        {Edge(0, 1), Edge(1, 0)});
+
+    std::string leaves_path;
+    std::string nodes_path;
+    build_rtree<GraphFixture, MiniStaticRTree>("test_bearing", &fixture, leaves_path, nodes_path);
+    MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords);
+    MockDataFacade mockfacade;
+    engine::GeospatialQuery<MiniStaticRTree, MockDataFacade> query(rtree, fixture.coords,
+                                                                   mockfacade);
+
+    Coordinate input(FloatLongitude(5.1), FloatLatitude(5.0));
+
+    {
+        auto results = query.NearestPhantomNodes(input, 5);
+        BOOST_CHECK_EQUAL(results.size(), 2);
+        BOOST_CHECK_EQUAL(results.back().phantom_node.forward_segment_id.id, 0);
+        BOOST_CHECK_EQUAL(results.back().phantom_node.reverse_segment_id.id, 1);
+    }
+
+    {
+        auto results = query.NearestPhantomNodes(input, 5, 270, 10);
+        BOOST_CHECK_EQUAL(results.size(), 0);
+    }
+
+    {
+        auto results = query.NearestPhantomNodes(input, 5, 45, 10);
+        BOOST_CHECK_EQUAL(results.size(), 2);
+
+        BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled);
+        BOOST_CHECK(!results[0].phantom_node.reverse_segment_id.enabled);
+        BOOST_CHECK_EQUAL(results[0].phantom_node.forward_segment_id.id, 1);
+
+        BOOST_CHECK(!results[1].phantom_node.forward_segment_id.enabled);
+        BOOST_CHECK(results[1].phantom_node.reverse_segment_id.enabled);
+        BOOST_CHECK_EQUAL(results[1].phantom_node.reverse_segment_id.id, 1);
+    }
+
+    {
+        auto results = query.NearestPhantomNodesInRange(input, 11000);
+        BOOST_CHECK_EQUAL(results.size(), 2);
+    }
+
+    {
+        auto results = query.NearestPhantomNodesInRange(input, 11000, 270, 10);
+        BOOST_CHECK_EQUAL(results.size(), 0);
+    }
+
+    {
+        auto results = query.NearestPhantomNodesInRange(input, 11000, 45, 10);
+        BOOST_CHECK_EQUAL(results.size(), 2);
+
+        BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled);
+        BOOST_CHECK(!results[0].phantom_node.reverse_segment_id.enabled);
+        BOOST_CHECK_EQUAL(results[0].phantom_node.forward_segment_id.id, 1);
+
+        BOOST_CHECK(!results[1].phantom_node.forward_segment_id.enabled);
+        BOOST_CHECK(results[1].phantom_node.reverse_segment_id.enabled);
+        BOOST_CHECK_EQUAL(results[1].phantom_node.reverse_segment_id.id, 1);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(bbox_search_tests)
+{
+    using Coord = std::pair<FloatLongitude, FloatLatitude>;
+    using Edge = std::pair<unsigned, unsigned>;
+
+    GraphFixture fixture(
+        {
+            Coord(FloatLongitude(0.0), FloatLatitude(0.0)),
+            Coord(FloatLongitude(1.0), FloatLatitude(1.0)),
+            Coord(FloatLongitude(2.0), FloatLatitude(2.0)),
+            Coord(FloatLongitude(3.0), FloatLatitude(3.0)),
+            Coord(FloatLongitude(4.0), FloatLatitude(4.0)),
+        },
+        {Edge(0, 1), Edge(1, 2), Edge(2, 3), Edge(3, 4)});
+
+    std::string leaves_path;
+    std::string nodes_path;
+    build_rtree<GraphFixture, MiniStaticRTree>("test_bbox", &fixture, leaves_path, nodes_path);
+    MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords);
+    MockDataFacade mockfacade;
+    engine::GeospatialQuery<MiniStaticRTree, MockDataFacade> query(rtree, fixture.coords,
+                                                                   mockfacade);
+
+    {
+        RectangleInt2D bbox = {FloatLongitude(0.5), FloatLongitude(1.5), FloatLatitude(0.5),
+                               FloatLatitude(1.5)};
+        auto results = query.Search(bbox);
+        BOOST_CHECK_EQUAL(results.size(), 2);
+    }
+
+    {
+        RectangleInt2D bbox = {FloatLongitude(1.5), FloatLongitude(3.5), FloatLatitude(1.5),
+                               FloatLatitude(3.5)};
+        auto results = query.Search(bbox);
+        BOOST_CHECK_EQUAL(results.size(), 3);
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/util/string_util.cpp b/unit_tests/util/string_util.cpp
new file mode 100644
index 0000000..e3a7204
--- /dev/null
+++ b/unit_tests/util/string_util.cpp
@@ -0,0 +1,41 @@
+#include "util/string_util.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include <iostream>
+
+BOOST_AUTO_TEST_SUITE(string_util)
+
+using namespace osrm;
+using namespace osrm::util;
+
+BOOST_AUTO_TEST_CASE(json_escaping)
+{
+    std::string input{"\b\\"};
+    std::string output{escape_JSON(input)};
+
+    BOOST_CHECK_EQUAL(output, "\\b\\\\");
+
+    input = "Aleja \"Solidarnosci\"";
+    output = escape_JSON(input);
+    BOOST_CHECK_EQUAL(output, "Aleja \\\"Solidarnosci\\\"");
+}
+
+BOOST_AUTO_TEST_CASE(print_int)
+{
+    const std::string input{"\b\\"};
+    char buffer[12];
+    buffer[11] = 0; // zero termination
+    std::string output = printInt<11, 8>(buffer, 314158976);
+    BOOST_CHECK_EQUAL(output, "3.14158976");
+
+    buffer[11] = 0;
+    output = printInt<11, 8>(buffer, 0);
+    BOOST_CHECK_EQUAL(output, "0.00000000");
+
+    output = printInt<11, 8>(buffer, -314158976);
+    BOOST_CHECK_EQUAL(output, "-3.14158976");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/util/viewport.cpp b/unit_tests/util/viewport.cpp
new file mode 100644
index 0000000..f5f4f9a
--- /dev/null
+++ b/unit_tests/util/viewport.cpp
@@ -0,0 +1,25 @@
+#include "util/viewport.hpp"
+
+using namespace osrm::util;
+
+#include <boost/functional/hash.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include <iostream>
+
+BOOST_AUTO_TEST_SUITE(viewport_test)
+
+using namespace osrm;
+using namespace osrm::util;
+
+BOOST_AUTO_TEST_CASE(zoom_level_test)
+{
+    BOOST_CHECK_EQUAL(
+        viewport::getFittedZoom(
+            Coordinate(FloatLongitude{5.668343999999995}, FloatLatitude{45.111511000000014}),
+            Coordinate(FloatLongitude{5.852471999999996}, FloatLatitude{45.26800200000002})),
+        12);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/util_tests.cpp b/unit_tests/util_tests.cpp
index 26275ab..7b641fa 100644
--- a/unit_tests/util_tests.cpp
+++ b/unit_tests/util_tests.cpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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.
-
-*/
-
 #define BOOST_TEST_MODULE util tests
 
 #include <boost/test/unit_test.hpp>
diff --git a/util/cast.hpp b/util/cast.hpp
deleted file mode 100644
index a9e97d6..0000000
--- a/util/cast.hpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 <string>
-#include <sstream>
-#include <iomanip>
-#include <type_traits>
-
-#include <boost/algorithm/string/classification.hpp>
-#include <boost/algorithm/string/trim.hpp>
-
-namespace cast
-{
-template <typename Enumeration>
-inline 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 T, int Precision = 6> inline std::string to_string_with_precision(const T x)
-{
-    static_assert(std::is_arithmetic<T>::value, "integral or floating point type required");
-
-    std::ostringstream out;
-    out << std::fixed << std::setprecision(Precision) << x;
-    auto rv = out.str();
-
-    // Javascript has no separation of float / int, digits without a '.' are integral typed
-    // X.Y.0 -> X.Y
-    // X.0 -> X
-    boost::trim_right_if(rv, boost::is_any_of("0"));
-    boost::trim_right_if(rv, boost::is_any_of("."));
-    // Note:
-    //  - assumes the locale to use '.' as digit separator
-    //  - this is not identical to:  trim_right_if(rv, is_any_of('0 .'))
-
-    return rv;
-}
-}
-
-#endif // CAST_HPP
diff --git a/util/compute_angle.cpp b/util/compute_angle.cpp
deleted file mode 100644
index 8cd8aa4..0000000
--- a/util/compute_angle.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "compute_angle.hpp"
-
-#include "trigonometry_table.hpp"
-#include "../util/mercator.hpp"
-
-#include <osrm/coordinate.hpp>
-
-#include <cmath>
-
-double ComputeAngle::OfThreeFixedPointCoordinates(const FixedPointCoordinate &first,
-                                                  const FixedPointCoordinate &second,
-                                                  const FixedPointCoordinate &third) noexcept
-{
-    const double v1x = (first.lon - second.lon) / COORDINATE_PRECISION;
-    const double v1y = mercator::lat2y(first.lat / COORDINATE_PRECISION) -
-                       mercator::lat2y(second.lat / COORDINATE_PRECISION);
-    const double v2x = (third.lon - second.lon) / COORDINATE_PRECISION;
-    const double v2y = mercator::lat2y(third.lat / COORDINATE_PRECISION) -
-                       mercator::lat2y(second.lat / COORDINATE_PRECISION);
-
-    double angle = (atan2_lookup(v2y, v2x) - atan2_lookup(v1y, v1x)) * 180. / M_PI;
-    while (angle < 0.)
-    {
-        angle += 360.;
-    }
-    return angle;
-}
diff --git a/util/compute_angle.hpp b/util/compute_angle.hpp
deleted file mode 100644
index da84caf..0000000
--- a/util/compute_angle.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 COMPUTE_ANGLE_HPP
-#define COMPUTE_ANGLE_HPP
-
-struct FixedPointCoordinate;
-
-struct ComputeAngle
-{
-    // Get angle of line segment (A,C)->(C,B)
-    // atan2 magic, formerly cosine theorem
-    static double OfThreeFixedPointCoordinates(const FixedPointCoordinate &first,
-                                               const FixedPointCoordinate &second,
-                                               const FixedPointCoordinate &third) noexcept;
-};
-
-#endif // COMPUTE_ANGLE_HPP
diff --git a/util/container.hpp b/util/container.hpp
deleted file mode 100644
index 14b88ee..0000000
--- a/util/container.hpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 CONTAINER_HPP
-#define CONTAINER_HPP
-
-#include <algorithm>
-#include <iterator>
-#include <vector>
-
-namespace osrm
-{
-namespace detail
-{
-// Culled by SFINAE if reserve does not exist or is not accessible
-template <typename T>
-constexpr auto has_resize_method(T &t) noexcept -> decltype(t.resize(0), bool())
-{
-    return true;
-}
-
-// Used as fallback when SFINAE culls the template method
-constexpr bool has_resize_method(...) noexcept { return false; }
-}
-
-template <typename Container> void sort_unique_resize(Container &vector) noexcept
-{
-    std::sort(std::begin(vector), std::end(vector));
-    const auto number_of_unique_elements =
-        std::unique(std::begin(vector), std::end(vector)) - std::begin(vector);
-    if (detail::has_resize_method(vector))
-    {
-        vector.resize(number_of_unique_elements);
-    }
-}
-
-// 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 ForwardIterator, typename Function>
-Function for_each_pair(ForwardIterator begin, ForwardIterator end, Function function)
-{
-    if (begin == end)
-    {
-        return function;
-    }
-
-    auto next = begin;
-    next = std::next(next);
-
-    while (next != end)
-    {
-        function(*begin, *next);
-        begin = std::next(begin);
-        next = std::next(next);
-    }
-    return function;
-}
-
-template <class ContainerT, typename Function>
-Function for_each_pair(ContainerT &container, Function function)
-{
-    return for_each_pair(std::begin(container), std::end(container), function);
-}
-
-template <class Container> void append_to_container(Container &&) {}
-
-template <class Container, typename T, typename... Args>
-void append_to_container(Container &&container, T value, Args &&... args)
-{
-    container.emplace_back(value);
-    append_to_container(std::forward<Container>(container), std::forward<Args>(args)...);
-}
-
-} // namespace osrm
-#endif /* CONTAINER_HPP */
diff --git a/util/datastore_options.hpp b/util/datastore_options.hpp
deleted file mode 100644
index 4a8320c..0000000
--- a/util/datastore_options.hpp
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 DATASTORE_OPTIONS_HPP
-#define DATASTORE_OPTIONS_HPP
-
-#include "util/version.hpp"
-#include "ini_file.hpp"
-#include "osrm_exception.hpp"
-#include "simple_logger.hpp"
-
-#include <boost/any.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/program_options.hpp>
-
-#include <string>
-#include <unordered_map>
-
-// generate boost::program_options object for the routing part
-bool GenerateDataStoreOptions(const int argc, const char *argv[], std::unordered_map<std::string, boost::filesystem::path> &paths)
-{
-    // 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")(
-        "springclean,s", "Remove all regions in shared memory")(
-        "config,c", boost::program_options::value<boost::filesystem::path>(&paths["config"])
-                        ->default_value("server.ini"),
-        "Path to a configuration file");
-
-    // declare a group of options that will be allowed both on command line
-    // as well as in a config file
-    boost::program_options::options_description config_options("Configuration");
-    config_options.add_options()(
-        "hsgrdata", boost::program_options::value<boost::filesystem::path>(&paths["hsgrdata"]),
-        ".hsgr file")("nodesdata",
-                      boost::program_options::value<boost::filesystem::path>(&paths["nodesdata"]),
-                      ".nodes file")(
-        "edgesdata", boost::program_options::value<boost::filesystem::path>(&paths["edgesdata"]),
-        ".edges file")("geometry",
-                       boost::program_options::value<boost::filesystem::path>(&paths["geometry"]),
-                       ".geometry file")(
-        "ramindex", boost::program_options::value<boost::filesystem::path>(&paths["ramindex"]),
-        ".ramIndex file")(
-        "fileindex", boost::program_options::value<boost::filesystem::path>(&paths["fileindex"]),
-        ".fileIndex file")("core",
-                           boost::program_options::value<boost::filesystem::path>(&paths["core"]),
-                           ".core file")(
-        "namesdata", boost::program_options::value<boost::filesystem::path>(&paths["namesdata"]),
-        ".names file")("timestamp",
-                       boost::program_options::value<boost::filesystem::path>(&paths["timestamp"]),
-                       ".timestamp file");
-
-    // 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()(
-        "base,b", boost::program_options::value<boost::filesystem::path>(&paths["base"]),
-        "base path to .osrm file");
-
-    // positional option
-    boost::program_options::positional_options_description positional_options;
-    positional_options.add("base", 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]) + " [<options>] <configuration>");
-    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() << OSRM_VERSION;
-        return false;
-    }
-
-    if (option_variables.count("help"))
-    {
-        SimpleLogger().Write() << visible_options;
-        return false;
-    }
-
-    boost::program_options::notify(option_variables);
-
-    const bool parameter_present =
-        (paths.find("hsgrdata") != paths.end() &&
-         !paths.find("hsgrdata")->second.string().empty()) ||
-        (paths.find("nodesdata") != paths.end() &&
-         !paths.find("nodesdata")->second.string().empty()) ||
-        (paths.find("edgesdata") != paths.end() &&
-         !paths.find("edgesdata")->second.string().empty()) ||
-        (paths.find("geometry") != paths.end() &&
-         !paths.find("geometry")->second.string().empty()) ||
-        (paths.find("ramindex") != paths.end() &&
-         !paths.find("ramindex")->second.string().empty()) ||
-        (paths.find("fileindex") != paths.end() &&
-         !paths.find("fileindex")->second.string().empty()) ||
-        (paths.find("core") != paths.end() && !paths.find("core")->second.string().empty()) ||
-        (paths.find("timestamp") != paths.end() &&
-         !paths.find("timestamp")->second.string().empty());
-
-    if (parameter_present)
-    {
-        if ((paths.find("config") != paths.end() &&
-             boost::filesystem::is_regular_file(paths.find("config")->second)) ||
-            option_variables.count("base"))
-        {
-            SimpleLogger().Write(logWARNING) << "conflicting parameters";
-            SimpleLogger().Write() << visible_options;
-            return false;
-        }
-    }
-
-    // parse config file
-    auto path_iterator = paths.find("config");
-    if (path_iterator != paths.end() && boost::filesystem::is_regular_file(path_iterator->second) &&
-        !option_variables.count("base"))
-    {
-        SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string();
-        std::string ini_file_contents = read_file_lower_content(path_iterator->second);
-        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);
-    }
-    else if (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())
-        {
-            path_iterator->second = base_string + ".hsgr";
-        }
-
-        path_iterator = paths.find("nodesdata");
-        if (path_iterator != paths.end())
-        {
-            path_iterator->second = base_string + ".nodes";
-        }
-
-        path_iterator = paths.find("edgesdata");
-        if (path_iterator != paths.end())
-        {
-            path_iterator->second = base_string + ".edges";
-        }
-
-        path_iterator = paths.find("geometry");
-        if (path_iterator != paths.end())
-        {
-            path_iterator->second = base_string + ".geometry";
-        }
-
-        path_iterator = paths.find("ramindex");
-        if (path_iterator != paths.end())
-        {
-            path_iterator->second = base_string + ".ramIndex";
-        }
-
-        path_iterator = paths.find("fileindex");
-        if (path_iterator != paths.end())
-        {
-            path_iterator->second = base_string + ".fileIndex";
-        }
-
-        path_iterator = paths.find("core");
-        if (path_iterator != paths.end())
-        {
-            path_iterator->second = base_string + ".core";
-        }
-
-        path_iterator = paths.find("namesdata");
-        if (path_iterator != paths.end())
-        {
-            path_iterator->second = base_string + ".names";
-        }
-
-        path_iterator = paths.find("timestamp");
-        if (path_iterator != paths.end())
-        {
-            path_iterator->second = base_string + ".timestamp";
-        }
-    }
-
-    path_iterator = paths.find("hsgrdata");
-    if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
-        !boost::filesystem::is_regular_file(path_iterator->second))
-    {
-        throw osrm::exception("valid .hsgr file must be specified");
-    }
-
-    path_iterator = paths.find("nodesdata");
-    if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
-        !boost::filesystem::is_regular_file(path_iterator->second))
-    {
-        throw osrm::exception("valid .nodes file must be specified");
-    }
-
-    path_iterator = paths.find("edgesdata");
-    if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
-        !boost::filesystem::is_regular_file(path_iterator->second))
-    {
-        throw osrm::exception("valid .edges file must be specified");
-    }
-
-    path_iterator = paths.find("geometry");
-    if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
-        !boost::filesystem::is_regular_file(path_iterator->second))
-    {
-        throw osrm::exception("valid .geometry file must be specified");
-    }
-
-    path_iterator = paths.find("ramindex");
-    if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
-        !boost::filesystem::is_regular_file(path_iterator->second))
-    {
-        throw osrm::exception("valid .ramindex file must be specified");
-    }
-
-    path_iterator = paths.find("fileindex");
-    if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
-        !boost::filesystem::is_regular_file(path_iterator->second))
-    {
-        throw osrm::exception("valid .fileindex file must be specified");
-    }
-
-    path_iterator = paths.find("namesdata");
-    if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
-        !boost::filesystem::is_regular_file(path_iterator->second))
-    {
-        throw osrm::exception("valid .names file must be specified");
-    }
-
-    path_iterator = paths.find("timestamp");
-    if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
-        !boost::filesystem::is_regular_file(path_iterator->second))
-    {
-        throw osrm::exception("valid .timestamp file must be specified");
-    }
-
-    return true;
-}
-
-#endif /* DATASTORE_OPTIONS_HPP */
diff --git a/util/debug_geometry.hpp b/util/debug_geometry.hpp
deleted file mode 100644
index daa7e10..0000000
--- a/util/debug_geometry.hpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 DEBUG_GEOMETRY_H
-#define DEBUG_GEOMETRY_H
-
-#include "../contractor/contractor_options.hpp"
-#include "../data_structures/query_node.hpp"
-
-#ifndef DEBUG_GEOMETRY
-
-inline void DEBUG_GEOMETRY_START(ContractorConfig & /* config */) {}
-inline void DEBUG_GEOMETRY_EDGE(int /* new_segment_weight */ , double /* segment_length */,
-        OSMNodeID /* previous_osm_node_id */, OSMNodeID /* this_osm_node_id */) {}
-inline void DEBUG_GEOMETRY_STOP() {}
-
-inline void DEBUG_TURNS_START(const std::string & /* debug_turns_filename */) {}
-inline void DEBUG_TURN( const NodeID /* node */, const std::vector<QueryNode>& /* m_node_info_list */,
-        const FixedPointCoordinate & /* first_coordinate */, const int /* turn_angle */,
-        const int /* turn_penalty */) {}
-inline void DEBUG_UTURN( const NodeID /* node */, const std::vector<QueryNode>& /* m_node_info_list */,
-        const int /* uturn_penalty */ ) {}
-inline void DEBUG_SIGNAL( const NodeID /* node */, const std::vector<QueryNode>& /* m_node_info_list */,
-        const int /* signal_penalty */ ) {}
-
-inline void DEBUG_TURNS_STOP() {}
-
-#else // DEBUG_GEOMETRY
-
-#include <boost/filesystem.hpp>
-#include <ctime>
-#include <string>
-#include <iomanip>
-#include <iostream>
-
-#include "../include/osrm/coordinate.hpp"
-#include "../algorithms/coordinate_calculation.hpp"
-
-boost::filesystem::ofstream debug_geometry_file;
-bool dg_output_debug_geometry = false;
-bool dg_first_debug_geometry = true;
-char dg_time_buffer[80];
-
-boost::filesystem::ofstream dg_debug_turns_file;
-bool dg_output_turn_debug = false;
-bool dg_first_turn_debug = true;
-
-inline void DEBUG_GEOMETRY_START(const ContractorConfig &config)
-{
-    time_t raw_time;
-    struct tm *timeinfo;
-    time(&raw_time);
-    timeinfo = localtime(&raw_time);
-    strftime(dg_time_buffer, 80, "%Y-%m-%d %H:%M %Z", timeinfo);
-
-    dg_output_debug_geometry = config.debug_geometry_path != "";
-
-    if (dg_output_debug_geometry)
-    {
-        debug_geometry_file.open(config.debug_geometry_path, std::ios::binary);
-        debug_geometry_file << "{\"type\":\"FeatureCollection\", \"features\":[" << std::endl;
-    }
-}
-
-inline void DEBUG_GEOMETRY_EDGE(int new_segment_weight, double segment_length, OSMNodeID previous_osm_node_id, OSMNodeID this_osm_node_id)
-{
-    if (dg_output_debug_geometry)
-    {
-        if (!dg_first_debug_geometry)
-            debug_geometry_file << "," << std::endl;
-        debug_geometry_file
-            << "{ \"type\":\"Feature\",\"properties\":{\"original\":false, "
-               "\"weight\":"
-            << new_segment_weight / 10.0 << ",\"speed\":"
-            << static_cast<int>(
-                   std::floor((segment_length / new_segment_weight) * 10. * 3.6))
-            << ",";
-        debug_geometry_file << "\"from_node\": " << previous_osm_node_id
-                            << ", \"to_node\": " << this_osm_node_id << ",";
-        debug_geometry_file << "\"timestamp\": \"" << dg_time_buffer << "\"},";
-        debug_geometry_file
-            << "\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[!!"
-            << previous_osm_node_id << "!!],[!!" << this_osm_node_id << "!!]]}}"
-            << std::endl;
-        dg_first_debug_geometry = false;
-    }
-}
-
-inline void DEBUG_GEOMETRY_STOP()
-{
-    if (dg_output_debug_geometry)
-    {
-        debug_geometry_file << std::endl << "]}" << std::endl;
-        debug_geometry_file.close();
-    }
-}
-
-
-inline void DEBUG_TURNS_START(const std::string & debug_turns_path)
-{   
-    dg_output_turn_debug = debug_turns_path != "";
-    if (dg_output_turn_debug) 
-    {
-        dg_debug_turns_file.open(debug_turns_path);
-        dg_debug_turns_file << "{\"type\":\"FeatureCollection\", \"features\":[" << std::endl;
-    }
-} 
-
-inline void DEBUG_SIGNAL(
-        const NodeID node, 
-        const std::vector<QueryNode>& m_node_info_list,
-        const int traffic_signal_penalty)
-{
-    if (dg_output_turn_debug)
-    {
-        const QueryNode &nodeinfo = m_node_info_list[node];
-        if (!dg_first_turn_debug) dg_debug_turns_file << "," << std::endl;
-        dg_debug_turns_file << "{ \"type\":\"Feature\",\"properties\":{\"type\":\"trafficlights\",\"cost\":" << traffic_signal_penalty/10. << "},";
-        dg_debug_turns_file << " \"geometry\":{\"type\":\"Point\",\"coordinates\":[" << std::setprecision(12) << nodeinfo.lon/COORDINATE_PRECISION << "," << nodeinfo.lat/COORDINATE_PRECISION << "]}}";
-        dg_first_turn_debug = false;
-    }
-}
-
-inline void DEBUG_UTURN(
-        const NodeID node, 
-        const std::vector<QueryNode>& m_node_info_list,
-        const int traffic_signal_penalty)
-{
-    if (dg_output_turn_debug)
-    {
-        const QueryNode &nodeinfo = m_node_info_list[node];
-        if (!dg_first_turn_debug) dg_debug_turns_file << "," << std::endl;
-        dg_debug_turns_file << "{ \"type\":\"Feature\",\"properties\":{\"type\":\"trafficlights\",\"cost\":" << traffic_signal_penalty/10. << "},";
-        dg_debug_turns_file << " \"geometry\":{\"type\":\"Point\",\"coordinates\":[" << std::setprecision(12) << nodeinfo.lon/COORDINATE_PRECISION << "," << nodeinfo.lat/COORDINATE_PRECISION << "]}}";
-        dg_first_turn_debug = false;
-    }
-}
-
-
-inline void DEBUG_TURN(
-        const NodeID node, 
-        const std::vector<QueryNode>& m_node_info_list,
-        const FixedPointCoordinate & first_coordinate,
-        const int turn_angle,
-        const int turn_penalty)
-{
-    if (turn_penalty > 0 && dg_output_turn_debug) 
-    {
-        const QueryNode &v = m_node_info_list[node];
-
-        const float bearing_uv = coordinate_calculation::bearing(first_coordinate,v);
-        float uvw_normal = bearing_uv + turn_angle/2;
-        while (uvw_normal >= 360.) { uvw_normal -= 360.; }
-
-        if (!dg_first_turn_debug) dg_debug_turns_file << "," << std::endl;
-        dg_debug_turns_file << "{ \"type\":\"Feature\",\"properties\":{\"type\":\"turn\",\"cost\":" << turn_penalty/10. << ",\"turn_angle\":" << static_cast<int>(turn_angle) << ",\"normal\":" << static_cast<int>(uvw_normal) << "},";
-        dg_debug_turns_file << " \"geometry\":{\"type\":\"Point\",\"coordinates\":[" << std::setprecision(12) << v.lon/COORDINATE_PRECISION << "," << v.lat/COORDINATE_PRECISION << "]}}";
-        dg_first_turn_debug = false;
-    }
-}
-
-inline void DEBUG_TURNS_STOP()
-{
-    if (dg_output_turn_debug)
-    {
-        dg_debug_turns_file << std::endl << "]}" << std::endl;
-        dg_debug_turns_file.close();
-    }
-}
-
-#endif // DEBUG_GEOMETRY
-
-
-#endif // DEBUG_GEOMETRY_H
diff --git a/util/fingerprint.hpp b/util/fingerprint.hpp
deleted file mode 100644
index 99576f9..0000000
--- a/util/fingerprint.hpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 FINGERPRINT_H
-#define FINGERPRINT_H
-
-#include <boost/uuid/uuid.hpp>
-#include <type_traits>
-
-// implements a singleton, i.e. there is one and only one conviguration object
-class FingerPrint
-{
-  public:
-    static FingerPrint GetValid();
-    const boost::uuids::uuid &GetFingerPrint() const;
-    bool IsMagicNumberOK(const FingerPrint &other) const;
-    bool TestGraphUtil(const FingerPrint &other) const;
-    bool TestPrepare(const FingerPrint &other) const;
-    bool TestRTree(const FingerPrint &other) const;
-    bool TestQueryObjects(const FingerPrint &other) const;
-
-  private:
-    unsigned magic_number;
-    char md5_prepare[33];
-    char md5_tree[33];
-    char md5_graph[33];
-    char md5_objects[33];
-
-    // initialize to {6ba7b810-9dad-11d1-80b4-00c04fd430c8}
-    boost::uuids::uuid named_uuid;
-
-};
-
-static_assert(std::is_trivial<FingerPrint>::value, "FingerPrint needs to be trivial.");
-
-
-#endif /* FingerPrint_H */
diff --git a/util/ini_file.hpp b/util/ini_file.hpp
deleted file mode 100644
index b42f9ae..0000000
--- a/util/ini_file.hpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 INI_FILE_HPP
-#define INI_FILE_HPP
-
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
-
-#include <algorithm>
-#include <string>
-
-namespace
-{
-
-// support old capitalized option names by down-casing them with a regex replace
-std::string read_file_lower_content(const boost::filesystem::path &path)
-{
-    boost::filesystem::fstream config_stream(path);
-    std::string ini_file_content((std::istreambuf_iterator<char>(config_stream)),
-                                 std::istreambuf_iterator<char>());
-    std::transform(std::begin(ini_file_content), std::end(ini_file_content),
-                   std::begin(ini_file_content), ::tolower);
-    return ini_file_content;
-}
-}
-#endif // INI_FILE_HPP
diff --git a/util/integer_range.hpp b/util/integer_range.hpp
deleted file mode 100644
index 02de7f8..0000000
--- a/util/integer_range.hpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 INTEGER_RANGE_HPP
-#define INTEGER_RANGE_HPP
-
-#include <boost/assert.hpp>
-
-#include <type_traits>
-
-#include <cstdint>
-
-namespace osrm
-{
-
-template <typename Integer> class range
-{
-  private:
-    const Integer last;
-    Integer iter;
-
-  public:
-    range(Integer start, Integer end) noexcept : last(end), iter(start)
-    {
-        BOOST_ASSERT_MSG(start <= end, "backwards counting ranges not suppoted");
-        static_assert(std::is_integral<Integer>::value, "range type must be integral");
-    }
-
-    // Iterable functions
-    const range &begin() const noexcept { return *this; }
-    const range &end() const noexcept { return *this; }
-    Integer front() const noexcept { return iter; }
-    Integer back() const noexcept { return last - 1; }
-    std::size_t size() const noexcept
-    {
-        return static_cast<std::size_t>(last - iter);
-    }
-
-    // Iterator functions
-    bool operator!=(const range &) const noexcept { return iter < last; }
-    void operator++() noexcept { ++iter; }
-    Integer operator*() const noexcept { return iter; }
-};
-
-// 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) noexcept
-{
-    return range<Integer>(first, last);
-}
-}
-
-#endif // INTEGER_RANGE_HPP
diff --git a/util/json_util.hpp b/util/json_util.hpp
deleted file mode 100644
index bfb8a8b..0000000
--- a/util/json_util.hpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 JSON_UTIL_HPP
-#define JSON_UTIL_HPP
-
-#include <osrm/json_container.hpp>
-
-#include <cmath>
-#include <limits>
-
-namespace osrm
-{
-namespace json
-{
-
-// Make sure we don't have inf and NaN values
-template <typename T> T clamp_float(T d)
-{
-    if (std::isnan(d) || std::numeric_limits<T>::infinity() == d)
-    {
-        return std::numeric_limits<T>::max();
-    }
-    if (-std::numeric_limits<T>::infinity() == d)
-    {
-        return std::numeric_limits<T>::lowest();
-    }
-
-    return d;
-}
-
-template <typename... Args> osrm::json::Array make_array(Args... args)
-{
-    osrm::json::Array a;
-    append_to_container(a.values, args...);
-    return a;
-}
-
-template <typename T> osrm::json::Array make_array(const std::vector<T> &vector)
-{
-    osrm::json::Array a;
-    for (const auto &v : vector)
-    {
-        a.values.emplace_back(v);
-    }
-    return a;
-}
-
-// template specialization needed as clang does not play nice
-template <> osrm::json::Array make_array(const std::vector<bool> &vector)
-{
-    osrm::json::Array a;
-    for (const bool v : vector)
-    {
-        a.values.emplace_back(v);
-    }
-    return a;
-}
-
-// Easy acces to object hierachies
-osrm::json::Value &get(osrm::json::Value &value) { return value; }
-
-template <typename... Keys>
-osrm::json::Value &get(osrm::json::Value &value, const char *key, Keys... keys)
-{
-    using recursive_object_t = mapbox::util::recursive_wrapper<osrm::json::Object>;
-    return get(value.get<recursive_object_t>().get().values[key], keys...);
-}
-
-template <typename... Keys>
-osrm::json::Value &get(osrm::json::Value &value, unsigned key, Keys... keys)
-{
-    using recursive_array_t = mapbox::util::recursive_wrapper<osrm::json::Array>;
-    return get(value.get<recursive_array_t>().get().values[key], keys...);
-}
-
-} // namespace json
-} // namespace osrm
-#endif // JSON_UTIL_HPP
diff --git a/util/lua_util.hpp b/util/lua_util.hpp
deleted file mode 100644
index 6dbdc8b..0000000
--- a/util/lua_util.hpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 LUA_UTIL_HPP
-#define LUA_UTIL_HPP
-
-extern "C" {
-#include <lua.h>
-#include <lauxlib.h>
-#include <lualib.h>
-}
-
-#include <boost/filesystem/convenience.hpp>
-#include <luabind/luabind.hpp>
-
-#include <iostream>
-#include <string>
-
-template <typename T> void LUA_print(T output) { std::cout << "[LUA] " << output << std::endl; }
-
-// Check if the lua function <name> is defined
-inline bool lua_function_exists(lua_State *lua_state, const char *name)
-{
-    luabind::object globals_table = luabind::globals(lua_state);
-    luabind::object lua_function = globals_table[name];
-    return lua_function && (luabind::type(lua_function) == LUA_TFUNCTION);
-}
-
-// Add the folder contain the script to the lua load path, so script can easily require() other lua
-// scripts inside that folder, or subfolders.
-// See http://lua-users.org/wiki/PackagePath for details on the package.path syntax.
-inline void luaAddScriptFolderToLoadPath(lua_State *lua_state, const char *file_name)
-{
-    boost::filesystem::path profile_path = boost::filesystem::canonical(file_name);
-    std::string folder = profile_path.parent_path().string();
-    // TODO: This code is most probably not Windows safe since it uses UNIX'ish path delimiters
-    const std::string lua_code = "package.path = \"" + folder + "/?.lua;\" .. package.path";
-    luaL_dostring(lua_state, lua_code.c_str());
-}
-
-#endif // LUA_UTIL_HPP
diff --git a/util/matching_debug_info.hpp b/util/matching_debug_info.hpp
deleted file mode 100644
index 28bc6ee..0000000
--- a/util/matching_debug_info.hpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 MATCHING_DEBUG_INFO_HPP
-#define MATCHING_DEBUG_INFO_HPP
-
-#include "json_logger.hpp"
-#include "json_util.hpp"
-#include "../data_structures/hidden_markov_model.hpp"
-
-#include <osrm/coordinate.hpp>
-
-// Provides the debug interface for introspection tools
-struct MatchingDebugInfo
-{
-    MatchingDebugInfo(const osrm::json::Logger *logger) : logger(logger)
-    {
-        if (logger)
-        {
-            object = &logger->map->at("matching");
-        }
-    }
-
-    template <class CandidateLists> void initialize(const CandidateLists &candidates_list)
-    {
-        // json logger not enabled
-        if (!logger)
-        {
-            return;
-        }
-
-        osrm::json::Array states;
-        for (auto &elem : candidates_list)
-        {
-            osrm::json::Array timestamps;
-            for (auto &elem_s : elem)
-            {
-                osrm::json::Object state;
-                state.values["transitions"] = osrm::json::Array();
-                state.values["coordinate"] =
-                    osrm::json::make_array(elem_s.phantom_node.location.lat / COORDINATE_PRECISION,
-                                           elem_s.phantom_node.location.lon / COORDINATE_PRECISION);
-                state.values["viterbi"] =
-                    osrm::json::clamp_float(osrm::matching::IMPOSSIBLE_LOG_PROB);
-                state.values["pruned"] = 0u;
-                timestamps.values.push_back(state);
-            }
-            states.values.push_back(timestamps);
-        }
-        osrm::json::get(*object, "states") = states;
-    }
-
-    void add_transition_info(const unsigned prev_t,
-                             const unsigned current_t,
-                             const unsigned prev_state,
-                             const unsigned current_state,
-                             const double prev_viterbi,
-                             const double emission_pr,
-                             const double transition_pr,
-                             const double network_distance,
-                             const double haversine_distance)
-    {
-        // json logger not enabled
-        if (!logger)
-        {
-            return;
-        }
-
-        osrm::json::Object transistion;
-        transistion.values["to"] = osrm::json::make_array(current_t, current_state);
-        transistion.values["properties"] = osrm::json::make_array(
-            osrm::json::clamp_float(prev_viterbi), osrm::json::clamp_float(emission_pr),
-            osrm::json::clamp_float(transition_pr), network_distance, haversine_distance);
-
-        osrm::json::get(*object, "states", prev_t, prev_state, "transitions")
-            .get<mapbox::util::recursive_wrapper<osrm::json::Array>>()
-            .get()
-            .values.push_back(transistion);
-    }
-
-    void set_viterbi(const std::vector<std::vector<double>> &viterbi,
-                     const std::vector<std::vector<bool>> &pruned,
-                     const std::vector<std::vector<bool>> &suspicious)
-    {
-        // json logger not enabled
-        if (!logger)
-        {
-            return;
-        }
-
-        for (auto t = 0u; t < viterbi.size(); t++)
-        {
-            for (auto s_prime = 0u; s_prime < viterbi[t].size(); ++s_prime)
-            {
-                osrm::json::get(*object, "states", t, s_prime, "viterbi") =
-                    osrm::json::clamp_float(viterbi[t][s_prime]);
-                osrm::json::get(*object, "states", t, s_prime, "pruned") =
-                    static_cast<unsigned>(pruned[t][s_prime]);
-                osrm::json::get(*object, "states", t, s_prime, "suspicious") =
-                    static_cast<unsigned>(suspicious[t][s_prime]);
-            }
-        }
-    }
-
-    void add_chosen(const unsigned t, const unsigned s)
-    {
-        // json logger not enabled
-        if (!logger)
-        {
-            return;
-        }
-
-        osrm::json::get(*object, "states", t, s, "chosen") = true;
-    }
-
-    void add_breakage(const std::vector<bool> &breakage)
-    {
-        // json logger not enabled
-        if (!logger)
-        {
-            return;
-        }
-
-        osrm::json::get(*object, "breakage") = osrm::json::make_array(breakage);
-    }
-
-    const osrm::json::Logger *logger;
-    osrm::json::Value *object;
-};
-
-#endif // MATCHING_DEBUG_INFO_HPP
diff --git a/util/mercator.cpp b/util/mercator.cpp
deleted file mode 100644
index 0ccd999..0000000
--- a/util/mercator.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "mercator.hpp"
-
-#include <cmath>
-
-double mercator::y2lat(const double value) noexcept
-{
-    return 180. * M_1_PI * (2. * std::atan(std::exp(value * M_PI / 180.)) - M_PI_2);
-}
-
-double mercator::lat2y(const double latitude) noexcept
-{
-    return 180. * M_1_PI * std::log(std::tan(M_PI_4 + latitude * (M_PI / 180.) / 2.));
-}
diff --git a/util/mercator.hpp b/util/mercator.hpp
deleted file mode 100644
index e994c84..0000000
--- a/util/mercator.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 MERCATOR_HPP
-#define MERCATOR_HPP
-
-struct mercator
-{
-    static double y2lat(const double value) noexcept;
-
-    static double lat2y(const double latitude) noexcept;
-};
-
-#endif // MERCATOR_HPP
diff --git a/util/osrm_exception.cpp b/util/osrm_exception.cpp
deleted file mode 100644
index 9738b8e..0000000
--- a/util/osrm_exception.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 "osrm_exception.hpp"
-
-namespace osrm
-{
-// 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 {}
-}
diff --git a/util/routed_options.hpp b/util/routed_options.hpp
deleted file mode 100644
index bfe8e5c..0000000
--- a/util/routed_options.hpp
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 ROUTED_OPTIONS_HPP
-#define ROUTED_OPTIONS_HPP
-
-#include "util/version.hpp"
-#include "ini_file.hpp"
-#include "osrm_exception.hpp"
-#include "simple_logger.hpp"
-
-#include <boost/any.hpp>
-#include <boost/program_options.hpp>
-
-#include <unordered_map>
-#include <fstream>
-#include <string>
-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(std::unordered_map<std::string, boost::filesystem::path> &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["coredata"] = base_string + ".core";
-        BOOST_ASSERT(server_paths.find("coredata") != 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))
-    {
-        throw osrm::exception(".hsgr not found");
-    }
-
-    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[],
-                             std::unordered_map<std::string, boost::filesystem::path> &paths,
-                             std::string &ip_address,
-                             int &ip_port,
-                             int &requested_num_threads,
-                             bool &use_shared_memory,
-                             bool &trial,
-                             int &max_locations_trip,
-                             int &max_locations_viaroute,
-                             int &max_locations_distance_table,
-                             int &max_locations_map_matching)
-{
-    using boost::program_options::value;
-    using boost::filesystem::path;
-
-    // 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", value<boost::filesystem::path>(&paths["config"])->default_value("server.ini"),
-         "Path to a configuration file") //
-        ("trial", value<bool>(&trial)->implicit_value(true), "Quit after initialization");
-
-    // declare a group of options that will be allowed both on command line
-    // as well as in a config file
-    boost::program_options::options_description config_options("Configuration");
-    config_options.add_options()                                                             //
-        ("hsgrdata", value<boost::filesystem::path>(&paths["hsgrdata"]), ".hsgr file")       //
-        ("nodesdata", value<boost::filesystem::path>(&paths["nodesdata"]), ".nodes file")    //
-        ("edgesdata", value<boost::filesystem::path>(&paths["edgesdata"]), ".edges file")    //
-        ("geometry", value<boost::filesystem::path>(&paths["geometries"]), ".geometry file") //
-        ("ramindex", value<boost::filesystem::path>(&paths["ramindex"]), ".ramIndex file")   //
-        ("fileindex", value<boost::filesystem::path>(&paths["fileindex"]),
-         "File index file") //
-        ("namesdata", value<boost::filesystem::path>(&paths["namesdata"]),
-         ".names file") //
-        ("timestamp", value<boost::filesystem::path>(&paths["timestamp"]),
-         ".timestamp file") //
-        ("ip,i", value<std::string>(&ip_address)->default_value("0.0.0.0"),
-         "IP address") //
-        ("port,p", value<int>(&ip_port)->default_value(5000),
-         "TCP/IP port") //
-        ("threads,t", value<int>(&requested_num_threads)->default_value(8),
-         "Number of threads to use") //
-        ("shared-memory,s",
-         value<bool>(&use_shared_memory)->implicit_value(true)->default_value(false),
-         "Load data from shared memory") //
-        ("max-viaroute-size", value<int>(&max_locations_viaroute)->default_value(500),
-         "Max. locations supported in viaroute query") //
-        ("max-trip-size", value<int>(&max_locations_trip)->default_value(100),
-         "Max. locations supported in trip query") //
-        ("max-table-size", value<int>(&max_locations_distance_table)->default_value(100),
-         "Max. locations supported in distance table query") //
-        ("max-matching-size", value<int>(&max_locations_map_matching)->default_value(100),
-         "Max. locations supported in map matching query");
-
-    // 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()("base,b", value<boost::filesystem::path>(&paths["base"]),
-                                 "base path to .osrm file");
-
-    // positional option
-    boost::program_options::positional_options_description positional_options;
-    positional_options.add("base", 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]) + " <base.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() << OSRM_VERSION;
-        return INIT_OK_DO_NOT_START_ENGINE;
-    }
-
-    if (option_variables.count("help"))
-    {
-        SimpleLogger().Write() << visible_options;
-        return INIT_OK_DO_NOT_START_ENGINE;
-    }
-
-    boost::program_options::notify(option_variables);
-
-    // parse config file
-    auto path_iterator = paths.find("config");
-    if (path_iterator != paths.end() && boost::filesystem::is_regular_file(path_iterator->second) &&
-        !option_variables.count("base"))
-    {
-        SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string();
-        std::string ini_file_contents = read_file_lower_content(path_iterator->second);
-        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);
-        return INIT_OK_START_ENGINE;
-    }
-
-    if (1 > requested_num_threads)
-    {
-        throw osrm::exception("Number of threads must be a positive number");
-    }
-    if (2 > max_locations_distance_table)
-    {
-        throw osrm::exception("Max location for distance table must be at least two");
-    }
-    if (2 > max_locations_map_matching)
-    {
-        throw osrm::exception("Max location for map matching must be at least two");
-    }
-
-    if (!use_shared_memory && option_variables.count("base"))
-    {
-        return INIT_OK_START_ENGINE;
-    }
-    else if (use_shared_memory && !option_variables.count("base"))
-    {
-        return INIT_OK_START_ENGINE;
-    }
-    else if (use_shared_memory && option_variables.count("base"))
-    {
-        SimpleLogger().Write(logWARNING) << "Shared memory settings conflict with path settings.";
-    }
-
-    SimpleLogger().Write() << visible_options;
-    return INIT_OK_DO_NOT_START_ENGINE;
-}
-
-#endif // ROUTED_OPTIONS_HPP
diff --git a/util/simple_logger.hpp b/util/simple_logger.hpp
deleted file mode 100644
index df61a9d..0000000
--- a/util/simple_logger.hpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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_HPP
-#define SIMPLE_LOGGER_HPP
-
-#include <atomic>
-#include <mutex>
-#include <sstream>
-
-enum LogLevel
-{
-    logINFO,
-    logWARNING,
-    logDEBUG
-};
-
-class LogPolicy
-{
-  public:
-    void Unmute();
-
-    void Mute();
-
-    bool IsMute() const;
-
-    static LogPolicy &GetInstance();
-
-    LogPolicy(const LogPolicy &) = delete;
-
-  private:
-    LogPolicy() : m_is_mute(true) {}
-    std::atomic<bool> m_is_mute;
-};
-
-class SimpleLogger
-{
-  public:
-    SimpleLogger();
-
-    virtual ~SimpleLogger();
-    std::mutex &get_mutex();
-    std::ostringstream &Write(LogLevel l = logINFO) noexcept;
-
-  private:
-    std::ostringstream os;
-    LogLevel level;
-};
-
-#endif /* SIMPLE_LOGGER_HPP */
diff --git a/util/std_hash.hpp b/util/std_hash.hpp
deleted file mode 100644
index 9e78fcc..0000000
--- a/util/std_hash.hpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 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> void hash_combine(std::size_t &seed, const T &val)
-{
-    seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
-}
-
-template <typename T> void hash_val(std::size_t &seed, const T &val) { hash_combine(seed, val); }
-
-template <typename T, typename... Types>
-void hash_val(std::size_t &seed, const T &val, const Types &... args)
-{
-    hash_combine(seed, val);
-    hash_val(seed, args...);
-}
-
-template <typename... Types> std::size_t hash_val(const Types &... args)
-{
-    std::size_t seed = 0;
-    hash_val(seed, args...);
-    return seed;
-}
-}
-
-namespace std
-{
-template <typename T1, typename T2> struct hash<std::pair<T1, T2>>
-{
-    size_t operator()(const std::pair<T1, T2> &pair) const
-    {
-        return hash_val(pair.first, pair.second);
-    }
-};
-}
-
-#endif // STD_HASH_HPP
diff --git a/util/version.hpp.in b/util/version.hpp.in
deleted file mode 100644
index 2eafd48..0000000
--- a/util/version.hpp.in
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-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 VERSION_HPP
-#define VERSION_HPP
-
-#define OSRM_VERSION_MAJOR "@OSRM_VERSION_MAJOR@"
-#define OSRM_VERSION_MINOR "@OSRM_VERSION_MINOR@"
-#define OSRM_VERSION_PATCH "@OSRM_VERSION_PATCH@"
-
-#define OSRM_VERSION "v" OSRM_VERSION_MAJOR "." OSRM_VERSION_MINOR "." OSRM_VERSION_PATCH
-
-#endif // VERSION_HPP
diff --git a/util/xml_renderer.hpp b/util/xml_renderer.hpp
deleted file mode 100644
index 44f7c2d..0000000
--- a/util/xml_renderer.hpp
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-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 "cast.hpp"
-
-#include <osrm/json_container.hpp>
-
-namespace osrm
-{
-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::to_string_with_precision(number.value);
-        out.insert(out.end(), number_string.begin(), number_string.end());
-    }
-
-    void operator()(const Object &object) const
-    {
-        for (auto &&each : object.values)
-        {
-            if (each.first.at(0) != '_')
-            {
-                out.push_back('<');
-                out.insert(out.end(), each.first.begin(), each.first.end());
-            }
-            else
-            {
-                out.push_back(' ');
-                out.insert(out.end(), ++(each).first.begin(), each.first.end());
-                out.push_back('=');
-            }
-            mapbox::util::apply_visitor(XMLToArrayRenderer(out), each.second);
-            if (each.first.at(0) != '_')
-            {
-                out.push_back('/');
-                out.push_back('>');
-            }
-        }
-    }
-
-    void operator()(const Array &array) const
-    {
-        for (auto &&each : array.values)
-        {
-            mapbox::util::apply_visitor(XMLToArrayRenderer(out), each);
-        }
-    }
-
-    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
-} // namespace osrm
-#endif // XML_RENDERER_HPP

-- 
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