[osrm] 02/07: Imported Upstream version 4.7.0

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Sat Aug 22 19:42:33 UTC 2015


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

sebastic pushed a commit to branch master
in repository osrm.

commit 3d1b3188669c69d362a3e7f6d6fe4dead9ebdaf5
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Sat Aug 22 20:03:20 2015 +0200

    Imported Upstream version 4.7.0
---
 .gitignore                                         |   4 +
 .travis.yml                                        |   3 +-
 CMakeLists.txt                                     |   8 +-
 Gemfile.lock                                       |  27 +-
 README.md                                          |  31 +-
 algorithms/polyline_compressor.cpp                 |  38 +
 algorithms/polyline_compressor.hpp                 |   4 +
 algorithms/tiny_components.hpp                     |   2 +-
 appveyor-build.bat                                 | 113 +++
 appveyor.yml                                       |  43 +-
 build-local.bat                                    |  19 +
 contractor/contractor.hpp                          |   5 +-
 contractor/contractor_options.cpp                  | 135 ++++
 .../contractor_options.hpp                         |  27 +-
 contractor/edge_based_graph_factory.cpp            |  90 ++-
 contractor/edge_based_graph_factory.hpp            |  17 +-
 contractor/processing_chain.cpp                    | 507 +++++--------
 contractor/processing_chain.hpp                    |  58 +-
 data_structures/dynamic_graph.hpp                  |   3 +
 data_structures/import_edge.cpp                    |   7 +
 data_structures/import_edge.hpp                    |   5 +-
 data_structures/node_based_graph.hpp               | 268 +++----
 data_structures/restriction_map.hpp                |   7 +-
 data_structures/route_parameters.cpp               |   8 +
 data_structures/static_rtree.hpp                   |  39 +-
 datastore.cpp                                      |   5 +-
 descriptors/description_factory.cpp                |   7 +-
 extract.cpp                                        |   2 +-
 extractor/extraction_containers.cpp                | 841 +++++++++++++--------
 extractor/extraction_containers.hpp                |  17 +-
 extractor/extraction_helper_functions.hpp          |   2 +-
 extractor/extractor.cpp                            |  21 +-
 extractor/extractor.hpp                            |   9 +-
 extractor/extractor_callbacks.cpp                  |  74 +-
 extractor/extractor_options.cpp                    |   4 +
 extractor/extractor_options.hpp                    |   1 +
 extractor/internal_extractor_edge.hpp              | 112 +--
 extractor/restriction_parser.cpp                   |   2 +-
 extractor/scripting_environment.cpp                |   2 +-
 features/bicycle/access.feature                    |   6 +-
 features/bicycle/access_node.feature               |  35 +-
 features/bicycle/surface.feature                   |   2 +-
 features/car/maxspeed.feature                      |  19 +
 features/car/names.feature                         |  10 +-
 features/foot/access.feature                       |   4 +-
 features/foot/access_node.feature                  |   4 +-
 features/foot/surface.feature                      |   2 +-
 features/foot/way.feature                          |   6 +
 features/nearest/pick.feature                      |  20 +-
 features/options/prepare/help.feature              |   2 +-
 features/step_definitions/data.rb                  |   4 +
 features/step_definitions/distance_matrix.rb       |   2 +-
 features/step_definitions/locate.rb                |   4 +-
 features/step_definitions/matching.rb              |   2 +-
 features/step_definitions/nearest.rb               |   4 +-
 features/step_definitions/routability.rb           |   2 +-
 features/step_definitions/routing.rb               |   2 +-
 features/support/cucumber.rb                       |  76 --
 features/support/env.rb                            |  10 +-
 features/support/hooks.rb                          |  16 +-
 features/support/http.rb                           |  34 +
 features/support/locate.rb                         |  17 +-
 features/support/match.rb                          |  12 +-
 features/support/nearest.rb                        |  17 +-
 features/support/route.rb                          |  14 +-
 features/testbot/ferry.feature                     |  30 +
 features/testbot/loop.feature                      |  19 +
 features/testbot/post.feature                      | 100 +++
 features/testbot/snap.feature                      |  42 +-
 features/testbot/via.feature                       |  22 +-
 include/osrm/route_parameters.hpp                  |   2 +
 prepare.cpp                                        |  70 +-
 profiles/bicycle.lua                               | 123 +--
 profiles/car.lua                                   |  60 +-
 profiles/foot.lua                                  | 291 +++----
 profiles/lib/access.lua                            |   8 +-
 profiles/lib/maxspeed.lua                          |   6 +-
 routing_algorithms/alternative_path.hpp            |   4 +-
 routing_algorithms/shortest_path.hpp               |   6 +-
 server/api_grammar.hpp                             |   7 +-
 server/request_parser.cpp                          |  71 +-
 server/request_parser.hpp                          |   8 +-
 tools/components.cpp                               | 142 ++--
 tools/graph_compare.cpp                            | 199 -----
 unit_tests/algorithms/duration_parsing.cpp         |  24 +-
 unit_tests/algorithms/geometry_string.cpp          |  74 ++
 util/fingerprint.hpp                               |  13 +-
 util/fingerprint_impl.hpp.in                       |  45 +-
 util/graph_loader.hpp                              | 444 ++---------
 util/iso_8601_duration_parser.hpp                  |   2 +-
 util/lua_util.hpp                                  |   5 +-
 91 files changed, 2460 insertions(+), 2250 deletions(-)

diff --git a/.gitignore b/.gitignore
index 6ed5d2a..6264b42 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,7 @@
+# pre compiled dependencies #
+#############################
+osrm-deps
+
 # Compiled source #
 ###################
 *.com
diff --git a/.travis.yml b/.travis.yml
index ed023e4..55e7190 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,6 +30,7 @@ script:
  - make
  - make tests
  - make benchmarks
+ - ./algorithm-tests
  - ./datastructure-tests
  - cd ..
  - cucumber -p verify
@@ -58,7 +59,7 @@ notifications:
   skip_join: false
 
   recipients:
-    - dennis at mapbox.com
+    - patrick at mapbox.com
   email:
     on_success: change
     on_failure: always
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 503171a..80eb3d3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -90,7 +90,7 @@ set(
 
 add_library(COORDINATE OBJECT ${CoordinateGlob})
 add_library(GITDESCRIPTION OBJECT util/git_sha.cpp)
-add_library(OSRM ${OSRMSources} $<TARGET_OBJECTS:ANGLE> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
+add_library(OSRM ${OSRMSources} $<TARGET_OBJECTS:ANGLE> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR> $<TARGET_OBJECTS:IMPORT>)
 
 add_library(FINGERPRINT OBJECT util/fingerprint.cpp)
 add_dependencies(FINGERPRINT FingerPrintConfigure)
@@ -328,12 +328,10 @@ if(WITH_TOOLS OR BUILD_TOOLS)
   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_link_libraries(osrm-check-hsgr ${Boost_LIBRARIES})
+  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:GITDESCRIPTION> $<TARGET_OBJECTS:EXCEPTION>)
   target_link_libraries(osrm-springclean ${Boost_LIBRARIES})
-  add_executable(osrm-graph-compare tools/graph_compare.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
-  target_link_libraries(osrm-graph-compare ${Boost_LIBRARIES} ${TBB_LIBRARIES})
 
   install(TARGETS osrm-cli DESTINATION bin)
   install(TARGETS osrm-io-benchmark DESTINATION bin)
diff --git a/Gemfile.lock b/Gemfile.lock
index ac056a0..3363e92 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -2,22 +2,27 @@ GEM
   remote: http://rubygems.org/
   specs:
     builder (3.2.2)
-    cucumber (1.3.8)
+    cucumber (2.0.0)
       builder (>= 2.1.2)
+      cucumber-core (~> 1.1.3)
       diff-lcs (>= 1.1.3)
-      gherkin (~> 2.12.1)
+      gherkin (~> 2.12)
       multi_json (>= 1.7.5, < 2.0)
-      multi_test (>= 0.0.2)
-    diff-lcs (1.2.4)
-    gherkin (2.12.1)
+      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.8.0)
-    multi_test (0.0.2)
+    multi_json (1.11.0)
+    multi_test (0.1.2)
     osmlib-base (0.1.4)
-    rake (10.1.0)
-    rspec-expectations (2.14.3)
-      diff-lcs (>= 1.1.3, < 2.0)
-    sys-proctable (0.9.3)
+    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
diff --git a/README.md b/README.md
index 624cc1d..d319d26 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,25 @@
-# Readme
+## About
 
-For instructions on how to compile and run OSRM, please consult the Wiki at
+The Open Source Routing Machine is a high performance routing engine written in C++11 designed to run on OpenStreetMap data.
 
-https://github.com/Project-OSRM/osrm-backend/wiki
+## Current build status
+
+| build config |  branch | status |
+|:-------------|:--------|:------------|
+| Linux        | master  | [![Build Status](https://travis-ci.org/Project-OSRM/osrm-backend.png?branch=master)](https://travis-ci.org/Project-OSRM/osrm-backend) |
+| Linux        | develop | [![Build Status](https://travis-ci.org/Project-OSRM/osrm-backend.png?branch=develop)](https://travis-ci.org/Project-OSRM/osrm-backend) |
+| Windows      | master/develop | [![Build status](https://ci.appveyor.com/api/projects/status/4iuo3s9gxprmcjjh)](https://ci.appveyor.com/project/DennisOSRM/osrm-backend) |
+| LUAbind fork | master  | [![Build Status](https://travis-ci.org/DennisOSRM/luabind.png?branch=master)](https://travis-ci.org/DennisOSRM/luabind) |
+
+## Building
+
+For instructions on how to [build](https://github.com/Project-OSRM/osrm-backend/wiki/Building-OSRM) and [run OSRM](https://github.com/Project-OSRM/osrm-backend/wiki/Running-OSRM), please consult [the Wiki](https://github.com/Project-OSRM/osrm-backend/wiki).
 
-or use our free and daily updated online service at
+To quickly try OSRM use our [free and daily updated online service](http://map.project-osrm.org)
 
-http://map.project-osrm.org
+## Documentation
+
+See the Wiki's [server API documentation](https://github.com/Project-OSRM/osrm-backend/wiki/Server-api) as well as the [library API documentation](https://github.com/Project-OSRM/osrm-backend/wiki/Library-api)
 
 ## References in publications
 
@@ -31,11 +44,3 @@ When using the code in a (scientific) publication, please cite
 }
 ```
 
-## Current build status
-
-| build config |  branch | status |
-|:-------------|:--------|:------------|
-| Linux        | master  | [![Build Status](https://travis-ci.org/Project-OSRM/osrm-backend.png?branch=master)](https://travis-ci.org/DennisOSRM/Project-OSRM) |
-| Linux        | develop | [![Build Status](https://travis-ci.org/Project-OSRM/osrm-backend.png?branch=develop)](https://travis-ci.org/DennisOSRM/Project-OSRM) |
-| Windows      | master/develop | [![Build status](https://ci.appveyor.com/api/projects/status/4iuo3s9gxprmcjjh)](https://ci.appveyor.com/project/DennisOSRM/osrm-backend) |
-| LUAbind fork | master  | [![Build Status](https://travis-ci.org/DennisOSRM/luabind.png?branch=master)](https://travis-ci.org/DennisOSRM/luabind) |
diff --git a/algorithms/polyline_compressor.cpp b/algorithms/polyline_compressor.cpp
index d5fd582..0db75dc 100644
--- a/algorithms/polyline_compressor.cpp
+++ b/algorithms/polyline_compressor.cpp
@@ -88,3 +88,41 @@ PolylineCompressor::get_encoded_string(const std::vector<SegmentInformation> &po
     }
     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
index 933ac7a..a148200 100644
--- a/algorithms/polyline_compressor.hpp
+++ b/algorithms/polyline_compressor.hpp
@@ -30,6 +30,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct SegmentInformation;
 
+#include <osrm/coordinate.hpp>
+
 #include <string>
 #include <vector>
 
@@ -42,6 +44,8 @@ class PolylineCompressor
 
   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/tiny_components.hpp b/algorithms/tiny_components.hpp
index 8eb61a9..8abc1cb 100644
--- a/algorithms/tiny_components.hpp
+++ b/algorithms/tiny_components.hpp
@@ -150,7 +150,7 @@ template <typename GraphT> class TarjanSCC
                         // Traverse outgoing edges
                         if (barrier_node_set.find(v) != barrier_node_set.end() && u != vprime)
                         {
-                            // continue;
+                            continue;
                         }
 
                         if (to_node_of_only_restriction != std::numeric_limits<unsigned>::max() &&
diff --git a/appveyor-build.bat b/appveyor-build.bat
new file mode 100644
index 0000000..eef29b1
--- /dev/null
+++ b/appveyor-build.bat
@@ -0,0 +1,113 @@
+ at ECHO OFF
+SETLOCAL
+SET EL=0
+
+ECHO platform^: %platform%
+:: 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
+IF "%computername%"=="MB" GOTO SKIPDL
+
+IF EXIST %DEPSPKG% DEL %DEPSPKG%
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+ECHO downloading %DEPSPKG%
+powershell Invoke-WebRequest https://mapbox.s3.amazonaws.com/windows-builds/windows-deps/$env:DEPSPKG -OutFile C:\projects\osrm\$env:DEPSPKG
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+7z -y x %DEPSPKG% | %windir%\system32\FIND "ing archive"
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+:SKIPDL
+
+IF EXIST build rd /s /q build
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+mkdir build
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+cd build
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+SET OSRMDEPSDIR=c:\projects\osrm\osrm-deps
+set PREFIX=%OSRMDEPSDIR%/libs
+set BOOST_ROOT=%OSRMDEPSDIR%/boost
+set TBB_INSTALL_DIR=%OSRMDEPSDIR%/tbb
+set TBB_ARCH_PLATFORM=intel64/vc14
+
+ECHO calling cmake ....
+cmake .. ^
+-G "Visual Studio 14 Win64" ^
+-DBOOST_ROOT=%BOOST_ROOT% ^
+-DBoost_ADDITIONAL_VERSIONS=1.57 ^
+-DBoost_USE_MULTITHREADED=ON ^
+-DBoost_USE_STATIC_LIBS=ON ^
+-DCMAKE_BUILD_TYPE=%CONFIGURATION% ^
+-DCMAKE_INSTALL_PREFIX=%PREFIX%
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+ECHO building ...
+msbuild OSRM.sln ^
+/p:Configuration=%Configuration% ^
+/p:Platform=x64 ^
+/t:rebuild ^
+/p:BuildInParallel=true ^
+/m:%NUMBER_OF_PROCESSORS% ^
+/toolsversion:14.0 ^
+/p:PlatformToolset=v140 ^
+/clp:Verbosity=normal ^
+/nologo ^
+/flp1:logfile=build_errors.txt;errorsonly ^
+/flp2:logfile=build_warnings.txt;warningsonly
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+ECHO ========= TODO^: CREATE PACKAGES ==========
+
+CD c:\projects\osrm\build\%Configuration%
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+SET PATH=c:\projects\osrm\osrm-deps\libs\bin;%PATH%
+
+ECHO running datastructure-tests.exe ...
+datastructure-tests.exe
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+ECHO running algorithm-tests.exe ...
+algorithm-tests.exe
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+GOTO DONE
+
+:ERROR
+SET EL=%ERRORLEVEL%
+ECHO ============== ERROR ===============
+
+:DONE
+ECHO ============= DONE ===============
+CD C:\projects\osrm
+EXIT /b %EL%
+
+
+
+
+  - cd c:/projects/osrm
+  - mkdir build
+  - cd build
+  - echo Running cmake...
+  - call "%VS120COMNTOOLS%\..\..\VC\vcvarsall.bat" x86_amd64
+  - SET PATH=C:\Program Files (x86)\MSBuild\12.0\bin\;%PATH%
+  - SET P=c:/projects/osrm
+  - set TBB_INSTALL_DIR=%P%/tbb
+  - set TBB_ARCH_PLATFORM=intel64/vc12
+  - cmake .. -G "Visual Studio 14 Win64" -DCMAKE_BUILD_TYPE=%Configuration% -DCMAKE_INSTALL_PREFIX=%P%/libs -DBOOST_ROOT=%P%/boost_min -DBoost_ADDITIONAL_VERSIONS=1.57 -DBoost_USE_STATIC_LIBS=ON
+  - SET PLATFORM_TOOLSET=v140
+  - SET TOOLS_VERSION=14.0
+  - msbuild /p:Platform=x64 /clp:Verbosity=minimal /toolsversion:%TOOLS_VERSION% /p:PlatformToolset=%PLATFORM_TOOLSET% /nologo OSRM.sln
+  - msbuild /p:Platform=x64 /clp:Verbosity=minimal /toolsversion:%TOOLS_VERSION% /p:PlatformToolset=%PLATFORM_TOOLSET% /nologo tests.vcxproj
+  - cd %Configuration%
+  - if "%APPVEYOR_REPO_BRANCH%"=="develop" (7z a %P%/osrm_%Configuration%.zip *.exe *.pdb %P%/libs/bin/*.dll -tzip)
+  - cd ..\..\profiles
+  - echo disk=c:\temp\stxxl,10000,wincall > .stxxl.txt
+  - if "%APPVEYOR_REPO_BRANCH%"=="develop" (7z a %P%/osrm_%Configuration%.zip * -tzip)
+  - set PATH=%PATH%;c:/projects/osrm/libs/bin
+  - cd c:/projects/osrm/build/%Configuration%
+  - datastructure-tests.exe
+  - algorithm-tests.exe
diff --git a/appveyor.yml b/appveyor.yml
index afb8dd4..cf45a32 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,60 +1,33 @@
 environment:
   matrix:
-  - configuration: Debug
   - configuration: Release
-
-# branches to build
-branches:
-  # whitelist
-  only:
-    - develop
+#  - configuration: Debug
 
 # scripts that are called at very beginning, before repo cloning
 init:
   - git config --global core.autocrlf input
 
+os: Visual Studio 2015 RC
+
 # clone directory
 clone_folder: c:\projects\osrm
 
 platform: x64
 
 install:
-  # by default, all script lines are interpreted as batch
-  - nuget install protobuf
-  - cd c:\projects\osrm
-  - curl -O http://build.project-osrm.org/libs_osrm_%Configuration%.7z
-  - 7z x libs_osrm_%Configuration%.7z | find ":"
+  - 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
 
 build_script:
-  - cd c:/projects/osrm
-  - mkdir build
-  - cd build
-  - echo Running cmake...
-  - call "%VS120COMNTOOLS%\..\..\VC\vcvarsall.bat" x86_amd64
-  - SET PATH=C:\Program Files (x86)\MSBuild\12.0\bin\;%PATH%
-  - SET P=c:/projects/osrm
-  - set TBB_INSTALL_DIR=%P%/tbb
-  - set TBB_ARCH_PLATFORM=intel64/vc12
-  - cmake .. -G "Visual Studio 12 Win64" -DCMAKE_BUILD_TYPE=%Configuration% -DCMAKE_INSTALL_PREFIX=%P%/libs -DBOOST_ROOT=%P%/boost_min -DBoost_ADDITIONAL_VERSIONS=1.57 -DBoost_USE_STATIC_LIBS=ON -T CTP_Nov2013
-  - msbuild /clp:Verbosity=minimal /nologo OSRM.sln
-  - msbuild /clp:Verbosity=minimal /nologo tests.vcxproj
-  - cd %Configuration%
-  - if "%APPVEYOR_REPO_BRANCH%"=="develop" (7z a %P%/osrm_%Configuration%.zip *.exe *.pdb %P%/libs/bin/*.dll -tzip)
-  - cd ..\..\profiles
-  - echo disk=c:\temp\stxxl,10000,wincall > .stxxl.txt
-  - if "%APPVEYOR_REPO_BRANCH%"=="develop" (7z a %P%/osrm_%Configuration%.zip * -tzip)
-  - set PATH=%PATH%;c:/projects/osrm/libs/bin
-  - cd c:/projects/osrm/build/%Configuration%
-  - datastructure-tests.exe
-  - algorithm-tests.exe
+  - CALL appveyor-build.bat
 
 test: off
 
 artifacts:
-  - path: osrm_Debug.zip
-    name: osrm_Debug.zip
   - path: osrm_Release.zip
     name: osrm_Release.zip
+#  - path: osrm_Debug.zip
+#    name: osrm_Debug.zip
 
 deploy:
   provider: FTP
diff --git a/build-local.bat b/build-local.bat
new file mode 100644
index 0000000..47a1fb3
--- /dev/null
+++ b/build-local.bat
@@ -0,0 +1,19 @@
+ at ECHO OFF
+
+SET PLATFORM=x64
+SET CONFIGURATION=Release
+
+WHERE msbuild
+IF %ERRORLEVEL% EQU 0 GOTO RUNBUILD
+
+SET PATH=C:\mb\windows-builds-64\tmp-bin\cmake-3.1.0-win32-x86\bin;%PATH%
+SET PATH=C:\Program Files\7-Zip;%PATH%
+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
+
+:RUNBUILD
+
+powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted -Force
+CALL appveyor-build.bat
+EXIT /b %ERRORLEVEL%
diff --git a/contractor/contractor.hpp b/contractor/contractor.hpp
index ccfabbc..4468f5e 100644
--- a/contractor/contractor.hpp
+++ b/contractor/contractor.hpp
@@ -171,7 +171,8 @@ class Contractor
             {
                 SimpleLogger().Write(logWARNING)
                     << "Edge weight large -> "
-                    << static_cast<unsigned int>(std::max(diter->weight, 1));
+                    << static_cast<unsigned int>(std::max(diter->weight, 1)) << " : "
+                    << static_cast<unsigned int>(diter->source) << " -> " << static_cast<unsigned int>(diter->target);
             }
 #endif
             edges.emplace_back(diter->source, diter->target,
@@ -186,6 +187,7 @@ class Contractor
         }
         // clear input vector
         input_edge_list.clear();
+        // FIXME not sure if we need this
         edges.shrink_to_fit();
 
         tbb::parallel_sort(edges.begin(), edges.end());
@@ -953,7 +955,6 @@ class Contractor
     }
 
     std::shared_ptr<ContractorGraph> contractor_graph;
-    std::vector<ContractorGraph::InputEdge> contracted_edge_list;
     stxxl::vector<QueryEdge> external_edge_list;
     std::vector<NodeID> orig_node_id_to_new_id_map;
     XORFastHash fast_hash;
diff --git a/contractor/contractor_options.cpp b/contractor/contractor_options.cpp
new file mode 100644
index 0000000..eaa1ba9
--- /dev/null
+++ b/contractor/contractor_options.cpp
@@ -0,0 +1,135 @@
+/*
+
+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/git_sha.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()(
+        "restrictions,r",
+        boost::program_options::value<boost::filesystem::path>(&contractor_config.restrictions_path),
+        "Restrictions file in .osrm.restrictions format")(
+        "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");
+
+    // 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() << g_GIT_DESCRIPTION;
+        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("restrictions"))
+    {
+        contractor_config.restrictions_path = contractor_config.osrm_input_path.string() + ".restrictions";
+    }
+
+    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.node_output_path = contractor_config.osrm_input_path.string() + ".nodes";
+    contractor_config.edge_output_path = contractor_config.osrm_input_path.string() + ".edges";
+    contractor_config.geometry_output_path = contractor_config.osrm_input_path.string() + ".geometry";
+    contractor_config.graph_output_path = contractor_config.osrm_input_path.string() + ".hsgr";
+    contractor_config.rtree_nodes_output_path = contractor_config.osrm_input_path.string() + ".ramIndex";
+    contractor_config.rtree_leafs_output_path = contractor_config.osrm_input_path.string() + ".fileIndex";
+}
diff --git a/extractor/extractor_options.hpp b/contractor/contractor_options.hpp
similarity index 70%
copy from extractor/extractor_options.hpp
copy to contractor/contractor_options.hpp
index 5712ea0..87541af 100644
--- a/extractor/extractor_options.hpp
+++ b/contractor/contractor_options.hpp
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 */
 
-#ifndef EXTRACTOR_OPTIONS_HPP
-#define EXTRACTOR_OPTIONS_HPP
+#ifndef CONTRACTOR_OPTIONS_HPP
+#define CONTRACTOR_OPTIONS_HPP
 
 #include <boost/filesystem/path.hpp>
 
@@ -39,25 +39,30 @@ enum class return_code : unsigned
     exit
 };
 
-struct ExtractorConfig
+struct ContractorConfig
 {
-    ExtractorConfig() noexcept : requested_num_threads(0) {}
+    ContractorConfig() noexcept : requested_num_threads(0) {}
+
     boost::filesystem::path config_file_path;
-    boost::filesystem::path input_path;
+    boost::filesystem::path osrm_input_path;
+    boost::filesystem::path restrictions_path;
     boost::filesystem::path profile_path;
 
-    std::string output_file_name;
-    std::string restriction_file_name;
-    std::string timestamp_file_name;
+    std::string node_output_path;
+    std::string edge_output_path;
+    std::string geometry_output_path;
+    std::string graph_output_path;
+    std::string rtree_nodes_output_path;
+    std::string rtree_leafs_output_path;
 
     unsigned requested_num_threads;
 };
 
-struct ExtractorOptions
+struct ContractorOptions
 {
-    static return_code ParseArguments(int argc, char *argv[], ExtractorConfig &extractor_config);
+    static return_code ParseArguments(int argc, char *argv[], ContractorConfig &extractor_config);
 
-    static void GenerateOutputFilesNames(ExtractorConfig &extractor_config);
+    static void GenerateOutputFilesNames(ContractorConfig &extractor_config);
 };
 
 #endif // EXTRACTOR_OPTIONS_HPP
diff --git a/contractor/edge_based_graph_factory.cpp b/contractor/edge_based_graph_factory.cpp
index 268bb9f..dbd73a7 100644
--- a/contractor/edge_based_graph_factory.cpp
+++ b/contractor/edge_based_graph_factory.cpp
@@ -40,21 +40,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <iomanip>
 #include <limits>
 
-EdgeBasedGraphFactory::EdgeBasedGraphFactory(
-    const std::shared_ptr<NodeBasedDynamicGraph> &node_based_graph,
-    std::unique_ptr<RestrictionMap> restriction_map,
-    std::vector<NodeID> &barrier_node_list,
-    std::vector<NodeID> &traffic_light_node_list,
-    std::vector<QueryNode> &node_info_list,
-    SpeedProfileProperties &speed_profile)
+EdgeBasedGraphFactory::EdgeBasedGraphFactory(std::shared_ptr<NodeBasedDynamicGraph> node_based_graph,
+                                   std::shared_ptr<RestrictionMap> restriction_map,
+                                   std::unique_ptr<std::vector<NodeID>> barrier_node_list,
+                                   std::unique_ptr<std::vector<NodeID>> traffic_light_node_list,
+                                   const std::vector<QueryNode> &node_info_list,
+                                   const SpeedProfileProperties &speed_profile)
     : speed_profile(speed_profile),
       m_number_of_edge_based_nodes(std::numeric_limits<unsigned>::max()),
-      m_node_info_list(node_info_list), m_node_based_graph(node_based_graph),
+      m_node_info_list(node_info_list),
+      m_node_based_graph(std::move(node_based_graph)),
       m_restriction_map(std::move(restriction_map)), max_id(0), removed_node_count(0)
 {
     // insert into unordered sets for fast lookup
-    m_barrier_nodes.insert(barrier_node_list.begin(), barrier_node_list.end());
-    m_traffic_lights.insert(traffic_light_node_list.begin(), traffic_light_node_list.end());
+    m_barrier_nodes.insert(barrier_node_list->begin(), barrier_node_list->end());
+    m_traffic_lights.insert(traffic_light_node_list->begin(), traffic_light_node_list->end());
 }
 
 void EdgeBasedGraphFactory::GetEdgeBasedEdges(DeallocatingVector<EdgeBasedEdge> &output_edge_list)
@@ -193,15 +193,16 @@ void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u,
         {
             BOOST_ASSERT(forward_data.forward);
         }
-        if (reverse_data.edgeBasedNodeID != SPECIAL_NODEID)
+        else
         {
-            BOOST_ASSERT(reverse_data.forward);
+            BOOST_ASSERT(!forward_data.forward);
         }
-        if (forward_data.edgeBasedNodeID == SPECIAL_NODEID)
+
+        if (reverse_data.edgeBasedNodeID != SPECIAL_NODEID)
         {
-            BOOST_ASSERT(!forward_data.forward);
+            BOOST_ASSERT(reverse_data.forward);
         }
-        if (reverse_data.edgeBasedNodeID == SPECIAL_NODEID)
+        else
         {
             BOOST_ASSERT(!reverse_data.forward);
         }
@@ -233,7 +234,6 @@ void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename,
                                 const std::string &geometry_filename,
                                 lua_State *lua_state)
 {
-
     TIMER_START(geometry);
     CompressGeometry();
     TIMER_STOP(geometry);
@@ -290,12 +290,33 @@ void EdgeBasedGraphFactory::CompressGeometry()
             continue;
         }
 
+        /*
+         *    reverse_e2   forward_e2
+         * u <---------- v -----------> w
+         *    ----------> <-----------
+         *    forward_e1   reverse_e1
+         *
+         * Will be compressed to:
+         *
+         *    reverse_e1
+         * u <---------- w
+         *    ---------->
+         *    forward_e1
+         *
+         * If the edges are compatible.
+         *
+         */
+
         const bool reverse_edge_order =
             !(m_node_based_graph->GetEdgeData(m_node_based_graph->BeginEdges(node_v)).forward);
         const EdgeID forward_e2 = m_node_based_graph->BeginEdges(node_v) + reverse_edge_order;
         BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
+        BOOST_ASSERT(forward_e2 >= m_node_based_graph->BeginEdges(node_v) &&
+                     forward_e2 < m_node_based_graph->EndEdges(node_v));
         const EdgeID reverse_e2 = m_node_based_graph->BeginEdges(node_v) + 1 - reverse_edge_order;
         BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2);
+        BOOST_ASSERT(reverse_e2 >= m_node_based_graph->BeginEdges(node_v) &&
+                     reverse_e2 < m_node_based_graph->EndEdges(node_v));
 
         const EdgeData &fwd_edge_data2 = m_node_based_graph->GetEdgeData(forward_e2);
         const EdgeData &rev_edge_data2 = m_node_based_graph->GetEdgeData(reverse_e2);
@@ -322,9 +343,20 @@ void EdgeBasedGraphFactory::CompressGeometry()
             continue;
         }
 
-        if ( // TODO: rename to IsCompatibleTo
-            fwd_edge_data1.IsEqualTo(fwd_edge_data2) && rev_edge_data1.IsEqualTo(rev_edge_data2))
+        // this case can happen if two ways with different names overlap
+        if (fwd_edge_data1.nameID != rev_edge_data1.nameID ||
+            fwd_edge_data2.nameID != rev_edge_data2.nameID)
         {
+            continue;
+        }
+
+        if (fwd_edge_data1.IsCompatibleTo(fwd_edge_data2) && rev_edge_data1.IsCompatibleTo(rev_edge_data2))
+        {
+            BOOST_ASSERT(m_node_based_graph->GetEdgeData(forward_e1).nameID ==
+                         m_node_based_graph->GetEdgeData(reverse_e1).nameID);
+            BOOST_ASSERT(m_node_based_graph->GetEdgeData(forward_e2).nameID ==
+                         m_node_based_graph->GetEdgeData(reverse_e2).nameID);
+
             // Get distances before graph is modified
             const int forward_weight1 = m_node_based_graph->GetEdgeData(forward_e1).distance;
             const int forward_weight2 = m_node_based_graph->GetEdgeData(forward_e2).distance;
@@ -336,7 +368,7 @@ void EdgeBasedGraphFactory::CompressGeometry()
             const int reverse_weight2 = m_node_based_graph->GetEdgeData(reverse_e2).distance;
 
             BOOST_ASSERT(0 != reverse_weight1);
-            BOOST_ASSERT(0 != forward_weight2);
+            BOOST_ASSERT(0 != reverse_weight2);
 
             const bool has_node_penalty = m_traffic_lights.find(node_v) != m_traffic_lights.end();
 
@@ -362,11 +394,11 @@ void EdgeBasedGraphFactory::CompressGeometry()
             // update any involved turn restrictions
             m_restriction_map->FixupStartingTurnRestriction(node_u, node_v, node_w);
             m_restriction_map->FixupArrivingTurnRestriction(node_u, node_v, node_w,
-                                                            m_node_based_graph);
+                                                            *m_node_based_graph);
 
             m_restriction_map->FixupStartingTurnRestriction(node_w, node_v, node_u);
             m_restriction_map->FixupArrivingTurnRestriction(node_w, node_v, node_u,
-                                                            m_node_based_graph);
+                                                            *m_node_based_graph);
 
             // store compressed geometry in container
             m_geometry_compressor.CompressEdge(
@@ -378,8 +410,7 @@ void EdgeBasedGraphFactory::CompressGeometry()
                 reverse_weight2 + (has_node_penalty ? speed_profile.traffic_signal_penalty : 0));
             ++removed_node_count;
 
-            BOOST_ASSERT(m_node_based_graph->GetEdgeData(forward_e1).nameID ==
-                         m_node_based_graph->GetEdgeData(reverse_e1).nameID);
+
         }
     }
     SimpleLogger().Write() << "removed " << removed_node_count << " nodes";
@@ -403,18 +434,19 @@ void EdgeBasedGraphFactory::CompressGeometry()
                            << new_edge_count / (double)original_number_of_edges;
 }
 
-/**
- * Writes the id of the edge in the edge expanded graph (into the edge in the node based graph)
- */
+/// Renumbers all _forward_ edges and sets the edgeBasedNodeID.
+/// A specific numbering is not important. Any unique ID will do.
 void EdgeBasedGraphFactory::RenumberEdges()
 {
-    // renumber edge based node IDs
+    // 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);
+
+            // this edge is an incoming edge
             if (!edge_data.forward)
             {
                 continue;
@@ -466,7 +498,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
             const NodeID node_v = m_node_based_graph->GetTarget(e1);
 
             BOOST_ASSERT(SPECIAL_NODEID != node_v);
-            // pick only every other edge
+            // pick only every other edge, since we have every edge as an outgoing
+            // and incoming egde
             if (node_u > node_v)
             {
                 continue;
@@ -492,6 +525,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
 
             const bool component_is_tiny = size_of_component < 1000;
 
+            // we only set edgeBasedNodeID for forward edges
             if (edge_data.edgeBasedNodeID == SPECIAL_NODEID)
             {
                 InsertEdgeBasedNode(node_v, node_u,
diff --git a/contractor/edge_based_graph_factory.hpp b/contractor/edge_based_graph_factory.hpp
index 95b65ba..a527439 100644
--- a/contractor/edge_based_graph_factory.hpp
+++ b/contractor/edge_based_graph_factory.hpp
@@ -59,12 +59,12 @@ class EdgeBasedGraphFactory
 
     struct SpeedProfileProperties;
 
-    explicit EdgeBasedGraphFactory(const std::shared_ptr<NodeBasedDynamicGraph> &node_based_graph,
-                                   std::unique_ptr<RestrictionMap> restricion_map,
-                                   std::vector<NodeID> &barrier_node_list,
-                                   std::vector<NodeID> &traffic_light_node_list,
-                                   std::vector<QueryNode> &node_info_list,
-                                   SpeedProfileProperties &speed_profile);
+    explicit EdgeBasedGraphFactory(std::shared_ptr<NodeBasedDynamicGraph> node_based_graph,
+                                   std::shared_ptr<RestrictionMap> restricion_map,
+                                   std::unique_ptr<std::vector<NodeID>> barrier_node_list,
+                                   std::unique_ptr<std::vector<NodeID>> traffic_light_node_list,
+                                   const std::vector<QueryNode> &node_info_list,
+                                   const SpeedProfileProperties &speed_profile);
 
     void Run(const std::string &original_edge_data_filename,
              const std::string &geometry_filename,
@@ -97,15 +97,16 @@ class EdgeBasedGraphFactory
 
     unsigned m_number_of_edge_based_nodes;
 
-    std::vector<QueryNode> m_node_info_list;
     std::vector<EdgeBasedNode> m_edge_based_node_list;
     DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
 
+    const std::vector<QueryNode>& m_node_info_list;
     std::shared_ptr<NodeBasedDynamicGraph> m_node_based_graph;
+    std::shared_ptr<RestrictionMap> m_restriction_map;
+
     std::unordered_set<NodeID> m_barrier_nodes;
     std::unordered_set<NodeID> m_traffic_lights;
 
-    std::unique_ptr<RestrictionMap> m_restriction_map;
 
     GeometryCompressor m_geometry_compressor;
 
diff --git a/contractor/processing_chain.cpp b/contractor/processing_chain.cpp
index ccff7fd..a76bc65 100644
--- a/contractor/processing_chain.cpp
+++ b/contractor/processing_chain.cpp
@@ -48,7 +48,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <boost/filesystem/fstream.hpp>
 #include <boost/program_options.hpp>
 
-#include <tbb/task_scheduler_init.h>
 #include <tbb/parallel_sort.h>
 
 #include <chrono>
@@ -57,166 +56,98 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <thread>
 #include <vector>
 
-Prepare::Prepare() : requested_num_threads(1) {}
-
 Prepare::~Prepare() {}
 
-int Prepare::Process(int argc, char *argv[])
+int Prepare::Run()
 {
-    LogPolicy::GetInstance().Unmute();
-    TIMER_START(preparing);
-    TIMER_START(expansion);
-
-    if (!ParseArguments(argc, argv))
-    {
-        return 0;
-    }
-    if (!boost::filesystem::is_regular_file(input_path))
-    {
-        SimpleLogger().Write(logWARNING) << "Input file " << input_path.string() << " not found!";
-        return 1;
-    }
-
-    if (!boost::filesystem::is_regular_file(profile_path))
-    {
-        SimpleLogger().Write(logWARNING) << "Profile " << profile_path.string() << " not found!";
-        return 1;
-    }
-
-    if (1 > requested_num_threads)
-    {
-        SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
-        return 1;
-    }
-
-    const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
-
-    SimpleLogger().Write() << "Input file: " << input_path.filename().string();
-    SimpleLogger().Write() << "Restrictions file: " << restrictions_path.filename().string();
-    SimpleLogger().Write() << "Profile: " << profile_path.filename().string();
-    SimpleLogger().Write() << "Threads: " << requested_num_threads;
-    if (recommended_num_threads != requested_num_threads)
-    {
-        SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
-                                         << recommended_num_threads
-                                         << "! This setting may have performance side-effects.";
-    }
-
-    tbb::task_scheduler_init init(requested_num_threads);
-
-    LogPolicy::GetInstance().Unmute();
-
-    FingerPrint fingerprint_orig;
-    CheckRestrictionsFile(fingerprint_orig);
-
-    boost::filesystem::ifstream input_stream(input_path, std::ios::in | std::ios::binary);
-
-    node_filename = input_path.string() + ".nodes";
-    edge_out = input_path.string() + ".edges";
-    geometry_filename = input_path.string() + ".geometry";
-    graph_out = input_path.string() + ".hsgr";
-    rtree_nodes_path = input_path.string() + ".ramIndex";
-    rtree_leafs_path = input_path.string() + ".fileIndex";
-
-    /*** Setup Scripting Environment ***/
-    // Create a new lua state
-    lua_State *lua_state = luaL_newstate();
-
-    // Connect LuaBind to this lua state
-    luabind::open(lua_state);
-
-    EdgeBasedGraphFactory::SpeedProfileProperties speed_profile;
-
-    if (!SetupScriptingEnvironment(lua_state, speed_profile))
-    {
-        return 1;
-    }
-
 #ifdef WIN32
 #pragma message("Memory consumption on Windows can be higher due to different bit packing")
 #else
-    static_assert(sizeof(ImportEdge) == 20,
-                  "changing ImportEdge type has influence on memory consumption!");
+    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
-    NodeID number_of_node_based_nodes = readBinaryOSRMGraphFromStream(
-        input_stream, edge_list, barrier_node_list, traffic_light_list,
-        &internal_to_external_node_map, restriction_list);
-    input_stream.close();
 
-    if (edge_list.empty())
-    {
-        SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
-        return 1;
-    }
+    TIMER_START(preparing);
 
-    SimpleLogger().Write() << restriction_list.size() << " restrictions, "
-                           << barrier_node_list.size() << " bollard nodes, "
-                           << traffic_light_list.size() << " traffic lights";
+    // Create a new lua state
 
-    std::vector<EdgeBasedNode> node_based_edge_list;
-    unsigned number_of_edge_based_nodes = 0;
+    SimpleLogger().Write() << "Generating edge-expanded graph representation";
+
+    TIMER_START(expansion);
+
+    auto node_based_edge_list = osrm::make_unique<std::vector<EdgeBasedNode>>();;
     DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
+    auto internal_to_external_node_map = osrm::make_unique<std::vector<QueryNode>>();
+    auto graph_size =
+        BuildEdgeExpandedGraph(*internal_to_external_node_map,
+                               *node_based_edge_list, edge_based_edge_list);
 
-    // init node_based_edge_list, edge_based_edge_list by edgeList
-    number_of_edge_based_nodes =
-        BuildEdgeExpandedGraph(lua_state, number_of_node_based_nodes, node_based_edge_list,
-                               edge_based_edge_list, speed_profile);
-    lua_close(lua_state);
+    auto number_of_node_based_nodes = graph_size.first;
+    auto number_of_edge_based_nodes = graph_size.second;
 
     TIMER_STOP(expansion);
 
-    BuildRTree(node_based_edge_list);
-
-    RangebasedCRC32 crc32;
-    if (crc32.using_hardware())
-    {
-        SimpleLogger().Write() << "using hardware based CRC32 computation";
-    }
-    else
-    {
-        SimpleLogger().Write() << "using software based CRC32 computation";
-    }
+    SimpleLogger().Write() << "building r-tree ...";
+    TIMER_START(rtree);
 
-    const unsigned crc32_value = crc32(node_based_edge_list);
-    node_based_edge_list.clear();
-    node_based_edge_list.shrink_to_fit();
-    SimpleLogger().Write() << "CRC32: " << crc32_value;
+    BuildRTree(*node_based_edge_list, *internal_to_external_node_map);
 
-    WriteNodeMapping();
+    TIMER_STOP(rtree);
 
-    /***
-     * Contracting the edge-expanded graph
-     */
+    SimpleLogger().Write() << "writing node map ...";
+    WriteNodeMapping(std::move(internal_to_external_node_map));
 
-    SimpleLogger().Write() << "initializing contractor";
-    auto contractor =
-        osrm::make_unique<Contractor>(number_of_edge_based_nodes, edge_based_edge_list);
+    // Contracting the edge-expanded graph
 
     TIMER_START(contraction);
-    contractor->Run();
+    auto contracted_edge_list = osrm::make_unique<DeallocatingVector<QueryEdge>>();
+    ContractGraph(number_of_edge_based_nodes, edge_based_edge_list, *contracted_edge_list);
     TIMER_STOP(contraction);
 
     SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
 
-    DeallocatingVector<QueryEdge> contracted_edge_list;
-    contractor->GetEdges(contracted_edge_list);
-    contractor.reset();
+    std::size_t number_of_used_edges = WriteContractedGraph(number_of_edge_based_nodes,
+                                                            std::move(node_based_edge_list),
+                                                            std::move(contracted_edge_list));
 
-    /***
-     * Sorting contracted edges in a way that the static query graph can read some in in-place.
-     */
+    TIMER_STOP(preparing);
 
-    tbb::parallel_sort(contracted_edge_list.begin(), contracted_edge_list.end());
-    const unsigned contracted_edge_count = contracted_edge_list.size();
+    SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
+    SimpleLogger().Write() << "Expansion  : " << (number_of_node_based_nodes / TIMER_SEC(expansion))
+                           << " nodes/sec and "
+                           << (number_of_edge_based_nodes / TIMER_SEC(expansion)) << " edges/sec";
+
+    SimpleLogger().Write() << "Contraction: "
+                           << (number_of_edge_based_nodes / TIMER_SEC(contraction))
+                           << " nodes/sec and " << number_of_used_edges / TIMER_SEC(contraction)
+                           << " edges/sec";
+
+    SimpleLogger().Write() << "finished preprocessing";
+
+    return 0;
+}
+
+std::size_t Prepare::WriteContractedGraph(unsigned number_of_edge_based_nodes,
+                                          std::unique_ptr<std::vector<EdgeBasedNode>> node_based_edge_list,
+                                          std::unique_ptr<DeallocatingVector<QueryEdge>> contracted_edge_list)
+{
+    const unsigned crc32_value = CalculateEdgeChecksum(std::move(node_based_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";
 
-    boost::filesystem::ofstream hsgr_output_stream(graph_out, std::ios::binary);
-    hsgr_output_stream.write((char *)&fingerprint_orig, sizeof(FingerPrint));
+    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 = 1 + [&contracted_edge_list]
     {
         unsigned tmp_max = 0;
-        for (const QueryEdge &edge : contracted_edge_list)
+        for (const QueryEdge &edge : *contracted_edge_list)
         {
             BOOST_ASSERT(SPECIAL_NODEID != edge.source);
             BOOST_ASSERT(SPECIAL_NODEID != edge.target);
@@ -241,7 +172,7 @@ int Prepare::Process(int argc, char *argv[])
     for (const auto node : osrm::irange(0u, max_used_node_id))
     {
         last_edge = edge;
-        while ((edge < contracted_edge_count) && (contracted_edge_list[edge].source == node))
+        while ((edge < contracted_edge_count) && ((*contracted_edge_list)[edge].source == node))
         {
             ++edge;
         }
@@ -270,19 +201,19 @@ int Prepare::Process(int argc, char *argv[])
         hsgr_output_stream.write((char *)&node_array[0],
                                  sizeof(StaticGraph<EdgeData>::NodeArrayEntry) * node_array_size);
     }
-    // serialize all edges
 
+    // serialize all edges
     SimpleLogger().Write() << "Building edge array";
     edge = 0;
     int number_of_used_edges = 0;
 
     StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
-    for (const auto edge : osrm::irange<std::size_t>(0, contracted_edge_list.size()))
+    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;
+        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);
@@ -290,12 +221,12 @@ int Prepare::Process(int argc, char *argv[])
         if (current_edge.data.distance <= 0)
         {
             SimpleLogger().Write(logWARNING) << "Edge: " << edge
-                                             << ",source: " << contracted_edge_list[edge].source
-                                             << ", target: " << contracted_edge_list[edge].target
+                                             << ",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 << "/"
+                                             << (*contracted_edge_list)[edge].source << "/"
                                              << node_array.size() - 1;
             return 1;
         }
@@ -305,170 +236,54 @@ int Prepare::Process(int argc, char *argv[])
 
         ++number_of_used_edges;
     }
-    hsgr_output_stream.close();
 
-    TIMER_STOP(preparing);
-
-    SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
-    SimpleLogger().Write() << "Expansion  : " << (number_of_node_based_nodes / TIMER_SEC(expansion))
-                           << " nodes/sec and "
-                           << (number_of_edge_based_nodes / TIMER_SEC(expansion)) << " edges/sec";
-
-    SimpleLogger().Write() << "Contraction: "
-                           << (number_of_edge_based_nodes / TIMER_SEC(contraction))
-                           << " nodes/sec and " << number_of_used_edges / TIMER_SEC(contraction)
-                           << " edges/sec";
-
-    node_array.clear();
-    SimpleLogger().Write() << "finished preprocessing";
-
-    return 0;
+    return number_of_used_edges;
 }
 
-/**
- \brief Parses command line arguments
- \param argc count of arguments
- \param argv array of arguments
- \param result [out] value for exit return value
- \return true if everything is ok, false if need to terminate execution
-*/
-bool Prepare::ParseArguments(int argc, char *argv[])
+unsigned Prepare::CalculateEdgeChecksum(std::unique_ptr<std::vector<EdgeBasedNode>> node_based_edge_list)
 {
-    // declare a group of options that will be allowed only on command line
-    boost::program_options::options_description generic_options("Options");
-    generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
-        "config,c", boost::program_options::value<boost::filesystem::path>(&config_file_path)
-                        ->default_value("contractor.ini"),
-        "Path to a configuration file.");
-
-    // declare a group of options that will be allowed both on command line and in config file
-    boost::program_options::options_description config_options("Configuration");
-    config_options.add_options()(
-        "restrictions,r",
-        boost::program_options::value<boost::filesystem::path>(&restrictions_path),
-        "Restrictions file in .osrm.restrictions format")(
-        "profile,p", boost::program_options::value<boost::filesystem::path>(&profile_path)
-                         ->default_value("profile.lua"),
-        "Path to LUA routing profile")(
-        "threads,t", boost::program_options::value<unsigned int>(&requested_num_threads)
-                         ->default_value(tbb::task_scheduler_init::default_num_threads()),
-        "Number of threads to use");
-
-    // hidden options, will be allowed both on command line and in config file, but will not be
-    // shown to the user
-    boost::program_options::options_description hidden_options("Hidden options");
-    hidden_options.add_options()(
-        "input,i", boost::program_options::value<boost::filesystem::path>(&input_path),
-        "Input file in .osm, .osm.bz2 or .osm.pbf format");
-
-    // positional option
-    boost::program_options::positional_options_description positional_options;
-    positional_options.add("input", 1);
-
-    // combine above options for parsing
-    boost::program_options::options_description cmdline_options;
-    cmdline_options.add(generic_options).add(config_options).add(hidden_options);
-
-    boost::program_options::options_description config_file_options;
-    config_file_options.add(config_options).add(hidden_options);
-
-    boost::program_options::options_description visible_options(
-        "Usage: " + boost::filesystem::basename(argv[0]) + " <input.osrm> [options]");
-    visible_options.add(generic_options).add(config_options);
-
-    // parse command line options
-    boost::program_options::variables_map option_variables;
-    boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
-                                      .options(cmdline_options)
-                                      .positional(positional_options)
-                                      .run(),
-                                  option_variables);
-
-    const auto &temp_config_path = option_variables["config"].as<boost::filesystem::path>();
-    if (boost::filesystem::is_regular_file(temp_config_path))
-    {
-        boost::program_options::store(boost::program_options::parse_config_file<char>(
-                                          temp_config_path.string().c_str(), cmdline_options, true),
-                                      option_variables);
-    }
-
-    if (option_variables.count("version"))
-    {
-        SimpleLogger().Write() << g_GIT_DESCRIPTION;
-        return false;
-    }
-
-    if (option_variables.count("help"))
-    {
-        SimpleLogger().Write() << "\n" << visible_options;
-        return false;
-    }
-
-    boost::program_options::notify(option_variables);
-
-    if (!option_variables.count("restrictions"))
+    RangebasedCRC32 crc32;
+    if (crc32.using_hardware())
     {
-        restrictions_path = std::string(input_path.string() + ".restrictions");
+        SimpleLogger().Write() << "using hardware based CRC32 computation";
     }
-
-    if (!option_variables.count("input"))
+    else
     {
-        SimpleLogger().Write() << "\n" << visible_options;
-        return false;
+        SimpleLogger().Write() << "using software based CRC32 computation";
     }
 
-    return true;
-}
-
-/**
- \brief Loads and checks file UUIDs
-*/
-void Prepare::CheckRestrictionsFile(FingerPrint &fingerprint_orig)
-{
-    boost::filesystem::ifstream restriction_stream(restrictions_path, std::ios::binary);
-    FingerPrint fingerprint_loaded;
-    unsigned number_of_usable_restrictions = 0;
-    restriction_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
-    if (!fingerprint_loaded.TestPrepare(fingerprint_orig))
-    {
-        SimpleLogger().Write(logWARNING) << ".restrictions was prepared with different build.\n"
-                                            "Reprocess to get rid of this warning.";
-    }
+    const unsigned crc32_value = crc32(*node_based_edge_list);
+    SimpleLogger().Write() << "CRC32: " << crc32_value;
 
-    restriction_stream.read((char *)&number_of_usable_restrictions, sizeof(unsigned));
-    restriction_list.resize(number_of_usable_restrictions);
-    if (number_of_usable_restrictions > 0)
-    {
-        restriction_stream.read((char *)&(restriction_list[0]),
-                                number_of_usable_restrictions * sizeof(TurnRestriction));
-    }
-    restriction_stream.close();
+    return crc32_value;
 }
 
 /**
     \brief Setups scripting environment (lua-scripting)
     Also initializes speed profile.
 */
-bool Prepare::SetupScriptingEnvironment(
+void Prepare::SetupScriptingEnvironment(
     lua_State *lua_state, EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile)
 {
     // open utility libraries string library;
     luaL_openlibs(lua_state);
 
     // adjust lua load path
-    luaAddScriptFolderToLoadPath(lua_state, profile_path.string().c_str());
+    luaAddScriptFolderToLoadPath(lua_state, config.profile_path.string().c_str());
 
     // Now call our function in a lua script
-    if (0 != luaL_dofile(lua_state, profile_path.string().c_str()))
+    if (0 != luaL_dofile(lua_state, config.profile_path.string().c_str()))
     {
-        std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
-        return false;
+        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::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
-        return false;
+        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)
@@ -476,92 +291,140 @@ bool Prepare::SetupScriptingEnvironment(
 
     if (0 != luaL_dostring(lua_state, "return u_turn_penalty\n"))
     {
-        std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
-        return false;
+        std::stringstream msg;
+        msg << lua_tostring(lua_state, -1) << " occured in scripting block";
+        throw osrm::exception(msg.str());
     }
 
     speed_profile.u_turn_penalty = 10 * lua_tointeger(lua_state, -1);
     speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function");
+}
 
-    return true;
+/**
+  \brief Build load restrictions from .restriction file
+  */
+std::shared_ptr<RestrictionMap> Prepare::LoadRestrictionMap()
+{
+    boost::filesystem::ifstream input_stream(config.restrictions_path, std::ios::in | std::ios::binary);
+
+    std::vector<TurnRestriction> restriction_list;
+    loadRestrictionsFromFile(input_stream, restriction_list);
+
+    SimpleLogger().Write() << " - " << restriction_list.size() << " restrictions.";
+
+    return std::make_shared<RestrictionMap>(restriction_list);
 }
 
 /**
+  \brief Load node based graph from .osrm file
+  */
+std::shared_ptr<NodeBasedDynamicGraph>
+Prepare::LoadNodeBasedGraph(std::vector<NodeID> &barrier_node_list,
+                            std::vector<NodeID> &traffic_light_list,
+                            std::vector<QueryNode>& internal_to_external_node_map)
+{
+    std::vector<NodeBasedEdge> edge_list;
+
+    boost::filesystem::ifstream input_stream(config.osrm_input_path, std::ios::in | std::ios::binary);
+
+    NodeID number_of_node_based_nodes = loadNodesFromFile(input_stream,
+                                            barrier_node_list, traffic_light_list,
+                                            internal_to_external_node_map);
+
+    SimpleLogger().Write() << " - " << barrier_node_list.size() << " bollard nodes, "
+                           << traffic_light_list.size() << " traffic lights";
+
+    loadEdgesFromFile(input_stream, edge_list);
+
+    if (edge_list.empty())
+    {
+        SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
+        return std::shared_ptr<NodeBasedDynamicGraph>();
+    }
+
+    return NodeBasedDynamicGraphFromImportEdges(number_of_node_based_nodes, edge_list);
+}
+
+
+/**
  \brief Building an edge-expanded graph from node-based input and turn restrictions
 */
-std::size_t
-Prepare::BuildEdgeExpandedGraph(lua_State *lua_state,
-                                NodeID number_of_node_based_nodes,
+std::pair<std::size_t, std::size_t>
+Prepare::BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map,
                                 std::vector<EdgeBasedNode> &node_based_edge_list,
-                                DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
-                                EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile)
+                                DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list)
 {
-    SimpleLogger().Write() << "Generating edge-expanded graph representation";
-    std::shared_ptr<NodeBasedDynamicGraph> node_based_graph =
-        NodeBasedDynamicGraphFromImportEdges(number_of_node_based_nodes, edge_list);
-    std::unique_ptr<RestrictionMap> restriction_map =
-        osrm::make_unique<RestrictionMap>(restriction_list);
-    std::shared_ptr<EdgeBasedGraphFactory> edge_based_graph_factory =
-        std::make_shared<EdgeBasedGraphFactory>(node_based_graph, std::move(restriction_map),
-                                                barrier_node_list, traffic_light_list,
-                                                internal_to_external_node_map, speed_profile);
-    edge_list.clear();
-    edge_list.shrink_to_fit();
-
-    edge_based_graph_factory->Run(edge_out, geometry_filename, lua_state);
-
-    restriction_list.clear();
-    restriction_list.shrink_to_fit();
-    barrier_node_list.clear();
-    barrier_node_list.shrink_to_fit();
-    traffic_light_list.clear();
-    traffic_light_list.shrink_to_fit();
+    lua_State *lua_state = luaL_newstate();
+    luabind::open(lua_state);
+
+    EdgeBasedGraphFactory::SpeedProfileProperties speed_profile;
+
+    SetupScriptingEnvironment(lua_state, speed_profile);
+
+    auto barrier_node_list = osrm::make_unique<std::vector<NodeID>>();
+    auto traffic_light_list = osrm::make_unique<std::vector<NodeID>>();
+
+    auto restriction_map = LoadRestrictionMap();
+    auto node_based_graph = LoadNodeBasedGraph(*barrier_node_list, *traffic_light_list, internal_to_external_node_map);
+
+    const std::size_t number_of_node_based_nodes = node_based_graph->GetNumberOfNodes();
+
+    EdgeBasedGraphFactory edge_based_graph_factory(node_based_graph,
+                                                   restriction_map,
+                                                   std::move(barrier_node_list),
+                                                   std::move(traffic_light_list),
+                                                   internal_to_external_node_map,
+                                                   speed_profile);
+
+    edge_based_graph_factory.Run(config.edge_output_path, config.geometry_output_path, lua_state);
+    lua_close(lua_state);
 
     const std::size_t number_of_edge_based_nodes =
-        edge_based_graph_factory->GetNumberOfEdgeBasedNodes();
+        edge_based_graph_factory.GetNumberOfEdgeBasedNodes();
 
     BOOST_ASSERT(number_of_edge_based_nodes != std::numeric_limits<unsigned>::max());
-#ifndef WIN32
-    static_assert(sizeof(EdgeBasedEdge) == 16,
-                  "changing ImportEdge type has influence on memory consumption!");
-#endif
 
-    edge_based_graph_factory->GetEdgeBasedEdges(edge_based_edge_list);
-    edge_based_graph_factory->GetEdgeBasedNodes(node_based_edge_list);
+    edge_based_graph_factory.GetEdgeBasedEdges(edge_based_edge_list);
+    edge_based_graph_factory.GetEdgeBasedNodes(node_based_edge_list);
 
-    edge_based_graph_factory.reset();
-    node_based_graph.reset();
+    return std::make_pair(number_of_node_based_nodes, number_of_edge_based_nodes);
+}
 
-    return number_of_edge_based_nodes;
+/**
+ \brief Build contracted graph.
+ */
+void Prepare::ContractGraph(const std::size_t number_of_edge_based_nodes,
+                            DeallocatingVector<EdgeBasedEdge>& edge_based_edge_list,
+                            DeallocatingVector<QueryEdge>& contracted_edge_list)
+{
+    Contractor contractor(number_of_edge_based_nodes, edge_based_edge_list);
+    contractor.Run();
+    contractor.GetEdges(contracted_edge_list);
 }
 
 /**
   \brief Writing info on original (node-based) nodes
  */
-void Prepare::WriteNodeMapping()
+void Prepare::WriteNodeMapping(std::unique_ptr<std::vector<QueryNode>> internal_to_external_node_map)
 {
-    SimpleLogger().Write() << "writing node map ...";
-    boost::filesystem::ofstream node_stream(node_filename, std::ios::binary);
-    const unsigned size_of_mapping = internal_to_external_node_map.size();
+    boost::filesystem::ofstream node_stream(config.node_output_path, std::ios::binary);
+    const unsigned size_of_mapping = internal_to_external_node_map->size();
     node_stream.write((char *)&size_of_mapping, sizeof(unsigned));
     if (size_of_mapping > 0)
     {
-        node_stream.write((char *)&(internal_to_external_node_map[0]),
+        node_stream.write((char *) internal_to_external_node_map->data(),
                           size_of_mapping * sizeof(QueryNode));
     }
     node_stream.close();
-    internal_to_external_node_map.clear();
-    internal_to_external_node_map.shrink_to_fit();
 }
 
 /**
     \brief Building rtree-based nearest-neighbor data structure
 
-    Saves info to files: '.ramIndex' and '.fileIndex'.
+    Saves tree into '.ramIndex' and leaves into '.fileIndex'.
  */
-void Prepare::BuildRTree(std::vector<EdgeBasedNode> &node_based_edge_list)
+void Prepare::BuildRTree(const std::vector<EdgeBasedNode> &node_based_edge_list, const std::vector<QueryNode>& internal_to_external_node_map)
 {
-    SimpleLogger().Write() << "building r-tree ...";
-    StaticRTree<EdgeBasedNode>(node_based_edge_list, rtree_nodes_path.c_str(),
-                               rtree_leafs_path.c_str(), internal_to_external_node_map);
+    StaticRTree<EdgeBasedNode>(node_based_edge_list, config.rtree_nodes_output_path.c_str(),
+                               config.rtree_leafs_output_path.c_str(), internal_to_external_node_map);
 }
diff --git a/contractor/processing_chain.hpp b/contractor/processing_chain.hpp
index 933213a..2817681 100644
--- a/contractor/processing_chain.hpp
+++ b/contractor/processing_chain.hpp
@@ -28,11 +28,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef PROCESSING_CHAIN_HPP
 #define PROCESSING_CHAIN_HPP
 
+#include "contractor_options.hpp"
 #include "edge_based_graph_factory.hpp"
 #include "../data_structures/query_edge.hpp"
 #include "../data_structures/static_graph.hpp"
 
-class FingerPrint;
 struct EdgeBasedNode;
 struct lua_State;
 
@@ -50,46 +50,36 @@ class Prepare
     using InputEdge = DynamicGraph<EdgeData>::InputEdge;
     using StaticEdge = StaticGraph<EdgeData>::InputEdge;
 
-    explicit Prepare();
+    explicit Prepare(const ContractorConfig& contractor_config)
+        : config(contractor_config) {}
     Prepare(const Prepare &) = delete;
     ~Prepare();
 
-    int Process(int argc, char *argv[]);
+    int Run();
 
   protected:
-    bool ParseArguments(int argc, char *argv[]);
-    void CheckRestrictionsFile(FingerPrint &fingerprint_orig);
-    bool SetupScriptingEnvironment(lua_State *myLuaState,
+    void SetupScriptingEnvironment(lua_State *myLuaState,
                                    EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile);
-    std::size_t BuildEdgeExpandedGraph(lua_State *myLuaState,
-                                       NodeID nodeBasedNodeNumber,
-                                       std::vector<EdgeBasedNode> &nodeBasedEdgeList,
-                                       DeallocatingVector<EdgeBasedEdge> &edgeBasedEdgeList,
-                                       EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile);
-    void WriteNodeMapping();
-    void BuildRTree(std::vector<EdgeBasedNode> &node_based_edge_list);
-
+    std::shared_ptr<RestrictionMap> LoadRestrictionMap();
+    unsigned CalculateEdgeChecksum(std::unique_ptr<std::vector<EdgeBasedNode>> node_based_edge_list);
+    void ContractGraph(const std::size_t number_of_edge_based_nodes,
+                       DeallocatingVector<EdgeBasedEdge>& edge_based_edge_list,
+                       DeallocatingVector<QueryEdge>& contracted_edge_list);
+    std::size_t WriteContractedGraph(unsigned number_of_edge_based_nodes,
+                                     std::unique_ptr<std::vector<EdgeBasedNode>> node_based_edge_list,
+                                     std::unique_ptr<DeallocatingVector<QueryEdge>> contracted_edge_list);
+    std::shared_ptr<NodeBasedDynamicGraph> LoadNodeBasedGraph(std::vector<NodeID> &barrier_node_list,
+                                               std::vector<NodeID> &traffic_light_list,
+                                               std::vector<QueryNode>& internal_to_external_node_map);
+    std::pair<std::size_t, std::size_t>
+    BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map,
+                                       std::vector<EdgeBasedNode> &node_based_edge_list,
+                                       DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list);
+    void WriteNodeMapping(std::unique_ptr<std::vector<QueryNode>> internal_to_external_node_map);
+    void BuildRTree(const std::vector<EdgeBasedNode> &node_based_edge_list,
+                    const std::vector<QueryNode> &internal_to_external_node_map);
   private:
-    std::vector<QueryNode> internal_to_external_node_map;
-    std::vector<TurnRestriction> restriction_list;
-    std::vector<NodeID> barrier_node_list;
-    std::vector<NodeID> traffic_light_list;
-    std::vector<ImportEdge> edge_list;
-
-    unsigned requested_num_threads;
-    boost::filesystem::path config_file_path;
-    boost::filesystem::path input_path;
-    boost::filesystem::path restrictions_path;
-    boost::filesystem::path preinfo_path;
-    boost::filesystem::path profile_path;
-
-    std::string node_filename;
-    std::string edge_out;
-    std::string info_out;
-    std::string geometry_filename;
-    std::string graph_out;
-    std::string rtree_nodes_path;
-    std::string rtree_leafs_path;
+    ContractorConfig config;
 };
 
 #endif // PROCESSING_CHAIN_HPP
diff --git a/data_structures/dynamic_graph.hpp b/data_structures/dynamic_graph.hpp
index 43e6c3a..b18204c 100644
--- a/data_structures/dynamic_graph.hpp
+++ b/data_structures/dynamic_graph.hpp
@@ -85,6 +85,9 @@ template <typename EdgeDataT> class DynamicGraph
         edge_list.resize(number_of_nodes);
     }
 
+    /**
+     * Constructs a DynamicGraph from a list of edges sorted by source node id.
+     */
     template <class ContainerT> DynamicGraph(const NodeIterator nodes, const ContainerT &graph)
     {
         number_of_nodes = nodes;
diff --git a/data_structures/import_edge.cpp b/data_structures/import_edge.cpp
index f41b066..3f2146c 100644
--- a/data_structures/import_edge.cpp
+++ b/data_structures/import_edge.cpp
@@ -47,6 +47,13 @@ bool NodeBasedEdge::operator<(const NodeBasedEdge &other) const
     return source < other.source;
 }
 
+NodeBasedEdge::NodeBasedEdge()
+    : source(SPECIAL_NODEID), target(SPECIAL_NODEID), name_id(0), weight(0), forward(false),
+      backward(false), roundabout(false), in_tiny_cc(false),
+      access_restricted(false), is_split(false), travel_mode(false)
+{
+}
+
 NodeBasedEdge::NodeBasedEdge(NodeID source,
                              NodeID target,
                              NodeID name_id,
diff --git a/data_structures/import_edge.hpp b/data_structures/import_edge.hpp
index f422de1..e489850 100644
--- a/data_structures/import_edge.hpp
+++ b/data_structures/import_edge.hpp
@@ -35,6 +35,7 @@ struct NodeBasedEdge
 {
     bool operator<(const NodeBasedEdge &e) const;
 
+    NodeBasedEdge();
     explicit NodeBasedEdge(NodeID source,
                            NodeID target,
                            NodeID name_id,
@@ -58,8 +59,6 @@ struct NodeBasedEdge
     bool access_restricted : 1;
     bool is_split : 1;
     TravelMode travel_mode : 4;
-
-    NodeBasedEdge() = delete;
 };
 
 struct EdgeBasedEdge
@@ -86,6 +85,4 @@ struct EdgeBasedEdge
     bool backward : 1;
 };
 
-using ImportEdge = NodeBasedEdge;
-
 #endif /* IMPORT_EDGE_HPP */
diff --git a/data_structures/node_based_graph.hpp b/data_structures/node_based_graph.hpp
index 54e07a7..b69053a 100644
--- a/data_structures/node_based_graph.hpp
+++ b/data_structures/node_based_graph.hpp
@@ -64,7 +64,7 @@ struct NodeBasedEdgeData
         backward = temp_flag;
     }
 
-    bool IsEqualTo(const NodeBasedEdgeData &other) const
+    bool IsCompatibleTo(const NodeBasedEdgeData &other) const
     {
         return (forward == other.forward) && (backward == other.backward) &&
                (nameID == other.nameID) && (ignore_in_grid == other.ignore_in_grid) &&
@@ -72,26 +72,123 @@ struct NodeBasedEdgeData
     }
 };
 
-struct SimpleEdgeData
+using NodeBasedDynamicGraph = DynamicGraph<NodeBasedEdgeData>;
+
+inline bool validateNeighborHood(const NodeBasedDynamicGraph& graph, const NodeID source)
 {
-    SimpleEdgeData() : capacity(0) {}
-    EdgeWeight capacity;
-};
+    for (auto edge = graph.BeginEdges(source); edge < graph.EndEdges(source); ++edge)
+    {
+        const auto& data = graph.GetEdgeData(edge);
+        if (!data.forward && !data.backward)
+        {
+            SimpleLogger().Write(logWARNING) << "Invalid edge directions";
+            return false;
+        }
 
-using NodeBasedDynamicGraph = DynamicGraph<NodeBasedEdgeData>;
-using SimpleNodeBasedDynamicGraph = DynamicGraph<SimpleEdgeData>;
+        auto target = graph.GetTarget(edge);
+        if (target == SPECIAL_NODEID)
+        {
+            SimpleLogger().Write(logWARNING) << "Invalid edge target";
+            return false;
+        }
+
+        bool found_reverse = false;
+        for (auto rev_edge = graph.BeginEdges(target); rev_edge < graph.EndEdges(target); ++rev_edge)
+        {
+            auto rev_target = graph.GetTarget(rev_edge);
+            if (rev_target == SPECIAL_NODEID)
+            {
+                SimpleLogger().Write(logWARNING) << "Invalid reverse edge target";
+                return false;
+            }
+
+            if (rev_target != source)
+            {
+                continue;
+            }
+
+            if (found_reverse)
+            {
+                SimpleLogger().Write(logWARNING) << "Found more than one reverse edge";
+                return false;
+            }
+
+            const auto& rev_data = graph.GetEdgeData(rev_edge);
+
+            // edge is incoming, this must be an outgoing edge
+            if (data.backward && !rev_data.forward)
+            {
+                SimpleLogger().Write(logWARNING) << "Found no outgoing edge to an incoming edge!";
+                return false;
+            }
+
+            // edge is bi-directional, reverse must be as well
+            if (data.forward && data.backward && (!rev_data.forward || !rev_data.backward))
+            {
+                SimpleLogger().Write(logWARNING) << "Found bi-directional edge that is not bi-directional to both ends";
+                return false;
+            }
+
+            found_reverse = true;
+
+        }
+
+        if (!found_reverse)
+        {
+            SimpleLogger().Write(logWARNING) << "Could not find reverse edge";
+            return false;
+        }
+    }
+
+    return true;
+}
+
+// This function checks if the overal graph is undirected (has an edge in each direction).
+inline bool validateNodeBasedGraph(const NodeBasedDynamicGraph& graph)
+{
+    for (auto source = 0u; source < graph.GetNumberOfNodes(); ++source)
+    {
+        if (!validateNeighborHood(graph, source))
+        {
+            return false;
+        }
+    }
+
+    return true;
+}
 
-// Factory method to create NodeBasedDynamicGraph from ImportEdges
+// Factory method to create NodeBasedDynamicGraph from NodeBasedEdges
+// The since DynamicGraph expects directed edges, we need to insert
+// two edges for undirected edges.
 inline std::shared_ptr<NodeBasedDynamicGraph>
-NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge> &input_edge_list)
+NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<NodeBasedEdge> &input_edge_list)
 {
     static_assert(sizeof(NodeBasedEdgeData) == 16,
                   "changing node based edge data size changes memory consumption");
 
     DeallocatingVector<NodeBasedDynamicGraph::InputEdge> edges_list;
     NodeBasedDynamicGraph::InputEdge edge;
-    for (const ImportEdge &import_edge : input_edge_list)
+
+    // 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 backward=true
+    // flag to indicate which is which.
+    //
+    // We do the transformation in the following way:
+    //
+    // if the edge (a, b) is split:
+    //   1. this edge must be in only one direction, so its a --> b
+    //   2. there must be another directed edge b --> a somewhere in the data
+    // if the edge (a, b) is not split:
+    //   1. this edge be on of a --> b od a <-> b
+    //      (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 (I think a --> b and b <-- a would work as well though)
+    for (const NodeBasedEdge &import_edge : input_edge_list)
     {
+        // edges that are not forward get converted by flipping the end points
+        BOOST_ASSERT(import_edge.forward);
+
         if (import_edge.forward)
         {
             edge.source = import_edge.source;
@@ -99,20 +196,10 @@ NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge
             edge.data.forward = import_edge.forward;
             edge.data.backward = import_edge.backward;
         }
-        else
-        {
-            edge.source = import_edge.target;
-            edge.target = import_edge.source;
-            edge.data.backward = import_edge.forward;
-            edge.data.forward = import_edge.backward;
-        }
 
-        if (edge.source == edge.target)
-        {
-            continue;
-        }
+        BOOST_ASSERT(edge.source != edge.target);
 
-        edge.data.distance = (std::max)(static_cast<int>(import_edge.weight), 1);
+        edge.data.distance = static_cast<int>(import_edge.weight);
         BOOST_ASSERT(edge.data.distance > 0);
         edge.data.shortcut = false;
         edge.data.roundabout = import_edge.roundabout;
@@ -132,147 +219,16 @@ NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge
         }
     }
 
-    // remove duplicate edges
     tbb::parallel_sort(edges_list.begin(), edges_list.end());
-    NodeID edge_count = 0;
-    for (NodeID i = 0; i < edges_list.size();)
-    {
-        const NodeID source = edges_list[i].source;
-        const NodeID target = edges_list[i].target;
-        // remove eigenloops
-        if (source == target)
-        {
-            i++;
-            continue;
-        }
-        NodeBasedDynamicGraph::InputEdge forward_edge;
-        NodeBasedDynamicGraph::InputEdge reverse_edge;
-        forward_edge = reverse_edge = edges_list[i];
-        forward_edge.data.forward = reverse_edge.data.backward = true;
-        forward_edge.data.backward = reverse_edge.data.forward = false;
-        forward_edge.data.shortcut = reverse_edge.data.shortcut = false;
-        forward_edge.data.distance = reverse_edge.data.distance = std::numeric_limits<int>::max();
-        // remove parallel edges
-        while (i < edges_list.size() && edges_list[i].source == source &&
-               edges_list[i].target == target)
-        {
-            if (edges_list[i].data.forward)
-            {
-                forward_edge.data.distance =
-                    std::min(edges_list[i].data.distance, forward_edge.data.distance);
-            }
-            if (edges_list[i].data.backward)
-            {
-                reverse_edge.data.distance =
-                    std::min(edges_list[i].data.distance, reverse_edge.data.distance);
-            }
-            ++i;
-        }
-        // merge edges (s,t) and (t,s) into bidirectional edge
-        if (forward_edge.data.distance == reverse_edge.data.distance)
-        {
-            if (static_cast<int>(forward_edge.data.distance) != std::numeric_limits<int>::max())
-            {
-                forward_edge.data.backward = true;
-                edges_list[edge_count++] = forward_edge;
-            }
-        }
-        else
-        { // insert seperate edges
-            if (static_cast<int>(forward_edge.data.distance) != std::numeric_limits<int>::max())
-            {
-                edges_list[edge_count++] = forward_edge;
-            }
-            if (static_cast<int>(reverse_edge.data.distance) != std::numeric_limits<int>::max())
-            {
-                edges_list[edge_count++] = reverse_edge;
-            }
-        }
-    }
-    edges_list.resize(edge_count);
-    SimpleLogger().Write() << "merged " << edges_list.size() - edge_count << " edges out of "
-                           << edges_list.size();
 
     auto graph = std::make_shared<NodeBasedDynamicGraph>(
         static_cast<NodeBasedDynamicGraph::NodeIterator>(number_of_nodes), edges_list);
-    return graph;
-}
-
-template <class SimpleEdgeT>
-inline std::shared_ptr<SimpleNodeBasedDynamicGraph>
-SimpleNodeBasedDynamicGraphFromEdges(int number_of_nodes, std::vector<SimpleEdgeT> &input_edge_list)
-{
-    static_assert(sizeof(NodeBasedEdgeData) == 16,
-                  "changing node based edge data size changes memory consumption");
-    tbb::parallel_sort(input_edge_list.begin(), input_edge_list.end());
 
-    DeallocatingVector<SimpleNodeBasedDynamicGraph::InputEdge> edges_list;
-    SimpleNodeBasedDynamicGraph::InputEdge edge;
-    edge.data.capacity = 1;
-    for (const SimpleEdgeT &import_edge : input_edge_list)
-    {
-        if (import_edge.source == import_edge.target)
-        {
-            continue;
-        }
-        edge.source = import_edge.source;
-        edge.target = import_edge.target;
-        edges_list.push_back(edge);
-        std::swap(edge.source, edge.target);
-        edges_list.push_back(edge);
-    }
 
-    // remove duplicate edges
-    tbb::parallel_sort(edges_list.begin(), edges_list.end());
-    NodeID edge_count = 0;
-    for (NodeID i = 0; i < edges_list.size();)
-    {
-        const NodeID source = edges_list[i].source;
-        const NodeID target = edges_list[i].target;
-        // remove eigenloops
-        if (source == target)
-        {
-            i++;
-            continue;
-        }
-        SimpleNodeBasedDynamicGraph::InputEdge forward_edge;
-        SimpleNodeBasedDynamicGraph::InputEdge reverse_edge;
-        forward_edge = reverse_edge = edges_list[i];
-        forward_edge.data.capacity = reverse_edge.data.capacity = INVALID_EDGE_WEIGHT;
-        // remove parallel edges
-        while (i < edges_list.size() && edges_list[i].source == source &&
-               edges_list[i].target == target)
-        {
-            forward_edge.data.capacity =
-                std::min(edges_list[i].data.capacity, forward_edge.data.capacity);
-            reverse_edge.data.capacity =
-                std::min(edges_list[i].data.capacity, reverse_edge.data.capacity);
-            ++i;
-        }
-        // merge edges (s,t) and (t,s) into bidirectional edge
-        if (forward_edge.data.capacity == reverse_edge.data.capacity)
-        {
-            if (static_cast<int>(forward_edge.data.capacity) != INVALID_EDGE_WEIGHT)
-            {
-                edges_list[edge_count++] = forward_edge;
-            }
-        }
-        else
-        { // insert seperate edges
-            if (static_cast<int>(forward_edge.data.capacity) != INVALID_EDGE_WEIGHT)
-            {
-                edges_list[edge_count++] = forward_edge;
-            }
-            if (static_cast<int>(reverse_edge.data.capacity) != INVALID_EDGE_WEIGHT)
-            {
-                edges_list[edge_count++] = reverse_edge;
-            }
-        }
-    }
-    SimpleLogger().Write() << "merged " << edges_list.size() - edge_count << " edges out of "
-                           << edges_list.size();
+#ifndef NDEBUG
+    BOOST_ASSERT(validateNodeBasedGraph(*graph));
+#endif
 
-    auto graph = std::make_shared<SimpleNodeBasedDynamicGraph>(number_of_nodes, edges_list);
     return graph;
 }
 
diff --git a/data_structures/restriction_map.hpp b/data_structures/restriction_map.hpp
index 27a6698..98b360c 100644
--- a/data_structures/restriction_map.hpp
+++ b/data_structures/restriction_map.hpp
@@ -91,6 +91,7 @@ template <> struct hash<RestrictionTarget>
 class RestrictionMap
 {
   public:
+    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
@@ -98,7 +99,7 @@ class RestrictionMap
     void FixupArrivingTurnRestriction(const NodeID node_u,
                                       const NodeID node_v,
                                       const NodeID node_w,
-                                      const std::shared_ptr<GraphT> &graph)
+                                      const GraphT &graph)
     {
         BOOST_ASSERT(node_u != SPECIAL_NODEID);
         BOOST_ASSERT(node_v != SPECIAL_NODEID);
@@ -112,9 +113,9 @@ class RestrictionMap
         // find all potential start edges. It is more efficent to get a (small) list
         // of potential start edges than iterating over all buckets
         std::vector<NodeID> predecessors;
-        for (const EdgeID current_edge_id : graph->GetAdjacentEdgeRange(node_u))
+        for (const EdgeID current_edge_id : graph.GetAdjacentEdgeRange(node_u))
         {
-            const NodeID target = graph->GetTarget(current_edge_id);
+            const NodeID target = graph.GetTarget(current_edge_id);
             if (node_v != target)
             {
                 predecessors.push_back(target);
diff --git a/data_structures/route_parameters.cpp b/data_structures/route_parameters.cpp
index 3b615e2..86b9553 100644
--- a/data_structures/route_parameters.cpp
+++ b/data_structures/route_parameters.cpp
@@ -31,6 +31,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #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),
@@ -131,3 +133,9 @@ void RouteParameters::addCoordinate(
         static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<0>(received_coordinates)),
         static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<1>(received_coordinates)));
 }
+
+void RouteParameters::getCoordinatesFromGeometry(const std::string geometry_string)
+{
+    PolylineCompressor pc;
+    coordinates = pc.decode_string(geometry_string);
+}
diff --git a/data_structures/static_rtree.hpp b/data_structures/static_rtree.hpp
index f219a64..fa56071 100644
--- a/data_structures/static_rtree.hpp
+++ b/data_structures/static_rtree.hpp
@@ -344,7 +344,7 @@ class StaticRTree
     StaticRTree(const StaticRTree &) = delete;
 
     // Construct a packed Hilbert-R-Tree with Kamel-Faloutsos algorithm [1]
-    explicit StaticRTree(std::vector<EdgeDataT> &input_data_vector,
+    explicit StaticRTree(const std::vector<EdgeDataT> &input_data_vector,
                          const std::string tree_node_filename,
                          const std::string leaf_node_filename,
                          const std::vector<QueryNode> &coordinate_list)
@@ -646,22 +646,16 @@ class StaticRTree
         const FixedPointCoordinate &input_coordinate,
         std::vector<PhantomNode> &result_phantom_node_vector,
         const unsigned max_number_of_phantom_nodes,
-        const unsigned max_checked_elements = 4 * LEAF_NODE_SIZE)
+        const float max_distance = 1100)
     {
         unsigned inspected_elements = 0;
         unsigned number_of_elements_from_big_cc = 0;
         unsigned number_of_elements_from_tiny_cc = 0;
 
-#ifdef NDEBUG
-        unsigned pruned_elements = 0;
-#endif
         std::pair<double, double> projected_coordinate = {
             mercator::lat2y(input_coordinate.lat / COORDINATE_PRECISION),
             input_coordinate.lon / COORDINATE_PRECISION};
 
-        // upper bound pruning technique
-        upper_bound<float> pruning_bound(max_number_of_phantom_nodes);
-
         // initialize queue with root element
         std::priority_queue<IncrementalQueryCandidate> traversal_queue;
         traversal_queue.emplace(0.f, m_search_tree[0]);
@@ -669,6 +663,10 @@ class StaticRTree
         while (!traversal_queue.empty())
         {
             const IncrementalQueryCandidate current_query_node = traversal_queue.top();
+            if (current_query_node.min_dist > max_distance)
+            {
+                break;
+            }
             traversal_queue.pop();
 
             if (current_query_node.node.template is<TreeNode>())
@@ -692,18 +690,7 @@ class StaticRTree
                         // distance must be non-negative
                         BOOST_ASSERT(0.f <= current_perpendicular_distance);
 
-                        if (pruning_bound.get() >= current_perpendicular_distance ||
-                            current_edge.is_in_tiny_cc())
-                        {
-                            pruning_bound.insert(current_perpendicular_distance);
-                            traversal_queue.emplace(current_perpendicular_distance, current_edge);
-                        }
-#ifdef NDEBUG
-                        else
-                        {
-                            ++pruned_elements;
-                        }
-#endif
+                        traversal_queue.emplace(current_perpendicular_distance, current_edge);
                     }
                 }
                 else
@@ -771,9 +758,8 @@ class StaticRTree
             }
 
             // stop the search by flushing the queue
-            if ((result_phantom_node_vector.size() >= max_number_of_phantom_nodes &&
-                 number_of_elements_from_big_cc > 0) ||
-                inspected_elements >= max_checked_elements)
+            if (result_phantom_node_vector.size() >= max_number_of_phantom_nodes &&
+                 number_of_elements_from_big_cc > 0)
             {
                 traversal_queue = std::priority_queue<IncrementalQueryCandidate>{};
             }
@@ -809,6 +795,10 @@ class StaticRTree
         unsigned number_of_elements_from_big_cc = 0;
         unsigned number_of_elements_from_tiny_cc = 0;
 
+        // is true if a big cc was added to the queue to we also have a lower bound
+        // for them. it actives pruning for big components
+        bool has_big_cc = false;
+
         unsigned pruned_elements = 0;
 
         std::pair<double, double> projected_coordinate = {
@@ -849,10 +839,11 @@ class StaticRTree
                         BOOST_ASSERT(0.f <= current_perpendicular_distance);
 
                         if (pruning_bound.get() >= current_perpendicular_distance ||
-                            current_edge.is_in_tiny_cc())
+                            (!has_big_cc && !current_edge.is_in_tiny_cc()))
                         {
                             pruning_bound.insert(current_perpendicular_distance);
                             traversal_queue.emplace(current_perpendicular_distance, current_edge);
+                            has_big_cc = has_big_cc || !current_edge.is_in_tiny_cc();
                         }
                         else
                         {
diff --git a/datastore.cpp b/datastore.cpp
index 3c032a2..89efefc 100644
--- a/datastore.cpp
+++ b/datastore.cpp
@@ -264,9 +264,10 @@ int main(const int argc, const char *argv[])
 
         boost::filesystem::ifstream hsgr_input_stream(hsgr_path, std::ios::binary);
 
-        FingerPrint fingerprint_loaded, fingerprint_orig;
+        FingerPrint fingerprint_valid = FingerPrint::GetValid();
+        FingerPrint fingerprint_loaded;
         hsgr_input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
-        if (fingerprint_loaded.TestGraphUtil(fingerprint_orig))
+        if (fingerprint_loaded.TestGraphUtil(fingerprint_valid))
         {
             SimpleLogger().Write(logDEBUG) << "Fingerprint checked out ok";
         }
diff --git a/descriptors/description_factory.cpp b/descriptors/description_factory.cpp
index e466562..71dd795 100644
--- a/descriptors/description_factory.cpp
+++ b/descriptors/description_factory.cpp
@@ -173,6 +173,7 @@ void DescriptionFactory::Run(const unsigned zoom_level)
     //        }
     //        string0 = string1;
     //    }
+    //
 
     float segment_length = 0.;
     EdgeWeight segment_duration = 0;
@@ -197,7 +198,8 @@ void DescriptionFactory::Run(const unsigned zoom_level)
 
     // Post-processing to remove empty or nearly empty path segments
     if (path_description.size() > 2 &&
-        std::numeric_limits<float>::epsilon() > path_description.back().length)
+        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;
@@ -206,7 +208,8 @@ void DescriptionFactory::Run(const unsigned zoom_level)
     }
 
     if (path_description.size() > 2 &&
-        std::numeric_limits<float>::epsilon() > path_description.front().length)
+        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;
diff --git a/extract.cpp b/extract.cpp
index a147629..5f88cc3 100644
--- a/extract.cpp
+++ b/extract.cpp
@@ -73,7 +73,7 @@ int main(int argc, char *argv[])
                                              << " not found!";
             return 1;
         }
-        return extractor().run(extractor_config);
+        return extractor(extractor_config).run();
     }
     catch (const std::exception &e)
     {
diff --git a/extractor/extraction_containers.cpp b/extractor/extraction_containers.cpp
index 7c912f3..caca05c 100644
--- a/extractor/extraction_containers.cpp
+++ b/extractor/extraction_containers.cpp
@@ -35,6 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../util/osrm_exception.hpp"
 #include "../util/simple_logger.hpp"
 #include "../util/timing_util.hpp"
+#include "../util/fingerprint.hpp"
 
 #include <boost/assert.hpp>
 #include <boost/filesystem.hpp>
@@ -54,6 +55,7 @@ ExtractionContainers::ExtractionContainers()
 
 ExtractionContainers::~ExtractionContainers()
 {
+    // FIXME isn't this done implicitly of the stxxl::vectors go out of scope?
     used_node_id_list.clear();
     all_nodes_list.clear();
     all_edges_list.clear();
@@ -71,394 +73,561 @@ ExtractionContainers::~ExtractionContainers()
  * - filter nodes list to nodes that are referenced by ways
  * - merge edges with nodes to include location of start/end points and serialize
  *
- * FIXME: Each of this step should be an own function for readability.
  */
 void ExtractionContainers::PrepareData(const std::string &output_file_name,
-                                       const std::string &restrictions_file_name)
+                                       const std::string &restrictions_file_name,
+                                       const std::string &name_file_name)
 {
     try
     {
-        unsigned number_of_used_nodes = 0;
-        unsigned number_of_used_edges = 0;
-
-        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);
-        TIMER_STOP(sorting_used_nodes);
-        std::cout << "ok, after " << TIMER_SEC(sorting_used_nodes) << "s" << std::endl;
-
-        std::cout << "[extractor] Erasing duplicate nodes   ... " << std::flush;
-        TIMER_START(erasing_dups);
-        auto new_end = std::unique(used_node_id_list.begin(), used_node_id_list.end());
-        used_node_id_list.resize(new_end - used_node_id_list.begin());
-        TIMER_STOP(erasing_dups);
-        std::cout << "ok, after " << TIMER_SEC(erasing_dups) << "s" << std::endl;
-
-        std::cout << "[extractor] Sorting all nodes         ... " << std::flush;
-        TIMER_START(sorting_nodes);
-        stxxl::sort(all_nodes_list.begin(), all_nodes_list.end(), ExternalMemoryNodeSTXXLCompare(),
-                    stxxl_memory);
-        TIMER_STOP(sorting_nodes);
-        std::cout << "ok, after " << TIMER_SEC(sorting_nodes) << "s" << std::endl;
-
-        std::cout << "[extractor] Sorting used ways         ... " << std::flush;
-        TIMER_START(sort_ways);
-        stxxl::sort(way_start_end_id_list.begin(), way_start_end_id_list.end(),
-                    FirstAndLastSegmentOfWayStxxlCompare(), stxxl_memory);
-        TIMER_STOP(sort_ways);
-        std::cout << "ok, after " << TIMER_SEC(sort_ways) << "s" << std::endl;
-
-        std::cout << "[extractor] Sorting " << restrictions_list.size()
-                  << " restrictions. by from... " << std::flush;
-        TIMER_START(sort_restrictions);
-        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;
-
-        std::cout << "[extractor] Fixing restriction starts ... " << std::flush;
-        TIMER_START(fix_restriction_starts);
-        auto restrictions_iterator = restrictions_list.begin();
-        auto way_start_and_end_iterator = way_start_end_id_list.cbegin();
-
-        while (way_start_and_end_iterator != way_start_end_id_list.cend() &&
-               restrictions_iterator != restrictions_list.end())
+        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));
+
+        PrepareNodes();
+        WriteNodes(file_out_stream);
+        PrepareEdges();
+        WriteEdges(file_out_stream);
+
+        file_out_stream.close();
+
+        PrepareRestrictions();
+        WriteRestrictions(restrictions_file_name);
+
+        WriteNames(name_file_name);
+    }
+    catch (const std::exception &e)
+    {
+        std::cerr << "Caught Execption:" << e.what() << std::endl;
+    }
+}
+
+void ExtractionContainers::WriteNames(const std::string& names_file_name) const
+{
+    std::cout << "[extractor] writing street name index ... " << std::flush;
+    TIMER_START(write_name_index);
+    boost::filesystem::ofstream name_file_stream(names_file_name, std::ios::binary);
+
+    unsigned total_length = 0;
+    std::vector<unsigned> name_lengths;
+    for (const std::string &temp_string : name_list)
+    {
+        const unsigned string_length =
+            std::min(static_cast<unsigned>(temp_string.length()), 255u);
+        name_lengths.push_back(string_length);
+        total_length += string_length;
+    }
+
+    // builds and writes the index
+    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
+    for (const std::string &temp_string : name_list)
+    {
+        const unsigned string_length =
+            std::min(static_cast<unsigned>(temp_string.length()), 255u);
+        name_file_stream.write(temp_string.c_str(), string_length);
+    }
+
+    name_file_stream.close();
+    TIMER_STOP(write_name_index);
+    std::cout << "ok, after " << TIMER_SEC(write_name_index) << "s" << std::endl;
+}
+
+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);
+    TIMER_STOP(sorting_used_nodes);
+    std::cout << "ok, after " << TIMER_SEC(sorting_used_nodes) << "s" << std::endl;
+
+    std::cout << "[extractor] Erasing duplicate nodes   ... " << std::flush;
+    TIMER_START(erasing_dups);
+    auto new_end = std::unique(used_node_id_list.begin(), used_node_id_list.end());
+    used_node_id_list.resize(new_end - used_node_id_list.begin());
+    TIMER_STOP(erasing_dups);
+    std::cout << "ok, after " << TIMER_SEC(erasing_dups) << "s" << std::endl;
+
+    std::cout << "[extractor] Building node id map      ... " << std::flush;
+    TIMER_START(id_map);
+    external_to_internal_node_id_map.reserve(used_node_id_list.size());
+    for (NodeID i = 0u; i < used_node_id_list.size(); ++i)
+        external_to_internal_node_id_map[used_node_id_list[i]] = i;
+    TIMER_STOP(id_map);
+    std::cout << "ok, after " << TIMER_SEC(id_map) << "s" << std::endl;
+
+    std::cout << "[extractor] Sorting all nodes         ... " << std::flush;
+    TIMER_START(sorting_nodes);
+    stxxl::sort(all_nodes_list.begin(), all_nodes_list.end(), ExternalMemoryNodeSTXXLCompare(),
+                stxxl_memory);
+    TIMER_STOP(sorting_nodes);
+    std::cout << "ok, after " << TIMER_SEC(sorting_nodes) << "s" << std::endl;
+}
+
+void ExtractionContainers::PrepareEdges()
+{
+    // Sort edges by start.
+    std::cout << "[extractor] Sorting edges by start    ... " << std::flush;
+    TIMER_START(sort_edges_by_start);
+    stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByStartID(), stxxl_memory);
+    TIMER_STOP(sort_edges_by_start);
+    std::cout << "ok, after " << TIMER_SEC(sort_edges_by_start) << "s" << std::endl;
+
+    std::cout << "[extractor] Setting start coords      ... " << std::flush;
+    TIMER_START(set_start_coords);
+    // Traverse list of edges and nodes in parallel and set start coord
+    auto node_iterator = all_nodes_list.begin();
+    auto edge_iterator = all_edges_list.begin();
+    while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
+    {
+        if (edge_iterator->result.source < node_iterator->node_id)
         {
-            if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.from.way)
-            {
-                ++way_start_and_end_iterator;
-                continue;
-            }
+            edge_iterator->result.source = SPECIAL_NODEID;
+            ++edge_iterator;
+            continue;
+        }
+        if (edge_iterator->result.source > node_iterator->node_id)
+        {
+            node_iterator++;
+            continue;
+        }
 
-            if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.from.way)
-            {
-                ++restrictions_iterator;
-                continue;
-            }
+        // remove loops
+        if (edge_iterator->result.source == edge_iterator->result.target)
+        {
+            edge_iterator->result.source = SPECIAL_NODEID;
+            edge_iterator->result.target = SPECIAL_NODEID;
+            ++edge_iterator;
+            continue;
+        }
 
-            BOOST_ASSERT(way_start_and_end_iterator->way_id ==
-                         restrictions_iterator->restriction.from.way);
-            const NodeID via_node_id = restrictions_iterator->restriction.via.node;
+        BOOST_ASSERT(edge_iterator->result.source == node_iterator->node_id);
 
-            if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
-            {
-                restrictions_iterator->restriction.from.node =
-                    way_start_and_end_iterator->first_segment_target_id;
-            }
-            else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
-            {
-                restrictions_iterator->restriction.from.node =
-                    way_start_and_end_iterator->last_segment_source_id;
-            }
-            ++restrictions_iterator;
+        // assign new node id
+        auto id_iter = external_to_internal_node_id_map.find(node_iterator->node_id);
+        BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
+        edge_iterator->result.source = id_iter->second;
+
+        edge_iterator->source_coordinate.lat = node_iterator->lat;
+        edge_iterator->source_coordinate.lon = node_iterator->lon;
+        ++edge_iterator;
+    }
+    TIMER_STOP(set_start_coords);
+    std::cout << "ok, after " << TIMER_SEC(set_start_coords) << "s" << std::endl;
+
+    // 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(), CmpEdgeByTargetID(),
+                stxxl_memory);
+    TIMER_STOP(sort_edges_by_target);
+    std::cout << "ok, after " << TIMER_SEC(sort_edges_by_target) << "s" << std::endl;
+
+    // Compute edge weights
+    std::cout << "[extractor] Computing edge weights    ... " << std::flush;
+    TIMER_START(compute_weights);
+    node_iterator = all_nodes_list.begin();
+    edge_iterator = all_edges_list.begin();
+    while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
+    {
+        // skip all invalid edges
+        if (edge_iterator->result.source == SPECIAL_NODEID)
+        {
+            ++edge_iterator;
+            continue;
         }
 
-        TIMER_STOP(fix_restriction_starts);
-        std::cout << "ok, after " << TIMER_SEC(fix_restriction_starts) << "s" << std::endl;
-
-        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);
-        TIMER_STOP(sort_restrictions_to);
-        std::cout << "ok, after " << TIMER_SEC(sort_restrictions_to) << "s" << std::endl;
-
-        std::cout << "[extractor] Fixing restriction ends   ... " << std::flush;
-        TIMER_START(fix_restriction_ends);
-        restrictions_iterator = restrictions_list.begin();
-        way_start_and_end_iterator = way_start_end_id_list.cbegin();
-        while (way_start_and_end_iterator != way_start_end_id_list.cend() &&
-               restrictions_iterator != restrictions_list.end())
+        if (edge_iterator->result.target < node_iterator->node_id)
         {
-            if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.to.way)
-            {
-                ++way_start_and_end_iterator;
-                continue;
-            }
-            if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.to.way)
-            {
-                ++restrictions_iterator;
-                continue;
-            }
-            BOOST_ASSERT(way_start_and_end_iterator->way_id ==
-                         restrictions_iterator->restriction.to.way);
-            const NodeID via_node_id = restrictions_iterator->restriction.via.node;
+            edge_iterator->result.target = SPECIAL_NODEID;
+            ++edge_iterator;
+            continue;
+        }
+        if (edge_iterator->result.target > node_iterator->node_id)
+        {
+            ++node_iterator;
+            continue;
+        }
 
-            if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
-            {
-                restrictions_iterator->restriction.to.node =
-                    way_start_and_end_iterator->first_segment_target_id;
-            }
-            else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
+        BOOST_ASSERT(edge_iterator->result.target == 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());
+
+        const double distance = coordinate_calculation::euclidean_distance(
+            edge_iterator->source_coordinate.lat, edge_iterator->source_coordinate.lon,
+            node_iterator->lat, node_iterator->lon);
+
+        const double weight = [distance](const InternalExtractorEdge::WeightData& data) {
+            switch (data.type)
             {
-                restrictions_iterator->restriction.to.node =
-                    way_start_and_end_iterator->last_segment_source_id;
+                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");
             }
-            ++restrictions_iterator;
+            return -1.0;
+        }(edge_iterator->weight_data);
+
+        auto& edge = edge_iterator->result;
+        edge.weight = std::max(1, static_cast<int>(std::floor(weight + .5)));
+
+        // assign new node id
+        auto id_iter = external_to_internal_node_id_map.find(node_iterator->node_id);
+        BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
+        edge.target = id_iter->second;
+
+        // orient edges consistently: source id < target id
+        // important for multi-edge removal
+        if (edge.source > edge.target)
+        {
+            std::swap(edge.source, edge.target);
+
+            // std::swap does not work with bit-fields
+            bool temp = edge.forward;
+            edge.forward = edge.backward;
+            edge.backward = temp;
         }
-        TIMER_STOP(fix_restriction_ends);
-        std::cout << "ok, after " << TIMER_SEC(fix_restriction_ends) << "s" << std::endl;
-
-        // serialize restrictions
-        std::ofstream restrictions_out_stream;
-        unsigned written_restriction_count = 0;
-        restrictions_out_stream.open(restrictions_file_name.c_str(), std::ios::binary);
-        restrictions_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
-        const auto count_position = restrictions_out_stream.tellp();
-        restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
-
-        for (const auto &restriction_container : restrictions_list)
+        ++edge_iterator;
+    }
+    TIMER_STOP(compute_weights);
+    std::cout << "ok, after " << TIMER_SEC(compute_weights) << "s" << std::endl;
+
+    // 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(), CmpEdgeByStartThenTargetID(), stxxl_memory);
+    TIMER_STOP(sort_edges_by_renumbered_start);
+    std::cout << "ok, after " << TIMER_SEC(sort_edges_by_renumbered_start) << "s" << std::endl;
+
+    BOOST_ASSERT(all_edges_list.size() > 0);
+    for (unsigned i = 0; i < all_edges_list.size();)
+    {
+        // only invalid edges left
+        if (all_edges_list[i].result.source == SPECIAL_NODEID)
         {
-            if (SPECIAL_NODEID != restriction_container.restriction.from.node &&
-                SPECIAL_NODEID != restriction_container.restriction.to.node)
-            {
-                restrictions_out_stream.write((char *)&(restriction_container.restriction),
-                                              sizeof(TurnRestriction));
-                ++written_restriction_count;
-            }
+            break;
+        }
+        // skip invalid edges
+        if (all_edges_list[i].result.target == SPECIAL_NODEID)
+        {
+            continue;
         }
-        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;
+        unsigned start_idx = i;
+        NodeID source = all_edges_list[i].result.source;
+        NodeID target = all_edges_list[i].result.target;
 
-        std::ofstream file_out_stream;
-        file_out_stream.open(output_file_name.c_str(), std::ios::binary);
-        file_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
-        file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
-        std::cout << "[extractor] Confirming/Writing used nodes     ... " << std::flush;
-        TIMER_START(write_nodes);
-        // identify all used nodes by a merging step of two sorted lists
-        auto node_iterator = all_nodes_list.begin();
-        auto node_id_iterator = used_node_id_list.begin();
-        while (node_id_iterator != used_node_id_list.end() && node_iterator != all_nodes_list.end())
+        int min_forward_weight = std::numeric_limits<int>::max();
+        int min_backward_weight = std::numeric_limits<int>::max();
+        unsigned min_forward_idx = std::numeric_limits<unsigned>::max();
+        unsigned min_backward_idx = std::numeric_limits<unsigned>::max();
+
+        // find minimal edge in both directions
+        while (all_edges_list[i].result.source == source &&
+               all_edges_list[i].result.target == target)
         {
-            if (*node_id_iterator < node_iterator->node_id)
+            if (all_edges_list[i].result.forward && all_edges_list[i].result.weight < min_forward_weight)
             {
-                ++node_id_iterator;
-                continue;
+                min_forward_idx = i;
             }
-            if (*node_id_iterator > node_iterator->node_id)
+            if (all_edges_list[i].result.backward && all_edges_list[i].result.weight < min_backward_weight)
             {
-                ++node_iterator;
-                continue;
+                min_backward_idx = i;
             }
-            BOOST_ASSERT(*node_id_iterator == node_iterator->node_id);
 
-            file_out_stream.write((char *)&(*node_iterator), sizeof(ExternalMemoryNode));
-
-            ++number_of_used_nodes;
-            ++node_id_iterator;
-            ++node_iterator;
+            // this also increments the outer loop counter!
+            i++;
         }
 
-        TIMER_STOP(write_nodes);
-        std::cout << "ok, after " << TIMER_SEC(write_nodes) << "s" << std::endl;
-
-        std::cout << "[extractor] setting number of nodes   ... " << std::flush;
-        std::ios::pos_type previous_file_position = file_out_stream.tellp();
-        file_out_stream.seekp(std::ios::beg + sizeof(FingerPrint));
-        file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
-        file_out_stream.seekp(previous_file_position);
-
-        std::cout << "ok" << std::endl;
-
-        // Sort edges by start.
-        std::cout << "[extractor] Sorting edges by start    ... " << std::flush;
-        TIMER_START(sort_edges_by_start);
-        stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByStartID(), stxxl_memory);
-        TIMER_STOP(sort_edges_by_start);
-        std::cout << "ok, after " << TIMER_SEC(sort_edges_by_start) << "s" << std::endl;
-
-        std::cout << "[extractor] Setting start coords      ... " << std::flush;
-        TIMER_START(set_start_coords);
-        file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
-        // Traverse list of edges and nodes in parallel and set start coord
-        node_iterator = all_nodes_list.begin();
-        auto edge_iterator = all_edges_list.begin();
-        while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
+        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());
+
+        if (min_backward_idx == min_forward_idx)
+        {
+            all_edges_list[min_forward_idx].result.is_split = false;
+            all_edges_list[min_forward_idx].result.forward = true;
+            all_edges_list[min_forward_idx].result.backward = true;
+        }
+        else
         {
-            if (edge_iterator->start < node_iterator->node_id)
+            bool has_forward = min_forward_idx != std::numeric_limits<unsigned>::max();
+            bool has_backward = min_backward_idx != std::numeric_limits<unsigned>::max();
+            if (has_forward)
             {
-                ++edge_iterator;
-                continue;
+                all_edges_list[min_forward_idx].result.forward = true;
+                all_edges_list[min_forward_idx].result.backward = false;
+                all_edges_list[min_forward_idx].result.is_split = has_backward;
             }
-            if (edge_iterator->start > node_iterator->node_id)
+            if (has_backward)
             {
-                node_iterator++;
-                continue;
+                std::swap(all_edges_list[min_backward_idx].result.source,
+                          all_edges_list[min_backward_idx].result.target);
+                all_edges_list[min_backward_idx].result.forward = true;
+                all_edges_list[min_backward_idx].result.backward = false;
+                all_edges_list[min_backward_idx].result.is_split = has_forward;
             }
-
-            BOOST_ASSERT(edge_iterator->start == node_iterator->node_id);
-            edge_iterator->source_coordinate.lat = node_iterator->lat;
-            edge_iterator->source_coordinate.lon = node_iterator->lon;
-            ++edge_iterator;
         }
-        TIMER_STOP(set_start_coords);
-        std::cout << "ok, after " << TIMER_SEC(set_start_coords) << "s" << std::endl;
-
-        // 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(), CmpEdgeByTargetID(),
-                    stxxl_memory);
-        TIMER_STOP(sort_edges_by_target);
-        std::cout << "ok, after " << TIMER_SEC(sort_edges_by_target) << "s" << std::endl;
-
-        std::cout << "[extractor] Setting target coords     ... " << std::flush;
-        TIMER_START(set_target_coords);
-        // Traverse list of edges and nodes in parallel and set target coord
-        node_iterator = all_nodes_list.begin();
-        edge_iterator = all_edges_list.begin();
-
-        // Also serializes the edges
-        while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
+
+        // invalidate all unused edges
+        for (unsigned j = start_idx; j < i; j++)
         {
-            if (edge_iterator->target < node_iterator->node_id)
-            {
-                ++edge_iterator;
-                continue;
-            }
-            if (edge_iterator->target > node_iterator->node_id)
+            if (j == min_forward_idx || j == min_backward_idx)
             {
-                ++node_iterator;
                 continue;
             }
-            BOOST_ASSERT(edge_iterator->target == node_iterator->node_id);
-            if (edge_iterator->source_coordinate.lat != std::numeric_limits<int>::min() &&
-                edge_iterator->source_coordinate.lon != std::numeric_limits<int>::min())
-            {
-                BOOST_ASSERT(edge_iterator->speed != -1);
-                edge_iterator->target_coordinate.lat = node_iterator->lat;
-                edge_iterator->target_coordinate.lon = node_iterator->lon;
-
-                const double distance = coordinate_calculation::euclidean_distance(
-                    edge_iterator->source_coordinate.lat, edge_iterator->source_coordinate.lon,
-                    node_iterator->lat, node_iterator->lon);
-
-                const double weight = (distance * 10.) / (edge_iterator->speed / 3.6);
-                int integer_weight = std::max(
-                    1, (int)std::floor(
-                           (edge_iterator->is_duration_set ? edge_iterator->speed : weight) + .5));
-                // FIXME: This means we have a _minimum_ edge length of 1m
-                // maybe use dm as base unit?
-                const int integer_distance = std::max(1, (int)distance);
-                const short zero = 0;
-                const short one = 1;
-                const bool yes = true;
-                const bool no = false;
-
-                file_out_stream.write((char *)&edge_iterator->start, sizeof(unsigned));
-                file_out_stream.write((char *)&edge_iterator->target, sizeof(unsigned));
-                file_out_stream.write((char *)&integer_distance, sizeof(int));
-                switch (edge_iterator->direction)
-                {
-                case ExtractionWay::notSure:
-                    file_out_stream.write((char *)&zero, sizeof(short));
-                    break;
-                case ExtractionWay::oneway:
-                    file_out_stream.write((char *)&one, sizeof(short));
-                    break;
-                case ExtractionWay::bidirectional:
-                    file_out_stream.write((char *)&zero, sizeof(short));
-                    break;
-                case ExtractionWay::opposite:
-                    file_out_stream.write((char *)&one, sizeof(short));
-                    break;
-                default:
-                    throw osrm::exception("edge has broken direction");
-                }
-
-                file_out_stream.write((char *)&integer_weight, sizeof(int));
-                file_out_stream.write((char *)&edge_iterator->name_id, sizeof(unsigned));
-                if (edge_iterator->is_roundabout)
-                {
-                    file_out_stream.write((char *)&yes, sizeof(bool));
-                }
-                else
-                {
-                    file_out_stream.write((char *)&no, sizeof(bool));
-                }
-                if (edge_iterator->is_in_tiny_cc)
-                {
-                    file_out_stream.write((char *)&yes, sizeof(bool));
-                }
-                else
-                {
-                    file_out_stream.write((char *)&no, sizeof(bool));
-                }
-                if (edge_iterator->is_access_restricted)
-                {
-                    file_out_stream.write((char *)&yes, sizeof(bool));
-                }
-                else
-                {
-                    file_out_stream.write((char *)&no, sizeof(bool));
-                }
-
-                // cannot take adress of bit field, so use local
-                const TravelMode travel_mode = edge_iterator->travel_mode;
-                file_out_stream.write((char *)&travel_mode, sizeof(TravelMode));
-
-                if (edge_iterator->is_split)
-                {
-                    file_out_stream.write((char *)&yes, sizeof(bool));
-                }
-                else
-                {
-                    file_out_stream.write((char *)&no, sizeof(bool));
-                }
-                ++number_of_used_edges;
-            }
-            ++edge_iterator;
+            all_edges_list[j].result.source = SPECIAL_NODEID;
+            all_edges_list[j].result.target = SPECIAL_NODEID;
         }
-        TIMER_STOP(set_target_coords);
-        std::cout << "ok, after " << TIMER_SEC(set_target_coords) << "s" << std::endl;
+    }
+}
 
-        std::cout << "[extractor] setting number of edges   ... " << std::flush;
+void ExtractionContainers::WriteEdges(std::ofstream& file_out_stream) const
+{
+    std::cout << "[extractor] Writing used egdes       ... " << std::flush;
+    TIMER_START(write_edges);
+    // Traverse list of edges and nodes in parallel and set target coord
+    unsigned number_of_used_edges = 0;
 
-        file_out_stream.seekp(previous_file_position);
-        file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
-        file_out_stream.close();
-        std::cout << "ok" << std::endl;
+    auto start_position = file_out_stream.tellp();
+    file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
 
-        std::cout << "[extractor] writing street name index ... " << std::flush;
-        TIMER_START(write_name_index);
-        std::string name_file_streamName = (output_file_name + ".names");
-        boost::filesystem::ofstream name_file_stream(name_file_streamName, std::ios::binary);
+    for (const auto& edge : all_edges_list)
+    {
+        if (edge.result.source == SPECIAL_NODEID || edge.result.target == SPECIAL_NODEID)
+        {
+            continue;
+        }
+
+        file_out_stream.write((char*) &edge.result, sizeof(NodeBasedEdge));
+        number_of_used_edges++;
+    }
+    TIMER_STOP(write_edges);
+    std::cout << "ok, after " << TIMER_SEC(write_edges) << "s" << std::endl;
 
-        unsigned total_length = 0;
-        std::vector<unsigned> name_lengths;
-        for (const std::string &temp_string : name_list)
+    std::cout << "[extractor] setting number of edges   ... " << std::flush;
+    file_out_stream.seekp(start_position);
+    file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
+    std::cout << "ok" << std::endl;
+
+    SimpleLogger().Write() << "Processed " << number_of_used_edges << " edges";
+}
+
+void ExtractionContainers::WriteNodes(std::ofstream& file_out_stream) const
+{
+    unsigned number_of_used_nodes = 0;
+    // write dummy value, will be overwritten later
+    file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
+    std::cout << "[extractor] Confirming/Writing used nodes     ... " << std::flush;
+    TIMER_START(write_nodes);
+    // identify all used nodes by a merging step of two sorted lists
+    auto node_iterator = all_nodes_list.begin();
+    auto node_id_iterator = used_node_id_list.begin();
+    while (node_id_iterator != used_node_id_list.end() && node_iterator != all_nodes_list.end())
+    {
+        if (*node_id_iterator < node_iterator->node_id)
         {
-            const unsigned string_length =
-                std::min(static_cast<unsigned>(temp_string.length()), 255u);
-            name_lengths.push_back(string_length);
-            total_length += string_length;
+            ++node_id_iterator;
+            continue;
         }
+        if (*node_id_iterator > node_iterator->node_id)
+        {
+            ++node_iterator;
+            continue;
+        }
+        BOOST_ASSERT(*node_id_iterator == node_iterator->node_id);
 
-        RangeTable<> table(name_lengths);
-        name_file_stream << table;
+        file_out_stream.write((char *)&(*node_iterator), sizeof(ExternalMemoryNode));
 
-        name_file_stream.write((char *)&total_length, sizeof(unsigned));
-        // write all chars consecutively
-        for (const std::string &temp_string : name_list)
+        ++number_of_used_nodes;
+        ++node_id_iterator;
+        ++node_iterator;
+    }
+    TIMER_STOP(write_nodes);
+    std::cout << "ok, after " << TIMER_SEC(write_nodes) << "s" << std::endl;
+
+    std::cout << "[extractor] setting number of nodes   ... " << std::flush;
+    std::ios::pos_type previous_file_position = file_out_stream.tellp();
+    file_out_stream.seekp(std::ios::beg + sizeof(FingerPrint));
+    file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
+    file_out_stream.seekp(previous_file_position);
+    std::cout << "ok" << std::endl;
+
+    SimpleLogger().Write() << "Processed " << number_of_used_nodes << " nodes";
+}
+
+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 auto count_position = restrictions_out_stream.tellp();
+    restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
+
+    for (const auto &restriction_container : restrictions_list)
+    {
+        if (SPECIAL_NODEID != restriction_container.restriction.from.node &&
+            SPECIAL_NODEID != restriction_container.restriction.via.node &&
+            SPECIAL_NODEID != restriction_container.restriction.to.node)
         {
-            const unsigned string_length =
-                std::min(static_cast<unsigned>(temp_string.length()), 255u);
-            name_file_stream.write(temp_string.c_str(), string_length);
+            restrictions_out_stream.write((char *)&(restriction_container.restriction),
+                                          sizeof(TurnRestriction));
+            ++written_restriction_count;
         }
+    }
+    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;
+}
 
-        name_file_stream.close();
-        TIMER_STOP(write_name_index);
-        std::cout << "ok, after " << TIMER_SEC(write_name_index) << "s" << std::endl;
+void ExtractionContainers::PrepareRestrictions()
+{
+    std::cout << "[extractor] Sorting used ways         ... " << std::flush;
+    TIMER_START(sort_ways);
+    stxxl::sort(way_start_end_id_list.begin(), way_start_end_id_list.end(),
+                FirstAndLastSegmentOfWayStxxlCompare(), stxxl_memory);
+    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;
+    TIMER_START(sort_restrictions);
+    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;
+
+    std::cout << "[extractor] Fixing restriction starts ... " << std::flush;
+    TIMER_START(fix_restriction_starts);
+    auto restrictions_iterator = restrictions_list.begin();
+    auto way_start_and_end_iterator = way_start_end_id_list.cbegin();
+
+    while (way_start_and_end_iterator != way_start_end_id_list.cend() &&
+           restrictions_iterator != restrictions_list.end())
+    {
+        if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.from.way)
+        {
+            ++way_start_and_end_iterator;
+            continue;
+        }
+
+        if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.from.way)
+        {
+            SimpleLogger().Write(LogLevel::logDEBUG) << "Restriction references invalid way: " << restrictions_iterator->restriction.from.way;
+            restrictions_iterator->restriction.from.node = SPECIAL_NODEID;
+            ++restrictions_iterator;
+            continue;
+        }
+
+        BOOST_ASSERT(way_start_and_end_iterator->way_id ==
+                     restrictions_iterator->restriction.from.way);
+        // we do not remap the via id yet, since we will need it for the to node as well
+        const NodeID via_node_id = restrictions_iterator->restriction.via.node;
+
+        // 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())
+        {
+            SimpleLogger().Write(LogLevel::logDEBUG) << "Restriction references invalid node: " << restrictions_iterator->restriction.via.node;
+            restrictions_iterator->restriction.via.node = SPECIAL_NODEID;
+            ++restrictions_iterator;
+            continue;
+        }
 
-        SimpleLogger().Write() << "Processed " << number_of_used_nodes << " nodes and "
-                               << number_of_used_edges << " edges";
+        if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
+        {
+            // assign new from node id
+            auto id_iter = external_to_internal_node_id_map.find(
+                    way_start_and_end_iterator->first_segment_target_id);
+            BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
+            restrictions_iterator->restriction.from.node = id_iter->second;
+        }
+        else if (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(
+                    way_start_and_end_iterator->last_segment_source_id);
+            BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
+            restrictions_iterator->restriction.from.node = id_iter->second;
+        }
+        ++restrictions_iterator;
     }
-    catch (const std::exception &e)
+
+    TIMER_STOP(fix_restriction_starts);
+    std::cout << "ok, after " << TIMER_SEC(fix_restriction_starts) << "s" << std::endl;
+
+    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);
+    TIMER_STOP(sort_restrictions_to);
+    std::cout << "ok, after " << TIMER_SEC(sort_restrictions_to) << "s" << std::endl;
+
+    std::cout << "[extractor] Fixing restriction ends   ... " << std::flush;
+    TIMER_START(fix_restriction_ends);
+    restrictions_iterator = restrictions_list.begin();
+    way_start_and_end_iterator = way_start_end_id_list.cbegin();
+    while (way_start_and_end_iterator != way_start_end_id_list.cend() &&
+           restrictions_iterator != restrictions_list.end())
     {
-        std::cerr << "Caught Execption:" << e.what() << std::endl;
+        if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.to.way)
+        {
+            ++way_start_and_end_iterator;
+            continue;
+        }
+        if (restrictions_iterator->restriction.from.node == SPECIAL_NODEID ||
+            restrictions_iterator->restriction.via.node == SPECIAL_NODEID)
+        {
+            ++restrictions_iterator;
+            continue;
+        }
+        if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.to.way)
+        {
+            SimpleLogger().Write(LogLevel::logDEBUG) << "Restriction references invalid way: " << restrictions_iterator->restriction.to.way;
+            restrictions_iterator->restriction.to.way = SPECIAL_NODEID;
+            ++restrictions_iterator;
+            continue;
+        }
+        BOOST_ASSERT(way_start_and_end_iterator->way_id ==
+                     restrictions_iterator->restriction.to.way);
+        const NodeID via_node_id = restrictions_iterator->restriction.via.node;
+
+        // assign new via node id
+        auto via_id_iter = external_to_internal_node_id_map.find(via_node_id);
+        BOOST_ASSERT(via_id_iter != external_to_internal_node_id_map.end());
+        restrictions_iterator->restriction.via.node = via_id_iter->second;
+
+        if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
+        {
+            auto to_id_iter = external_to_internal_node_id_map.find(
+                    way_start_and_end_iterator->first_segment_target_id);
+            BOOST_ASSERT(to_id_iter != external_to_internal_node_id_map.end());
+            restrictions_iterator->restriction.to.node = to_id_iter->second;
+        }
+        else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
+        {
+            auto to_id_iter = external_to_internal_node_id_map.find(
+                    way_start_and_end_iterator->last_segment_source_id);
+            BOOST_ASSERT(to_id_iter != external_to_internal_node_id_map.end());
+            restrictions_iterator->restriction.to.node = to_id_iter->second;
+        }
+        ++restrictions_iterator;
     }
+    TIMER_STOP(fix_restriction_ends);
+    std::cout << "ok, after " << TIMER_SEC(fix_restriction_ends) << "s" << std::endl;
 }
diff --git a/extractor/extraction_containers.hpp b/extractor/extraction_containers.hpp
index d04f595..ef71d05 100644
--- a/extractor/extraction_containers.hpp
+++ b/extractor/extraction_containers.hpp
@@ -32,13 +32,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "first_and_last_segment_of_way.hpp"
 #include "../data_structures/external_memory_node.hpp"
 #include "../data_structures/restriction.hpp"
-#include "../util/fingerprint.hpp"
 
 #include <stxxl/vector>
+#include <unordered_map>
 
 /**
  * Uses external memory containers from stxxl to store all the data that
  * is collected by the extractor callbacks.
+ *
+ * The data is the filtered, aggregated and finally written to disk.
  */
 class ExtractionContainers
 {
@@ -49,6 +51,14 @@ class ExtractionContainers
 #else
     const static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? INT_MAX : UINT_MAX);
 #endif
+    void PrepareNodes();
+    void PrepareRestrictions();
+    void PrepareEdges();
+
+    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<NodeID>;
     using STXXLNodeVector = stxxl::vector<ExternalMemoryNode>;
@@ -63,14 +73,15 @@ class ExtractionContainers
     STXXLStringVector name_list;
     STXXLRestrictionsVector restrictions_list;
     STXXLWayIDStartEndVector way_start_end_id_list;
-    const FingerPrint fingerprint;
+    std::unordered_map<NodeID, NodeID> external_to_internal_node_id_map;
 
     ExtractionContainers();
 
     ~ExtractionContainers();
 
     void PrepareData(const std::string &output_file_name,
-                     const std::string &restrictions_file_name);
+                     const std::string &restrictions_file_name,
+                     const std::string &names_file_name);
 };
 
 #endif /* EXTRACTION_CONTAINERS_HPP */
diff --git a/extractor/extraction_helper_functions.hpp b/extractor/extraction_helper_functions.hpp
index d10200a..e61e543 100644
--- a/extractor/extraction_helper_functions.hpp
+++ b/extractor/extraction_helper_functions.hpp
@@ -102,7 +102,7 @@ unsigned parseDuration(const std::string &s)
                 minutes = cast::string_to_int(result[1]);
                 hours = cast::string_to_int(result[0]);
             }
-            return 10 * (3600 * hours + 60 * minutes + seconds);
+            return (3600 * hours + 60 * minutes + seconds);
         }
     }
     else if (iso_8601_duration_is_valid(s))
diff --git a/extractor/extractor.cpp b/extractor/extractor.cpp
index fce0f88..c1a0a21 100644
--- a/extractor/extractor.cpp
+++ b/extractor/extractor.cpp
@@ -82,7 +82,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *  .restrictions : Turn restrictions that are used my osrm-prepare to construct the edge-expanded graph
  *
  */
-int extractor::run(const ExtractorConfig &extractor_config)
+int extractor::run()
 {
     try
     {
@@ -91,20 +91,20 @@ int extractor::run(const ExtractorConfig &extractor_config)
 
         const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
         const auto number_of_threads =
-            std::min(recommended_num_threads, extractor_config.requested_num_threads);
+            std::min(recommended_num_threads, config.requested_num_threads);
         tbb::task_scheduler_init init(number_of_threads);
 
-        SimpleLogger().Write() << "Input file: " << extractor_config.input_path.filename().string();
-        SimpleLogger().Write() << "Profile: " << extractor_config.profile_path.filename().string();
+        SimpleLogger().Write() << "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(extractor_config.profile_path.string().c_str());
+        ScriptingEnvironment scripting_environment(config.profile_path.string().c_str());
 
         ExtractionContainers extraction_containers;
         auto extractor_callbacks = osrm::make_unique<ExtractorCallbacks>(extraction_containers);
 
-        const osmium::io::File input_file(extractor_config.input_path.string());
+        const osmium::io::File input_file(config.input_path.string());
         osmium::io::Reader reader(input_file);
         const osmium::io::Header header = reader.header();
 
@@ -131,7 +131,7 @@ int extractor::run(const ExtractorConfig &extractor_config)
         }
         SimpleLogger().Write() << "timestamp: " << timestamp;
 
-        boost::filesystem::ofstream timestamp_out(extractor_config.timestamp_file_name);
+        boost::filesystem::ofstream timestamp_out(config.timestamp_file_name);
         timestamp_out.write(timestamp.c_str(), timestamp.length());
         timestamp_out.close();
 
@@ -236,12 +236,13 @@ int extractor::run(const ExtractorConfig &extractor_config)
             return 1;
         }
 
-        extraction_containers.PrepareData(extractor_config.output_file_name,
-                                          extractor_config.restriction_file_name);
+        extraction_containers.PrepareData(config.output_file_name,
+                                          config.restriction_file_name,
+                                          config.names_file_name);
         TIMER_STOP(extracting);
         SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting) << "s";
         SimpleLogger().Write() << "To prepare the data for routing, run: "
-                               << "./osrm-prepare " << extractor_config.output_file_name
+                               << "./osrm-prepare " << config.output_file_name
                                << std::endl;
     }
     catch (std::exception &e)
diff --git a/extractor/extractor.hpp b/extractor/extractor.hpp
index 8ea56c3..72defca 100644
--- a/extractor/extractor.hpp
+++ b/extractor/extractor.hpp
@@ -30,8 +30,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "extractor_options.hpp"
 
-struct extractor
+class extractor
 {
-    int run(const ExtractorConfig &extractor_config);
+public:
+    extractor(const ExtractorConfig &extractor_config)
+        : config(extractor_config) {}
+    int run();
+private:
+   ExtractorConfig config;
 };
 #endif /* EXTRACTOR_HPP */
diff --git a/extractor/extractor_callbacks.cpp b/extractor/extractor_callbacks.cpp
index deef831..bab309d 100644
--- a/extractor/extractor_callbacks.cpp
+++ b/extractor/extractor_callbacks.cpp
@@ -108,17 +108,40 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
                                        << " of size " << input_way.nodes().size();
         return;
     }
+
+    InternalExtractorEdge::WeightData forward_weight_data;
+    InternalExtractorEdge::WeightData backward_weight_data;
+
     if (0 < parsed_way.duration)
     {
-        // TODO: iterate all way segments and set duration corresponding to the length of each
-        // segment
-        const_cast<ExtractionWay &>(parsed_way).forward_speed =
-            parsed_way.duration / (input_way.nodes().size() - 1);
-        const_cast<ExtractionWay &>(parsed_way).backward_speed =
-            parsed_way.duration / (input_way.nodes().size() - 1);
+        const unsigned num_edges = (input_way.nodes().size() - 1);
+        // FIXME We devide by the numer of nodes here, but should rather consider
+        // the length of each segment. We would eigther have to compute the length
+        // of the whole way here (we can't: no node coordinates) or push that back
+        // to the container and keep a reference to the way.
+        forward_weight_data.duration = parsed_way.duration / num_edges;
+        forward_weight_data.type = InternalExtractorEdge::WeightType::WAY_DURATION;
+        backward_weight_data.duration = parsed_way.duration / num_edges;
+        backward_weight_data.type = InternalExtractorEdge::WeightType::WAY_DURATION;
+    }
+    else
+    {
+        if (parsed_way.forward_speed > 0 &&
+            parsed_way.forward_travel_mode != TRAVEL_MODE_INACCESSIBLE)
+        {
+            forward_weight_data.speed = parsed_way.forward_speed;
+            forward_weight_data.type = InternalExtractorEdge::WeightType::SPEED;
+        }
+        if (parsed_way.backward_speed > 0 &&
+            parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE)
+        {
+            backward_weight_data.speed = parsed_way.backward_speed;
+            backward_weight_data.type = InternalExtractorEdge::WeightType::SPEED;
+        }
     }
 
-    if (std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.forward_speed))
+    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();
         return;
@@ -144,36 +167,34 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
                             ((parsed_way.forward_speed != parsed_way.backward_speed) ||
                              (parsed_way.forward_travel_mode != parsed_way.backward_travel_mode));
 
-    auto pair_wise_segment_split =
+    // lambda to add edge to container
+    auto pair_wise_segment_split_forward =
         [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
     {
-        // SimpleLogger().Write() << "adding edge (" << first_node.ref() << "," <<
-        // last_node.ref() << "), fwd speed: " << parsed_way.forward_speed;
+        const bool forward_only = split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode;
         external_memory.all_edges_list.push_back(InternalExtractorEdge(
-            first_node.ref(), last_node.ref(),
-            ((split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode)
-                 ? ExtractionWay::oneway
-                 : ExtractionWay::bidirectional),
-            parsed_way.forward_speed, name_id, parsed_way.roundabout, parsed_way.ignore_in_grid,
-            (0 < parsed_way.duration), parsed_way.is_access_restricted,
-            parsed_way.forward_travel_mode, split_edge));
+            first_node.ref(), last_node.ref(), name_id, forward_weight_data,
+            true, !forward_only, parsed_way.roundabout, parsed_way.ignore_in_grid,
+            parsed_way.is_access_restricted, parsed_way.forward_travel_mode, split_edge));
         external_memory.used_node_id_list.push_back(first_node.ref());
     };
 
     const bool is_opposite_way = TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode;
+    // traverse way in reverse in this case
     if (is_opposite_way)
     {
+        // why don't we have to swap the parsed_way.forward/backward speed here as well
         const_cast<ExtractionWay &>(parsed_way).forward_travel_mode =
             parsed_way.backward_travel_mode;
         const_cast<ExtractionWay &>(parsed_way).backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
         osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(),
-                            pair_wise_segment_split);
+                            pair_wise_segment_split_forward);
         external_memory.used_node_id_list.push_back(input_way.nodes().front().ref());
     }
     else
     {
         osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(),
-                            pair_wise_segment_split);
+                            pair_wise_segment_split_forward);
         external_memory.used_node_id_list.push_back(input_way.nodes().back().ref());
     }
 
@@ -187,22 +208,19 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
 
     if (split_edge)
     { // Only true if the way should be split
-        BOOST_ASSERT(parsed_way.backward_travel_mode > 0);
+        BOOST_ASSERT(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE);
         auto pair_wise_segment_split_2 =
             [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
         {
-            // SimpleLogger().Write() << "adding edge (" << last_node.ref() << "," <<
-            // first_node.ref() << "), bwd speed: " << parsed_way.backward_speed;
             external_memory.all_edges_list.push_back(InternalExtractorEdge(
-                last_node.ref(), first_node.ref(), ExtractionWay::oneway, parsed_way.backward_speed,
-                name_id, parsed_way.roundabout, parsed_way.ignore_in_grid,
-                (0 < parsed_way.duration), parsed_way.is_access_restricted,
-                parsed_way.backward_travel_mode, split_edge));
+                last_node.ref(), first_node.ref(), name_id, backward_weight_data,
+                true, false, parsed_way.roundabout, parsed_way.ignore_in_grid,
+                parsed_way.is_access_restricted, parsed_way.backward_travel_mode, split_edge));
+            external_memory.used_node_id_list.push_back(last_node.ref());
         };
 
         if (is_opposite_way)
         {
-            // SimpleLogger().Write() << "opposite2";
             osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(),
                                 pair_wise_segment_split_2);
             external_memory.used_node_id_list.push_back(input_way.nodes().front().ref());
@@ -211,7 +229,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
         {
             osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(),
                                 pair_wise_segment_split_2);
-            external_memory.used_node_id_list.push_back(input_way.nodes().back().ref());
+            external_memory.used_node_id_list.push_back(input_way.nodes().front().ref());
         }
 
         external_memory.way_start_end_id_list.push_back(
diff --git a/extractor/extractor_options.cpp b/extractor/extractor_options.cpp
index 9ae5cd4..23cbacc 100644
--- a/extractor/extractor_options.cpp
+++ b/extractor/extractor_options.cpp
@@ -135,6 +135,7 @@ void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_confi
     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();
     std::string::size_type pos = extractor_config.output_file_name.find(".osm.bz2");
     if (pos == std::string::npos)
@@ -156,12 +157,14 @@ void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_confi
         {
             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");
         }
         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");
         }
     }
@@ -169,6 +172,7 @@ void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_confi
     {
         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");
     }
 }
diff --git a/extractor/extractor_options.hpp b/extractor/extractor_options.hpp
index 5712ea0..c164f6a 100644
--- a/extractor/extractor_options.hpp
+++ b/extractor/extractor_options.hpp
@@ -48,6 +48,7 @@ struct ExtractorConfig
 
     std::string output_file_name;
     std::string restriction_file_name;
+    std::string names_file_name;
     std::string timestamp_file_name;
 
     unsigned requested_num_threads;
diff --git a/extractor/internal_extractor_edge.hpp b/extractor/internal_extractor_edge.hpp
index 27e1af1..15f3c0d 100644
--- a/extractor/internal_extractor_edge.hpp
+++ b/extractor/internal_extractor_edge.hpp
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "../typedefs.h"
 #include "../data_structures/travel_mode.hpp"
+#include "../data_structures/import_edge.hpp"
 
 #include <boost/assert.hpp>
 
@@ -37,83 +38,108 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct InternalExtractorEdge
 {
-    InternalExtractorEdge()
-        : start(0), target(0), speed(0), name_id(0), direction(0), is_roundabout(false),
-          is_in_tiny_cc(false), is_duration_set(false), is_access_restricted(false),
-          is_split(false), travel_mode(TRAVEL_MODE_INACCESSIBLE)
+    // specify the type of the weight data
+    enum class WeightType : char {
+        INVALID,
+        SPEED,
+        EDGE_DURATION,
+        WAY_DURATION,
+    };
+
+    struct WeightData
+    {
+
+        WeightData() : duration(0.0), type(WeightType::INVALID)
+        {
+        }
+
+        union
+        {
+            double duration;
+            double speed;
+        };
+        WeightType type;
+    };
+
+    explicit InternalExtractorEdge()
+        : result(0, 0, 0, 0, false, false, false, false, false,
+                TRAVEL_MODE_INACCESSIBLE, false)
     {
     }
 
-    explicit InternalExtractorEdge(NodeID start,
-                                   NodeID target,
-                                   short direction,
-                                   double speed,
-                                   unsigned name_id,
-                                   bool is_roundabout,
-                                   bool is_in_tiny_cc,
-                                   bool is_duration_set,
-                                   bool is_access_restricted,
-                                   TravelMode travel_mode,
-                                   bool is_split)
-        : start(start), target(target), speed(speed), name_id(name_id), direction(direction),
-          is_roundabout(is_roundabout), is_in_tiny_cc(is_in_tiny_cc),
-          is_duration_set(is_duration_set), is_access_restricted(is_access_restricted),
-          is_split(is_split), travel_mode(travel_mode)
+    explicit InternalExtractorEdge(NodeID source,
+                           NodeID target,
+                           NodeID name_id,
+                           const WeightData& weight_data,
+                           bool forward,
+                           bool backward,
+                           bool roundabout,
+                           bool in_tiny_cc,
+                           bool access_restricted,
+                           TravelMode travel_mode,
+                           bool is_split)
+        : result(source, target, name_id, 0, forward, backward, roundabout,
+                 in_tiny_cc, access_restricted, travel_mode, is_split),
+          weight_data(weight_data)
     {
     }
 
+    // data that will be written to disk
+    NodeBasedEdge result;
+    // intermediate edge weight
+    WeightData weight_data;
+    // coordinate of the source node
+    FixedPointCoordinate source_coordinate;
+
+
     // necessary static util functions for stxxl's sorting
     static InternalExtractorEdge min_value()
     {
-        return InternalExtractorEdge(0, 0, 0, 0, 0, false, false, false, false,
-                                     TRAVEL_MODE_INACCESSIBLE, false);
+        return InternalExtractorEdge(0, 0, 0, WeightData(), false, false, false,
+                                     false, false, TRAVEL_MODE_INACCESSIBLE, false);
     }
     static InternalExtractorEdge max_value()
     {
-        return InternalExtractorEdge(SPECIAL_NODEID, SPECIAL_NODEID, 0, 0, 0, false, false, false,
-                                     false, TRAVEL_MODE_INACCESSIBLE, false);
+        return InternalExtractorEdge(SPECIAL_NODEID, SPECIAL_NODEID, 0, WeightData(), false, false,
+                                     false, false, false, TRAVEL_MODE_INACCESSIBLE, false);
     }
+};
 
-    NodeID start;
-    NodeID target;
-    double speed;
-    unsigned name_id;
-    short direction;
-    bool is_roundabout : 1;
-    bool is_in_tiny_cc : 1;
-    bool is_duration_set : 1;
-    bool is_access_restricted : 1;
-    bool is_split : 1;
-    TravelMode travel_mode : 4;
+struct CmpEdgeByStartThenTargetID
+{
+    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));
+    }
 
-    FixedPointCoordinate source_coordinate;
-    FixedPointCoordinate target_coordinate;
+    value_type max_value() { return InternalExtractorEdge::max_value(); }
+    value_type min_value() { return InternalExtractorEdge::min_value(); }
 };
 
 struct CmpEdgeByStartID
 {
     using value_type = InternalExtractorEdge;
-    bool operator()(const InternalExtractorEdge &a, const InternalExtractorEdge &b) const
+    bool operator()(const InternalExtractorEdge &lhs, const InternalExtractorEdge &rhs) const
     {
-        return a.start < b.start;
+        return lhs.result.source < rhs.result.source;
     }
 
     value_type max_value() { return InternalExtractorEdge::max_value(); }
-
     value_type min_value() { return InternalExtractorEdge::min_value(); }
 };
 
 struct CmpEdgeByTargetID
 {
     using value_type = InternalExtractorEdge;
-
-    bool operator()(const InternalExtractorEdge &a, const InternalExtractorEdge &b) const
+    bool operator()(const InternalExtractorEdge &lhs, const InternalExtractorEdge &rhs) const
     {
-        return a.target < b.target;
+        return lhs.result.target < rhs.result.target;
     }
 
     value_type max_value() { return InternalExtractorEdge::max_value(); }
-
     value_type min_value() { return InternalExtractorEdge::min_value(); }
 };
 
diff --git a/extractor/restriction_parser.cpp b/extractor/restriction_parser.cpp
index 77dae9c..9b209b7 100644
--- a/extractor/restriction_parser.cpp
+++ b/extractor/restriction_parser.cpp
@@ -44,7 +44,7 @@ namespace
 {
 int lua_error_callback(lua_State *lua_state)
 {
-    luabind::object error_msg(luabind::from_stack(lua_state, -1));
+    std::string error_msg = lua_tostring(lua_state, -1);
     std::ostringstream error_stream;
     error_stream << error_msg;
     throw osrm::exception("ERROR occured in profile script:\n" + error_stream.str());
diff --git a/extractor/scripting_environment.cpp b/extractor/scripting_environment.cpp
index 9727722..b32ab4b 100644
--- a/extractor/scripting_environment.cpp
+++ b/extractor/scripting_environment.cpp
@@ -53,7 +53,7 @@ auto get_value_by_key(T const &object, const char *key) -> decltype(object.get_v
 int lua_error_callback(lua_State *L) // This is so I can use my own function as an
 // exception handler, pcall_log()
 {
-    luabind::object error_msg(luabind::from_stack(L, -1));
+    std::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());
diff --git a/features/bicycle/access.feature b/features/bicycle/access.feature
index 2087327..3a2fffb 100644
--- a/features/bicycle/access.feature
+++ b/features/bicycle/access.feature
@@ -120,7 +120,7 @@ Feature: Bike - Access tags on ways
             | no           |              |              |       |
             | private      |              |              |       |
             | agricultural |              |              |       |
-            | forestery    |              |              |       |
+            | forestry     |              |              |       |
             |              | yes          |              | x     |
             |              | permissive   |              | x     |
             |              | designated   |              | x     |
@@ -128,7 +128,7 @@ Feature: Bike - Access tags on ways
             |              | no           |              |       |
             |              | private      |              |       |
             |              | agricultural |              |       |
-            |              | forestery    |              |       |
+            |              | forestry     |              |       |
             |              |              | yes          | x     |
             |              |              | permissive   | x     |
             |              |              | designated   | x     |
@@ -136,7 +136,7 @@ Feature: Bike - Access tags on ways
             |              |              | no           |       |
             |              |              | private      |       |
             |              |              | agricultural |       |
-            |              |              | forestery    |       |
+            |              |              | forestry     |       |
 
     Scenario: Bike - Access tags on both node and way
         Then routability should be
diff --git a/features/bicycle/access_node.feature b/features/bicycle/access_node.feature
index 5a6f2b5..05e94fe 100644
--- a/features/bicycle/access_node.feature
+++ b/features/bicycle/access_node.feature
@@ -7,20 +7,21 @@ Feature: Bike - Access tags on nodes
 
     Scenario: Bike - Access tag hierachy on nodes
         Then routability should be
-            | node/access | node/vehicle | node/bicycle | bothw |
-            |             |              |              | x     |
-            | yes         |              |              | x     |
-            | no          |              |              |       |
-            |             | yes          |              | x     |
-            |             | no           |              |       |
-            | no          | yes          |              | x     |
-            | yes         | no           |              |       |
-            |             |              | yes          | x     |
-            |             |              | no           |       |
-            | no          |              | yes          | x     |
-            | yes         |              | no           |       |
-            |             | no           | yes          | x     |
-            |             | yes          | no           |       |
+            | node/access | node/vehicle | node/bicycle | node/highway  | bothw |
+            |             |              |              |               | x     |
+            | yes         |              |              |               | x     |
+            | no          |              |              |               |       |
+            |             | yes          |              |               | x     |
+            |             | no           |              |               |       |
+            | no          | yes          |              |               | x     |
+            | yes         | no           |              |               |       |
+            |             |              | yes          |               | x     |
+            |             |              | no           |               |       |
+            |             |              | no           | crossing      | x     |
+            | no          |              | yes          |               | x     |
+            | yes         |              | no           |               |       |
+            |             | no           | yes          |               | x     |
+            |             | yes          | no           |               |       |
 
     Scenario: Bike - Overwriting implied acccess on nodes doesn't overwrite way
         Then routability should be
@@ -45,7 +46,7 @@ Feature: Bike - Access tags on nodes
             | no           |              |              |       |
             | private      |              |              |       |
             | agricultural |              |              |       |
-            | forestery    |              |              |       |
+            | forestry     |              |              |       |
             |              | yes          |              | x     |
             |              | permissive   |              | x     |
             |              | designated   |              | x     |
@@ -53,7 +54,7 @@ Feature: Bike - Access tags on nodes
             |              | no           |              |       |
             |              | private      |              |       |
             |              | agricultural |              |       |
-            |              | forestery    |              |       |
+            |              | forestry     |              |       |
             |              |              | yes          | x     |
             |              |              | permissive   | x     |
             |              |              | designated   | x     |
@@ -61,4 +62,4 @@ Feature: Bike - Access tags on nodes
             |              |              | no           |       |
             |              |              | private      |       |
             |              |              | agricultural |       |
-            |              |              | forestery    |       |
+            |              |              | forestry     |       |
diff --git a/features/bicycle/surface.feature b/features/bicycle/surface.feature
index 216307b..8d303aa 100644
--- a/features/bicycle/surface.feature
+++ b/features/bicycle/surface.feature
@@ -16,7 +16,7 @@ Feature: Bike - Surfaces
             | cycleway | unpaved               | 120s  |
             | cycleway | fine_gravel           | 120s  |
             | cycleway | gravel                | 120s  |
-            | cycleway | pebbelstone           | 120s  |
+            | cycleway | pebblestone           | 120s  |
             | cycleway | dirt                  | 120s  |
             | cycleway | earth                 | 120s  |
             | cycleway | grass                 | 120s  |
diff --git a/features/car/maxspeed.feature b/features/car/maxspeed.feature
index 781f4c6..84cfa4f 100644
--- a/features/car/maxspeed.feature
+++ b/features/car/maxspeed.feature
@@ -93,3 +93,22 @@ OSRM will use 4/5 of the projected free-flow speed.
             | primary | 15       |       | 30               | 60                | 34 km/h | 59 km/h |
             | primary | 15       |   3   | 30               | 60                | 15 km/h | 30 km/h |
 
+    Scenario: Car - Single lane streets be ignored or incur a penalty
+        Then routability should be
+
+            | highway | maxspeed | lanes | maxspeed:forward | maxspeed:backward | forw    | backw   |
+            | primary |          |       |                  |                   | 63 km/h | 63 km/h |
+            | primary |          |   1   |                  |                   | 32 km/h | 32 km/h |
+            | primary | 60       |       |                  |                   | 59 km/h | 59 km/h |
+            | primary | 60       |   1   |                  |                   | 30 km/h | 30 km/h |
+            | primary |          |       | 60               |                   | 59 km/h | 63 km/h |
+            | primary |          |   1   | 60               |                   | 30 km/h | 32 km/h |
+            | primary |          |       |                  | 60                | 63 km/h | 59 km/h |
+            | primary |          |   1   |                  | 60                | 32 km/h | 30 km/h |
+            | primary | 15       |       | 60               |                   | 59 km/h | 23 km/h |
+            | primary | 15       |   1   | 60               |                   | 30 km/h |  7 km/h |
+            | primary | 15       |       |                  | 60                | 23 km/h | 59 km/h |
+            | primary | 15       |   1   |                  | 60                |  7 km/h | 30 km/h |
+            | primary | 15       |       | 30               | 60                | 34 km/h | 59 km/h |
+            | primary | 15       |   1   | 30               | 60                | 15 km/h | 30 km/h |
+
diff --git a/features/car/names.feature b/features/car/names.feature
index ac4bfc8..b6a95ae 100644
--- a/features/car/names.feature
+++ b/features/car/names.feature
@@ -10,13 +10,13 @@ Feature: Car - Street names in instructions
             |   | c |
 
         And the ways
-            | nodes | name     |
-            | ab    | My Way   |
-            | bc    | Your Way |
+            | nodes | name     | ref |
+            | ab    | My Way   |     |
+            | bc    | Your Way | A1  |
 
         When I route I should get
-            | from | to | route           |
-            | a    | c  | My Way,Your Way |
+            | from | to | route                |
+            | a    | c  | My Way,Your Way (A1) |
 
     @todo
     Scenario: Car - Use way type to describe unnamed ways
diff --git a/features/foot/access.feature b/features/foot/access.feature
index 4d81d0e..353076c 100644
--- a/features/foot/access.feature
+++ b/features/foot/access.feature
@@ -51,7 +51,7 @@ Feature: Foot - Access tags on ways
             | no           |              |       |
             | private      |              |       |
             | agricultural |              |       |
-            | forestery    |              |       |
+            | forestry     |              |       |
             |              | yes          | x     |
             |              | permissive   | x     |
             |              | designated   | x     |
@@ -59,7 +59,7 @@ Feature: Foot - Access tags on ways
             |              | no           |       |
             |              | private      |       |
             |              | agricultural |       |
-            |              | forestery    |       |
+            |              | forestry     |       |
 
     Scenario: Foot - Access tags on both node and way
         Then routability should be
diff --git a/features/foot/access_node.feature b/features/foot/access_node.feature
index 5a4a131..8519d05 100644
--- a/features/foot/access_node.feature
+++ b/features/foot/access_node.feature
@@ -39,7 +39,7 @@ Feature: Foot - Access tags on nodes
             | no           |              |       |
             | private      |              |       |
             | agricultural |              |       |
-            | forestery    |              |       |
+            | forestry     |              |       |
             | no           | yes          | x     |
             | no           | permissive   | x     |
             | no           | designated   | x     |
@@ -47,4 +47,4 @@ Feature: Foot - Access tags on nodes
             | yes          | no           |       |
             | yes          | private      |       |
             | yes          | agricultural |       |
-            | yes          | forestery    |       |
+            | yes          | forestry     |       |
diff --git a/features/foot/surface.feature b/features/foot/surface.feature
index 556c3d8..9bcd80c 100644
--- a/features/foot/surface.feature
+++ b/features/foot/surface.feature
@@ -10,6 +10,6 @@ Feature: Foot - Surfaces
             | footway |             | 145s ~10% |
             | footway | fine_gravel | 193s ~10% |
             | footway | gravel      | 193s ~10% |
-            | footway | pebbelstone | 193s ~10% |
+            | footway | pebblestone | 193s ~10% |
             | footway | mud         | 289s ~10% |
             | footway | sand        | 289s ~10% |
diff --git a/features/foot/way.feature b/features/foot/way.feature
index 653c773..ff3314f 100644
--- a/features/foot/way.feature
+++ b/features/foot/way.feature
@@ -30,3 +30,9 @@ Feature: Foot - Accessability of different way types
             | pier           | x    |
             | cycleway       |      |
             | bridleway      |      |
+
+    Scenario: Foot - Basic access
+        Then routability should be
+            | highway | leisure  | forw |
+            | (nil)   | track    |   x  |
+
diff --git a/features/nearest/pick.feature b/features/nearest/pick.feature
index 08e6652..75dbc6e 100644
--- a/features/nearest/pick.feature
+++ b/features/nearest/pick.feature
@@ -57,14 +57,13 @@ Feature: Locating Nearest node on a Way - pick closest way
 
     Scenario: Nearest - High lat/lon
         Given the node locations
-            | node | lat | lon  |
-            | a    | -85 | -180 |
-            | b    | -85 | -160 |
-            | c    | -85 | -140 |
-            | x    |  75 | -180 |
-            | y    |  75 | -180 |
-            | v    |   1 |    1 |
-            | w    |  -1 |   -1 |
+            | 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 |
@@ -73,6 +72,5 @@ Feature: Locating Nearest node on a Way - pick closest way
         When I request nearest I should get
             | in | out |
             | x  | a   |
-            | y  | a   |
-            | v  | c   |
-            | w  | c   |
+            | y  | b   |
+            | z  | c   |
diff --git a/features/options/prepare/help.feature b/features/options/prepare/help.feature
index 49497ae..dae522d 100644
--- a/features/options/prepare/help.feature
+++ b/features/options/prepare/help.feature
@@ -17,7 +17,7 @@ Feature: osrm-prepare command line options: help
         And stdout should contain "--profile"
         And stdout should contain "--threads"
         And stdout should contain 15 lines
-        And it should exit with code 0
+        And it should exit with code 1
 
     Scenario: osrm-prepare - Help, short
         When I run "osrm-prepare -h"
diff --git a/features/step_definitions/data.rb b/features/step_definitions/data.rb
index f1e58ba..524fd32 100644
--- a/features/step_definitions/data.rb
+++ b/features/step_definitions/data.rb
@@ -174,3 +174,7 @@ 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.rb b/features/step_definitions/distance_matrix.rb
index f85bdcc..8c4e927 100644
--- a/features/step_definitions/distance_matrix.rb
+++ b/features/step_definitions/distance_matrix.rb
@@ -52,5 +52,5 @@ When /^I request a travel time matrix I should get$/ do |table|
       actual << r
     end
   end
-  table.routing_diff! actual
+  table.diff! actual
 end
diff --git a/features/step_definitions/locate.rb b/features/step_definitions/locate.rb
index 3e67be3..2fd8e62 100644
--- a/features/step_definitions/locate.rb
+++ b/features/step_definitions/locate.rb
@@ -9,7 +9,7 @@ When /^I request locate I should get$/ do |table|
       out_node = find_node_by_name row['out']
       raise "*** unknown out-node '#{row['out']}" unless out_node
 
-      response = request_locate("#{in_node.lat},#{in_node.lon}")
+      response = request_locate(in_node)
       if response.code == "200" && response.body.empty? == false
         json = JSON.parse response.body
         if json['status'] == 0
@@ -39,7 +39,7 @@ When /^I request locate I should get$/ do |table|
       actual << got
     end
   end
-  table.routing_diff! actual
+  table.diff! actual
 end
 
 When /^I request locate (\d+) times I should get$/ do |n,table|
diff --git a/features/step_definitions/matching.rb b/features/step_definitions/matching.rb
index 3f3181f..e9b7234 100644
--- a/features/step_definitions/matching.rb
+++ b/features/step_definitions/matching.rb
@@ -91,6 +91,6 @@ When /^I match I should get$/ do |table|
       actual << got
     end
   end
-  table.routing_diff! actual
+  table.diff! actual
 end
 
diff --git a/features/step_definitions/nearest.rb b/features/step_definitions/nearest.rb
index 532c1f0..481c741 100644
--- a/features/step_definitions/nearest.rb
+++ b/features/step_definitions/nearest.rb
@@ -9,7 +9,7 @@ When /^I request nearest I should get$/ do |table|
       out_node = find_node_by_name row['out']
       raise "*** unknown out-node '#{row['out']}" unless out_node
 
-      response = request_nearest("#{in_node.lat},#{in_node.lon}")
+      response = request_nearest(in_node)
       if response.code == "200" && response.body.empty? == false
         json = JSON.parse response.body
         if json['status'] == 0
@@ -39,7 +39,7 @@ When /^I request nearest I should get$/ do |table|
       actual << got
     end
   end
-  table.routing_diff! actual
+  table.diff! actual
 end
 
 When /^I request nearest (\d+) times I should get$/ do |n,table|
diff --git a/features/step_definitions/routability.rb b/features/step_definitions/routability.rb
index dcbde5a..a9241be 100644
--- a/features/step_definitions/routability.rb
+++ b/features/step_definitions/routability.rb
@@ -74,5 +74,5 @@ Then /^routability should be$/ do |table|
       actual << output_row
     end
   end
-  table.routing_diff! actual
+  table.diff! actual
 end
diff --git a/features/step_definitions/routing.rb b/features/step_definitions/routing.rb
index c25f5b7..597ea65 100644
--- a/features/step_definitions/routing.rb
+++ b/features/step_definitions/routing.rb
@@ -140,7 +140,7 @@ When /^I route I should get$/ do |table|
       actual << got
     end
   end
-  table.routing_diff! actual
+  table.diff! actual
 end
 
 When /^I route (\d+) times I should get$/ do |n,table|
diff --git a/features/support/cucumber.rb b/features/support/cucumber.rb
deleted file mode 100644
index a43082a..0000000
--- a/features/support/cucumber.rb
+++ /dev/null
@@ -1,76 +0,0 @@
-#monkey patch cucumber table class to reorder output.
-#we always want failed rows to be shown right below the expected row.
-
-class Cucumber::Ast::Table
-  def routing_diff!(other_table, options={})
-    options = {:missing_row => true, :surplus_row => true, :missing_col => true, :surplus_col => false}.merge(options)
-
-    other_table = ensure_table(other_table)
-    other_table.convert_headers!
-    other_table.convert_columns!
-    ensure_green!
-
-    convert_headers!
-    convert_columns!
-
-    original_width = cell_matrix[0].length
-    other_table_cell_matrix = pad!(other_table.cell_matrix)
-    padded_width = cell_matrix[0].length
-
-    missing_col = cell_matrix[0].detect{|cell| cell.status == :undefined}
-    surplus_col = padded_width > original_width
-
-    require_diff_lcs
-    cell_matrix.extend(Diff::LCS)
-    changes = cell_matrix.diff(other_table_cell_matrix).flatten
-
-    inserted = 0
-    missing  = 0
-
-    row_indices = Array.new(other_table_cell_matrix.length) {|n| n}
-
-    last_change = nil
-    missing_row_pos = nil
-    insert_row_pos  = nil
-
-    changes.each do |change|
-      if(change.action == '-')
-        missing_row_pos = change.position + inserted
-        cell_matrix[missing_row_pos].each{|cell| cell.status = :undefined}
-        row_indices.insert(missing_row_pos, nil)
-        missing += 1
-      else # '+'
-        #change index so we interleave instead
-        insert_row_pos = change.position + inserted + 1
-        #insert_row_pos = change.position + missing     #original
-
-        inserted_row = change.element
-        inserted_row.each{|cell| cell.status = :comment}
-        cell_matrix.insert(insert_row_pos, inserted_row)
-        row_indices[insert_row_pos] = nil
-        inspect_rows(cell_matrix[missing_row_pos], inserted_row) if last_change && last_change.action == '-'
-        inserted += 1
-      end
-      last_change = change
-    end
-
-    other_table_cell_matrix.each_with_index do |other_row, i|
-      row_index = row_indices.index(i)
-      row = cell_matrix[row_index] if row_index
-      if row
-        (original_width..padded_width).each do |col_index|
-          surplus_cell = other_row[col_index]
-          row[col_index].value = surplus_cell.value if row[col_index]
-        end
-      end
-    end
-
-    clear_cache!
-    should_raise =
-    missing_row_pos && options[:missing_row] ||
-    insert_row_pos  && options[:surplus_row] ||
-    missing_col     && options[:missing_col] ||
-    surplus_col     && options[:surplus_col]
-    raise Different.new(self) if should_raise
-  end
-end
\ No newline at end of file
diff --git a/features/support/env.rb b/features/support/env.rb
index f9a4fe4..ea74959 100644
--- a/features/support/env.rb
+++ b/features/support/env.rb
@@ -22,10 +22,10 @@ SHUTDOWN_TIMEOUT = 10
 DEFAULT_LOAD_METHOD = 'datastore'
 OSRM_ROUTED_LOG_FILE = 'osrm-routed.log'
 
-if ENV['OS']==/Windows.*/ then
-  TERMSIGNAL='TERM'
-else
+if ENV['OS']=~/Windows.*/ then
   TERMSIGNAL=9
+else
+  TERMSIGNAL='TERM'
 end
 
 
@@ -72,8 +72,8 @@ end
 
 def verify_existance_of_binaries
   ["osrm-extract", "osrm-prepare", "osrm-routed"].each do |bin|  
-    unless File.exists? "#{BIN_PATH}/#{bin}"
-      raise "*** #{BIN_PATH}/#{bin} is missing. Build failed?"
+    unless File.exists? "#{BIN_PATH}/#{bin}#{EXE}"
+      raise "*** #{BIN_PATH}/#{bin}#{EXE} is missing. Build failed?"
     end
   end
 end
diff --git a/features/support/hooks.rb b/features/support/hooks.rb
index 3370142..2ad49dc 100644
--- a/features/support/hooks.rb
+++ b/features/support/hooks.rb
@@ -4,22 +4,16 @@ STRESS_TIMEOUT = 300
 
 Before do |scenario|
 
-  # feature name
+  # fetch scenario and feature name, so we can use it in log files if needed
   case scenario
-    when Cucumber::Ast::Scenario
+    when Cucumber::RunningTestCase::Scenario
       @feature_name = scenario.feature.name
-    when Cucumber::Ast::OutlineTable::ExampleRow
-      @feature_name = scenario.scenario_outline.feature.name
-  end
-
-  # scenario name
-  case scenario
-    when Cucumber::Ast::Scenario
       @scenario_title = scenario.name
-    when Cucumber::Ast::OutlineTable::ExampleRow
+    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")
diff --git a/features/support/http.rb b/features/support/http.rb
new file mode 100644
index 0000000..80dad8a
--- /dev/null
+++ b/features/support/http.rb
@@ -0,0 +1,34 @@
+require 'net/http'
+
+def generate_request_url path
+  if @http_method.eql? "POST"
+    pos = path.index('?') - 1
+    service = path[0..pos]
+    uri = URI.parse "#{HOST}/#{service}"
+  else
+    uri = URI.parse "#{HOST}/#{path}"
+  end
+end
+
+def send_request uri, waypoints=[], options={}, timestamps=[]
+  @query = uri.to_s
+  Timeout.timeout(OSRM_TIMEOUT) do
+    if @http_method.eql? "POST"
+      datas = {}
+      if waypoints.length > 0
+        datas[:loc] = waypoints.compact.map { |w| "#{w.lat},#{w.lon}" }
+      end
+      if timestamps.length > 0
+        datas[:t] = timestamps.compact.map { |t| "#{t}" }
+      end
+      datas.merge! options
+      response = Net::HTTP.post_form uri, datas
+    else
+      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/locate.rb b/features/support/locate.rb
index 9007247..a62e53a 100644
--- a/features/support/locate.rb
+++ b/features/support/locate.rb
@@ -1,17 +1,12 @@
 require 'net/http'
 
-def request_locate_url path
+def request_locate_url path, node
   @query = path
-  uri = URI.parse "#{HOST}/#{path}"
-  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."
+
+  uri = generate_request_url path
+  response = send_request uri, [node]
 end
 
-def request_locate a
-  request_locate_url "locate?loc=#{a}"
+def request_locate node
+  request_locate_url "locate?loc=#{node.lat},#{node.lon}", node
 end
diff --git a/features/support/match.rb b/features/support/match.rb
index bf51189..8bcf7a2 100644
--- a/features/support/match.rb
+++ b/features/support/match.rb
@@ -13,14 +13,8 @@ def request_matching trace=[], timestamps=[], options={}
   end
   params = (trace_params + defaults.merge(options).to_param).join('&')
   params = nil if params==""
-  uri = URI.parse ["#{HOST}/match", params].compact.join('?')
-  @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."
+  
+  uri = generate_request_url ("match" + '?' + params)
+  response = send_request uri, trace, options, timestamps
 end
 
diff --git a/features/support/nearest.rb b/features/support/nearest.rb
index 77fc351..af52b49 100644
--- a/features/support/nearest.rb
+++ b/features/support/nearest.rb
@@ -1,17 +1,12 @@
 require 'net/http'
 
-def request_nearest_url path
+def request_nearest_url path, node
   @query = path
-  uri = URI.parse "#{HOST}/#{path}"
-  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."
+  
+  uri = generate_request_url path
+  response = send_request uri, [node]
 end
 
-def request_nearest a
-  request_nearest_url "nearest?loc=#{a}"
+def request_nearest node
+  request_nearest_url "nearest?loc=#{node.lat},#{node.lon}", node
 end
diff --git a/features/support/route.rb b/features/support/route.rb
index a8c7822..ca353d6 100644
--- a/features/support/route.rb
+++ b/features/support/route.rb
@@ -15,15 +15,13 @@ def request_path path, waypoints=[], options={}
   locs = waypoints.compact.map { |w| "loc=#{w.lat},#{w.lon}" }
   params = (locs + options.to_param).join('&')
   params = nil if params==""
-  uri = URI.parse ["#{HOST}/#{path}", params].compact.join('?')
-  @query = uri.to_s
-  Timeout.timeout(OSRM_TIMEOUT) do
-    Net::HTTP.get_response uri
+  
+  if params == nil
+    uri = generate_request_url (path)
+  else
+    uri = generate_request_url (path + '?' + params)
   end
-rescue Errno::ECONNREFUSED => e
-  raise "*** osrm-routed is not running."
-rescue Timeout::Error
-  raise "*** osrm-routed did not respond."
+  response = send_request uri, waypoints, options
 end
 
 def request_url path
diff --git a/features/testbot/ferry.feature b/features/testbot/ferry.feature
index 5516061..21cefcb 100644
--- a/features/testbot/ferry.feature
+++ b/features/testbot/ferry.feature
@@ -173,3 +173,33 @@ Feature: Testbot - Handle ferry routes
             | from | to | route   | time       |
             | a    | g  | abcdefg | 23400s +-2 |
             | g    | a  | abcdefg | 23400s +-2 |
+
+    @todo
+    Scenario: Testbot - Ferry duration formats
+        Given the node map
+            | a | c | e | g | i | k | m | o | q | s |
+            | b | d | f | h | j | l | n | p | r | t |
+
+        And the ways
+            | nodes | route | duration |
+            | ab    | ferry | 0:01     |
+            | cd    | ferry | 00:01    |
+            | ef    | ferry | 1:00     |
+            | gh    | ferry | 01:00    |
+            | ij    | ferry | 02:20    |
+            | kl    | ferry | 10:00    |
+            | mn    | ferry | 100:00   |
+            | op    | ferry | 1000:00  |
+            | qr    | ferry | 10000:00 |
+
+        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 |
diff --git a/features/testbot/loop.feature b/features/testbot/loop.feature
index 72cad33..c69e7a2 100644
--- a/features/testbot/loop.feature
+++ b/features/testbot/loop.feature
@@ -4,6 +4,25 @@ Feature: Avoid weird loops caused by rounding errors
     Background:
         Given the profile "testbot"
 
+    Scenario: Weired sidestreet loops
+        Given the node map
+            | a | 1 | b | 2 | c | 3 | d |
+            |   |   |   |   |   |   |   |
+            | e |   | f |   | g |   | h |
+
+       And the ways
+            | nodes  |
+            | aefghd |
+            | abcd   |
+            | bf     |
+            | 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 |
+
     Scenario: Avoid weird loops 1
         Given the node locations
             | node | lat        | lon        |
diff --git a/features/testbot/post.feature b/features/testbot/post.feature
new file mode 100644
index 0000000..ff22824
--- /dev/null
+++ b/features/testbot/post.feature
@@ -0,0 +1,100 @@
+ 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 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 - locate POST request
+        Given the node locations
+            | node | lat | lon  |
+            | a    | -85 | -180 |
+            | b    | 0   | 0    |
+            | c    | 85  | 180  |
+            | x    | -84 | -180 |
+            | y    | 84  | 180  |
+
+        And the ways
+            | nodes |
+            | abc   |
+
+        When I request locate I should get
+            | in | out |
+            | x  | a   |
+            | y  | c   |
+            
+    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/snap.feature b/features/testbot/snap.feature
index bee75bc..01c590b 100644
--- a/features/testbot/snap.feature
+++ b/features/testbot/snap.feature
@@ -98,30 +98,26 @@ Feature: Snap start/end point to the nearest way
             | b    | x  | xb    |
             | c    | x  | xc    |
 
-    Scenario: Find edges within 1km, and the same from 10km
-        Given a grid size of 1000 meters
+    Scenario: Find edges within 100m, and the same from 1km
+        Given a grid size of 100 meters
         Given the node map
-            | p |  |  |  |  |  |  |  |  |   |   | i |   |   |  |  |  |  |  |  |  |  | j |
-            |   |  |  |  |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |  |  |  |   |
-            |   |  |  |  |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |  |  |  |   |
-            |   |  |  |  |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |  |  |  |   |
-            |   |  |  |  |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |  |  |  |   |
-            |   |  |  |  |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |  |  |  |   |
-            |   |  |  |  |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |  |  |  |   |
-            |   |  |  |  |  |  |  |  |  | 8 |   | 1 |   | 2 |  |  |  |  |  |  |  |  |   |
-            |   |  |  |  |  |  |  |  |  |   | h | a | b |   |  |  |  |  |  |  |  |  |   |
-            | o |  |  |  |  |  |  |  |  | 7 | g | x | c | 3 |  |  |  |  |  |  |  |  | k |
-            |   |  |  |  |  |  |  |  |  |   | f | e | d |   |  |  |  |  |  |  |  |  |   |
-            |   |  |  |  |  |  |  |  |  | 6 |   | 5 |   | 4 |  |  |  |  |  |  |  |  |   |
-            |   |  |  |  |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |  |  |  |   |
-            |   |  |  |  |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |  |  |  |   |
-            |   |  |  |  |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |  |  |  |   |
-            |   |  |  |  |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |  |  |  |   |
-            |   |  |  |  |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |  |  |  |   |
-            |   |  |  |  |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |  |  |  |   |
-            |   |  |  |  |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |  |  |  |   |
-            |   |  |  |  |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |  |  |  |   |
-            | n |  |  |  |  |  |  |  |  |   |   | m |   |   |  |  |  |  |  |  |  |  | l |
+            | p |  |  |  |  |  |   |   | i |   |   |  |  |  |  |  | j |
+            |   |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |   |
+            |   |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |   |
+            |   |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |   |
+            |   |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |   |
+            |   |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |   |
+            |   |  |  |  |  |  | 8 |   | 1 |   | 2 |  |  |  |  |  |   |
+            |   |  |  |  |  |  |   | h | a | b |   |  |  |  |  |  |   |
+            | o |  |  |  |  |  | 7 | g | x | c | 3 |  |  |  |  |  | k |
+            |   |  |  |  |  |  |   | f | e | d |   |  |  |  |  |  |   |
+            |   |  |  |  |  |  | 6 |   | 5 |   | 4 |  |  |  |  |  |   |
+            |   |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |   |
+            |   |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |   |
+            |   |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |   |
+            |   |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |   |
+            |   |  |  |  |  |  |   |   |   |   |   |  |  |  |  |  |   |
+            | n |  |  |  |  |  |   |   | m |   |   |  |  |  |  |  | l |
 
         Given the ways
             | nodes |
diff --git a/features/testbot/via.feature b/features/testbot/via.feature
index 9eb8f55..a70ee9f 100644
--- a/features/testbot/via.feature
+++ b/features/testbot/via.feature
@@ -52,6 +52,21 @@ Feature: Via points
             | a,c,f     | ab,bcd,bcd,de,efg        |
             | a,c,f,h   | ab,bcd,bcd,de,efg,efg,gh |
 
+    Scenario: Duplicate via point
+        Given the node map
+            | x |   |   |   |   |   |
+            | a | 1 | 2 | 3 | 4 | b |
+            |   |   |   |   |   |   |
+
+        And the ways
+            | nodes |
+            | xa    |
+            | ab    |
+
+        When I route I should get
+            | waypoints | route | turns                |
+            | 1,1,4     | ab,ab | head,via,destination |
+
     Scenario: Via points on ring of oneways
     # xa it to avoid only having a single ring, which cna trigger edge cases
         Given the node map
@@ -77,7 +92,6 @@ Feature: Via points
             | 1,3,2     | ab,bc,cd,cd,de,ef,fa,ab,bc | 1600m +-1 | head,straight,straight,via,right,right,right,right,straight,destination |
             | 3,2,1     | cd,de,ef,fa,ab,bc,bc,cd,de,ef,fa,ab | 2400m +-1 | head,right,right,right,right,straight,via,straight,right,right,right,right,destination |
 
-    @bug
     Scenario: Via points on ring on the same oneway
     # xa it to avoid only having a single ring, which cna trigger edge cases
         Given the node map
@@ -97,6 +111,6 @@ Feature: Via points
             | 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                         | 200m +-1  | head,destination                                                 |
-            | 1,3,2     | ab,bc,cd,da,ab             | 1100m +-1 | head,right,right,right,right,destination                         |
-            | 3,2,1     | ab,bc,cd,da,ab,bc,cd,da,ab | 1600m +-1 | head,right,right,right,right,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 |
diff --git a/include/osrm/route_parameters.hpp b/include/osrm/route_parameters.hpp
index 9babbd7..bc413d7 100644
--- a/include/osrm/route_parameters.hpp
+++ b/include/osrm/route_parameters.hpp
@@ -78,6 +78,8 @@ struct RouteParameters
     void setCompressionFlag(const bool flag);
 
     void addCoordinate(const boost::fusion::vector<double, double> &received_coordinates);
+    
+    void getCoordinatesFromGeometry(const std::string geometry_string);
 
     short zoom_level;
     bool print_instructions;
diff --git a/prepare.cpp b/prepare.cpp
index af10df0..5de3204 100644
--- a/prepare.cpp
+++ b/prepare.cpp
@@ -26,10 +26,13 @@ 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 <exception>
 #include <ostream>
 
@@ -37,21 +40,64 @@ int main(int argc, char *argv[])
 {
     try
     {
-        return Prepare().Process(argc, argv);
-    }
-    catch (boost::program_options::too_many_positional_options_error &)
-    {
-        SimpleLogger().Write(logWARNING) << "Only one file can be specified";
-        return 1;
-    }
-    catch (boost::program_options::error &e)
-    {
-        SimpleLogger().Write(logWARNING) << e.what();
-        return 1;
+        LogPolicy::GetInstance().Unmute();
+        ContractorConfig contractor_config;
+
+        const return_code result = ContractorOptions::ParseArguments(argc, argv, contractor_config);
+
+        if (return_code::fail == result)
+        {
+            return 1;
+        }
+
+        if (return_code::exit == result)
+        {
+            return 0;
+        }
+
+        ContractorOptions::GenerateOutputFilesNames(contractor_config);
+
+        if (1 > contractor_config.requested_num_threads)
+        {
+            SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
+            return 1;
+        }
+
+        const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
+
+        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 1;
+        }
+
+        if (!boost::filesystem::is_regular_file(contractor_config.profile_path))
+        {
+            SimpleLogger().Write(logWARNING) << "Profile " << contractor_config.profile_path.string()
+                                             << " not found!";
+            return 1;
+        }
+
+        SimpleLogger().Write() << "Input file: " << contractor_config.osrm_input_path.filename().string();
+        SimpleLogger().Write() << "Restrictions file: " << contractor_config.restrictions_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::exception &e)
     {
-        SimpleLogger().Write(logWARNING) << "Exception occured: " << e.what() << std::endl;
+        SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
         return 1;
     }
 }
diff --git a/profiles/bicycle.lua b/profiles/bicycle.lua
index 497321c..f236063 100644
--- a/profiles/bicycle.lua
+++ b/profiles/bicycle.lua
@@ -1,19 +1,21 @@
-require("lib/access")
-require("lib/maxspeed")
+-- Bicycle profile
+
+local find_access_tag = require("lib/access").find_access_tag
+local limit = require("lib/maxspeed").limit
 
 -- Begin of globals
 barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true }
 access_tag_whitelist = { ["yes"] = true, ["permissive"] = true, ["designated"] = true }
-access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestery"] = true }
+access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true }
 access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
 access_tags_hierachy = { "bicycle", "vehicle", "access" }
 cycleway_tags = {["track"]=true,["lane"]=true,["opposite"]=true,["opposite_lane"]=true,["opposite_track"]=true,["share_busway"]=true,["sharrow"]=true,["shared"]=true }
 service_tag_restricted = { ["parking_aisle"] = true }
 restriction_exception_tags = { "bicycle", "vehicle", "access" }
+unsafe_highway_list = { ["primary"] = true, ["secondary"] = true, ["tertiary"] = true, ["primary_link"] = true, ["secondary_link"] = true, ["tertiary_link"] = true}
 
-default_speed = 15
-
-walking_speed = 6
+local default_speed = 15
+local walking_speed = 6
 
 bicycle_speeds = {
   ["cycleway"] = default_speed,
@@ -79,8 +81,7 @@ surface_speeds = {
   ["unpaved"] = 6,
   ["fine_gravel"] = 6,
   ["gravel"] = 6,
-  ["fine_gravel"] = 6,
-  ["pebbelstone"] = 6,
+  ["pebblestone"] = 6,
   ["ground"] = 6,
   ["dirt"] = 6,
   ["earth"] = 6,
@@ -89,24 +90,27 @@ surface_speeds = {
   ["sand"] = 3
 }
 
-take_minimum_of_speeds  = true
-obey_oneway       = true
-obey_bollards       = false
-use_restrictions    = true
-ignore_areas      = true    -- future feature
-traffic_signal_penalty  = 5
-u_turn_penalty      = 20
-use_turn_restrictions   = false
-turn_penalty      = 60
-turn_bias         = 1.4
-
+traffic_signal_penalty          = 2
+use_turn_restrictions           = false
+
+local obey_oneway               = true
+local obey_bollards             = false
+local ignore_areas              = true
+local u_turn_penalty            = 20
+local turn_penalty              = 60
+local turn_bias                 = 1.4
+-- reduce the driving speed by 30% for unsafe roads
+-- local safety_penalty            = 0.7
+local safety_penalty            = 1.0
+local use_public_transport      = true
+local fallback_names            = true
 
 --modes
-mode_normal = 1
-mode_pushing = 2
-mode_ferry = 3
-mode_train = 4
-mode_movable_bridge = 5
+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
@@ -122,7 +126,6 @@ local function parse_maxspeed(source)
     return n
 end
 
-
 function get_exceptions(vector)
   for i,v in ipairs(restriction_exception_tags) do
     vector:Add(v)
@@ -130,29 +133,31 @@ function get_exceptions(vector)
 end
 
 function node_function (node, result)
-  local barrier = node:get_value_by_key("barrier")
-  local access = Access.find_access_tag(node, access_tags_hierachy)
-  local traffic_signal = node:get_value_by_key("highway")
-
-	-- flag node if it carries a traffic light
-	if traffic_signal and traffic_signal == "traffic_signals" then
-		result.traffic_lights = true
-	end
-
-	-- parse access and barrier tags
-	if access and access ~= "" then
-		if access_tag_blacklist[access] then
-			result.barrier = true
-		else
-			result.barrier = false
-		end
-	elseif barrier and barrier ~= "" then
-		if barrier_whitelist[barrier] then
-			result.barrier = false
-		else
-			result.barrier = true
-		end
-	end
+  -- parse access and barrier tags
+  local highway = node:get_value_by_key("highway")
+  local is_crossing = highway and highway == "crossing"
+
+  local access = find_access_tag(node, access_tags_hierachy)
+  if access and access ~= "" then
+    -- access restrictions on crossing nodes are not relevant for
+    -- the traffic on the road
+    if access_tag_blacklist[access] and not is_crossing then
+      result.barrier = true
+    end
+  else
+    local barrier = node:get_value_by_key("barrier")
+    if barrier and "" ~= barrier then
+      if not barrier_whitelist[barrier] then
+        result.barrier = true
+      end
+    end
+  end
+
+  -- check if node is a traffic light
+  local tag = node:get_value_by_key("highway")
+  if tag and "traffic_signals" == tag then
+    result.traffic_lights = true;
+  end
 end
 
 function way_function (way, result)
@@ -165,8 +170,8 @@ function way_function (way, result)
   local public_transport = way:get_value_by_key("public_transport")
   local bridge = way:get_value_by_key("bridge")
   if (not highway or highway == '') and
-  (not route or route == '') and
-  (not railway or railway=='') and
+  (not use_public_transport or not route or route == '') and
+  (not use_public_transport or not railway or railway=='') and
   (not amenity or amenity=='') and
   (not man_made or man_made=='') and
   (not public_transport or public_transport=='') and
@@ -181,7 +186,7 @@ function way_function (way, result)
   end
 
   -- access
-  local access = Access.find_access_tag(way, access_tags_hierachy)
+  local access = find_access_tag(way, access_tags_hierachy)
   if access and access_tag_blacklist[access] then
     return
   end
@@ -213,7 +218,8 @@ function way_function (way, result)
     result.name = ref
   elseif name and "" ~= name then
     result.name = name
-  elseif highway then
+  -- TODO find a better solution for encoding way type
+  elseif fallback_names and highway then
     -- if no name exists, use way type
     -- this encoding scheme is excepted to be a temporary solution
     result.name = "{highway:"..highway.."}"
@@ -246,15 +252,16 @@ function way_function (way, result)
        result.forward_speed = route_speeds[route]
        result.backward_speed = route_speeds[route]
     end
-  elseif railway and platform_speeds[railway] then
+  -- public transport
+  elseif use_public_transport and railway and platform_speeds[railway] then
     -- railway platforms (old tagging scheme)
     result.forward_speed = platform_speeds[railway]
     result.backward_speed = platform_speeds[railway]
-  elseif platform_speeds[public_transport] then
+  elseif use_public_transport and platform_speeds[public_transport] then
     -- public_transport platforms (new tagging platform)
     result.forward_speed = platform_speeds[public_transport]
     result.backward_speed = platform_speeds[public_transport]
-    elseif railway and railway_speeds[railway] then
+  elseif use_public_transport and railway and railway_speeds[railway] then
       result.forward_mode = mode_train
       result.backward_mode = mode_train
      -- railways
@@ -270,6 +277,10 @@ function way_function (way, result)
     -- regular ways
     result.forward_speed = bicycle_speeds[highway]
     result.backward_speed = bicycle_speeds[highway]
+    if safety_penalty < 1 and unsafe_highway_list[highway] then
+      result.forward_speed = result.forward_speed * safety_penalty
+      result.backward_speed = result.backward_speed * safety_penalty
+    end
   elseif access and access_tag_whitelist[access] then
     -- unknown way, but valid access tag
     result.forward_speed = default_speed
@@ -391,7 +402,7 @@ function way_function (way, result)
   end
 
   -- maxspeed
-  MaxSpeed.limit( result, maxspeed, maxspeed_forward, maxspeed_backward )
+  limit( result, maxspeed, maxspeed_forward, maxspeed_backward )
 end
 
 function turn_function (angle)
diff --git a/profiles/car.lua b/profiles/car.lua
index 813afd1..8c68bc9 100644
--- a/profiles/car.lua
+++ b/profiles/car.lua
@@ -1,6 +1,8 @@
--- Begin of globals
---require("lib/access") --function temporarily inlined
+-- Car profile
+
+local find_access_tag = require("lib/access").find_access_tag
 
+-- Begin of globals
 barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = true, ["checkpoint"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["lift_gate"] = true, ["no"] = true, ["entrance"] = true }
 access_tag_whitelist = { ["yes"] = true, ["motorcar"] = true, ["motor_vehicle"] = true, ["vehicle"] = true, ["permissive"] = true, ["designated"] = true }
 access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["emergency"] = true, ["psv"] = true }
@@ -130,10 +132,9 @@ maxspeed_table = {
 traffic_signal_penalty          = 2
 use_turn_restrictions           = true
 
-local take_minimum_of_speeds    = false
 local obey_oneway               = true
 local obey_bollards             = true
-local ignore_areas              = true     -- future feature
+local ignore_areas              = true
 local u_turn_penalty            = 20
 
 local abs = math.abs
@@ -147,16 +148,6 @@ local mode_normal = 1
 local mode_ferry = 2
 local mode_movable_bridge = 3
 
-local function find_access_tag(source, access_tags_hierachy)
-  for i,v in ipairs(access_tags_hierachy) do
-    local access_tag = source:get_value_by_key(v)
-    if access_tag and "" ~= access_tag then
-      return access_tag
-    end
-  end
-  return ""
-end
-
 function get_exceptions(vector)
   for i,v in ipairs(restriction_exception_tags) do
     vector:Add(v)
@@ -187,6 +178,7 @@ local function parse_maxspeed(source)
   return n
 end
 
+-- FIXME Why was this commented out?
 -- function turn_function (angle)
 --   -- print ("called at angle " .. angle )
 --   local index = math.abs(math.floor(angle/10+0.5))+1 -- +1 'coz LUA starts as idx 1
@@ -198,7 +190,7 @@ end
 function node_function (node, result)
   -- parse access and barrier tags
   local access = find_access_tag(node, access_tags_hierachy)
-  if access ~= "" then
+  if access and access ~= "" then
     if access_tag_blacklist[access] then
       result.barrier = true
     end
@@ -249,12 +241,6 @@ function way_function (way, result)
     return
   end
 
-  local width = math.huge
-  local width_string = way:get_value_by_key("width")
-  if width_string and tonumber(width_string:match("%d*")) then
-    width = tonumber(width_string:match("%d*"))
-  end
-
   -- Check if we are allowed to access the way
   local access = find_access_tag(way, access_tags_hierachy)
   if access_tag_blacklist[access] then
@@ -353,9 +339,14 @@ function way_function (way, result)
   local service = way:get_value_by_key("service")
 
   -- Set the name that will be used for instructions
-  if ref and "" ~= ref then
+  local has_ref = ref and "" ~= ref
+  local has_name = name and "" ~= name
+
+  if has_name and has_ref then
+    result.name = name .. " (" .. ref .. ")"
+  elseif has_ref then
     result.name = ref
-  elseif name and "" ~= name then
+  elseif has_name then
     result.name = name
 --  else
       --    result.name = highway  -- if no name exists, use way type
@@ -407,12 +398,25 @@ function way_function (way, result)
     result.ignore_in_grid = true
   end
 
+  local width = math.huge
+  local lanes = math.huge
+  if result.forward_speed > 0 or result.backward_speed > 0 then
+    local width_string = way:get_value_by_key("width")
+    if width_string and tonumber(width_string:match("%d*")) then
+      width = tonumber(width_string:match("%d*"))
+    end
+
+    local lanes_string = way:get_value_by_key("lanes")
+    if lanes_string and tonumber(lanes_string:match("%d*")) then
+      lanes = tonumber(lanes_string:match("%d*"))
+    end
+  end
 
   -- scale speeds to get better avg driving times
   if result.forward_speed > 0 then
     local scaled_speed = result.forward_speed*speed_reduction + 11;
     local penalized_speed = math.huge
-    if width <= 3 then
+    if width <= 3 or lanes <= 1 then
       penalized_speed = result.forward_speed / 2;
     end
     result.forward_speed = math.min(penalized_speed, scaled_speed)
@@ -421,16 +425,10 @@ function way_function (way, result)
   if result.backward_speed > 0 then
     local scaled_speed = result.backward_speed*speed_reduction + 11;
     local penalized_speed = math.huge
-    if width <= 3 then
+    if width <= 3 or lanes <= 1 then
       penalized_speed = result.backward_speed / 2;
     end
     result.backward_speed = math.min(penalized_speed, scaled_speed)
   end
 end
 
--- These are wrappers to parse vectors of nodes and ways and thus to speed up any tracing JIT
-function node_vector_function(vector)
-  for v in vector.nodes do
-    node_function(v)
-  end
-end
diff --git a/profiles/foot.lua b/profiles/foot.lua
index 5a37097..4b3bc1c 100644
--- a/profiles/foot.lua
+++ b/profiles/foot.lua
@@ -1,10 +1,11 @@
 -- Foot profile
 
-require("lib/access")
+local find_access_tag = require("lib/access").find_access_tag
 
+-- Begin of globals
 barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true}
 access_tag_whitelist = { ["yes"] = true, ["foot"] = true, ["permissive"] = true, ["designated"] = true  }
-access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestery"] = true }
+access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true }
 access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
 access_tags_hierachy = { "foot", "access" }
 service_tag_restricted = { ["parking_aisle"] = true }
@@ -35,32 +36,36 @@ speeds = {
 }
 
 route_speeds = {
-	["ferry"] = 5
+  ["ferry"] = 5
 }
 
 platform_speeds = {
-	["platform"] = walking_speed
+  ["platform"] = walking_speed
 }
 
 amenity_speeds = {
-	["parking"] = walking_speed,
-	["parking_entrance"] = walking_speed
+  ["parking"] = walking_speed,
+  ["parking_entrance"] = walking_speed
 }
 
 man_made_speeds = {
-	["pier"] = walking_speed
+  ["pier"] = walking_speed
 }
 
 surface_speeds = {
-	["fine_gravel"] =   walking_speed*0.75,
-	["gravel"] =        walking_speed*0.75,
-	["pebbelstone"] =   walking_speed*0.75,
-	["mud"] =           walking_speed*0.5,
-	["sand"] =          walking_speed*0.5
+  ["fine_gravel"] =   walking_speed*0.75,
+  ["gravel"] =        walking_speed*0.75,
+  ["pebblestone"] =   walking_speed*0.75,
+  ["mud"] =           walking_speed*0.5,
+  ["sand"] =          walking_speed*0.5
 }
 
-traffic_signal_penalty 	= 2
-u_turn_penalty 			= 2
+leisure_speeds = {
+  ["track"] = walking_speed
+}
+
+traffic_signal_penalty   = 2
+u_turn_penalty       = 2
 use_turn_restrictions   = false
 
 --modes
@@ -68,144 +73,150 @@ local mode_normal = 1
 local mode_ferry = 2
 
 function get_exceptions(vector)
-	for i,v in ipairs(restriction_exception_tags) do
-		vector:Add(v)
-	end
+  for i,v in ipairs(restriction_exception_tags) do
+    vector:Add(v)
+  end
 end
 
 function node_function (node, result)
-	local barrier = node:get_value_by_key("barrier")
-	local access = Access.find_access_tag(node, access_tags_hierachy)
-	local traffic_signal = node:get_value_by_key("highway")
-
-	-- flag node if it carries a traffic light
-	if traffic_signal and traffic_signal == "traffic_signals" then
-		result.traffic_light = true
-	end
-
-	-- parse access and barrier tags
-	if access and access ~= "" then
-		if access_tag_blacklist[access] then
-			result.barrier = true
-		else
-			result.barrier = false
-		end
-	elseif barrier and barrier ~= "" then
-		if barrier_whitelist[barrier] then
-			result.barrier = false
-		else
-			result.barrier = true
-		end
-	end
-
-	return 1
-end
-
-function way_function (way, result)
-	-- initial routability check, filters out buildings, boundaries, etc
-	local highway = way:get_value_by_key("highway")
-	local route = way:get_value_by_key("route")
-	local man_made = way:get_value_by_key("man_made")
-	local railway = way:get_value_by_key("railway")
-	local amenity = way:get_value_by_key("amenity")
-	local public_transport = way:get_value_by_key("public_transport")
-	if (not highway or highway == '') and
-		(not route or route == '') and
-		(not railway or railway=='') and
-		(not amenity or amenity=='') and
-		(not man_made or man_made=='') and
-		(not public_transport or public_transport=='')
-		then
-		return
-    end
+  local barrier = node:get_value_by_key("barrier")
+  local access = find_access_tag(node, access_tags_hierachy)
+  local traffic_signal = node:get_value_by_key("highway")
 
-    -- don't route on ways that are still under construction
-    if highway=='construction' then
-        return
-    end
+  -- flag node if it carries a traffic light
+  if traffic_signal and traffic_signal == "traffic_signals" then
+    result.traffic_light = true
+  end
 
-	-- access
-    local access = Access.find_access_tag(way, access_tags_hierachy)
+  -- parse access and barrier tags
+  if access and access ~= "" then
     if access_tag_blacklist[access] then
-		return
+      result.barrier = true
+    else
+      result.barrier = false
+    end
+  elseif barrier and barrier ~= "" then
+    if barrier_whitelist[barrier] then
+      result.barrier = false
+    else
+      result.barrier = true
     end
+  end
 
-	local name = way:get_value_by_key("name")
-	local ref = way:get_value_by_key("ref")
-	local junction = way:get_value_by_key("junction")
-	local onewayClass = way:get_value_by_key("oneway:foot")
-	local duration	= way:get_value_by_key("duration")
-	local service	= way:get_value_by_key("service")
-	local area = way:get_value_by_key("area")
-	local foot = way:get_value_by_key("foot")
-	local surface = way:get_value_by_key("surface")
-
- 	-- name
-	if ref and "" ~= ref and name and "" ~= name then
-		result.name = name .. ' / ' .. ref
+  return 1
+end
+
+function way_function (way, result)
+  -- initial routability check, filters out buildings, boundaries, etc
+  local highway = way:get_value_by_key("highway")
+  local leisure = way:get_value_by_key("leisure")
+  local route = way:get_value_by_key("route")
+  local man_made = way:get_value_by_key("man_made")
+  local railway = way:get_value_by_key("railway")
+  local amenity = way:get_value_by_key("amenity")
+  local public_transport = way:get_value_by_key("public_transport")
+  if (not highway or highway == '') and
+    (not leisure or leisure == '') and
+    (not route or route == '') and
+    (not railway or railway=='') and
+    (not amenity or amenity=='') and
+    (not man_made or man_made=='') and
+    (not public_transport or public_transport=='')
+    then
+    return
+  end
+
+  -- don't route on ways that are still under construction
+  if highway=='construction' then
+      return
+  end
+
+  -- access
+  local access = find_access_tag(way, access_tags_hierachy)
+  if access_tag_blacklist[access] then
+    return
+  end
+
+  local name = way:get_value_by_key("name")
+  local ref = way:get_value_by_key("ref")
+  local junction = way:get_value_by_key("junction")
+  local onewayClass = way:get_value_by_key("oneway:foot")
+  local duration  = way:get_value_by_key("duration")
+  local service  = way:get_value_by_key("service")
+  local area = way:get_value_by_key("area")
+  local foot = way:get_value_by_key("foot")
+  local surface = way:get_value_by_key("surface")
+
+   -- name
+  if ref and "" ~= ref and name and "" ~= name then
+    result.name = name .. ' / ' .. ref
     elseif ref and "" ~= ref then
-    	result.name = ref
-	elseif name and "" ~= name then
-		result.name = name
-	elseif highway then
-		result.name = "{highway:"..highway.."}"	-- if no name exists, use way type
-		                                        -- this encoding scheme is excepted to be a temporary solution
-	end
+      result.name = ref
+  elseif name and "" ~= name then
+    result.name = name
+  elseif highway then
+    result.name = "{highway:"..highway.."}"  -- if no name exists, use way type
+                                            -- this encoding scheme is excepted to be a temporary solution
+  end
 
     -- roundabouts
-	if "roundabout" == junction then
-	  result.roundabout = true;
-	end
+  if "roundabout" == junction then
+    result.roundabout = true;
+  end
 
     -- speed
-    if route_speeds[route] then
-		-- ferries (doesn't cover routes tagged using relations)
-		result.ignore_in_grid = true
-		if duration and durationIsValid(duration) then
-			result.duration = math.max( 1, parseDuration(duration) )
-		else
-			result.forward_speed = route_speeds[route]
-			result.backward_speed = route_speeds[route]
-		end
-		result.forward_mode = mode_ferry
-		result.backward_mode = mode_ferry
-	elseif railway and platform_speeds[railway] then
-		-- railway platforms (old tagging scheme)
-		result.forward_speed = platform_speeds[railway]
-		result.backward_speed = platform_speeds[railway]
-	elseif platform_speeds[public_transport] then
-		-- public_transport platforms (new tagging platform)
-		result.forward_speed = platform_speeds[public_transport]
-		result.backward_speed = platform_speeds[public_transport]
-	elseif amenity and amenity_speeds[amenity] then
-		-- parking areas
-		result.forward_speed = amenity_speeds[amenity]
-		result.backward_speed = amenity_speeds[amenity]
-	elseif speeds[highway] then
-		-- regular ways
-		result.forward_speed = speeds[highway]
-		result.backward_speed = speeds[highway]
-	elseif access and access_tag_whitelist[access] then
-	    -- unknown way, but valid access tag
-		result.forward_speed = walking_speed
-		result.backward_speed = walking_speed
-    end
-
-	-- oneway
-	if onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then
-		result.backward_mode = 0
-	elseif onewayClass == "no" or onewayClass == "0" or onewayClass == "false" then
-		-- nothing to do
-	elseif onewayClass == "-1" then
-		result.forward_mode = 0
-    end
-
-    -- surfaces
-    if surface then
-        surface_speed = surface_speeds[surface]
-        if surface_speed then
-            result.forward_speed = math.min(result.forward_speed, surface_speed)
-            result.backward_speed  = math.min(result.backward_speed, surface_speed)
-        end
+  if route_speeds[route] then
+    -- ferries (doesn't cover routes tagged using relations)
+    result.ignore_in_grid = true
+  if duration and durationIsValid(duration) then
+    result.duration = math.max( 1, parseDuration(duration) )
+  else
+    result.forward_speed = route_speeds[route]
+    result.backward_speed = route_speeds[route]
+  end
+    result.forward_mode = mode_ferry
+    result.backward_mode = mode_ferry
+  elseif railway and platform_speeds[railway] then
+    -- railway platforms (old tagging scheme)
+    result.forward_speed = platform_speeds[railway]
+    result.backward_speed = platform_speeds[railway]
+  elseif platform_speeds[public_transport] then
+    -- public_transport platforms (new tagging platform)
+    result.forward_speed = platform_speeds[public_transport]
+    result.backward_speed = platform_speeds[public_transport]
+  elseif amenity and amenity_speeds[amenity] then
+    -- parking areas
+    result.forward_speed = amenity_speeds[amenity]
+    result.backward_speed = amenity_speeds[amenity]
+  elseif leisure and leisure_speeds[leisure] then
+    -- running tracks
+    result.forward_speed = leisure_speeds[leisure]
+    result.backward_speed = leisure_speeds[leisure]
+  elseif speeds[highway] then
+    -- regular ways
+    result.forward_speed = speeds[highway]
+    result.backward_speed = speeds[highway]
+  elseif access and access_tag_whitelist[access] then
+      -- unknown way, but valid access tag
+    result.forward_speed = walking_speed
+    result.backward_speed = walking_speed
+  end
+
+  -- oneway
+  if onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then
+    result.backward_mode = 0
+  elseif onewayClass == "no" or onewayClass == "0" or onewayClass == "false" then
+    -- nothing to do
+  elseif onewayClass == "-1" then
+    result.forward_mode = 0
+  end
+
+  -- surfaces
+  if surface then
+    surface_speed = surface_speeds[surface]
+    if surface_speed then
+      result.forward_speed = math.min(result.forward_speed, surface_speed)
+      result.backward_speed  = math.min(result.backward_speed, surface_speed)
     end
+  end
 end
diff --git a/profiles/lib/access.lua b/profiles/lib/access.lua
index 76d2e2c..3fd4ff6 100644
--- a/profiles/lib/access.lua
+++ b/profiles/lib/access.lua
@@ -1,13 +1,15 @@
 local ipairs = ipairs
 
-module "Access"
+local Access = {}
 
-function find_access_tag(source,access_tags_hierachy)
+function Access.find_access_tag(source,access_tags_hierachy)
     for i,v in ipairs(access_tags_hierachy) do
         local tag = source:get_value_by_key(v)
         if tag and tag ~= '' then
             return tag
         end
     end
-    return nil
+    return ""
 end
+
+return Access
diff --git a/profiles/lib/maxspeed.lua b/profiles/lib/maxspeed.lua
index aca344a..0dd9b82 100644
--- a/profiles/lib/maxspeed.lua
+++ b/profiles/lib/maxspeed.lua
@@ -1,8 +1,8 @@
 local math = math
 
-module "MaxSpeed"
+local MaxSpeed = {}
 
-function limit(way,max,maxf,maxb)
+function MaxSpeed.limit(way,max,maxf,maxb)
   if maxf and maxf>0 then
     way.forward_speed = math.min(way.forward_speed, maxf)
   elseif max and max>0 then
@@ -15,3 +15,5 @@ function limit(way,max,maxf,maxb)
     way.backward_speed = math.min(way.backward_speed, max)
   end
 end
+
+return MaxSpeed
diff --git a/routing_algorithms/alternative_path.hpp b/routing_algorithms/alternative_path.hpp
index 1dcc020..327bb32 100644
--- a/routing_algorithms/alternative_path.hpp
+++ b/routing_algorithms/alternative_path.hpp
@@ -103,8 +103,8 @@ 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.GetForwardWeightPlusOffset(),
+                     -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
 
         if (phantom_node_pair.source_phantom.forward_node_id != SPECIAL_NODEID)
         {
diff --git a/routing_algorithms/shortest_path.hpp b/routing_algorithms/shortest_path.hpp
index 3dedc2b..eaa6d3c 100644
--- a/routing_algorithms/shortest_path.hpp
+++ b/routing_algorithms/shortest_path.hpp
@@ -93,8 +93,8 @@ class ShortestPathRouting final
             const bool allow_u_turn = current_leg > 0 && uturn_indicators.size() > current_leg &&
                                       uturn_indicators[current_leg - 1];
             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.GetForwardWeightPlusOffset(),
+                         -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
 
             // insert new starting nodes into forward heap, adjusted by previous distances.
             if ((allow_u_turn || search_from_1st_node) &&
@@ -272,11 +272,13 @@ class ShortestPathRouting final
                     if (start_id_of_leg1 != last_id_of_packed_legs1)
                     {
                         packed_legs1 = packed_legs2;
+                        distance1 = distance2;
                         BOOST_ASSERT(start_id_of_leg1 == temporary_packed_leg1.front());
                     }
                     else if (start_id_of_leg2 != last_id_of_packed_legs2)
                     {
                         packed_legs2 = packed_legs1;
+                        distance2 = distance1;
                         BOOST_ASSERT(start_id_of_leg2 == temporary_packed_leg2.front());
                     }
                 }
diff --git a/server/api_grammar.hpp b/server/api_grammar.hpp
index a629cfb..470954f 100644
--- a/server/api_grammar.hpp
+++ b/server/api_grammar.hpp
@@ -42,7 +42,7 @@ template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Ite
                    *(query) >> -(uturns);
         query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | timestamp | u | cmp |
                             language | instruction | geometry | alt_route | old_API | num_results |
-                            matching_beta | gps_precision | classify));
+                            matching_beta | gps_precision | classify | locs));
 
         zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >>
                qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
@@ -83,17 +83,20 @@ template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Ite
                qi::short_[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;
     qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location,
         hint, timestamp, stringwithDot, stringwithPercent, language, instruction, geometry, cmp, alt_route, u,
-        uturns, old_API, num_results, matching_beta, gps_precision, classify;
+        uturns, old_API, num_results, matching_beta, gps_precision, classify, locs, stringforPolyline;
 
     HandlerT *handler;
 };
diff --git a/server/request_parser.cpp b/server/request_parser.cpp
index 584dcbe..502e6e0 100644
--- a/server/request_parser.cpp
+++ b/server/request_parser.cpp
@@ -42,7 +42,8 @@ namespace http
 
 RequestParser::RequestParser()
     : state(internal_state::method_start), current_header({"", ""}),
-      selected_compression(no_compression)
+      selected_compression(no_compression), is_post_header(false),
+      content_length(0)
 {
 }
 
@@ -58,6 +59,11 @@ RequestParser::parse(request &current_request, char *begin, char *end)
         }
     }
     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);
 }
 
@@ -70,8 +76,39 @@ osrm::tribool RequestParser::consume(request &current_request, const char 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 == ' ')
         {
@@ -204,6 +241,24 @@ osrm::tribool RequestParser::consume(request &current_request, const char input)
         {
             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')
         {
@@ -272,7 +327,19 @@ osrm::tribool RequestParser::consume(request &current_request, const char input)
             return osrm::tribool::indeterminate;
         }
         return osrm::tribool::no;
-    default: // expecting_newline_3
+    case internal_state::expecting_newline_3:
+        if(input == '\n')
+        {
+            if(is_post_header)
+            {
+                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;
     }
 }
diff --git a/server/request_parser.hpp b/server/request_parser.hpp
index 2b6bf69..3724613 100644
--- a/server/request_parser.hpp
+++ b/server/request_parser.hpp
@@ -80,11 +80,17 @@ class RequestParser
         space_before_header_value,
         header_value,
         expecting_newline_2,
-        expecting_newline_3
+        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
diff --git a/tools/components.cpp b/tools/components.cpp
index 7ac64f8..660d922 100644
--- a/tools/components.cpp
+++ b/tools/components.cpp
@@ -76,12 +76,68 @@ void DeleteFileIfExists(const std::string &file_name)
 }
 }
 
+void LoadRestrictions(const char* path, std::vector<TurnRestriction>& restriction_list)
+{
+    std::ifstream input_stream(path, std::ios::binary);
+    if (!input_stream.is_open())
+    {
+        throw osrm::exception("Cannot open restriction file");
+    }
+    loadRestrictionsFromFile(input_stream, restriction_list);
+}
+
+std::size_t LoadGraph(const char* path,
+                      std::vector<QueryNode>& coordinate_list,
+                      std::vector<NodeID>& barrier_node_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;
+
+    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;
     std::vector<TurnRestriction> restriction_list;
-    std::vector<NodeID> bollard_node_list;
-    std::vector<NodeID> traffic_lights_list;
+    std::vector<NodeID> barrier_node_list;
 
     LogPolicy::GetInstance().Unmute();
     try
@@ -95,83 +151,10 @@ int main(int argc, char *argv[])
         }
 
         SimpleLogger().Write() << "Using restrictions from file: " << argv[2];
-        std::ifstream restriction_ifstream(argv[2], std::ios::binary);
-        const FingerPrint fingerprint_orig;
-        FingerPrint fingerprint_loaded;
-        restriction_ifstream.read(reinterpret_cast<char *>(&fingerprint_loaded),
-                                  sizeof(FingerPrint));
-
-        // check fingerprint and warn if necessary
-        if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
-        {
-            SimpleLogger().Write(logWARNING) << argv[2] << " was prepared with a different build. "
-                                                           "Reprocess to get rid of this warning.";
-        }
-
-        if (!restriction_ifstream.good())
-        {
-            throw osrm::exception("Could not access <osrm-restrictions> files");
-        }
-        uint32_t usable_restrictions = 0;
-        restriction_ifstream.read(reinterpret_cast<char *>(&usable_restrictions), sizeof(uint32_t));
-        restriction_list.resize(usable_restrictions);
-
-        // load restrictions
-        if (usable_restrictions > 0)
-        {
-            restriction_ifstream.read(reinterpret_cast<char *>(&restriction_list[0]),
-                                      usable_restrictions * sizeof(TurnRestriction));
-        }
-        restriction_ifstream.close();
-
-        std::ifstream input_stream(argv[1], std::ifstream::in | std::ifstream::binary);
-        if (!input_stream.is_open())
-        {
-            throw osrm::exception("Cannot open osrm file");
-        }
-
-        // load graph data
-        std::vector<ImportEdge> edge_list;
-        const NodeID number_of_nodes =
-            readBinaryOSRMGraphFromStream(input_stream, edge_list, bollard_node_list,
-                                          traffic_lights_list, &coordinate_list, restriction_list);
-        input_stream.close();
 
-        BOOST_ASSERT_MSG(restriction_list.size() == usable_restrictions,
-                         "size of restriction_list changed");
-
-        SimpleLogger().Write() << restriction_list.size() << " restrictions, "
-                               << bollard_node_list.size() << " bollard nodes, "
-                               << traffic_lights_list.size() << " traffic lights";
-
-        traffic_lights_list.clear();
-        traffic_lights_list.shrink_to_fit();
-
-        // Building an node-based graph
         std::vector<TarjanEdge> graph_edge_list;
-//        DeallocatingVector<TarjanEdge> graph_edge_list;
-        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);
-            }
-        }
-        edge_list.clear();
-        edge_list.shrink_to_fit();
-        BOOST_ASSERT_MSG(0 == edge_list.size() && 0 == edge_list.capacity(),
-                         "input edge vector not properly deallocated");
+        auto number_of_nodes = LoadGraph(argv[1], coordinate_list, barrier_node_list, graph_edge_list);
+        LoadRestrictions(argv[2], restriction_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);
@@ -181,9 +164,8 @@ int main(int argc, char *argv[])
         SimpleLogger().Write() << "Starting SCC graph traversal";
 
         RestrictionMap restriction_map(restriction_list);
-        auto tarjan = osrm::make_unique<TarjanSCC<TarjanGraph>>(graph,
-                                                                       restriction_map,
-                                                                       bollard_node_list);
+        auto tarjan = osrm::make_unique<TarjanSCC<TarjanGraph>>(graph, restriction_map,
+                                                                barrier_node_list);
         tarjan->run();
         SimpleLogger().Write() << "identified: " << tarjan->get_number_of_components()
                                << " many components";
diff --git a/tools/graph_compare.cpp b/tools/graph_compare.cpp
deleted file mode 100644
index 8adc06e..0000000
--- a/tools/graph_compare.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-#include "../data_structures/dynamic_graph.hpp"
-#include "../data_structures/import_edge.hpp"
-#include "../data_structures/query_node.hpp"
-#include "../data_structures/restriction.hpp"
-#include "../data_structures/static_graph.hpp"
-#include "../util/fingerprint.hpp"
-#include "../util/graph_loader.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/make_unique.hpp"
-#include "../util/osrm_exception.hpp"
-#include "../util/simple_logger.hpp"
-
-#include "../typedefs.h"
-
-#include <algorithm>
-#include <fstream>
-
-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 StaticTestGraph = StaticGraph<TarjanEdgeData>;
-using DynamicTestGraph = StaticGraph<TarjanEdgeData>;
-using StaticEdge = StaticTestGraph::InputEdge;
-using DynamicEdge = DynamicTestGraph::InputEdge;
-
-int main(int argc, char *argv[])
-{
-    std::vector<QueryNode> coordinate_list;
-    std::vector<TurnRestriction> restriction_list;
-    std::vector<NodeID> bollard_node_list;
-    std::vector<NodeID> traffic_lights_list;
-
-    LogPolicy::GetInstance().Unmute();
-    try
-    {
-        // enable logging
-        if (argc < 3)
-        {
-            SimpleLogger().Write(logWARNING) << "usage:\n" << argv[0]
-                                             << " <osrm> <osrm.restrictions>";
-            return -1;
-        }
-
-        SimpleLogger().Write() << "Using restrictions from file: " << argv[2];
-        std::ifstream restriction_ifstream(argv[2], std::ios::binary);
-        const FingerPrint fingerprint_orig;
-        FingerPrint fingerprint_loaded;
-        restriction_ifstream.read(reinterpret_cast<char *>(&fingerprint_loaded),
-                                  sizeof(FingerPrint));
-
-        // check fingerprint and warn if necessary
-        if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
-        {
-            SimpleLogger().Write(logWARNING) << argv[2] << " was prepared with a different build. "
-                                                           "Reprocess to get rid of this warning.";
-        }
-
-        if (!restriction_ifstream.good())
-        {
-            throw osrm::exception("Could not access <osrm-restrictions> files");
-        }
-        uint32_t usable_restrictions = 0;
-        restriction_ifstream.read(reinterpret_cast<char *>(&usable_restrictions), sizeof(uint32_t));
-        restriction_list.resize(usable_restrictions);
-
-        // load restrictions
-        if (usable_restrictions > 0)
-        {
-            restriction_ifstream.read(reinterpret_cast<char *>(&restriction_list[0]),
-                                      usable_restrictions * sizeof(TurnRestriction));
-        }
-        restriction_ifstream.close();
-
-        std::ifstream input_stream(argv[1], std::ifstream::in | std::ifstream::binary);
-        if (!input_stream.is_open())
-        {
-            throw osrm::exception("Cannot open osrm file");
-        }
-
-        // load graph data
-        std::vector<ImportEdge> edge_list;
-        const NodeID number_of_nodes =
-            readBinaryOSRMGraphFromStream(input_stream, edge_list, bollard_node_list,
-                                          traffic_lights_list, &coordinate_list, restriction_list);
-        input_stream.close();
-
-        BOOST_ASSERT_MSG(restriction_list.size() == usable_restrictions,
-                         "size of restriction_list changed");
-
-        SimpleLogger().Write() << restriction_list.size() << " restrictions, "
-                               << bollard_node_list.size() << " bollard nodes, "
-                               << traffic_lights_list.size() << " traffic lights";
-
-        traffic_lights_list.clear();
-        traffic_lights_list.shrink_to_fit();
-
-        // Building an node-based graph
-        std::vector<StaticEdge> static_graph_edge_list;
-        std::vector<DynamicEdge> dynamic_graph_edge_list;
-        for (const auto &input_edge : edge_list)
-        {
-            if (input_edge.source == input_edge.target)
-            {
-                continue;
-            }
-
-            if (input_edge.forward)
-            {
-                static_graph_edge_list.emplace_back(input_edge.source, input_edge.target,
-                                                    (std::max)(input_edge.weight, 1),
-                                                    input_edge.name_id);
-                dynamic_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)
-            {
-                dynamic_graph_edge_list.emplace_back(input_edge.target, input_edge.source,
-                                                     (std::max)(input_edge.weight, 1),
-                                                     input_edge.name_id);
-                static_graph_edge_list.emplace_back(input_edge.target, input_edge.source,
-                                                    (std::max)(input_edge.weight, 1),
-                                                    input_edge.name_id);
-            }
-        }
-        edge_list.clear();
-        edge_list.shrink_to_fit();
-        BOOST_ASSERT_MSG(0 == edge_list.size() && 0 == edge_list.capacity(),
-                         "input edge vector not properly deallocated");
-
-        tbb::parallel_sort(static_graph_edge_list.begin(), static_graph_edge_list.end());
-        tbb::parallel_sort(dynamic_graph_edge_list.begin(), dynamic_graph_edge_list.end());
-
-        auto static_graph =
-            osrm::make_unique<StaticTestGraph>(number_of_nodes, static_graph_edge_list);
-        auto dynamic_graph =
-            osrm::make_unique<DynamicTestGraph>(number_of_nodes, dynamic_graph_edge_list);
-
-        SimpleLogger().Write() << "Starting static/dynamic graph comparison";
-
-        BOOST_ASSERT(static_graph->GetNumberOfNodes() == dynamic_graph->GetNumberOfNodes());
-        BOOST_ASSERT(static_graph->GetNumberOfEdges() == dynamic_graph->GetNumberOfEdges());
-        for (const auto node : osrm::irange(0u, static_graph->GetNumberOfNodes()))
-        {
-            const auto static_range = static_graph->GetAdjacentEdgeRange(node);
-            const auto dynamic_range = dynamic_graph->GetAdjacentEdgeRange(node);
-            SimpleLogger().Write() << "checking node " << node << "/"
-                                   << static_graph->GetNumberOfNodes();
-
-            BOOST_ASSERT(static_range.size() == dynamic_range.size());
-            const auto static_begin = static_graph->BeginEdges(node);
-            const auto dynamic_begin = dynamic_graph->BeginEdges(node);
-
-            // check raw interface
-            for (const auto i : osrm::irange(0u, static_range.size()))
-            {
-                const auto static_target = static_graph->GetTarget(static_begin + i);
-                const auto dynamic_target = dynamic_graph->GetTarget(dynamic_begin + i);
-                BOOST_ASSERT(static_target == dynamic_target);
-
-                const auto static_data = static_graph->GetEdgeData(static_begin + i);
-                const auto dynamic_data = dynamic_graph->GetEdgeData(dynamic_begin + i);
-
-                BOOST_ASSERT(static_data.distance == dynamic_data.distance);
-                BOOST_ASSERT(static_data.name_id == dynamic_data.name_id);
-            }
-
-            // check range interface
-            std::vector<EdgeID> static_target_ids, dynamic_target_ids;
-            std::vector<TarjanEdgeData> static_edge_data, dynamic_edge_data;
-            for (const auto static_id : static_range)
-            {
-                static_target_ids.push_back(static_graph->GetTarget(static_id));
-                static_edge_data.push_back(static_graph->GetEdgeData(static_id));
-            }
-            for (const auto dynamic_id : dynamic_range)
-            {
-                dynamic_target_ids.push_back(dynamic_graph->GetTarget(dynamic_id));
-                dynamic_edge_data.push_back(dynamic_graph->GetEdgeData(dynamic_id));
-            }
-            BOOST_ASSERT(static_target_ids.size() == dynamic_target_ids.size());
-            BOOST_ASSERT(std::equal(std::begin(static_target_ids), std::end(static_target_ids),
-                                    std::begin(dynamic_target_ids)));
-        }
-
-        SimpleLogger().Write() << "Graph comparison finished successfully";
-    }
-    catch (const std::exception &e)
-    {
-        SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
-    }
-
-    return 0;
-}
diff --git a/unit_tests/algorithms/duration_parsing.cpp b/unit_tests/algorithms/duration_parsing.cpp
index ec3b819..e3035dc 100644
--- a/unit_tests/algorithms/duration_parsing.cpp
+++ b/unit_tests/algorithms/duration_parsing.cpp
@@ -41,24 +41,24 @@ BOOST_AUTO_TEST_CASE(all_necessary_test)
 
 BOOST_AUTO_TEST_CASE(common_durations_get_translated)
 {
-    BOOST_CHECK_EQUAL(parseDuration("00:01"), 600);
-    BOOST_CHECK_EQUAL(parseDuration("00:01:01"), 610);
-    BOOST_CHECK_EQUAL(parseDuration("01:01"), 36600);
+    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"), 610);
-    BOOST_CHECK_EQUAL(parseDuration("PT1H1S"), 36010);
-    BOOST_CHECK_EQUAL(parseDuration("PT15M"), 9000);
-    BOOST_CHECK_EQUAL(parseDuration("PT15S"), 150);
-    BOOST_CHECK_EQUAL(parseDuration("PT15H"), 540000);
-    BOOST_CHECK_EQUAL(parseDuration("PT1H15M"), 45000);
-    BOOST_CHECK_EQUAL(parseDuration("PT1H15M1S"), 45010);
+    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"), 9000);
-    BOOST_CHECK_EQUAL(parseDuration("PT1h15m"), 45000);
+    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
new file mode 100644
index 0000000..035b321
--- /dev/null
+++ b/unit_tests/algorithms/geometry_string.cpp
@@ -0,0 +1,74 @@
+/*
+
+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 "../../data_structures/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/util/fingerprint.hpp b/util/fingerprint.hpp
index 82eb136..3894fc8 100644
--- a/util/fingerprint.hpp
+++ b/util/fingerprint.hpp
@@ -29,23 +29,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #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:
-    FingerPrint();
-    FingerPrint(const FingerPrint &) = delete;
-    ~FingerPrint();
+    static FingerPrint GetValid();
     const boost::uuids::uuid &GetFingerPrint() const;
-    bool IsMagicNumberOK() 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:
-    const unsigned magic_number;
+    unsigned magic_number;
     char md5_prepare[33];
     char md5_tree[33];
     char md5_graph[33];
@@ -54,6 +53,10 @@ class FingerPrint
     // initialize to {6ba7b810-9dad-11d1-80b4-00c04fd430c8}
     boost::uuids::uuid named_uuid;
     bool has_64_bits;
+
 };
 
+static_assert(std::is_trivial<FingerPrint>::value, "FingerPrint needs to be trivial.");
+
+
 #endif /* FingerPrint_H */
diff --git a/util/fingerprint_impl.hpp.in b/util/fingerprint_impl.hpp.in
index 9259afd..98bb122 100644
--- a/util/fingerprint_impl.hpp.in
+++ b/util/fingerprint_impl.hpp.in
@@ -40,35 +40,38 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #cmakedefine MD5GRAPH "${MD5GRAPH}"
 #cmakedefine MD5OBJECTS "${MD5OBJECTS}"
 
-FingerPrint::FingerPrint() : magic_number(1297240911)
+FingerPrint FingerPrint::GetValid()
 {
-    md5_prepare[32] = md5_tree[32] = md5_graph[32] = md5_objects[32] = '\0';
+    FingerPrint fingerprint;
 
-    boost::uuids::name_generator gen(named_uuid);
+    fingerprint.magic_number = 1297240911;
+    fingerprint.md5_prepare[32] = fingerprint.md5_tree[32] = fingerprint.md5_graph[32] = fingerprint.md5_objects[32] = '\0';
+
+    boost::uuids::name_generator gen(fingerprint.named_uuid);
     std::string temp_string;
 
-    std::memcpy(md5_prepare, MD5PREPARE, strlen(MD5PREPARE));
-    temp_string += md5_prepare;
-    std::memcpy(md5_tree, MD5RTREE, 32);
-    temp_string += md5_tree;
-    std::memcpy(md5_graph, MD5GRAPH, 32);
-    temp_string += md5_graph;
-    std::memcpy(md5_objects, MD5OBJECTS, 32);
-    temp_string += md5_objects;
-
-    named_uuid = gen(temp_string);
-    has_64_bits = HAS64BITS;
-}
+    std::memcpy(fingerprint.md5_prepare, MD5PREPARE, 32);
+    temp_string += fingerprint.md5_prepare;
+    std::memcpy(fingerprint.md5_tree, MD5RTREE, 32);
+    temp_string += fingerprint.md5_tree;
+    std::memcpy(fingerprint.md5_graph, MD5GRAPH, 32);
+    temp_string += fingerprint.md5_graph;
+    std::memcpy(fingerprint.md5_objects, MD5OBJECTS, 32);
+    temp_string += fingerprint.md5_objects;
 
-FingerPrint::~FingerPrint() {}
+    fingerprint.named_uuid = gen(temp_string);
+    fingerprint.has_64_bits = HAS64BITS;
+
+    return fingerprint;
+}
 
 const boost::uuids::uuid &FingerPrint::GetFingerPrint() const { return named_uuid; }
 
-bool FingerPrint::IsMagicNumberOK() const { return 1297240911 == magic_number; }
+bool FingerPrint::IsMagicNumberOK(const FingerPrint& other) const { return other.magic_number == magic_number; }
 
 bool FingerPrint::TestGraphUtil(const FingerPrint &other) const
 {
-    if (!other.IsMagicNumberOK())
+    if (!IsMagicNumberOK(other))
     {
         throw osrm::exception("hsgr input file misses magic number. Check or reprocess the file");
     }
@@ -77,7 +80,7 @@ bool FingerPrint::TestGraphUtil(const FingerPrint &other) const
 
 bool FingerPrint::TestPrepare(const FingerPrint &other) const
 {
-    if (!other.IsMagicNumberOK())
+    if (!IsMagicNumberOK(other))
     {
         throw osrm::exception("osrm input file misses magic number. Check or reprocess the file");
     }
@@ -86,7 +89,7 @@ bool FingerPrint::TestPrepare(const FingerPrint &other) const
 
 bool FingerPrint::TestRTree(const FingerPrint &other) const
 {
-    if (!other.IsMagicNumberOK())
+    if (!IsMagicNumberOK(other))
     {
         throw osrm::exception("r-tree input file misses magic number. Check or reprocess the file");
     }
@@ -95,7 +98,7 @@ bool FingerPrint::TestRTree(const FingerPrint &other) const
 
 bool FingerPrint::TestQueryObjects(const FingerPrint &other) const
 {
-    if (!other.IsMagicNumberOK())
+    if (!IsMagicNumberOK(other))
     {
         throw osrm::exception("missing magic number. Check or reprocess the file");
     }
diff --git a/util/graph_loader.hpp b/util/graph_loader.hpp
index d741334..71bc9e9 100644
--- a/util/graph_loader.hpp
+++ b/util/graph_loader.hpp
@@ -52,243 +52,57 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <unordered_map>
 #include <vector>
 
-template <typename EdgeT>
-NodeID read_undirected_osrm_stream(std::istream &input_stream,
-                                   std::vector<EdgeT> &edge_list,
-                                   std::vector<FixedPointCoordinate> &coordinate_list)
+/**
+ * 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)
 {
-    const FingerPrint fingerprint_orig;
+    const FingerPrint fingerprint_valid = FingerPrint::GetValid();
     FingerPrint fingerprint_loaded;
-    input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(FingerPrint));
-
-    if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
+    unsigned number_of_usable_restrictions = 0;
+    input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
+    if (!fingerprint_loaded.TestPrepare(fingerprint_valid))
     {
-        SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build.\n"
+        SimpleLogger().Write(logWARNING) << ".restrictions was prepared with different build.\n"
                                             "Reprocess to get rid of this warning.";
     }
 
-    std::unordered_map<NodeID, NodeID> ext_to_int_id_map;
-
-    NodeID n;
-    input_stream.read(reinterpret_cast<char *>(&n), sizeof(NodeID));
-    SimpleLogger().Write() << "Importing n = " << n << " nodes ";
-
-    ExternalMemoryNode current_node;
-    for (NodeID i = 0; i < n; ++i)
+    input_stream.read((char *)&number_of_usable_restrictions, sizeof(unsigned));
+    restriction_list.resize(number_of_usable_restrictions);
+    if (number_of_usable_restrictions > 0)
     {
-        input_stream.read(reinterpret_cast<char *>(&current_node), sizeof(ExternalMemoryNode));
-        coordinate_list.emplace_back(current_node.lat, current_node.lon);
-        ext_to_int_id_map.emplace(current_node.node_id, i);
-        // if (current_node.barrier)
-        // {
-        //     barrier_node_list.emplace_back(i);
-        // }
-        // if (current_node.traffic_lights)
-        // {
-        //     traffic_light_node_list.emplace_back(i);
-        // }
+        input_stream.read((char *) restriction_list.data(),
+                                number_of_usable_restrictions * sizeof(TurnRestriction));
     }
 
-    // tighten vector sizes
-    // barrier_node_list.shrink_to_fit();
-    // traffic_light_node_list.shrink_to_fit();
-
-    // renumber nodes in turn restrictions
-    // for (TurnRestriction &current_restriction : restriction_list)
-    // {
-    //     auto internal_id_iter = ext_to_int_id_map.find(current_restriction.from.node);
-    //     if (internal_id_iter == ext_to_int_id_map.end())
-    //     {
-    //         SimpleLogger().Write(logDEBUG) << "Unmapped from node " <<
-    //         current_restriction.from.node
-    //                                        << " of restriction";
-    //         continue;
-    //     }
-    //     current_restriction.from.node = internal_id_iter->second;
-
-    //     internal_id_iter = ext_to_int_id_map.find(current_restriction.via.node);
-    //     if (internal_id_iter == ext_to_int_id_map.end())
-    //     {
-    //         SimpleLogger().Write(logDEBUG) << "Unmapped via node " <<
-    //         current_restriction.via.node
-    //                                        << " of restriction";
-    //         continue;
-    //     }
-
-    //     current_restriction.via.node = internal_id_iter->second;
-
-    //     internal_id_iter = ext_to_int_id_map.find(current_restriction.to.node);
-    //     if (internal_id_iter == ext_to_int_id_map.end())
-    //     {
-    //         SimpleLogger().Write(logDEBUG) << "Unmapped to node " << current_restriction.to.node
-    //                                        << " of restriction";
-    //         continue;
-    //     }
-    //     current_restriction.to.node = internal_id_iter->second;
-    // }
-
-    EdgeWeight weight;
-    NodeID source, target;
-    unsigned nameID;
-    int length;
-    short dir; // direction (0 = open, 1 = forward, 2+ = open)
-    bool is_roundabout, ignore_in_grid, is_access_restricted, is_split;
-    TravelMode travel_mode;
-
-    EdgeID m;
-    input_stream.read(reinterpret_cast<char *>(&m), sizeof(unsigned));
-    edge_list.reserve(m);
-    SimpleLogger().Write() << " and " << m << " edges ";
-
-    for (EdgeID i = 0; i < m; ++i)
-    {
-        input_stream.read(reinterpret_cast<char *>(&source), sizeof(unsigned));
-        input_stream.read(reinterpret_cast<char *>(&target), sizeof(unsigned));
-        input_stream.read(reinterpret_cast<char *>(&length), sizeof(int));
-        input_stream.read(reinterpret_cast<char *>(&dir), sizeof(short));
-        input_stream.read(reinterpret_cast<char *>(&weight), sizeof(int));
-        input_stream.read(reinterpret_cast<char *>(&nameID), sizeof(unsigned));
-        input_stream.read(reinterpret_cast<char *>(&is_roundabout), sizeof(bool));
-        input_stream.read(reinterpret_cast<char *>(&ignore_in_grid), sizeof(bool));
-        input_stream.read(reinterpret_cast<char *>(&is_access_restricted), sizeof(bool));
-        input_stream.read(reinterpret_cast<char *>(&travel_mode), sizeof(TravelMode));
-        input_stream.read(reinterpret_cast<char *>(&is_split), sizeof(bool));
-
-        BOOST_ASSERT_MSG(length > 0, "loaded null length edge");
-        BOOST_ASSERT_MSG(weight > 0, "loaded null weight");
-        BOOST_ASSERT_MSG(0 <= dir && dir <= 2, "loaded bogus direction");
-
-        // bool forward = true;
-        // bool backward = true;
-        // if (1 == dir)
-        // {
-        //     backward = false;
-        // }
-        // if (2 == dir)
-        // {
-        //     forward = false;
-        // }
-
-        // translate the external NodeIDs to internal IDs
-        auto internal_id_iter = ext_to_int_id_map.find(source);
-        if (ext_to_int_id_map.find(source) == ext_to_int_id_map.end())
-        {
-#ifndef NDEBUG
-            SimpleLogger().Write(logWARNING) << " unresolved source NodeID: " << source;
-#endif
-            continue;
-        }
-        source = internal_id_iter->second;
-        internal_id_iter = ext_to_int_id_map.find(target);
-        if (ext_to_int_id_map.find(target) == ext_to_int_id_map.end())
-        {
-#ifndef NDEBUG
-            SimpleLogger().Write(logWARNING) << "unresolved target NodeID : " << target;
-#endif
-            continue;
-        }
-        target = internal_id_iter->second;
-        BOOST_ASSERT_MSG(source != SPECIAL_NODEID && target != SPECIAL_NODEID,
-                         "nonexisting source or target");
-
-        if (source > target)
-        {
-            std::swap(source, target);
-            // std::swap(forward, backward);
-        }
-
-        edge_list.emplace_back(source, target);
-    }
-    ext_to_int_id_map.clear();
-
-    tbb::parallel_sort(edge_list.begin(), edge_list.end());
-
-    // for (unsigned i = 1; i < edge_list.size(); ++i)
-    // {
-    //     if ((edge_list[i - 1].target == edge_list[i].target) &&
-    //         (edge_list[i - 1].source == edge_list[i].source))
-    //     {
-    //         const bool edge_flags_equivalent = (edge_list[i - 1].forward == edge_list[i].forward)
-    //         &&
-    //                                            (edge_list[i - 1].backward ==
-    //                                            edge_list[i].backward);
-    //         const bool edge_flags_are_superset1 =
-    //             (edge_list[i - 1].forward && edge_list[i - 1].backward) &&
-    //             (edge_list[i].forward != edge_list[i].backward);
-    //         const bool edge_flags_are_superset_2 =
-    //             (edge_list[i].forward && edge_list[i].backward) &&
-    //             (edge_list[i - 1].forward != edge_list[i - 1].backward);
-
-    //         if (edge_flags_equivalent)
-    //         {
-    //             edge_list[i].weight = std::min(edge_list[i - 1].weight, edge_list[i].weight);
-    //             edge_list[i - 1].source = SPECIAL_NODEID;
-    //         }
-    //         else if (edge_flags_are_superset1)
-    //         {
-    //             if (edge_list[i - 1].weight <= edge_list[i].weight)
-    //             {
-    //                 // edge i-1 is smaller and goes in both directions. Throw away the other edge
-    //                 edge_list[i].source = SPECIAL_NODEID;
-    //             }
-    //             else
-    //             {
-    //                 // edge i-1 is open in both directions, but edge i is smaller in one
-    //                 direction.
-    //                 // Close edge i-1 in this direction
-    //                 edge_list[i - 1].forward = !edge_list[i].forward;
-    //                 edge_list[i - 1].backward = !edge_list[i].backward;
-    //             }
-    //         }
-    //         else if (edge_flags_are_superset_2)
-    //         {
-    //             if (edge_list[i - 1].weight <= edge_list[i].weight)
-    //             {
-    //                 // edge i-1 is smaller for one direction. edge i is open in both. close edge
-    //                 i
-    //                 // in the other direction
-    //                 edge_list[i].forward = !edge_list[i - 1].forward;
-    //                 edge_list[i].backward = !edge_list[i - 1].backward;
-    //             }
-    //             else
-    //             {
-    //                 // edge i is smaller and goes in both direction. Throw away edge i-1
-    //                 edge_list[i - 1].source = SPECIAL_NODEID;
-    //             }
-    //         }
-    //     }
-    // }
-    // const auto new_end_iter =
-    //     std::remove_if(edge_list.begin(), edge_list.end(), [](const EdgeT &edge)
-    //                    {
-    //                        return edge.source == SPECIAL_NODEID || edge.target == SPECIAL_NODEID;
-    //                    });
-    // edge_list.erase(new_end_iter, edge_list.end()); // remove excess candidates.
-    // edge_list.shrink_to_fit();
-    SimpleLogger().Write() << "Graph loaded ok and has " << edge_list.size() << " edges";
-    return n;
+    return number_of_usable_restrictions;
 }
 
-template <typename EdgeT>
-NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
-                                     std::vector<EdgeT> &edge_list,
-                                     std::vector<NodeID> &barrier_node_list,
-                                     std::vector<NodeID> &traffic_light_node_list,
-                                     std::vector<QueryNode> *int_to_ext_node_id_map,
-                                     std::vector<TurnRestriction> &restriction_list)
+
+/**
+ * Reads the beginning of an .osrm file and produces:
+ *  - list of barrier nodes
+ *  - list of traffic lights
+ *  - nodes indexed by their internal (non-osm) id
+ */
+NodeID loadNodesFromFile(std::istream &input_stream,
+                         std::vector<NodeID> &barrier_node_list,
+                         std::vector<NodeID> &traffic_light_node_list,
+                         std::vector<QueryNode> &node_array)
 {
-    const FingerPrint fingerprint_orig;
+    const FingerPrint fingerprint_valid = FingerPrint::GetValid();
     FingerPrint fingerprint_loaded;
     input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(FingerPrint));
 
-    if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
+    if (!fingerprint_loaded.TestPrepare(fingerprint_valid))
     {
         SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build.\n"
                                             "Reprocess to get rid of this warning.";
     }
 
-    std::unordered_map<NodeID, NodeID> ext_to_int_id_map;
-
     NodeID n;
     input_stream.read(reinterpret_cast<char *>(&n), sizeof(NodeID));
     SimpleLogger().Write() << "Importing n = " << n << " nodes ";
@@ -297,9 +111,7 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
     for (NodeID i = 0; i < n; ++i)
     {
         input_stream.read(reinterpret_cast<char *>(&current_node), sizeof(ExternalMemoryNode));
-        int_to_ext_node_id_map->emplace_back(current_node.lat, current_node.lon,
-                                             current_node.node_id);
-        ext_to_int_id_map.emplace(current_node.node_id, i);
+        node_array.emplace_back(current_node.lat, current_node.lon, current_node.node_id);
         if (current_node.barrier)
         {
             barrier_node_list.emplace_back(i);
@@ -314,175 +126,48 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
     barrier_node_list.shrink_to_fit();
     traffic_light_node_list.shrink_to_fit();
 
-    // renumber nodes in turn restrictions
-    for (TurnRestriction &current_restriction : restriction_list)
-    {
-        auto internal_id_iter = ext_to_int_id_map.find(current_restriction.from.node);
-        if (internal_id_iter == ext_to_int_id_map.end())
-        {
-            SimpleLogger().Write(logDEBUG) << "Unmapped from node " << current_restriction.from.node
-                                           << " of restriction";
-            continue;
-        }
-        current_restriction.from.node = internal_id_iter->second;
-
-        internal_id_iter = ext_to_int_id_map.find(current_restriction.via.node);
-        if (internal_id_iter == ext_to_int_id_map.end())
-        {
-            SimpleLogger().Write(logDEBUG) << "Unmapped via node " << current_restriction.via.node
-                                           << " of restriction";
-            continue;
-        }
-
-        current_restriction.via.node = internal_id_iter->second;
-
-        internal_id_iter = ext_to_int_id_map.find(current_restriction.to.node);
-        if (internal_id_iter == ext_to_int_id_map.end())
-        {
-            SimpleLogger().Write(logDEBUG) << "Unmapped to node " << current_restriction.to.node
-                                           << " of restriction";
-            continue;
-        }
-        current_restriction.to.node = internal_id_iter->second;
-    }
-
-    EdgeWeight weight;
-    NodeID source, target;
-    unsigned nameID;
-    int length;
-    short dir; // direction (0 = open, 1 = forward, 2+ = open)
-    bool is_roundabout, ignore_in_grid, is_access_restricted, is_split;
-    TravelMode travel_mode;
+    return n;
+}
 
+/**
+ * Reads a .osrm file and produces the edges.
+ */
+NodeID loadEdgesFromFile(std::istream &input_stream,
+                         std::vector<NodeBasedEdge> &edge_list)
+{
     EdgeID m;
     input_stream.read(reinterpret_cast<char *>(&m), sizeof(unsigned));
-    edge_list.reserve(m);
+    edge_list.resize(m);
     SimpleLogger().Write() << " and " << m << " edges ";
 
-    for (EdgeID i = 0; i < m; ++i)
-    {
-        input_stream.read(reinterpret_cast<char *>(&source), sizeof(unsigned));
-        input_stream.read(reinterpret_cast<char *>(&target), sizeof(unsigned));
-        input_stream.read(reinterpret_cast<char *>(&length), sizeof(int));
-        input_stream.read(reinterpret_cast<char *>(&dir), sizeof(short));
-        input_stream.read(reinterpret_cast<char *>(&weight), sizeof(int));
-        input_stream.read(reinterpret_cast<char *>(&nameID), sizeof(unsigned));
-        input_stream.read(reinterpret_cast<char *>(&is_roundabout), sizeof(bool));
-        input_stream.read(reinterpret_cast<char *>(&ignore_in_grid), sizeof(bool));
-        input_stream.read(reinterpret_cast<char *>(&is_access_restricted), sizeof(bool));
-        input_stream.read(reinterpret_cast<char *>(&travel_mode), sizeof(TravelMode));
-        input_stream.read(reinterpret_cast<char *>(&is_split), sizeof(bool));
-
-        BOOST_ASSERT_MSG(length > 0, "loaded null length edge");
-        BOOST_ASSERT_MSG(weight > 0, "loaded null weight");
-        BOOST_ASSERT_MSG(0 <= dir && dir <= 2, "loaded bogus direction");
-
-        bool forward = true;
-        bool backward = true;
-        if (1 == dir)
-        {
-            backward = false;
-        }
-        if (2 == dir)
-        {
-            forward = false;
-        }
+    input_stream.read((char *) edge_list.data(), m * sizeof(NodeBasedEdge));
+
+    BOOST_ASSERT(edge_list.size() > 0);
 
-        // translate the external NodeIDs to internal IDs
-        auto internal_id_iter = ext_to_int_id_map.find(source);
-        if (ext_to_int_id_map.find(source) == ext_to_int_id_map.end())
-        {
-#ifndef NDEBUG
-            SimpleLogger().Write(logWARNING) << " unresolved source NodeID: " << source;
-#endif
-            continue;
-        }
-        source = internal_id_iter->second;
-        internal_id_iter = ext_to_int_id_map.find(target);
-        if (ext_to_int_id_map.find(target) == ext_to_int_id_map.end())
-        {
 #ifndef NDEBUG
-            SimpleLogger().Write(logWARNING) << "unresolved target NodeID : " << target;
-#endif
-            continue;
-        }
-        target = internal_id_iter->second;
-        BOOST_ASSERT_MSG(source != SPECIAL_NODEID && target != SPECIAL_NODEID,
-                         "nonexisting source or target");
+    SimpleLogger().Write() << "Validating loaded edges...";
+    std::sort(edge_list.begin(), edge_list.end(),
+            [](const NodeBasedEdge& lhs, const NodeBasedEdge& rhs)
+            {
+                return (lhs.source < rhs.source) || (lhs.source == rhs.source && lhs.target < rhs.target);
+            });
+    for (auto i = 1u; i < edge_list.size(); ++i)
+    {
+        const auto& edge = edge_list[i];
+        const auto& prev_edge = edge_list[i-1];
 
-        if (source > target)
-        {
-            std::swap(source, target);
-            std::swap(forward, backward);
-        }
+        BOOST_ASSERT_MSG(edge.weight > 0, "loaded null weight");
+        BOOST_ASSERT_MSG(edge.forward, "edge must be oriented in forward direction");
+        BOOST_ASSERT_MSG(edge.travel_mode != TRAVEL_MODE_INACCESSIBLE, "loaded non-accessible");
 
-        edge_list.emplace_back(source, target, nameID, weight, forward, backward, is_roundabout,
-                               ignore_in_grid, is_access_restricted, travel_mode, is_split);
+        BOOST_ASSERT_MSG(edge.source != edge.target, "loaded edges contain a loop");
+        BOOST_ASSERT_MSG(edge.source != prev_edge.source || edge.target != prev_edge.target, "loaded edges contain a multi edge");
     }
-    ext_to_int_id_map.clear();
-
-    tbb::parallel_sort(edge_list.begin(), edge_list.end());
+#endif
 
-    for (unsigned i = 1; i < edge_list.size(); ++i)
-    {
-        if ((edge_list[i - 1].target == edge_list[i].target) &&
-            (edge_list[i - 1].source == edge_list[i].source))
-        {
-            const bool edge_flags_equivalent = (edge_list[i - 1].forward == edge_list[i].forward) &&
-                                               (edge_list[i - 1].backward == edge_list[i].backward);
-            const bool edge_flags_are_superset1 =
-                (edge_list[i - 1].forward && edge_list[i - 1].backward) &&
-                (edge_list[i].forward != edge_list[i].backward);
-            const bool edge_flags_are_superset_2 =
-                (edge_list[i].forward && edge_list[i].backward) &&
-                (edge_list[i - 1].forward != edge_list[i - 1].backward);
-
-            if (edge_flags_equivalent)
-            {
-                edge_list[i].weight = std::min(edge_list[i - 1].weight, edge_list[i].weight);
-                edge_list[i - 1].source = SPECIAL_NODEID;
-            }
-            else if (edge_flags_are_superset1)
-            {
-                if (edge_list[i - 1].weight <= edge_list[i].weight)
-                {
-                    // edge i-1 is smaller and goes in both directions. Throw away the other edge
-                    edge_list[i].source = SPECIAL_NODEID;
-                }
-                else
-                {
-                    // edge i-1 is open in both directions, but edge i is smaller in one direction.
-                    // Close edge i-1 in this direction
-                    edge_list[i - 1].forward = !edge_list[i].forward;
-                    edge_list[i - 1].backward = !edge_list[i].backward;
-                }
-            }
-            else if (edge_flags_are_superset_2)
-            {
-                if (edge_list[i - 1].weight <= edge_list[i].weight)
-                {
-                    // edge i-1 is smaller for one direction. edge i is open in both. close edge i
-                    // in the other direction
-                    edge_list[i].forward = !edge_list[i - 1].forward;
-                    edge_list[i].backward = !edge_list[i - 1].backward;
-                }
-                else
-                {
-                    // edge i is smaller and goes in both direction. Throw away edge i-1
-                    edge_list[i - 1].source = SPECIAL_NODEID;
-                }
-            }
-        }
-    }
-    const auto new_end_iter =
-        std::remove_if(edge_list.begin(), edge_list.end(), [](const EdgeT &edge)
-                       {
-                           return edge.source == SPECIAL_NODEID || edge.target == SPECIAL_NODEID;
-                       });
-    edge_list.erase(new_end_iter, edge_list.end()); // remove excess candidates.
-    edge_list.shrink_to_fit();
     SimpleLogger().Write() << "Graph loaded ok and has " << edge_list.size() << " edges";
-    return n;
+
+    return m;
 }
 
 template <typename NodeT, typename EdgeT>
@@ -502,9 +187,10 @@ unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
 
     boost::filesystem::ifstream hsgr_input_stream(hsgr_file, std::ios::binary);
 
-    FingerPrint fingerprint_loaded, fingerprint_orig;
+    const FingerPrint fingerprint_valid = FingerPrint::GetValid();
+    FingerPrint fingerprint_loaded;
     hsgr_input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(FingerPrint));
-    if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
+    if (!fingerprint_loaded.TestGraphUtil(fingerprint_valid))
     {
         SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build.\n"
                                             "Reprocess to get rid of this warning.";
diff --git a/util/iso_8601_duration_parser.hpp b/util/iso_8601_duration_parser.hpp
index 1981c89..3e558ce 100644
--- a/util/iso_8601_duration_parser.hpp
+++ b/util/iso_8601_duration_parser.hpp
@@ -90,7 +90,7 @@ template <typename Iterator> struct iso_8601_grammar : qi::grammar<Iterator>
 
     unsigned get_duration() const
     {
-        unsigned temp = 10 * (3600 * hours + 60 * minutes + seconds);
+        unsigned temp = (3600 * hours + 60 * minutes + seconds);
         if (temp == 0)
         {
             temp = std::numeric_limits<unsigned>::max();
diff --git a/util/lua_util.hpp b/util/lua_util.hpp
index af6277c..6dbdc8b 100644
--- a/util/lua_util.hpp
+++ b/util/lua_util.hpp
@@ -55,11 +55,10 @@ inline bool lua_function_exists(lua_State *lua_state, const char *name)
 // 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)
 {
-    const boost::filesystem::path profile_path(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;profiles/?.lua;\" .. package.path";
+    const std::string lua_code = "package.path = \"" + folder + "/?.lua;\" .. package.path";
     luaL_dostring(lua_state, lua_code.c_str());
 }
 

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